@tonyclaw/agent-inspector 2.0.41 → 2.0.43

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 (42) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-DCg6S2cl.js → CompareDrawer-CxM1gCfL.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-TtRG-0E7.js +117 -0
  4. package/.output/public/assets/{ReplayDialog-ClVgjSDE.js → ReplayDialog-UseUkucS.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-BhqvLQp9.js → RequestAnatomy-aPxgEJ2L.js} +1 -1
  6. package/.output/public/assets/{ResponseView-BZAJoK6B.js → ResponseView-DA-F4F97.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-CaORmoKX.js → StreamingChunkSequence-JSQEPeNS.js} +1 -1
  8. package/.output/public/assets/_sessionId-BEXuCWq5.js +1 -0
  9. package/.output/public/assets/index-Bhsa_2xX.js +1 -0
  10. package/.output/public/assets/index-DOWlRJ0W.css +1 -0
  11. package/.output/public/assets/{main-CI3HFEcV.js → main-BpGVJcpB.js} +2 -2
  12. package/.output/server/{_sessionId-DQ0ljHQ8.mjs → _sessionId-DGn-TENM.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-nkVa9epn.mjs → CompareDrawer-CFElCSYY.mjs} +2 -2
  14. package/.output/server/_ssr/{ProxyViewerContainer-CXA7iH3H.mjs → ProxyViewerContainer-B7SR9mrD.mjs} +383 -76
  15. package/.output/server/_ssr/{ReplayDialog-CK71-ucq.mjs → ReplayDialog-DfKapj0k.mjs} +3 -3
  16. package/.output/server/_ssr/{RequestAnatomy-DDCUJJ3X.mjs → RequestAnatomy-CUxTCg31.mjs} +2 -2
  17. package/.output/server/_ssr/{ResponseView-C6ZA7V3B.mjs → ResponseView-BXY0w197.mjs} +2 -2
  18. package/.output/server/_ssr/{StreamingChunkSequence-DW5v_o6G.mjs → StreamingChunkSequence-CzMnES9H.mjs} +2 -2
  19. package/.output/server/_ssr/{index-Ckex98yq.mjs → index-CVlT-REW.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-ChJIVv7-.mjs → router-B2d1LUx6.mjs} +1313 -468
  22. package/.output/server/{_tanstack-start-manifest_v-CJ4__weU.mjs → _tanstack-start-manifest_v-Drpi28BM.mjs} +1 -1
  23. package/.output/server/index.mjs +60 -60
  24. package/README.md +36 -12
  25. package/package.json +1 -1
  26. package/src/components/ProxyViewer.tsx +156 -17
  27. package/src/components/ProxyViewerContainer.tsx +66 -4
  28. package/src/components/groups/GroupsDialog.tsx +11 -10
  29. package/src/components/providers/SettingsDialog.tsx +137 -0
  30. package/src/components/proxy-viewer/LogEntry.tsx +107 -56
  31. package/src/components/ui/dialog.tsx +1 -1
  32. package/src/lib/runContract.ts +3 -0
  33. package/src/mcp/currentContext.ts +65 -0
  34. package/src/mcp/mode.ts +56 -0
  35. package/src/mcp/server.ts +466 -15
  36. package/src/mcp/toolHandlers.ts +372 -0
  37. package/src/proxy/evidenceExporter.ts +1 -0
  38. package/src/proxy/runStore.ts +74 -22
  39. package/.output/public/assets/ProxyViewerContainer-DsU6QETm.js +0 -115
  40. package/.output/public/assets/_sessionId-BHqywvM3.js +0 -1
  41. package/.output/public/assets/index-B_LPYuM0.js +0 -1
  42. package/.output/public/assets/index-BfGJEb-2.css +0 -1
