@tonyclaw/agent-inspector 2.0.18 → 2.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.output/cli.js +137 -8
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-CepU-dLW.js → CompareDrawer-D-90PIPw.js} +1 -1
  4. package/.output/public/assets/ProxyViewerContainer-CxRDWacg.js +114 -0
  5. package/.output/public/assets/ReplayDialog-DzlLYoTO.js +1 -0
  6. package/.output/public/assets/{RequestAnatomy-C_C6ZU3T.js → RequestAnatomy-0hbyf6oa.js} +1 -1
  7. package/.output/public/assets/ResponseView-CKe0tNqr.js +1 -0
  8. package/.output/public/assets/StreamingChunkSequence-enhfdeNh.js +1 -0
  9. package/.output/public/assets/_sessionId-CJ-SusES.js +1 -0
  10. package/.output/public/assets/index-BbFsmQRC.js +1 -0
  11. package/.output/public/assets/index-BfBgrkgU.css +1 -0
  12. package/.output/public/assets/{main-BRXsrxtv.js → main-o9-hg8g1.js} +2 -2
  13. package/.output/server/_libs/lucide-react.mjs +141 -118
  14. package/.output/server/_libs/tanstack__react-virtual.mjs +13 -2
  15. package/.output/server/_libs/tanstack__virtual-core.mjs +24 -1
  16. package/.output/server/{_sessionId-B8Bbfs-v.mjs → _sessionId-F8lm6PIb.mjs} +3 -2
  17. package/.output/server/_ssr/{CompareDrawer-TgGZLf1J.mjs → CompareDrawer-Cf1yfwfd.mjs} +4 -3
  18. package/.output/server/_ssr/{ProxyViewerContainer-B_ppaNmQ.mjs → ProxyViewerContainer-Bmu9867L.mjs} +349 -74
  19. package/.output/server/_ssr/{ReplayDialog-BXlajnMC.mjs → ReplayDialog-DxZfLBOe.mjs} +199 -17
  20. package/.output/server/_ssr/{RequestAnatomy-CCrx09-i.mjs → RequestAnatomy-CbdERGZd.mjs} +4 -3
  21. package/.output/server/_ssr/{ResponseView-BxtMJrov.mjs → ResponseView-CvLd6qxI.mjs} +4 -3
  22. package/.output/server/_ssr/{StreamingChunkSequence-BlpdSPb8.mjs → StreamingChunkSequence-B_lkRB6o.mjs} +4 -3
  23. package/.output/server/_ssr/{index-BeTMNSJy.mjs → index-ejrSItfz.mjs} +3 -2
  24. package/.output/server/_ssr/index.mjs +2 -2
  25. package/.output/server/_ssr/{router-Ddl1tuU7.mjs → router-SbCnbDc2.mjs} +872 -232
  26. package/.output/server/{_tanstack-start-manifest_v-Bvdz_U0f.mjs → _tanstack-start-manifest_v-yx8ftqWz.mjs} +1 -1
  27. package/.output/server/index.mjs +54 -54
  28. package/README.md +11 -109
  29. package/package.json +2 -1
  30. package/src/cli/doctor.ts +150 -5
  31. package/src/components/OnboardingBanner.tsx +13 -13
  32. package/src/components/ProxyViewer.tsx +55 -38
  33. package/src/components/ProxyViewerContainer.tsx +5 -0
  34. package/src/components/providers/SettingsDialog.tsx +113 -2
  35. package/src/components/proxy-viewer/ConversationGroup.tsx +20 -3
  36. package/src/components/proxy-viewer/ConversationGroupList.tsx +144 -0
  37. package/src/components/proxy-viewer/ConversationHeader.tsx +0 -2
  38. package/src/components/proxy-viewer/ReplayDialog.tsx +200 -13
  39. package/src/components/proxy-viewer/index.ts +1 -1
  40. package/src/knowledge/openclawClient.ts +0 -8
  41. package/src/knowledge/types.ts +0 -2
  42. package/src/lib/export-logs.ts +72 -5
  43. package/src/lib/providerTestContract.ts +0 -1
  44. package/src/lib/useProviders.ts +1 -1
  45. package/src/mcp/server.ts +14 -6
  46. package/src/mcp/toolHandlers.ts +21 -4
  47. package/src/proxy/chunkStorage.ts +2 -4
  48. package/src/proxy/dataDir.ts +3 -3
  49. package/src/proxy/formats/anthropic/index.ts +0 -1
  50. package/src/proxy/formats/anthropic/schemas.ts +0 -2
  51. package/src/proxy/handler.ts +41 -29
  52. package/src/proxy/logFinalizer.ts +93 -11
  53. package/src/proxy/logger.ts +35 -10
  54. package/src/proxy/providers.ts +12 -5
  55. package/src/proxy/rawStreamCapture.ts +85 -0
  56. package/src/proxy/schemas.ts +1 -51
  57. package/src/proxy/sessionRuntime.ts +0 -9
  58. package/src/proxy/socketTracker.ts +15 -8
  59. package/src/proxy/store.ts +414 -13
  60. package/src/routes/api/logs.$id.replay.ts +66 -1
  61. package/src/routes/api/logs.stream.ts +11 -3
  62. package/src/routes/api/logs.ts +51 -17
  63. package/src/routes/api/providers.$providerId.ts +10 -3
  64. package/src/routes/api/providers.ts +6 -3
  65. package/.output/public/assets/ProxyViewerContainer-BG7rc33d.js +0 -114
  66. package/.output/public/assets/ReplayDialog-DK6SPv8X.js +0 -1
  67. package/.output/public/assets/ResponseView-Bqpra4Zw.js +0 -1
  68. package/.output/public/assets/StreamingChunkSequence-CdPbpprq.js +0 -1
  69. package/.output/public/assets/_sessionId-CsNARHj5.js +0 -1
  70. package/.output/public/assets/index-37NfO0zx.js +0 -1
  71. package/.output/public/assets/index-D_nZj9Vt.css +0 -1
  72. package/src/components/ui/json-expansion-button.tsx +0 -56
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_TIME_DISPLAY_FORMAT, c as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, i as createPendingProviderTestResults, j as ProviderTestResultsSchema, k as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, T as TimeDisplayFormatSchema, g as getSessionPath, f as providerHasContextMetadata, h as findProviderModelMetadata, s as safeGetOwnProperty, K as KnowledgeCandidateSchema, e as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, d as AnthropicRequestSchema, l as resolveProviderContextWindow, m as isPlainRecord } from "./router-Ddl1tuU7.mjs";
2
+ import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_TIME_DISPLAY_FORMAT, c as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, i as createPendingProviderTestResults, j as ProviderTestResultsSchema, k as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, f as providerHasContextMetadata, h as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, d as AnthropicRequestSchema, s as safeGetOwnProperty, l as resolveProviderContextWindow, K as KnowledgeCandidateSchema, e as stripClaudeCodeBillingHeader, n as isPlainRecord } from "./router-SbCnbDc2.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";
@@ -7,9 +7,9 @@ import { t as twMerge } from "../_libs/tailwind-merge.mjs";
7
7
  import { c as cva } from "../_libs/class-variance-authority.mjs";
