@tonyclaw/agent-inspector 2.1.16 → 2.1.18

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 (55) hide show
  1. package/.output/cli.js +57 -13
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-Ccrrcx1j.js → CompareDrawer-Fqqw5Lci.js} +1 -1
  4. package/.output/public/assets/ProxyViewerContainer-CP_RzwW9.js +106 -0
  5. package/.output/public/assets/{ReplayDialog-C7axhr-l.js → ReplayDialog-hYhz_i6W.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-WOptg8j_.js → RequestAnatomy-CTuWbtwC.js} +1 -1
  7. package/.output/public/assets/{ResponseView-CSAcxh_M.js → ResponseView-CsZ7S5Gv.js} +2 -2
  8. package/.output/public/assets/{StreamingChunkSequence-DJS5KhPx.js → StreamingChunkSequence-PIbJMotU.js} +1 -1
  9. package/.output/public/assets/_sessionId-CUGA9qU3.js +1 -0
  10. package/.output/public/assets/{index-DMPNh46t.js → index-F7mynwuH.js} +1 -1
  11. package/.output/public/assets/index-G4dTUobw.js +1 -0
  12. package/.output/public/assets/index-gvYkgMPF.css +1 -0
  13. package/.output/public/assets/{json-viewer-inX5QSa3.js → json-viewer-DCXtNmmD.js} +1 -1
  14. package/.output/public/assets/{main-aCAKYGSD.js → main-BJZf7_Ib.js} +2 -2
  15. package/.output/server/_libs/lucide-react.mjs +220 -202
  16. package/.output/server/{_sessionId-C0fhvQnn.mjs → _sessionId-DjSHDNh8.mjs} +2 -2
  17. package/.output/server/_ssr/{CompareDrawer-CO-Ti5sg.mjs → CompareDrawer-Dal52IFo.mjs} +3 -3
  18. package/.output/server/_ssr/{ProxyViewerContainer-N4J7uBCX.mjs → ProxyViewerContainer-CVqFZGff.mjs} +1833 -1366
  19. package/.output/server/_ssr/{ReplayDialog-J1VxC0In.mjs → ReplayDialog-BOEgdMes.mjs} +4 -4
  20. package/.output/server/_ssr/{RequestAnatomy-DBH-F3rq.mjs → RequestAnatomy-gch7_vCV.mjs} +2 -2
  21. package/.output/server/_ssr/{ResponseView-DLFwV7Hd.mjs → ResponseView-lEWPy-H4.mjs} +3 -3
  22. package/.output/server/_ssr/{StreamingChunkSequence-BywmuND0.mjs → StreamingChunkSequence-DnudbJ1O.mjs} +2 -2
  23. package/.output/server/_ssr/{index-CStymIc0.mjs → index-Cza8zDrW.mjs} +2 -2
  24. package/.output/server/_ssr/index.mjs +2 -2
  25. package/.output/server/_ssr/{json-viewer-DlQu0N1x.mjs → json-viewer-C2lIVEX3.mjs} +3 -3
  26. package/.output/server/_ssr/{router-CQ4Zxhmr.mjs → router-bF9uzd1k.mjs} +939 -113
  27. package/.output/server/{_tanstack-start-manifest_v-BHeJBGfo.mjs → _tanstack-start-manifest_v-ErvW-mtr.mjs} +1 -1
  28. package/.output/server/index.mjs +74 -74
  29. package/README.md +57 -2
  30. package/package.json +1 -1
  31. package/src/cli/startupOutput.ts +16 -0
  32. package/src/cli.ts +61 -15
  33. package/src/components/ProxyViewer.tsx +395 -64
  34. package/src/components/providers/ProviderCard.tsx +132 -31
  35. package/src/components/providers/ProviderForm.tsx +43 -11
  36. package/src/components/providers/ProvidersPanel.tsx +1 -1
  37. package/src/components/proxy-viewer/ConversationHeader.tsx +133 -112
  38. package/src/components/proxy-viewer/LogEntry.tsx +109 -26
  39. package/src/components/proxy-viewer/LogEntryHeader.tsx +339 -329
  40. package/src/components/proxy-viewer/ThreadConnector.tsx +49 -46
  41. package/src/components/proxy-viewer/TurnGroup.tsx +22 -62
  42. package/src/components/proxy-viewer/bodyHydration.ts +56 -0
  43. package/src/lib/providerTestContract.ts +56 -10
  44. package/src/lib/providerTestPrompt.ts +23 -1
  45. package/src/lib/upstreamUrl.ts +105 -1
  46. package/src/mcp/server.ts +275 -0
  47. package/src/mcp/toolHandlers.ts +381 -4
  48. package/src/proxy/logSearch.ts +3 -0
  49. package/src/proxy/store.ts +40 -15
  50. package/src/routes/api/logs.ts +8 -2
  51. package/src/routes/api/providers.$providerId.test.log.ts +85 -10
  52. package/.output/public/assets/ProxyViewerContainer-DLqClc9A.js +0 -106
  53. package/.output/public/assets/_sessionId-DUSalzKH.js +0 -1
  54. package/.output/public/assets/index-BPpA21dY.css +0 -1
  55. package/.output/public/assets/index-Bt0Az2I2.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { I as InspectorGroupsListResponseSchema, 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 packageJson, P as ProviderConfigSchema, i as apiFormatForPath, n as GroupEvidenceExportResultSchema, o as DeleteInspectorGroupResponseSchema, v as createPendingProviderTestResults, w as ProviderTestResultsSchema, x as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, y as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, l as AlertSummarySchema, m as AlertListResponseSchema, G as GroupEvidenceReadResponseSchema, t as maskApiKey, q as providerHasContextMetadata, r as findProviderModelMetadata, f as parseOpenAIResponse, g as parseOpenAIResponsesResponse, O as OpenAIRequestSchema, h as OpenAIResponsesRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, z as resolveProviderContextWindow, j as getSessionPath, u as buildUpstreamUrl, K as KnowledgeCandidateSchema, B as isPlainRecord, k as stripClaudeCodeBillingHeader, L as LogBodyChunkSchema } from "./router-CQ4Zxhmr.mjs";
2
+ import { I as InspectorGroupsListResponseSchema, 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 packageJson, P as ProviderConfigSchema, i as apiFormatForPath, n as GroupEvidenceExportResultSchema, o as DeleteInspectorGroupResponseSchema, y as createPendingProviderTestResults, z as ProviderTestResultsSchema, B as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, E as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, l as AlertSummarySchema, m as AlertListResponseSchema, G as GroupEvidenceReadResponseSchema, t as maskApiKey, u as PATH_V1_MESSAGES, v as PATH_V1_CHAT_COMPLETIONS, w as PATH_V1_RESPONSES, q as providerHasContextMetadata, r as findProviderModelMetadata, f as parseOpenAIResponse, g as parseOpenAIResponsesResponse, O as OpenAIRequestSchema, h as OpenAIResponsesRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, F as resolveProviderContextWindow, j as getSessionPath, x as previewUpstreamUrl, K as KnowledgeCandidateSchema, H as isPlainRecord, k as stripClaudeCodeBillingHeader, L as LogBodyChunkSchema } from "./router-bF9uzd1k.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,7 +9,7 @@ import { c as cva } from "../_libs/class-variance-authority.mjs";
9
9
  import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
10
10
  import { d as diffJson, a as diffLines } from "../_libs/diff.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 { T as TriangleAlert, C as CircleCheck, X, I as Info, a as ChevronDown, b as Check, U as Upload, D as Download, F as FileBraces, c as Trash2, P as Plus, A as ArrowLeft, d as ChevronUp, e as Copy, f as ChevronsLeft, g as ChevronLeft, h as ChevronRight, i as ChevronsRight, j as Clapperboard, S as Siren, G as Gauge, L as LoaderCircle, R as RefreshCw, k as Layers, l as Settings, M as Monitor, m as Scan, n as CircleAlert, o as Terminal, p as ArrowUpRight, q as ArrowDownRight, r as Cpu, s as FolderOpen, B as Bell, t as Clock3, u as ShieldAlert, E as EyeOff, v as Eye, w as ExternalLink, x as RotateCw, y as Clock, z as Pencil, H as MessageSquare, Z as Zap, W as Wrench, J as Brain, K as Minus, N as CircleCheckBig, O as CircleQuestionMark, Q as Server, V as Lock, Y as Wifi, _ as WifiOff, $ as CircleX, a0 as ShieldCheck, a1 as Save, a2 as FileSearch, a3 as CloudUpload, a4 as OctagonAlert, a5 as Radio, a6 as Globe, a7 as FileTerminal, a8 as ChevronsUp, a9 as ChevronsDown, aa as FileDiff, ab as History, ac as RotateCcw, ad as Search, ae as GitCompareArrows, af as ArrowUp, ag as ArrowDown, ah as Ellipsis, ai as CodeXml, aj as Blocks, ak as MousePointerClick, al as FileText, am as Rows3, an as Columns2 } from "../_libs/lucide-react.mjs";
12
+ import { T as TriangleAlert, C as CircleCheck, X, I as Info, a as ChevronDown, b as Check, U as Upload, D as Download, F as FileBraces, c as Trash2, P as Plus, A as ArrowLeft, d as ChevronUp, e as Copy, f as ChevronsLeft, g as ChevronLeft, h as ChevronRight, i as ChevronsRight, j as Clapperboard, k as Flag, S as Siren, l as Timer, G as Gauge, L as LoaderCircle, R as RefreshCw, m as Layers, n as Settings, M as Monitor, o as Scan, p as CircleAlert, q as Terminal, r as ArrowUpRight, s as ArrowDownRight, t as Cpu, u as FolderOpen, B as Bell, v as Clock3, w as ShieldAlert, E as EyeOff, x as Eye, y as ExternalLink, z as RotateCw, H as Clock, J as Pencil, K as MessageSquare, Z as Zap, W as Wrench, N as Brain, O as Minus, Q as CircleCheckBig, V as CircleQuestionMark, Y as Server, _ as Lock, $ as Wifi, a0 as WifiOff, a1 as CircleX, a2 as ShieldCheck, a3 as Save, a4 as FileSearch, a5 as CloudUpload, a6 as OctagonAlert, a7 as Radio, a8 as Globe, a9 as FileTerminal, aa as ChevronsUp, ab as ChevronsDown, ac as FileDiff, ad as History, ae as RotateCcw, af as Search, ag as GitCompareArrows, ah as ArrowUp, ai as ArrowDown, aj as Ellipsis, ak as CodeXml, al as Blocks, am as MousePointerClick, an as FileText, ao as Rows3, ap as Columns2 } from "../_libs/lucide-react.mjs";
13
13
  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";
14
14
  import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
15
15
  import { R as Root2$1, L as List, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
@@ -522,6 +522,78 @@ function formatTimestamp$2(iso, format) {
522
522
  function formatTimestampRange(startedAt, endedAt, format) {
523
523
  return `${formatTimestamp$2(startedAt, format)} - ${formatTimestamp$2(endedAt, format)}`;
524
524
  }
525
+ function isRecord(value) {
526
+ return typeof value === "object" && value !== null && !Array.isArray(value);
527
+ }
528
+ function normalizeAnthropicStopReason(value) {
529
+ switch (value) {
530
+ case "end_turn":
531
+ case "tool_use":
532
+ return value;
533
+ default:
534
+ return null;
535
+ }
536
+ }
537
+ function normalizeOpenAIFinishReason(value) {
538
+ switch (value) {
539
+ case "stop":
540
+ case "length":
541
+ return value;
542
+ default:
543
+ return null;
544
+ }
545
+ }
546
+ function isResponsesLengthLimitReason(value) {
547
+ switch (value) {
548
+ case "max_output_tokens":
549
+ case "max_tokens":
550
+ return true;
551
+ default:
552
+ return false;
553
+ }
554
+ }
555
+ function extractStopReason(log) {
556
+ if (log.responseText === null) return null;
557
+ try {
558
+ let json = JSON.parse(log.responseText);
559
+ if (typeof json === "string") {
560
+ json = JSON.parse(json);
561
+ }
562
+ if (!isRecord(json)) return null;
563
+ if (typeof json.stop_reason === "string") {
564
+ return normalizeAnthropicStopReason(json.stop_reason);
565
+ }
566
+ if (Array.isArray(json.choices)) {
567
+ for (const choice of json.choices) {
568
+ if (!isRecord(choice) || typeof choice.finish_reason !== "string") continue;
569
+ const reason = normalizeOpenAIFinishReason(choice.finish_reason);
570
+ if (reason !== null) return reason;
571
+ }
572
+ }
573
+ if (Array.isArray(json.output)) {
574
+ for (const item of json.output) {
575
+ if (isRecord(item) && item.type === "function_call") {
576
+ return "tool_use";
577
+ }
578
+ }
579
+ if (json.status === "completed") {
580
+ return "stop";
581
+ }
582
+ }
583
+ if (json.status === "incomplete" && isRecord(json.incomplete_details)) {
584
+ const reason = json.incomplete_details.reason;
585
+ if (typeof reason === "string" && isResponsesLengthLimitReason(reason)) {
586
+ return "length";
587
+ }
588
+ }
589
+ return null;
590
+ } catch {
591
+ return null;
592
+ }
593
+ }
594
+ function isTurnBoundary(stopReason) {
595
+ return stopReason === "end_turn" || stopReason === "stop" || stopReason === "length";
596
+ }
525
597
  function cn(...inputs) {
526
598
  return twMerge(clsx(inputs));
527
599
  }
@@ -1003,7 +1075,6 @@ function TooltipContent({
1003
1075
  ) });
1004
1076
  }
1005
1077
  const MAX_VISIBLE_LOGOS = 3;
1006
- const ROW_CHEVRON_SLOT_CLASS = "flex h-8 w-5 shrink-0 items-center justify-center text-muted-foreground";
1007
1078
  function ProviderLogoStack({
1008
1079
  items,
1009
1080
  ariaLabel,
@@ -1410,6 +1481,28 @@ function resolveLogFormat(log) {
1410
1481
  const pathFormat = apiFormatForPath(log.path);
1411
1482
  return pathFormat === "unknown" ? log.apiFormat : pathFormat;
1412
1483
  }
1484
+ const HEADER_ACTION_BUTTON_CLASS$1 = "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground";
1485
+ function HeaderMetric({
1486
+ icon,
1487
+ children,
1488
+ title,
1489
+ className
1490
+ }) {
1491
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1492
+ "span",
1493
+ {
1494
+ className: cn(
1495
+ "border border-border bg-muted/30 inline-flex h-7 min-w-0 items-center gap-1.5 rounded-md px-2 text-xs text-muted-foreground",
1496
+ className
1497
+ ),
1498
+ title,
1499
+ children: [
1500
+ icon,
1501
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 font-mono tabular-nums", children })
1502
+ ]
1503
+ }
1504
+ );
1505
+ }
1413
1506
  function ConversationHeader({
1414
1507
  conversationId,
1415
1508
  startTime,
@@ -1453,6 +1546,8 @@ function ConversationHeader({
1453
1546
  const clientTooltip = detectedClientLabel !== null && hasUserAgent ? `${detectedClientLabel} - ${userAgent}` : null;
1454
1547
  const isFallbackConversation = conversationId.startsWith("PID:") || conversationId.includes("|");
1455
1548
  const compactSessionLabel = conversationId.length > 24 ? conversationId.slice(0, 12) + "..." + conversationId.slice(-12) : conversationId;
1549
+ const timeLabel = formatTimestampRange(startTime, endTime, timeDisplayFormat);
1550
+ const callsLabel = `${totalCalls} call${totalCalls !== 1 ? "s" : ""}`;
1456
1551
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1457
1552
  "div",
1458
1553
  {
@@ -1461,11 +1556,11 @@ function ConversationHeader({
1461
1556
  "data-nav-id": `conv-${conversationId}`,
1462
1557
  "data-nav-action": expanded ? "collapse" : "expand",
1463
1558
  className: cn(
1464
- "border border-border bg-card shadow-sm flex cursor-pointer items-center gap-3 rounded-[8px] px-3 py-2 transition-colors",
1559
+ "border border-border bg-card shadow-sm flex cursor-pointer items-start gap-3 rounded-[8px] px-3 py-2.5 transition-colors",
1465
1560
  "hover:border-cyan-200/20",
1466
1561
  "select-none",
1467
1562
  "sticky top-0 z-10 mb-2",
1468
- "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
1563
+ "focus-visible:ring-1 focus-visible:ring-cyan-300/35 focus-visible:outline-none"
1469
1564
  ),
1470
1565
  onClick: onToggle,
1471
1566
  onKeyDown: (e) => {
@@ -1476,115 +1571,119 @@ function ConversationHeader({
1476
1571
  }
1477
1572
  },
1478
1573
  children: [
1479
- /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderLogoStack, { items: providerLogoItems, ariaLabel: "Models used in this session" }),
1480
- isFallbackConversation && showProcessMetadata ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1481
- clientPid !== null && clientPid !== void 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1482
- "span",
1483
- {
1484
- className: "shrink-0 font-mono text-xs font-semibold text-violet-200",
1485
- title: `PID ${clientPid}`,
1486
- children: [
1487
- "PID ",
1488
- clientPid
1489
- ]
1490
- }
1491
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 font-mono text-xs font-semibold text-violet-200", children: conversationId }),
1492
- clientProjectFolder !== null && clientProjectFolder !== void 0 && clientProjectFolder !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx(
1493
- "span",
1574
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1575
+ ProviderLogoStack,
1576
+ {
1577
+ items: providerLogoItems,
1578
+ ariaLabel: "Models used in this session",
1579
+ className: "mt-0.5"
1580
+ }
1581
+ ),
1582
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0 flex-1", children: [
1583
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
1584
+ isFallbackConversation && showProcessMetadata ? clientPid !== null && clientPid !== void 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1585
+ "span",
1586
+ {
1587
+ className: "min-w-0 max-w-full truncate font-mono text-xs font-semibold text-violet-200",
1588
+ title: `PID ${clientPid}`,
1589
+ children: [
1590
+ "PID ",
1591
+ clientPid
1592
+ ]
1593
+ }
1594
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
1595
+ "span",
1596
+ {
1597
+ className: "min-w-0 max-w-full truncate font-mono text-xs font-semibold text-violet-200",
1598
+ title: conversationId,
1599
+ children: conversationId
1600
+ }
1601
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
1602
+ "span",
1603
+ {
1604
+ className: "min-w-0 max-w-full truncate font-mono text-xs font-semibold text-violet-200",
1605
+ title: conversationId,
1606
+ children: isFallbackConversation ? "sessionless" : compactSessionLabel
1607
+ }
1608
+ ),
1609
+ !isFallbackConversation && showProcessMetadata && clientPid !== null && clientPid !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1610
+ "span",
1611
+ {
1612
+ className: "border border-border bg-muted/40 shrink-0 rounded px-1.5 py-0.5 font-mono text-xs tabular-nums text-muted-foreground",
1613
+ title: `Client process ID ${clientPid}`,
1614
+ children: [
1615
+ "PID ",
1616
+ clientPid
1617
+ ]
1618
+ }
1619
+ ),
1620
+ isFallbackConversation && showProcessMetadata && clientProjectFolder !== null && clientProjectFolder !== void 0 && clientProjectFolder !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx(
1621
+ "span",
1622
+ {
1623
+ className: "min-w-0 max-w-[240px] truncate font-mono text-xs text-muted-foreground",
1624
+ title: clientProjectFolder,
1625
+ children: clientProjectFolder
1626
+ }
1627
+ ),
1628
+ showClientIdentity && clientDisplayLabel !== null && clientDisplayLabel !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1629
+ "span",
1630
+ {
1631
+ className: "border border-border bg-muted/30 inline-flex h-6 max-w-[180px] shrink-0 items-center gap-1 rounded-md px-1.5 text-xs text-muted-foreground",
1632
+ title: clientTooltip ?? clientDisplayLabel,
1633
+ children: [
1634
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ClientLogo, { client: clientApp, className: "size-4 shrink-0" }),
1635
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate font-mono tabular-nums", children: clientDisplayLabel })
1636
+ ]
1637
+ }
1638
+ )
1639
+ ] }),
1640
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-1.5", children: [
1641
+ /* @__PURE__ */ jsxRuntimeExports.jsx(HeaderMetric, { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3 shrink-0" }), title: timeLabel, children: timeLabel }),
1642
+ /* @__PURE__ */ jsxRuntimeExports.jsx(HeaderMetric, { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3 shrink-0" }), children: callsLabel }),
1643
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(HeaderMetric, { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 shrink-0" }), className: "max-w-full", children: [
1644
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400", children: formatTokens(totalInputTokens) }),
1645
+ " / ",
1646
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-400", children: formatTokens(totalOutputTokens) })
1647
+ ] })
1648
+ ] })
1649
+ ] }),
1650
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex shrink-0 items-start gap-1.5", children: [
1651
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1652
+ "button",
1494
1653
  {
1495
- className: "text-muted-foreground text-xs font-mono truncate max-w-[200px] shrink-0",
1496
- title: clientProjectFolder,
1497
- children: clientProjectFolder
1654
+ type: "button",
1655
+ onClick: handleOpenInNewTab,
1656
+ onKeyDown: (e) => {
1657
+ if (e.key === "Enter" || e.key === " ") {
1658
+ handleOpenInNewTab(e);
1659
+ }
1660
+ },
1661
+ "aria-label": `Open session ${conversationId} in a new tab`,
1662
+ title: "Open this session in a new tab",
1663
+ className: HEADER_ACTION_BUTTON_CLASS$1,
1664
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3.5" })
1498
1665
  }
