@tonyclaw/agent-inspector 3.0.8 → 3.0.9

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 (40) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-Bth_Ywyt.js → CompareDrawer-CJKL4LMm.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-DBUy29O-.js +106 -0
  4. package/.output/public/assets/{ReplayDialog-C2YYAuTe.js → ReplayDialog-BYanl-a_.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-8k9dAX2j.js → RequestAnatomy-DvPz1jqE.js} +1 -1
  6. package/.output/public/assets/{ResponseView-DEL6JcXm.js → ResponseView-sZnxp9GN.js} +2 -2
  7. package/.output/public/assets/{StreamingChunkSequence-DngmoR9j.js → StreamingChunkSequence-G-tiYiBd.js} +1 -1
  8. package/.output/public/assets/{_sessionId-4vk9RMZ5.js → _sessionId-_hDcsmXq.js} +1 -1
  9. package/.output/public/assets/agent-inspector-58K1_MsC.ico +0 -0
  10. package/.output/public/assets/index-DAPAWsAd.js +1 -0
  11. package/.output/public/assets/index-DspnLqUW.css +1 -0
  12. package/.output/public/assets/{index-DINLvnm9.js → index-SuOSQb2_.js} +1 -1
  13. package/.output/public/assets/{json-viewer-CH5dvS2Y.js → json-viewer-yQdhgjaw.js} +1 -1
  14. package/.output/public/assets/{main-GWkZn4xy.js → main-CgjcDxjR.js} +2 -2
  15. package/.output/server/_libs/radix-ui__react-dialog.mjs +2 -2
  16. package/.output/server/{_sessionId-EgsjdkN7.mjs → _sessionId-BGISf2En.mjs} +2 -2
  17. package/.output/server/_ssr/{CompareDrawer-CaM8FYuD.mjs → CompareDrawer-s-UF9gW3.mjs} +2 -2
  18. package/.output/server/_ssr/{ProxyViewerContainer-EJIogcGd.mjs → ProxyViewerContainer-C0Sbz9ED.mjs} +496 -229
  19. package/.output/server/_ssr/{ReplayDialog-BPpJ2-q8.mjs → ReplayDialog-DvS8gvJr.mjs} +3 -3
  20. package/.output/server/_ssr/{RequestAnatomy-DeQAWnZx.mjs → RequestAnatomy-BwhWglJL.mjs} +2 -2
  21. package/.output/server/_ssr/{ResponseView-Dshm8iQ7.mjs → ResponseView-wBVreqQf.mjs} +2 -2
  22. package/.output/server/_ssr/{StreamingChunkSequence-32yIU2hn.mjs → StreamingChunkSequence-Dr6eg-MJ.mjs} +2 -2
  23. package/.output/server/_ssr/{index-XRcx9blU.mjs → index-B98Wia1X.mjs} +2 -2
  24. package/.output/server/_ssr/index.mjs +2 -2
  25. package/.output/server/_ssr/{json-viewer-C0aX5rqC.mjs → json-viewer-D7L8y0FH.mjs} +2 -2
  26. package/.output/server/_ssr/{router-BI-Mvxz9.mjs → router-g9mo0nWT.mjs} +22 -28
  27. package/.output/server/{_tanstack-start-manifest_v-jKScklL_.mjs → _tanstack-start-manifest_v-CbGc-o50.mjs} +1 -1
  28. package/.output/server/index.mjs +74 -67
  29. package/package.json +1 -1
  30. package/src/components/ProxyViewer.tsx +194 -29
  31. package/src/components/ProxyViewerContainer.tsx +137 -3
  32. package/src/components/clients/ClientLogo.tsx +16 -1
  33. package/src/components/proxy-viewer/TurnGroup.tsx +0 -16
  34. package/src/components/proxy-viewer/log-formats/anthropic.ts +5 -5
  35. package/src/components/proxy-viewer/log-formats/openai.ts +7 -10
  36. package/src/components/proxy-viewer/requestTools.ts +5 -2
  37. package/src/routes/api/providers.$providerId.test.log.ts +28 -24
  38. package/.output/public/assets/ProxyViewerContainer-C73EU9Jq.js +0 -106
  39. package/.output/public/assets/index-DBEB1rHe.css +0 -1
  40. package/.output/public/assets/index-LPIGiUMP.js +0 -1
@@ -1,19 +1,19 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, p as packageJson, P as ProviderConfigSchema, i as apiFormatForPath, n as DeleteInspectorGroupsResponseSchema, o as GroupEvidenceExportResultSchema, q as DeleteInspectorGroupResponseSchema, l as AlertSummarySchema, m as AlertListResponseSchema, I as InspectorGroupsListResponseSchema, G as GroupEvidenceReadResponseSchema, z as createPendingProviderTestResults, B as ProviderTestResultsSchema, E as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, F as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, t as maskApiKey, u as PATH_V1_MESSAGES, v as PATH_V1_CHAT_COMPLETIONS, w as PATH_V1_RESPONSES, r as providerHasContextMetadata, f as parseOpenAIResponse, g as parseOpenAIResponsesResponse, O as OpenAIRequestSchema, h as OpenAIResponsesRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, H as resolveProviderContextWindow, j as getSessionPath, x as findProviderModelMetadata, y as previewUpstreamUrl, K as KnowledgeCandidateSchema, J as isPlainRecord, k as stripClaudeCodeBillingHeader, L as LogBodyChunkSchema } from "./router-BI-Mvxz9.mjs";
2
+ import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, p as packageJson, P as ProviderConfigSchema, i as apiFormatForPath, n as DeleteInspectorGroupsResponseSchema, o as GroupEvidenceExportResultSchema, q as DeleteInspectorGroupResponseSchema, l as AlertSummarySchema, m as AlertListResponseSchema, I as InspectorGroupsListResponseSchema, G as GroupEvidenceReadResponseSchema, z as createPendingProviderTestResults, B as ProviderTestResultsSchema, E as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, F as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, t as maskApiKey, u as PATH_V1_MESSAGES, v as PATH_V1_CHAT_COMPLETIONS, w as PATH_V1_RESPONSES, r as providerHasContextMetadata, f as parseOpenAIResponse, g as parseOpenAIResponsesResponse, O as OpenAIRequestSchema, h as OpenAIResponsesRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, H as resolveProviderContextWindow, j as getSessionPath, x as findProviderModelMetadata, y as previewUpstreamUrl, K as KnowledgeCandidateSchema, J as isPlainRecord, k as stripClaudeCodeBillingHeader, L as LogBodyChunkSchema } from "./router-g9mo0nWT.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
- import { R as Root, T as Trigger$1, C as Content, a as Close, b as Title, D as Description, P as Portal$2, O as Overlay } from "../_libs/radix-ui__react-dialog.mjs";
7
+ import { R as Root, C as Content, a as Close, T as Title, D as Description, P as Portal$1, O as Overlay, b as Trigger$1 } from "../_libs/radix-ui__react-dialog.mjs";
8
8
  import { c as cva } from "../_libs/class-variance-authority.mjs";
9
9
  import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
10
10
  import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
11
11
  import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
12
12
  import { T as TriangleAlert, C as CircleCheck, X, I as Info, a as ChevronDown, b as Check, R as RefreshCw, c as Trash2, S as Search, U as Upload, D as Download, F as FileBraces, P as Plus, A as ArrowLeft, d as ChevronUp, e as Copy, f as ChevronsLeft, g as ChevronLeft, h as ChevronRight, i as ChevronsRight, j as Clapperboard, k as Flag, l as Siren, m as Timer, G as Gauge, L as LoaderCircle, n as Layers, o as FlaskConical, p as Sparkles, q as Activity, B as Beaker, N as Network, r as Terminal, s as Settings, M as Monitor, t as Rocket, u as PackageCheck, v as Scan, w as CircleAlert, x as ArrowUpRight, y as ArrowDownRight, z as Cpu, E as FolderOpen, H as Bell, J as Clock3, K as ShieldAlert, O as EyeOff, Q as Eye, V as ExternalLink, W as Clock, Y as RotateCw, Z as Pencil, _ as MessageSquare, $ as Zap, a0 as Wrench, a1 as Brain, a2 as Minus, a3 as CircleCheckBig, a4 as CircleQuestionMark, a5 as Server, a6 as Lock, a7 as Wifi, a8 as WifiOff, a9 as CircleX, aa as ShieldCheck, ab as Save, ac as FileSearch, ad as CloudUpload, ae as OctagonAlert, af as Radio, ag as Globe, ah as FileTerminal, ai as ChevronsUp, aj as ChevronsDown, ak as FileDiff, al as History, am as RotateCcw, an as GitCompareArrows, ao as ArrowUp, ap as ArrowDown, aq as Ellipsis, ar as CodeXml, as as Blocks, at as MousePointerClick, au as FileText, av as Rows3, aw as Columns2 } from "../_libs/lucide-react.mjs";
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";
13
+ import { u as union, d as object, a as array, l as literal, n as number, c as boolean, b as string, _ as _enum } from "../_libs/zod.mjs";
14
14
  import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
