@tonyclaw/llm-inspector 1.14.9 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, a as parseRequest, O as OpenAIRequestSchema, p as parseOpenAIResponse, I as InspectorResponseSchema, s as stripClaudeCodeBillingHeader, R as RuntimeConfigSchema, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema } from "./router-CmanwZJc.mjs";
2
+ import { C as CapturedLogSchema, a as parseRequest, R as RuntimeConfigSchema, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema, O as OpenAIRequestSchema, p as parseOpenAIResponse, I as InspectorResponseSchema, s as stripClaudeCodeBillingHeader } from "./router-DpLCKk51.mjs";
3
3
  import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
4
4
  import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
5
5
  import { c as clsx } from "../_libs/clsx.mjs";
@@ -8,13 +8,13 @@ import { J as JSZip } from "../_libs/jszip.mjs";
8
8
  import { c as cva } from "../_libs/class-variance-authority.mjs";
9
9
  import { d as diffLines, a as diffJson } from "../_libs/diff.mjs";
10
10
  import { R as Root, T as Trigger$2, C as Content, a as Close, b as Title, P as Portal$2, O as Overlay } from "../_libs/radix-ui__react-dialog.mjs";
11
- import { R as Root2, T as Trigger$1, I as Icon, V as Value, P as Portal$1, C as Content2$1, 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";
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
12
  import "../_libs/modelcontextprotocol__server.mjs";
13
- import { D as Download, L as LayoutGrid, a as List, G as GitBranch, S as Settings, C as ChevronDown, b as Check, c as GitCompareArrows, R as RotateCcw, X, U as Upload, d as Scan, P as Plus, e as Copy, f as CircleAlert, g as ChevronUp, h as LoaderCircle, i as ChevronRight, j as User, k as Clock, M as MessageSquare, Z as Zap, W as Wrench, l as Globe, F as FileTerminal, m as Radio, n as Rows3, o as Columns2, p as Minus, q as Pencil, E as Equal, r as EyeOff, s as Eye, t as ExternalLink, u as RotateCw, T as Trash2, A as ArrowUp, v as ArrowDown, w as TriangleAlert, x as CircleCheckBig, y as CircleStop, z as CircleQuestionMark, B as Server, H as Gauge, I as Lock, J as Wifi, K as WifiOff, N as ChevronsUp, O as ChevronsDown, Q as Brain, V as Terminal } from "../_libs/lucide-react.mjs";
13
+ import { D as Download, S as Settings, C as ChevronDown, a as Check, X, U as Upload, b as Scan, P as Plus, c as Copy, d as CircleAlert, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, R as Rows3, i as Columns2, j as Minus, k as Pencil, E as Equal, l as EyeOff, m as Eye, n as ExternalLink, o as RotateCw, T as Trash2, G as GitCompareArrows, p as RotateCcw, q as CircleCheckBig, W as Wrench, r as Globe, F as FileTerminal, s as Radio, t as CircleQuestionMark, u as Server, v as Gauge, w as Lock, x as Wifi, y as WifiOff, A as ArrowUp, z as ArrowDown, B as TriangleAlert, H as CircleStop, I as ChevronsUp, J as ChevronsDown, K as Brain, N as Terminal } from "../_libs/lucide-react.mjs";
14
14
  import { M as Markdown } from "../_libs/react-markdown.mjs";
15
15
  import { a as array, b as string, u as union, d as object, l as literal, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
16
- import { P as Provider, R as Root3, T as Trigger, a as Portal, C as Content2, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
17
- import { R as Root2$1, L as List$1, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
16
+ import { P as Provider, R as Root3, T as Trigger$1, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
17
+ import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
18
18
  import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
19
19
  import { R as Root$1 } from "../_libs/radix-ui__react-separator.mjs";
20
20
  import { R as Root$2, C as CollapsibleTrigger$1, a as CollapsibleContent$1 } from "../_libs/radix-ui__react-collapsible.mjs";
@@ -269,7 +269,7 @@ function Tooltip({ ...props }) {
269
269
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Root3, { "data-slot": "tooltip", ...props });
270
270
  }
271
271
  function TooltipTrigger({ ...props }) {
272
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger, { "data-slot": "tooltip-trigger", ...props });
272
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$1, { "data-slot": "tooltip-trigger", ...props });
273
273
  }
274
274
  function TooltipContent({
275
275
  className,
@@ -277,8 +277,8 @@ function TooltipContent({
277
277
  children,
278
278
  ...props
279
279
  }) {
280
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
281
- Content2,
280
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
281
+ Content2$1,
282
282
  {
283
283
  "data-slot": "tooltip-content",
284
284
  sideOffset,
@@ -333,7 +333,7 @@ async function exportLogsAsZip(logs) {
333
333
  document.body.removeChild(anchor);
334
334
  URL.revokeObjectURL(url);
335
335
  }
336
- const version = "1.14.9";
336
+ const version = "1.15.0";
337
337
  const packageJson = {
338
338
  version
339
339
  };
@@ -348,13 +348,13 @@ function extractStopReason(log) {
348
348
  json = JSON.parse(json);
349
349
  }
350
350
  if (!isRecord(json)) return null;
351
- if (log.apiFormat === "anthropic" && typeof json.stop_reason === "string") {
351
+ if (typeof json.stop_reason === "string") {
352
352
  if (json.stop_reason === "end_turn" || json.stop_reason === "tool_use") {
353
353
  return json.stop_reason;
354
354
  }
355
355
  return null;
356
356
  }
357
- if (log.apiFormat === "openai" && Array.isArray(json.choices) && json.choices.length > 0 && isRecord(json.choices[0]) && typeof json.choices[0].finish_reason === "string" && json.choices[0].finish_reason === "stop") {
357
+ if (Array.isArray(json.choices) && json.choices.length > 0 && isRecord(json.choices[0]) && typeof json.choices[0].finish_reason === "string" && json.choices[0].finish_reason === "stop") {
358
358
  return "stop";
359
359
  }
360
360
  return null;
@@ -362,6 +362,9 @@ function extractStopReason(log) {
362
362
  return null;
363
363
  }
364
364
  }
365
+ function isTurnBoundary(stopReason) {
366
+ return stopReason === "end_turn" || stopReason === "stop";
367
+ }
365
368
  const badgeVariants = cva(
366
369
  "inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
367
370
  {
@@ -418,8 +421,6 @@ function ConversationHeader({
418
421
  onToggle,
419
422
  hideApiFormat = false,
420
423
  isLoading = false,
421
- viewMode,
422
- onToggleViewMode,
423
424
  userAgent
424
425
  }) {
425
426
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -442,22 +443,6 @@ function ConversationHeader({
442
443
  },
443
444
  children: [
444
445
  expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" }),
445
- expanded && onToggleViewMode !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
446
- "button",
447
- {
448
- type: "button",
449
- onClick: (e) => {
450
- e.stopPropagation();
451
- onToggleViewMode();
452
- },
453
- className: cn(
454
- "px-1.5 py-0.5 rounded text-[10px] font-mono transition-colors shrink-0 cursor-pointer",
455
- viewMode === "thread" ? "bg-amber-500/15 text-amber-400 border border-amber-500/30" : "bg-muted text-muted-foreground border border-border hover:text-foreground"
456
- ),
457
- title: viewMode === "thread" ? "Thread view — click for flat view" : "Flat view — click for thread view",
458
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "size-3" })
459
- }
460
- ),
461
446
  /* @__PURE__ */ jsxRuntimeExports.jsx(
462
447
  "span",
463
448
  {
@@ -995,7 +980,7 @@ function TabsList({
995
980
  ...props
996
981
  }) {
997
982
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
998
- List$1,
983
+ List,
999
984
  {
1000
985
  "data-slot": "tabs-list",
1001
986
  "data-variant": variant,
@@ -1530,7 +1515,7 @@ const LogEntryHeader = reactExports.memo(function({
1530
1515
  children: log.responseStatus
1531
1516
  }
1532
1517
  ) }),
1533
- log.elapsedMs !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
1518
+ log.elapsedMs !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden xl:flex items-center gap-1 text-muted-foreground text-xs shrink-0", children: [
1534
1519
  /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
1535
1520
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: formatElapsed(log.elapsedMs) })
1536
1521
  ] }),
@@ -1601,7 +1586,7 @@ const LogEntryHeader = reactExports.memo(function({
1601
1586
  log.origin !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1602
1587
  "span",
1603
1588
  {
1604
- className: "flex items-center gap-1 text-muted-foreground text-xs shrink-0",
1589
+ className: "hidden xl:flex items-center gap-1 text-muted-foreground text-xs shrink-0",
1605
1590
  title: `Origin: ${log.origin}`,
1606
1591
  children: [
1607
1592
  /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { className: "size-3" }),
@@ -1610,7 +1595,7 @@ const LogEntryHeader = reactExports.memo(function({
1610
1595
  }
1611
1596
  ),
1612
1597
  (log.clientPid !== null || log.clientProjectFolder !== null) && /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
1613
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-purple-400/80 text-xs shrink-0", children: [
1598
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden xl:flex items-center gap-1 text-purple-400/80 text-xs shrink-0", children: [
1614
1599
  /* @__PURE__ */ jsxRuntimeExports.jsx(FileTerminal, { className: "size-3" }),
1615
1600
  log.clientProjectFolder !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono tabular-nums", children: log.clientProjectFolder }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums", children: [
1616
1601
  "PID ",
@@ -2784,51 +2769,399 @@ const LogEntry = reactExports.memo(function({
2784
2769
  /* @__PURE__ */ jsxRuntimeExports.jsx(ReplayDialog, { log, open: replayOpen, onOpenChange: setReplayOpen })
2785
2770
  ] });
2786
2771
  });
2772
+ function SvgShell({
2773
+ className,
2774
+ style,
2775
+ d,
2776
+ eyeStalks,
2777
+ eyes,
2778
+ legs,
2779
+ extras
2780
+ }) {
2781
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
2782
+ "svg",
2783
+ {
2784
+ viewBox: "0 0 24 24",
2785
+ fill: "none",
2786
+ stroke: "currentColor",
2787
+ strokeWidth: "1.5",
2788
+ strokeLinecap: "round",
2789
+ strokeLinejoin: "round",
2790
+ "aria-hidden": "true",
2791
+ style,
2792
+ className: cn("inline-block size-5", className),
2793
+ children: [
2794
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d }),
2795
+ eyeStalks,
2796
+ eyes,
2797
+ legs,
2798
+ extras
2799
+ ]
2800
+ }
2801
+ );
2802
+ }
2803
+ const StdLegs = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2804
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6.5", y1: "16", x2: "4.5", y2: "19.5" }),
2805
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "17.5", x2: "8", y2: "20.5" }),
2806
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15", y1: "17.5", x2: "16", y2: "20.5" }),
2807
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17.5", y1: "16", x2: "19.5", y2: "19.5" })
2808
+ ] });
2809
+ const ShortLegs = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2810
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "16", x2: "5.5", y2: "18.5" }),
2811
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "17", x2: "8.5", y2: "19.5" }),
2812
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "17", x2: "15.5", y2: "19.5" }),
2813
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "16", x2: "18.5", y2: "18.5" })
2814
+ ] });
2815
+ function Crab1({ className }) {
2816
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2817
+ SvgShell,
2818
+ {
2819
+ className,
2820
+ 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",
2821
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2822
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
2823
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
2824
+ ] }),
2825
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2826
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" }),
2827
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" })
2828
+ ] }),
2829
+ legs: StdLegs,
2830
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2831
+ /* @__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" }),
2832
+ /* @__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" })
2833
+ ] })
2834
+ }
2835
+ );
2836
+ }
2837
+ function Crab2({ className }) {
2838
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2839
+ SvgShell,
2840
+ {
2841
+ className,
2842
+ 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",
2843
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2844
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "6.5", x2: "9.5", y2: "4.5" }),
2845
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "6.5", x2: "14.5", y2: "4.5" })
2846
+ ] }),
2847
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2848
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" }),
2849
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4", r: "1.1", fill: "currentColor", stroke: "none" })
2850
+ ] }),
2851
+ legs: ShortLegs,
2852
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2853
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C4 9.5 2.5 10 3 12 C3.5 13.5 4.5 13 5 12" }),
2854
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20 9.5 21.5 10 21 12 C20.5 13.5 19.5 13 19 12" })
2855
+ ] })
2856
+ }
2857
+ );
2858
+ }
2859
+ function Crab3({ className }) {
2860
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2861
+ SvgShell,
2862
+ {
2863
+ className,
2864
+ 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",
2865
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2866
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "7", x2: "6.5", y2: "4.5" }),
2867
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "7", x2: "17.5", y2: "4.5" })
2868
+ ] }),
2869
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2870
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "6.5", cy: "4", r: "0.8", fill: "currentColor", stroke: "none" }),
2871
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17.5", cy: "4", r: "0.8", fill: "currentColor", stroke: "none" })
2872
+ ] }),
2873
+ legs: StdLegs,
2874
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2875
+ /* @__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" }),
2876
+ /* @__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" })
2877
+ ] })
2878
+ }
2879
+ );
2880
+ }
2881
+ function Crab4({ className }) {
2882
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2883
+ SvgShell,
2884
+ {
2885
+ className,
2886
+ 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",
2887
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2888
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6.5", x2: "10", y2: "3.5" }),
2889
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "6.5", x2: "14", y2: "3.5" })
2890
+ ] }),
2891
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2892
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "10", cy: "3", r: "0.7", fill: "currentColor", stroke: "none" }),
2893
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14", cy: "3", r: "0.7", fill: "currentColor", stroke: "none" })
2894
+ ] }),
2895
+ legs: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2896
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7", y1: "17", x2: "5", y2: "20.5" }),
2897
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "18.5", x2: "8.5", y2: "21.5" }),
2898
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "18.5", x2: "15.5", y2: "21.5" }),
2899
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "17", y1: "17", x2: "19", y2: "20.5" })
2900
+ ] }),
2901
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2902
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6.5 11 C5 8.5 3 9 3.5 11.5 C4 13.5 5 13 6 12" }),
2903
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M17.5 11 C19 8.5 21 9 20.5 11.5 C20 13.5 19 13 18 12" })
2904
+ ] })
2905
+ }
2906
+ );
2907
+ }
2908
+ function Crab5({ className }) {
2909
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2910
+ SvgShell,
2911
+ {
2912
+ className,
2913
+ 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",
2914
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2915
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
2916
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
2917
+ ] }),
2918
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2919
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.8", fill: "currentColor", stroke: "none" }),
2920
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.8", fill: "currentColor", stroke: "none" })
2921
+ ] }),
2922
+ legs: StdLegs,
2923
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2924
+ /* @__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" }),
2925
+ /* @__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" })
2926
+ ] })
2927
+ }
2928
+ );
2929
+ }
2930
+ function Crab6({ className }) {
2931
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2932
+ SvgShell,
2933
+ {
2934
+ className,
2935
+ 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",
2936
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2937
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
2938
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
2939
+ ] }),
2940
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2941
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.9", fill: "currentColor", stroke: "none" }),
2942
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13.5", y1: "4", x2: "15.5", y2: "5" })
2943
+ ] }),
2944
+ legs: StdLegs,
2945
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2946
+ /* @__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" }),
2947
+ /* @__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" })
2948
+ ] })
2949
+ }
2950
+ );
2951
+ }
2952
+ function Crab7({ className }) {
2953
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2954
+ SvgShell,
2955
+ {
2956
+ className,
2957
+ 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",
2958
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2959
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "8", x2: "10", y2: "6" }),
2960
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "8", x2: "14", y2: "6" })
2961
+ ] }),
2962
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2963
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "6", x2: "11", y2: "6.5" }),
2964
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13", y1: "6", x2: "15", y2: "6.5" })
2965
+ ] }),
2966
+ legs: ShortLegs,
2967
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2968
+ /* @__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" }),
2969
+ /* @__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" })
2970
+ ] })
2971
+ }
2972
+ );
2973
+ }
2974
+ function Crab8({ className }) {
2975
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
2976
+ SvgShell,
2977
+ {
2978
+ className,
2979
+ 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",
2980
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2981
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
2982
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
2983
+ ] }),
2984
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2985
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "0.7", fill: "currentColor", stroke: "none" }),
2986
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "0.7", fill: "currentColor", stroke: "none" })
2987
+ ] }),
2988
+ legs: StdLegs,
2989
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2990
+ /* @__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" }),
2991
+ /* @__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" }),
2992
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "8.5", y1: "4", x2: "10.5", y2: "4.5" }),
2993
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15.5", y1: "4", x2: "13.5", y2: "4.5" }),
2994
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 15.5 C10 14.5 14 14.5 15 15.5" })
2995
+ ] })
2996
+ }
2997
+ );
2998
+ }
2999
+ function Crab9({ className }) {
3000
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3001
+ SvgShell,
3002
+ {
3003
+ className,
3004
+ 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",
3005
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3006
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5" }),
3007
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5" })
3008
+ ] }),
3009
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3010
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9.5", cy: "4.5", r: "1.2", fill: "none", stroke: "currentColor" }),
3011
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "14.5", cy: "4.5", r: "1.2", fill: "none", stroke: "currentColor" })
3012
+ ] }),
3013
+ legs: StdLegs,
3014
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3015
+ /* @__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" }),
3016
+ /* @__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" }),
3017
+ /* @__PURE__ */ jsxRuntimeExports.jsx("ellipse", { cx: "12", cy: "15", rx: "2", ry: "1.5", fill: "currentColor", stroke: "none" })
3018
+ ] })
3019
+ }
3020
+ );
3021
+ }
3022
+ function Crab10({ className }) {
3023
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3024
+ SvgShell,
3025
+ {
3026
+ className,
3027
+ 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",
3028
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3029
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9.5", y1: "7", x2: "9", y2: "5" }),
3030
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14.5", y1: "7", x2: "15", y2: "5" })
3031
+ ] }),
3032
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3033
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9", cy: "4.5", r: "1", fill: "currentColor", stroke: "none" }),
3034
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "15", cy: "4.5", r: "1", fill: "currentColor", stroke: "none" })
3035
+ ] }),
3036
+ legs: StdLegs,
3037
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3038
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M5 11 C3.5 9 2 9.5 2.5 12 C3 14 4 13 5 12" }),
3039
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 11 C20.5 9 22 9.5 21.5 12 C21 14 20 13 19 12" }),
3040
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 14.5 C10 16 14 16 15 14.5" }),
3041
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "13", r: "1", fill: "currentColor", stroke: "none", opacity: "0.3" }),
3042
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "13", r: "1", fill: "currentColor", stroke: "none", opacity: "0.3" })
3043
+ ] })
3044
+ }
3045
+ );
3046
+ }
3047
+ function Crab11({ className }) {
3048
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3049
+ SvgShell,
3050
+ {
3051
+ className,
3052
+ 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",
3053
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3054
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "7", x2: "9.5", y2: "5.5" }),
3055
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "7", x2: "14.5", y2: "5.5" })
3056
+ ] }),
3057
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3058
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "7.5", y1: "5.5", x2: "16.5", y2: "5.5" }),
3059
+ /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "7", y: "5", width: "4", height: "2", rx: "0.5", fill: "currentColor", stroke: "none" }),
3060
+ /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "13", y: "5", width: "4", height: "2", rx: "0.5", fill: "currentColor", stroke: "none" })
3061
+ ] }),
3062
+ legs: StdLegs,
3063
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3064
+ /* @__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" }),
3065
+ /* @__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" }),
3066
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9.5 15 C10.5 16 13.5 16 14.5 15" })
3067
+ ] })
3068
+ }
3069
+ );
3070
+ }
3071
+ function Crab12({ className }) {
3072
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3073
+ SvgShell,
3074
+ {
3075
+ className,
3076
+ 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",
3077
+ eyeStalks: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3078
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10.5", y1: "9.5", x2: "10.5", y2: "8" }),
3079
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "13.5", y1: "9.5", x2: "13.5", y2: "8" })
3080
+ ] }),
3081
+ eyes: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3082
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "10.5", cy: "7.5", r: "0.8", fill: "currentColor", stroke: "none" }),
3083
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "13.5", cy: "7.5", r: "0.8", fill: "currentColor", stroke: "none" })
3084
+ ] }),
3085
+ legs: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3086
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "8", y1: "16", x2: "6.5", y2: "18" }),
3087
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "17", x2: "9.5", y2: "19" }),
3088
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "17", x2: "14.5", y2: "19" }),
3089
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "16", y1: "16", x2: "17.5", y2: "18" })
3090
+ ] }),
3091
+ extras: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3092
+ /* @__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" }),
3093
+ /* @__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" })
3094
+ ] })
3095
+ }
3096
+ );
3097
+ }
3098
+ const crabVariants = [
3099
+ Crab1,
3100
+ Crab2,
3101
+ Crab3,
3102
+ Crab4,
3103
+ Crab5,
3104
+ Crab6,
3105
+ Crab7,
3106
+ Crab8,
3107
+ Crab9,
3108
+ Crab10,
3109
+ Crab11,
3110
+ Crab12
3111
+ ];
3112
+ function getCrabVariant(index) {
3113
+ return crabVariants[Math.abs(index) % crabVariants.length] ?? Crab1;
3114
+ }
2787
3115
  function ThreadConnector({
2788
3116
  stopReason,
2789
3117
  isPending,
2790
3118
  isFirst,
2791
- isLast: _isLast,
2792
- isTurnStart
3119
+ isTurnStart,
3120
+ crabIndex = 0,
3121
+ collapsible = false,
3122
+ collapsed = false,
3123
+ onToggle
2793
3124
  }) {
2794
3125
  const isBoundary = stopReason === "end_turn" || stopReason === "stop";
2795
- const isToolUse = stopReason === "tool_use";
3126
+ const isRunning = isPending && !isBoundary;
3127
+ const Crab = reactExports.useMemo(() => getCrabVariant(crabIndex), [crabIndex]);
2796
3128
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center w-6 shrink-0", children: [
2797
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-4", children: !isFirst && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30" }) }),
2798
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-0.5", children: isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2799
- "div",
3129
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-2.5", children: !isFirst && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/30" }) }),
3130
+ collapsible && /* @__PURE__ */ jsxRuntimeExports.jsx(
3131
+ "button",
2800
3132
  {
2801
- className: cn(
2802
- "size-2.5 rounded-full border-2",
2803
- "bg-background border-amber-400",
2804
- "shadow-[0_0_6px_rgba(251,191,36,0.4)]"
2805
- ),
2806
- title: stopReason === "end_turn" ? "End of Turn (Anthropic)" : "End of Turn (OpenAI)"
3133
+ type: "button",
3134
+ onClick: onToggle,
3135
+ title: collapsed ? "Expand turn" : "Collapse turn",
3136
+ className: "cursor-pointer flex justify-center py-0.5",
3137
+ children: collapsed ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground hover:text-foreground transition-colors" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground hover:text-foreground transition-colors" })
2807
3138
  }