1499
- )
1500
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1501
- /* @__PURE__ */ jsxRuntimeExports.jsx(
1502
- "span",
1666
+ ),
1667
+ onClear !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
1668
+ "button",
1503
1669
  {
1504
- className: "shrink-0 font-mono text-xs font-semibold text-violet-200",
1505
- title: conversationId,
1506
- children: isFallbackConversation ? "sessionless" : compactSessionLabel
1670
+ type: "button",
1671
+ onClick: handleClearClick,
1672
+ "aria-label": `Clear group (${totalCalls} request${totalCalls !== 1 ? "s" : ""})`,
1673
+ title: "Clear this group",
1674
+ className: HEADER_ACTION_BUTTON_CLASS$1,
1675
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
1507
1676
  }
1508
1677
  ),
1509
- showProcessMetadata && clientPid !== null && clientPid !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1678
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1510
1679
  "span",
1511
1680
  {
1512
- className: "border border-border bg-muted/40 shrink-0 rounded px-1.5 py-0.5 font-mono text-xs tabular-nums text-muted-foreground",
1513
- title: `Client process ID ${clientPid}`,
1514
- children: [
1515
- "PID ",
1516
- clientPid
1517
- ]
1681
+ className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 items-center justify-center rounded-md text-slate-200",
1682
+ "aria-hidden": "true",
1683
+ children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 shrink-0" }) : isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 shrink-0 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 shrink-0" })
1518
1684
  }
1519
1685
  )
1520
1686
  ] }),
1521
- showClientIdentity && clientDisplayLabel !== null && clientDisplayLabel !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1522
- "span",
1523
- {
1524
- className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0",
1525
- title: clientTooltip ?? clientDisplayLabel,
1526
- children: [
1527
- /* @__PURE__ */ jsxRuntimeExports.jsx(ClientLogo, { client: clientApp, className: "size-5" }),
1528
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[120px]", children: clientDisplayLabel })
1529
- ]
1530
- }
1531
- ),
1532
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
1533
- /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
1534
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatTimestampRange(startTime, endTime, timeDisplayFormat) })
1535
- ] }),
1536
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
1537
- /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
1538
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
1539
- totalCalls,
1540
- " call",
1541
- totalCalls !== 1 ? "s" : ""
1542
- ] })
1543
- ] }),
1544
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-xs shrink-0", children: [
1545
- /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
1546
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
1547
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400", children: formatTokens(totalInputTokens) }),
1548
- " / ",
1549
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-400", children: formatTokens(totalOutputTokens) })
1550
- ] })
1551
- ] }),
1552
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
1553
- /* @__PURE__ */ jsxRuntimeExports.jsx(
1554
- "button",
1555
- {
1556
- type: "button",
1557
- onClick: handleOpenInNewTab,
1558
- onKeyDown: (e) => {
1559
- if (e.key === "Enter" || e.key === " ") {
1560
- handleOpenInNewTab(e);
1561
- }
1562
- },
1563
- "aria-label": `Open session ${conversationId} in a new tab`,
1564
- title: "Open this session in a new tab",
1565
- className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground",
1566
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3.5" })
1567
- }
1568
- ),
1569
- onClear !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
1570
- "button",
1571
- {
1572
- type: "button",
1573
- onClick: handleClearClick,
1574
- "aria-label": `Clear group (${totalCalls} request${totalCalls !== 1 ? "s" : ""})`,
1575
- title: "Clear this group",
1576
- className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground",
1577
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" })
1578
- }
1579
- ),
1580
- /* @__PURE__ */ jsxRuntimeExports.jsx(
1581
- "span",
1582
- {
1583
- className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 items-center justify-center rounded-md text-slate-200",
1584
- "aria-hidden": "true",
1585
- children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 shrink-0" }) : isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 shrink-0 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 shrink-0" })
1586
- }
1587
- ),
1588
1687
  /* @__PURE__ */ jsxRuntimeExports.jsx(
1589
1688
  ConfirmDialog,
1590
1689
  {
@@ -1667,794 +1766,406 @@ function readLogFocusRequest(event) {
1667
1766
  return null;
1668
1767
  }
1669
1768
  }
1670
- function isRecord(value) {
1671
- return typeof value === "object" && value !== null && !Array.isArray(value);
1769
+ const FULL_EXPAND_NODE_LIMIT = 400;
1770
+ const STRUCTURE_EXPAND_NODE_LIMIT = 2e3;
1771
+ function isJsonArray(value) {
1772
+ return Array.isArray(value);
1672
1773
  }
1673
- function normalizeAnthropicStopReason(value) {
1674
- switch (value) {
1675
- case "end_turn":
1676
- case "tool_use":
1677
- return value;
1678
- default:
1679
- return null;
1774
+ function countJsonNodesUpTo(value, limit) {
1775
+ const stack = [value];
1776
+ let count = 0;
1777
+ while (stack.length > 0) {
1778
+ const current = stack.pop();
1779
+ if (current === void 0) continue;
1780
+ count += 1;
1781
+ if (count > limit) return count;
1782
+ if (current === null || typeof current !== "object") continue;
1783
+ if (isJsonArray(current)) {
1784
+ for (const child of current) {
1785
+ stack.push(child);
1786
+ }
1787
+ continue;
1788
+ }
1789
+ for (const key of Object.keys(current)) {
1790
+ const child = current[key];
1791
+ if (child !== void 0) stack.push(child);
1792
+ }
1680
1793
  }
1794
+ return count;
1681
1795
  }
1682
- function normalizeOpenAIFinishReason(value) {
1683
- switch (value) {
1684
- case "stop":
1685
- case "length":
1686
- return value;
1687
- default:
1688
- return null;
1689
- }
1796
+ function getJsonExpansionPolicy(value) {
1797
+ const nodeCount = countJsonNodesUpTo(value, STRUCTURE_EXPAND_NODE_LIMIT + 1);
1798
+ if (nodeCount <= FULL_EXPAND_NODE_LIMIT) return { depth: Number.POSITIVE_INFINITY };
1799
+ if (nodeCount <= STRUCTURE_EXPAND_NODE_LIMIT) return { depth: 3 };
1800
+ return { depth: 2 };
1690
1801
  }
1691
- function isResponsesLengthLimitReason(value) {
1692
- switch (value) {
1693
- case "max_output_tokens":
1694
- case "max_tokens":
1695
- return true;
1696
- default:
1697
- return false;
1802
+ function parseJsonText(text) {
1803
+ try {
1804
+ const parsed = JSON.parse(text);
1805
+ return { kind: "json", data: safeJsonValue(parsed) };
1806
+ } catch {
1807
+ return { kind: "text" };
1698
1808
  }
1699
1809
  }
1700
- function extractStopReason(log) {
1701
- if (log.responseText === null) return null;
1702
- try {
1703
- let json = JSON.parse(log.responseText);
1704
- if (typeof json === "string") {
1705
- json = JSON.parse(json);
1706
- }
1707
- if (!isRecord(json)) return null;
1708
- if (typeof json.stop_reason === "string") {
1709
- return normalizeAnthropicStopReason(json.stop_reason);
1710
- }
1711
- if (Array.isArray(json.choices)) {
1712
- for (const choice of json.choices) {
1713
- if (!isRecord(choice) || typeof choice.finish_reason !== "string") continue;
1714
- const reason = normalizeOpenAIFinishReason(choice.finish_reason);
1715
- if (reason !== null) return reason;
1716
- }
1717
- }
1718
- if (Array.isArray(json.output)) {
1719
- for (const item of json.output) {
1720
- if (isRecord(item) && item.type === "function_call") {
1721
- return "tool_use";
1722
- }
1723
- }
1724
- if (json.status === "completed") {
1725
- return "stop";
1810
+ function useJsonBulkExpansion(text) {
1811
+ const parsed = reactExports.useMemo(() => text === null ? null : parseJsonText(text), [text]);
1812
+ const parsedData = parsed?.kind === "json" ? parsed.data : null;
1813
+ const policy = reactExports.useMemo(
1814
+ () => parsedData === null ? null : getJsonExpansionPolicy(parsedData),
1815
+ [parsedData]
1816
+ );
1817
+ const [isExpanded, setIsExpanded] = reactExports.useState(false);
1818
+ const [bulkDepth, setBulkDepth] = reactExports.useState(0);
1819
+ const [bulkRevision, setBulkRevision] = reactExports.useState(0);
1820
+ const [isPending, startTransition] = reactExports.useTransition();
1821
+ const toggle = reactExports.useCallback(() => {
1822
+ const nextExpanded = !isExpanded;
1823
+ const targetDepth = nextExpanded && policy !== null ? policy.depth : 0;
1824
+ startTransition(() => {
1825
+ setIsExpanded(nextExpanded);
1826
+ setBulkDepth(targetDepth);
1827
+ setBulkRevision((current) => current + 1);
1828
+ });
1829
+ }, [isExpanded, policy]);
1830
+ return { parsedData, policy, isExpanded, toggle, isPending, bulkDepth, bulkRevision };
1831
+ }
1832
+ function safeJsonValue(value) {
1833
+ if (value === null || value === void 0) return null;
1834
+ switch (typeof value) {
1835
+ case "string":
1836
+ return value;
1837
+ case "number":
1838
+ return value;
1839
+ case "boolean":
1840
+ return value;
1841
+ case "object": {
1842
+ if (Array.isArray(value)) {
1843
+ return value.map((item) => safeJsonValue(item));
1726
1844
  }
1727
- }
1728
- if (json.status === "incomplete" && isRecord(json.incomplete_details)) {
1729
- const reason = json.incomplete_details.reason;
1730
- if (typeof reason === "string" && isResponsesLengthLimitReason(reason)) {
1731
- return "length";
1845
+ const result = {};
1846
+ for (const key of Object.keys(value)) {
1847
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1848
+ result[key] = safeJsonValue(descriptor?.value);
1732
1849
  }
1850
+ return result;
1733
1851
  }
1734
- return null;
1735
- } catch {
1736
- return null;
1852
+ case "bigint":
1853
+ case "symbol":
1854
+ case "function":
1855
+ case "undefined":
1856
+ return String(value);
1737
1857
  }
1858
+ return null;
1738
1859
  }
1739
- function isTurnBoundary(stopReason) {
1740
- return stopReason === "end_turn" || stopReason === "stop" || stopReason === "length";
1741
- }
1742
- function SvgShell({
1860
+ function Tabs({
1743
1861
  className,
1744
- style,
1745
- d,
1746
- eyeStalks,
1747
- eyes,
1748
- legs,
1749
- extras
1862
+ orientation = "horizontal",
1863
+ ...props
1750
1864
  }) {
1751
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1752
- "svg",
1753
- {
1754
- viewBox: "0 0 24 24",
1755
- fill: "none",
1756
- stroke: "currentColor",
1757
- strokeWidth: "1.5",
1758
- strokeLinecap: "round",
1759
- strokeLinejoin: "round",
1760
- "aria-hidden": "true",
1761
- style,
1762
- className: cn("inline-block size-5", className),
1763
- children: [
1764
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d }),
1765
- eyeStalks,
1766
- eyes,
1767
- legs,
1768
- extras
1769
- ]
1770
- }
1771
- );
1772
- }
1773
- const StdLegs = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1774
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6.5", y1: "16", x2: "4.5", y2: "19.5" }),
1775
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "17.5", x2: "8", y2: "20.5" }),
1776
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15", y1: "17.5", x2: "16", y2: "20.5" }),
1777
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17.5", y1: "16", x2: "19.5", y2: "19.5" })
1778
- ] });
1779
- const ShortLegs = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1780
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "16", x2: "5.5", y2: "18.5" }),
1781
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "17", x2: "8.5", y2: "19.5" }),
1782
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "17", x2: "15.5", y2: "19.5" }),
1783
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "16", x2: "18.5", y2: "18.5" })
1784
- ] });
1785
- function Crab1({ className }) {
1786
1865
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
1787
- SvgShell,
1866
+ Root2$1,
1788
1867
  {
1789
- className,
1790
- d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
1791
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1792
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
1793
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
1794
- ] }),
1795
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1796
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" }),
1797
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" })
1798
- ] }),
1799
- legs: StdLegs,
1800
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1801
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
1802
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" })
1803
- ] })
1868
+ "data-slot": "tabs",
1869
+ "data-orientation": orientation,
1870
+ orientation,
1871
+ className: cn("group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", className),
1872
+ ...props
1804
1873
  }
1805
1874
  );
1806
1875
  }
1807
- function Crab2({ className }) {
1808
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
1809
- SvgShell,
1810
- {
1811
- className,
1812
- d: "M4 13 C4 7 7.5 5.5 12 5.5 C16.5 5.5 20 7 20 13 C20 17.5 16.5 19 12 19 C7.5 19 4 17.5 4 13 Z",
1813
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1814
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "6.5", x2: "9.5", y2: "4.5" }),
1815
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "6.5", x2: "14.5", y2: "4.5" })
1816
- ] }),
1817
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1818
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" }),
1819
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" })
1820
- ] }),
1821
- legs: ShortLegs,
1822
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1823
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C4 9.5 2.5 10 3 12 C3.5 13.5 4.5 13 5 12" }),
1824
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20 9.5 21.5 10 21 12 C20.5 13.5 19.5 13 19 12" })
1825
- ] })
1876
+ const tabsListVariants = cva(
1877
+ "rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
1878
+ {
1879
+ variants: {
1880
+ variant: {
1881
+ default: "bg-muted",
1882
+ line: "gap-1 bg-transparent"
1883
+ }
1884
+ },
1885
+ defaultVariants: {
1886
+ variant: "default"
1826
1887
  }
1827
- );
1828
- }
1829
- function Crab3({ className }) {
1888
+ }
1889
+ );
1890
+ function TabsList({
1891
+ className,
1892
+ variant = "default",
1893
+ ...props
1894
+ }) {
1830
1895
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
1831
- SvgShell,
1896
+ List,
1832
1897
  {
1833
- className,
1834
- d: "M3 13.5 C3 8 7 6 12 6 C17 6 21 8 21 13.5 C21 17 17 19 12 19 C7 19 3 17 3 13.5 Z",
1835
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1836
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "7", x2: "6.5", y2: "4.5" }),
1837
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "7", x2: "17.5", y2: "4.5" })
1838
- ] }),
1839
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1840
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "6.5", cy: "4", r: "0.8", fill: "currentColor", stroke: "none" }),
1841
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17.5", cy: "4", r: "0.8", fill: "currentColor", stroke: "none" })
1842
- ] }),
1843
- legs: StdLegs,
1844
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1845
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M4 12 C2.5 10.5 1 11 1.5 13 C2 14.5 3.5 14 4.5 13" }),
1846
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M20 12 C21.5 10.5 23 11 22.5 13 C22 14.5 20.5 14 19.5 13" })
1847
- ] })
1898
+ "data-slot": "tabs-list",
1899
+ "data-variant": variant,
1900
+ className: cn(tabsListVariants({ variant }), className),
1901
+ ...props
1848
1902
  }
1849
1903
  );
1850
1904
  }
1851
- function Crab4({ className }) {
1905
+ function TabsTrigger({
1906
+ className,
1907
+ ...props
1908
+ }) {
1852
1909
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
1853
- SvgShell,
1910
+ Trigger$2,
1854
1911
  {
1855
- className,
1856
- d: "M6 14 C6 8 9 5.5 12 5.5 C15 5.5 18 8 18 14 C18 18 15 20 12 20 C9 20 6 18 6 14 Z",
1857
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1858
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6.5", x2: "10", y2: "3.5" }),
1859
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "6.5", x2: "14", y2: "3.5" })
1860
- ] }),
1861
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1862
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "10", cy: "3", r: "0.7", fill: "currentColor", stroke: "none" }),
1863
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14", cy: "3", r: "0.7", fill: "currentColor", stroke: "none" })
1864
- ] }),
1865
- legs: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1866
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "17", x2: "5", y2: "20.5" }),
1867
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "18.5", x2: "8.5", y2: "21.5" }),
1868
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "18.5", x2: "15.5", y2: "21.5" }),
1869
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "17", x2: "19", y2: "20.5" })
1870
- ] }),
1871
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1872
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6.5 11 C5 8.5 3 9 3.5 11.5 C4 13.5 5 13 6 12" }),
1873
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M17.5 11 C19 8.5 21 9 20.5 11.5 C20 13.5 19 13 18 12" })
1874
- ] })
1912
+ "data-slot": "tabs-trigger",
1913
+ className: cn(
1914
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1915
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
1916
+ "data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
1917
+ "after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
1918
+ className
1919
+ ),
1920
+ ...props
1875
1921
  }
1876
1922
  );
1877
1923
  }
1878
- function Crab5({ className }) {
1924
+ function TabsContent({
1925
+ className,
1926
+ ...props
1927
+ }) {
1879
1928
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
1880
- SvgShell,
1929
+ Content$1,
1881
1930
  {
1882
- className,
1883
- d: "M5 13 C5 9 8 7 12 7 L13 4 L14 7 C16 7 19 9 19 13 C19 16 16 18 13 18 L12 21 L11 18 C8 18 5 16 5 13 Z",
1884
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1885
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
1886
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
1887
- ] }),
1888
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1889
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.8", fill: "currentColor", stroke: "none" }),
1890
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.8", fill: "currentColor", stroke: "none" })
1891
- ] }),
1892
- legs: StdLegs,
1893
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1894
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
1895
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" })
1896
- ] })
1931
+ "data-slot": "tabs-content",
1932
+ className: cn("flex-1 outline-none", className),
1933
+ ...props
1897
1934
  }
1898
1935
  );
1899
1936
  }
1900
- function Crab6({ className }) {
1901
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
1902
- SvgShell,
1903
- {
1904
- className,
1905
- d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
1906
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1907
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
1908
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
1909
- ] }),
1910
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1911
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" }),
1912
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13.5", y1: "4", x2: "15.5", y2: "5" })
1913
- ] }),
1914
- legs: StdLegs,
1915
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1916
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
1917
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" })
1918
- ] })
1919
- }
1937
+ function useCopyFeedback(text) {
1938
+ const [copied, setCopied] = reactExports.useState(false);
1939
+ const timerRef = reactExports.useRef(null);
1940
+ reactExports.useEffect(
1941
+ () => () => {
1942
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
1943
+ },
1944
+ []
1920
1945
  );
1921
- }
1922
- function Crab7({ className }) {
1923
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
1924
- SvgShell,
1925
- {
1926
- className,
1927
- d: "M5.5 13.5 C5.5 10 8.5 8 12 8 C15.5 8 18.5 10 18.5 13.5 C18.5 16 15.5 17.5 12 17.5 C8.5 17.5 5.5 16 5.5 13.5 Z",
1928
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1929
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "8", x2: "10", y2: "6" }),
1930
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "8", x2: "14", y2: "6" })
1931
- ] }),
1932
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1933
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "6", x2: "11", y2: "6.5" }),
1934
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13", y1: "6", x2: "15", y2: "6.5" })
1935
- ] }),
1936
- legs: ShortLegs,
1937
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1938
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6 11.5 C4.5 10.5 3 11 3.5 12.5 C4 13.5 5 13 5.5 12.5" }),
1939
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M18 11.5 C19.5 10.5 21 11 20.5 12.5 C20 13.5 19 13 18.5 12.5" })
1940
- ] })
1941
- }
1946
+ const copy = reactExports.useCallback(
1947
+ (event) => {
1948
+ event.stopPropagation();
1949
+ if (text === null) return;
1950
+ void copyTextToClipboard(text).then((success) => {
1951
+ if (!success) return;
1952
+ setCopied(true);
1953
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
1954
+ timerRef.current = setTimeout(() => setCopied(false), 2e3);
1955
+ });
1956
+ },
1957
+ [text]
1942
1958
  );
1959
+ return { copied, copy };
1943
1960
  }