15
15
  import { R as Root2$1, L as List, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
16
- import { P as Provider, R as Root3, T as Trigger$3, a as Portal$1, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
16
+ import { P as Provider, R as Root3, T as Trigger$3, a as Portal$2, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
17
17
  import { R as Root$1, C as CollapsibleContent$1, a as CollapsibleTrigger$1 } from "../_libs/radix-ui__react-collapsible.mjs";
18
18
  import { R as Root$2, V as Viewport$1, C as Corner, S as ScrollAreaScrollbar, a as ScrollAreaThumb } from "../_libs/radix-ui__react-scroll-area.mjs";
19
19
  const ApiErrorSchema = object({
@@ -738,7 +738,7 @@ function DialogTrigger({
738
738
  function DialogPortal({
739
739
  ...props
740
740
  }) {
741
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { "data-slot": "dialog-portal", ...props });
741
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { "data-slot": "dialog-portal", ...props });
742
742
  }
743
743
  function DialogOverlay({
744
744
  className,
@@ -892,7 +892,9 @@ const ClaudeCodeLogoSvg = "data:image/svg+xml,%3csvg%20height='1em'%20style='fle
892
892
  const CodexLogoSvg = "data:image/svg+xml,%3csvg%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eCodex%3c/title%3e%3cpath%20d='M19.503%200H4.496A4.496%204.496%200%20000%204.496v15.007A4.496%204.496%200%20004.496%2024h15.007A4.496%204.496%200%200024%2019.503V4.496A4.496%204.496%200%200019.503%200z'%20fill='%23fff'%3e%3c/path%3e%3cpath%20d='M9.064%203.344a4.578%204.578%200%20012.285-.312c1%20.115%201.891.54%202.673%201.275.01.01.024.017.037.021a.09.09%200%2000.043%200%204.55%204.55%200%20013.046.275l.047.022.116.057a4.581%204.581%200%20012.188%202.399c.209.51.313%201.041.315%201.595a4.24%204.24%200%2001-.134%201.223.123.123%200%2000.03.115c.594.607.988%201.33%201.183%202.17.289%201.425-.007%202.71-.887%203.854l-.136.166a4.548%204.548%200%2001-2.201%201.388.123.123%200%2000-.081.076c-.191.551-.383%201.023-.74%201.494-.9%201.187-2.222%201.846-3.711%201.838-1.187-.006-2.239-.44-3.157-1.302a.107.107%200%2000-.105-.024c-.388.125-.78.143-1.204.138a4.441%204.441%200%2001-1.945-.466%204.544%204.544%200%2001-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81%205.81%200%2001-.37-.961%204.582%204.582%200%2001-.014-2.298.124.124%200%2000.006-.056.085.085%200%2000-.027-.048%204.467%204.467%200%2001-1.034-1.651%203.896%203.896%200%2001-.251-1.192%205.189%205.189%200%2001.141-1.6c.337-1.112.982-1.985%201.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098%200%2000.065-.066%204.51%204.51%200%2001.829-1.615%204.535%204.535%200%20011.837-1.388zm3.482%2010.565a.637.637%200%20000%201.272h3.636a.637.637%200%20100-1.272h-3.636zM8.462%209.23a.637.637%200%2000-1.106.631l1.272%202.224-1.266%202.136a.636.636%200%20101.095.649l1.454-2.455a.636.636%200%2000.005-.64L8.462%209.23z'%20fill='url(%23lobe-icons-codex-_R_0_)'%3e%3c/path%3e%3cdefs%3e%3clinearGradient%20gradientUnits='userSpaceOnUse'%20id='lobe-icons-codex-_R_0_'%20x1='12'%20x2='12'%20y1='3'%20y2='21'%3e%3cstop%20stop-color='%23B1A7FF'%3e%3c/stop%3e%3cstop%20offset='.5'%20stop-color='%237A9DFF'%3e%3c/stop%3e%3cstop%20offset='1'%20stop-color='%233941FF'%3e%3c/stop%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e";
893
893
  const OpenCodeLogoSvg = "data:image/svg+xml,%3csvg%20fill='%237dd3fc'%20fill-rule='evenodd'%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eOpenCode%3c/title%3e%3cpath%20d='M16%206H8v12h8V6zm4%2016H4V2h16v20z'%3e%3c/path%3e%3c/svg%3e";
894
894
  const MiMoCodeLogoSvg = "data:image/svg+xml,%3csvg%20fill='%23ff6900'%20fill-rule='evenodd'%20height='1em'%20style='flex:none;line-height:1'%20viewBox='0%200%2024%2024'%20width='1em'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eMiMo%20Code%3c/title%3e%3cpath%20d='M.958%2015.936a.459.459%200%2001.459.44v2.729a.46.46%200%2001-.918%200v-2.729a.459.459%200%2001.459-.44zm4.814-2.035a.46.46%200%2001.553.45v4.754a.458.458%200%2011-.918%200V15.48L3.74%2017.202a.462.462%200%2001-.655.016.462.462%200%2001-.065-.082L.628%2014.67a.459.459%200%2001.658-.637l2.124%202.187%202.127-2.188a.46.46%200%2001.235-.13zm2.068.004a.46.46%200%2001.458.445v4.755a.46.46%200%2001-.458.458.459.459%200%2001-.458-.458V14.35a.459.459%200%2001.458-.445zm1.973%202.014a.46.46%200%2001.46.457v2.729a.46.46%200%2001-.784.324.46.46%200%2001-.134-.324v-2.729a.46.46%200%2001.458-.458zm.002-2.045a.458.458%200%2001.328.157l2.127%202.19%202.125-2.19a.459.459%200%2001.784.318v4.756a.46.46%200%2001-.455.458.46.46%200%2001-.458-.458V15.48l-1.667%201.723a.46.46%200%2001-.65.008l-.005-.005c0-.002-.002-.002-.004-.003l-2.455-2.534a.46.46%200%2001-.008-.667.461.461%200%2001.338-.128zm6.797%201.206a.46.46%200%2001.53.651A1.966%201.966%200%200019.81%2018.4a.462.462%200%2001.623.18.46.46%200%2001-.181.624%202.863%202.863%200%2001-1.38.353l-.142-.004a2.88%202.88%200%2001-2.393-4.263.461.461%200%2001.274-.21zm.864-.931a2.884%202.884%200%20013.915%203.914.46.46%200%2001-.402.24l-.057-.004a.458.458%200%2001-.164-.055.46.46%200%2001-.182-.622%201.967%201.967%200%2000-2.669-2.67.459.459%200%2011-.441-.803zM9.59%206.368c1.481%200%201.696%201.202%201.696%201.654v2.648h-.917v-.432c-.26.346-.792.535-1.36.535-.133%200-1.289-.03-1.384-1.136-.082-.932.675-1.61%202.053-1.61h.691c0-.563-.367-.886-.983-.886-.44.013-.864.174-1.2.458l-.36-.664c.484-.379%201.012-.567%201.764-.567zm4.427.1c1.263%200%202.082.97%202.083%202.15%200%201.181-.824%202.154-2.083%202.154-1.26%200-2.084-.972-2.084-2.152%200-1.18.82-2.153%202.084-2.153zm6.801.015c.68%200%201.202.465%201.197%201.548v2.642H21.1V8.29c0-.312-.002-.98-.63-.98s-.628.667-.628.838v2.524h-.89V8.148c0-.17-.001-.838-.63-.838-.628%200-.628.668-.628.98v2.383h-.917v-4.03h.917V7a1.22%201.22%200%2001.947-.516c.398%200%20.76.193.982.686a1.321%201.321%200%20011.195-.686zm-18.093.872l1.457-1.772H5.32L3.311%208.07l2.14%202.602H4.24L2.725%208.796%201.21%2010.672H0L2.138%208.07.13%205.583h1.138l1.458%201.772zm4.149%203.317h-.916V6.644h.916v4.028zm16.99%200h-.916V6.644h.916v4.028zM9.925%208.71c-1.055%200-1.359.412-1.326.742.032.329.324.537.757.537a1.013%201.013%200%20001.014-.968l.002-.31h-.447zM14.018%207.3c-.663%200-1.184.487-1.184%201.32%200%20.832.52%201.32%201.184%201.32.662%200%201.182-.49%201.182-1.32%200-.832-.52-1.32-1.182-1.32zM6.417%205.001a.568.568%200%2001.587.582.588.588%200%2001-1.175%200A.57.57%200%20016.417%205zm16.991%200a.57.57%200%2001.592.582.588.588%200%2001-1.174%200%20.57.57%200%2001.357-.542.572.572%200%2001.225-.04z'%3e%3c/path%3e%3c/svg%3e";
895
+ const AgentInspectorLogo = "/assets/agent-inspector-58K1_MsC.ico";
895
896
  const CLIENT_LABELS = {
897
+ "agent-inspector": "Inspector",
896
898
  codex: "Codex",
897
899
  opencode: "OpenCode",
898
900
  "mimo-code": "MiMo Code",
@@ -913,6 +915,9 @@ function detectClientApp(input) {
913
915
  normalize(input.conversationId),
914
916
  normalize(input.clientProjectFolder)
915
917
  ].join(" ");
918
+ if (matchesAny(haystack, ["agent-inspector", "agent inspector", "provider-test"])) {
919
+ return "agent-inspector";
920
+ }
916
921
  if (matchesAny(haystack, ["mimocode", "mimo-code", "mimo code"])) return "mimo-code";
917
922
  if (matchesAny(haystack, ["opencode", "open-code", "open code"])) return "opencode";
918
923
  if (matchesAny(haystack, ["claude-code", "claude code", "claudecode"])) return "claude-code";
@@ -923,6 +928,7 @@ function detectClientApp(input) {
923
928
  }
924
929
  function clientAppLabel(client) {
925
930
  switch (client) {
931
+ case "agent-inspector":
926
932
  case "codex":
927
933
  case "opencode":
928
934
  case "mimo-code":
@@ -933,18 +939,21 @@ function clientAppLabel(client) {
933
939
  }
934
940
  }
935
941
  const CLIENT_LOGOS = {
942
+ "agent-inspector": AgentInspectorLogo,
936
943
  codex: CodexLogoSvg,
937
944
  opencode: OpenCodeLogoSvg,
938
945
  "mimo-code": MiMoCodeLogoSvg,
939
946
  "claude-code": ClaudeCodeLogoSvg
940
947
  };
941
948
  const CLIENT_LOGO_FRAMES = {
949
+ "agent-inspector": "border-orange-200/25 bg-orange-300/[0.12]",
942
950
  codex: "border-cyan-200/20 bg-cyan-300/[0.08]",
943
951
  opencode: "border-sky-200/25 bg-sky-300/[0.12]",
944
952
  "mimo-code": "border-orange-200/25 bg-orange-400/[0.12]",
945
953
  "claude-code": "border-amber-100/20 bg-amber-300/[0.09]"
946
954
  };
947
955
  const CLIENT_LOGO_IMAGES = {
956
+ "agent-inspector": "p-0.5 drop-shadow-[0_0_8px_rgba(251,146,60,0.35)]",
948
957
  codex: "p-0.5",
949
958
  opencode: "p-1 drop-shadow-[0_0_8px_rgba(125,211,252,0.35)]",
950
959
  "mimo-code": "p-0.5 drop-shadow-[0_0_8px_rgba(255,105,0,0.35)]",
@@ -1089,7 +1098,7 @@ function TooltipContent({
1089
1098
  children,
1090
1099
  ...props
1091
1100
  }) {
1092
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1101
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$2, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
1093
1102
  Content2$1,
1094
1103
  {
1095
1104
  "data-slot": "tooltip-content",
@@ -1164,6 +1173,171 @@ function countCharacters(text) {
1164
1173
  });
1165
1174
  return n;
1166
1175
  }
1176
+ const CATEGORY_ORDER = [
1177
+ "file",
1178
+ "shell",
1179
+ "browser",
1180
+ "web",
1181
+ "mcp",
1182
+ "code",
1183
+ "other"
1184
+ ];
1185
+ function firstTextSlice(value) {
1186
+ const normalized = value.replace(/\s+/g, " ").trim();
1187
+ if (normalized.length <= 120) return normalized;
1188
+ return `${normalized.slice(0, 119)}...`;
1189
+ }
1190
+ function previewDescription(description) {
1191
+ if (description === null) return null;
1192
+ const normalized = description.replace(/\s+/g, " ").trim();
1193
+ if (normalized.length === 0) return null;
1194
+ const sentenceEnd = normalized.search(/[.!?。!?]/);
1195
+ if (sentenceEnd >= 24) return firstTextSlice(normalized.slice(0, sentenceEnd + 1));
1196
+ return firstTextSlice(normalized);
1197
+ }
1198
+ function lowerHaystack(name, description) {
1199
+ return `${name} ${description ?? ""}`.toLowerCase();
1200
+ }
1201
+ function includesAny(value, needles) {
1202
+ return needles.some((needle) => value.includes(needle));
1203
+ }
1204
+ function categorizeTool(name, description) {
1205
+ const haystack = lowerHaystack(name, description);
1206
+ if (name.startsWith("mcp__") || name.startsWith("inspector_") || includesAny(haystack, [" mcp", "model context protocol"])) {
1207
+ return "mcp";
1208
+ }
1209
+ if (includesAny(haystack, ["bash", "shell", "terminal", "command", "powershell", "exec", "process"])) {
1210
+ return "shell";
1211
+ }
1212
+ if (includesAny(haystack, [
1213
+ "browser",
1214
+ "playwright",
1215
+ "screenshot",
1216
+ "click",
1217
+ "navigate",
1218
+ "page",
1219
+ "tab"
1220
+ ])) {
1221
+ return "browser";
1222
+ }
1223
+ if (includesAny(haystack, [
1224
+ "read",
1225
+ "write",
1226
+ "edit",
1227
+ "file",
1228
+ "glob",
1229
+ "grep",
1230
+ "patch",
1231
+ "filesystem",
1232
+ "directory"
1233
+ ])) {
1234
+ return "file";
1235
+ }
1236
+ if (includesAny(haystack, ["web", "search", "http", "url", "fetch"])) {
1237
+ return "web";
1238
+ }
1239
+ if (includesAny(haystack, ["code", "typescript", "javascript", "python", "repl"])) {
1240
+ return "code";
1241
+ }
1242
+ return "other";
1243
+ }
1244
+ function parameterNames(schema) {
1245
+ const properties = safeGetOwnProperty(schema, "properties");
1246
+ if (properties === null || typeof properties !== "object" || Array.isArray(properties)) {
1247
+ return [];
1248
+ }
1249
+ return Object.keys(properties).sort((a, b) => a.localeCompare(b));
1250
+ }
1251
+ function requiredParameterNames(schema) {
1252
+ const required = safeGetOwnProperty(schema, "required");
1253
+ if (!Array.isArray(required)) return [];
1254
+ const names = [];
1255
+ for (const item of required) {
1256
+ if (typeof item === "string" && item.length > 0) names.push(item);
1257
+ }
1258
+ return names.sort((a, b) => a.localeCompare(b));
1259
+ }
1260
+ function parseAnthropicTool(tool) {
1261
+ const name = safeGetOwnProperty(tool, "name");
1262
+ if (typeof name !== "string" || name.length === 0) return null;
1263
+ const description = safeGetOwnProperty(tool, "description");
1264
+ const schema = safeGetOwnProperty(tool, "input_schema") ?? null;
1265
+ const normalizedDescription = typeof description === "string" ? description : null;
1266
+ return {
1267
+ name,
1268
+ description: normalizedDescription,
1269
+ descriptionPreview: previewDescription(normalizedDescription),
1270
+ category: categorizeTool(name, normalizedDescription),
1271
+ parameterCount: parameterNames(schema).length,
1272
+ requiredParameters: requiredParameterNames(schema),
1273
+ schema
1274
+ };
1275
+ }
1276
+ function parseOpenAITool(tool) {
1277
+ const fn = safeGetOwnProperty(tool, "function");
1278
+ const toolType = safeGetOwnProperty(tool, "type");
1279
+ if (fn === void 0 && typeof toolType !== "string") return null;
1280
+ const name = safeGetOwnProperty(fn, "name") ?? safeGetOwnProperty(tool, "name") ?? (typeof toolType === "string" ? toolType : void 0);
1281
+ if (typeof name !== "string" || name.length === 0) return null;
1282
+ const description = safeGetOwnProperty(fn, "description") ?? safeGetOwnProperty(tool, "description");
1283
+ const schema = safeGetOwnProperty(fn, "parameters") ?? safeGetOwnProperty(tool, "parameters") ?? null;
1284
+ const normalizedDescription = typeof description === "string" ? description : null;
1285
+ return {
1286
+ name,
1287
+ description: normalizedDescription,
1288
+ descriptionPreview: previewDescription(normalizedDescription),
1289
+ category: categorizeTool(name, normalizedDescription),
1290
+ parameterCount: parameterNames(schema).length,
1291
+ requiredParameters: requiredParameterNames(schema),
1292
+ schema
1293
+ };
1294
+ }
1295
+ function parseTool(tool) {
1296
+ const openAITool = parseOpenAITool(tool);
1297
+ if (openAITool !== null) return openAITool;
1298
+ return parseAnthropicTool(tool);
1299
+ }
1300
+ function formatToolChoice(choice) {
1301
+ if (choice === void 0 || choice === null) return null;
1302
+ if (typeof choice === "string") return choice;
1303
+ const type = safeGetOwnProperty(choice, "type");
1304
+ const name = safeGetOwnProperty(choice, "name");
1305
+ const fnName = safeGetOwnProperty(safeGetOwnProperty(choice, "function"), "name");
1306
+ if (typeof type === "string" && typeof fnName === "string" && fnName.length > 0) {
1307
+ return `${type}: ${fnName}`;
1308
+ }
1309
+ if (typeof type === "string" && typeof name === "string" && name.length > 0) {
1310
+ return `${type}: ${name}`;
1311
+ }
1312
+ if (typeof type === "string") return type;
1313
+ const encoded = JSON.stringify(choice);
1314
+ return encoded === void 0 ? null : firstTextSlice(encoded);
1315
+ }
1316
+ function summarizeCategories(tools) {
1317
+ const counts = /* @__PURE__ */ new Map();
1318
+ for (const tool of tools) {
1319
+ counts.set(tool.category, (counts.get(tool.category) ?? 0) + 1);
1320
+ }
1321
+ return CATEGORY_ORDER.flatMap((category) => {
1322
+ const count = counts.get(category) ?? 0;
1323
+ return count > 0 ? [{ category, count }] : [];
1324
+ });
1325
+ }
1326
+ function parseRequestTools(parsed) {
1327
+ const rawTools = safeGetOwnProperty(parsed, "tools");
1328
+ if (!Array.isArray(rawTools) || rawTools.length === 0) return null;
1329
+ const tools = [];
1330
+ for (const rawTool of rawTools) {
1331
+ const tool = parseTool(rawTool);
1332
+ if (tool !== null) tools.push(tool);
1333
+ }
1334
+ if (tools.length === 0) return null;
1335
+ return {
1336
+ tools,
1337
+ toolChoiceLabel: formatToolChoice(safeGetOwnProperty(parsed, "tool_choice")),
1338
+ categories: summarizeCategories(tools)
1339
+ };
1340
+ }
1167
1341
  function emptyRequestAnalysis(rawBody) {
1168
1342
  return {
1169
1343
  parsed: null,
@@ -1259,13 +1433,15 @@ const anthropicLogFormatAdapter = {
1259
1433
  analyzeRequest(rawBody) {
1260
1434
  if (rawBody === null) return emptyRequestAnalysis(rawBody);
1261
1435
  try {
1262
- const result = AnthropicRequestSchema.safeParse(JSON.parse(rawBody));
1436
+ const parsedBody = JSON.parse(rawBody);
1437
+ const toolCount = parseRequestTools(parsedBody)?.tools.length ?? null;
1438
+ const result = AnthropicRequestSchema.safeParse(parsedBody);
1263
1439
  if (!result.success) return emptyRequestAnalysis(rawBody);
1264
1440
  return {
1265
1441
  parsed: result.data,
1266
1442
  comparisonValue: result.data,
1267
1443
  messageCount: result.data.messages.length,
1268
- toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
1444
+ toolCount
1269
1445
  };
1270
1446
  } catch {
1271
1447
  return emptyRequestAnalysis(rawBody);
@@ -1416,22 +1592,24 @@ const openAILogFormatAdapter = {
1416
1592
  analyzeRequest(rawBody) {
1417
1593
  if (rawBody === null) return emptyRequestAnalysis(rawBody);
1418
1594
  try {
1419
- const result = OpenAIRequestSchema.safeParse(JSON.parse(rawBody));
1595
+ const parsedBody = JSON.parse(rawBody);
1596
+ const toolCount = parseRequestTools(parsedBody)?.tools.length ?? null;
1597
+ const result = OpenAIRequestSchema.safeParse(parsedBody);
1420
1598
  if (!result.success) {
1421
- const responsesResult = OpenAIResponsesRequestSchema.safeParse(JSON.parse(rawBody));
1599
+ const responsesResult = OpenAIResponsesRequestSchema.safeParse(parsedBody);
1422
1600
  if (!responsesResult.success) return emptyRequestAnalysis(rawBody);
1423
1601
  return {
1424
1602
  parsed: responsesResult.data,
1425
1603
  comparisonValue: responsesResult.data,
1426
1604
  messageCount: countResponsesInput(responsesResult.data.input),
1427
- toolCount: responsesResult.data.tools !== void 0 && responsesResult.data.tools.length > 0 ? responsesResult.data.tools.length : null
1605
+ toolCount
1428
1606
  };
1429
1607
  }
1430
1608
  return {
1431
1609
  parsed: result.data,
1432
1610
  comparisonValue: result.data,
1433
1611
  messageCount: result.data.messages.length,
1434
- toolCount: result.data.tools !== void 0 && result.data.tools.length > 0 ? result.data.tools.length : null
1612
+ toolCount
1435
1613
  };
1436
1614
  } catch {
1437
1615
  return emptyRequestAnalysis(rawBody);
@@ -2368,27 +2546,27 @@ function useCopyFeedback(text) {
2368
2546
  return { copied, copy };
2369
2547
  }
2370
2548
  const LazyCompareDrawer = reactExports.lazy(
2371
- () => import("./CompareDrawer-CaM8FYuD.mjs").then((m) => ({ default: m.CompareDrawer }))
2549
+ () => import("./CompareDrawer-s-UF9gW3.mjs").then((m) => ({ default: m.CompareDrawer }))
2372
2550
  );
2373
2551
  const LazyReplayDialog = reactExports.lazy(
2374
- () => import("./ReplayDialog-BPpJ2-q8.mjs").then((m) => ({ default: m.ReplayDialog }))
2552
+ () => import("./ReplayDialog-DvS8gvJr.mjs").then((m) => ({ default: m.ReplayDialog }))
2375
2553
  );
2376
2554
  const LazyRequestAnatomy = reactExports.lazy(
2377
- () => import("./RequestAnatomy-DeQAWnZx.mjs").then((m) => ({ default: m.RequestAnatomy }))
2555
+ () => import("./RequestAnatomy-BwhWglJL.mjs").then((m) => ({ default: m.RequestAnatomy }))
2378
2556
  );
2379
2557
  const LazyResponseView = reactExports.lazy(
2380
- () => import("./ResponseView-Dshm8iQ7.mjs").then((m) => ({ default: m.ResponseView }))
2558
+ () => import("./ResponseView-wBVreqQf.mjs").then((m) => ({ default: m.ResponseView }))
2381
2559
  );
2382
2560
  const LazyStreamingChunkSequence = reactExports.lazy(
2383
- () => import("./StreamingChunkSequence-32yIU2hn.mjs").then((m) => ({
2561
+ () => import("./StreamingChunkSequence-Dr6eg-MJ.mjs").then((m) => ({
2384
2562
  default: m.StreamingChunkSequence
2385
2563
  }))
2386
2564
  );
2387
2565
  const LazyJsonViewer = reactExports.lazy(
2388
- () => import("./json-viewer-C0aX5rqC.mjs").then((m) => ({ default: m.JsonViewer }))
2566
+ () => import("./json-viewer-D7L8y0FH.mjs").then((m) => ({ default: m.JsonViewer }))
2389
2567
  );
2390
2568
  const LazyJsonViewerFromString = reactExports.lazy(
2391
- () => import("./json-viewer-C0aX5rqC.mjs").then((m) => ({ default: m.JsonViewerFromString }))
2569
+ () => import("./json-viewer-D7L8y0FH.mjs").then((m) => ({ default: m.JsonViewerFromString }))
2392
2570
  );
2393
2571
  const HIGHLIGHT_DURATION_MS = 1200;
2394
2572
  const MAX_HIGHLIGHT_ATTEMPTS = 12;
@@ -3535,171 +3713,6 @@ function shouldShowHeadersDiffButton(viewMode, hasRawHeaders) {
3535
3713
  function shouldShowRequestDiffButton(apiFormat, viewMode, strip, hasRawRequest) {
3536
3714
  return apiFormat === "anthropic" && viewMode === "full" && strip && hasRawRequest;
3537
3715
  }
3538
- const CATEGORY_ORDER = [
3539
- "file",
3540
- "shell",
3541
- "browser",
3542
- "web",
3543
- "mcp",
3544
- "code",
3545
- "other"
3546
- ];
3547
- function firstTextSlice(value) {
3548
- const normalized = value.replace(/\s+/g, " ").trim();
3549
- if (normalized.length <= 120) return normalized;
3550
- return `${normalized.slice(0, 119)}...`;
3551
- }
3552
- function previewDescription(description) {
3553
- if (description === null) return null;
3554
- const normalized = description.replace(/\s+/g, " ").trim();
3555
- if (normalized.length === 0) return null;
3556
- const sentenceEnd = normalized.search(/[.!?。!?]/);
3557
- if (sentenceEnd >= 24) return firstTextSlice(normalized.slice(0, sentenceEnd + 1));
3558
- return firstTextSlice(normalized);
3559
- }
3560
- function lowerHaystack(name, description) {
3561
- return `${name} ${description ?? ""}`.toLowerCase();
3562
- }
3563
- function includesAny(value, needles) {
3564
- return needles.some((needle) => value.includes(needle));
3565
- }
3566
- function categorizeTool(name, description) {
3567
- const haystack = lowerHaystack(name, description);
3568
- if (name.startsWith("mcp__") || name.startsWith("inspector_") || includesAny(haystack, [" mcp", "model context protocol"])) {
3569
- return "mcp";
3570
- }
3571
- if (includesAny(haystack, ["bash", "shell", "terminal", "command", "powershell", "exec", "process"])) {
3572
- return "shell";
3573
- }
3574
- if (includesAny(haystack, [
3575
- "browser",
3576
- "playwright",
3577
- "screenshot",
3578
- "click",
3579
- "navigate",
3580
- "page",
3581
- "tab"
3582
- ])) {
3583
- return "browser";
3584
- }
3585
- if (includesAny(haystack, [
3586
- "read",
3587
- "write",
3588
- "edit",
3589
- "file",
3590
- "glob",
3591
- "grep",
3592
- "patch",
3593
- "filesystem",
3594
- "directory"
3595
- ])) {
3596
- return "file";
3597
- }
3598
- if (includesAny(haystack, ["web", "search", "http", "url", "fetch"])) {
3599
- return "web";
3600
- }
3601
- if (includesAny(haystack, ["code", "typescript", "javascript", "python", "repl"])) {
3602
- return "code";
3603
- }
3604
- return "other";
3605
- }
3606
- function parameterNames(schema) {
3607
- const properties = safeGetOwnProperty(schema, "properties");
3608
- if (properties === null || typeof properties !== "object" || Array.isArray(properties)) {
3609
- return [];
3610
- }
3611
- return Object.keys(properties).sort((a, b) => a.localeCompare(b));
3612
- }
3613
- function requiredParameterNames(schema) {
3614
- const required = safeGetOwnProperty(schema, "required");
3615
- if (!Array.isArray(required)) return [];
3616
- const names = [];
3617
- for (const item of required) {
3618
- if (typeof item === "string" && item.length > 0) names.push(item);
3619
- }
3620
- return names.sort((a, b) => a.localeCompare(b));
3621
- }
3622
- function parseAnthropicTool(tool) {
3623
- const name = safeGetOwnProperty(tool, "name");
3624
- if (typeof name !== "string" || name.length === 0) return null;
3625
- const description = safeGetOwnProperty(tool, "description");
3626
- const schema = safeGetOwnProperty(tool, "input_schema") ?? null;
3627
- const normalizedDescription = typeof description === "string" ? description : null;
3628
- return {
3629
- name,
3630
- description: normalizedDescription,
3631
- descriptionPreview: previewDescription(normalizedDescription),
3632
- category: categorizeTool(name, normalizedDescription),
3633
- parameterCount: parameterNames(schema).length,
3634
- requiredParameters: requiredParameterNames(schema),
3635
- schema
3636
- };
3637
- }
3638
- function parseOpenAITool(tool) {
3639
- const fn = safeGetOwnProperty(tool, "function");
3640
- const toolType = safeGetOwnProperty(tool, "type");
3641
- if (fn === void 0 && toolType !== "function") return null;
3642
- const name = safeGetOwnProperty(fn, "name") ?? safeGetOwnProperty(tool, "name");
3643
- if (typeof name !== "string" || name.length === 0) return null;
3644
- const description = safeGetOwnProperty(fn, "description") ?? safeGetOwnProperty(tool, "description");
3645
- const schema = safeGetOwnProperty(fn, "parameters") ?? safeGetOwnProperty(tool, "parameters") ?? null;
3646
- const normalizedDescription = typeof description === "string" ? description : null;
3647
- return {
3648
- name,
3649
- description: normalizedDescription,
3650
- descriptionPreview: previewDescription(normalizedDescription),
3651
- category: categorizeTool(name, normalizedDescription),
3652
- parameterCount: parameterNames(schema).length,
3653
- requiredParameters: requiredParameterNames(schema),
3654
- schema
3655
- };
3656
- }
3657
- function parseTool(tool) {
3658
- const openAITool = parseOpenAITool(tool);
3659
- if (openAITool !== null) return openAITool;
3660
- return parseAnthropicTool(tool);
3661
- }
3662
- function formatToolChoice(choice) {
3663
- if (choice === void 0 || choice === null) return null;
3664
- if (typeof choice === "string") return choice;
3665
- const type = safeGetOwnProperty(choice, "type");
3666
- const name = safeGetOwnProperty(choice, "name");
3667
- const fnName = safeGetOwnProperty(safeGetOwnProperty(choice, "function"), "name");
3668
- if (typeof type === "string" && typeof fnName === "string" && fnName.length > 0) {
3669
- return `${type}: ${fnName}`;
3670
- }
3671
- if (typeof type === "string" && typeof name === "string" && name.length > 0) {
3672
- return `${type}: ${name}`;
3673
- }
3674
- if (typeof type === "string") return type;
3675
- const encoded = JSON.stringify(choice);
3676
- return encoded === void 0 ? null : firstTextSlice(encoded);
3677
- }
3678
- function summarizeCategories(tools) {
3679
- const counts = /* @__PURE__ */ new Map();
3680
- for (const tool of tools) {
3681
- counts.set(tool.category, (counts.get(tool.category) ?? 0) + 1);
3682
- }
3683
- return CATEGORY_ORDER.flatMap((category) => {
3684
- const count = counts.get(category) ?? 0;
3685
- return count > 0 ? [{ category, count }] : [];
3686
- });
3687
- }
3688
- function parseRequestTools(parsed) {
3689
- const rawTools = safeGetOwnProperty(parsed, "tools");
3690
- if (!Array.isArray(rawTools) || rawTools.length === 0) return null;
3691
- const tools = [];
3692
- for (const rawTool of rawTools) {
3693
- const tool = parseTool(rawTool);
3694
- if (tool !== null) tools.push(tool);
3695
- }
3696
- if (tools.length === 0) return null;
3697
- return {
3698
- tools,
3699
- toolChoiceLabel: formatToolChoice(safeGetOwnProperty(parsed, "tool_choice")),
3700
- categories: summarizeCategories(tools)
3701
- };
3702
- }
3703
3716
  function TabFallback() {
3704
3717
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1", "aria-hidden": "true" });
3705
3718
  }
@@ -5067,7 +5080,6 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
5067
5080
  }
5068
5081
  },
5069
5082
  children: [
5070
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }),
5071
5083
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-6 shrink-0 flex flex-col items-center pt-1.5 pb-1.5", children: [
5072
5084
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center h-[calc(0.75rem-8px)]" }),
5073
5085
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -5174,7 +5186,6 @@ const TurnGroup = reactExports.memo(function TurnGroup2({
5174
5186
  const { log, stopReason: reason } = entry;
5175
5187
  const isTurnStart = visibleIdx === 0;
5176
5188
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-stretch", children: [
5177
- isTurnStart ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0 flex items-start pt-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono tabular-nums leading-none select-none", children: turnIndex + 1 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5 shrink-0" }),
5178
5189
  /* @__PURE__ */ jsxRuntimeExports.jsx(
5179
5190
  ThreadConnector,
5180
5191
  {
@@ -13777,6 +13788,36 @@ function LogPaginationButton({
13777
13788
  }
13778
13789
  );
13779
13790
  }
13791
+ function formatDurationSeconds(ms) {
13792
+ return `${Math.max(0, Math.ceil(ms / 1e3)).toString()}s`;
13793
+ }
13794
+ function SessionLoadProgressBar({ progress }) {
13795
+ const elapsedRatio = Math.min(1, progress.elapsedMs / progress.timeoutMs);
13796
+ const percent = Math.max(4, Math.round(elapsedRatio * 100));
13797
+ const remainingMs = Math.max(0, progress.timeoutMs - progress.elapsedMs);
13798
+ const nearTimeout = elapsedRatio >= 0.75;
13799
+ const details = [
13800
+ progress.loadedLogs > 0 ? `${progress.loadedLogs.toString()} logs` : null,
13801
+ progress.loadedPages > 0 ? `${progress.loadedPages.toString()} page${progress.loadedPages === 1 ? "" : "s"}` : null,
13802
+ `${formatDurationSeconds(remainingMs)} before timeout`
13803
+ ].filter((item) => item !== null);
13804
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 space-y-1 px-1 pb-1", children: [
13805
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center justify-between gap-3 font-mono text-[10px] text-muted-foreground", children: [
13806
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate", children: progress.label }),
13807
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("shrink-0 tabular-nums", nearTimeout && "text-amber-300"), children: details.join(" / ") })
13808
+ ] }),
13809
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1.5 overflow-hidden rounded-full bg-white/[0.06]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
13810
+ "div",
13811
+ {
13812
+ className: cn(
13813
+ "h-full rounded-full transition-all duration-300",
13814
+ nearTimeout ? "bg-amber-300/80" : "bg-cyan-300/70"
13815
+ ),
13816
+ style: { width: `${percent.toString()}%` }
13817
+ }
13818
+ ) })
13819
+ ] });
13820
+ }
13780
13821
  function LogPaginationBar({
13781
13822
  logs,
13782
13823
  pagination,
@@ -13794,7 +13835,8 @@ function LogPaginationBar({
13794
13835
  children: [
13795
13836
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full min-w-0 px-1 font-mono text-[11px] text-muted-foreground sm:flex-1", children: [
13796
13837
  formatPaginationStatus({ logs, pagination }),
13797
- pagination.isLoading && logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2", children: "Loading..." })
13838
+ pagination.isLoading && logs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2", children: "Loading..." }),
13839
+ pagination.loadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: pagination.loadProgress })
13798
13840
  ] }),
13799
13841
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-full items-center gap-1 overflow-x-auto sm:w-auto", children: [
13800
13842
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -13932,16 +13974,6 @@ function CopyableCommand({ command }) {
13932
13974
  )
13933
13975
  ] });
13934
13976
  }
13935
- function McpReadyBadge() {
13936
- return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
13937
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "bg-cyan-300/[0.055] shadow-[inset_0_1px_0_rgba(255,255,255,0.05)] inline-flex h-7 items-center gap-2 rounded-md px-2.5 font-mono text-[11px] font-medium text-cyan-200", children: [
13938
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "size-1.5 rounded-full bg-cyan-200 shadow-[0_0_8px_rgba(125,211,252,0.75)]" }),
13939
- "MCP Ready",
13940
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "hidden text-cyan-200/70 sm:inline", children: "/api/mcp" })
13941
- ] }) }),
13942
- /* @__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." })
13943
- ] }) });
13944
- }
13945
13977
  function SidebarPanel({
13946
13978
  label,
13947
13979
  children,
@@ -13986,7 +14018,7 @@ function CrabFamily({
13986
14018
  entrancePhase
13987
14019
  }) {
13988
14020
  if (compact) {
13989
- return /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-7 text-amber-500" });
14021
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-14 text-amber-500" });
13990
14022
  }
13991
14023
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex shrink-0 items-end gap-1 group cursor-default", "aria-hidden": "true", children: [
13992
14024
  /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-10 text-amber-500 transition-all duration-300 group-hover:scale-125 group-hover:-translate-y-1.5" }),
@@ -14014,30 +14046,27 @@ function BrandHeader({
14014
14046
  logCount
14015
14047
  }) {
14016
14048
  if (compact) {
14017
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_16px_44px_rgba(0,0,0,0.18)] rounded-[8px] p-3", children: [
14018
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
14019
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-fit items-start gap-2", children: [
14020
- /* @__PURE__ */ jsxRuntimeExports.jsx(CrabFamily, { compact: true, entrancePhase: crabEntrancePhase }),
14021
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-fit", children: [
14022
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-fit flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [
14023
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "whitespace-nowrap text-base font-bold", children: "Agent Inspector" }),
14024
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden shrink-0 font-mono text-[11px] font-semibold text-muted-foreground sm:inline", children: [
14025
- "v",
14026
- packageJson.version
14027
- ] })
14028
- ] }),
14029
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "hidden text-[11px] font-semibold text-muted-foreground sm:block", children: "Local First. Evidence First." })
14030
- ] })
14031
- ] }),
14032
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
14033
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertsDialog, {}),
14034
- /* @__PURE__ */ jsxRuntimeExports.jsx(GroupsDialog, {}),
14035
- /* @__PURE__ */ jsxRuntimeExports.jsx(AgentLabDialog, { currentSessionId, logCount }),
14036
- /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {})
14049
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_16px_44px_rgba(0,0,0,0.18)] rounded-[8px] p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
14050
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-fit items-start gap-3", children: [
14051
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CrabFamily, { compact: true, entrancePhase: crabEntrancePhase }),
14052
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-fit", children: [
14053
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-fit flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [
14054
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "whitespace-nowrap text-base font-bold", children: "Agent Inspector" }),
14055
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden shrink-0 font-mono text-[11px] font-semibold text-muted-foreground sm:inline", children: [
14056
+ "v",
14057
+ packageJson.version
14058
+ ] })
14059
+ ] }),
14060
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "hidden text-[11px] font-semibold text-muted-foreground sm:block", children: "Local First. Evidence First." })
14037
14061
  ] })