2808
- ) : isToolUse ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2809
- "div",
3139
+ ),
3140
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-0.5", children: isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx(
3141
+ "span",
2810
3142
  {
2811
- className: cn(
2812
- "size-2 rounded-full",
2813
- isTurnStart ? "bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.5)]" : "bg-muted-foreground/25"
2814
- ),
2815
- title: isTurnStart ? "Tool Use — start of turn" : "Tool Use — turn continues"
3143
+ title: stopReason === "end_turn" ? "End of Turn (Anthropic)" : "End of Turn (OpenAI)",
3144
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3145
+ Crab,
3146
+ {
3147
+ className: cn(
3148
+ "size-3.5 text-amber-400",
3149
+ "animate-crab-settle",
3150
+ "drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]"
3151
+ )
3152
+ }
3153
+ )
2816
3154
  }
2817
- ) : isPending ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2818
- "div",
2819
- {
2820
- className: "size-2.5 rounded-full border-2 border-dashed border-muted-foreground/30 animate-pulse",
2821
- title: "Response pending"
2822
- }
2823
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
2824
- "div",
3155
+ ) : isTurnStart ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Start of turn", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3156
+ Crab,
2825
3157
  {
2826
3158
  className: cn(
2827
- "size-1.5 rounded-full",
2828
- isTurnStart ? "bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.5)]" : "bg-muted-foreground/30"
3159
+ "size-3.5 text-emerald-400",
3160
+ "animate-crab-appear",
3161
+ "drop-shadow-[0_0_4px_rgba(52,211,153,0.5)]"
2829
3162
  )
2830
3163
  }