@@ -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_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, v as packageJson, i as GroupEvidenceExportResultSchema, j as DeleteInspectorGroupResponseSchema, d as RuntimeConfigSchema, P as ProviderConfigSchema, f as apiFormatForPath, n as createPendingProviderTestResults, o as ProviderTestResultsSchema, q as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, r as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, k as providerHasContextMetadata, l as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, t as resolveProviderContextWindow, K as KnowledgeCandidateSchema, h as stripClaudeCodeBillingHeader, u as isPlainRecord, G as GroupEvidenceReadResponseSchema, I as InspectorGroupsListResponseSchema } from "./router-ChJIVv7-.mjs";
2
+ import { I as InspectorGroupsListResponseSchema, C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, v as packageJson, i as GroupEvidenceExportResultSchema, j as DeleteInspectorGroupResponseSchema, d as RuntimeConfigSchema, P as ProviderConfigSchema, f as apiFormatForPath, n as createPendingProviderTestResults, o as ProviderTestResultsSchema, q as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, r as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, k as providerHasContextMetadata, l as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, t as resolveProviderContextWindow, K as KnowledgeCandidateSchema, h as stripClaudeCodeBillingHeader, u as isPlainRecord, G as GroupEvidenceReadResponseSchema } from "./router-B2d1LUx6.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";
@@ -629,7 +629,7 @@ function DialogOverlay({
629
629
  {
630
630
  "data-slot": "dialog-overlay",
631
631
  className: cn(
632
- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
632
+ "fixed inset-0 z-40 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
633
633
  className
634
634
  ),
635
635
  ...props
@@ -1937,19 +1937,19 @@ function useCopyFeedback(text) {
1937
1937
  return { copied, copy };
1938
1938
  }
1939
1939
  const LazyCompareDrawer = reactExports.lazy(
1940
- () => import("./CompareDrawer-nkVa9epn.mjs").then((m) => ({ default: m.CompareDrawer }))
1940
+ () => import("./CompareDrawer-CFElCSYY.mjs").then((m) => ({ default: m.CompareDrawer }))
1941
1941
  );
1942
1942
  const LazyReplayDialog = reactExports.lazy(
1943
- () => import("./ReplayDialog-CK71-ucq.mjs").then((m) => ({ default: m.ReplayDialog }))
1943
+ () => import("./ReplayDialog-DfKapj0k.mjs").then((m) => ({ default: m.ReplayDialog }))
1944
1944
  );
1945
1945
  const LazyRequestAnatomy = reactExports.lazy(
1946
- () => import("./RequestAnatomy-DDCUJJ3X.mjs").then((m) => ({ default: m.RequestAnatomy }))
1946
+ () => import("./RequestAnatomy-CUxTCg31.mjs").then((m) => ({ default: m.RequestAnatomy }))
1947
1947
  );
1948
1948
  const LazyResponseView = reactExports.lazy(
1949
- () => import("./ResponseView-C6ZA7V3B.mjs").then((m) => ({ default: m.ResponseView }))
1949
+ () => import("./ResponseView-BXY0w197.mjs").then((m) => ({ default: m.ResponseView }))
1950
1950
  );
1951
1951
  const LazyStreamingChunkSequence = reactExports.lazy(
1952
- () => import("./StreamingChunkSequence-DW5v_o6G.mjs").then((m) => ({
1952
+ () => import("./StreamingChunkSequence-CzMnES9H.mjs").then((m) => ({
1953
1953
  default: m.StreamingChunkSequence
1954
1954
  }))
1955
1955
  );
@@ -3505,6 +3505,9 @@ function resolveFocusedTab(tab, anatomySegments) {
3505
3505
  return "request";
3506
3506
  }
3507
3507
  }
3508
+ function shouldHydrateLogBody(log) {
3509
+ return log.bodyContentMode === "compact" || log.bodyContentMode === "truncated";
3510
+ }
3508
3511
  function DiffToggleButton({
3509
3512
  active,
3510
3513
  onClick
@@ -3561,40 +3564,43 @@ const LogEntry = reactExports.memo(function({
3561
3564
  const [requestDiff, setRequestDiff] = reactExports.useState(false);
3562
3565
  const [activeTab, setActiveTab] = reactExports.useState("request");
3563
3566
  const [expandToPath, setExpandToPath] = reactExports.useState(null);
3567
+ const [hydratedLog, setHydratedLog] = reactExports.useState(null);
3568
+ const [bodyHydrationState, setBodyHydrationState] = reactExports.useState("idle");
3564
3569
  const requestJsonRef = reactExports.useRef(null);
3565
- const resolvedFormat = resolveLogFormat(log);
3570
+ const displayLog = hydratedLog ?? log;
3571
+ const resolvedFormat = resolveLogFormat(displayLog);
3566
3572
  const adapter = getLogFormatAdapter(resolvedFormat);
3567
3573
  const requestAnalysis = reactExports.useMemo(
3568
- () => adapter.analyzeRequest(log.rawRequestBody),
3569
- [adapter, log.rawRequestBody]
3574
+ () => adapter.analyzeRequest(displayLog.rawRequestBody),
3575
+ [adapter, displayLog.rawRequestBody]
3570
3576
  );
3571
3577
  const responseAnalysis = reactExports.useMemo(
3572
- () => adapter.analyzeResponse(log.responseText),
3573
- [adapter, log.responseText]
3578
+ () => adapter.analyzeResponse(displayLog.responseText),
3579
+ [adapter, displayLog.responseText]
3574
3580
  );
3575
3581
  const strippedRequestBody = reactExports.useMemo(() => {
3576
- if (!strip || resolvedFormat !== "anthropic" || log.rawRequestBody === null) {
3582
+ if (!strip || resolvedFormat !== "anthropic" || displayLog.rawRequestBody === null) {
3577
3583
  return null;
3578
3584
  }
3579
- return stripClaudeCodeBillingHeader(log.rawRequestBody).body;
3580
- }, [log.rawRequestBody, resolvedFormat, strip]);
3581
- const displayedRequestBody = strippedRequestBody ?? log.rawRequestBody;
3585
+ return stripClaudeCodeBillingHeader(displayLog.rawRequestBody).body;
3586
+ }, [displayLog.rawRequestBody, resolvedFormat, strip]);
3587
+ const displayedRequestBody = strippedRequestBody ?? displayLog.rawRequestBody;
3582
3588
  const requestExpansion = useJsonBulkExpansion(displayedRequestBody);
3583
- const rawRequestExpansion = useJsonBulkExpansion(log.rawRequestBody);
3584
- const responseExpansion = useJsonBulkExpansion(log.responseText);
3589
+ const rawRequestExpansion = useJsonBulkExpansion(displayLog.rawRequestBody);
3590
+ const responseExpansion = useJsonBulkExpansion(displayLog.responseText);
3585
3591
  const headersText = reactExports.useMemo(
3586
- () => log.headers && Object.keys(log.headers).length > 0 ? JSON.stringify(log.headers, null, 2) : null,
3587
- [log.headers]
3592
+ () => displayLog.headers && Object.keys(displayLog.headers).length > 0 ? JSON.stringify(displayLog.headers, null, 2) : null,
3593
+ [displayLog.headers]
3588
3594
  );
3589
3595
  const rawHeadersText = reactExports.useMemo(
3590
- () => log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? JSON.stringify(log.rawHeaders, null, 2) : null,
3591
- [log.rawHeaders]
3596
+ () => displayLog.rawHeaders && Object.keys(displayLog.rawHeaders).length > 0 ? JSON.stringify(displayLog.rawHeaders, null, 2) : null,
3597
+ [displayLog.rawHeaders]
3592
3598
  );
3593
3599
  const requestCopy = useCopyFeedback(displayedRequestBody);
3594
- const rawRequestCopy = useCopyFeedback(log.rawRequestBody);
3600
+ const rawRequestCopy = useCopyFeedback(displayLog.rawRequestBody);
3595
3601
  const headersCopy = useCopyFeedback(headersText);
3596
3602
  const rawHeadersCopy = useCopyFeedback(rawHeadersText);
3597
- const responseCopy = useCopyFeedback(log.responseText);
3603
+ const responseCopy = useCopyFeedback(displayLog.responseText);
3598
3604
  const tabActions = reactExports.useMemo(
3599
3605
  () => ({
3600
3606
  request: {
@@ -3614,15 +3620,15 @@ const LogEntry = reactExports.memo(function({
3614
3620
  resolvedFormat,
3615
3621
  viewMode,
3616
3622
  strip,
3617
- log.rawRequestBody !== null
3623
+ displayLog.rawRequestBody !== null
3618
3624
  ) ? { active: requestDiff, onToggle: () => setRequestDiff(!requestDiff) } : void 0,
3619
3625
  diffWithPrevious: onCompareWithPrevious === void 0 ? void 0 : () => {
3620
- onCompareWithPrevious(log);
3626
+ onCompareWithPrevious(displayLog);
3621
3627
  }
3622
3628
  },
3623
3629
  "raw-request": {
3624
3630
  copyLabel: "Copy raw request",
3625
- copyText: log.rawRequestBody,
3631
+ copyText: displayLog.rawRequestBody,
3626
3632
  copyCopied: rawRequestCopy.copied,
3627
3633
  onCopy: rawRequestCopy.copy,
3628
3634
  expansion: {
@@ -3648,7 +3654,7 @@ const LogEntry = reactExports.memo(function({
3648
3654
  },
3649
3655
  raw: {
3650
3656
  copyLabel: "Copy response",
3651
- copyText: log.responseText,
3657
+ copyText: displayLog.responseText,
3652
3658
  copyCopied: responseCopy.copied,
3653
3659
  onCopy: responseCopy.copy,
3654
3660
  expansion: {
@@ -3663,14 +3669,15 @@ const LogEntry = reactExports.memo(function({
3663
3669
  requestCopy,
3664
3670
  requestExpansion,
3665
3671
  requestDiff,
3666
- log.rawRequestBody,
3672
+ displayLog,
3673
+ displayLog.rawRequestBody,
3667
3674
  rawRequestCopy,
3668
3675
  rawRequestExpansion,
3669
3676
  headersText,
3670
3677
  headersCopy,
3671
3678
  rawHeadersText,
3672
3679
  rawHeadersCopy,
3673
- log.responseText,
3680
+ displayLog.responseText,
3674
3681
  responseCopy,
3675
3682
  responseExpansion,
3676
3683
  resolvedFormat,
@@ -3687,7 +3694,7 @@ const LogEntry = reactExports.memo(function({
3687
3694
  () => parseRequestTools(requestExpansion.parsedData),
3688
3695
  [requestExpansion.parsedData]
3689
3696
  );
3690
- const warnings = log.warnings ?? [];
3697
+ const warnings = displayLog.warnings ?? [];
3691
3698
  const anatomyPaths = reactExports.useMemo(() => {
3692
3699
  if (anatomySegments === null) return void 0;
3693
3700
  return new Set(anatomySegments.map((s) => s.path));
@@ -3706,6 +3713,28 @@ const LogEntry = reactExports.memo(function({
3706
3713
  }
3707
3714
  setExpanded(nextExpanded);
3708
3715
  }, [anatomySegments, expanded]);
3716
+ reactExports.useEffect(() => {
3717
+ setHydratedLog(null);
3718
+ setBodyHydrationState("idle");
3719
+ }, [log.id]);
3720
+ reactExports.useEffect(() => {
3721
+ if (!expanded) return;
3722
+ if (!shouldHydrateLogBody(log)) return;
3723
+ if (hydratedLog !== null || bodyHydrationState !== "idle") return;
3724
+ let cancelled = false;
3725
+ setBodyHydrationState("loading");
3726
+ void fetchJson(`/api/logs/${String(log.id)}`, CapturedLogSchema).then((fullLog) => {
3727
+ if (cancelled) return;
3728
+ setHydratedLog(fullLog);
3729
+ setBodyHydrationState("idle");
3730
+ }).catch(() => {
3731
+ if (cancelled) return;
3732
+ setBodyHydrationState("failed");
3733
+ });
3734
+ return () => {
3735
+ cancelled = true;
3736
+ };
3737
+ }, [bodyHydrationState, expanded, hydratedLog, log.bodyContentMode, log.id]);
3709
3738
  reactExports.useEffect(() => {
3710
3739
  const handleLogFocusRequest = (event) => {
3711
3740
  const request = readLogFocusRequest(event);
@@ -3724,7 +3753,7 @@ const LogEntry = reactExports.memo(function({
3724
3753
  /* @__PURE__ */ jsxRuntimeExports.jsx(
3725
3754
  LogEntryHeader,
3726
3755
  {
3727
- log,
3756
+ log: displayLog,
3728
3757
  messageCount: requestAnalysis.messageCount,
3729
3758
  toolCount: requestAnalysis.toolCount,
3730
3759
  expanded,
@@ -3749,15 +3778,17 @@ const LogEntry = reactExports.memo(function({
3749
3778
  viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }),
3750
3779
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
3751
3780
  ] }),
3752
- shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: log.rawRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : rawRequestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3781
+ shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-request", children: activeTab === "raw-request" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: displayLog.rawRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : rawRequestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3753
3782
  LazyJsonViewer,
3754
3783
  {
3755
3784
  data: rawRequestExpansion.parsedData,
3756
3785
  bulkDepth: rawRequestExpansion.bulkDepth,
3757
3786
  bulkRevision: rawRequestExpansion.bulkRevision
3758
3787
  }
3759
- ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: log.rawRequestBody }) }) }),
3788
+ ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs whitespace-pre-wrap break-words", children: displayLog.rawRequestBody }) }) }),
3760
3789
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "request", children: activeTab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3", children: [
3790
+ bodyHydrationState === "loading" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-3 rounded border border-border bg-muted/30 p-3 text-xs text-muted-foreground", children: "Loading full request and response bodies..." }),
3791
+ bodyHydrationState === "failed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-3 rounded border border-amber-500/30 bg-amber-500/10 p-3 text-xs text-amber-200", children: "Full request and response bodies could not be loaded. Compact metadata is still available." }),
3761
3792
  warnings.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-3 rounded border border-amber-500/30 bg-amber-500/10 p-3 text-xs", children: [
3762
3793
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 font-semibold text-amber-300", children: [
3763
3794
  /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "size-3.5" }),
@@ -3775,7 +3806,7 @@ const LogEntry = reactExports.memo(function({
3775
3806
  requestDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
3776
3807
  RequestDiffContent,
3777
3808
  {
3778
- rawBody: log.rawRequestBody,
3809
+ rawBody: displayLog.rawRequestBody,
3779
3810
  displayedBody: displayedRequestBody,
3780
3811
  emptyLabel: "No transformation applied; raw and sent request bodies are identical."
3781
3812
  }
@@ -3794,8 +3825,8 @@ const LogEntry = reactExports.memo(function({
3794
3825
  LazyRequestAnatomy,
3795
3826
  {
3796
3827
  parsed: requestExpansion.parsedData,
3797
- inputTokens: log.inputTokens ?? null,
3798
- model: log.model,
3828
+ inputTokens: displayLog.inputTokens ?? null,
3829
+ model: displayLog.model,
3799
3830
  segments: anatomySegments,
3800
3831
  onSegmentActivate: jumpToAnatomySegment
3801
3832
  }
@@ -3803,7 +3834,7 @@ const LogEntry = reactExports.memo(function({
3803
3834
  viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "headers", children: activeTab === "headers" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3", children: [
3804
3835
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end gap-2 mb-2", children: shouldShowHeadersDiffButton(
3805
3836
  viewMode,
3806
- log.rawHeaders !== void 0 && Object.keys(log.rawHeaders).length > 0
3837
+ displayLog.rawHeaders !== void 0 && Object.keys(displayLog.rawHeaders).length > 0
3807
3838
  ) && /* @__PURE__ */ jsxRuntimeExports.jsx(
3808
3839
  DiffToggleButton,
3809
3840
  {
@@ -3817,11 +3848,11 @@ const LogEntry = reactExports.memo(function({
3817
3848
  headersDiff ? /* @__PURE__ */ jsxRuntimeExports.jsx(
3818
3849
  HeadersDiffContent,
3819
3850
  {
3820
- rawHeaders: log.rawHeaders,
3821
- headers: log.headers,
3851
+ rawHeaders: displayLog.rawHeaders,
3852
+ headers: displayLog.headers,
3822
3853
  emptyLabel: "No transformation applied; raw and processed headers are identical."
3823
3854
  }
3824
- ) : log.headers && Object.keys(log.headers).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.headers).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
3855
+ ) : displayLog.headers && Object.keys(displayLog.headers).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(displayLog.headers).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
3825
3856
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
3826
3857
  key,
3827
3858
  ":"
@@ -3829,7 +3860,7 @@ const LogEntry = reactExports.memo(function({
3829
3860
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
3830
3861
  ] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No headers captured" })
3831
3862
  ] }) }),
3832
- viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: activeTab === "raw-headers" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: log.rawHeaders && Object.keys(log.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
3863
+ viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw-headers", children: activeTab === "raw-headers" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: displayLog.rawHeaders && Object.keys(displayLog.rawHeaders).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(displayLog.rawHeaders).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
3833
3864
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
3834
3865
  key,
3835
3866
  ":"
@@ -3837,44 +3868,44 @@ const LogEntry = reactExports.memo(function({
3837
3868
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground truncate", title: value, children: value })
3838
3869
  ] }, key)) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No raw headers captured" }) }) }),
3839
3870
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "raw", children: activeTab === "raw" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pt-1 pb-3 space-y-3", children: [
3840
- log.error !== void 0 && log.error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-destructive/50 bg-destructive/10 p-3 text-xs", children: [
3871
+ displayLog.error !== void 0 && displayLog.error !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-destructive/50 bg-destructive/10 p-3 text-xs", children: [
3841
3872
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-destructive mb-1", children: "SSE Error" }),
3842
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: log.error })
3873
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground font-mono", children: displayLog.error })
3843
3874
  ] }),
3844
- log.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3875
+ displayLog.responseText !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3845
3876
  LazyJsonViewerFromString,
3846
3877
  {
3847
- text: log.responseText,
3878
+ text: displayLog.responseText,
3848
3879
  defaultExpandDepth: 0,
3849
3880
  bulkDepth: responseExpansion.bulkDepth,
3850
3881
  bulkRevision: responseExpansion.bulkRevision
3851
3882
  }
3852
3883
  ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No response" }),
3853
- log.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3884
+ displayLog.streaming === true && /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3854
3885
  LazyStreamingChunkSequence,
3855
3886
  {
3856
- logId: log.id,
3857
- truncated: log.streamingChunksPath !== null
3887
+ logId: displayLog.id,
3888
+ truncated: displayLog.streamingChunksPath !== null
3858
3889
  }
3859
3890
  ) })
3860
3891
  ] }) }),
3861
3892
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "parsed", children: activeTab === "parsed" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pt-1 pb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3862
3893
  LazyResponseView,
3863
3894
  {
3864
- responseText: log.responseText,
3865
- responseStatus: log.responseStatus,
3866
- streaming: log.streaming,
3867
- inputTokens: log.inputTokens,
3868
- outputTokens: log.outputTokens,
3869
- cacheCreationInputTokens: log.cacheCreationInputTokens,
3870
- cacheReadInputTokens: log.cacheReadInputTokens,
3895
+ responseText: displayLog.responseText,
3896
+ responseStatus: displayLog.responseStatus,
3897
+ streaming: displayLog.streaming,
3898
+ inputTokens: displayLog.inputTokens,
3899
+ outputTokens: displayLog.outputTokens,
3900
+ cacheCreationInputTokens: displayLog.cacheCreationInputTokens,
3901
+ cacheReadInputTokens: displayLog.cacheReadInputTokens,
3871
3902
  apiFormat: resolvedFormat,
3872
- error: log.error
3903
+ error: displayLog.error
3873
3904
  }
3874
3905
  ) }) }) })
3875
3906
  ] }) })
3876
3907
  ] }),
3877
- /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyReplayDialog, { log, open: replayOpen, onOpenChange: setReplayOpen }) })
3908
+ /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LazyReplayDialog, { log: displayLog, open: replayOpen, onOpenChange: setReplayOpen }) })
3878
3909
  ] });
