@tonyclaw/llm-inspector 1.18.1 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +776 -139
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-CAhlM_Gq.js → CompareDrawer-DwayZPPO.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-iv3LVMEW.js +101 -0
- package/.output/public/assets/{ReplayDialog-Bqu2f5HE.js → ReplayDialog-CaV1elYO.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CpVNH0CD.js → RequestAnatomy-CSfnjK7j.js} +1 -1
- package/.output/public/assets/{ResponseView-B_Gg37Lr.js → ResponseView-YkOL__xm.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-E2M_SS1A.js → StreamingChunkSequence-D_p6L-oB.js} +1 -1
- package/.output/public/assets/_sessionId-BgCVUC6R.js +1 -0
- package/.output/public/assets/index-CWA4S0FO.js +1 -0
- package/.output/public/assets/index-DeJyypsp.css +1 -0
- package/.output/public/assets/{json-viewer-DqhA-ODG.js → json-viewer-BB-9bqnP.js} +2 -2
- package/.output/public/assets/{main-DpH7JlHv.js → main-COVN451W.js} +7 -7
- package/.output/server/_libs/lucide-react.mjs +100 -73
- package/.output/server/{_sessionId-DcJ0RDNl.mjs → _sessionId-BJT5qIib.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-DajC3x7u.mjs → CompareDrawer-DNGYdUXs.mjs} +5 -5
- package/.output/server/_ssr/{ProxyViewerContainer-C2dnFXoC.mjs → ProxyViewerContainer-B-zDOLYE.mjs} +501 -352
- package/.output/server/_ssr/{ReplayDialog-BnCLuA5z.mjs → ReplayDialog-DWeqMA4y.mjs} +5 -5
- package/.output/server/_ssr/{RequestAnatomy-OHE3iT-f.mjs → RequestAnatomy-TOsrMu9-.mjs} +4 -4
- package/.output/server/_ssr/{ResponseView-NPshHwOv.mjs → ResponseView-BuqdPrzm.mjs} +5 -5
- package/.output/server/_ssr/{StreamingChunkSequence-BfukoR7F.mjs → StreamingChunkSequence-DuzNZkqL.mjs} +5 -5
- package/.output/server/_ssr/{index-CF8M0tsv.mjs → index-1nCQUt3y.mjs} +3 -3
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-CHBa-Oas.mjs → json-viewer-BL8xhHbi.mjs} +10 -6
- package/.output/server/_ssr/{router-B5hOtKSn.mjs → router-aCaUgVTW.mjs} +32 -17
- package/.output/server/{_tanstack-start-manifest_v-CFyWvIH6.mjs → _tanstack-start-manifest_v-cBRxvCjb.mjs} +1 -1
- package/.output/server/index.mjs +66 -66
- package/README.md +109 -59
- package/package.json +2 -1
- package/src/assets/logos/mcp.png +0 -0
- package/src/cli/detect-tools.ts +146 -0
- package/src/cli/onboard.ts +229 -0
- package/src/cli/templates/command-onboard.ts +17 -0
- package/src/cli/templates/skill-onboard.ts +325 -0
- package/src/cli.ts +185 -163
- package/src/components/ProxyViewer.tsx +297 -136
- package/src/components/ProxyViewerContainer.tsx +24 -9
- package/src/components/proxy-viewer/ConversationHeader.tsx +7 -22
- package/src/components/proxy-viewer/LogEntry.tsx +136 -157
- package/src/components/proxy-viewer/LogEntryHeader.tsx +147 -66
- package/src/components/proxy-viewer/useCopyFeedback.ts +36 -0
- package/src/components/ui/json-viewer.tsx +12 -0
- package/src/components/ui/mcp-logo.tsx +20 -0
- package/src/lib/sessionUrl.ts +44 -0
- package/src/routes/session/$sessionId.tsx +5 -57
- package/.output/public/assets/ProxyViewerContainer--miVHNPZ.js +0 -101
- package/.output/public/assets/_sessionId-P9LgC1bF.js +0 -1
- package/.output/public/assets/index-C0wv3YP9.css +0 -1
- package/.output/public/assets/index-kboKku6a.js +0 -1
package/.output/server/_ssr/{ProxyViewerContainer-C2dnFXoC.mjs → ProxyViewerContainer-B-zDOLYE.mjs}
RENAMED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as RuntimeConfigSchema, r as requestFormatForPath, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, d as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, e as ProviderConfigSchema, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, b as AnthropicRequestSchema } from "./router-
|
|
2
|
+
import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as RuntimeConfigSchema, r as requestFormatForPath, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, d as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, g as getSessionPath, e as ProviderConfigSchema, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, b as AnthropicRequestSchema } from "./router-aCaUgVTW.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";
|
|
6
6
|
import { t as twMerge } from "../_libs/tailwind-merge.mjs";
|
|
7
7
|
import { c as cva } from "../_libs/class-variance-authority.mjs";
|
|
8
|
-
import { R as Root, T as Trigger$
|
|
8
|
+
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";
|
|
9
9
|
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
10
10
|
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
11
11
|
import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
|
|
12
|
-
import { C as Check, X, D as Download, S as Settings,
|
|
12
|
+
import { C as Check, X, P as Plus, D as Download, S as Settings, A as ArrowLeft, a as Copy, b as ChevronDown, U as Upload, c as Scan, d as CircleAlert, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, E as ExternalLink, T as Trash2, i as TriangleAlert, j as EyeOff, k as Eye, R as RotateCw, l as Pencil, m as Minus, n as CircleCheckBig, O as OctagonAlert, W as Wrench, G as Globe, F as FileTerminal, o as Radio, p as ChevronsUp, q as ChevronsDown, r as FileDiff, H as History, s as RotateCcw, t as GitCompareArrows, u as CircleQuestionMark, v as Server, w as Gauge, x as Lock, y as Wifi, z as WifiOff, B as ArrowUp, I as ArrowDown, J as Rows3, K 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
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
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";
|
|
15
|
+
import { R as Root2$1, L as List, T as Trigger$3, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
16
16
|
import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
17
17
|
const ApiErrorSchema = object({
|
|
18
18
|
error: string()
|
|
@@ -275,7 +275,7 @@ function getStatusCategory(status) {
|
|
|
275
275
|
if (status >= 500) return "server_error";
|
|
276
276
|
return "pending";
|
|
277
277
|
}
|
|
278
|
-
const version = "1.
|
|
278
|
+
const version = "1.19.0";
|
|
279
279
|
const packageJson = {
|
|
280
280
|
version
|
|
281
281
|
};
|
|
@@ -322,12 +322,12 @@ function Dialog({
|
|
|
322
322
|
function DialogTrigger({
|
|
323
323
|
...props
|
|
324
324
|
}) {
|
|
325
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$
|
|
325
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$2, { "data-slot": "dialog-trigger", ...props });
|
|
326
326
|
}
|
|
327
327
|
function DialogPortal({
|
|
328
328
|
...props
|
|
329
329
|
}) {
|
|
330
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$
|
|
330
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { "data-slot": "dialog-portal", ...props });
|
|
331
331
|
}
|
|
332
332
|
function DialogOverlay({
|
|
333
333
|
className,
|
|
@@ -497,14 +497,7 @@ function ConversationHeader({
|
|
|
497
497
|
const handleOpenInNewTab = reactExports.useCallback(
|
|
498
498
|
(e) => {
|
|
499
499
|
e.stopPropagation();
|
|
500
|
-
|
|
501
|
-
try {
|
|
502
|
-
encoded = btoa(conversationId).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
503
|
-
} catch {
|
|
504
|
-
encoded = encodeURIComponent(conversationId);
|
|
505
|
-
}
|
|
506
|
-
const url = `/session/${encoded}`;
|
|
507
|
-
window.open(url, "_blank", "noopener,noreferrer");
|
|
500
|
+
window.open(getSessionPath(conversationId), "_blank", "noopener,noreferrer");
|
|
508
501
|
},
|
|
509
502
|
[conversationId]
|
|
510
503
|
);
|
|
@@ -537,7 +530,7 @@ function ConversationHeader({
|
|
|
537
530
|
{
|
|
538
531
|
className: "text-purple-400/90 font-mono text-xs font-semibold shrink-0",
|
|
539
532
|
title: conversationId,
|
|
540
|
-
children: conversationId.startsWith("PID:") || conversationId.includes("|") ? conversationId : conversationId.length > 24 ? conversationId.slice(0, 12) + "
|
|
533
|
+
children: conversationId.startsWith("PID:") || conversationId.includes("|") ? conversationId : conversationId.length > 24 ? conversationId.slice(0, 12) + "..." + conversationId.slice(-12) : conversationId
|
|
541
534
|
}
|
|
542
535
|
),
|
|
543
536
|
userAgent !== null && userAgent !== void 0 && userAgent !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -1163,7 +1156,7 @@ function Tooltip({ ...props }) {
|
|
|
1163
1156
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Root3, { "data-slot": "tooltip", ...props });
|
|
1164
1157
|
}
|
|
1165
1158
|
function TooltipTrigger({ ...props }) {
|
|
1166
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$
|
|
1159
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger$1, { "data-slot": "tooltip-trigger", ...props });
|
|
1167
1160
|
}
|
|
1168
1161
|
function TooltipContent({
|
|
1169
1162
|
className,
|
|
@@ -1171,7 +1164,7 @@ function TooltipContent({
|
|
|
1171
1164
|
children,
|
|
1172
1165
|
...props
|
|
1173
1166
|
}) {
|
|
1174
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$
|
|
1167
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1175
1168
|
Content2$1,
|
|
1176
1169
|
{
|
|
1177
1170
|
"data-slot": "tooltip-content",
|
|
@@ -1188,37 +1181,6 @@ function TooltipContent({
|
|
|
1188
1181
|
}
|
|
1189
1182
|
) });
|
|
1190
1183
|
}
|
|
1191
|
-
function JsonExpansionButton({
|
|
1192
|
-
policy,
|
|
1193
|
-
isExpanded,
|
|
1194
|
-
isPending,
|
|
1195
|
-
onToggle
|
|
1196
|
-
}) {
|
|
1197
|
-
if (policy === null) return null;
|
|
1198
|
-
const label = isPending ? "Updating..." : isExpanded ? "Collapse all" : "Expand all";
|
|
1199
|
-
const tooltip = isExpanded ? "Collapse all JSON nodes" : "Expand all JSON nodes";
|
|
1200
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1201
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1202
|
-
Button,
|
|
1203
|
-
{
|
|
1204
|
-
variant: "outline",
|
|
1205
|
-
size: "sm",
|
|
1206
|
-
className: "h-8 text-xs",
|
|
1207
|
-
onClick: (e) => {
|
|
1208
|
-
e.stopPropagation();
|
|
1209
|
-
onToggle();
|
|
1210
|
-
},
|
|
1211
|
-
disabled: isPending,
|
|
1212
|
-
"aria-pressed": isExpanded,
|
|
1213
|
-
children: [
|
|
1214
|
-
isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3.5 mr-1" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5 mr-1" }),
|
|
1215
|
-
label
|
|
1216
|
-
]
|
|
1217
|
-
}
|
|
1218
|
-
) }),
|
|
1219
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: tooltip })
|
|
1220
|
-
] }) });
|
|
1221
|
-
}
|
|
1222
1184
|
function getJsonExpansionPolicy(_value) {
|
|
1223
1185
|
return { depth: Number.POSITIVE_INFINITY };
|
|
1224
1186
|
}
|
|
@@ -1330,7 +1292,7 @@ function TabsTrigger({
|
|
|
1330
1292
|
...props
|
|
1331
1293
|
}) {
|
|
1332
1294
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1333
|
-
Trigger$
|
|
1295
|
+
Trigger$3,
|
|
1334
1296
|
{
|
|
1335
1297
|
"data-slot": "tabs-trigger",
|
|
1336
1298
|
className: cn(
|
|
@@ -1357,28 +1319,51 @@ function TabsContent({
|
|
|
1357
1319
|
}
|
|
1358
1320
|
);
|
|
1359
1321
|
}
|
|
1322
|
+
function useCopyFeedback(text) {
|
|
1323
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
1324
|
+
const timerRef = reactExports.useRef(null);
|
|
1325
|
+
reactExports.useEffect(
|
|
1326
|
+
() => () => {
|
|
1327
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
1328
|
+
},
|
|
1329
|
+
[]
|
|
1330
|
+
);
|
|
1331
|
+
const copy = reactExports.useCallback(
|
|
1332
|
+
(event) => {
|
|
1333
|
+
event.stopPropagation();
|
|
1334
|
+
if (text === null) return;
|
|
1335
|
+
void window.navigator.clipboard.writeText(text).then(() => {
|
|
1336
|
+
setCopied(true);
|
|
1337
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
1338
|
+
timerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
1339
|
+
});
|
|
1340
|
+
},
|
|
1341
|
+
[text]
|
|
1342
|
+
);
|
|
1343
|
+
return { copied, copy };
|
|
1344
|
+
}
|
|
1360
1345
|
const LazyCompareDrawer = reactExports.lazy(
|
|
1361
|
-
() => import("./CompareDrawer-
|
|
1346
|
+
() => import("./CompareDrawer-DNGYdUXs.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
1362
1347
|
);
|
|
1363
1348
|
const LazyReplayDialog = reactExports.lazy(
|
|
1364
|
-
() => import("./ReplayDialog-
|
|
1349
|
+
() => import("./ReplayDialog-DWeqMA4y.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
1365
1350
|
);
|
|
1366
1351
|
const LazyRequestAnatomy = reactExports.lazy(
|
|
1367
|
-
() => import("./RequestAnatomy-
|
|
1352
|
+
() => import("./RequestAnatomy-TOsrMu9-.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
1368
1353
|
);
|
|
1369
1354
|
const LazyResponseView = reactExports.lazy(
|
|
1370
|
-
() => import("./ResponseView-
|
|
1355
|
+
() => import("./ResponseView-BuqdPrzm.mjs").then((m) => ({ default: m.ResponseView }))
|
|
1371
1356
|
);
|
|
1372
1357
|
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
1373
|
-
() => import("./StreamingChunkSequence-
|
|
1358
|
+
() => import("./StreamingChunkSequence-DuzNZkqL.mjs").then((m) => ({
|
|
1374
1359
|
default: m.StreamingChunkSequence
|
|
1375
1360
|
}))
|
|
1376
1361
|
);
|
|
1377
1362
|
const LazyJsonViewer = reactExports.lazy(
|
|
1378
|
-
() => import("./json-viewer-
|
|
1363
|
+
() => import("./json-viewer-BL8xhHbi.mjs").then((m) => ({ default: m.JsonViewer }))
|
|
1379
1364
|
);
|
|
1380
1365
|
const LazyJsonViewerFromString = reactExports.lazy(
|
|
1381
|
-
() => import("./json-viewer-
|
|
1366
|
+
() => import("./json-viewer-BL8xhHbi.mjs").then((m) => ({ default: m.JsonViewerFromString }))
|
|
1382
1367
|
);
|
|
1383
1368
|
const HIGHLIGHT_DURATION_MS = 1200;
|
|
1384
1369
|
const MAX_HIGHLIGHT_ATTEMPTS = 12;
|
|
@@ -1797,11 +1782,9 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1797
1782
|
onToggle,
|
|
1798
1783
|
responseToolNames = null,
|
|
1799
1784
|
cacheTrend = null,
|
|
1785
|
+
activeTab,
|
|
1786
|
+
tabActions,
|
|
1800
1787
|
onReplay,
|
|
1801
|
-
onCopyRequest,
|
|
1802
|
-
requestCopied = false,
|
|
1803
|
-
onToggleRequestExpansion,
|
|
1804
|
-
requestExpansionState = null,
|
|
1805
1788
|
slowResponseThresholdSeconds = 0
|
|
1806
1789
|
}) {
|
|
1807
1790
|
const statusCategory = getStatusCategory(log.responseStatus);
|
|
@@ -1965,36 +1948,74 @@ const LogEntryHeader = reactExports.memo(function({
|
|
|
1965
1948
|
onClick: (e) => e.stopPropagation(),
|
|
1966
1949
|
onKeyDown: (e) => e.stopPropagation(),
|
|
1967
1950
|
children: [
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1951
|
+
tabActions !== void 0 && activeTab !== void 0 && (() => {
|
|
1952
|
+
const action = tabActions[activeTab];
|
|
1953
|
+
if (action === void 0) return null;
|
|
1954
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
1955
|
+
action.expansion !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1956
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1957
|
+
Button,
|
|
1958
|
+
{
|
|
1959
|
+
variant: "outline",
|
|
1960
|
+
size: "icon",
|
|
1961
|
+
className: "size-8",
|
|
1962
|
+
onClick: action.expansion.onToggle,
|
|
1963
|
+
disabled: action.expansion.isPending,
|
|
1964
|
+
"aria-pressed": action.expansion.isExpanded,
|
|
1965
|
+
"aria-label": action.expansion.isExpanded ? "Collapse all JSON" : "Expand all JSON",
|
|
1966
|
+
children: action.expansion.isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsUp, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsDown, { className: "size-3.5" })
|
|
1967
|
+
}
|
|
1968
|
+
) }),
|
|
1969
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.expansion.isExpanded ? "Collapse all JSON nodes" : "Expand all JSON nodes" })
|
|
1970
|
+
] }),
|
|
1971
|
+
action.diffWithRaw !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1972
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1973
|
+
Button,
|
|
1974
|
+
{
|
|
1975
|
+
variant: "outline",
|
|
1976
|
+
size: "icon",
|
|
1977
|
+
className: cn(
|
|
1978
|
+
"size-8",
|
|
1979
|
+
action.diffWithRaw.active && "bg-accent text-accent-foreground"
|
|
1980
|
+
),
|
|
1981
|
+
onClick: action.diffWithRaw.onToggle,
|
|
1982
|
+
"aria-pressed": action.diffWithRaw.active,
|
|
1983
|
+
"aria-label": action.diffWithRaw.active ? "Hide raw diff" : "Diff with raw",
|
|
1984
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(FileDiff, { className: "size-3.5" })
|
|
1985
|
+
}
|
|
1986
|
+
) }),
|
|
1987
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.diffWithRaw.active ? "Hide diff with raw request" : "Show diff between displayed and raw request body" })
|
|
1988
|
+
] }),
|
|
1989
|
+
action.diffWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1990
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1991
|
+
Button,
|
|
1992
|
+
{
|
|
1993
|
+
variant: "outline",
|
|
1994
|
+
size: "icon",
|
|
1995
|
+
className: "size-8",
|
|
1996
|
+
onClick: action.diffWithPrevious,
|
|
1997
|
+
"aria-label": "Diff with previous",
|
|
1998
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(History, { className: "size-3.5" })
|
|
1999
|
+
}
|
|
2000
|
+
) }),
|
|
2001
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
|
|
2002
|
+
] }),
|
|
2003
|
+
action.copyText !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2004
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2005
|
+
Button,
|
|
2006
|
+
{
|
|
2007
|
+
variant: "outline",
|
|
2008
|
+
size: "icon",
|
|
2009
|
+
className: "size-8",
|
|
2010
|
+
onClick: action.onCopy,
|
|
2011
|
+
"aria-label": action.copyCopied ? "Copied" : action.copyLabel,
|
|
2012
|
+
children: action.copyCopied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
2013
|
+
}
|
|
2014
|
+
) }),
|
|
2015
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: action.copyCopied ? "Copied to clipboard" : action.copyLabel })
|
|
2016
|
+
] })
|
|
2017
|
+
] });
|
|
2018
|
+
})(),
|
|
1998
2019
|
onReplay !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
1999
2020
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2000
2021
|
Button,
|
|
@@ -2335,31 +2356,6 @@ function shouldShowRequestDiffButton(apiFormat, viewMode, strip, hasRawRequest)
|
|
|
2335
2356
|
function TabFallback() {
|
|
2336
2357
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1", "aria-hidden": "true" });
|
|
2337
2358
|
}
|
|
2338
|
-
function CopyButton({
|
|
2339
|
-
text,
|
|
2340
|
-
label,
|
|
2341
|
-
copied,
|
|
2342
|
-
onCopy
|
|
2343
|
-
}) {
|
|
2344
|
-
if (text === null) return null;
|
|
2345
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2346
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2347
|
-
Button,
|
|
2348
|
-
{
|
|
2349
|
-
variant: "outline",
|
|
2350
|
-
size: "sm",
|
|
2351
|
-
className: "h-8 text-xs",
|
|
2352
|
-
onClick: onCopy,
|
|
2353
|
-
"aria-label": label,
|
|
2354
|
-
children: [
|
|
2355
|
-
copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5 mr-1 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5 mr-1" }),
|
|
2356
|
-
copied ? "Copied!" : label
|
|
2357
|
-
]
|
|
2358
|
-
}
|
|
2359
|
-
) }),
|
|
2360
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: copied ? "Copied to clipboard" : label })
|
|
2361
|
-
] });
|
|
2362
|
-
}
|
|
2363
2359
|
function DiffToggleButton({
|
|
2364
2360
|
active,
|
|
2365
2361
|
onClick
|
|
@@ -2401,29 +2397,6 @@ const HeadersDiffContent = reactExports.memo(function({
|
|
|
2401
2397
|
const result = reactExports.useMemo(() => computeHeadersDiff(rawHeaders, headers), [rawHeaders, headers]);
|
|
2402
2398
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { result, emptyLabel });
|
|
2403
2399
|
});
|
|
2404
|
-
function useCopyFeedback(text) {
|
|
2405
|
-
const [copied, setCopied] = reactExports.useState(false);
|
|
2406
|
-
const timerRef = reactExports.useRef(null);
|
|
2407
|
-
reactExports.useEffect(
|
|
2408
|
-
() => () => {
|
|
2409
|
-
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2410
|
-
},
|
|
2411
|
-
[]
|
|
2412
|
-
);
|
|
2413
|
-
const copy = reactExports.useCallback(
|
|
2414
|
-
(event) => {
|
|
2415
|
-
event.stopPropagation();
|
|
2416
|
-
if (text === null) return;
|
|
2417
|
-
void window.navigator.clipboard.writeText(text).then(() => {
|
|
2418
|
-
setCopied(true);
|
|
2419
|
-
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
2420
|
-
timerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
2421
|
-
});
|
|
2422
|
-
},
|
|
2423
|
-
[text]
|
|
2424
|
-
);
|
|
2425
|
-
return { copied, copy };
|
|
2426
|
-
}
|
|
2427
2400
|
const LogEntry = reactExports.memo(function({
|
|
2428
2401
|
log,
|
|
2429
2402
|
viewMode = "simple",
|
|
@@ -2456,11 +2429,106 @@ const LogEntry = reactExports.memo(function({
|
|
|
2456
2429
|
return stripClaudeCodeBillingHeader(log.rawRequestBody).body;
|
|
2457
2430
|
}, [log.rawRequestBody, resolvedFormat, strip]);
|
|
2458
2431
|
const displayedRequestBody = strippedRequestBody ?? log.rawRequestBody;
|
|
2432
|
+
const requestExpansion = useJsonBulkExpansion(displayedRequestBody);
|
|
2433
|
+
const rawRequestExpansion = useJsonBulkExpansion(log.rawRequestBody);
|
|
2434
|
+
const responseExpansion = useJsonBulkExpansion(log.responseText);
|
|
2435
|
+
const headersText = reactExports.useMemo(
|
|
2436
|
+
() => log.headers && Object.keys(log.headers).length > 0 ? JSON.stringify(log.headers, null, 2) : null,
|
|
2437
|
+
[log.headers]
|
|
2438
|
+
);
|
|
2439
|
+
const rawHeadersText = reactExports.useMemo(
|
|
2440
|
+
() => log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? JSON.stringify(log.rawHeaders, null, 2) : null,
|
|
2441
|
+
[log.rawHeaders]
|
|
2442
|
+
);
|
|
2459
2443
|
const requestCopy = useCopyFeedback(displayedRequestBody);
|
|
2460
2444
|
const rawRequestCopy = useCopyFeedback(log.rawRequestBody);
|
|
2445
|
+
const headersCopy = useCopyFeedback(headersText);
|
|
2446
|
+
const rawHeadersCopy = useCopyFeedback(rawHeadersText);
|
|
2461
2447
|
const responseCopy = useCopyFeedback(log.responseText);
|
|
2462
|
-
const
|
|
2463
|
-
|
|
2448
|
+
const tabActions = reactExports.useMemo(
|
|
2449
|
+
() => ({
|
|
2450
|
+
request: {
|
|
2451
|
+
copyLabel: "Copy request body",
|
|
2452
|
+
copyText: displayedRequestBody,
|
|
2453
|
+
copyCopied: requestCopy.copied,
|
|
2454
|
+
onCopy: requestCopy.copy,
|
|
2455
|
+
expansion: {
|
|
2456
|
+
isExpanded: requestExpansion.isExpanded,
|
|
2457
|
+
isPending: requestExpansion.isPending,
|
|
2458
|
+
onToggle: requestExpansion.toggle
|
|
2459
|
+
},
|
|
2460
|
+
// "Diff with Raw" only makes sense when there's a raw body to compare
|
|
2461
|
+
// against (Anthropic + strip pipeline produces one). "Diff with
|
|
2462
|
+
// Previous" only exists when the parent wired up the compare drawer.
|
|
2463
|
+
diffWithRaw: shouldShowRequestDiffButton(
|
|
2464
|
+
resolvedFormat,
|
|
2465
|
+
viewMode,
|
|
2466
|
+
strip,
|
|
2467
|
+
log.rawRequestBody !== null
|
|
2468
|
+
) ? { active: requestDiff, onToggle: () => setRequestDiff(!requestDiff) } : void 0,
|
|
2469
|
+
diffWithPrevious: onCompareWithPrevious === void 0 ? void 0 : () => {
|
|
2470
|
+
onCompareWithPrevious(log);
|
|
2471
|
+
}
|
|
2472
|
+
},
|
|
2473
|
+
"raw-request": {
|
|
2474
|
+
copyLabel: "Copy raw request",
|
|
2475
|
+
copyText: log.rawRequestBody,
|
|
2476
|
+
copyCopied: rawRequestCopy.copied,
|
|
2477
|
+
onCopy: rawRequestCopy.copy,
|
|
2478
|
+
expansion: {
|
|
2479
|
+
isExpanded: rawRequestExpansion.isExpanded,
|
|
2480
|
+
isPending: rawRequestExpansion.isPending,
|
|
2481
|
+
onToggle: rawRequestExpansion.toggle
|
|
2482
|
+
}
|
|
2483
|
+
},
|
|
2484
|
+
headers: {
|
|
2485
|
+
copyLabel: "Copy headers",
|
|
2486
|
+
copyText: headersText,
|
|
2487
|
+
copyCopied: headersCopy.copied,
|
|
2488
|
+
onCopy: headersCopy.copy,
|
|
2489
|
+
// Headers are a flat dict, no JSON tree to expand.
|
|
2490
|
+
expansion: null
|
|
2491
|
+
},
|
|
2492
|
+
"raw-headers": {
|
|
2493
|
+
copyLabel: "Copy raw headers",
|
|
2494
|
+
copyText: rawHeadersText,
|
|
2495
|
+
copyCopied: rawHeadersCopy.copied,
|
|
2496
|
+
onCopy: rawHeadersCopy.copy,
|
|
2497
|
+
expansion: null
|
|
2498
|
+
},
|
|
2499
|
+
raw: {
|
|
2500
|
+
copyLabel: "Copy response",
|
|
2501
|
+
copyText: log.responseText,
|
|
2502
|
+
copyCopied: responseCopy.copied,
|
|
2503
|
+
onCopy: responseCopy.copy,
|
|
2504
|
+
expansion: {
|
|
2505
|
+
isExpanded: responseExpansion.isExpanded,
|
|
2506
|
+
isPending: responseExpansion.isPending,
|
|
2507
|
+
onToggle: responseExpansion.toggle
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
}),
|
|
2511
|
+
[
|
|
2512
|
+
displayedRequestBody,
|
|
2513
|
+
requestCopy,
|
|
2514
|
+
requestExpansion,
|
|
2515
|
+
requestDiff,
|
|
2516
|
+
log.rawRequestBody,
|
|
2517
|
+
rawRequestCopy,
|
|
2518
|
+
rawRequestExpansion,
|
|
2519
|
+
headersText,
|
|
2520
|
+
headersCopy,
|
|
2521
|
+
rawHeadersText,
|
|
2522
|
+
rawHeadersCopy,
|
|
2523
|
+
log.responseText,
|
|
2524
|
+
responseCopy,
|
|
2525
|
+
responseExpansion,
|
|
2526
|
+
resolvedFormat,
|
|
2527
|
+
viewMode,
|
|
2528
|
+
strip,
|
|
2529
|
+
onCompareWithPrevious
|
|
2530
|
+
]
|
|
2531
|
+
);
|
|
2464
2532
|
const anatomySegments = reactExports.useMemo(
|
|
2465
2533
|
() => requestExpansion.parsedData !== null ? adapter.anatomySegments(requestExpansion.parsedData) : null,
|
|
2466
2534
|
[adapter, requestExpansion.parsedData]
|
|
@@ -2489,17 +2557,10 @@ const LogEntry = reactExports.memo(function({
|
|
|
2489
2557
|
responseToolNames: responseAnalysis.toolNames,
|
|
2490
2558
|
cacheTrend,
|
|
2491
2559
|
slowResponseThresholdSeconds,
|
|
2560
|
+
activeTab,
|
|
2561
|
+
tabActions,
|
|
2492
2562
|
onReplay: onCompareWithPrevious === void 0 ? void 0 : () => {
|
|
2493
2563
|
setReplayOpen(true);
|
|
2494
|
-
},
|
|
2495
|
-
onCopyRequest: displayedRequestBody === null ? void 0 : (e) => {
|
|
2496
|
-
requestCopy.copy(e);
|
|
2497
|
-
},
|
|
2498
|
-
requestCopied: requestCopy.copied,
|
|
2499
|
-
onToggleRequestExpansion: requestExpansion.toggle,
|
|
2500
|
-
requestExpansionState: requestExpansion.policy === null ? null : {
|
|
2501
|
-
isExpanded: requestExpansion.isExpanded,
|
|
2502
|
-
isPending: requestExpansion.isPending
|
|
2503
2564
|
}
|
|
2504
2565
|
}
|
|
2505
2566
|
),
|
|
@@ -2513,96 +2574,31 @@ const LogEntry = reactExports.memo(function({
|
|
|
2513
2574
|
viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }),
|
|
2514
2575
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
|
|
2515
2576
|
] }),
|
|
2516
|
-
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
bulkDepth: rawRequestExpansion.bulkDepth,
|
|
2542
|
-
bulkRevision: rawRequestExpansion.bulkRevision
|
|
2543
|
-
}
|
|
2544
|
-
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: log.rawRequestBody })
|
|
2545
|
-
] }) }),
|
|
2546
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3", children: [
|
|
2547
|
-
(shouldShowRequestDiffButton(
|
|
2548
|
-
resolvedFormat,
|
|
2549
|
-
viewMode,
|
|
2550
|
-
strip,
|
|
2551
|
-
log.rawRequestBody !== null
|
|
2552
|
-
) || onCompareWithPrevious !== void 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 mb-2", children: [
|
|
2553
|
-
shouldShowRequestDiffButton(
|
|
2554
|
-
resolvedFormat,
|
|
2555
|
-
viewMode,
|
|
2556
|
-
strip,
|
|
2557
|
-
log.rawRequestBody !== null
|
|
2558
|
-
) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2559
|
-
DiffToggleButton,
|
|
2560
|
-
{
|
|
2561
|
-
active: requestDiff,
|
|
2562
|
-
onClick: (e) => {
|
|
2563
|
-
e.stopPropagation();
|
|
2564
|
-
setRequestDiff(!requestDiff);
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
),
|
|
2568
|
-
onCompareWithPrevious !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
2569
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2570
|
-
Button,
|
|
2571
|
-
{
|
|
2572
|
-
variant: "outline",
|
|
2573
|
-
size: "sm",
|
|
2574
|
-
className: "h-8 text-xs",
|
|
2575
|
-
onClick: (e) => {
|
|
2576
|
-
e.stopPropagation();
|
|
2577
|
-
onCompareWithPrevious(log);
|
|
2578
|
-
},
|
|
2579
|
-
children: [
|
|
2580
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(GitCompareArrows, { className: "size-3 mr-1" }),
|
|
2581
|
-
"Diff with Previous"
|
|
2582
|
-
]
|
|
2583
|
-
}
|
|
2584
|
-
) }),
|
|
2585
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Compare this request with the immediately preceding one" })
|
|
2586
|
-
] })
|
|
2587
|
-
] }),
|
|
2588
|
-
requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2589
|
-
RequestDiffContent,
|
|
2590
|
-
{
|
|
2591
|
-
rawBody: log.rawRequestBody,
|
|
2592
|
-
displayedBody: displayedRequestBody,
|
|
2593
|
-
emptyLabel: "No transformation applied — raw and sent request bodies are identical."
|
|
2594
|
-
}
|
|
2595
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: requestJsonRef, children: displayedRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : requestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2596
|
-
LazyJsonViewer,
|
|
2597
|
-
{
|
|
2598
|
-
data: requestExpansion.parsedData,
|
|
2599
|
-
bulkDepth: requestExpansion.bulkDepth,
|
|
2600
|
-
bulkRevision: requestExpansion.bulkRevision,
|
|
2601
|
-
anatomyPaths,
|
|
2602
|
-
expandToPath
|
|
2603
|
-
}
|
|
2604
|
-
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: displayedRequestBody }) })
|
|
2605
|
-
] }) }),
|
|
2577
|
+
shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: log.rawRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : rawRequestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2578
|
+
LazyJsonViewer,
|
|
2579
|
+
{
|
|
2580
|
+
data: rawRequestExpansion.parsedData,
|
|
2581
|
+
bulkDepth: rawRequestExpansion.bulkDepth,
|
|
2582
|
+
bulkRevision: rawRequestExpansion.bulkRevision
|
|
2583
|
+
}
|
|
2584
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: log.rawRequestBody }) }) }),
|
|
2585
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2586
|
+
RequestDiffContent,
|
|
2587
|
+
{
|
|
2588
|
+
rawBody: log.rawRequestBody,
|
|
2589
|
+
displayedBody: displayedRequestBody,
|
|
2590
|
+
emptyLabel: "No transformation applied — raw and sent request bodies are identical."
|
|
2591
|
+
}
|
|
2592
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: requestJsonRef, children: displayedRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : requestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2593
|
+
LazyJsonViewer,
|
|
2594
|
+
{
|
|
2595
|
+
data: requestExpansion.parsedData,
|
|
2596
|
+
bulkDepth: requestExpansion.bulkDepth,
|
|
2597
|
+
bulkRevision: requestExpansion.bulkRevision,
|
|
2598
|
+
anatomyPaths,
|
|
2599
|
+
expandToPath
|
|
2600
|
+
}
|
|
2601
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: displayedRequestBody }) }) }) }),
|
|
2606
2602
|
anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "anatomy", children: activeTab === "anatomy" && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2607
2603
|
LazyRequestAnatomy,
|
|
2608
2604
|
{
|
|
@@ -2653,16 +2649,15 @@ const LogEntry = reactExports.memo(function({
|
|
|
2653
2649
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
|
|
2654
2650
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
|
|
2655
2651
|
] }),
|
|
2656
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2657
|
-
|
|
2652
|
+
log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2653
|
+
LazyJsonViewerFromString,
|
|
2658
2654
|
{
|
|
2659
2655
|
text: log.responseText,
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2656
|
+
defaultExpandDepth: 0,
|
|
2657
|
+
bulkDepth: responseExpansion.bulkDepth,
|
|
2658
|
+
bulkRevision: responseExpansion.bulkRevision
|
|
2663
2659
|
}
|
|
2664
|
-
) }),
|
|
2665
|
-
log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyJsonViewerFromString, { text: log.responseText, defaultExpandDepth: 0 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No response" }),
|
|
2660
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No response" }),
|
|
2666
2661
|
log.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2667
2662
|
LazyStreamingChunkSequence,
|
|
2668
2663
|
{
|
|
@@ -3163,6 +3158,18 @@ function CrabLogo({ className }) {
|
|
|
3163
3158
|
}
|
|
3164
3159
|
);
|
|
3165
3160
|
}
|
|
3161
|
+
const McpLogoPng = "data:image/png;base64,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";
|
|
3162
|
+
function McpLogo({ className }) {
|
|
3163
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
3164
|
+
"img",
|
|
3165
|
+
{
|
|
3166
|
+
src: McpLogoPng,
|
|
3167
|
+
alt: "Model Context Protocol",
|
|
3168
|
+
"aria-hidden": "true",
|
|
3169
|
+
className: cn("inline-block size-8 object-contain invert", className)
|
|
3170
|
+
}
|
|
3171
|
+
);
|
|
3172
|
+
}
|
|
3166
3173
|
function Select({
|
|
3167
3174
|
...props
|
|
3168
3175
|
}) {
|
|
@@ -5196,6 +5203,25 @@ function computeTokenSummary(logs) {
|
|
|
5196
5203
|
}
|
|
5197
5204
|
return { totalIn, totalOut };
|
|
5198
5205
|
}
|
|
5206
|
+
function formatTimeRange(logs) {
|
|
5207
|
+
const first = logs[0];
|
|
5208
|
+
const last = logs[logs.length - 1];
|
|
5209
|
+
if (first === void 0 || last === void 0) return null;
|
|
5210
|
+
const format = (iso) => new Date(iso).toLocaleTimeString([], {
|
|
5211
|
+
hour: "2-digit",
|
|
5212
|
+
minute: "2-digit",
|
|
5213
|
+
second: "2-digit"
|
|
5214
|
+
});
|
|
5215
|
+
return `${format(first.timestamp)} - ${format(last.timestamp)}`;
|
|
5216
|
+
}
|
|
5217
|
+
function getFirstUserAgent(logs) {
|
|
5218
|
+
for (const log of logs) {
|
|
5219
|
+
if (log.userAgent !== null && log.userAgent !== void 0 && log.userAgent !== "") {
|
|
5220
|
+
return log.userAgent;
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
return null;
|
|
5224
|
+
}
|
|
5199
5225
|
function CopyableCommand({ command }) {
|
|
5200
5226
|
const [copied, setCopied] = reactExports.useState(false);
|
|
5201
5227
|
const handleCopy = reactExports.useCallback(() => {
|
|
@@ -5247,6 +5273,82 @@ function CopyableCommand({ command }) {
|
|
|
5247
5273
|
)
|
|
5248
5274
|
] });
|
|
5249
5275
|
}
|
|
5276
|
+
function McpReadyBadge() {
|
|
5277
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
5278
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex h-7 items-center gap-2 rounded-md border border-cyan-400/30 bg-cyan-500/10 px-2.5 font-mono text-[11px] font-medium text-cyan-300 shadow-[0_0_16px_rgba(34,211,238,0.08)]", children: [
|
|
5279
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "size-1.5 rounded-full bg-emerald-300 shadow-[0_0_8px_rgba(110,231,183,0.8)]" }),
|
|
5280
|
+
"MCP Ready",
|
|
5281
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden text-cyan-200/70 sm:inline", children: "/api/mcp" })
|
|
5282
|
+
] }) }),
|
|
5283
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { sideOffset: 8, className: "max-w-[320px] text-left leading-relaxed", children: "Coding agents can inspect logs, replay requests, test providers, and debug sessions through MCP at /api/mcp." })
|
|
5284
|
+
] }) });
|
|
5285
|
+
}
|
|
5286
|
+
function SessionContextBar({
|
|
5287
|
+
sessionId,
|
|
5288
|
+
logs,
|
|
5289
|
+
totalIn,
|
|
5290
|
+
totalOut
|
|
5291
|
+
}) {
|
|
5292
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
5293
|
+
const timeRange = reactExports.useMemo(() => formatTimeRange(logs), [logs]);
|
|
5294
|
+
const userAgent = reactExports.useMemo(() => getFirstUserAgent(logs), [logs]);
|
|
5295
|
+
const handleCopyLink = reactExports.useCallback(() => {
|
|
5296
|
+
void window.navigator.clipboard.writeText(window.location.href).then(() => {
|
|
5297
|
+
setCopied(true);
|
|
5298
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
5299
|
+
});
|
|
5300
|
+
}, []);
|
|
5301
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 flex items-center gap-3 border border-border rounded-md bg-muted/20 px-3 py-2 text-xs", children: [
|
|
5302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5303
|
+
"a",
|
|
5304
|
+
{
|
|
5305
|
+
href: "/",
|
|
5306
|
+
className: "inline-flex size-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
5307
|
+
"aria-label": "Back to all sessions",
|
|
5308
|
+
title: "Back to all sessions",
|
|
5309
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { className: "size-3.5" })
|
|
5310
|
+
}
|
|
5311
|
+
),
|
|
5312
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
5313
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
5314
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-semibold text-purple-400/90 truncate", title: sessionId, children: truncateSessionId(sessionId) }),
|
|
5315
|
+
userAgent !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5316
|
+
"span",
|
|
5317
|
+
{
|
|
5318
|
+
className: "font-mono text-muted-foreground truncate max-w-[220px]",
|
|
5319
|
+
title: userAgent,
|
|
5320
|
+
children: userAgent
|
|
5321
|
+
}
|
|
5322
|
+
)
|
|
5323
|
+
] }),
|
|
5324
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-muted-foreground", children: [
|
|
5325
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
5326
|
+
logs.length,
|
|
5327
|
+
" request",
|
|
5328
|
+
logs.length !== 1 ? "s" : ""
|
|
5329
|
+
] }),
|
|
5330
|
+
timeRange !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: timeRange }),
|
|
5331
|
+
(totalIn > 0 || totalOut > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [
|
|
5332
|
+
formatTokens(totalIn),
|
|
5333
|
+
" in / ",
|
|
5334
|
+
formatTokens(totalOut),
|
|
5335
|
+
" out"
|
|
5336
|
+
] })
|
|
5337
|
+
] })
|
|
5338
|
+
] }),
|
|
5339
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5340
|
+
"button",
|
|
5341
|
+
{
|
|
5342
|
+
type: "button",
|
|
5343
|
+
onClick: handleCopyLink,
|
|
5344
|
+
className: "inline-flex size-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
5345
|
+
"aria-label": copied ? "Copied session link" : "Copy session link",
|
|
5346
|
+
title: copied ? "Copied session link" : "Copy session link",
|
|
5347
|
+
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3.5" })
|
|
5348
|
+
}
|
|
5349
|
+
)
|
|
5350
|
+
] });
|
|
5351
|
+
}
|
|
5250
5352
|
function ProxyViewer({
|
|
5251
5353
|
logs,
|
|
5252
5354
|
sessions,
|
|
@@ -5261,7 +5363,8 @@ function ProxyViewer({
|
|
|
5261
5363
|
onViewModeChange,
|
|
5262
5364
|
strip,
|
|
5263
5365
|
slowResponseThresholdSeconds,
|
|
5264
|
-
hideSessionFilter = false
|
|
5366
|
+
hideSessionFilter = false,
|
|
5367
|
+
pinnedSessionId
|
|
5265
5368
|
}) {
|
|
5266
5369
|
const { totalIn, totalOut } = reactExports.useMemo(() => computeTokenSummary(logs), [logs]);
|
|
5267
5370
|
const [exporting, setExporting] = reactExports.useState(false);
|
|
@@ -5283,6 +5386,14 @@ function ProxyViewer({
|
|
|
5283
5386
|
clearTimeout(t2);
|
|
5284
5387
|
};
|
|
5285
5388
|
}, []);
|
|
5389
|
+
reactExports.useEffect(() => {
|
|
5390
|
+
if (pinnedSessionId === void 0) {
|
|
5391
|
+
document.title = "LLM Inspector";
|
|
5392
|
+
return;
|
|
5393
|
+
}
|
|
5394
|
+
const requestLabel = logs.length === 1 ? "1 req" : `${logs.length} req`;
|
|
5395
|
+
document.title = `${truncateSessionId(pinnedSessionId)} - ${requestLabel} - LLM Inspector`;
|
|
5396
|
+
}, [logs.length, pinnedSessionId]);
|
|
5286
5397
|
const handleExport = reactExports.useCallback(async () => {
|
|
5287
5398
|
setExporting(true);
|
|
5288
5399
|
try {
|
|
@@ -5308,117 +5419,141 @@ function ProxyViewer({
|
|
|
5308
5419
|
[comparisonPredecessors]
|
|
5309
5420
|
);
|
|
5310
5421
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[1400px] xl:max-w-[1600px] 2xl:max-w-[1800px] mx-auto px-6 pb-6", children: [
|
|
5311
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "
|
|
5312
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("
|
|
5313
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
5314
|
-
|
|
5315
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
5316
|
-
|
|
5317
|
-
"
|
|
5318
|
-
"text-rose-500",
|
|
5319
|
-
"text-sky-500",
|
|
5320
|
-
"text-emerald-500",
|
|
5321
|
-
"text-violet-500",
|
|
5322
|
-
"text-orange-500",
|
|
5323
|
-
"text-cyan-500",
|
|
5324
|
-
"text-pink-500",
|
|
5325
|
-
"text-lime-500",
|
|
5326
|
-
"text-blue-500",
|
|
5327
|
-
"text-yellow-500",
|
|
5328
|
-
"text-fuchsia-500"
|
|
5329
|
-
][i];
|
|
5330
|
-
const entranceClass = crabEntrancePhase === "hidden" ? "opacity-0 scale-0" : crabEntrancePhase === "playing" ? "animate-crab-piano-pop" : "";
|
|
5331
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5332
|
-
Crab,
|
|
5422
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sticky top-0 z-30 bg-background pt-6", children: [
|
|
5423
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[1fr_auto_1fr] items-start gap-3 pb-8", children: [
|
|
5424
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", {}),
|
|
5425
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "flex min-w-0 flex-col items-center gap-2 text-center", children: [
|
|
5426
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex max-w-[calc(100vw-7rem)] items-end gap-2 whitespace-nowrap", children: [
|
|
5427
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5428
|
+
"span",
|
|
5333
5429
|
{
|
|
5334
|
-
className:
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5430
|
+
className: "flex shrink-0 items-end gap-1 group cursor-default",
|
|
5431
|
+
"aria-hidden": "true",
|
|
5432
|
+
children: [
|
|
5433
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" }),
|
|
5434
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden items-end gap-0.5 sm:flex", children: crabVariants.map((Crab, i) => {
|
|
5435
|
+
const color = [
|
|
5436
|
+
"text-amber-500",
|
|
5437
|
+
"text-rose-500",
|
|
5438
|
+
"text-sky-500",
|
|
5439
|
+
"text-emerald-500",
|
|
5440
|
+
"text-violet-500",
|
|
5441
|
+
"text-orange-500",
|
|
5442
|
+
"text-cyan-500",
|
|
5443
|
+
"text-pink-500",
|
|
5444
|
+
"text-lime-500",
|
|
5445
|
+
"text-blue-500",
|
|
5446
|
+
"text-yellow-500",
|
|
5447
|
+
"text-fuchsia-500"
|
|
5448
|
+
][i];
|
|
5449
|
+
const entranceClass = crabEntrancePhase === "hidden" ? "opacity-0 scale-0" : crabEntrancePhase === "playing" ? "animate-crab-piano-pop" : "";
|
|
5450
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5451
|
+
Crab,
|
|
5452
|
+
{
|
|
5453
|
+
className: `size-5 ${color} transition-all duration-300 ease-out group-hover:scale-125 group-hover:-translate-y-1 ${entranceClass}`,
|
|
5454
|
+
style: {
|
|
5455
|
+
transitionDelay: `${i * 50}ms`,
|
|
5456
|
+
...crabEntrancePhase === "playing" ? { animationDelay: `${i * 400}ms` } : {}
|
|
5457
|
+
}
|
|
5458
|
+
},
|
|
5459
|
+
i
|
|
5460
|
+
);
|
|
5461
|
+
}) })
|
|
5462
|
+
]
|
|
5463
|
+
}
|
|
5464
|
+
),
|
|
5465
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 items-baseline gap-2 pl-1", children: [
|
|
5466
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate text-lg font-bold", children: "LLM Inspector" }),
|
|
5467
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 font-mono text-xs font-semibold text-muted-foreground", children: [
|
|
5468
|
+
"v",
|
|
5469
|
+
packageJson.version
|
|
5470
|
+
] })
|
|
5471
|
+
] }),
|
|
5472
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-4 shrink-0 text-muted-foreground/70", "aria-hidden": "true" }),
|
|
5473
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(McpLogo, { className: "size-10 shrink-0" })
|
|
5474
|
+
] }),
|
|
5475
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(McpReadyBadge, {})
|
|
5343
5476
|
] }),
|
|
5344
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
5345
|
-
"LLM Inspector",
|
|
5346
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-muted-foreground font-mono", children: [
|
|
5347
|
-
"v",
|
|
5348
|
-
packageJson.version
|
|
5349
|
-
] })
|
|
5350
|
-
] })
|
|
5351
|
-
] }),
|
|
5352
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}) })
|
|
5353
|
-
] }),
|
|
5354
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
5355
|
-
!hideSessionFilter && /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedSession, onValueChange: onSessionChange, children: [
|
|
5356
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[350px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All sessions" }) }),
|
|
5357
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
|
|
5358
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All sessions" }),
|
|
5359
|
-
sessions.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: s, children: truncateSessionId(s) }, s))
|
|
5360
|
-
] })
|
|
5477
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "justify-self-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {}) })
|
|
5361
5478
|
] }),
|
|
5362
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5479
|
+
pinnedSessionId !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5480
|
+
SessionContextBar,
|
|
5481
|
+
{
|
|
5482
|
+
sessionId: pinnedSessionId,
|
|
5483
|
+
logs,
|
|
5484
|
+
totalIn,
|
|
5485
|
+
totalOut
|
|
5486
|
+
}
|
|
5487
|
+
),
|
|
5488
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
5489
|
+
!hideSessionFilter && /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedSession, onValueChange: onSessionChange, children: [
|
|
5490
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[350px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All sessions" }) }),
|
|
5491
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
|
|
5492
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All sessions" }),
|
|
5493
|
+
sessions.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: s, children: truncateSessionId(s) }, s))
|
|
5494
|
+
] })
|
|
5495
|
+
] }),
|
|
5496
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedModel, onValueChange: onModelChange, children: [
|
|
5497
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[250px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All models" }) }),
|
|
5498
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
|
|
5499
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "__all__", children: "All models" }),
|
|
5500
|
+
models.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: m, children: m }, m))
|
|
5501
|
+
] })
|
|
5502
|
+
] }),
|
|
5503
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
|
|
5504
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5505
|
+
"button",
|
|
5506
|
+
{
|
|
5507
|
+
type: "button",
|
|
5508
|
+
onClick: () => onViewModeChange("simple"),
|
|
5509
|
+
className: `h-8 px-3 cursor-pointer transition-colors text-xs ${viewMode === "simple" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
5510
|
+
children: "Simple"
|
|
5511
|
+
}
|
|
5512
|
+
),
|
|
5513
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5514
|
+
"button",
|
|
5515
|
+
{
|
|
5516
|
+
type: "button",
|
|
5517
|
+
onClick: () => onViewModeChange("full"),
|
|
5518
|
+
className: `h-8 px-3 cursor-pointer transition-colors text-xs ${viewMode === "full" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
|
|
5519
|
+
children: "Full"
|
|
5520
|
+
}
|
|
5521
|
+
)
|
|
5522
|
+
] }),
|
|
5523
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
5524
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
|
|
5525
|
+
logs.length,
|
|
5526
|
+
" request",
|
|
5527
|
+
logs.length !== 1 ? "s" : "",
|
|
5528
|
+
totalIn > 0 || totalOut > 0 ? ` · ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out` : ""
|
|
5529
|
+
] }),
|
|
5530
|
+
logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5371
5531
|
"button",
|
|
5372
5532
|
{
|
|
5373
5533
|
type: "button",
|
|
5374
|
-
onClick: () =>
|
|
5375
|
-
|
|
5376
|
-
|
|
5534
|
+
onClick: () => {
|
|
5535
|
+
void handleExport();
|
|
5536
|
+
},
|
|
5537
|
+
disabled: exporting,
|
|
5538
|
+
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5 rounded-md hover:bg-muted",
|
|
5539
|
+
title: "Export all logs as JSON ZIP",
|
|
5540
|
+
children: exporting ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
5541
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3.5" }),
|
|
5542
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export" })
|
|
5543
|
+
] })
|
|
5377
5544
|
}
|
|
5378
5545
|
),
|
|
5379
5546
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5380
5547
|
"button",
|
|
5381
5548
|
{
|
|
5382
5549
|
type: "button",
|
|
5383
|
-
onClick:
|
|
5384
|
-
className:
|
|
5385
|
-
|
|
5550
|
+
onClick: onClearAll,
|
|
5551
|
+
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer rounded-md hover:bg-muted",
|
|
5552
|
+
title: "Clear all logs",
|
|
5553
|
+
children: "Clear"
|
|
5386
5554
|
}
|
|
5387
5555
|
)
|
|
5388
|
-
] })
|
|
5389
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
5390
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
|
|
5391
|
-
logs.length,
|
|
5392
|
-
" request",
|
|
5393
|
-
logs.length !== 1 ? "s" : "",
|
|
5394
|
-
totalIn > 0 || totalOut > 0 ? ` · ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out` : ""
|
|
5395
|
-
] }),
|
|
5396
|
-
logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5397
|
-
"button",
|
|
5398
|
-
{
|
|
5399
|
-
type: "button",
|
|
5400
|
-
onClick: () => {
|
|
5401
|
-
void handleExport();
|
|
5402
|
-
},
|
|
5403
|
-
disabled: exporting,
|
|
5404
|
-
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5 rounded-md hover:bg-muted",
|
|
5405
|
-
title: "Export all logs as JSON ZIP",
|
|
5406
|
-
children: exporting ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
5407
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3.5" }),
|
|
5408
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export" })
|
|
5409
|
-
] })
|
|
5410
|
-
}
|
|
5411
|
-
),
|
|
5412
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5413
|
-
"button",
|
|
5414
|
-
{
|
|
5415
|
-
type: "button",
|
|
5416
|
-
onClick: onClearAll,
|
|
5417
|
-
className: "h-8 px-3 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer rounded-md hover:bg-muted",
|
|
5418
|
-
title: "Clear all logs",
|
|
5419
|
-
children: "Clear"
|
|
5420
|
-
}
|
|
5421
|
-
)
|
|
5556
|
+
] })
|
|
5422
5557
|
] }),
|
|
5423
5558
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: logs.length === 0 ? selectedSession !== "__all__" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
|
|
5424
5559
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: "Session not found" }),
|
|
@@ -5426,7 +5561,7 @@ function ProxyViewer({
|
|
|
5426
5561
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs", children: [
|
|
5427
5562
|
"This session may have been cleared or never existed.",
|
|
5428
5563
|
" ",
|
|
5429
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5564
|
+
hideSessionFilter ? /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "/", className: "underline hover:text-foreground transition-colors", children: "Back to all sessions" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5430
5565
|
"button",
|
|
5431
5566
|
{
|
|
5432
5567
|
type: "button",
|
|
@@ -5499,6 +5634,11 @@ function filterLogs(logs, selectedSession, selectedModel) {
|
|
|
5499
5634
|
});
|
|
5500
5635
|
}
|
|
5501
5636
|
const DEBOUNCE_MS = 50;
|
|
5637
|
+
function buildLogsStreamUrl(sessionId) {
|
|
5638
|
+
if (sessionId === void 0) return "/api/logs/stream";
|
|
5639
|
+
const params = new URLSearchParams({ sessionId });
|
|
5640
|
+
return `/api/logs/stream?${params.toString()}`;
|
|
5641
|
+
}
|
|
5502
5642
|
function ProxyViewerContainer({
|
|
5503
5643
|
initialSessionId
|
|
5504
5644
|
} = {}) {
|
|
@@ -5550,7 +5690,7 @@ function ProxyViewerContainer({
|
|
|
5550
5690
|
if (eventSourceRef.current) {
|
|
5551
5691
|
eventSourceRef.current.close();
|
|
5552
5692
|
}
|
|
5553
|
-
const es = new EventSource(
|
|
5693
|
+
const es = new EventSource(buildLogsStreamUrl(initialSessionId));
|
|
5554
5694
|
eventSourceRef.current = es;
|
|
5555
5695
|
es.onmessage = (event) => {
|
|
5556
5696
|
try {
|
|
@@ -5591,7 +5731,7 @@ function ProxyViewerContainer({
|
|
|
5591
5731
|
}
|
|
5592
5732
|
reconnectTimeoutRef.current = setTimeout(connectSSE, 3e3);
|
|
5593
5733
|
};
|
|
5594
|
-
}, [scheduleUpdate]);
|
|
5734
|
+
}, [initialSessionId, scheduleUpdate]);
|
|
5595
5735
|
reactExports.useEffect(() => {
|
|
5596
5736
|
connectSSE();
|
|
5597
5737
|
return () => {
|
|
@@ -5610,9 +5750,17 @@ function ProxyViewerContainer({
|
|
|
5610
5750
|
};
|
|
5611
5751
|
}, [connectSSE]);
|
|
5612
5752
|
const handleClearAll = reactExports.useCallback(() => {
|
|
5753
|
+
if (initialSessionId !== void 0 && allLogs.length === 0) return;
|
|
5613
5754
|
void (async () => {
|
|
5614
5755
|
try {
|
|
5615
|
-
const
|
|
5756
|
+
const body = initialSessionId === void 0 ? void 0 : JSON.stringify({ ids: allLogs.map((log) => log.id) });
|
|
5757
|
+
const res = await fetch("/api/logs", {
|
|
5758
|
+
method: "DELETE",
|
|
5759
|
+
...body === void 0 ? {} : {
|
|
5760
|
+
headers: { "Content-Type": "application/json" },
|
|
5761
|
+
body
|
|
5762
|
+
}
|
|
5763
|
+
});
|
|
5616
5764
|
if (!res.ok) {
|
|
5617
5765
|
setError("Failed to clear logs");
|
|
5618
5766
|
return;
|
|
@@ -5624,7 +5772,7 @@ function ProxyViewerContainer({
|
|
|
5624
5772
|
setError(err instanceof Error ? err.message : "Unknown error clearing logs");
|
|
5625
5773
|
}
|
|
5626
5774
|
})();
|
|
5627
|
-
}, []);
|
|
5775
|
+
}, [allLogs, initialSessionId]);
|
|
5628
5776
|
const handleClearGroup = reactExports.useCallback((ids) => {
|
|
5629
5777
|
if (ids.length === 0) return;
|
|
5630
5778
|
void (async () => {
|
|
@@ -5675,7 +5823,8 @@ function ProxyViewerContainer({
|
|
|
5675
5823
|
onViewModeChange: setViewMode,
|
|
5676
5824
|
strip,
|
|
5677
5825
|
slowResponseThresholdSeconds,
|
|
5678
|
-
hideSessionFilter: initialSessionId !== void 0
|
|
5826
|
+
hideSessionFilter: initialSessionId !== void 0,
|
|
5827
|
+
pinnedSessionId: initialSessionId
|
|
5679
5828
|
}
|
|
5680
5829
|
)
|
|
5681
5830
|
] });
|