2831
- ) }),
3164
+ ) }) : 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(Crab, { className: "size-3.5 text-muted-foreground/40" }) }),
2832
3165
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex justify-center min-h-1", children: isBoundary ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-0.5 bg-muted-foreground/10 h-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
2833
3166
  "div",
2834
3167
  {
@@ -2840,6 +3173,67 @@ function ThreadConnector({
2840
3173
  ) })
2841
3174
  ] });
2842
3175
  }
3176
+ function TurnGroup({
3177
+ logs,
3178
+ viewMode,
3179
+ strip,
3180
+ cacheTrends,
3181
+ onCompareWithPrevious,
3182
+ turnIndex = 0
3183
+ }) {
3184
+ const stopReasons = reactExports.useMemo(() => logs.map((l) => extractStopReason(l)), [logs]);
3185
+ const lastIdx = logs.length - 1;
3186
+ const lastStop = stopReasons[lastIdx] ?? null;
3187
+ const isComplete = lastStop !== null ? isTurnBoundary(lastStop) : false;
3188
+ const isPending = logs[lastIdx]?.responseStatus === null;
3189
+ const collapsible = isComplete && !isPending;
3190
+ const [collapsed, setCollapsed] = reactExports.useState(false);
3191
+ const toggleCollapse = reactExports.useCallback(() => {
3192
+ if (collapsible) setCollapsed((prev) => !prev);
3193
+ }, [collapsible]);
3194
+ const visibleLogs = reactExports.useMemo(() => {
3195
+ if (!collapsed) return logs;
3196
+ const last = logs[lastIdx];
3197
+ return last !== void 0 ? [last] : [];
3198
+ }, [logs, collapsed, lastIdx]);
3199
+ const bgClass = turnIndex % 2 === 0 ? "bg-muted/10" : "bg-muted/25";
3200
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3201
+ "div",
3202
+ {
3203
+ className: cn("border rounded-lg", isPending ? "border-amber-500/10" : "border-transparent"),
3204
+ children: visibleLogs.map((log, visibleIdx) => {
3205
+ const originalIdx = collapsed ? lastIdx : visibleIdx;
3206
+ const reason = stopReasons[originalIdx] ?? null;
3207
+ const isBoundary = reason === "end_turn" || reason === "stop";
3208
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
3209
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3210
+ ThreadConnector,
3211
+ {
3212
+ stopReason: reason,
3213
+ isPending: log.responseStatus === null,
3214
+ isFirst: originalIdx === 0,
3215
+ isTurnStart: originalIdx === 0,
3216
+ crabIndex: log.id % 12,
3217
+ collapsible: collapsible && isBoundary && logs.length > 1,
3218
+ collapsed,
3219
+ onToggle: toggleCollapse
3220
+ }
3221
+ ),
3222
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex-1 min-w-0 mb-2 rounded-lg", bgClass), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3223
+ LogEntry,
3224
+ {
3225
+ log,
3226
+ viewMode,
3227
+ strip,
3228
+ cacheTrend: cacheTrends?.get(log.id) ?? null,
3229
+ onCompareWithPrevious: () => onCompareWithPrevious(log)
3230
+ }
3231
+ ) })
3232
+ ] }, log.id);
3233
+ })
3234
+ }
3235
+ );
3236
+ }
2843
3237
  function computeStats(logs) {
2844
3238
  let totalInput = 0;
2845
3239
  let totalOutput = 0;
@@ -2855,13 +3249,9 @@ const ConversationGroup = reactExports.memo(function({
2855
3249
  strip,
2856
3250
  cacheTrends,
2857
3251
  onCompareWithPrevious,
2858
- defaultGroupViewMode = "thread"
3252
+ standalone = false
2859
3253
  }) {
2860
- const [expanded, setExpanded] = reactExports.useState(false);
2861
- const [groupViewMode, setGroupViewMode] = reactExports.useState(defaultGroupViewMode);
2862
- reactExports.useEffect(() => {
2863
- setGroupViewMode(defaultGroupViewMode);
2864
- }, [defaultGroupViewMode]);
3254
+ const [expanded, setExpanded] = reactExports.useState(standalone);
2865
3255
  const stats = computeStats(group.logs);
2866
3256
  const startTime = group.logs[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2867
3257
  const endTime = group.logs[group.logs.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -2879,9 +3269,32 @@ const ConversationGroup = reactExports.memo(function({
2879
3269
  }
2880
3270
  return indices;
2881
3271
  }, [stopReasons]);
3272
+ const turnGroups = reactExports.useMemo(() => {
3273
+ const groups = [];
3274
+ let currentGroup = [];
3275
+ let currentTurn = 0;
3276
+ for (let i = 0; i < group.logs.length; i++) {
3277
+ const turnIdx = turnIndices[i] ?? 0;
3278
+ const log = group.logs[i];
3279
+ if (!log) continue;
3280
+ if (turnIdx !== currentTurn) {
3281
+ if (currentGroup.length > 0) {
3282
+ groups.push({ logs: currentGroup, turnIndex: currentTurn });
3283
+ }
3284
+ currentGroup = [log];
3285
+ currentTurn = turnIdx;
3286
+ } else {
3287
+ currentGroup.push(log);
3288
+ }
3289
+ }
3290
+ if (currentGroup.length > 0) {
3291
+ groups.push({ logs: currentGroup, turnIndex: currentTurn });
3292
+ }
3293
+ return groups;
3294
+ }, [group.logs, turnIndices]);
2882
3295
  const displayId = group.conversationId.startsWith("PID:") || group.conversationId.includes("|") ? group.conversationId : group.conversationId.length > 24 ? group.conversationId.slice(0, 12) + "…" + group.conversationId.slice(-12) : group.conversationId;
2883
3296
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4", children: [
2884
- /* @__PURE__ */ jsxRuntimeExports.jsx(
3297
+ !standalone && /* @__PURE__ */ jsxRuntimeExports.jsx(
2885
3298
  ConversationHeader,
2886
3299
  {
2887
3300
  conversationId: displayId,
@@ -2895,56 +3308,21 @@ const ConversationGroup = reactExports.memo(function({
2895
3308
  onToggle: () => setExpanded(!expanded),
2896
3309
  hideApiFormat: mixed,
2897
3310
  isLoading,
2898
- userAgent: group.logs[0]?.userAgent ?? null,
2899
- viewMode: groupViewMode,
2900
- onToggleViewMode: () => setGroupViewMode((prev) => prev === "thread" ? "flat" : "thread")
3311
+ userAgent: group.logs[0]?.userAgent ?? null
2901
3312
  }
2902
3313
  ),
2903
- expanded && groupViewMode === "flat" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 border-l-2 border-muted ml-3", children: group.logs.map((log) => /* @__PURE__ */ jsxRuntimeExports.jsx(
2904
- LogEntry,
3314
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: turnGroups.map((tg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3315
+ TurnGroup,
2905
3316
  {
2906
- log,
3317
+ logs: tg.logs,
2907
3318
  viewMode,
2908
3319
  strip,
2909
- cacheTrend: cacheTrends?.get(log.id) ?? null,
2910
- onCompareWithPrevious: () => onCompareWithPrevious(log)
3320
+ cacheTrends,
3321
+ onCompareWithPrevious,
3322
+ turnIndex: tg.turnIndex
2911
3323
  },
2912
- log.id
2913
- )) }),
2914
- expanded && groupViewMode === "thread" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-3", children: group.logs.map((log, idx) => {
2915
- const isTurnStart = idx === 0 || stopReasons[idx - 1] === "end_turn" || stopReasons[idx - 1] === "stop";
2916
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
2917
- /* @__PURE__ */ jsxRuntimeExports.jsx(
2918
- ThreadConnector,
2919
- {
2920
- stopReason: stopReasons[idx] ?? null,
2921
- isPending: log.responseStatus === null,
2922
- isFirst: idx === 0,
2923
- isLast: idx === group.logs.length - 1,
2924
- isTurnStart
2925
- }
2926
- ),
2927
- /* @__PURE__ */ jsxRuntimeExports.jsx(
2928
- "div",
2929
- {
2930
- className: cn(
2931
- "flex-1 min-w-0 mb-2 rounded-lg",
2932
- (turnIndices[idx] ?? 0) % 2 === 0 ? "bg-muted/10" : "bg-muted/25"
2933
- ),
2934
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2935
- LogEntry,
2936
- {
2937
- log,
2938
- viewMode,
2939
- strip,
2940
- cacheTrend: cacheTrends?.get(log.id) ?? null,
2941
- onCompareWithPrevious: () => onCompareWithPrevious(log)
2942
- }
2943
- )
2944
- }
2945
- )
2946
- ] }, log.id);
2947
- }) })
3324
+ tg.turnIndex
3325
+ )) })
2948
3326
  ] });