3879
3910
  });
3880
3911
  function ThreadConnector({
@@ -6217,21 +6248,24 @@ function MemberRow({ row }) {
6217
6248
  const errors = session?.errorCount ?? null;
6218
6249
  const tokens = session?.tokenUsage.total ?? null;
6219
6250
  const firstChunkMs = log?.firstChunkMs ?? null;
6251
+ const sessionLabel = firstNonEmpty(member.label, member.sessionId);
6220
6252
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border last:border-0", children: [
6221
6253
  /* @__PURE__ */ jsxRuntimeExports.jsxs("td", { className: "max-w-56 px-3 py-2", children: [
6222
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
6223
- /* @__PURE__ */ jsxRuntimeExports.jsx(
6224
- "a",
6225
- {
6226
- href: sessionPath,
6227
- target: "_blank",
6228
- rel: "noreferrer",
6229
- className: "min-w-0 truncate font-mono text-xs text-primary hover:underline",
6230
- children: firstNonEmpty(member.label, member.sessionId)
6231
- }
6232
- ),
6233
- /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3 shrink-0 text-muted-foreground" })
6234
- ] }),
6254
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
6255
+ "a",
6256
+ {
6257
+ href: sessionPath,
6258
+ target: "_blank",
6259
+ rel: "noreferrer",
6260
+ className: "inline-flex max-w-full min-w-0 items-center gap-2 rounded-sm font-mono text-xs text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
6261
+ "aria-label": `Open session ${sessionLabel}`,
6262
+ title: `Open session ${sessionLabel}`,
6263
+ children: [
6264
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 truncate", children: sessionLabel }),
6265
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3 shrink-0 text-muted-foreground" })
6266
+ ]
6267
+ }
6268
+ ),
6235
6269
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 truncate text-[11px] text-muted-foreground", children: displayText(member.agent) })
6236
6270
  ] }),