14038
14062
  ] }),
14039
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 hidden sm:block", children: /* @__PURE__ */ jsxRuntimeExports.jsx(McpReadyBadge, {}) })
14040
- ] });
14063
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
14064
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertsDialog, {}),
14065
+ /* @__PURE__ */ jsxRuntimeExports.jsx(GroupsDialog, {}),
14066
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AgentLabDialog, { currentSessionId, logCount }),
14067
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsDialog, {})
14068
+ ] })
14069
+ ] }) });
14041
14070
  }
14042
14071
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-x-4 gap-y-3 pb-6", children: [
14043
14072
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-w-10 flex-1", "aria-hidden": "true" }),
@@ -14054,8 +14083,7 @@ function BrandHeader({
14054
14083
  /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-4 shrink-0 text-muted-foreground/70", "aria-hidden": "true" }),
14055
14084
  /* @__PURE__ */ jsxRuntimeExports.jsx(McpLogo, { className: "size-10 shrink-0" })
14056
14085
  ] }),
14057
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "max-w-full text-sm font-semibold text-muted-foreground", children: "Local First. Evidence First." }),
14058
- /* @__PURE__ */ jsxRuntimeExports.jsx(McpReadyBadge, {})
14086
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "max-w-full text-sm font-semibold text-muted-foreground", children: "Local First. Evidence First." })
14059
14087
  ] }),