1944
- function Crab8({ className }) {
1945
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
1946
- SvgShell,
1947
- {
1948
- className,
1949
- d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
1950
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1951
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
1952
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
1953
- ] }),
1954
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1955
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.7", fill: "currentColor", stroke: "none" }),
1956
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.7", fill: "currentColor", stroke: "none" })
1957
- ] }),
1958
- legs: StdLegs,
1959
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1960
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
1961
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" }),
1962
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "8.5", y1: "4", x2: "10.5", y2: "4.5" }),
1963
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15.5", y1: "4", x2: "13.5", y2: "4.5" }),
1964
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 15.5 C10 14.5 14 14.5 15 15.5" })
1965
- ] })
1966
- }
1961
+ const LazyCompareDrawer = reactExports.lazy(
1962
+ () => import("./CompareDrawer-Dal52IFo.mjs").then((m) => ({ default: m.CompareDrawer }))
1963
+ );
1964
+ const LazyReplayDialog = reactExports.lazy(
1965
+ () => import("./ReplayDialog-BOEgdMes.mjs").then((m) => ({ default: m.ReplayDialog }))
1966
+ );
1967
+ const LazyRequestAnatomy = reactExports.lazy(
1968
+ () => import("./RequestAnatomy-gch7_vCV.mjs").then((m) => ({ default: m.RequestAnatomy }))
1969
+ );
1970
+ const LazyResponseView = reactExports.lazy(
1971
+ () => import("./ResponseView-lEWPy-H4.mjs").then((m) => ({ default: m.ResponseView }))
1972
+ );
1973
+ const LazyStreamingChunkSequence = reactExports.lazy(
1974
+ () => import("./StreamingChunkSequence-DnudbJ1O.mjs").then((m) => ({
1975
+ default: m.StreamingChunkSequence
1976
+ }))
1977
+ );
1978
+ const LazyJsonViewer = reactExports.lazy(
1979
+ () => import("./json-viewer-C2lIVEX3.mjs").then((m) => ({ default: m.JsonViewer }))
1980
+ );
1981
+ const LazyJsonViewerFromString = reactExports.lazy(
1982
+ () => import("./json-viewer-C2lIVEX3.mjs").then((m) => ({ default: m.JsonViewerFromString }))
1983
+ );
1984
+ const HIGHLIGHT_DURATION_MS = 1200;
1985
+ const MAX_HIGHLIGHT_ATTEMPTS = 12;
1986
+ function useAnatomyJump(options) {
1987
+ const { containerRef, setExpandToPath, ensureTabActive, highlightMs } = options;
1988
+ const highlightTimer = reactExports.useRef(null);
1989
+ return reactExports.useCallback(
1990
+ (segment2) => {
1991
+ ensureTabActive?.();
1992
+ setExpandToPath(segment2.path);
1993
+ const applyHighlight = (target) => {
1994
+ target.scrollIntoView({ behavior: "smooth", block: "center" });
1995
+ target.classList.add(
1996
+ "ring-2",
1997
+ "ring-primary/60",
1998
+ "ring-offset-1",
1999
+ "ring-offset-background",
2000
+ "rounded-sm",
2001
+ "transition-shadow"
2002
+ );
2003
+ if (highlightTimer.current !== null) clearTimeout(highlightTimer.current);
2004
+ highlightTimer.current = setTimeout(() => {
2005
+ target.classList.remove(
2006
+ "ring-2",
2007
+ "ring-primary/60",
2008
+ "ring-offset-1",
2009
+ "ring-offset-background",
2010
+ "rounded-sm",
2011
+ "transition-shadow"
2012
+ );
2013
+ setExpandToPath(null);
2014
+ }, highlightMs ?? HIGHLIGHT_DURATION_MS);
2015
+ };
2016
+ const escape = (value) => {
2017
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
2018
+ return CSS.escape(value);
2019
+ }
2020
+ return value.replace(/(["'\\[\](){}])/g, "\\$1");
2021
+ };
2022
+ const selector = `[data-anatomy-path="${escape(segment2.path)}"]`;
2023
+ const tryFindTarget = (attemptsLeft) => {
2024
+ const container = containerRef.current;
2025
+ if (container !== null) {
2026
+ const target = container.querySelector(selector);
2027
+ if (target !== null) {
2028
+ applyHighlight(target);
2029
+ return;
2030
+ }
2031
+ }
2032
+ if (attemptsLeft > 0) {
2033
+ window.requestAnimationFrame(() => tryFindTarget(attemptsLeft - 1));
2034
+ } else {
2035
+ setExpandToPath(null);
2036
+ }
2037
+ };
2038
+ window.requestAnimationFrame(() => tryFindTarget(MAX_HIGHLIGHT_ATTEMPTS));
2039
+ },
2040
+ [containerRef, ensureTabActive, highlightMs, setExpandToPath]
1967
2041
  );
1968
2042
  }
1969
- function Crab9({ className }) {
1970
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
1971
- SvgShell,
1972
- {
1973
- className,
1974
- d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
1975
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1976
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
1977
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
1978
- ] }),
1979
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1980
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "1.2", fill: "none", stroke: "currentColor" }),
1981
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "1.2", fill: "none", stroke: "currentColor" })
1982
- ] }),
1983
- legs: StdLegs,
1984
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1985
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
1986
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" }),
1987
- /* @__PURE__ */ jsxRuntimeExports.jsx("ellipse", { cx: "12", cy: "15", rx: "2", ry: "1.5", fill: "currentColor", stroke: "none" })
1988
- ] })
1989
- }
1990
- );
2043
+ const DEFAULT_FULL_BODY_HYDRATION_ERROR_DETAIL = "The compact log metadata is still available. Retry if the local server was restarting or the body store was briefly unavailable.";
2044
+ function formatBytes$1(bytes) {
2045
+ if (bytes < 1024) return `${bytes.toLocaleString()} B`;
2046
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
2047
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MiB`;
2048
+ return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GiB`;
1991
2049
  }
1992
- function Crab10({ className }) {
1993
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
1994
- SvgShell,
1995
- {
1996
- className,
1997
- d: "M4.5 13 C4.5 8 7.5 6 12 6 C16.5 6 19.5 8 19.5 13 C19.5 17 16.5 18.5 12 18.5 C7.5 18.5 4.5 17 4.5 13 Z",
1998
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1999
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "7", x2: "9", y2: "5" }),
2000
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "7", x2: "15", y2: "5" })
2001
- ] }),
2002
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2003
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9", cy: "4.5", r: "1", fill: "currentColor", stroke: "none" }),
2004
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "15", cy: "4.5", r: "1", fill: "currentColor", stroke: "none" })
2005
- ] }),
2006
- legs: StdLegs,
2007
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2008
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9 2 9.5 2.5 12 C3 14 4 13 5 12" }),
2009
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9 22 9.5 21.5 12 C21 14 20 13 19 12" }),
2010
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 14.5 C10 16 14 16 15 14.5" }),
2011
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "13", r: "1", fill: "currentColor", stroke: "none", opacity: "0.3" }),
2012
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "13", r: "1", fill: "currentColor", stroke: "none", opacity: "0.3" })
2013
- ] })
2014
- }
2015
- );
2050
+ function formatBodyHydrationFootprint(requestBytes, responseBytes) {
2051
+ const parts = [];
2052
+ if (requestBytes !== null && requestBytes !== void 0) {
2053
+ parts.push(`Request ${formatBytes$1(requestBytes)}`);
2054
+ }
2055
+ if (responseBytes !== null && responseBytes !== void 0) {
2056
+ parts.push(`Response ${formatBytes$1(responseBytes)}`);
2057
+ }
2058
+ return parts.length === 0 ? null : parts.join(" · ");
2016
2059
  }
2017
- function Crab11({ className }) {
2018
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
2019
- SvgShell,
2020
- {
2021
- className,
2022
- d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
2023
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2024
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5.5" }),
2025
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5.5" })
2026
- ] }),
2027
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2028
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7.5", y1: "5.5", x2: "16.5", y2: "5.5" }),
2029
- /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "7", y: "5", width: "4", height: "2", rx: "0.5", fill: "currentColor", stroke: "none" }),
2030
- /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "13", y: "5", width: "4", height: "2", rx: "0.5", fill: "currentColor", stroke: "none" })
2031
- ] }),
2032
- legs: StdLegs,
2033
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2034
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
2035
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" }),
2036
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9.5 15 C10.5 16 13.5 16 14.5 15" })
2037
- ] })
2038
- }
2039
- );
2060
+ function describeFullBodyHydrationError(error) {
2061
+ if (error instanceof ApiTimeoutError) {
2062
+ return {
2063
+ title: "Full bodies timed out",
2064
+ detail: "The log store did not answer before the UI timeout. Compact metadata is still available; retry loading the bodies."
2065
+ };
2066
+ }
2067
+ if (error instanceof Error) {
2068
+ const message = error.message.trim();
2069
+ return {
2070
+ title: "Full bodies could not be loaded",
2071
+ detail: message === "" ? DEFAULT_FULL_BODY_HYDRATION_ERROR_DETAIL : message
2072
+ };
2073
+ }
2074
+ return {
2075
+ title: "Full bodies could not be loaded",
2076
+ detail: DEFAULT_FULL_BODY_HYDRATION_ERROR_DETAIL
2077
+ };
2040
2078
  }