2949
3327
  });
2950
3328
  function CrabLogo({ className }) {
@@ -2992,7 +3370,7 @@ function SelectTrigger({
2992
3370
  ...props
2993
3371
  }) {
2994
3372
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
2995
- Trigger$1,
3373
+ Trigger,
2996
3374
  {
2997
3375
  "data-slot": "select-trigger",
2998
3376
  "data-size": size,
@@ -3015,8 +3393,8 @@ function SelectContent({
3015
3393
  align = "center",
3016
3394
  ...props
3017
3395
  }) {
3018
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
3019
- Content2$1,
3396
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
3397
+ Content2,
3020
3398
  {
3021
3399
  "data-slot": "select-content",
3022
3400
  className: cn(
@@ -5743,8 +6121,6 @@ function ProxyViewer({
5743
6121
  strip
5744
6122
  }) {
5745
6123
  const { totalIn, totalOut } = computeTokenSummary(logs);
5746
- const [groupedView, setGroupedView] = reactExports.useState(true);
5747
- const [groupViewMode, setGroupViewMode] = reactExports.useState("thread");
5748
6124
  const [exporting, setExporting] = reactExports.useState(false);
5749
6125
  const [comparePair, setComparePair] = reactExports.useState(null);
5750
6126
  const handleExport = reactExports.useCallback(async () => {
@@ -5774,30 +6150,40 @@ function ProxyViewer({
5774
6150
  );
5775
6151
  const groups = reactExports.useMemo(() => groupLogsByConversation(logs), [logs]);
5776
6152
  const cacheTrends = reactExports.useMemo(() => computeCacheTrends(groups), [groups]);
5777
- const stopReasons = reactExports.useMemo(() => logs.map((log) => extractStopReason(log)), [logs]);
5778
- const turnIndices = reactExports.useMemo(() => {
5779
- const indices = [];
5780
- let turn = 0;
5781
- for (let i = 0; i < stopReasons.length; i++) {
5782
- if (i > 0 && (stopReasons[i - 1] === "end_turn" || stopReasons[i - 1] === "stop")) {
5783
- turn++;
5784
- }
5785
- indices.push(turn);
5786
- }
5787
- return indices;
5788
- }, [stopReasons]);
5789
- const renderGroups = logs.length > 0 && groupedView && groups.length > 1;
5790
6153
  const rowVirtualizer = useVirtualizer({
5791
- count: renderGroups ? groups.length : logs.length,
6154
+ count: groups.length,
5792
6155
  getScrollElement: () => parentRef.current,
5793
6156
  estimateSize: () => 150,
5794
6157
  measureElement: typeof window !== "undefined" ? (element) => element.getBoundingClientRect().height : void 0,
5795
6158
  overscan: 5
5796
6159
  });
5797
6160
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[1200px] mx-auto flex flex-col h-screen", style: { maxHeight: "100vh" }, children: [
5798
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 mb-4 px-6 pt-6", children: [
5799
- /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-lg font-bold flex-1 flex items-center gap-2", children: [
5800
- /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 self-center" }),
6161
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end px-6 pt-6 pb-3 relative", children: [
6162
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-lg font-bold flex items-end gap-2 absolute left-1/2 -translate-x-1/2 whitespace-nowrap", children: [
6163
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-end gap-1 group cursor-default", "aria-hidden": "true", children: [
6164
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" }),
6165
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex items-end gap-0.5", children: crabVariants.map((Crab, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(
6166
+ Crab,
6167
+ {
6168
+ className: `size-5 ${[
6169
+ "text-amber-500",
6170
+ "text-rose-500",
6171
+ "text-sky-500",
6172
+ "text-emerald-500",
6173
+ "text-violet-500",
6174
+ "text-orange-500",
6175
+ "text-cyan-500",
6176
+ "text-pink-500",
6177
+ "text-lime-500",
6178
+ "text-blue-500",
6179
+ "text-yellow-500",
6180
+ "text-fuchsia-500"
6181
+ ][i]} transition-all duration-300 ease-out group-hover:scale-125 group-hover:-translate-y-1`,
6182
+ style: { transitionDelay: `${i * 50}ms` }
6183
+ },
6184
+ i
6185
+ )) })
6186
+ ] }),
5801
6187
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-baseline gap-2", children: [
5802
6188
  "LLM Inspector",
5803
6189
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-muted-foreground font-mono", children: [
@@ -5806,6 +6192,23 @@ function ProxyViewer({
5806
6192
  ] })
5807
6193
  ] })