8
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
- import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
10
+ import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
11
11
  import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
12
- import { C as Check, X, P as Plus, D as Download, S as Settings, A as ArrowLeft, a as Copy, b as ChevronDown, U as Upload, c as Scan, d as CircleAlert, T as Terminal, e as ChevronUp, L as LoaderCircle, f as ChevronRight, g as User, h as Clock, M as MessageSquare, Z as Zap, E as ExternalLink, i as Trash2, W as Wrench, j as TriangleAlert, B as Brain, k as EyeOff, l as Eye, R as RotateCw, m as Pencil, n as ArrowUpRight, o as ArrowDownRight, p as Minus, q as CircleCheckBig, r as CircleX, s as ShieldCheck, t as RefreshCw, u as Save, F as FileSearch, v as CircleCheck, w as CloudUpload, O as OctagonAlert, G as Globe, x as FileTerminal, y as Radio, z as ChevronsUp, H as ChevronsDown, I as FileDiff, J as History, K as RotateCcw, N as Search, Q as GitCompareArrows, V as CircleQuestionMark, Y as Server, _ as Gauge, $ as Lock, a0 as Wifi, a1 as WifiOff, a2 as ArrowUp, a3 as ArrowDown, a4 as Ellipsis, a5 as CodeXml, a6 as Blocks, a7 as MousePointerClick, a8 as FileText, a9 as Rows3, aa as Columns2 } from "../_libs/lucide-react.mjs";
12
+ import { C as Check, X, P as Plus, D as Download, S as Settings, A as ArrowLeft, a as Copy, b as ChevronDown, U as Upload, c as Scan, d as CircleAlert, T as Terminal, e as ChevronUp, E as EyeOff, f as Eye, g as ExternalLink, R as RotateCw, h as Clock, i as Pencil, j as Trash2, L as LoaderCircle, k as ArrowUpRight, l as ArrowDownRight, m as ChevronRight, n as User, M as MessageSquare, Z as Zap, W as Wrench, o as TriangleAlert, B as Brain, p as Minus, q as CircleCheckBig, r as CircleQuestionMark, s as Server, G as Gauge, t as Lock, u as Wifi, v as WifiOff, w as CircleX, x as ShieldCheck, y as RefreshCw, z as Save, F as FileSearch, H as CircleCheck, I as CloudUpload, O as OctagonAlert, J as Globe, K as FileTerminal, N as Radio, Q as ChevronsUp, V as ChevronsDown, Y as FileDiff, _ as History, $ as RotateCcw, a0 as Search, a1 as GitCompareArrows, a2 as ArrowUp, a3 as ArrowDown, a4 as Ellipsis, a5 as CodeXml, a6 as Blocks, a7 as MousePointerClick, a8 as FileText, a9 as Rows3, aa as Columns2 } from "../_libs/lucide-react.mjs";
13
13
  import { M as Markdown } from "../_libs/react-markdown.mjs";