2041
- function Crab12({ className }) {
2042
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
2043
- SvgShell,
2044
- {
2045
- className,
2046
- d: "M7 13.5 C7 10.5 9.5 9 12 9 C14.5 9 17 10.5 17 13.5 C17 16 14.5 17.5 12 17.5 C9.5 17.5 7 16 7 13.5 Z",
2047
- eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2048
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10.5", y1: "9.5", x2: "10.5", y2: "8" }),
2049
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13.5", y1: "9.5", x2: "13.5", y2: "8" })
2050
- ] }),
2051
- eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2052
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "10.5", cy: "7.5", r: "0.8", fill: "currentColor", stroke: "none" }),
2053
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "13.5", cy: "7.5", r: "0.8", fill: "currentColor", stroke: "none" })
2054
- ] }),
2055
- legs: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2056
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "8", y1: "16", x2: "6.5", y2: "18" }),
2057
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "17", x2: "9.5", y2: "19" }),
2058
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "17", x2: "14.5", y2: "19" }),
2059
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "16", y1: "16", x2: "17.5", y2: "18" })
2060
- ] }),
2061
- extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2062
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M7.5 12 C6.5 11 5.5 11.5 6 13 C6.5 14 7 13.5 7.5 13" }),
2063
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16.5 12 C17.5 11 18.5 11.5 18 13 C17.5 14 17 13.5 16.5 13" })
2064
- ] })
2065
- }
2066
- );
2067
- }
2068
- const crabVariants = [
2069
- Crab1,
2070
- Crab2,
2071
- Crab3,
2072
- Crab4,
2073
- Crab5,
2074
- Crab6,
2075
- Crab7,
2076
- Crab8,
2077
- Crab9,
2078
- Crab10,
2079
- Crab11,
2080
- Crab12
2081
- ];
2082
- function getCrabVariant(index) {
2083
- return crabVariants[Math.abs(index) % crabVariants.length] ?? Crab1;
2084
- }
2085
- function getInteriorCrabVariantIndex(seed) {
2086
- const interiorCount = crabVariants.length - 2;
2087
- if (interiorCount <= 0) return 0;
2088
- const normalizedSeed = Number.isFinite(seed) ? Math.trunc(seed) : 0;
2089
- return 1 + (normalizedSeed % interiorCount + interiorCount) % interiorCount;
2090
- }
2091
- function getInteriorCrabVariant(seed) {
2092
- return getCrabVariant(getInteriorCrabVariantIndex(seed));
2079
+ function normalizeHeaders(headers) {
2080
+ if (headers === void 0) return [];
2081
+ return Object.entries(headers).map((entry) => [entry[0].toLowerCase(), entry[1]]).sort(([a], [b]) => a.localeCompare(b));
2093
2082
  }
2094
- const FULL_EXPAND_NODE_LIMIT = 400;
2095
- const STRUCTURE_EXPAND_NODE_LIMIT = 2e3;
2096
- function isJsonArray(value) {
2097
- return Array.isArray(value);
2083
+ function headerLine([key, value]) {
2084
+ return `${key}: ${value}`;
2098
2085
  }
2099
- function countJsonNodesUpTo(value, limit) {
2100
- const stack = [value];
2101
- let count = 0;
2102
- while (stack.length > 0) {
2103
- const current = stack.pop();
2104
- if (current === void 0) continue;
2105
- count += 1;
2106
- if (count > limit) return count;
2107
- if (current === null || typeof current !== "object") continue;
2108
- if (isJsonArray(current)) {
2109
- for (const child of current) {
2110
- stack.push(child);
2086
+ function changesToLines(changes) {
2087
+ const lines = [];
2088
+ let oldNum = 0;
2089
+ let newNum = 0;
2090
+ for (const change of changes) {
2091
+ const parts = change.value.split("\n");
2092
+ if (parts.length > 0 && parts[parts.length - 1] === "") parts.pop();
2093
+ for (const text of parts) {
2094
+ if (change.added) {
2095
+ newNum += 1;
2096
+ lines.push({ kind: "added", text, oldLineNumber: null, newLineNumber: newNum });
2097
+ } else if (change.removed) {
2098
+ oldNum += 1;
2099
+ lines.push({ kind: "removed", text, oldLineNumber: oldNum, newLineNumber: null });
2100
+ } else {
2101
+ oldNum += 1;
2102
+ newNum += 1;
2103
+ lines.push({
2104
+ kind: "context",
2105
+ text,
2106
+ oldLineNumber: oldNum,
2107
+ newLineNumber: newNum
2108
+ });
2111
2109
  }
2112
- continue;
2113
- }
2114
- for (const key of Object.keys(current)) {
2115
- const child = current[key];
2116
- if (child !== void 0) stack.push(child);
2117
2110
  }
2118
2111
  }
2119
- return count;
2112
+ return lines;
2120
2113
  }
2121
- function getJsonExpansionPolicy(value) {
2122
- const nodeCount = countJsonNodesUpTo(value, STRUCTURE_EXPAND_NODE_LIMIT + 1);
2123
- if (nodeCount <= FULL_EXPAND_NODE_LIMIT) return { depth: Number.POSITIVE_INFINITY };
2124
- if (nodeCount <= STRUCTURE_EXPAND_NODE_LIMIT) return { depth: 3 };
2125
- return { depth: 2 };
2114
+ function computeHeadersDiff(rawHeaders, processedHeaders) {
2115
+ const left = normalizeHeaders(rawHeaders).map(headerLine).join("\n");
2116
+ const right = normalizeHeaders(processedHeaders).map(headerLine).join("\n");
2117
+ if (left === right) {
2118
+ return { lines: [], isEmpty: true };
2119
+ }
2120
+ const changes = diffLines(left, right);
2121
+ return { lines: changesToLines(changes), isEmpty: false };
2126
2122
  }
2127
- function parseJsonText(text) {
2123
+ function tryParseJson(text) {
2128
2124
  try {
2129
2125
  const parsed = JSON.parse(text);
2130
- return { kind: "json", data: safeJsonValue(parsed) };
2126
+ if (parsed === null) return parsed;
2127
+ if (typeof parsed === "string" || typeof parsed === "object") return parsed;
2128
+ return null;
2131
2129
  } catch {
2132
- return { kind: "text" };
2130
+ return null;
2133
2131
  }
2134
2132
  }
2135
- function useJsonBulkExpansion(text) {
2136
- const parsed = reactExports.useMemo(() => text === null ? null : parseJsonText(text), [text]);
2137
- const parsedData = parsed?.kind === "json" ? parsed.data : null;
2138
- const policy = reactExports.useMemo(
2139
- () => parsedData === null ? null : getJsonExpansionPolicy(parsedData),
2140
- [parsedData]
2141
- );
2142
- const [isExpanded, setIsExpanded] = reactExports.useState(false);
2143
- const [bulkDepth, setBulkDepth] = reactExports.useState(0);
2144
- const [bulkRevision, setBulkRevision] = reactExports.useState(0);
2145
- const [isPending, startTransition] = reactExports.useTransition();
2146
- const toggle = reactExports.useCallback(() => {
2147
- const nextExpanded = !isExpanded;
2148
- const targetDepth = nextExpanded && policy !== null ? policy.depth : 0;
2149
- startTransition(() => {
2150
- setIsExpanded(nextExpanded);
2151
- setBulkDepth(targetDepth);
2152
- setBulkRevision((current) => current + 1);
2153
- });
2154
- }, [isExpanded, policy]);
2155
- return { parsedData, policy, isExpanded, toggle, isPending, bulkDepth, bulkRevision };
2156
- }
2157
- function safeJsonValue(value) {
2158
- if (value === null || value === void 0) return null;
2159
- switch (typeof value) {
2160
- case "string":
2161
- return value;
2162
- case "number":
2163
- return value;
2164
- case "boolean":
2165
- return value;
2166
- case "object": {
2167
- if (Array.isArray(value)) {
2168
- return value.map((item) => safeJsonValue(item));
2169
- }
2170
- const result = {};
2171
- for (const key of Object.keys(value)) {
2172
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
2173
- result[key] = safeJsonValue(descriptor?.value);
2133
+ function computeRequestDiff(rawBody, processedBody) {
2134
+ const left = rawBody ?? "";
2135
+ const right = processedBody ?? "";
2136
+ if (left === right) {
2137
+ return { lines: [], isEmpty: true };
2138
+ }
2139
+ const leftJson = tryParseJson(left);
2140
+ const rightJson = tryParseJson(right);
2141
+ if (leftJson !== null && rightJson !== null) {
2142
+ const changes2 = diffJson(leftJson, rightJson) ?? [];
2143
+ if (changes2.length === 1) {
2144
+ const first = changes2[0];
2145
+ if (first !== void 0 && !first.added && !first.removed) {
2146
+ return { lines: [], isEmpty: true };
2174
2147
  }
2175
- return result;
2176
2148
  }
2177
- case "bigint":
2178
- case "symbol":
2179
- case "function":
2180
- case "undefined":
2181
- return String(value);
2149
+ return { lines: changesToLines(changes2), isEmpty: false };
2182
2150
  }
2183
- return null;
2151
+ const changes = diffLines(left, right);
2152
+ return { lines: changesToLines(changes), isEmpty: false };
2184
2153
  }
2185
- function Tabs({
2186
- className,
2187
- orientation = "horizontal",
2188
- ...props
2189
- }) {
2190
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
2191
- Root2$1,
2192
- {
2193
- "data-slot": "tabs",
2194
- "data-orientation": orientation,
2195
- orientation,
2196
- className: cn("group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", className),
2197
- ...props
2198
- }
2199
- );
2154
+ const ESTIMATED_LINE_HEIGHT = 22;
2155
+ const MAX_RENDERED_LINES = 1e4;
2156
+ function kindPrefix(kind) {
2157
+ if (kind === "added") return "+";
2158
+ if (kind === "removed") return "-";
2159
+ return " ";
2200
2160
  }
2201
- const tabsListVariants = cva(
2202
- "rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
2203
- {
2204
- variants: {
2205
- variant: {
2206
- default: "bg-muted",
2207
- line: "gap-1 bg-transparent"
2208
- }
2209
- },
2210
- defaultVariants: {
2211
- variant: "default"
2212
- }
2161
+ function kindClass(kind) {
2162
+ if (kind === "added") {
2163
+ return "bg-green-500/10 text-green-700 dark:text-green-300";
2213
2164
  }
2214
- );
2215
- function TabsList({
2216
- className,
2217
- variant = "default",
2218
- ...props
2219
- }) {
2220
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
2221
- List,
2222
- {
2223
- "data-slot": "tabs-list",
2224
- "data-variant": variant,
2225
- className: cn(tabsListVariants({ variant }), className),
2226
- ...props
2227
- }
2228
- );
2229
- }
2230
- function TabsTrigger({
2231
- className,
2232
- ...props
2233
- }) {
2234
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
2235
- Trigger$2,
2236
- {
2237
- "data-slot": "tabs-trigger",
2238
- className: cn(
2239
- "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2240
- "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
2241
- "data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
2242
- "after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
2243
- className
2244
- ),
2245
- ...props
2246
- }
2247
- );
2248
- }
2249
- function TabsContent({
2250
- className,
2251
- ...props
2252
- }) {
2253
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
2254
- Content$1,
2255
- {
2256
- "data-slot": "tabs-content",
2257
- className: cn("flex-1 outline-none", className),
2258
- ...props
2259
- }
2260
- );
2261
- }
2262
- function useCopyFeedback(text) {
2263
- const [copied, setCopied] = reactExports.useState(false);
2264
- const timerRef = reactExports.useRef(null);
2265
- reactExports.useEffect(
2266
- () => () => {
2267
- if (timerRef.current !== null) clearTimeout(timerRef.current);
2268
- },
2269
- []
2270
- );
2271
- const copy = reactExports.useCallback(
2272
- (event) => {
2273
- event.stopPropagation();
2274
- if (text === null) return;
2275
- void copyTextToClipboard(text).then((success) => {
2276
- if (!success) return;
2277
- setCopied(true);
2278
- if (timerRef.current !== null) clearTimeout(timerRef.current);
2279
- timerRef.current = setTimeout(() => setCopied(false), 2e3);
2280
- });
2281
- },
2282
- [text]
2283
- );
2284
- return { copied, copy };
2285
- }
2286
- const LazyCompareDrawer = reactExports.lazy(
2287
- () => import("./CompareDrawer-CO-Ti5sg.mjs").then((m) => ({ default: m.CompareDrawer }))
2288
- );
2289
- const LazyReplayDialog = reactExports.lazy(
2290
- () => import("./ReplayDialog-J1VxC0In.mjs").then((m) => ({ default: m.ReplayDialog }))
2291
- );
2292
- const LazyRequestAnatomy = reactExports.lazy(
2293
- () => import("./RequestAnatomy-DBH-F3rq.mjs").then((m) => ({ default: m.RequestAnatomy }))
2294
- );
2295
- const LazyResponseView = reactExports.lazy(
2296
- () => import("./ResponseView-DLFwV7Hd.mjs").then((m) => ({ default: m.ResponseView }))
2297
- );
2298
- const LazyStreamingChunkSequence = reactExports.lazy(
2299
- () => import("./StreamingChunkSequence-BywmuND0.mjs").then((m) => ({
2300
- default: m.StreamingChunkSequence
2301
- }))
2302
- );
2303
- const LazyJsonViewer = reactExports.lazy(
2304
- () => import("./json-viewer-DlQu0N1x.mjs").then((m) => ({ default: m.JsonViewer }))
2305
- );
2306
- const LazyJsonViewerFromString = reactExports.lazy(
2307
- () => import("./json-viewer-DlQu0N1x.mjs").then((m) => ({ default: m.JsonViewerFromString }))
2308
- );
2309
- const HIGHLIGHT_DURATION_MS = 1200;
2310
- const MAX_HIGHLIGHT_ATTEMPTS = 12;
2311
- function useAnatomyJump(options) {
2312
- const { containerRef, setExpandToPath, ensureTabActive, highlightMs } = options;
2313
- const highlightTimer = reactExports.useRef(null);
2314
- return reactExports.useCallback(
2315
- (segment2) => {
2316
- ensureTabActive?.();
2317
- setExpandToPath(segment2.path);
2318
- const applyHighlight = (target) => {
2319
- target.scrollIntoView({ behavior: "smooth", block: "center" });
2320
- target.classList.add(
2321
- "ring-2",
2322
- "ring-primary/60",
2323
- "ring-offset-1",
2324
- "ring-offset-background",
2325
- "rounded-sm",
2326
- "transition-shadow"
2327
- );
2328
- if (highlightTimer.current !== null) clearTimeout(highlightTimer.current);
2329
- highlightTimer.current = setTimeout(() => {
2330
- target.classList.remove(
2331
- "ring-2",
2332
- "ring-primary/60",
2333
- "ring-offset-1",
2334
- "ring-offset-background",
2335
- "rounded-sm",
2336
- "transition-shadow"
2337
- );
2338
- setExpandToPath(null);
2339
- }, highlightMs ?? HIGHLIGHT_DURATION_MS);
2340
- };
2341
- const escape = (value) => {
2342
- if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
2343
- return CSS.escape(value);
2344
- }
2345
- return value.replace(/(["'\\[\](){}])/g, "\\$1");
2346
- };
2347
- const selector = `[data-anatomy-path="${escape(segment2.path)}"]`;
2348
- const tryFindTarget = (attemptsLeft) => {
2349
- const container = containerRef.current;
2350
- if (container !== null) {
2351
- const target = container.querySelector(selector);
2352
- if (target !== null) {
2353
- applyHighlight(target);
2354
- return;
2355
- }
2356
- }
2357
- if (attemptsLeft > 0) {
2358
- window.requestAnimationFrame(() => tryFindTarget(attemptsLeft - 1));
2359
- } else {
2360
- setExpandToPath(null);
2361
- }
2362
- };
2363
- window.requestAnimationFrame(() => tryFindTarget(MAX_HIGHLIGHT_ATTEMPTS));
2364
- },
2365
- [containerRef, ensureTabActive, highlightMs, setExpandToPath]
2366
- );
2367
- }
2368
- function normalizeHeaders(headers) {
2369
- if (headers === void 0) return [];
2370
- return Object.entries(headers).map((entry) => [entry[0].toLowerCase(), entry[1]]).sort(([a], [b]) => a.localeCompare(b));
2371
- }
2372
- function headerLine([key, value]) {
2373
- return `${key}: ${value}`;
2374
- }
2375
- function changesToLines(changes) {
2376
- const lines = [];
2377
- let oldNum = 0;
2378
- let newNum = 0;
2379
- for (const change of changes) {
2380
- const parts = change.value.split("\n");
2381
- if (parts.length > 0 && parts[parts.length - 1] === "") parts.pop();
2382
- for (const text of parts) {
2383
- if (change.added) {
2384
- newNum += 1;
2385
- lines.push({ kind: "added", text, oldLineNumber: null, newLineNumber: newNum });
2386
- } else if (change.removed) {
2387
- oldNum += 1;
2388
- lines.push({ kind: "removed", text, oldLineNumber: oldNum, newLineNumber: null });
2389
- } else {
2390
- oldNum += 1;
2391
- newNum += 1;
2392
- lines.push({
2393
- kind: "context",
2394
- text,
2395
- oldLineNumber: oldNum,
2396
- newLineNumber: newNum
2397
- });
2398
- }
2399
- }
2400
- }
2401
- return lines;
2402
- }
2403
- function computeHeadersDiff(rawHeaders, processedHeaders) {
2404
- const left = normalizeHeaders(rawHeaders).map(headerLine).join("\n");
2405
- const right = normalizeHeaders(processedHeaders).map(headerLine).join("\n");
2406
- if (left === right) {
2407
- return { lines: [], isEmpty: true };
2408
- }
2409
- const changes = diffLines(left, right);
2410
- return { lines: changesToLines(changes), isEmpty: false };
2411
- }
2412
- function tryParseJson(text) {
2413
- try {
2414
- const parsed = JSON.parse(text);
2415
- if (parsed === null) return parsed;
2416
- if (typeof parsed === "string" || typeof parsed === "object") return parsed;
2417
- return null;
2418
- } catch {
2419
- return null;
2420
- }
2421
- }
2422
- function computeRequestDiff(rawBody, processedBody) {
2423
- const left = rawBody ?? "";
2424
- const right = processedBody ?? "";
2425
- if (left === right) {
2426
- return { lines: [], isEmpty: true };
2427
- }
2428
- const leftJson = tryParseJson(left);
2429
- const rightJson = tryParseJson(right);
2430
- if (leftJson !== null && rightJson !== null) {
2431
- const changes2 = diffJson(leftJson, rightJson) ?? [];
2432
- if (changes2.length === 1) {
2433
- const first = changes2[0];
2434
- if (first !== void 0 && !first.added && !first.removed) {
2435
- return { lines: [], isEmpty: true };
2436
- }
2437
- }
2438
- return { lines: changesToLines(changes2), isEmpty: false };
2439
- }
2440
- const changes = diffLines(left, right);
2441
- return { lines: changesToLines(changes), isEmpty: false };
2442
- }
2443
- const ESTIMATED_LINE_HEIGHT = 22;
2444
- const MAX_RENDERED_LINES = 1e4;
2445
- function kindPrefix(kind) {
2446
- if (kind === "added") return "+";
2447
- if (kind === "removed") return "-";
2448
- return " ";
2449
- }
2450
- function kindClass(kind) {
2451
- if (kind === "added") {
2452
- return "bg-green-500/10 text-green-700 dark:text-green-300";
2453
- }
2454
- if (kind === "removed") {
2455
- return "bg-red-500/10 text-red-700 dark:text-red-300";
2456
- }
2457
- return "text-foreground/80";
2165
+ if (kind === "removed") {
2166
+ return "bg-red-500/10 text-red-700 dark:text-red-300";
2167
+ }
2168
+ return "text-foreground/80";
2458
2169
  }
2459
2170
  const DiffViewInner = function DiffView2({ result, emptyLabel }) {
2460
2171
  const [mode, setMode] = reactExports.useState("unified");
@@ -2814,6 +2525,8 @@ const LogEntryHeader = reactExports.memo(function({
2814
2525
  const hasClientCwd = log.clientCwd !== null && log.clientCwd !== void 0 && log.clientCwd !== "";
2815
2526
  const statusCue = STATUS_CUE_CLASSES[statusCategory];
2816
2527
  const statusLabel2 = statusCueLabel(statusCategory, log.responseStatus);
2528
+ const showStatusBadge = statusCategory !== "success" || log.responseStatus !== 200;
2529
+ const showStandaloneStreamingIndicator = log.streaming && firstChunkLabel === null && tokenRateLabel === null;
2817
2530
  return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2818
2531
  "div",
2819
2532
  {
@@ -2823,7 +2536,7 @@ const LogEntryHeader = reactExports.memo(function({
2823
2536
  "data-nav-id": `log-${log.id}`,
2824
2537
  "data-nav-action": expanded ? "collapse" : "expand",
2825
2538
  className: cn(
2826
- "group/header relative isolate flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 overflow-hidden px-3 py-2 cursor-pointer transition-[background-color,border-color,box-shadow]",
2539
+ "group/header relative isolate flex min-w-0 cursor-pointer items-start gap-2 overflow-hidden px-3 py-2 transition-[background-color,border-color,box-shadow]",
2827
2540
  expanded ? "bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.10)]" : "bg-transparent hover:bg-white/[0.035]",
2828
2541
  "select-none before:pointer-events-none before:absolute before:inset-x-3 before:top-0 before:h-px before:bg-white/12",
2829
2542
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
@@ -2836,277 +2549,286 @@ const LogEntryHeader = reactExports.memo(function({
2836
2549
  }
2837
2550
  },
2838
2551
  children: [
2839
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
2840
- "span",
2841
- {
2842
- className: cn(
2843
- "border border-border bg-muted/40 inline-flex h-8 shrink-0 items-center gap-2 rounded-md px-2 font-mono",
2844
- statusCue.frame
2845
- ),
2846
- children: [
2847
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("size-1.5 rounded-full", statusCue.dot), "aria-hidden": "true" }),
2848
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-semibold tabular-nums", title: `Log ID ${String(log.id)}`, children: [
2849
- "#",
2850
- displayNumber
2851
- ] })
2852
- ]
2853
- }
2854
- ),
2855
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "border border-border bg-muted/40 flex h-7 shrink-0 items-center gap-1 rounded-md px-2 text-xs text-muted-foreground", children: [
2856
- /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2857
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", title: log.timestamp, children: formatTimestamp$2(log.timestamp, timeDisplayFormat) })
2858
- ] }),
2859
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
2860
- Badge,
2861
- {
2862
- variant: "outline",
2863
- className: cn(
2864
- "h-6 gap-1 rounded-md px-2 py-0 font-mono text-[10px] font-semibold uppercase tabular-nums shadow-[inset_0_1px_0_rgba(255,255,255,0.05)]",
2865
- STATUS_BADGE_CLASSES[statusCategory]
2866
- ),
2867
- children: [
2868
- statusCategory === "success" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3", "aria-label": "Success" }) : statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(OctagonAlert, { className: "size-3", "aria-label": "Server error" }) : statusCategory === "client_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Client error" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin", "aria-label": "Pending" }),
2869
- statusLabel2
2870
- ]
2871
- }
2872
- ),
2873
- warningCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2874
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2875
- Badge,
2552
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-x-2 gap-y-1", children: [
2553
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2554
+ "span",
2876
2555
  {
2877
- variant: "outline",
2878
- className: "h-6 gap-1 rounded-md border-amber-300/30 bg-amber-300/[0.10] px-2 py-0 font-mono text-[10px] tabular-nums text-amber-100",
2556
+ className: cn(
2557
+ "border border-border bg-muted/40 inline-flex h-8 shrink-0 items-center gap-2 rounded-md px-2 font-mono",
2558
+ statusCue.frame
2559
+ ),
2879
2560
  children: [
2880
- /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Tool schema warnings" }),
2881
- warningCount
2561
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("size-1.5 rounded-full", statusCue.dot), "aria-hidden": "true" }),
2562
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-semibold tabular-nums", title: `Log ID ${String(log.id)}`, children: [
2563
+ "#",
2564
+ displayNumber
2565
+ ] })
2882
2566
  ]
2883
2567
  }
2884
- ) }),
2885
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: warningCount === 1 ? "1 tool schema warning" : `${warningCount} tool schema warnings` })
2886
- ] }),
2887
- log.elapsedMs !== null && (isSlowResponse ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2888
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2889
- "span",
2568
+ ),
2569
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "border border-border bg-muted/40 flex h-7 shrink-0 items-center gap-1 rounded-md px-2 text-xs text-muted-foreground", children: [
2570
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2571
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", title: log.timestamp, children: formatTimestamp$2(log.timestamp, timeDisplayFormat) })
2572
+ ] }),
2573
+ showStatusBadge && /* @__PURE__ */ jsxRuntimeExports.jsxs(
2574
+ Badge,
2890
2575
  {
2576
+ variant: "outline",
2891
2577
  className: cn(
2892
- TELEMETRY_CHIP_CLASS,
2893
- "shrink-0 border-amber-300/25 text-amber-200"
2578
+ "h-6 gap-1 rounded-md px-2 py-0 font-mono text-[10px] font-semibold uppercase tabular-nums shadow-[inset_0_1px_0_rgba(255,255,255,0.05)]",
2579
+ STATUS_BADGE_CLASSES[statusCategory]
2894
2580
  ),
2895
2581
  children: [
2896
- /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2897
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$3(log.elapsedMs) }),
2898
- /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Slow response" })
2582
+ statusCategory === "success" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3", "aria-label": "Success" }) : statusCategory === "server_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(OctagonAlert, { className: "size-3", "aria-label": "Server error" }) : statusCategory === "client_error" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Client error" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin", "aria-label": "Pending" }),
2583
+ statusLabel2
2899
2584
  ]
2900
2585
  }
2901
- ) }),
2902
- /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContent, { children: [
2903
- "Slow response: ",
2904
- formatElapsed$3(log.elapsedMs),
2905
- " exceeds",
2906
- " ",
2907
- formatElapsed$3(slowResponseThresholdSeconds * 1e3)
2908
- ] })
2909
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-muted-foreground"), children: [
2910
- /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2911
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$3(log.elapsedMs) })
2912
- ] })),
2913
- log.streaming && firstChunkLabel !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2914
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-cyan-300"), children: [
2915
- /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3" }),
2916
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
2917
- "first ",
2918
- firstChunkLabel
2919
- ] })
2920
- ] }) }),
2921
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Time to first streaming chunk" })
2922
- ] }),
2923
- log.streaming && tokenRateLabel !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2924
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-cyan-300"), children: [
2925
- /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { className: "size-3" }),
2926
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: tokenRateLabel })
2927
- ] }) }),
2928
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Output token throughput after first chunk" })
2929
- ] }),
2930
- hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "min-w-0 sm:shrink-0"), children: [
2931
- /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
2932
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 flex-wrap items-center gap-x-1 font-mono tabular-nums", children: [
2933
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
2934
- "span",
2586
+ ),
2587
+ warningCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2588
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2589
+ Badge,
2935
2590
  {
2936
- className: cn(
2937
- "whitespace-nowrap",
2938
- log.inputTokens !== null ? "text-blue-400" : "text-muted-foreground"
2939
- ),
2591
+ variant: "outline",
2592
+ className: "h-6 gap-1 rounded-md border-amber-300/30 bg-amber-300/[0.10] px-2 py-0 font-mono text-[10px] tabular-nums text-amber-100",
2940
2593
  children: [
2941
- "IN ",
2942
- log.inputTokens !== null ? formatTokens(log.inputTokens) : "n/a"
2594
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Tool schema warnings" }),
2595
+ warningCount
2943
2596
  ]
2944
2597
  }
2945
- ),
2946
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "/" }),
2947
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
2598
+ ) }),
2599
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: warningCount === 1 ? "1 tool schema warning" : `${warningCount} tool schema warnings` })
2600
+ ] }),
2601
+ log.elapsedMs !== null && (isSlowResponse ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2602
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2948
2603
  "span",
2949
2604
  {
2950
2605
  className: cn(
2951
- "whitespace-nowrap",
2952
- log.outputTokens !== null ? "text-amber-400" : "text-muted-foreground"
2606
+ TELEMETRY_CHIP_CLASS,
2607
+ "shrink-0 border-amber-300/25 text-amber-200"
2953
2608
  ),
2954
2609
  children: [
2955
- "OUT ",
2956
- log.outputTokens !== null ? formatTokens(log.outputTokens) : "n/a"
2610
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2611
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$3(log.elapsedMs) }),
2612
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Slow response" })
2957
2613
  ]
2958
2614
  }