14060
14088
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 justify-end gap-1", children: [
14061
14089
  /* @__PURE__ */ jsxRuntimeExports.jsx(AlertsDialog, {}),
@@ -14362,6 +14390,7 @@ function ProxyViewer({
14362
14390
  onSessionChange,
14363
14391
  onModelChange,
14364
14392
  onClearAll,
14393
+ onDeleteCurrentView,
14365
14394
  onReloadSession,
14366
14395
  onClearGroup,
14367
14396
  onNotify,
@@ -14373,6 +14402,7 @@ function ProxyViewer({
14373
14402
  timeDisplayFormat,
14374
14403
  isLoading = false,
14375
14404
  pagination,
14405
+ sessionLoadProgress,
14376
14406
  sessionMemberships = [],
14377
14407
  hideSessionFilter = false,
14378
14408
  pinnedSessionId
@@ -14384,6 +14414,9 @@ function ProxyViewer({
14384
14414
  const [importing, setImporting] = reactExports.useState(false);
14385
14415
  const [importStatus, setImportStatus] = reactExports.useState(null);
14386
14416
  const [importError, setImportError] = reactExports.useState(null);
14417
+ const [deleteDialogOpen, setDeleteDialogOpen] = reactExports.useState(false);
14418
+ const [deleteStoredData, setDeleteStoredData] = reactExports.useState(false);
14419
+ const [deletingCurrentView, setDeletingCurrentView] = reactExports.useState(false);
14387
14420
  const [comparePair, setComparePair] = reactExports.useState(null);
14388
14421
  const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
14389
14422
  "hidden"
@@ -14500,6 +14533,34 @@ function ProxyViewer({
14500
14533
  setComparePair(null);
14501
14534
  onClearAll();
14502
14535
  }, [cancelTransientTasks, onClearAll]);
14536
+ const handleRequestDeleteCurrentView = reactExports.useCallback(() => {
14537
+ setDeleteStoredData(false);
14538
+ setDeleteDialogOpen(true);
14539
+ }, []);
14540
+ const handleConfirmDeleteCurrentView = reactExports.useCallback(() => {
14541
+ cancelTransientTasks();
14542
+ setImportStatus(null);
14543
+ setImportError(null);
14544
+ setComparePair(null);
14545
+ if (!deleteStoredData || onDeleteCurrentView === void 0) {
14546
+ setDeleteDialogOpen(false);
14547
+ onClearAll();
14548
+ return;
14549
+ }
14550
+ setDeletingCurrentView(true);
14551
+ void onDeleteCurrentView(logs.map((log) => log.id)).then(() => {
14552
+ setDeleteDialogOpen(false);
14553
+ }).catch((err) => {
14554
+ const message = err instanceof Error ? err.message : "Failed to delete stored logs";
14555
+ if (onNotify !== void 0) {
14556
+ onNotify({ message, tone: "error" });
14557
+ } else {
14558
+ setImportError(message);
14559
+ }
14560
+ }).finally(() => {
14561
+ setDeletingCurrentView(false);
14562
+ });
14563
+ }, [cancelTransientTasks, deleteStoredData, logs, onClearAll, onDeleteCurrentView, onNotify]);
14503
14564
  const handleReloadCurrentSession = reactExports.useCallback(() => {
14504
14565
  if (onReloadSession === void 0) return;
14505
14566
  cancelTransientTasks();
@@ -14622,16 +14683,31 @@ function ProxyViewer({
14622
14683
  disabled: !canClearCurrentView,
14623
14684
  className: cn(
14624
14685
  "bg-white/[0.035] hover:bg-white/[0.065] inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2 text-xs text-muted-foreground shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50",
14625
- onReloadSession === void 0 && "col-span-2"
14686
+ onReloadSession === void 0 && onDeleteCurrentView === void 0 && "col-span-2"
14626
14687
  ),
14627
14688
  title: "Clear the current view. Stored logs remain reloadable.",
14628
14689
  children: [
14629
14690
  /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
14630
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear view" })
14691
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear" })
14692
+ ]
14693
+ }
14694
+ ),
14695
+ onDeleteCurrentView !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
14696
+ "button",
14697
+ {
14698
+ type: "button",
14699
+ onClick: handleRequestDeleteCurrentView,
14700
+ disabled: !canClearCurrentView || deletingCurrentView,
14701
+ className: "bg-red-500/[0.07] hover:bg-red-500/[0.12] inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2 text-xs text-red-200 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.14)] transition-colors hover:text-red-100 disabled:cursor-not-allowed disabled:opacity-50",
14702
+ title: "Choose whether to delete stored data for the current view.",
14703
+ children: [
14704
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
14705
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Delete" })
14631
14706
  ]
14632
14707
  }
14633
14708
  )
14634
- ] })
14709
+ ] }),
14710
+ sessionLoadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md bg-black/20 px-2 py-2 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: sessionLoadProgress }) })
14635
14711
  ] }),