14
14
  import { u as union, d as object, a as array, l as literal, b as string, n as number, c as boolean, _ as _enum } from "../_libs/zod.mjs";
15
15
  import { P as Provider, R as Root3, T as Trigger$1, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
@@ -191,36 +191,39 @@ function OnboardingBanner() {
191
191
  children: [
192
192
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
193
193
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-1 font-medium text-amber-600 dark:text-amber-400", children: isFullMode ? "Agent Inspector is ready in Full mode" : "Agent Inspector is ready in Simple mode" }),
194
- /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "space-y-0.5 text-xs leading-relaxed text-muted-foreground", children: [
194
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("ol", { className: "space-y-0.5 text-xs leading-relaxed text-muted-foreground", children: [
195
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
196
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "1. Start in the right mode" }),
197
+ ": this process is currently running in",
198
+ " ",
199
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: captureMode }),
200
+ ". Mode is fixed at startup."
201
+ ] }),
195
202
  isFullMode ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
196
203
  /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
197
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Full mode" }),
198
- ": raw headers, raw response, and SSE chunks are captured for diagnostics."
204
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "2. Full diagnostics" }),
205
+ ": raw headers, raw response, and SSE chunks are captured for deep investigations."
199
206
  ] }),
200
207
  /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
201
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Daily work" }),
202
- ": restart with ",
203
- /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "agent-inspector --mode simple" }),
208
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "3. Daily work" }),
209
+ ": restart with",
204
210
  " ",
205
- "to reduce capture overhead."
211
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "agent-inspector --mode simple" }),
212
+ " to reduce capture overhead."
206
213
  ] })
207
214
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
208
215
  /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
209
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Simple mode" }),
210
- ": lightweight capture for requests, responses, tools, timing, and token usage."
216
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "2. Simple capture" }),
217
+ ": requests, responses, tools, timing, tokens, replay, and memory candidates are available with lower overhead."
211
218
  ] }),
212
219
  /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
213
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Need diagnostics?" }),
220
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "3. Need raw diagnostics?" }),
214
221
  " Restart with",
215
222
  " ",
216
223
  /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "agent-inspector --mode full" }),
217
224
  " for raw headers, raw response, and SSE chunks."
218
225
  ] })
219
226
  ] }),
220
- /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
221
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Replay and Memory" }),
222
- ": available in both modes for provider checks and reviewable knowledge candidates."
223
- ] }),
224
227
  /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
225
228
  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Agent setup" }),
226
229
  ": run ",
@@ -265,6 +268,15 @@ function OnboardingBanner() {
265
268
  }
266
269
  );
267
270
  }