2959
- )
2960
- ] })
2961
- ] }),
2962
- log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0"), children: [
2963
- /* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.creation ?? null }),
2964
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-cyan-300", children: [
2965
- "KV Cache +",
2966
- formatTokens(log.cacheCreationInputTokens)
2967
- ] })
2968
- ] }),
2969
- log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0"), children: [
2970
- /* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.read ?? null }),
2971
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
2972
- "KV Cache ~",
2973
- formatTokens(log.cacheReadInputTokens)
2974
- ] })
2975
- ] }),
2976
- messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-muted-foreground"), children: [
2977
- /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
2978
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: messageCount })
2979
- ] }),
2980
- toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-muted-foreground"), children: [
2981
- /* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
2982
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: toolCount })
2983
- ] }),
2984
- log.origin !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
2985
- "span",
2986
- {
2987
- className: cn(TELEMETRY_CHIP_CLASS, "hidden shrink-0 text-muted-foreground xl:flex"),
2988
- title: `Origin: ${log.origin}`,
2989
- children: [
2990
- /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { className: "size-3" }),
2991
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[120px]", title: log.origin, children: log.origin })
2992
- ]
2993
- }
2994
- ),
2995
- showClientMetadata && (hasClientPid || hasClientProjectFolder) && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2996
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "hidden shrink-0 text-purple-300 xl:flex"), children: [
2997
- /* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
2998
- hasClientProjectFolder ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
2999
- "PID ",
3000
- log.clientPid
2615
+ ) }),
2616
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContent, { children: [
2617
+ "Slow response: ",
2618
+ formatElapsed$3(log.elapsedMs),
2619
+ " exceeds",
2620
+ " ",
2621
+ formatElapsed$3(slowResponseThresholdSeconds * 1e3)
3001
2622
  ] })
3002
- ] }) }),
3003
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: hasClientCwd ? `PID: ${log.clientPid ?? "?"} CWD: ${log.clientCwd}` : `Process ID: ${log.clientPid ?? "?"}` })
3004
- ] }),
3005
- log.streaming && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3006
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3 text-muted-foreground/60 shrink-0" }) }),
3007
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request used SSE streaming" })
3008
- ] }),
3009
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
3010
- expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs(
3011
- "span",
3012
- {
3013
- className: "flex items-center gap-1.5 shrink-0",
3014
- onClick: (e) => e.stopPropagation(),
3015
- onKeyDown: (e) => e.stopPropagation(),
3016
- children: [
3017
- tabActions !== void 0 && activeTab !== void 0 && (() => {
3018
- const action = tabActions[activeTab];
3019
- if (action === void 0) return null;
3020
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3021
- action.expansion !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3022
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3023
- Button,
3024
- {
3025
- variant: "outline",
3026
- size: "icon",
3027
- className: HEADER_ACTION_BUTTON_CLASS,
3028
- onClick: action.expansion.onToggle,
3029
- disabled: action.expansion.isPending,
3030
- "aria-pressed": action.expansion.isExpanded,
3031
- "aria-label": action.expansion.isExpanded ? "Collapse all JSON" : "Expand all JSON",
3032
- children: action.expansion.isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5" })
3033
- }
3034
- ) }),
3035
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.expansion.isExpanded ? "Collapse all JSON nodes" : "Expand all JSON nodes" })
3036
- ] }),
3037
- action.diffWithRaw !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3038
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3039
- Button,
3040
- {
3041
- variant: "outline",
3042
- size: "icon",
3043
- className: cn(
3044
- HEADER_ACTION_BUTTON_CLASS,
3045
- action.diffWithRaw.active && "border-cyan-300/35 bg-cyan-400/15 text-cyan-100"
3046
- ),
3047
- onClick: action.diffWithRaw.onToggle,
3048
- "aria-pressed": action.diffWithRaw.active,
3049
- "aria-label": action.diffWithRaw.active ? "Hide raw diff" : "Diff with raw",
3050
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FileDiff, { className: "size-3.5" })
3051
- }
3052
- ) }),
3053
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.diffWithRaw.active ? "Hide diff with raw request" : "Show diff between displayed and raw request body" })
3054
- ] }),
3055
- action.diffWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3056
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3057
- Button,
3058
- {
3059
- variant: "outline",
3060
- size: "icon",
3061
- className: HEADER_ACTION_BUTTON_CLASS,
3062
- onClick: action.diffWithPrevious,
3063
- "aria-label": "Diff with previous",
3064
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(History, { className: "size-3.5" })
3065
- }
3066
- ) }),
3067
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
3068
- ] }),
3069
- action.copyText !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3070
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3071
- Button,
3072
- {
3073
- variant: "outline",
3074
- size: "icon",
3075
- className: HEADER_ACTION_BUTTON_CLASS,
3076
- onClick: action.onCopy,
3077
- "aria-label": action.copyCopied ? "Copied" : action.copyLabel,
3078
- children: action.copyCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-cyan-300" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
3079
- }
3080
- ) }),
3081
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.copyCopied ? "Copied to clipboard" : action.copyLabel })
3082
- ] })
3083
- ] });
3084
- })(),
3085
- onReplay !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
3086
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3087
- Button,
3088
- {
3089
- variant: "outline",
3090
- size: "icon",
3091
- className: HEADER_ACTION_BUTTON_CLASS,
3092
- onClick: onReplay,
3093
- "aria-label": "Replay request",
3094
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-3.5" })
3095
- }
3096
- ) }),
3097
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-send this request to the provider" })
2623
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-muted-foreground"), children: [
2624
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
2625
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$3(log.elapsedMs) })
2626
+ ] })),
2627
+ log.streaming && firstChunkLabel !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2628
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-cyan-300"), children: [
2629
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3" }),
2630
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
2631
+ "first ",
2632
+ firstChunkLabel
3098
2633
  ] })
3099
- ]
3100
- }
3101
- ),
3102
- /* @__PURE__ */ jsxRuntimeExports.jsx(
3103
- "span",
3104
- {
3105
- className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 items-center justify-center rounded-md text-slate-200",
3106
- "aria-hidden": "true",
3107
- children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 shrink-0" })
3108
- }
3109
- )
2634
+ ] }) }),
2635
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Time to first streaming chunk" })
2636
+ ] }),
2637
+ log.streaming && tokenRateLabel !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2638
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-cyan-300"), children: [
2639
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { className: "size-3" }),
2640
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: tokenRateLabel })
2641
+ ] }) }),
2642
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Output token throughput after first chunk" })
2643
+ ] }),
2644
+ hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "min-w-0 sm:shrink-0"), children: [
2645
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
2646
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 flex-wrap items-center gap-x-1 font-mono tabular-nums", children: [
2647
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2648
+ "span",
2649
+ {
2650
+ className: cn(
2651
+ "whitespace-nowrap",
2652
+ log.inputTokens !== null ? "text-blue-400" : "text-muted-foreground"
2653
+ ),
2654
+ children: [
2655
+ "IN ",
2656
+ log.inputTokens !== null ? formatTokens(log.inputTokens) : "n/a"
2657
+ ]
2658
+ }
2659
+ ),
2660
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "/" }),
2661
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2662
+ "span",
2663
+ {
2664
+ className: cn(
2665
+ "whitespace-nowrap",
2666
+ log.outputTokens !== null ? "text-amber-400" : "text-muted-foreground"
2667
+ ),
2668
+ children: [
2669
+ "OUT ",
2670
+ log.outputTokens !== null ? formatTokens(log.outputTokens) : "n/a"
2671
+ ]
2672
+ }
2673
+ )
2674
+ ] })
2675
+ ] }),
2676
+ log.cacheCreationInputTokens !== null && log.cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0"), children: [
2677
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.creation ?? null }),
2678
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-cyan-300", children: [
2679
+ "KV Cache +",
2680
+ formatTokens(log.cacheCreationInputTokens)
2681
+ ] })
2682
+ ] }),
2683
+ log.cacheReadInputTokens !== null && log.cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0"), children: [
2684
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CacheTrendIndicator, { trend: cacheTrend?.read ?? null }),
2685
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
2686
+ "KV Cache ~",
2687
+ formatTokens(log.cacheReadInputTokens)
2688
+ ] })
2689
+ ] }),
2690
+ messageCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-muted-foreground"), children: [
2691
+ /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-3" }),
2692
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: messageCount })
2693
+ ] }),
2694
+ toolCount !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn(TELEMETRY_CHIP_CLASS, "shrink-0 text-muted-foreground"), children: [
2695
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Wrench, { className: "size-3" }),
2696
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: toolCount })
2697
+ ] }),
2698
+ log.origin !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
2699
+ "span",
2700
+ {
2701
+ className: cn(TELEMETRY_CHIP_CLASS, "hidden shrink-0 text-muted-foreground xl:flex"),
2702
+ title: `Origin: ${log.origin}`,
2703
+ children: [
2704
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { className: "size-3" }),
2705
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums truncate max-w-[120px]", title: log.origin, children: log.origin })
2706
+ ]
2707
+ }
2708
+ ),
2709
+ showClientMetadata && (hasClientPid || hasClientProjectFolder) && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2710
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2711
+ "span",
2712
+ {
2713
+ className: cn(TELEMETRY_CHIP_CLASS, "hidden shrink-0 text-purple-300 xl:flex"),
2714
+ children: [
2715
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
2716
+ hasClientProjectFolder ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
2717
+ "PID ",
2718
+ log.clientPid
2719
+ ] })
2720
+ ]
2721
+ }
2722
+ ) }),
2723
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: hasClientCwd ? `PID: ${log.clientPid ?? "?"} CWD: ${log.clientCwd}` : `Process ID: ${log.clientPid ?? "?"}` })
2724
+ ] }),
2725
+ showStandaloneStreamingIndicator && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2726
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Radio, { className: "size-3 text-muted-foreground/60 shrink-0" }) }),
2727
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Request used SSE streaming" })
2728
+ ] })
2729
+ ] }),
2730
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex shrink-0 items-start gap-1.5", children: [
2731
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs(
2732
+ "span",
2733
+ {
2734
+ className: "flex items-center gap-1.5 shrink-0",
2735
+ onClick: (e) => e.stopPropagation(),
2736
+ onKeyDown: (e) => e.stopPropagation(),
2737
+ children: [
2738
+ tabActions !== void 0 && activeTab !== void 0 && (() => {
2739
+ const action = tabActions[activeTab];
2740
+ if (action === void 0) return null;
2741
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2742
+ action.expansion !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2743
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2744
+ Button,
2745
+ {
2746
+ variant: "outline",
2747
+ size: "icon",
2748
+ className: HEADER_ACTION_BUTTON_CLASS,
2749
+ onClick: action.expansion.onToggle,
2750
+ disabled: action.expansion.isPending,
2751
+ "aria-pressed": action.expansion.isExpanded,
2752
+ "aria-label": action.expansion.isExpanded ? "Collapse all JSON" : "Expand all JSON",
2753
+ children: action.expansion.isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5" })
2754
+ }
2755
+ ) }),
2756
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.expansion.isExpanded ? "Collapse all JSON nodes" : "Expand all JSON nodes" })
2757
+ ] }),
2758
+ action.diffWithRaw !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2759
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2760
+ Button,
2761
+ {
2762
+ variant: "outline",
2763
+ size: "icon",
2764
+ className: cn(
2765
+ HEADER_ACTION_BUTTON_CLASS,
2766
+ action.diffWithRaw.active && "border-cyan-300/35 bg-cyan-400/15 text-cyan-100"
2767
+ ),
2768
+ onClick: action.diffWithRaw.onToggle,
2769
+ "aria-pressed": action.diffWithRaw.active,
2770
+ "aria-label": action.diffWithRaw.active ? "Hide raw diff" : "Diff with raw",
2771
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FileDiff, { className: "size-3.5" })
2772
+ }
2773
+ ) }),
2774
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.diffWithRaw.active ? "Hide diff with raw request" : "Show diff between displayed and raw request body" })
2775
+ ] }),
2776
+ action.diffWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2777
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2778
+ Button,
2779
+ {
2780
+ variant: "outline",
2781
+ size: "icon",
2782
+ className: HEADER_ACTION_BUTTON_CLASS,
2783
+ onClick: action.diffWithPrevious,
2784
+ "aria-label": "Diff with previous",
2785
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(History, { className: "size-3.5" })
2786
+ }
2787
+ ) }),
2788
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
2789
+ ] }),
2790
+ action.copyText !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2791
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2792
+ Button,
2793
+ {
2794
+ variant: "outline",
2795
+ size: "icon",
2796
+ className: HEADER_ACTION_BUTTON_CLASS,
2797
+ onClick: action.onCopy,
2798
+ "aria-label": action.copyCopied ? "Copied" : action.copyLabel,
2799
+ children: action.copyCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-cyan-300" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
2800
+ }
2801
+ ) }),
2802
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.copyCopied ? "Copied to clipboard" : action.copyLabel })
2803
+ ] })
2804
+ ] });
2805
+ })(),
2806
+ onReplay !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
2807
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2808
+ Button,
2809
+ {
2810
+ variant: "outline",
2811
+ size: "icon",
2812
+ className: HEADER_ACTION_BUTTON_CLASS,
2813
+ onClick: onReplay,
2814
+ "aria-label": "Replay request",
2815
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "size-3.5" })
2816
+ }
2817
+ ) }),
2818
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Re-send this request to the provider" })
2819
+ ] })
2820
+ ]
2821
+ }
2822
+ ),
2823
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
2824
+ "span",
2825
+ {
2826
+ className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-8 shrink-0 items-center justify-center rounded-md text-slate-200",
2827
+ "aria-hidden": "true",
2828
+ children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 shrink-0" })
2829
+ }
2830
+ )
2831
+ ] })
3110
2832
  ]
3111
2833
  }
3112
2834
  ) });