6237
6271
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "max-w-52 px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block truncate", children: providerModel(member) }) }),
@@ -8450,6 +8484,7 @@ function SettingsDialog() {
8450
8484
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "providers", children: "Providers" }),
8451
8485
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "proxy", children: "Proxy" }),
8452
8486
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "storage", children: "Storage" }),
8487
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "mcp", children: "MCP" }),
8453
8488
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "onboarding", children: "Onboarding" })
8454
8489
  ] }),
8455
8490
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 flex-1 overflow-x-hidden overflow-y-auto pr-3", children: [
@@ -8471,6 +8506,7 @@ function SettingsDialog() {
8471
8506
  ) }),
8472
8507
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "proxy", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProxySettingsTab, {}) }),
8473
8508
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "storage", children: /* @__PURE__ */ jsxRuntimeExports.jsx(StorageSettingsTab, {}) }),
8509
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "mcp", children: /* @__PURE__ */ jsxRuntimeExports.jsx(McpSettingsTab, {}) }),
8474
8510
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "onboarding", children: /* @__PURE__ */ jsxRuntimeExports.jsx(OnboardingSettingsTab, {}) })
8475
8511
  ] })
8476
8512
  ] })
@@ -8720,6 +8756,129 @@ function OnboardingSettingsTab() {
8720
8756
  ] })