271
+ const REDACTED = "[REDACTED]";
272
+ const SECRET_KEY_PATTERN = /(^|[-_])(api[-_]?key|authorization|cookie|token|secret|password|access[-_]?token|refresh[-_]?token)([-_]|$)/i;
273
+ const SECRET_TEXT_PATTERNS = [
274
+ /Bearer\s+[A-Za-z0-9._~+/=-]{12,}/gi,
275
+ /\bsk-[A-Za-z0-9_-]{12,}\b/g,
276
+ /\bsk-ant-[A-Za-z0-9_-]{12,}\b/g,
277
+ /\bghp_[A-Za-z0-9_]{12,}\b/g,
278
+ /\bglpat-[A-Za-z0-9_-]{12,}\b/g
279
+ ];
268
280
  async function fetchStreamingChunks(logId) {
269
281
  try {
270
282
  const response = await fetch(`/api/logs/${logId}/chunks`);
@@ -275,14 +287,59 @@ async function fetchStreamingChunks(logId) {
275
287
  return null;
276
288
  }
277
289
  }
278
- async function exportLogsAsZip(logs) {
290
+ function isRecord$1(value) {
291
+ return typeof value === "object" && value !== null && !Array.isArray(value);
292
+ }
293
+ function redactValue(value) {
294
+ if (Array.isArray(value)) return value.map((item) => redactValue(item));
295
+ if (!isRecord$1(value)) return value;
296
+ const result = {};
297
+ for (const [key, item] of Object.entries(value)) {
298
+ result[key] = SECRET_KEY_PATTERN.test(key) ? REDACTED : redactValue(item);
299
+ }
300
+ return result;
301
+ }
302
+ function redactJsonText(text) {
303
+ const redactText = (value) => {
304
+ let result = value;
305
+ for (const pattern of SECRET_TEXT_PATTERNS) {
306
+ result = result.replace(pattern, REDACTED);
307
+ }
308
+ return result;
309
+ };
310
+ try {
311
+ const parsed = JSON.parse(text);
312
+ return redactText(JSON.stringify(redactValue(parsed), null, 2));
313
+ } catch {
314
+ return redactText(text);
315
+ }
316
+ }
317
+ function exportText(text, mode) {
318
+ return mode === "redacted" ? redactJsonText(text) : text;
319
+ }
320
+ async function exportLogsAsZip(logs, mode = "redacted") {
279
321
  const zip = new JSZip();
322
+ const suffix = mode === "redacted" ? "redacted" : "raw";
323
+ zip.file(
324
+ "manifest.json",
325
+ JSON.stringify(
326
+ {
327
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
328
+ mode,
329
+ redacted: mode === "redacted",
330
+ logCount: logs.length,
331
+ logIds: logs.map((log) => log.id)
332
+ },
333
+ null,
334
+ 2
335
+ )
336
+ );
280
337
  for (const log of logs) {
281
338
  if (log.rawRequestBody !== null) {
282
- zip.file(`#${log.id}.Request.json`, log.rawRequestBody);
339
+ zip.file(`#${log.id}.Request.json`, exportText(log.rawRequestBody, mode));
283
340
  }
284
341
  if (log.responseText !== null) {
285
- zip.file(`#${log.id}.Response.json`, log.responseText);
342
+ zip.file(`#${log.id}.Response.json`, exportText(log.responseText, mode));
286
343
  }
287
344
  }
288
345
  const streamingLogs = logs.filter((log) => log.streaming);
@@ -290,7 +347,7 @@ async function exportLogsAsZip(logs) {
290
347
  streamingLogs.map(async (log) => {
291
348
  const chunks = await fetchStreamingChunks(log.id);
292
349
  if (chunks !== null) {
293
- zip.file(`#${log.id}.SSE.Response.json`, chunks);
350
+ zip.file(`#${log.id}.SSE.Response.json`, exportText(chunks, mode));
294
351
  }
295
352
  })
296
353
  );
@@ -298,7 +355,7 @@ async function exportLogsAsZip(logs) {
298
355
  const url = URL.createObjectURL(blob);
299
356
  const anchor = document.createElement("a");
300
357
  anchor.href = url;
301
- anchor.download = `agent-inspector-export-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.zip`;
358
+ anchor.download = `agent-inspector-export-${suffix}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.zip`;
302
359
  document.body.appendChild(anchor);
303
360
  anchor.click();
304
361
  document.body.removeChild(anchor);
@@ -349,7 +406,7 @@ async function fetcher(url) {
349
406
  }
350
407
  function useProviders() {
351
408
  const response = useSWR(
352
- "/api/providers",
409
+ "/api/providers?includeSecrets=1",
353
410
  fetcher,
354
411
  {
355
412
  revalidateOnFocus: false,
@@ -363,7 +420,7 @@ function useProviders() {
363
420
  mutate: response.mutate
364
421
  };
365
422
  }
366
- const version = "2.0.18";
423
+ const version = "2.0.19";
367
424
  const packageJson = {
368
425
  version
369
426
  };
@@ -1424,19 +1481,19 @@ function useCopyFeedback(text) {
1424
1481
  return { copied, copy };
1425
1482
  }
1426
1483
  const LazyCompareDrawer = reactExports.lazy(
1427
- () => import("./CompareDrawer-TgGZLf1J.mjs").then((m) => ({ default: m.CompareDrawer }))
1484
+ () => import("./CompareDrawer-Cf1yfwfd.mjs").then((m) => ({ default: m.CompareDrawer }))
1428
1485
  );
1429
1486
  const LazyReplayDialog = reactExports.lazy(
1430
- () => import("./ReplayDialog-BXlajnMC.mjs").then((m) => ({ default: m.ReplayDialog }))
1487
+ () => import("./ReplayDialog-DxZfLBOe.mjs").then((m) => ({ default: m.ReplayDialog }))
1431
1488
  );
1432
1489
  const LazyRequestAnatomy = reactExports.lazy(
1433
- () => import("./RequestAnatomy-CCrx09-i.mjs").then((m) => ({ default: m.RequestAnatomy }))
1490
+ () => import("./RequestAnatomy-CbdERGZd.mjs").then((m) => ({ default: m.RequestAnatomy }))
1434
1491
  );
1435
1492
  const LazyResponseView = reactExports.lazy(
1436
- () => import("./ResponseView-BxtMJrov.mjs").then((m) => ({ default: m.ResponseView }))
1493
+ () => import("./ResponseView-CvLd6qxI.mjs").then((m) => ({ default: m.ResponseView }))
1437
1494
  );
1438
1495
  const LazyStreamingChunkSequence = reactExports.lazy(
1439
- () => import("./StreamingChunkSequence-BlpdSPb8.mjs").then((m) => ({
1496
+ () => import("./StreamingChunkSequence-B_lkRB6o.mjs").then((m) => ({
1440
1497
  default: m.StreamingChunkSequence
1441
1498
  }))
1442
1499
  );
@@ -4944,9 +5001,22 @@ const ConversationGroup = reactExports.memo(function({
4944
5001
  onClearGroup,
4945
5002
  standalone = false,
4946
5003
  hasPinnedSessionContext = false,
4947
- timeDisplayFormat
5004
+ timeDisplayFormat,
5005
+ expanded: controlledExpanded,
5006
+ onExpandedChange
4948
5007
  }) {
4949
- const [expanded, setExpanded] = reactExports.useState(false);
5008
+ const [internalExpanded, setInternalExpanded] = reactExports.useState(false);
5009
+ const expanded = controlledExpanded ?? internalExpanded;
5010
+ const setExpanded = reactExports.useCallback(
5011
+ (nextExpanded) => {
5012
+ if (onExpandedChange !== void 0) {
5013
+ onExpandedChange(nextExpanded);
5014
+ return;
5015
+ }
5016
+ setInternalExpanded(nextExpanded);
5017
+ },
5018
+ [onExpandedChange]
5019
+ );
4950
5020
  const stats = reactExports.useMemo(() => computeStats(group.logs), [group.logs]);
4951
5021
  const startTime = group.logs[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
4952
5022
  const endTime = group.logs[group.logs.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -4966,7 +5036,7 @@ const ConversationGroup = reactExports.memo(function({
4966
5036
  return () => {
4967
5037
  window.removeEventListener(LOG_FOCUS_REQUEST_EVENT, handleLogFocusRequest);
4968
5038
  };
4969
- }, [group.logs, standalone]);
5039
+ }, [group.logs, setExpanded, standalone]);
4970
5040
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-2", children: [
4971
5041
  !standalone && /* @__PURE__ */ jsxRuntimeExports.jsx(
4972
5042
  ConversationHeader,
@@ -5520,10 +5590,6 @@ function ImportWizardDialog({
5520
5590
  ] })
5521
5591
  ] }) });
5522
5592
  }
5523
- function maskApiKey(apiKey) {
5524
- if (apiKey.length <= 8) return "••••••••";
5525
- return apiKey.slice(0, 4) + "••••••••" + apiKey.slice(-4);
5526
- }
5527
5593
  const KNOWN_PROVIDER_DOCS = {
5528
5594
  deepseek: "https://api-docs.deepseek.com/zh-cn/"
5529
5595
  };
@@ -7112,6 +7178,7 @@ function SettingsDialog() {
7112
7178
  /* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { children: [
7113
7179
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "providers", children: "Providers" }),
7114
7180
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "proxy", children: "Proxy" }),
7181
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "storage", children: "Storage" }),
7115
7182
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "onboarding", children: "Onboarding" })
7116
7183
  ] }),
7117
7184
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 flex-1 overflow-x-hidden overflow-y-auto pr-3", children: [
@@ -7132,12 +7199,95 @@ function SettingsDialog() {
7132
7199
  }
7133
7200
  ) }),
7134
7201
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "proxy", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProxySettingsTab, {}) }),
7202
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "storage", children: /* @__PURE__ */ jsxRuntimeExports.jsx(StorageSettingsTab, {}) }),
7135
7203
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "onboarding", children: /* @__PURE__ */ jsxRuntimeExports.jsx(OnboardingSettingsTab, {}) })
7136
7204
  ] })