@@ -3615,12 +3337,6 @@ function shouldUseChunkedBodyLoading(log) {
3615
3337
  function shouldHydrateLogBody(log) {
3616
3338
  return isCompactBody(log) && !shouldUseChunkedBodyLoading(log);
3617
3339
  }
3618
- function formatBytes$1(bytes) {
3619
- if (bytes < 1024) return `${bytes.toLocaleString()} B`;
3620
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
3621
- if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MiB`;
3622
- return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GiB`;
3623
- }
3624
3340
  function bodyPreviewErrorMessage(error) {
3625
3341
  if (error instanceof ApiTimeoutError) {
3626
3342
  return "Body preview timed out. The log is still available on disk; try loading again.";
@@ -3628,6 +3344,43 @@ function bodyPreviewErrorMessage(error) {
3628
3344
  if (error instanceof Error) return error.message;
3629
3345
  return "Body preview could not be loaded.";
3630
3346
  }
3347
+ function FullBodyHydrationNotice({
3348
+ status,
3349
+ error,
3350
+ footprint,
3351
+ onRetry
3352
+ }) {
3353
+ switch (status) {
3354
+ case "idle":
3355
+ return null;
3356
+ case "loading":
3357
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(NoticeBlock, { tone: "loading", title: "Loading full bodies", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
3358
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
3359
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 shrink-0 animate-spin text-cyan-200" }),
3360
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Loading full request and response bodies from the log store." })
3361
+ ] }),
3362
+ footprint !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "rounded border border-cyan-300/15 bg-cyan-300/[0.06] px-2 py-0.5 font-mono text-[11px] text-cyan-100", children: footprint })
3363
+ ] }) });
3364
+ case "failed":
3365
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(NoticeBlock, { tone: "warning", title: error?.title ?? "Full bodies could not be loaded", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
3366
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: error?.detail ?? "Compact metadata is still available." }),
3367
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
3368
+ Button,
3369
+ {
3370
+ type: "button",
3371
+ variant: "outline",
3372
+ size: "sm",
3373
+ className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground h-7 gap-1.5 text-xs text-amber-100",
3374
+ onClick: onRetry,
3375
+ children: [
3376
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "size-3" }),
3377
+ "Retry"
3378
+ ]
3379
+ }
3380
+ )
3381
+ ] }) });
3382
+ }
3383
+ }
3631
3384
  function bodyPreviewTextForView(enabled, state) {
3632
3385
  if (!enabled) return null;
3633
3386
  if (state.text !== "") return state.text;
@@ -3794,7 +3547,9 @@ const LogEntry = reactExports.memo(function({
3794
3547
  const [activeTab, setActiveTab] = reactExports.useState("request");
3795
3548
  const [expandToPath, setExpandToPath] = reactExports.useState(null);
3796
3549
  const [hydratedLog, setHydratedLog] = reactExports.useState(null);
3797
- const [bodyHydrationState, setBodyHydrationState] = reactExports.useState("idle");
3550
+ const [bodyHydrationStatus, setBodyHydrationStatus] = reactExports.useState("idle");
3551
+ const [bodyHydrationError, setBodyHydrationError] = reactExports.useState(null);
3552
+ const [bodyHydrationRetryNonce, setBodyHydrationRetryNonce] = reactExports.useState(0);
3798
3553
  const [requestPreview, setRequestPreview] = reactExports.useState(
3799
3554
  () => createEmptyBodyPreviewState(log.rawRequestBodyBytes ?? null)
3800
3555
  );
@@ -3806,6 +3561,10 @@ const LogEntry = reactExports.memo(function({
3806
3561
  const bodyHydrationInFlightRef = reactExports.useRef(false);
3807
3562
  const displayLog = hydratedLog ?? log;
3808
3563
  const useChunkedBody = hydratedLog === null && shouldUseChunkedBodyLoading(log);
3564
+ const fullBodyHydrationFootprint = reactExports.useMemo(
3565
+ () => formatBodyHydrationFootprint(log.rawRequestBodyBytes, log.responseTextBytes),
3566
+ [log.rawRequestBodyBytes, log.responseTextBytes]
3567
+ );
3809
3568
  const requestPreviewBody = bodyPreviewTextForView(useChunkedBody, requestPreview);
3810
3569
  const responsePreviewBody = bodyPreviewTextForView(useChunkedBody, responsePreview);
3811
3570
  const rawRequestBodyForView = displayLog.rawRequestBody ?? requestPreviewBody;
@@ -4002,6 +3761,13 @@ const LogEntry = reactExports.memo(function({
4002
3761
  },
4003
3762
  [log.id]
4004
3763
  );
3764
+ const retryFullBodyHydration = reactExports.useCallback(() => {
3765
+ if (bodyHydrationInFlightRef.current) return;
3766
+ setHydratedLog(null);
3767
+ setBodyHydrationStatus("idle");
3768
+ setBodyHydrationError(null);
3769
+ setBodyHydrationRetryNonce((current) => current + 1);
3770
+ }, []);
4005
3771
  const handleToggleExpanded = reactExports.useCallback(() => {
4006
3772
  const nextExpanded = !expanded;
4007
3773
  if (nextExpanded) {
@@ -4013,7 +3779,9 @@ const LogEntry = reactExports.memo(function({
4013
3779
  logIdRef.current = log.id;
4014
3780
  bodyHydrationInFlightRef.current = false;
4015
3781
  setHydratedLog(null);
4016
- setBodyHydrationState("idle");
3782
+ setBodyHydrationStatus("idle");
3783
+ setBodyHydrationError(null);
3784
+ setBodyHydrationRetryNonce(0);
4017
3785
  setRequestPreview(createEmptyBodyPreviewState(log.rawRequestBodyBytes ?? null));
4018
3786
  setResponsePreview(createEmptyBodyPreviewState(log.responseTextBytes ?? null));
4019
3787
  }, [log.id, log.rawRequestBodyBytes, log.responseTextBytes]);
@@ -4023,7 +3791,8 @@ const LogEntry = reactExports.memo(function({
4023
3791
  if (hydratedLog !== null || bodyHydrationInFlightRef.current) return;
4024
3792
  let cancelled = false;
4025
3793
  bodyHydrationInFlightRef.current = true;
4026
- setBodyHydrationState("loading");
3794
+ setBodyHydrationStatus("loading");
3795
+ setBodyHydrationError(null);
4027
3796
  void fetchJsonWithTimeout(
4028
3797
  `/api/logs/${String(log.id)}`,
4029
3798
  CapturedLogSchema,
@@ -4032,11 +3801,13 @@ const LogEntry = reactExports.memo(function({
4032
3801
  if (cancelled) return;
4033
3802
  bodyHydrationInFlightRef.current = false;
4034
3803
  setHydratedLog(fullLog);
4035
- setBodyHydrationState("idle");
4036
- }).catch(() => {
3804
+ setBodyHydrationStatus("idle");
3805
+ setBodyHydrationError(null);
3806
+ }).catch((error) => {
4037
3807
  if (cancelled) return;
4038
3808
  bodyHydrationInFlightRef.current = false;
4039
- setBodyHydrationState("failed");
3809
+ setBodyHydrationStatus("failed");
3810
+ setBodyHydrationError(describeFullBodyHydrationError(error));
4040
3811
  });
4041
3812
  return () => {
4042
3813
  cancelled = true;
@@ -4048,7 +3819,8 @@ const LogEntry = reactExports.memo(function({
4048
3819
  log.bodyContentMode,
4049
3820
  log.id,
4050
3821
  log.rawRequestBodyBytes,
4051
- log.responseTextBytes
3822
+ log.responseTextBytes,
3823
+ bodyHydrationRetryNonce
4052
3824
  ]);
4053
3825
  reactExports.useEffect(() => {
4054
3826
  if (!expanded) return;
@@ -4155,6 +3927,15 @@ const LogEntry = reactExports.memo(function({
4155
3927
  }
4156
3928
  ),
4157
3929
  shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsxs(ExpandedPanel, { children: [
3930
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3931
+ FullBodyHydrationNotice,
3932
+ {
3933
+ status: bodyHydrationStatus,
3934
+ error: bodyHydrationError,
3935
+ footprint: fullBodyHydrationFootprint,
3936
+ onRetry: retryFullBodyHydration
3937
+ }
3938
+ ),
4158
3939
  useChunkedBody && /* @__PURE__ */ jsxRuntimeExports.jsx(
4159
3940
  BodyPreviewNotice,
4160
3941
  {
@@ -4174,8 +3955,15 @@ const LogEntry = reactExports.memo(function({
4174
3955
  ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(RawTextBlock, { children: rawRequestBodyForView })
4175
3956
  ] }) }),
4176
3957
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs(ExpandedPanel, { children: [
4177
- bodyHydrationState === "loading" && /* @__PURE__ */ jsxRuntimeExports.jsx(NoticeBlock, { tone: "loading", children: "Loading full request and response bodies..." }),
4178
- bodyHydrationState === "failed" && /* @__PURE__ */ jsxRuntimeExports.jsx(NoticeBlock, { tone: "warning", children: "Full request and response bodies could not be loaded. Compact metadata is still available." }),
3958
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3959
+ FullBodyHydrationNotice,
3960
+ {
3961
+ status: bodyHydrationStatus,
3962
+ error: bodyHydrationError,
3963
+ footprint: fullBodyHydrationFootprint,
3964
+ onRetry: retryFullBodyHydration
3965
+ }
3966
+ ),
4179
3967
  useChunkedBody && /* @__PURE__ */ jsxRuntimeExports.jsx(
4180
3968
  BodyPreviewNotice,
4181
3969
  {
@@ -4258,6 +4046,15 @@ const LogEntry = reactExports.memo(function({
4258
4046
  }
4259
4047
  ) }) }),
4260
4048
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: activeTab === "raw" && /* @__PURE__ */ jsxRuntimeExports.jsxs(ExpandedPanel, { className: "space-y-3", children: [
4049
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4050
+ FullBodyHydrationNotice,
4051
+ {
4052
+ status: bodyHydrationStatus,
4053
+ error: bodyHydrationError,
4054
+ footprint: fullBodyHydrationFootprint,
4055
+ onRetry: retryFullBodyHydration
4056
+ }
4057
+ ),
4261
4058
  useChunkedBody && /* @__PURE__ */ jsxRuntimeExports.jsx(
4262
4059
  BodyPreviewNotice,
4263
4060
  {
@@ -4286,6 +4083,15 @@ const LogEntry = reactExports.memo(function({
4286
4083
  ) })
4287
4084
  ] }) }),
4288
4085
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: activeTab === "parsed" && /* @__PURE__ */ jsxRuntimeExports.jsxs(ExpandedPanel, { children: [
4086
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4087
+ FullBodyHydrationNotice,
4088
+ {
4089
+ status: bodyHydrationStatus,
4090
+ error: bodyHydrationError,
4091
+ footprint: fullBodyHydrationFootprint,
4092
+ onRetry: retryFullBodyHydration
4093
+ }
4094
+ ),
4289
4095
  useChunkedBody && /* @__PURE__ */ jsxRuntimeExports.jsx(
4290
4096
  BodyPreviewNotice,
4291
4097
  {
@@ -4328,6 +4134,358 @@ const LogEntry = reactExports.memo(function({
4328
4134
  ) })
4329
4135
  ] });
4330
4136
  });
4137
+ function SvgShell({
4138
+ className,
4139
+ style,
4140
+ d,
4141
+ eyeStalks,
4142
+ eyes,
4143
+ legs,
4144
+ extras
4145
+ }) {
4146
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
4147
+ "svg",
4148
+ {
4149
+ viewBox: "0 0 24 24",
4150
+ fill: "none",
4151
+ stroke: "currentColor",
4152
+ strokeWidth: "1.5",
4153
+ strokeLinecap: "round",
4154
+ strokeLinejoin: "round",
4155
+ "aria-hidden": "true",
4156
+ style,
4157
+ className: cn("inline-block size-5", className),
4158
+ children: [
4159
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d }),
4160
+ eyeStalks,
4161
+ eyes,
4162
+ legs,
4163
+ extras
4164
+ ]
4165
+ }
4166
+ );
4167
+ }
4168
+ const StdLegs = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4169
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6.5", y1: "16", x2: "4.5", y2: "19.5" }),
4170
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "17.5", x2: "8", y2: "20.5" }),
4171
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15", y1: "17.5", x2: "16", y2: "20.5" }),
4172
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17.5", y1: "16", x2: "19.5", y2: "19.5" })
4173
+ ] });
4174
+ const ShortLegs = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4175
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "16", x2: "5.5", y2: "18.5" }),
4176
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "17", x2: "8.5", y2: "19.5" }),
4177
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "17", x2: "15.5", y2: "19.5" }),
4178
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "16", x2: "18.5", y2: "18.5" })
4179
+ ] });
4180
+ function Crab1({ className }) {
4181
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4182
+ SvgShell,
4183
+ {
4184
+ className,
4185
+ d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
4186
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4187
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
4188
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
4189
+ ] }),
4190
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4191
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" }),
4192
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" })
4193
+ ] }),
4194
+ legs: StdLegs,
4195
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4196
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
4197
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" })
4198
+ ] })
4199
+ }
4200
+ );
4201
+ }
4202
+ function Crab2({ className }) {
4203
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4204
+ SvgShell,
4205
+ {
4206
+ className,
4207
+ d: "M4 13 C4 7 7.5 5.5 12 5.5 C16.5 5.5 20 7 20 13 C20 17.5 16.5 19 12 19 C7.5 19 4 17.5 4 13 Z",
4208
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4209
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "6.5", x2: "9.5", y2: "4.5" }),
4210
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "6.5", x2: "14.5", y2: "4.5" })
4211
+ ] }),
4212
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4213
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" }),
4214
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" })
4215
+ ] }),
4216
+ legs: ShortLegs,
4217
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4218
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C4 9.5 2.5 10 3 12 C3.5 13.5 4.5 13 5 12" }),
4219
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20 9.5 21.5 10 21 12 C20.5 13.5 19.5 13 19 12" })
4220
+ ] })
4221
+ }
4222
+ );
4223
+ }
4224
+ function Crab3({ className }) {
4225
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4226
+ SvgShell,
4227
+ {
4228
+ className,
4229
+ d: "M3 13.5 C3 8 7 6 12 6 C17 6 21 8 21 13.5 C21 17 17 19 12 19 C7 19 3 17 3 13.5 Z",
4230
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4231
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "7", x2: "6.5", y2: "4.5" }),
4232
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "7", x2: "17.5", y2: "4.5" })
4233
+ ] }),
4234
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4235
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "6.5", cy: "4", r: "0.8", fill: "currentColor", stroke: "none" }),
4236
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17.5", cy: "4", r: "0.8", fill: "currentColor", stroke: "none" })
4237
+ ] }),
4238
+ legs: StdLegs,
4239
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4240
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M4 12 C2.5 10.5 1 11 1.5 13 C2 14.5 3.5 14 4.5 13" }),
4241
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M20 12 C21.5 10.5 23 11 22.5 13 C22 14.5 20.5 14 19.5 13" })
4242
+ ] })
4243
+ }
4244
+ );
4245
+ }
4246
+ function Crab4({ className }) {
4247
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4248
+ SvgShell,
4249
+ {
4250
+ className,
4251
+ d: "M6 14 C6 8 9 5.5 12 5.5 C15 5.5 18 8 18 14 C18 18 15 20 12 20 C9 20 6 18 6 14 Z",
4252
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4253
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6.5", x2: "10", y2: "3.5" }),
4254
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "6.5", x2: "14", y2: "3.5" })
4255
+ ] }),
4256
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4257
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "10", cy: "3", r: "0.7", fill: "currentColor", stroke: "none" }),
4258
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14", cy: "3", r: "0.7", fill: "currentColor", stroke: "none" })
4259
+ ] }),
4260
+ legs: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4261
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "17", x2: "5", y2: "20.5" }),
4262
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "18.5", x2: "8.5", y2: "21.5" }),
4263
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "18.5", x2: "15.5", y2: "21.5" }),
4264
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "17", x2: "19", y2: "20.5" })
4265
+ ] }),
4266
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4267
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6.5 11 C5 8.5 3 9 3.5 11.5 C4 13.5 5 13 6 12" }),
4268
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M17.5 11 C19 8.5 21 9 20.5 11.5 C20 13.5 19 13 18 12" })
4269
+ ] })
4270
+ }
4271
+ );
4272
+ }
4273
+ function Crab5({ className }) {
4274
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4275
+ SvgShell,
4276
+ {
4277
+ className,
4278
+ d: "M5 13 C5 9 8 7 12 7 L13 4 L14 7 C16 7 19 9 19 13 C19 16 16 18 13 18 L12 21 L11 18 C8 18 5 16 5 13 Z",
4279
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4280
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
4281
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
4282
+ ] }),
4283
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4284
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.8", fill: "currentColor", stroke: "none" }),
4285
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.8", fill: "currentColor", stroke: "none" })
4286
+ ] }),
4287
+ legs: StdLegs,
4288
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4289
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
4290
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" })
4291
+ ] })
4292
+ }
4293
+ );
4294
+ }
4295
+ function Crab6({ className }) {
4296
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4297
+ SvgShell,
4298
+ {
4299
+ className,
4300
+ d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
4301
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4302
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
4303
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
4304
+ ] }),
4305
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4306
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" }),
4307
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13.5", y1: "4", x2: "15.5", y2: "5" })
4308
+ ] }),
4309
+ legs: StdLegs,
4310
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4311
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
4312
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" })
4313
+ ] })
4314
+ }
4315
+ );
4316
+ }
4317
+ function Crab7({ className }) {
4318
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4319
+ SvgShell,
4320
+ {
4321
+ className,
4322
+ d: "M5.5 13.5 C5.5 10 8.5 8 12 8 C15.5 8 18.5 10 18.5 13.5 C18.5 16 15.5 17.5 12 17.5 C8.5 17.5 5.5 16 5.5 13.5 Z",
4323
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4324
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "8", x2: "10", y2: "6" }),
4325
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "8", x2: "14", y2: "6" })
4326
+ ] }),
4327
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4328
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "6", x2: "11", y2: "6.5" }),
4329
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13", y1: "6", x2: "15", y2: "6.5" })
4330
+ ] }),
4331
+ legs: ShortLegs,
4332
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4333
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6 11.5 C4.5 10.5 3 11 3.5 12.5 C4 13.5 5 13 5.5 12.5" }),
4334
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M18 11.5 C19.5 10.5 21 11 20.5 12.5 C20 13.5 19 13 18.5 12.5" })
4335
+ ] })
4336
+ }
4337
+ );
4338
+ }
4339
+ function Crab8({ className }) {
4340
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4341
+ SvgShell,
4342
+ {
4343
+ className,
4344
+ d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
4345
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4346
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
4347
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
4348
+ ] }),
4349
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4350
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.7", fill: "currentColor", stroke: "none" }),
4351
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.7", fill: "currentColor", stroke: "none" })
4352
+ ] }),
4353
+ legs: StdLegs,
4354
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4355
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
4356
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" }),
4357
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "8.5", y1: "4", x2: "10.5", y2: "4.5" }),
4358
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15.5", y1: "4", x2: "13.5", y2: "4.5" }),
4359
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 15.5 C10 14.5 14 14.5 15 15.5" })
4360
+ ] })
4361
+ }
4362
+ );
4363
+ }
4364
+ function Crab9({ className }) {
4365
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4366
+ SvgShell,
4367
+ {
4368
+ className,
4369
+ d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
4370
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4371
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
4372
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
4373
+ ] }),
4374
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4375
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "1.2", fill: "none", stroke: "currentColor" }),
4376
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "1.2", fill: "none", stroke: "currentColor" })
4377
+ ] }),
4378
+ legs: StdLegs,
4379
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4380
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
4381
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" }),
4382
+ /* @__PURE__ */ jsxRuntimeExports.jsx("ellipse", { cx: "12", cy: "15", rx: "2", ry: "1.5", fill: "currentColor", stroke: "none" })
4383
+ ] })
4384
+ }
4385
+ );
4386
+ }
4387
+ function Crab10({ className }) {
4388
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4389
+ SvgShell,
4390
+ {
4391
+ className,
4392
+ d: "M4.5 13 C4.5 8 7.5 6 12 6 C16.5 6 19.5 8 19.5 13 C19.5 17 16.5 18.5 12 18.5 C7.5 18.5 4.5 17 4.5 13 Z",
4393
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4394
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "7", x2: "9", y2: "5" }),
4395
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "7", x2: "15", y2: "5" })
4396
+ ] }),
4397
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4398
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9", cy: "4.5", r: "1", fill: "currentColor", stroke: "none" }),
4399
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "15", cy: "4.5", r: "1", fill: "currentColor", stroke: "none" })
4400
+ ] }),
4401
+ legs: StdLegs,
4402
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4403
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9 2 9.5 2.5 12 C3 14 4 13 5 12" }),
4404
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9 22 9.5 21.5 12 C21 14 20 13 19 12" }),
4405
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 14.5 C10 16 14 16 15 14.5" }),
4406
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "13", r: "1", fill: "currentColor", stroke: "none", opacity: "0.3" }),
4407
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "13", r: "1", fill: "currentColor", stroke: "none", opacity: "0.3" })
4408
+ ] })
4409
+ }
4410
+ );
4411
+ }
4412
+ function Crab11({ className }) {
4413
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4414
+ SvgShell,
4415
+ {
4416
+ className,
4417
+ d: "M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z",
4418
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4419
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5.5" }),
4420
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5.5" })
4421
+ ] }),
4422
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4423
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7.5", y1: "5.5", x2: "16.5", y2: "5.5" }),
4424
+ /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "7", y: "5", width: "4", height: "2", rx: "0.5", fill: "currentColor", stroke: "none" }),
4425
+ /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "13", y: "5", width: "4", height: "2", rx: "0.5", fill: "currentColor", stroke: "none" })
4426
+ ] }),
4427
+ legs: StdLegs,
4428
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4429
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" }),
4430
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" }),
4431
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9.5 15 C10.5 16 13.5 16 14.5 15" })
4432
+ ] })
4433
+ }
4434
+ );
4435
+ }
4436
+ function Crab12({ className }) {
4437
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4438
+ SvgShell,
4439
+ {
4440
+ className,
4441
+ d: "M7 13.5 C7 10.5 9.5 9 12 9 C14.5 9 17 10.5 17 13.5 C17 16 14.5 17.5 12 17.5 C9.5 17.5 7 16 7 13.5 Z",
4442
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4443
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10.5", y1: "9.5", x2: "10.5", y2: "8" }),
4444
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13.5", y1: "9.5", x2: "13.5", y2: "8" })
4445
+ ] }),
4446
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4447
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "10.5", cy: "7.5", r: "0.8", fill: "currentColor", stroke: "none" }),
4448
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "13.5", cy: "7.5", r: "0.8", fill: "currentColor", stroke: "none" })
4449
+ ] }),
4450
+ legs: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4451
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "8", y1: "16", x2: "6.5", y2: "18" }),
4452
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "17", x2: "9.5", y2: "19" }),
4453
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "17", x2: "14.5", y2: "19" }),
4454
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "16", y1: "16", x2: "17.5", y2: "18" })
4455
+ ] }),
4456
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4457
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M7.5 12 C6.5 11 5.5 11.5 6 13 C6.5 14 7 13.5 7.5 13" }),
4458
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16.5 12 C17.5 11 18.5 11.5 18 13 C17.5 14 17 13.5 16.5 13" })
4459
+ ] })
4460
+ }
4461
+ );
4462
+ }
4463
+ const crabVariants = [
4464
+ Crab1,
4465
+ Crab2,
4466
+ Crab3,
4467
+ Crab4,
4468
+ Crab5,
4469
+ Crab6,
4470
+ Crab7,
4471
+ Crab8,
4472
+ Crab9,
4473
+ Crab10,
4474
+ Crab11,
4475
+ Crab12
4476
+ ];
4477
+ function getCrabVariant(index) {
4478
+ return crabVariants[Math.abs(index) % crabVariants.length] ?? Crab1;
4479
+ }
4480
+ function getInteriorCrabVariantIndex(seed) {
4481
+ const interiorCount = crabVariants.length - 2;
4482
+ if (interiorCount <= 0) return 0;
4483
+ const normalizedSeed = Number.isFinite(seed) ? Math.trunc(seed) : 0;
4484
+ return 1 + (normalizedSeed % interiorCount + interiorCount) % interiorCount;
4485
+ }
4486
+ function getInteriorCrabVariant(seed) {
4487
+ return getCrabVariant(getInteriorCrabVariantIndex(seed));
4488
+ }
4331
4489
  function boundaryTitle(stopReason) {
4332
4490
  switch (stopReason) {
4333
4491
  case "end_turn":
@@ -4341,6 +4499,9 @@ function boundaryTitle(stopReason) {
4341
4499
  return "End of Turn";
4342
4500
  }
4343
4501
  }
4502
+ function crabShellClass(interactive) {
4503
+ return interactive ? "cursor-pointer transition-transform hover:scale-110" : "";
4504
+ }
4344
4505
  function ThreadConnector({
4345
4506
  stopReason,
4346
4507
  isPending,
@@ -4354,53 +4515,83 @@ function ThreadConnector({
4354
4515
  const isBoundary = isTurnBoundary(stopReason);
4355
4516
  const isFusedBoundary = isOnlyEntry && isTurnStart && isBoundary;
4356
4517
  const isRunning = isPending && !isBoundary;
4518
+ const interactive = collapsible && onToggle !== void 0;
4357
4519
  const Crab = reactExports.useMemo(() => getCrabVariant(crabIndex), [crabIndex]);
4358
4520
  const FusedCrab = reactExports.useMemo(() => getInteriorCrabVariant(crabIndex), [crabIndex]);
4359
- const interactiveProps = collapsible && onToggle ? {
4360
- role: "button",
4361
- tabIndex: 0,
4362
- className: "cursor-pointer",
4363
- onClick: (e) => {
4364
- e.stopPropagation();
4365
- onToggle();
4366
- },
4367
- onKeyDown: (e) => {
4368
- if (e.key === "Enter" || e.key === " ") {
4369
- e.preventDefault();
4370
- onToggle();
4371
- }
4372
- }
4373
- } : {};
4521
+ const handleCrabClick = (event) => {
4522
+ if (!interactive || onToggle === void 0) return;
4523
+ event.stopPropagation();
4524
+ onToggle();
4525
+ };
4526
+ const handleCrabKeyDown = (event) => {
4527
+ if (!interactive || onToggle === void 0) return;
4528
+ if (event.key !== "Enter" && event.key !== " ") return;
4529
+ event.preventDefault();
4530
+ onToggle();
4531
+ };
4374
4532
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center w-6 shrink-0 pt-0.5 pb-0.5", children: [
4375
4533
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]", children: !isFirst && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30 h-full" }) }),
4376
- isFusedBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Start and end of turn", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4377
- FusedCrab,
4534
+ isFusedBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx(
4535
+ "span",
4378
4536
  {
4379
- className: cn(
4380
- "size-3.5 text-cyan-300/90",
4381
- "animate-crab-settle",
4382
- "drop-shadow-[0_0_4px_rgba(103,232,249,0.35)]"
4537
+ role: interactive ? "button" : void 0,
4538
+ tabIndex: interactive ? 0 : void 0,
4539
+ title: "Single-request turn",
4540
+ className: crabShellClass(interactive),
4541
+ onClick: handleCrabClick,
4542
+ onKeyDown: handleCrabKeyDown,
4543
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4544
+ FusedCrab,
4545
+ {
4546
+ className: cn(
4547
+ "size-3.5 text-[#80FF00]",
4548
+ "animate-crab-settle",
4549
+ "drop-shadow-[0_0_4px_rgba(128,255,0,0.5)]"
4550
+ )
4551
+ }
4383
4552
  )
4384
4553
  }
4385
- ) }) : isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: boundaryTitle(stopReason), ...interactiveProps, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4386
- Crab,
4554
+ ) : isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx(
4555
+ "span",
4387
4556
  {
4388
- className: cn(
4389
- "size-3.5 text-amber-400",
4390
- "animate-crab-settle",
4391
- "drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]"
4557
+ role: interactive ? "button" : void 0,
4558
+ tabIndex: interactive ? 0 : void 0,
4559
+ title: boundaryTitle(stopReason),
4560
+ className: crabShellClass(interactive),
4561
+ onClick: handleCrabClick,
4562
+ onKeyDown: handleCrabKeyDown,
4563
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4564
+ Crab,
4565
+ {
4566
+ className: cn(
4567
+ "size-3.5 text-amber-400",
4568
+ "animate-crab-settle",
4569
+ "drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]"
4570
+ )
4571
+ }
4392
4572
  )
4393
4573
  }
4394
- ) }) : isTurnStart ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Start of turn", ...interactiveProps, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4395
- Crab,
4574
+ ) : isTurnStart ? /* @__PURE__ */ jsxRuntimeExports.jsx(
4575
+ "span",
4396
4576
  {
4397
- className: cn(
4398
- "size-3.5 text-cyan-300/85",
4399
- "animate-crab-appear",
4400
- "drop-shadow-[0_0_4px_rgba(103,232,249,0.32)]"
4577
+ role: interactive ? "button" : void 0,
4578
+ tabIndex: interactive ? 0 : void 0,
4579
+ title: "Start of turn",
4580
+ className: crabShellClass(interactive),
4581
+ onClick: handleCrabClick,
4582
+ onKeyDown: handleCrabKeyDown,
4583
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4584
+ Crab,
4585
+ {
4586
+ className: cn(
4587
+ "size-3.5 text-emerald-400",
4588
+ "animate-crab-appear",
4589
+ "drop-shadow-[0_0_4px_rgba(52,211,153,0.5)]"
4590
+ )
4591
+ }
4401
4592
  )
4402
4593
  }
4403
- ) }) : isRunning ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Processing", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Crab, { className: cn("size-3.5 text-amber-300/80", "animate-crab-crawl") }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Crab, { className: "size-3.5 text-muted-foreground/40" }) }),
4594
+ ) : isRunning ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Processing", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Crab, { className: cn("size-3.5 text-amber-300/80", "animate-crab-crawl") }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Request in turn", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Crab, { className: "size-3.5 text-muted-foreground/40" }) }),
4404
4595
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex justify-center min-h-0", children: !isBoundary && /* @__PURE__ */ jsxRuntimeExports.jsx(
4405
4596
  "div",
4406
4597
  {
@@ -4761,8 +4952,6 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
4761
4952
  maxElapsed
4762
4953
  };
4763
4954
  }, [entries, lastIdx]);
4764
- const StartCrab = reactExports.useMemo(() => getCrabVariant(entries[0]?.log.id ?? 0), [entries]);
4765
- const EndCrab = reactExports.useMemo(() => getCrabVariant(entries[lastIdx]?.log.id ?? 0), [entries, lastIdx]);
4766
4955
  const bgClass = turnIndex % 2 === 0 ? "bg-white/[0.012]" : "bg-cyan-300/[0.012]";
4767
4956
  const aggregateIsSlow = aggregate.maxElapsed !== null && slowResponseThresholdSeconds > 0 && aggregate.maxElapsed > slowResponseThresholdSeconds * 1e3;