14636
14712
  /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarPanel, { label: "Workspace", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-black/20 rounded-md px-3 py-2 shadow-[inset_0_1px_0_rgba(255,255,255,0.035)]", children: [
14637
14713
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -14795,11 +14871,26 @@ function ProxyViewer({
14795
14871
  title: "Clear the current view. Stored logs remain reloadable.",
14796
14872
  children: [
14797
14873
  /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
14798
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear view" })
14874
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Clear" })
14875
+ ]
14876
+ }
14877
+ ),
14878
+ onDeleteCurrentView !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
14879
+ "button",
14880
+ {
14881
+ type: "button",
14882
+ onClick: handleRequestDeleteCurrentView,
14883
+ disabled: !canClearCurrentView || deletingCurrentView,
14884
+ className: "bg-red-500/[0.07] hover:bg-red-500/[0.12] inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-red-200 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.14)] transition-colors hover:text-red-100 disabled:cursor-not-allowed disabled:opacity-50",
14885
+ title: "Choose whether to delete stored data for the current view.",
14886
+ children: [
14887
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3.5" }),
14888
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Delete" })
14799
14889
  ]
14800
14890
  }
14801
14891
  )
14802
14892
  ] }),
14893
+ pagination === void 0 && sessionLoadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md bg-black/20 px-2 py-2 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: sessionLoadProgress }) }),
14803
14894
  /* @__PURE__ */ jsxRuntimeExports.jsx(LogPaginationBar, { logs, pagination, embedded: true }),