7137
7205
  ] })
7138
7206
  ] })
7139
7207
  ] });
7140
7208
  }
7209
+ const LogStorageStatsSchema = object({
7210
+ memoryCount: number(),
7211
+ logDir: string(),
7212
+ logFileCount: number(),
7213
+ logBytes: number(),
7214
+ chunkDir: string(),
7215
+ chunkFileCount: number(),
7216
+ chunkBytes: number()
7217
+ });
7218
+ function formatBytes(bytes) {
7219
+ if (bytes < 1024) return `${bytes} B`;
7220
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
7221
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MiB`;
7222
+ return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GiB`;
7223
+ }
7224
+ function StorageSettingsTab() {
7225
+ const [stats, setStats] = reactExports.useState(null);
7226
+ const [error, setError] = reactExports.useState(null);
7227
+ const [loading, setLoading] = reactExports.useState(false);
7228
+ const refresh = reactExports.useCallback(async () => {
7229
+ setLoading(true);
7230
+ setError(null);
7231
+ try {
7232
+ const response = await fetch("/api/logs?stats=1");
7233
+ if (!response.ok) {
7234
+ setError(`Failed to load storage stats: HTTP ${String(response.status)}`);
7235
+ return;
7236
+ }
7237
+ const data = await response.json();
7238
+ const parsed = LogStorageStatsSchema.safeParse(data);
7239
+ if (!parsed.success) {
7240
+ setError("Storage stats response was not valid.");
7241
+ return;
7242
+ }
7243
+ setStats(parsed.data);
7244
+ } catch (err) {
7245
+ setError(err instanceof Error ? err.message : String(err));
7246
+ } finally {
7247
+ setLoading(false);
7248
+ }
7249
+ }, []);
7250
+ reactExports.useEffect(() => {
7251
+ void refresh();
7252
+ }, [refresh]);
7253
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
7254
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
7255
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
7256
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold", children: "Log storage" }),
7257
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Inspect local log and streaming chunk footprint before exporting or clearing sessions." })
7258
+ ] }),
7259
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void refresh(), children: loading ? "Refreshing..." : "Refresh" })
7260
+ ] }),
7261
+ stats !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2 text-xs", children: [
7262
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
7263
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "In-memory logs" }),
7264
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 font-mono text-muted-foreground", children: [
7265
+ stats.memoryCount.toLocaleString(),
7266
+ " loaded"
7267
+ ] })
7268
+ ] }),
7269
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
7270
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "Log files" }),
7271
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 break-all font-mono text-muted-foreground", children: stats.logDir }),
7272
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 font-mono text-muted-foreground", children: [
7273
+ stats.logFileCount.toLocaleString(),
7274
+ " files / ",
7275
+ formatBytes(stats.logBytes)
7276
+ ] })
7277
+ ] }),
7278
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2", children: [
7279
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "Streaming chunks" }),
7280
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 break-all font-mono text-muted-foreground", children: stats.chunkDir }),
7281
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 font-mono text-muted-foreground", children: [
7282
+ stats.chunkFileCount.toLocaleString(),
7283
+ " files / ",
7284
+ formatBytes(stats.chunkBytes)
7285
+ ] })
7286
+ ] })
7287
+ ] }),
7288
+ error !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: error })
7289
+ ] });
7290
+ }
7141
7291
  function CopyableSetupValue({
7142
7292
  id,
7143
7293
  label,
@@ -7300,7 +7450,8 @@ function ProxySettingsTab() {
7300
7450
  "agent-inspector --mode ",
7301
7451
  alternateCaptureMode
7302
7452
  ] }),