4768
4957
  const toolEventsByLogId = reactExports.useMemo(() => {
@@ -4812,155 +5001,114 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
4812
5001
  isPending ? "border-amber-300/15 shadow-[0_0_0_1px_rgba(252,211,77,0.04)]" : "border-transparent",
4813
5002
  !collapsed && "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none"
4814
5003
  ),
4815
- children: collapsed ? (
4816
- /* ---- Collapsed: dual-crab (+ summary card for multi-log turns) ---- */
4817
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
4818
- "div",
4819
- {
4820
- "data-nav-id": `turn-collapsed-${String(firstLogId)}`,
4821
- "data-nav-action": "expand",
4822
- role: "button",
4823
- tabIndex: 0,
4824
- className: "flex items-stretch cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none rounded-lg",
4825
- onClick: toggleCollapse,
4826
- onKeyDown: (e) => {
4827
- if (e.key === "Enter" || e.key === " ") {
4828
- e.preventDefault();
4829
- toggleCollapse();
4830
- }
4831
- },
4832
- children: [
4833
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }),
4834
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-6 shrink-0 flex flex-col items-center pt-0.5 pb-0.5", children: [
4835
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]" }),
4836
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4837
- "span",
4838
- {
4839
- role: "button",
4840
- tabIndex: 0,
4841
- title: "Start of turn - click to expand",
4842
- className: "cursor-pointer",
4843
- onClick: (e) => {
4844
- e.stopPropagation();
4845
- toggleCollapse();
4846
- },
4847
- onKeyDown: (e) => {
4848
- if (e.key === "Enter" || e.key === " ") {
4849
- e.preventDefault();
4850
- toggleCollapse();
4851
- }
4852
- },
4853
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4854
- StartCrab,
4855
- {
4856
- className: cn(
4857
- "size-3.5 text-cyan-300/85",
4858
- "animate-crab-appear drop-shadow-[0_0_4px_rgba(103,232,249,0.32)]"
4859
- )
4860
- }
4861
- )
4862
- }
4863
- ),
4864
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex justify-center min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30 h-full" }) }),
4865
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4866
- "span",
4867
- {
4868
- role: "button",
4869
- tabIndex: 0,
4870
- title: "End of Turn - click to expand",
4871
- className: "cursor-pointer",
4872
- onClick: (e) => {
4873
- e.stopPropagation();
4874
- toggleCollapse();
4875
- },
4876
- onKeyDown: (e) => {
4877
- if (e.key === "Enter" || e.key === " ") {
4878
- e.preventDefault();
4879
- toggleCollapse();
4880
- }
4881
- },
4882
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4883
- EndCrab,
4884
- {
4885
- className: cn(
4886
- "size-3.5 text-amber-400",
4887
- "animate-crab-settle drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]"
4888
- )
4889
- }
4890
- )
4891
- }
4892
- )
4893
- ] }),
4894
- entries.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
4895
- "div",
5004
+ children: collapsed ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
5005
+ "div",
5006
+ {
5007
+ "data-nav-id": `turn-collapsed-${String(firstLogId)}`,
5008
+ "data-nav-action": "expand",
5009
+ role: "button",
5010
+ tabIndex: 0,
5011
+ className: "flex items-stretch cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none rounded-lg",
5012
+ onClick: toggleCollapse,
5013
+ onKeyDown: (e) => {
5014
+ if (e.key === "Enter" || e.key === " ") {
5015
+ e.preventDefault();
5016
+ toggleCollapse();
5017
+ }
5018
+ },
5019
+ children: [
5020
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }),
5021
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-6 shrink-0 flex flex-col items-center pt-1.5 pb-1.5", children: [
5022
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]" }),
5023
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "size-2 rounded-full border border-cyan-300/45 bg-cyan-300/20" }),
5024
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex justify-center min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px bg-muted-foreground/25 h-full" }) }),
5025
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5026
+ "span",
4896
5027
  {
4897
5028
  className: cn(
4898
- "flex-1 min-w-0 mb-0.5 rounded-lg border border-cyan-300/10 py-1.5 px-3 flex items-center gap-3 text-xs shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]",
4899
- "border border-border bg-card shadow-sm",
4900
- bgClass
5029
+ "size-2 rounded-full border",
5030
+ isComplete ? "border-amber-300/45 bg-amber-300/20" : "border-muted-foreground/30 bg-muted/30"
5031
+ )
5032
+ }
5033
+ )
5034
+ ] }),
5035
+ entries.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
5036
+ "div",
5037
+ {
5038
+ className: cn(
5039
+ "flex-1 min-w-0 mb-0.5 rounded-[8px] py-1.5 px-3 flex items-center gap-3 text-xs shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]",
5040
+ "border border-border bg-card shadow-sm transition-colors hover:border-cyan-200/20",
5041
+ bgClass
5042
+ ),
5043
+ children: [
5044
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/70", children: turnLabel }),
5045
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
5046
+ "span",
5047
+ {
5048
+ className: "text-blue-300/85 font-mono font-semibold tabular-nums shrink-0",
5049
+ title: `Log IDs ${String(entries[0]?.log.id ?? "?")} ~ ${String(
5050
+ entries[lastIdx]?.log.id ?? "?"
5051
+ )}`,
5052
+ children: [
5053
+ "#",
5054
+ entries[0]?.sessionLogNumber ?? "?",
5055
+ " ~ #",
5056
+ entries[lastIdx]?.sessionLogNumber ?? "?"
5057
+ ]
5058
+ }
4901
5059
  ),
4902
- children: [
4903
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: ROW_CHEVRON_SLOT_CLASS, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 shrink-0" }) }),
4904
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
5060
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground shrink-0", children: [
5061
+ entries.length,
5062
+ " request",
5063
+ entries.length > 1 ? "s" : ""
5064
+ ] }),
5065
+ aggregate.maxElapsed !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
5066
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4905
5067
  "span",
4906
5068
  {
4907
- className: "text-blue-400/80 font-mono font-semibold tabular-nums shrink-0",
4908
- title: `Log IDs ${String(entries[0]?.log.id ?? "?")} ~ ${String(
4909
- entries[lastIdx]?.log.id ?? "?"
4910
- )}`,
5069
+ className: cn(
5070
+ "flex items-center gap-1 shrink-0",
5071
+ aggregateIsSlow ? "text-amber-400" : "text-muted-foreground"
5072
+ ),
4911
5073
  children: [
4912
- "#",
4913
- entries[0]?.sessionLogNumber ?? "?",
4914
- " ~ #",
4915
- entries[lastIdx]?.sessionLogNumber ?? "?"
5074
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
5075
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$2(aggregate.maxElapsed) }),
5076
+ aggregateIsSlow && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Slow response" })
4916
5077
  ]
4917
5078
  }
4918
- ),
4919
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground shrink-0", children: [
4920
- entries.length,
4921
- " request",
4922
- entries.length > 1 ? "s" : ""
4923
- ] }),
4924
- aggregate.maxElapsed !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
4925
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4926
- "span",
4927
- {
4928
- className: cn(
4929
- "flex items-center gap-1 shrink-0",
4930
- aggregateIsSlow ? "text-amber-400" : "text-muted-foreground"
4931
- ),
4932
- children: [
4933
- /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
4934
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed$2(aggregate.maxElapsed) }),
4935
- aggregateIsSlow && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3", "aria-label": "Slow response" })
4936
- ]
4937
- }
4938
- ) }),
4939
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: aggregateIsSlow ? `Slow response: ${formatElapsed$2(
4940
- aggregate.maxElapsed
4941
- )} exceeds ${formatElapsed$2(slowResponseThresholdSeconds * 1e3)}` : "Slowest request in this turn" })
4942
- ] }) }),
4943
- aggregate.hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 shrink-0", children: [
4944
- /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
4945
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
4946
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400", children: [
4947
- "IN ",
4948
- formatTokens(aggregate.totalInput)
4949
- ] }),
4950
- " / ",
4951
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-amber-400", children: [
4952
- "OUT ",
4953
- formatTokens(aggregate.totalOutput)
4954
- ] })
5079
+ ) }),
5080
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: aggregateIsSlow ? `Slow response: ${formatElapsed$2(
5081
+ aggregate.maxElapsed
5082
+ )} exceeds ${formatElapsed$2(slowResponseThresholdSeconds * 1e3)}` : "Slowest request in this turn" })
5083
+ ] }) }),
5084
+ aggregate.hasTokens && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 shrink-0", children: [
5085
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3 text-muted-foreground" }),
5086
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
5087
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-400", children: [
5088
+ "IN ",
5089
+ formatTokens(aggregate.totalInput)
5090
+ ] }),
5091
+ " / ",
5092
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-amber-400", children: [
5093
+ "OUT ",
5094
+ formatTokens(aggregate.totalOutput)
4955
5095
  ] })
4956
- ] }),
4957
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" })
4958
- ]
4959
- }
4960
- )
4961
- ]
4962
- }
4963
- )
5096
+ ] })
5097
+ ] }),
5098
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0" }),
5099
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5100
+ "span",
5101
+ {
5102
+ className: "border border-input bg-background inline-flex size-7 shrink-0 items-center justify-center rounded-md text-slate-200",
5103
+ "aria-hidden": "true",
5104
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 shrink-0" })
5105
+ }
5106
+ )
5107
+ ]
5108
+ }
5109
+ )
5110
+ ]
5111
+ }
4964
5112
  ) : (
4965
5113
  /* ---- Expanded: full entries ---- */
4966
5114
  entries.map((entry, visibleIdx) => {
@@ -8022,17 +8170,47 @@ function ProviderTestDetails({ result }) {
8022
8170
  function ProviderFormatTestStatus({
8023
8171
  results
8024
8172
  }) {
8025
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
8026
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
8173
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid min-w-0 gap-2 sm:grid-cols-2", children: [
8174
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 rounded-md border border-border/60 bg-muted/20 px-2 py-1.5", children: [
8027
8175
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Non-stream" }),
8028
8176
  /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: results.nonStreaming })
8029
8177
  ] }),
8030
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
8178
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 rounded-md border border-border/60 bg-muted/20 px-2 py-1.5", children: [
8031
8179
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground", children: "Stream" }),
8032
8180
  /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: results.streaming })
8033
8181
  ] })
8034
8182
  ] });
8035
8183
  }
8184
+ function EndpointDiagnosticLine({
8185
+ diagnostic
8186
+ }) {
8187
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: diagnostic.severity === "warning" ? "text-amber-200" : "text-muted-foreground", children: diagnostic.message });
8188
+ }
8189
+ function ProviderEndpointSummary({
8190
+ label,
8191
+ baseUrl,
8192
+ endpoint,
8193
+ providerName,
8194
+ children
8195
+ }) {
8196
+ const preview = previewUpstreamUrl(baseUrl, endpoint, { providerName });
8197
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-2 border-t border-border/60 pt-2 first:border-t-0 first:pt-0", children: [
8198
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid min-w-0 gap-1 text-xs sm:grid-cols-[104px_minmax(0,1fr)]", children: [
8199
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-muted-foreground", children: label }),
8200
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "min-w-0 break-all font-mono text-foreground/80", children: baseUrl }),
8201
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase text-muted-foreground/80", children: "Final" }),
8202
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "min-w-0 break-all font-mono text-foreground", children: preview.finalUrl })
8203
+ ] }),
8204
+ preview.diagnostics.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 text-xs", children: preview.diagnostics.map((diagnostic) => /* @__PURE__ */ jsxRuntimeExports.jsx(
8205
+ EndpointDiagnosticLine,
8206
+ {
8207
+ diagnostic
8208
+ },
8209
+ `${diagnostic.severity}:${diagnostic.message}`
8210
+ )) }),
8211
+ children
8212
+ ] });
8213
+ }
8036
8214
  function getErrorIcon(type) {
8037
8215
  const iconProps = { className: "size-3", strokeWidth: 2 };
8038
8216
  switch (type) {
@@ -8130,8 +8308,8 @@ function TestStatus({ result }) {
8130
8308
  displayTiming.push(timingParts[i]);
8131
8309
  }
8132
8310
  return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8133
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600 shrink-0", children: [
8134
- /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "size-3" }),
8311
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-cyan-100 shrink-0", children: [
8312
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "size-3 text-cyan-300" }),
8135
8313
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Connected" }),
8136
8314
  tokenParts.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground", children: [
8137
8315
  "(",
@@ -8233,6 +8411,13 @@ function ProviderCard({
8233
8411
  const hasContextMetadata = providerHasContextMetadata(provider);
8234
8412
  const canRefreshMetadata = provider.modelMetadataUrl !== void 0 && provider.modelMetadataUrl.trim() !== "";
8235
8413
  const metadataImportLabel = canRefreshMetadata ? "Refresh" : "Import defaults";
8414
+ const providerSourceBadge = provider.source === "company" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8415
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 rounded border border-cyan-300/20 bg-cyan-300/[0.08] px-1.5 py-0.5 text-xs text-cyan-100", children: "Company" }) }),
8416
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Company-provided API key" })
8417
+ ] }) }) : provider.source === "personal" ? /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8418
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 rounded border border-violet-300/20 bg-violet-300/[0.08] px-1.5 py-0.5 text-xs text-violet-100", children: "Personal" }) }),
8419
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Your personal API key" })
8420
+ ] }) }) : null;
8236
8421
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
8237
8422
  "div",
8238
8423
  {
@@ -8241,11 +8426,12 @@ function ProviderCard({
8241
8426
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
8242
8427
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
8243
8428
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium truncate", children: provider.name }),
8244
- provider.source === "company" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8429
+ providerSourceBadge,
8430
+ providerSourceBadge === null && provider.source === "company" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8245
8431
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 shrink-0", children: "公司" }) }),
8246
8432
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Company-provided API key" })
8247
8433
  ] }) }),
8248
- provider.source === "personal" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8434
+ providerSourceBadge === null && provider.source === "personal" && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
8249
8435
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 shrink-0", children: "个人" }) }),
8250
8436
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Your personal API key" })
8251
8437
  ] }) })
@@ -8344,31 +8530,40 @@ function ProviderCard({
8344
8530
  onClick: handleCopy,
8345
8531
  className: "text-muted-foreground hover:text-foreground transition-colors p-1",
8346
8532
  "aria-label": "Copy API key",
8347
- children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-4 text-green-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4" })
8533
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-4 text-cyan-300" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4" })
8348
8534
  }
8349
8535
  )
8350
8536
  ] }),
8351
- provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
8352
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 text-xs text-muted-foreground", children: [
8353
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: "Anthropic:" }),
8354
- " ",
8355
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.anthropicBaseUrl })
8356
- ] }),
8357
- testResults !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: testResults.anthropic })
8358
- ] }),
8359
- provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
8360
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 text-xs text-muted-foreground", children: [
8361
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: "OpenAI Chat:" }),
8362
- " ",
8363
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.openaiBaseUrl })
8364
- ] }),
8365
- testResults !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: testResults.openai })
8366
- ] }),
8367
- provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-w-0 flex-col gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 text-xs text-muted-foreground", children: [
8368
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: "OpenAI Responses:" }),
8369
- " ",
8370
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.openaiResponsesBaseUrl })
8371
- ] }) }),
8537
+ provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx(
8538
+ ProviderEndpointSummary,
8539
+ {
8540
+ label: "Anthropic",
8541
+ baseUrl: provider.anthropicBaseUrl,
8542
+ endpoint: PATH_V1_MESSAGES,
8543
+ providerName: provider.name,
8544
+ children: testResults !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: testResults.anthropic })
8545
+ }
8546
+ ),
8547
+ provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx(
8548
+ ProviderEndpointSummary,
8549
+ {
8550
+ label: "OpenAI Chat",
8551
+ baseUrl: provider.openaiBaseUrl,
8552
+ endpoint: PATH_V1_CHAT_COMPLETIONS,
8553
+ providerName: provider.name,
8554
+ children: testResults !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: testResults.openaiChat })
8555
+ }
8556
+ ),
8557
+ provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx(
8558
+ ProviderEndpointSummary,
8559
+ {
8560
+ label: "OpenAI Responses",
8561
+ baseUrl: provider.openaiResponsesBaseUrl,
8562
+ endpoint: PATH_V1_RESPONSES,
8563
+ providerName: provider.name,
8564
+ children: testResults !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: testResults.openaiResponses })
8565
+ }
8566
+ ),
8372
8567
  testResults?.testedAt !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
8373
8568
  /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
8374
8569
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
@@ -8395,12 +8590,14 @@ function ProviderCard({
8395
8590
  /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border", children: [
8396
8591
  /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "Model" }),
8397
8592
  provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "Anthropic" }),
8398
- provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "OpenAI" })
8593
+ provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "Chat" }),
8594
+ provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "Responses" })
8399
8595
  ] }) }),
8400
8596
  /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: Object.entries(testResults.models).map(([modelName, modelResult]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border/50 last:border-0", children: [
8401
8597
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2 font-medium", children: modelName }),
8402
8598
  provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2 align-top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: modelResult.anthropic }) }),
8403
- provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2 align-top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: modelResult.openai }) })
8599
+ provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2 align-top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: modelResult.openaiChat }) }),
8600
+ provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2 align-top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProviderFormatTestStatus, { results: modelResult.openaiResponses }) })
8404
8601
  ] }, modelName)) })
8405
8602
  ] }) })
8406
8603
  ] }),
@@ -8460,9 +8657,9 @@ const ZHIPU_CODING_PROVIDER_KEYWORDS = [
8460
8657
  "z.ai coding",
8461
8658
  "zai coding"
8462
8659
  ];
8463
- const ANTHROPIC_MESSAGES_ENDPOINT = "/v1/messages";
8464
- const OPENAI_CHAT_COMPLETIONS_ENDPOINT = "/v1/chat/completions";
8465
- const OPENAI_RESPONSES_ENDPOINT = "/v1/responses";
8660
+ const ANTHROPIC_MESSAGES_ENDPOINT = PATH_V1_MESSAGES;
8661
+ const OPENAI_CHAT_COMPLETIONS_ENDPOINT = PATH_V1_CHAT_COMPLETIONS;
8662
+ const OPENAI_RESPONSES_ENDPOINT = PATH_V1_RESPONSES;
8466
8663
  const KNOWN_PROVIDER_PRESETS = {
8467
8664
  deepseek: {
8468
8665
  openaiBaseUrl: "https://api.deepseek.com"
@@ -8650,19 +8847,28 @@ function stripEndpointSuffix(value, endpoint) {
8650
8847
  const normalized = trimmed.replace(/\/+$/, "");
8651
8848
  return normalized.endsWith(endpoint) ? normalized.slice(0, -endpoint.length).replace(/\/+$/, "") : trimmed;
8652
8849
  }
8653
- function previewEndpointUrl(baseUrl, endpoint) {
8850
+ function previewEndpointUrl(baseUrl, endpoint, providerName) {
8654
8851
  const trimmed = baseUrl.trim();
8655
- return trimmed === "" ? null : buildUpstreamUrl(trimmed, endpoint);
8852
+ return trimmed === "" ? null : previewUpstreamUrl(trimmed, endpoint, { providerName });
8656
8853
  }
8657
8854
  function EndpointUrlPreview({
8658
8855
  baseUrl,
8659
- endpoint
8856
+ endpoint,
8857
+ providerName
8660
8858
  }) {
8661
- const finalUrl = previewEndpointUrl(baseUrl, endpoint);
8662
- if (finalUrl === null) return null;
8859
+ const preview = previewEndpointUrl(baseUrl, endpoint, providerName);
8860
+ if (preview === null) return null;
8663
8861
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border bg-muted/40 rounded-md px-3 py-2 text-xs", children: [
8664
8862
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground", children: "Final URL" }),
8665
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "break-all font-mono text-foreground", children: finalUrl })
8863
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "break-all font-mono text-foreground", children: preview.finalUrl }),
8864
+ preview.diagnostics.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 space-y-1", children: preview.diagnostics.map((diagnostic) => /* @__PURE__ */ jsxRuntimeExports.jsx(
8865
+ "div",
8866
+ {
8867
+ className: diagnostic.severity === "warning" ? "text-amber-200" : "text-muted-foreground",
8868
+ children: diagnostic.message
8869
+ },
8870
+ `${diagnostic.severity}:${diagnostic.message}`
8871
+ )) })
8666
8872
  ] });
8667
8873
  }
8668
8874
  function ProviderForm({ provider, onSubmit, onCancel }) {
@@ -9037,7 +9243,7 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
9037
9243
  onClick: handleCopy,
9038
9244
  className: "text-muted-foreground hover:text-foreground transition-colors p-1 shrink-0",
9039
9245
  "aria-label": "Copy API key",
9040
- children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-4 text-green-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4" })
9246
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-4 text-cyan-300" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4" })
9041
9247
  }
9042
9248
  )
9043
9249
  ] }),
@@ -9263,7 +9469,14 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
9263
9469
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: ANTHROPIC_MESSAGES_ENDPOINT })
9264
9470
  ] }),
9265
9471
  errors.anthropicBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.anthropicBaseUrl }),
9266
- /* @__PURE__ */ jsxRuntimeExports.jsx(EndpointUrlPreview, { baseUrl: anthropicBaseUrl, endpoint: ANTHROPIC_MESSAGES_ENDPOINT }),
9472
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
9473
+ EndpointUrlPreview,
9474
+ {
9475
+ baseUrl: anthropicBaseUrl,
9476
+ endpoint: ANTHROPIC_MESSAGES_ENDPOINT,
9477
+ providerName: name
9478
+ }
9479
+ ),
9267
9480
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Anthropic-compatible base URL. Leave empty if this provider does not support Anthropic format." })
9268
9481
  ] }),