8721
8757
  ] });
8722
8758
  }
8759
+ function McpSettingsTab() {
8760
+ const [copiedId, setCopiedId] = reactExports.useState(null);
8761
+ const origin = reactExports.useMemo(() => {
8762
+ if (typeof window === "undefined") return "http://localhost:25947";
8763
+ return window.location.origin;
8764
+ }, []);
8765
+ const endpoint = `${origin}/api/mcp`;
8766
+ const values = reactExports.useMemo(
8767
+ () => [
8768
+ { id: "mcp-url", label: "Streamable HTTP MCP URL", value: endpoint },
8769
+ {
8770
+ id: "stdio",
8771
+ label: "Stdio bridge command",
8772
+ value: `agent-inspector-mcp stdio --url ${endpoint}`
8773
+ },
8774
+ {
8775
+ id: "doctor",
8776
+ label: "Bridge doctor",
8777
+ value: `agent-inspector-mcp doctor --url ${endpoint}`
8778
+ },
8779
+ {
8780
+ id: "readonly",
8781
+ label: "Readonly mode",
8782
+ value: "AGENT_INSPECTOR_MCP_READONLY=1 agent-inspector"
8783
+ },
8784
+ {
8785
+ id: "capabilities",
8786
+ label: "Capabilities resource",
8787
+ value: "inspector://mcp/capabilities"
8788
+ },
8789
+ {
8790
+ id: "context",
8791
+ label: "Current context resource",
8792
+ value: "inspector://context/current"
8793
+ },
8794
+ {
8795
+ id: "streamable-json",
8796
+ label: "Streamable HTTP JSON",
8797
+ value: JSON.stringify(
8798
+ {
8799
+ mcpServers: {
8800
+ "agent-inspector": {
8801
+ type: "streamableHttp",
8802
+ url: endpoint
8803
+ }
8804
+ }
8805
+ },
8806
+ null,
8807
+ 2
8808
+ )
8809
+ },
8810
+ {
8811
+ id: "stdio-json",
8812
+ label: "Stdio MCP JSON",
8813
+ value: JSON.stringify(
8814
+ {
8815
+ mcpServers: {
8816
+ "agent-inspector": {
8817
+ command: "agent-inspector-mcp",
8818
+ args: ["stdio", "--url", endpoint]
8819
+ }
8820
+ }
8821
+ },
8822
+ null,
8823
+ 2
8824
+ )
8825
+ },
8826
+ {
8827
+ id: "opencode-local",
8828
+ label: "OpenCode local MCP",
8829
+ value: JSON.stringify(
8830
+ {
8831
+ mcp: {
8832
+ "agent-inspector": {
8833
+ type: "local",
8834
+ command: ["agent-inspector-mcp", "stdio", "--url", endpoint],
8835
+ enabled: true
8836
+ }
8837
+ }
8838
+ },
8839
+ null,
8840
+ 2
8841
+ )
8842
+ },
8843
+ {
8844
+ id: "codex-toml",
8845
+ label: "Codex TOML",
8846
+ value: `[mcp_servers.agent-inspector]
8847
+ command = "agent-inspector-mcp"
8848
+ args = ["stdio", "--url", "${endpoint}"]`
8849
+ }
8850
+ ],
8851
+ [endpoint]
8852
+ );
8853
+ const handleCopy = reactExports.useCallback((id, value) => {
8854
+ void copyTextToClipboard(value).then((success) => {
8855
+ if (!success) return;
8856
+ setCopiedId(id);
8857
+ setTimeout(() => setCopiedId(null), 1600);
8858
+ });
8859
+ }, []);
8860
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 space-y-4", children: [
8861
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
8862
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "size-4 text-muted-foreground" }),
8863
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold", children: "MCP access" })
8864
+ ] }),
8865
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2 rounded-md border border-border bg-background px-3 py-2 text-xs text-muted-foreground", children: [
8866
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Use Streamable HTTP when the client supports URL-based MCP. Use the stdio bridge only for stdio-only clients. Configure one entry for the same Inspector instance." }),
8867
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "If the MCP client runs in another container or host, replace localhost with a reachable host/IP and verify the network path." })
8868
+ ] }),
8869
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-2", children: values.map((item) => /* @__PURE__ */ jsxRuntimeExports.jsx(
8870
+ CopyableSetupValue,
8871
+ {
8872
+ id: item.id,
8873
+ label: item.label,
8874
+ value: item.value,
8875
+ copiedId,
8876
+ onCopy: handleCopy
8877
+ },
8878
+ item.id
8879
+ )) })
8880
+ ] });
8881
+ }
8723
8882
  function ProxySettingsTab() {
8724
8883
  const {
8725
8884
  strip,
@@ -10173,6 +10332,99 @@ function formatContextWindow(summary) {
10173
10332
  if (tokens === null) return "Context window unknown";
10174
10333
  return `Context window ${formatContextWindowTokens(tokens)}`;
10175
10334
  }
10335
+ const MEMBER_METADATA_KEYS = [
10336
+ "score",
10337
+ "decision",
10338
+ "final_status",
10339
+ "validation_pass_ratio",
10340
+ "semantic_memory_score",
10341
+ "opencode_exit",
10342
+ "actual_model",
10343
+ "run_dir",
10344
+ "workspace",
10345
+ "project_dir",
10346
+ "work_dir"
10347
+ ];
10348
+ function formatMetadataValue(value) {
10349
+ if (typeof value === "string") return value.length > 0 ? value : null;
10350
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
10351
+ if (value === null) return null;
10352
+ return JSON.stringify(value);
10353
+ }
10354
+ function getMemberMetadataRows(member) {
10355
+ const rows = [];
10356
+ for (const key of MEMBER_METADATA_KEYS) {
10357
+ const value = member.metadata[key];
10358
+ if (value === void 0) continue;
10359
+ const formatted = formatMetadataValue(value);
10360
+ if (formatted !== null) rows.push({ key, value: formatted });
10361
+ }
10362
+ return rows;
10363
+ }
10364
+ function SessionMembershipPanel({
10365
+ memberships
10366
+ }) {
10367
+ if (memberships.length === 0) return null;
10368
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 rounded-md border border-border bg-muted/10 px-3 py-2 text-xs", children: [
10369
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
10370
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold text-foreground", children: "Group Member Evidence" }),
10371
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-mono text-[10px] text-muted-foreground", children: [
10372
+ memberships.length,
10373
+ " group",
10374
+ memberships.length === 1 ? "" : "s"
10375
+ ] })
10376
+ ] }),
10377
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: memberships.map((membership) => {
10378
+ const member = membership.member;
10379
+ const metadataRows = getMemberMetadataRows(member);
10380
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
10381
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
10382
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
10383
+ "span",
10384
+ {
10385
+ className: "truncate font-medium text-foreground",
10386
+ title: membership.groupTitle,
10387
+ children: membership.groupTitle
10388
+ }
10389
+ ),
10390
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-[10px] uppercase text-muted-foreground", children: membership.groupStatus }),
10391
+ member.status !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-muted-foreground", children: [
10392
+ "member ",
10393
+ member.status
10394
+ ] })
10395
+ ] }),
10396
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-muted-foreground", children: [
10397
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", title: member.sessionId, children: truncateSessionId(member.sessionId) }),
10398
+ member.label !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: member.label }),
10399
+ member.provider !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: member.provider }),
10400
+ member.model !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: member.model }),
10401
+ member.runId !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", title: member.runId, children: [
10402
+ "run ",
10403
+ truncateSessionId(member.runId)
10404
+ ] })
10405
+ ] }),
10406
+ metadataRows.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 grid gap-1 sm:grid-cols-2 xl:grid-cols-3", children: metadataRows.map((row) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
10407
+ "div",
10408
+ {
10409
+ className: "min-w-0 rounded border border-border/60 px-2 py-1",
10410
+ children: [
10411
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-mono text-[10px] text-muted-foreground", children: row.key }),
10412
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
10413
+ "div",
10414
+ {
10415
+ className: "truncate font-mono text-[11px] text-foreground",
10416
+ title: row.value,
10417
+ children: row.value
10418
+ }
10419
+ )
10420
+ ]
10421
+ },
10422
+ row.key
10423
+ )) })
10424
+ ] }, `${membership.groupId}:${member.id}`);
10425
+ }) })
10426
+ ] });
10427
+ }
10176
10428
  function formatRequestCount(count) {
10177
10429
  return `${count} ${count === 1 ? "request" : "requests"}`;
10178
10430
  }