14804
14895
  onNotify === void 0 && exportError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: exportError }),
14805
14896
  onNotify === void 0 && importError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: importError }),
@@ -14810,6 +14901,7 @@ function ProxyViewer({
14810
14901
  logs.length === 0 ? selectedSession !== "__all__" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-16 text-center text-muted-foreground", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white/[0.035] shadow-[inset_0_1px_0_rgba(255,255,255,0.045),0_18px_52px_rgba(0,0,0,0.18)] mx-auto max-w-xl space-y-4 rounded-[8px] px-4 py-8", children: [
14811
14902
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: isLoading ? "Loading session data..." : "No logs loaded for this session" }),
14812
14903
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "inline-block max-w-full rounded bg-muted px-3 py-1 font-mono text-xs break-all", children: truncateSessionId(selectedSession) }),
14904
+ sessionLoadProgress !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto max-w-md rounded-md bg-black/20 px-2 py-2 text-left shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionLoadProgressBar, { progress: sessionLoadProgress }) }),
14813
14905
  sessionMemberships.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-left", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionMembershipPanel, { memberships: sessionMemberships }) }),
14814
14906
  !isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3 text-xs", children: [
14815
14907
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Stored logs may still be available." }),
@@ -14881,6 +14973,59 @@ function ProxyViewer({
14881
14973
  ] })