5808
6194
  ] }),
6195
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}) })
6196
+ ] }),
6197
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-6 mb-4", children: [
6198
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedSession, onValueChange: onSessionChange, children: [
6199
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[350px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All sessions" }) }),
6200
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
6201
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All sessions" }),
6202
+ sessions.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: s, children: truncateSessionId(s) }, s))
6203
+ ] })
6204
+ ] }),
6205
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedModel, onValueChange: onModelChange, children: [
6206
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[250px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All models" }) }),
6207
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
6208
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All models" }),
6209
+ models.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: m, children: m }, m))
6210
+ ] })
6211
+ ] }),
5809
6212
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
5810
6213
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
5811
6214
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -5829,7 +6232,7 @@ function ProxyViewer({
5829
6232
  ] }) }),
5830
6233
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Simple shows parsed output; Full adds raw headers and tokens" })
5831
6234
  ] }) }),
5832
- /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}),
6235
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
5833
6236
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
5834
6237
  logs.length,
5835
6238
  " request",
@@ -5848,7 +6251,7 @@ function ProxyViewer({
5848
6251
  title: "Export all logs as JSON ZIP",
5849
6252
  children: exporting ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
5850
6253
  /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3" }),
5851
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export All" })
6254
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export" })
5852
6255
  ] })