@@ -10578,6 +10830,8 @@ function ProxyViewer({
10578
10830
  strip,
10579
10831
  slowResponseThresholdSeconds,
10580
10832
  timeDisplayFormat,
10833
+ isLoading = false,
10834
+ sessionMemberships = [],
10581
10835
  hideSessionFilter = false,
10582
10836
  pinnedSessionId
10583
10837
  }) {
@@ -10731,6 +10985,7 @@ function ProxyViewer({
10731
10985
  showBackLink: sessionContextScope.showBackLink
10732
10986
  }
10733
10987
  ),
10988
+ hasSessionContext && pinnedSessionId !== void 0 && sessionMemberships.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(SessionMembershipPanel, { memberships: sessionMemberships }),
10734
10989
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
10735
10990
  !hideSessionFilter && /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: selectedSession, onValueChange: onSessionChange, children: [
10736
10991
  /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "flex-1 max-w-[350px] text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "All sessions" }) }),
@@ -10822,9 +11077,10 @@ function ProxyViewer({
10822
11077
  exportError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-4 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: exportError })
10823
11078
  ] }),
10824
11079
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: logs.length === 0 ? selectedSession !== "__all__" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
10825
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: "Session not found" }),
11080
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: isLoading ? "Loading session data..." : "Session not found" }),
10826
11081
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs font-mono bg-muted px-3 py-1 rounded inline-block max-w-[500px] break-all", children: truncateSessionId(selectedSession) }),
10827
- /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs", children: [
11082
+ sessionMemberships.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto max-w-3xl text-left", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SessionMembershipPanel, { memberships: sessionMemberships }) }),
11083
+ !isLoading && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs", children: [
10828
11084
  "This session may have been cleared or never existed.",