14882
14974
  ] })
14883
14975
  ] }),
14976
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Dialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogContent, { className: "border-red-500/20 bg-zinc-950 text-zinc-100 sm:max-w-md", children: [
14977
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogHeader, { children: [
14978
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Delete current logs?" }),
14979
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DialogDescription, { children: "Choose whether this only clears the UI or also deletes the stored log data for the current view." })
14980
+ ] }),
14981
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-start gap-3 rounded-md bg-red-500/[0.08] px-3 py-3 text-sm text-red-100 shadow-[inset_0_0_0_1px_rgba(248,113,113,0.16)]", children: [
14982
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
14983
+ "input",
14984
+ {
14985
+ type: "checkbox",
14986
+ className: "mt-0.5 size-4 shrink-0",
14987
+ checked: deleteStoredData,
14988
+ disabled: deletingCurrentView,
14989
+ onChange: (event) => setDeleteStoredData(event.currentTarget.checked)
14990
+ }
14991
+ ),
14992
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0", children: [
14993
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block font-medium", children: "Also delete stored data" }),
14994
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "mt-1 block text-xs text-red-200/80", children: [
14995
+ "Removes persisted log rows, streaming chunks, and session archive entries for these",
14996
+ " ",
14997
+ logs.length.toString(),
14998
+ " visible request",
14999
+ logs.length === 1 ? "" : "s",
15000
+ "."
15001
+ ] })
15002
+ ] })
15003
+ ] }),
15004
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2", children: [
15005
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
15006
+ Button,
15007
+ {
15008
+ type: "button",
15009
+ variant: "outline",
15010
+ size: "sm",
15011
+ disabled: deletingCurrentView,
15012
+ onClick: () => setDeleteDialogOpen(false),
15013
+ children: "Cancel"
15014
+ }
15015
+ ),
15016
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
15017
+ Button,
15018
+ {
15019
+ type: "button",
15020
+ variant: deleteStoredData ? "destructive" : "secondary",
15021
+ size: "sm",
15022
+ disabled: deletingCurrentView,
15023
+ onClick: handleConfirmDeleteCurrentView,
15024
+ children: deletingCurrentView ? "Deleting..." : deleteStoredData ? "Delete data" : "Clear only"
15025
+ }
15026
+ )
15027
+ ] })
15028
+ ] }) }),
14884
15029
  comparePair !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
14885
15030
  LazyCompareDrawer,