7303
- " to change it."
7453
+ " to change it.",
7454
+ captureMode === "simple" ? " Simple mode keeps replay, parsed requests, responses, timing, tools, and token usage while skipping raw headers, raw response retention, and detailed SSE chunk retention." : " Full mode retains raw headers, raw responses, and SSE chunks for diagnostics; use simple mode for everyday lower-overhead capture."
7304
7455
  ] })
7305
7456
  ] }),
7306
7457
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
@@ -7330,7 +7481,7 @@ function ProxySettingsTab() {
7330
7481
  className: "size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
7331
7482
  }
7332
7483
  ),
7333
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: isLoading ? "Loading" : strip ? "Stripping enabled" : "Stripping disabled" })
7484
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: isLoading ? "Loading..." : strip ? "Stripping enabled" : "Stripping disabled" })
7334
7485
  ] }),
7335
7486
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
7336
7487
  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "slow-response-threshold", className: "text-sm font-semibold", children: "Slow response threshold" }),
@@ -7413,6 +7564,107 @@ function compareField(previous, current) {
7413
7564
  if (current < previous) return { direction: "down", delta: previous - current };
7414
7565
  return null;
7415
7566
  }
7567
+ const VIRTUALIZE_GROUP_THRESHOLD = 30;
7568
+ const ESTIMATED_GROUP_HEIGHT = 112;
7569
+ const VIRTUAL_OVERSCAN = 6;
7570
+ function shouldVirtualizeConversationGroups(groupCount) {
7571
+ return groupCount > VIRTUALIZE_GROUP_THRESHOLD;
7572
+ }
7573
+ function ConversationGroupList({
7574
+ groups,
7575
+ standalone,
7576
+ ...groupProps
7577
+ }) {
7578
+ if (!shouldVirtualizeConversationGroups(groups.length)) {
7579
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: groups.map((group) => /* @__PURE__ */ jsxRuntimeExports.jsx(ConversationGroup, { group, standalone, ...groupProps }, group.id)) });
7580
+ }
7581
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(VirtualizedConversationGroupList, { groups, standalone, ...groupProps });
7582
+ }
7583
+ function VirtualizedConversationGroupList({
7584
+ groups,
7585
+ standalone,
7586
+ ...groupProps
7587
+ }) {
7588
+ const [expandedByGroupId, setExpandedByGroupId] = reactExports.useState(
7589
+ () => /* @__PURE__ */ new Map()
7590
+ );
7591
+ const virtualizer = useWindowVirtualizer({
7592
+ count: groups.length,
7593
+ estimateSize: () => ESTIMATED_GROUP_HEIGHT,
7594
+ overscan: VIRTUAL_OVERSCAN,
7595
+ getItemKey: (index) => groups[index]?.id ?? index
7596
+ });
7597
+ const setGroupExpanded = reactExports.useCallback((groupId, expanded) => {
7598
+ setExpandedByGroupId((previous) => {
7599
+ const next = new Map(previous);
7600
+ if (expanded) {
7601
+ next.set(groupId, true);
7602
+ } else {
7603
+ next.delete(groupId);
7604
+ }
7605
+ return next;
7606
+ });
7607
+ }, []);
7608
+ const indexByLogId = reactExports.useMemo(() => {
7609
+ const result = /* @__PURE__ */ new Map();
7610
+ for (let index = 0; index < groups.length; index++) {
7611
+ const group = groups[index];
7612
+ if (group === void 0) continue;
7613
+ for (const log of group.logs) {
7614
+ result.set(log.id, index);
7615
+ }
7616
+ }
7617
+ return result;
7618
+ }, [groups]);
7619
+ reactExports.useEffect(() => {
7620
+ const handleLogFocusRequest = (event) => {
7621
+ const request = readLogFocusRequest(event);
7622
+ if (request === null) return;
7623
+ const index = indexByLogId.get(request.logId);
7624
+ if (index === void 0) return;
7625
+ const group = groups[index];
7626
+ if (group === void 0) return;
7627
+ setGroupExpanded(group.id, true);
7628
+ virtualizer.scrollToIndex(index, { align: "center" });
7629
+ };
7630
+ window.addEventListener(LOG_FOCUS_REQUEST_EVENT, handleLogFocusRequest);
7631
+ return () => {
7632
+ window.removeEventListener(LOG_FOCUS_REQUEST_EVENT, handleLogFocusRequest);
7633
+ };
7634
+ }, [groups, indexByLogId, setGroupExpanded, virtualizer]);
7635
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
7636
+ "div",
7637
+ {
7638
+ className: "relative w-full",
7639
+ style: { height: `${virtualizer.getTotalSize()}px` },
7640
+ "data-virtualized-conversation-list": "true",
7641
+ children: virtualizer.getVirtualItems().map((virtualItem) => {
7642
+ const group = groups[virtualItem.index];
7643
+ if (group === void 0) return null;
7644
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
7645
+ "div",
7646
+ {
7647
+ "data-index": virtualItem.index,
7648
+ ref: virtualizer.measureElement,
7649
+ className: "absolute left-0 top-0 w-full",
7650
+ style: { transform: `translateY(${virtualItem.start}px)` },
7651
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
7652
+ ConversationGroup,
7653
+ {
7654
+ group,
7655
+ standalone,
7656
+ expanded: expandedByGroupId.get(group.id) ?? false,
7657
+ onExpandedChange: (expanded) => setGroupExpanded(group.id, expanded),
7658
+ ...groupProps
7659
+ }
7660
+ )
7661
+ },
7662
+ virtualItem.key
7663
+ );
7664
+ })
7665
+ }
7666
+ );
7667
+ }
7416
7668
  const NAV_ATTR = "data-nav-id";