10829
11085
  " ",
10830
11086
  hideSessionFilter ? /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "/", className: "underline hover:text-foreground transition-colors", children: "Back to all sessions" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -10882,6 +11138,25 @@ const SSEUpdateSchema = union([
10882
11138
  log: CapturedLogSchema
10883
11139
  })
10884
11140
  ]);
11141
+ function buildSessionMembershipEvidence(groups, sessionId) {
11142
+ const memberships = [];
11143
+ for (const group of groups) {
11144
+ for (const member of group.members) {
11145
+ if (member.sessionId !== sessionId) continue;
11146
+ memberships.push({
11147
+ groupId: group.id,
11148
+ groupTitle: group.title,
11149
+ groupKind: group.kind,
11150
+ groupStatus: group.status,
11151
+ groupTask: group.task,
11152
+ groupProject: group.project,
11153
+ groupEvidence: group.evidence,
11154
+ member
11155
+ });
11156
+ }
11157
+ }
11158
+ return memberships;
11159
+ }
10885
11160
  function extractSessions(logs) {
10886
11161
  const set = /* @__PURE__ */ new Set();
10887
11162
  for (const l of logs) {
@@ -10909,9 +11184,13 @@ const HASH_SCROLL_ATTEMPTS = 12;
10909
11184
  const HASH_HIGHLIGHT_MS = 1800;
10910
11185
  const MAX_CLIENT_LOGS = 500;
10911
11186
  function buildLogsStreamUrl(sessionId) {
10912
- if (sessionId === void 0) return "/api/logs/stream";
10913
- const params = new URLSearchParams({ sessionId });
10914
- return `/api/logs/stream?${params.toString()}`;
11187
+ const params = new URLSearchParams();
11188
+ if (sessionId !== void 0) {
11189
+ params.set("sessionId", sessionId);
11190
+ params.set("compact", "1");
11191
+ }
11192
+ const query = params.toString();
11193
+ return query.length > 0 ? `/api/logs/stream?${query}` : "/api/logs/stream";
10915
11194
  }
10916
11195
  function buildLogIndex(logs) {
10917
11196
  const idx = /* @__PURE__ */ new Map();
@@ -10933,6 +11212,8 @@ function ProxyViewerContainer({
10933
11212
  const [selectedModel, setSelectedModel] = reactExports.useState("__all__");
10934
11213
  const [viewMode, setViewMode] = reactExports.useState("simple");
10935
11214
  const [error, setError] = reactExports.useState(null);
11215
+ const [streamInitialized, setStreamInitialized] = reactExports.useState(initialSessionId === void 0);
11216
+ const [sessionMemberships, setSessionMemberships] = reactExports.useState([]);
10936
11217
  const eventSourceRef = reactExports.useRef(null);
10937
11218
  const reconnectTimeoutRef = reactExports.useRef(null);
10938
11219
  const handledHashRef = reactExports.useRef(null);
@@ -10979,6 +11260,7 @@ function ProxyViewerContainer({
10979
11260
  if (eventSourceRef.current) {
10980
11261
  eventSourceRef.current.close();
10981
11262
  }
11263
+ setStreamInitialized(false);
10982
11264
  const es = new EventSource(buildLogsStreamUrl(initialSessionId));
10983
11265
  eventSourceRef.current = es;
10984
11266
  es.onmessage = (event) => {
@@ -11000,6 +11282,7 @@ function ProxyViewerContainer({
11000
11282
  const nextLogs = trimClientLogs(update.logs);
11001
11283
  logIndexRef.current = buildLogIndex(nextLogs);
11002
11284
  setAllLogs(nextLogs);
11285
+ setStreamInitialized(true);
11003
11286
  setError(null);
11004
11287
  } else if (update.type === "update") {
11005
11288
  scheduleUpdate(update.log);
@@ -11010,6 +11293,7 @@ function ProxyViewerContainer({
11010
11293
  };
11011
11294
  es.onerror = () => {
11012
11295
  setError("SSE connection lost, reconnecting...");
11296
+ setStreamInitialized(true);
11013
11297
  es.close();
11014
11298
  if (reconnectTimeoutRef.current !== null) {
11015
11299
  clearTimeout(reconnectTimeoutRef.current);
@@ -11017,6 +11301,27 @@ function ProxyViewerContainer({
11017
11301
  reconnectTimeoutRef.current = setTimeout(connectSSE, 3e3);
11018
11302
  };
11019
11303
  }, [initialSessionId, scheduleUpdate]);
11304
+ reactExports.useEffect(() => {
11305
+ if (initialSessionId === void 0) {
11306
+ setSessionMemberships([]);
11307
+ return;
11308
+ }
11309
+ let cancelled = false;
11310
+ void fetch("/api/groups").then(async (response) => {
11311
+ if (!response.ok) return null;
11312
+ const raw = await response.json();
11313
+ const parsed = InspectorGroupsListResponseSchema.safeParse(raw);
11314
+ return parsed.success ? parsed.data.groups : null;
11315
+ }).then((groups) => {
11316
+ if (cancelled || groups === null) return;
11317
+ setSessionMemberships(buildSessionMembershipEvidence(groups, initialSessionId));
11318
+ }).catch(() => {
11319
+ if (!cancelled) setSessionMemberships([]);
11320
+ });
11321
+ return () => {
11322
+ cancelled = true;
11323
+ };
11324
+ }, [initialSessionId]);
11020
11325
  reactExports.useEffect(() => {
11021
11326
  connectSSE();
11022
11327
  return () => {
@@ -11147,6 +11452,8 @@ function ProxyViewerContainer({
11147
11452
  onModelChange: setSelectedModel,
11148
11453
  onClearAll: handleClearAll,
11149
11454
  onClearGroup: handleClearGroup,
11455
+ isLoading: initialSessionId !== void 0 && !streamInitialized,
11456
+ sessionMemberships,
11150
11457
  viewMode,
11151
11458
  onViewModeChange: setViewMode,
11152
11459
  captureMode,