14886
15031
  {
@@ -14913,6 +15058,13 @@ const LogCursorPageSchema = object({
14913
15058
  newestLogId: number().int().positive().nullable()
14914
15059
  });
14915
15060
  const SessionsResponseSchema = array(string());
15061
+ const DeleteLogsResponseSchema = object({
15062
+ success: boolean(),
15063
+ cleared: number().int().nonnegative(),
15064
+ logFilesRewritten: number().int().nonnegative().optional(),
15065
+ chunkFilesDeleted: number().int().nonnegative(),
15066
+ sessionArchiveLogsDeleted: number().int().nonnegative().optional()
15067
+ });
14916
15068
  function buildSessionMembershipEvidence(groups, sessionId) {
14917
15069
  const memberships = [];
14918
15070
  for (const group of groups) {
@@ -15038,12 +15190,17 @@ function ProxyViewerContainer({
15038
15190
  const [streamInitialized, setStreamInitialized] = reactExports.useState(initialSessionId === void 0);
15039
15191
  const [logPage, setLogPage] = reactExports.useState(null);
15040
15192
  const [sessionPageLoading, setSessionPageLoading] = reactExports.useState(initialSessionId !== void 0);
15193
+ const [sessionLoadProgress, setSessionLoadProgress] = reactExports.useState(
15194
+ void 0
15195
+ );
15041
15196
  const [sessionMemberships, setSessionMemberships] = reactExports.useState([]);
15042
15197
  const [, startLogTransition] = reactExports.useTransition();
15043
15198
  const eventSourceRef = reactExports.useRef(null);
15044
15199
  const reconnectTimeoutRef = reactExports.useRef(null);
15045
15200
  const handledHashRef = reactExports.useRef(null);
15046
15201
  const sessionPageRequestIdRef = reactExports.useRef(0);
15202
+ const sessionLoadStartedAtRef = reactExports.useRef(null);
15203
+ const sessionLoadTimerRef = reactExports.useRef(null);
15047
15204
  const logIndexRef = reactExports.useRef(/* @__PURE__ */ new Map());
15048
15205
  const pendingUpdatesRef = reactExports.useRef([]);
15049
15206
  const flushTimerRef = reactExports.useRef(null);
@@ -15053,6 +15210,50 @@ function ProxyViewerContainer({
15053
15210
  },
15054
15211
  [showToast]
15055
15212
  );
15213
+ const stopSessionLoadProgress = reactExports.useCallback(() => {
15214
+ if (sessionLoadTimerRef.current !== null) {
15215
+ clearInterval(sessionLoadTimerRef.current);
15216
+ sessionLoadTimerRef.current = null;
15217
+ }
15218
+ sessionLoadStartedAtRef.current = null;
15219
+ setSessionLoadProgress(void 0);
15220
+ }, []);
15221
+ const startSessionLoadProgress = reactExports.useCallback(
15222
+ (label, requestId, loadedLogs = 0, loadedPages = 0) => {
15223
+ if (sessionLoadTimerRef.current !== null) {
15224
+ clearInterval(sessionLoadTimerRef.current);
15225
+ }
15226
+ const startedAt = Date.now();
15227
+ sessionLoadStartedAtRef.current = startedAt;
15228
+ const update = () => {
15229
+ if (sessionPageRequestIdRef.current !== requestId) return;
15230
+ setSessionLoadProgress({
15231
+ label,
15232
+ elapsedMs: Date.now() - startedAt,
15233
+ timeoutMs: SESSION_LOGS_FETCH_TIMEOUT_MS,
15234
+ loadedLogs,
15235
+ loadedPages
15236
+ });
15237
+ };
15238
+ update();
15239
+ sessionLoadTimerRef.current = setInterval(update, 250);
15240
+ },
15241
+ []
15242
+ );
15243
+ const updateSessionLoadProgress = reactExports.useCallback(
15244
+ (label, requestId, loadedLogs, loadedPages) => {
15245
+ const startedAt = sessionLoadStartedAtRef.current;
15246
+ if (startedAt === null || sessionPageRequestIdRef.current !== requestId) return;
15247
+ setSessionLoadProgress({
15248
+ label,
15249
+ elapsedMs: Date.now() - startedAt,
15250
+ timeoutMs: SESSION_LOGS_FETCH_TIMEOUT_MS,
15251
+ loadedLogs,
15252
+ loadedPages
15253
+ });
15254
+ },
15255
+ []
15256
+ );
15056
15257
  const logs = reactExports.useMemo(
15057
15258
  () => filterLogs(allLogs, selectedSession, selectedModel),
15058
15259
  [allLogs, selectedSession, selectedModel]
@@ -15148,6 +15349,7 @@ function ProxyViewerContainer({
15148
15349
  const requestId = sessionPageRequestIdRef.current + 1;
15149
15350
  sessionPageRequestIdRef.current = requestId;
15150
15351
  setSessionPageLoading(true);
15352
+ startSessionLoadProgress("Loading session logs", requestId);
15151
15353
  dismissToast();
15152
15354
  void fetchSessionLogsPage(initialSessionId, request).then((page) => {
15153
15355
  if (sessionPageRequestIdRef.current !== requestId) return;
@@ -15157,22 +15359,31 @@ function ProxyViewerContainer({
15157
15359
  setLogPage(page);
15158
15360
  setSelectedSession(initialSessionId);
15159
15361
  setSessionPageLoading(false);
15362
+ stopSessionLoadProgress();
15160
15363
  dismissToast();
15161
15364
  }).catch((err) => {
15162
15365
  if (sessionPageRequestIdRef.current !== requestId) return;
15163
15366
  setAllLogs([]);
15164
15367
  setLogPage(null);
15165
15368
  setSessionPageLoading(false);
15369
+ stopSessionLoadProgress();
15166
15370
  showErrorToast(err instanceof Error ? err.message : "Failed to load session logs");
15167
15371
  });
15168
15372
  },
15169
- [dismissToast, initialSessionId, showErrorToast]
15373
+ [
15374
+ dismissToast,
15375
+ initialSessionId,
15376
+ showErrorToast,
15377
+ startSessionLoadProgress,
15378
+ stopSessionLoadProgress
15379
+ ]
15170
15380
  );
15171
15381
  const reloadSessionLogs = reactExports.useCallback(
15172
15382
  (sessionId) => {
15173
15383
  const requestId = sessionPageRequestIdRef.current + 1;
15174
15384
  sessionPageRequestIdRef.current = requestId;
15175
15385
  setSessionPageLoading(true);
15386
+ startSessionLoadProgress("Reloading full session", requestId);
15176
15387
  dismissToast();
15177
15388
  void (async () => {
15178
15389
  const collected = [];
@@ -15182,6 +15393,7 @@ function ProxyViewerContainer({
15182
15393
  SESSION_RELOAD_PAGE_LIMIT
15183
15394
  );
15184
15395
  collected.push(...page.logs);
15396
+ updateSessionLoadProgress("Reloading full session", requestId, collected.length, 1);
15185
15397
  let loadedPages = 1;
15186
15398
  while (page.hasNewer && page.newestLogId !== null && loadedPages < MAX_SESSION_RELOAD_PAGES) {
15187
15399
  page = await fetchSessionLogsPage(
@@ -15191,6 +15403,12 @@ function ProxyViewerContainer({
15191
15403
  );
15192
15404
  collected.push(...page.logs);
15193
15405
  loadedPages += 1;
15406
+ updateSessionLoadProgress(
15407
+ "Reloading full session",
15408
+ requestId,
15409
+ collected.length,
15410
+ loadedPages
15411
+ );
15194
15412
  }
15195
15413
  if (sessionPageRequestIdRef.current !== requestId) return;
15196
15414
  setAllLogs((prev) => {
@@ -15200,6 +15418,7 @@ function ProxyViewerContainer({
15200
15418
  });
15201
15419
  setKnownSessions((prev) => mergeSessionIds(prev, [sessionId]));
15202
15420
  setSessionPageLoading(false);
15421
+ stopSessionLoadProgress();
15203
15422
  if (page.hasNewer) {
15204
15423
  showToast({
15205
15424
  message: `Loaded ${String(collected.length)} logs for this session. More history is available.`,
@@ -15211,10 +15430,18 @@ function ProxyViewerContainer({
15211
15430
  })().catch((err) => {
15212
15431
  if (sessionPageRequestIdRef.current !== requestId) return;
15213
15432
  setSessionPageLoading(false);
15433
+ stopSessionLoadProgress();
15214
15434
  showErrorToast(err instanceof Error ? err.message : "Failed to reload session logs");
15215
15435
  });
15216
15436
  },
15217
- [dismissToast, showErrorToast, showToast]
15437
+ [
15438
+ dismissToast,
15439
+ showErrorToast,
15440
+ showToast,
15441
+ startSessionLoadProgress,
15442
+ stopSessionLoadProgress,
15443
+ updateSessionLoadProgress
15444
+ ]
15218
15445
  );
15219
15446
  reactExports.useEffect(() => {
15220
15447
  if (initialSessionId === void 0) {
@@ -15239,6 +15466,11 @@ function ProxyViewerContainer({
15239
15466
  reactExports.useEffect(() => {
15240
15467
  refreshSessions();
15241
15468
  }, [refreshSessions]);
15469
+ reactExports.useEffect(() => {
15470
+ return () => {
15471
+ stopSessionLoadProgress();
15472
+ };
15473
+ }, [stopSessionLoadProgress]);
15242
15474
  reactExports.useEffect(() => {
15243
15475
  if (initialSessionId === void 0) return;
15244
15476
  loadSessionPage({ kind: "newest" });
@@ -15316,6 +15548,8 @@ function ProxyViewerContainer({
15316
15548
  }, [logs.length]);
15317
15549
  const handleClearAll = reactExports.useCallback(() => {
15318
15550
  const clearedSessions = extractSessions(allLogs);
15551
+ stopSessionLoadProgress();
15552
+ setSessionPageLoading(false);
15319
15553
  logIndexRef.current.clear();
15320
15554
  setAllLogs([]);
15321
15555
  setLogPage(null);
@@ -15324,7 +15558,7 @@ function ProxyViewerContainer({
15324
15558
  message: "Cleared the current view. Stored logs are still reloadable.",
15325
15559
  tone: "success"
15326
15560
  });
15327
- }, [allLogs, showToast]);
15561
+ }, [allLogs, showToast, stopSessionLoadProgress]);
15328
15562
  const handleClearGroup = reactExports.useCallback(
15329
15563
  (ids) => {
15330
15564
  if (ids.length === 0) return;
@@ -15340,6 +15574,35 @@ function ProxyViewerContainer({
15340
15574
  },
15341
15575
  [showToast]
15342
15576
  );
15577
+ const handleDeleteCurrentView = reactExports.useCallback(
15578
+ async (ids) => {
15579
+ if (ids.length === 0) return;
15580
+ const idSet = new Set(ids);
15581
+ const removed = allLogs.filter((log) => idSet.has(log.id));
15582
+ const result = await fetchJson("/api/logs", DeleteLogsResponseSchema, {
15583
+ method: "DELETE",
15584
+ headers: { "content-type": "application/json" },
15585
+ body: JSON.stringify({ ids })
15586
+ });
15587
+ setAllLogs((prev) => {
15588
+ const remaining = prev.filter((log) => !idSet.has(log.id));
15589
+ logIndexRef.current = buildLogIndex(remaining);
15590
+ return remaining;
15591
+ });
15592
+ setLogPage(
15593
+ (prev) => prev === null ? null : {
15594
+ ...prev,
15595
+ logs: prev.logs.filter((log) => !idSet.has(log.id))
15596
+ }
15597
+ );
15598
+ setKnownSessions((prev) => mergeSessionIds(prev, extractSessions(removed)));
15599
+ showToast({
15600
+ message: `Deleted ${result.cleared.toString()} stored log${result.cleared === 1 ? "" : "s"} from the current view.`,
15601
+ tone: "success"
15602
+ });
15603
+ },
15604
+ [allLogs, showToast]
15605
+ );
15343
15606
  const handleReloadSession = reactExports.useCallback(() => {
15344
15607
  if (initialSessionId !== void 0) {
15345
15608
  loadSessionPage({ kind: "newest" });
@@ -15400,6 +15663,7 @@ function ProxyViewerContainer({
15400
15663
  if (initialSessionId === void 0) return void 0;
15401
15664
  return {
15402
15665
  isLoading: sessionPageLoading,
15666
+ loadProgress: sessionLoadProgress,
15403
15667
  total: logPage?.total ?? null,
15404
15668
  pageSize: logPage?.limit ?? SESSION_PAGE_LIMIT,
15405
15669
  hasOlder: logPage?.hasOlder ?? false,
@@ -15418,6 +15682,7 @@ function ProxyViewerContainer({
15418
15682
  loadOlderPage,
15419
15683
  loadOldestPage,
15420
15684
  logPage,
15685
+ sessionLoadProgress,
15421
15686
  sessionPageLoading
15422
15687
  ]);
15423
15688
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
@@ -15434,12 +15699,14 @@ function ProxyViewerContainer({
15434
15699
  onSessionChange: setSelectedSession,
15435
15700
  onModelChange: setSelectedModel,
15436
15701
  onClearAll: handleClearAll,
15702
+ onDeleteCurrentView: handleDeleteCurrentView,
15437
15703
  onReloadSession: initialSessionId !== void 0 || selectedSession !== "__all__" ? handleReloadSession : void 0,
15438
15704
  onClearGroup: handleClearGroup,
15439
15705
  onNotify: showToast,
15440
15706
  onImportLogs: initialSessionId === void 0 ? handleImportLogs : void 0,
15441
15707
  isLoading: initialSessionId === void 0 ? !streamInitialized || sessionPageLoading : sessionPageLoading,
15442
15708
  pagination,
15709
+ sessionLoadProgress,
15443
15710
  sessionMemberships,
15444
15711
  viewMode,
15445
15712
  captureMode,