7417
7669
  const NAV_ACTION_ATTR = "data-nav-action";
7418
7670
  function findNavItems(container) {
@@ -8434,7 +8686,7 @@ function buildSessionContextSummary(logs, providers = []) {
8434
8686
  }
8435
8687
  function truncateSessionId(id) {
8436
8688
  if (id.length <= 30) return id;
8437
- return id.slice(0, 12) + "…" + id.slice(-12);
8689
+ return `${id.slice(0, 12)}...${id.slice(-12)}`;
8438
8690
  }
8439
8691
  function computeTokenSummary(logs) {
8440
8692
  let totalIn = 0;
@@ -8939,7 +9191,7 @@ function ProxyViewer({
8939
9191
  }) {
8940
9192
  const { totalIn, totalOut } = reactExports.useMemo(() => computeTokenSummary(logs), [logs]);
8941
9193
  const { providers } = useProviders();
8942
- const [exporting, setExporting] = reactExports.useState(false);
9194
+ const [exporting, setExporting] = reactExports.useState(null);
8943
9195
  const [comparePair, setComparePair] = reactExports.useState(null);
8944
9196
  const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
8945
9197
  "hidden"
@@ -8966,14 +9218,17 @@ function ProxyViewer({
8966
9218
  const requestLabel = logs.length === 1 ? "1 req" : `${logs.length} req`;
8967
9219
  document.title = `${truncateSessionId(pinnedSessionId)} - ${requestLabel} - Agent Inspector`;
8968
9220
  }, [logs.length, pinnedSessionId]);
8969
- const handleExport = reactExports.useCallback(async () => {
8970
- setExporting(true);
8971
- try {
8972
- await exportLogsAsZip(logs);
8973
- } finally {
8974
- setExporting(false);
8975
- }
8976
- }, [logs]);
9221
+ const handleExport = reactExports.useCallback(
9222
+ async (mode) => {
9223
+ setExporting(mode);
9224
+ try {
9225
+ await exportLogsAsZip(logs, mode);
9226
+ } finally {
9227
+ setExporting(null);
9228
+ }
9229
+ },
9230
+ [logs]
9231
+ );
8977
9232
  reactExports.useEffect(() => {
8978
9233
  setComparePair(null);
8979
9234
  }, [selectedSession, selectedModel]);
@@ -9114,24 +9369,37 @@ function ProxyViewer({
9114
9369
  logs.length,
9115
9370
  " request",
9116
9371
  logs.length !== 1 ? "s" : "",
9117
- totalIn > 0 || totalOut > 0 ? ` · ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out` : ""
9372
+ totalIn > 0 || totalOut > 0 ? ` - ${formatTokens(totalIn)} in / ${formatTokens(totalOut)} out` : ""
9118
9373
  ] }),
9119
9374
  logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
9120
9375
  "button",
9121
9376
  {
9122
9377
  type: "button",
9123
9378
  onClick: () => {
9124
- void handleExport();
9379
+ void handleExport("redacted");
9125
9380
  },
9126
- disabled: exporting,
9381
+ disabled: exporting !== null,
9127
9382
  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",
9128
- title: "Export all logs as JSON ZIP",
9129
- children: exporting ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
9383
+ title: "Export redacted logs as JSON ZIP",
9384
+ children: exporting === "redacted" ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Exporting..." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
9130
9385
  /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3.5" }),
9131
9386
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Export" })
9132
9387
  ] })