5853
6256
  }
5854
6257
  ),
@@ -5859,71 +6262,12 @@ function ProxyViewer({
5859
6262
  onClick: onClearAll,
5860
6263
  className: "text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
5861
6264
  title: "Clear all logs",
5862
- children: "Clear All"
6265
+ children: "Clear"
5863
6266
  }
5864
6267
  )
5865
6268
  ] }),
5866
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 px-6 mb-4", children: [
5867
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedSession, onValueChange: onSessionChange, children: [
5868
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[400px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All sessions" }) }),
5869
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
5870
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All sessions" }),
5871
- sessions.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: s, children: truncateSessionId(s) }, s))
5872
- ] })
5873
- ] }),
5874
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedModel, onValueChange: onModelChange, children: [
5875
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All models" }) }),
5876
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
5877
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All models" }),
5878
- models.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: m, children: m }, m))
5879
- ] })
5880
- ] }),
5881
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
5882
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5883
- "button",
5884
- {
5885
- type: "button",
5886
- onClick: () => setGroupedView(true),
5887
- className: `px-2 py-1.5 cursor-pointer transition-colors ${groupedView ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
5888
- title: "Grouped view",
5889
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(LayoutGrid, { className: "size-4" })
5890
- }
5891
- ),
5892
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5893
- "button",
5894
- {
5895
- type: "button",
5896
- onClick: () => setGroupedView(false),
5897
- className: `px-2 py-1.5 cursor-pointer transition-colors ${!groupedView ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
5898
- title: "Flat view",
5899
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { className: "size-4" })
5900
- }
5901
- )
5902
- ] }),
5903
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
5904
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5905
- "button",
5906
- {
5907
- type: "button",
5908
- onClick: () => setGroupViewMode("thread"),
5909
- className: `px-2 py-1.5 cursor-pointer transition-colors ${groupViewMode === "thread" ? "bg-amber-500/15 text-amber-400 border-r border-amber-500/30" : "text-muted-foreground hover:bg-muted/50"}`,
5910
- title: "Thread view (connected timeline)",
5911
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "size-4" })
5912
- }
5913
- ),
5914
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5915
- "button",
5916
- {
5917
- type: "button",
5918
- onClick: () => setGroupViewMode("flat"),
5919
- className: `px-2 py-1.5 cursor-pointer transition-colors ${groupViewMode === "flat" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
5920
- title: "Flat view (card list)",
5921
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { className: "size-4" })
5922
- }
5923
- )
5924
- ] })
5925
- ] }),
5926
6269
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 px-6 pb-6", children: logs.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
6270
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-12 text-muted-foreground/20 mx-auto" }),
5927
6271
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "No requests captured yet." }),
5928
6272
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: "Route AI coding tools through the proxy:" }),
5929
6273
  /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "LLM_BASE_URL=http://localhost:25947/proxy <your-tool>" })
@@ -5936,95 +6280,34 @@ function ProxyViewer({
5936
6280
  position: "relative"
5937
6281
  },
5938
6282
  children: rowVirtualizer.getVirtualItems().map((virtualRow) => {
5939
- if (renderGroups) {
5940
- const group = groups[virtualRow.index];
5941
- if (group === void 0) return null;
5942
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
5943
- "div",
5944
- {
5945
- "data-index": virtualRow.index,
5946
- ref: rowVirtualizer.measureElement,
5947
- style: {
5948
- position: "absolute",
5949
- top: 0,
5950
- left: 0,
5951
- width: "100%",
5952
- transform: `translateY(${virtualRow.start}px)`
5953
- },
5954
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
5955
- ConversationGroup,
5956
- {
5957
- group,
5958
- viewMode,
5959
- strip,
5960
- cacheTrends,
5961
- onCompareWithPrevious: handleCompareWithPrevious,
5962
- defaultGroupViewMode: groupViewMode
5963
- }
5964
- )
5965
- },
5966
- group.id
5967
- );
5968
- } else {
5969
- const log = logs[virtualRow.index];
5970
- if (log === void 0) return null;
5971
- const idx = virtualRow.index;
5972
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
5973
- "div",
5974
- {
5975
- "data-index": virtualRow.index,
5976
- ref: rowVirtualizer.measureElement,
5977
- style: {
5978
- position: "absolute",
5979
- top: 0,
5980
- left: 0,
5981
- width: "100%",
5982
- transform: `translateY(${virtualRow.start}px)`
5983
- },
5984
- children: groupViewMode === "thread" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch ml-3", children: [
5985
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5986
- ThreadConnector,
5987
- {
5988
- stopReason: stopReasons[idx] ?? null,
5989
- isPending: log.responseStatus === null,
5990
- isFirst: idx === 0,
5991
- isLast: idx === logs.length - 1,
5992
- isTurnStart: idx === 0 || stopReasons[idx - 1] === "end_turn" || stopReasons[idx - 1] === "stop"
5993
- }
5994
- ),
5995
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5996
- "div",
5997
- {
5998
- className: cn(
5999
- "flex-1 min-w-0 mb-2 rounded-lg",
6000
- (turnIndices[idx] ?? 0) % 2 === 0 ? "bg-muted/10" : "bg-muted/25"
6001
- ),
6002
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
6003
- LogEntry,
6004
- {
6005
- log,
6006
- viewMode,
6007
- strip,
6008
- cacheTrend: cacheTrends.get(log.id) ?? null,
6009
- onCompareWithPrevious: () => handleCompareWithPrevious(log)
6010
- }
6011
- )
6012
- }
6013
- )
6014
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
6015
- LogEntry,
6016
- {
6017
- log,
6018
- viewMode,
6019
- strip,
6020
- cacheTrend: cacheTrends.get(log.id) ?? null,
6021
- onCompareWithPrevious: () => handleCompareWithPrevious(log)
6022
- }
6023
- )
6283
+ const group = groups[virtualRow.index];
6284
+ if (group === void 0) return null;
6285
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
6286
+ "div",
6287
+ {
6288
+ "data-index": virtualRow.index,
6289
+ ref: rowVirtualizer.measureElement,
6290
+ style: {
6291
+ position: "absolute",
6292
+ top: 0,
6293
+ left: 0,
6294
+ width: "100%",
6295
+ transform: `translateY(${virtualRow.start}px)`
6024
6296
  },
6025
- log.id
6026
- );
6027
- }
6297
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
6298
+ ConversationGroup,
6299
+ {
6300
+ group,
6301
+ viewMode,
6302
+ strip,
6303
+ cacheTrends,
6304
+ onCompareWithPrevious: handleCompareWithPrevious,
6305
+ standalone: groups.length === 1
6306
+ }
6307
+ )
6308
+ },
6309
+ group.id
6310
+ );
6028
6311
  })
6029
6312
  }
6030
6313
  ) }) }),