9269
9482
  activeTab === "openai" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
@@ -9291,7 +9504,8 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
9291
9504
  EndpointUrlPreview,
9292
9505
  {
9293
9506
  baseUrl: openaiBaseUrl,
9294
- endpoint: OPENAI_CHAT_COMPLETIONS_ENDPOINT
9507
+ endpoint: OPENAI_CHAT_COMPLETIONS_ENDPOINT,
9508
+ providerName: name
9295
9509
  }
9296
9510
  ),
9297
9511
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "OpenAI Chat Completions-compatible base URL. Leave empty if this provider only supports the Responses API." })
@@ -9320,7 +9534,8 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
9320
9534
  EndpointUrlPreview,
9321
9535
  {
9322
9536
  baseUrl: openaiResponsesBaseUrl,
9323
- endpoint: OPENAI_RESPONSES_ENDPOINT
9537
+ endpoint: OPENAI_RESPONSES_ENDPOINT,
9538
+ providerName: name
9324
9539
  }
9325
9540
  ),
9326
9541
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Optional Responses-compatible base URL. Set only when the provider supports the Responses API." })
@@ -9851,7 +10066,7 @@ function ProvidersPanel({
9851
10066
  },
9852
10067
  className: "shrink-0 ml-auto text-muted-foreground hover:text-foreground transition-colors",
9853
10068
  "aria-label": configPathCopied ? "Copied config file path" : "Copy config file path",
9854
- children: configPathCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3 text-green-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" })
10069
+ children: configPathCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3 text-cyan-300" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" })
9855
10070
  }
9856
10071
  ) }),
9857
10072
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Copy config file path to clipboard" })
@@ -12141,97 +12356,348 @@ function getModelLabel(logs) {
12141
12356
  if (sorted.length === 1) return sorted[0] ?? "Model unknown";
12142
12357
  return `${sorted.length} models`;
12143
12358
  }
12359
+ function getProviderLabel(logs) {
12360
+ const providers = /* @__PURE__ */ new Set();
12361
+ for (const log of logs) {
12362
+ if (log.providerName !== null && log.providerName !== void 0 && log.providerName.length > 0) {
12363
+ providers.add(log.providerName);
12364
+ }
12365
+ }
12366
+ const sorted = [...providers].sort();
12367
+ if (sorted.length === 0) return "Provider unknown";
12368
+ if (sorted.length === 1) return sorted[0] ?? "Provider unknown";
12369
+ return `${sorted.length} providers`;
12370
+ }
12371
+ function formatElapsedMs(ms) {
12372
+ if (ms < 1e3) return `${ms}ms`;
12373
+ if (ms < 6e4) {
12374
+ const seconds2 = ms / 1e3;
12375
+ return `${seconds2 < 10 ? seconds2.toFixed(1) : seconds2.toFixed(0)}s`;
12376
+ }
12377
+ const totalSeconds = Math.round(ms / 1e3);
12378
+ const minutes = Math.floor(totalSeconds / 60);
12379
+ const seconds = totalSeconds % 60;
12380
+ return `${minutes}m ${seconds}s`;
12381
+ }
12382
+ function formatTokenPair(inputTokens, outputTokens) {
12383
+ return `${formatTokens(inputTokens)} in / ${formatTokens(outputTokens)} out`;
12384
+ }
12385
+ function countSessionTurns(logs, conversationGroups) {
12386
+ if (logs.length === 0) return 0;
12387
+ if (conversationGroups.length === 0) return buildTurnGroups(logs).length;
12388
+ let turns = 0;
12389
+ for (const group of conversationGroups) {
12390
+ turns += buildTurnGroups(group.logs).length;
12391
+ }
12392
+ return turns;
12393
+ }
12394
+ function summarizeFinishReason({
12395
+ stopReason,
12396
+ pending,
12397
+ lastFailureLogNumber
12398
+ }) {
12399
+ if (pending > 0) {
12400
+ return {
12401
+ label: "In flight",
12402
+ detail: `${pending} request${pending === 1 ? "" : "s"} pending`,
12403
+ tone: "cool"
12404
+ };
12405
+ }
12406
+ if (lastFailureLogNumber !== null && stopReason === null) {
12407
+ return {
12408
+ label: "Error",
12409
+ detail: `Last failed request #${lastFailureLogNumber}`,
12410
+ tone: "danger"
12411
+ };
12412
+ }
12413
+ switch (stopReason) {
12414
+ case "end_turn":
12415
+ return { label: "End turn", detail: "Assistant completed the turn", tone: "neutral" };
12416
+ case "stop":
12417
+ return { label: "Stop", detail: "Model reached a stop condition", tone: "neutral" };
12418
+ case "length":
12419
+ return { label: "Output limit", detail: "Turn ended at max output tokens", tone: "watch" };
12420
+ case "tool_use":
12421
+ return { label: "Tool call", detail: "Assistant requested a tool", tone: "cool" };
12422
+ case null:
12423
+ return { label: "Unknown", detail: "No finish reason captured", tone: "neutral" };
12424
+ }
12425
+ }
12426
+ function isClientAbortError(error) {
12427
+ if (error === null) return false;
12428
+ const lower = error.toLowerCase();
12429
+ return lower.includes("abort") || lower.includes("cancel") || lower.includes("client disconnected") || lower.includes("stream disconnected") || lower.includes("connection closed");
12430
+ }
12431
+ function summarizeSessionOutcome({
12432
+ pending,
12433
+ failures,
12434
+ lengthStops,
12435
+ stopReason,
12436
+ lastFailure
12437
+ }) {
12438
+ if (lastFailure !== null && (lastFailure.status === 499 || isClientAbortError(lastFailure.error))) {
12439
+ return {
12440
+ label: "Client aborted",
12441
+ detail: `Request #${lastFailure.logNumber} ended before completion`,
12442
+ tone: "watch"
12443
+ };
12444
+ }
12445
+ if (pending > 0) {
12446
+ return {
12447
+ label: "In flight",
12448
+ detail: `${pending} request${pending === 1 ? "" : "s"} still running`,
12449
+ tone: "cool"
12450
+ };
12451
+ }
12452
+ if (lastFailure !== null && lastFailure.status !== null && lastFailure.status >= 500) {
12453
+ return {
12454
+ label: "Provider error",
12455
+ detail: `Request #${lastFailure.logNumber} returned HTTP ${lastFailure.status}`,
12456
+ tone: "danger"
12457
+ };
12458
+ }
12459
+ if (failures > 0 && lastFailure !== null) {
12460
+ return {
12461
+ label: "Failed",
12462
+ detail: `Request #${lastFailure.logNumber} needs attention`,
12463
+ tone: "danger"
12464
+ };
12465
+ }
12466
+ if (lengthStops > 0 || stopReason === "length") {
12467
+ return {
12468
+ label: "Output limited",
12469
+ detail: "Model stopped at the output token limit",
12470
+ tone: "watch"
12471
+ };
12472
+ }
12473
+ switch (stopReason) {
12474
+ case "end_turn":
12475
+ case "stop":
12476
+ return { label: "Completed", detail: "Assistant completed normally", tone: "neutral" };
12477
+ case "tool_use":
12478
+ return { label: "Tool requested", detail: "Assistant handed off to a tool", tone: "cool" };
12479
+ case null:
12480
+ return { label: "Unknown", detail: "No terminal signal captured", tone: "neutral" };
12481
+ }
12482
+ }
12144
12483
  function buildSessionSlateStats({
12145
12484
  logs,
12485
+ conversationGroups,
12146
12486
  isLoading,
12147
12487
  timeDisplayFormat,
12148
12488
  slowResponseThresholdSeconds
12149
12489
  }) {
12150
12490
  let failures = 0;
12491
+ let pending = 0;
12151
12492
  let slow = 0;
12493
+ let lengthStops = 0;
12152
12494
  let totalIn = 0;
12153
12495
  let totalOut = 0;
12496
+ let terminalStopReason = null;
12497
+ let lastFailureLogNumber = null;
12498
+ let lastFailure = null;
12499
+ let slowestMs = null;
12500
+ let slowestLogNumber = null;
12501
+ let heaviestTokens = 0;
12502
+ let heaviestInputTokens = 0;
12503
+ let heaviestOutputTokens = 0;
12504
+ let heaviestLogNumber = null;
12154
12505
  const slowThresholdMs = slowResponseThresholdSeconds * 1e3;
12155
- for (const log of logs) {
12156
- if (hasLogFailure(log)) failures += 1;
12506
+ for (let index = 0; index < logs.length; index += 1) {
12507
+ const log = logs[index];
12508
+ if (log === void 0) continue;
12509
+ const logNumber = index + 1;
12510
+ const stopReason = extractStopReason(log);
12511
+ if (stopReason !== null) terminalStopReason = stopReason;
12512
+ if (stopReason === "length") lengthStops += 1;
12513
+ if (hasLogFailure(log)) {
12514
+ failures += 1;
12515
+ lastFailureLogNumber = logNumber;
12516
+ lastFailure = {
12517
+ logNumber,
12518
+ status: log.responseStatus,
12519
+ error: log.error ?? null
12520
+ };
12521
+ }
12522
+ if (log.responseStatus === null) pending += 1;
12157
12523
  if (slowResponseThresholdSeconds > 0 && log.elapsedMs !== null && log.elapsedMs >= slowThresholdMs) {
12158
12524
  slow += 1;
12159
12525
  }
12160
12526
  if (log.inputTokens !== null) totalIn += log.inputTokens;
12161
12527
  if (log.outputTokens !== null) totalOut += log.outputTokens;
12528
+ if (log.elapsedMs !== null && (slowestMs === null || log.elapsedMs > slowestMs)) {
12529
+ slowestMs = log.elapsedMs;
12530
+ slowestLogNumber = logNumber;
12531
+ }
12532
+ const inputTokens = log.inputTokens ?? 0;
12533
+ const outputTokens = log.outputTokens ?? 0;
12534
+ const requestTokens = inputTokens + outputTokens;
12535
+ if (requestTokens > heaviestTokens) {
12536
+ heaviestTokens = requestTokens;
12537
+ heaviestInputTokens = inputTokens;
12538
+ heaviestOutputTokens = outputTokens;
12539
+ heaviestLogNumber = logNumber;
12540
+ }
12162
12541
  }
12163
- const status = isLoading ? "rolling" : failures > 0 ? "failed" : slow > 0 ? "watch" : "clear";
12542
+ const status = isLoading || pending > 0 && failures === 0 ? "rolling" : failures > 0 ? "failed" : slow > 0 || lengthStops > 0 ? "watch" : "clear";
12164
12543
  const statusLabel2 = status === "rolling" ? "Rolling" : status === "failed" ? "Failure" : status === "watch" ? "Watch" : "Clear";
12544
+ const finish = summarizeFinishReason({
12545
+ stopReason: terminalStopReason,
12546
+ pending,
12547
+ lastFailureLogNumber
12548
+ });
12549
+ const outcome = summarizeSessionOutcome({
12550
+ pending,
12551
+ failures,
12552
+ lengthStops,
12553
+ stopReason: terminalStopReason,
12554
+ lastFailure
12555
+ });
12165
12556
  return {
12166
12557
  status,
12167
12558
  statusLabel: statusLabel2,
12168
12559
  modelLabel: getModelLabel(logs),
12560
+ providerLabel: getProviderLabel(logs),
12169
12561
  requests: logs.length,
12562
+ turns: countSessionTurns(logs, conversationGroups),
12170
12563
  failures,
12564
+ pending,
12171
12565
  slow,
12566
+ lengthStops,
12172
12567
  timeRange: formatTimeRange(logs, timeDisplayFormat),
12173
- tokenLabel: `${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out`
12568
+ tokenLabel: `${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out`,
12569
+ finishLabel: finish.label,
12570
+ finishDetail: finish.detail,
12571
+ finishTone: finish.tone,
12572
+ outcomeLabel: outcome.label,
12573
+ outcomeDetail: outcome.detail,
12574
+ outcomeTone: outcome.tone,
12575
+ slowestLabel: slowestMs === null ? "n/a" : formatElapsedMs(slowestMs),
12576
+ slowestDetail: slowestLogNumber === null ? "Latency pending" : `Request #${slowestLogNumber}`,
12577
+ heaviestDetail: heaviestLogNumber === null ? "Tokens pending" : `#${heaviestLogNumber} ${formatTokenPair(heaviestInputTokens, heaviestOutputTokens)}`
12174
12578
  };
12175
12579
  }
12176
- function slateStatusClass(status) {
12580
+ function slateMetricToneClass(tone) {
12581
+ switch (tone) {
12582
+ case "cool":
12583
+ return "text-cyan-100";
12584
+ case "danger":
12585
+ return "text-red-100";
12586
+ case "watch":
12587
+ return "text-amber-100";
12588
+ case "neutral":
12589
+ return "text-foreground";
12590
+ }
12591
+ }
12592
+ function statusMetricTone(status) {
12177
12593
  switch (status) {
12178
12594
  case "rolling":
12179
- return "border-cyan-400/35 bg-cyan-500/10 text-cyan-200";
12595
+ return "cool";
12180
12596
  case "failed":
12181
- return "border-red-400/35 bg-red-500/10 text-red-100";
12597
+ return "danger";
12182
12598
  case "watch":
12183
- return "border-amber-300/35 bg-amber-400/10 text-amber-100";
12599
+ return "watch";
12184
12600
  case "clear":
12185
- return "border-slate-300/20 bg-slate-300/[0.08] text-slate-100";
12601
+ return "neutral";
12186
12602
  }
12187
12603
  }
12604
+ function requestHealthDetail(stats) {
12605
+ if (stats.pending > 0) return `${stats.pending} pending / ${stats.failures} failed`;
12606
+ if (stats.lengthStops > 0) return `${stats.lengthStops} output limit / ${stats.failures} failed`;
12607
+ return `${stats.failures} failed / ${stats.slow} slow`;
12608
+ }
12609
+ function SessionSlateMetric({
12610
+ label,
12611
+ value,
12612
+ detail,
12613
+ icon,
12614
+ tone = "neutral"
12615
+ }) {
12616
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 border-t border-white/10 px-4 py-3", children: [
12617
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-[10px] uppercase text-muted-foreground", children: [
12618
+ icon,
12619
+ label
12620
+ ] }),
12621
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("mt-2 font-mono text-sm font-semibold", slateMetricToneClass(tone)), children: value }),
12622
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 font-mono text-[11px] leading-snug text-muted-foreground", children: detail })
12623
+ ] });
12624
+ }
12188
12625
  function SessionOpeningSlate({ stats }) {
12189
12626
  if (stats.requests === 0) return null;
12190
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-border bg-card shadow-sm mb-4 rounded-[8px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-0 md:grid-cols-[minmax(220px,1.2fr)_repeat(4,minmax(120px,1fr))]", children: [
12191
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 border-b border-white/10 px-4 py-3 md:col-span-1 md:border-b-0 md:border-r", children: [
12192
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-[10px] font-semibold uppercase text-muted-foreground", children: [
12193
- /* @__PURE__ */ jsxRuntimeExports.jsx(Clapperboard, { className: "size-3.5 text-cyan-300" }),
12194
- "Opening Slate"
12627
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border bg-card shadow-sm mb-4 overflow-hidden rounded-[8px]", children: [
12628
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [
12629
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
12630
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-[10px] font-semibold uppercase text-muted-foreground", children: [
12631
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clapperboard, { className: "size-3.5 text-slate-300" }),
12632
+ "Flight Recorder"
12633
+ ] }),
12634
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 min-w-0 font-mono text-sm font-semibold text-foreground", children: stats.modelLabel })
12195
12635
  ] }),
12196
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 min-w-0 truncate font-mono text-sm font-semibold text-foreground", children: stats.modelLabel }),
12197
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 truncate font-mono text-[11px] text-muted-foreground", children: stats.timeRange ?? "Timeline pending" })
12198
- ] }),
12199
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-r border-b border-white/10 px-4 py-3 md:border-b-0", children: [
12200
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase text-muted-foreground", children: "Status" }),
12636
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-4 gap-y-1 text-[11px] text-muted-foreground", children: [
12637
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 font-mono", children: stats.providerLabel }),
12638
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 font-mono", children: stats.timeRange ?? "Timeline pending" })
12639
+ ] })
12640
+ ] }) }),
12641
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 border-t border-white/10 md:grid-cols-3 2xl:grid-cols-6", children: [
12201
12642
  /* @__PURE__ */ jsxRuntimeExports.jsx(
12202
- "div",
12643
+ SessionSlateMetric,
12203
12644
  {
12204
- className: cn(
12205
- "mt-2 inline-flex h-7 items-center rounded-md border px-2.5 font-mono text-xs font-semibold",
12206
- slateStatusClass(stats.status)
12207
- ),
12208
- children: stats.statusLabel
12645
+ label: "Status",
12646
+ value: stats.statusLabel,
12647
+ detail: requestHealthDetail(stats),
12648
+ tone: statusMetricTone(stats.status)
12649
+ }
12650
+ ),
12651
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
12652
+ SessionSlateMetric,
12653
+ {
12654
+ label: "Turns",
12655
+ value: String(stats.turns),
12656
+ detail: stats.finishLabel,
12657
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Flag, { className: "size-3 text-muted-foreground" }),
12658
+ tone: stats.finishTone
12659
+ }
12660
+ ),
12661
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
12662
+ SessionSlateMetric,
12663
+ {
12664
+ label: "Requests",
12665
+ value: String(stats.requests),
12666
+ detail: `${stats.failures} failed / ${stats.slow} slow`,
12667
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Siren, { className: "size-3 text-muted-foreground" }),
12668
+ tone: stats.failures > 0 ? "danger" : "neutral"
12669
+ }
12670
+ ),
12671
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
12672
+ SessionSlateMetric,
12673
+ {
12674
+ label: "Peak",
12675
+ value: stats.slowestLabel,
12676
+ detail: stats.slowestDetail,
12677
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Timer, { className: "size-3 text-muted-foreground" }),
12678
+ tone: stats.slow > 0 ? "watch" : "neutral"
12679
+ }
12680
+ ),
12681
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
12682
+ SessionSlateMetric,
12683
+ {
12684
+ label: "Tokens",
12685
+ value: stats.tokenLabel,
12686
+ detail: stats.heaviestDetail,
12687
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { className: "size-3 text-muted-foreground" })
12688
+ }
12689
+ ),
12690
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
12691
+ SessionSlateMetric,
12692
+ {
12693
+ label: "Outcome",
12694
+ value: stats.outcomeLabel,
12695
+ detail: stats.outcomeDetail,
12696
+ tone: stats.outcomeTone
12209
12697
  }
12210
12698
  )
12211
- ] }),
12212
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-white/10 px-4 py-3 md:border-b-0 md:border-r", children: [
12213
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase text-muted-foreground", children: "Requests" }),
12214
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 font-mono text-xl font-semibold text-foreground", children: stats.requests })
12215
- ] }),
12216
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-r border-white/10 px-4 py-3 md:border-r", children: [
12217
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-[10px] uppercase text-muted-foreground", children: [
12218
- /* @__PURE__ */ jsxRuntimeExports.jsx(Siren, { className: "size-3 text-red-300" }),
12219
- "Failure"
12220
- ] }),
12221
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 font-mono text-xl font-semibold text-red-100", children: stats.failures })
12222
- ] }),
12223
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3", children: [
12224
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-[10px] uppercase text-muted-foreground", children: [
12225
- /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { className: "size-3 text-amber-200" }),
12226
- "Tempo"
12227
- ] }),
12228
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 font-mono text-sm font-semibold text-foreground", children: [
12229
- stats.slow,
12230
- " slow"
12231
- ] }),
12232
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 truncate font-mono text-[11px] text-muted-foreground", children: stats.tokenLabel })
12233
12699
  ] })
12234
- ] }) });
12700
+ ] });
12235
12701
  }
12236
12702
  function resolveSessionContextScope({
12237
12703
  pinnedSessionId,
@@ -13193,11 +13659,12 @@ function ProxyViewer({
13193
13659
  const slateStats = reactExports.useMemo(
13194
13660
  () => buildSessionSlateStats({
13195
13661
  logs,
13662
+ conversationGroups: groups,
13196
13663
  isLoading,
13197
13664
  timeDisplayFormat,
13198
13665
  slowResponseThresholdSeconds
13199
13666
  }),
13200
- [isLoading, logs, slowResponseThresholdSeconds, timeDisplayFormat]
13667
+ [groups, isLoading, logs, slowResponseThresholdSeconds, timeDisplayFormat]
13201
13668
  );
13202
13669
  const handleCompareWithPrevious = reactExports.useCallback(
13203
13670
  (log) => {