9133
9388
  }
9134
9389
  ),
9390
+ logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
9391
+ "button",
9392
+ {
9393
+ type: "button",
9394
+ onClick: () => {
9395
+ void handleExport("raw");
9396
+ },
9397
+ disabled: exporting !== null,
9398
+ className: "h-8 px-2 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed rounded-md hover:bg-muted",
9399
+ title: "Export raw logs without redaction",
9400
+ children: exporting === "raw" ? "Exporting..." : "Raw"
9401
+ }
9402
+ ),
9135
9403
  /* @__PURE__ */ jsxRuntimeExports.jsx(
9136
9404
  "button",
9137
9405
  {
@@ -9163,17 +9431,20 @@ function ProxyViewer({
9163
9431
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
9164
9432
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "No requests captured yet." }),
9165
9433
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: "Route AI coding tools through the proxy:" }),
9166
- /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "LLM_BASE_URL=http://localhost:25947/proxy <your-tool>" })
9434
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
9435
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "ANTHROPIC_BASE_URL=http://localhost:25947/proxy <your-tool>" }),
9436
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableCommand, { command: "OPENAI_BASE_URL=http://localhost:25947/proxy <your-tool>" })
9437
+ ] })
9167
9438
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
9168
9439
  "div",
9169
9440
  {
9170
9441
  ref: logListWrapperRef,
9171
9442
  tabIndex: 0,
9172
9443
  className: "flex flex-col gap-2 focus:outline-none",
9173
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: logListRef, children: groups.map((group) => /* @__PURE__ */ jsxRuntimeExports.jsx(
9174
- ConversationGroup,
9444
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: logListRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
9445
+ ConversationGroupList,
9175
9446
  {
9176
- group,
9447
+ groups,
9177
9448
  viewMode,
9178
9449
  strip,
9179
9450
  slowResponseThresholdSeconds,
@@ -9184,9 +9455,8 @@ function ProxyViewer({
9184
9455
  standalone: groups.length === 1,
9185
9456
  hasPinnedSessionContext: hasSessionContext,
9186
9457
  timeDisplayFormat
9187
- },
9188
- group.id
9189
- )) })
9458
+ }
9459
+ ) })
9190
9460
  }
9191
9461
  ) }),
9192
9462
  comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyCompareDrawer, { left: comparePair[0], right: comparePair[1], onClose: closeCompare }) })
@@ -9348,6 +9618,10 @@ function ProxyViewerContainer({
9348
9618
  if (!hash.startsWith("#log-")) return;
9349
9619
  if (handledHashRef.current === hash) return;
9350
9620
  const targetId = hash.slice(1);
9621
+ const logId = Number(targetId.replace(/^log-/, ""));
9622
+ if (Number.isInteger(logId) && logId > 0) {
9623
+ dispatchLogFocusRequest({ logId, tab: "request" });
9624
+ }
9351
9625
  let cancelled = false;
9352
9626
  let attempts = 0;
9353
9627
  let highlightedTarget = null;
@@ -9474,6 +9748,7 @@ export {
9474
9748
  Badge as B,
9475
9749
  CONTEXT_USAGE_THRESHOLDS as C,
9476
9750
  Dialog as D,
9751
+ safeJsonValue as E,
9477
9752
  JsonViewerFromString as J,
9478
9753
  ProxyViewerContainer as P,
9479
9754
  ROLE_COLOR_CLASSES as R,
@@ -9489,20 +9764,20 @@ export {
9489
9764
  TabsList as h,
9490
9765
  TabsTrigger as i,
9491
9766
  TabsContent as j,
9492
- TooltipProvider as k,
9493
- Tooltip as l,
9494
- TooltipTrigger as m,
9495
- TooltipContent as n,
9496
- Button as o,
9497
- analyzeContextIntelligence as p,
9498
- formatContextWindowTokens as q,
9767
+ Button as k,
9768
+ TooltipProvider as l,
9769
+ Tooltip as m,
9770
+ TooltipTrigger as n,
9771
+ TooltipContent as o,
9772
+ dispatchLogFocusRequest as p,
9773
+ analyzeContextIntelligence as q,
9499
9774
  resolveLogFormat as r,
9500
- getStatusCategory as s,
9501
- Collapsible as t,
9775
+ formatContextWindowTokens as s,
9776
+ getStatusCategory as t,
9502
9777
  useProviders as u,
9503
- CollapsibleTrigger as v,
9504
- CollapsibleContent as w,
9505
- ScrollArea as x,
9506
- JsonViewer as y,
9507
- safeJsonValue as z
9778
+ Collapsible as v,
9779
+ CollapsibleTrigger as w,
9780
+ CollapsibleContent as x,
9781
+ ScrollArea as y,
9782
+ JsonViewer as z
9508
9783
  };