@tonyclaw/agent-inspector 3.0.26 → 3.0.28

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 (86) hide show
  1. package/.output/cli.js +80 -11
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-SZRUDQc9.js → CompareDrawer-TghZr5t1.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-BJvwOrSi.js → ProxyViewerContainer-fShBAZjj.js} +201 -201
  5. package/.output/public/assets/{ReplayDialog-DgfmqiM3.js → ReplayDialog-CZMApaF4.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-CS6c7Qfn.js → RequestAnatomy-DNWccR7O.js} +1 -1
  7. package/.output/public/assets/{ResponseView-C0Ri_5gm.js → ResponseView-d25MdFhY.js} +2 -2
  8. package/.output/public/assets/{StreamingChunkSequence-7dYcHWyZ.js → StreamingChunkSequence-DIFZEnWe.js} +1 -1
  9. package/.output/public/assets/{_sessionId-D-V84cgw.js → _sessionId-DRfvuE2k.js} +1 -1
  10. package/.output/public/assets/{index-DgFWCxOs.js → index-B3aAuqWq.js} +1 -1
  11. package/.output/public/assets/index-BsxAGqMA.css +1 -0
  12. package/.output/public/assets/{index-DrVJsks2.js → index-D4HkS7Ct.js} +1 -1
  13. package/.output/public/assets/{index-CSIL7-MK.js → index-DzARL2Fi.js} +3 -3
  14. package/.output/public/assets/{json-viewer-C9Ji3gYN.js → json-viewer-wuJSKaed.js} +1 -1
  15. package/.output/server/_libs/lucide-react.mjs +39 -39
  16. package/.output/server/{_sessionId-BQ6YQOO1.mjs → _sessionId-BJTNiP_O.mjs} +4 -2
  17. package/.output/server/_ssr/{CompareDrawer-CqNzIeMR.mjs → CompareDrawer-BMRH3N97.mjs} +5 -3
  18. package/.output/server/_ssr/{ProxyViewerContainer-CMC7Vsbw.mjs → ProxyViewerContainer-AFwcHAIR.mjs} +330 -223
  19. package/.output/server/_ssr/{ReplayDialog-D9p_LaTr.mjs → ReplayDialog-CbWvRHiN.mjs} +6 -4
  20. package/.output/server/_ssr/{RequestAnatomy-B4ge3qNZ.mjs → RequestAnatomy-C4kcPyqN.mjs} +4 -2
  21. package/.output/server/_ssr/{ResponseView-BCqMKApI.mjs → ResponseView-D8VYt-gZ.mjs} +5 -3
  22. package/.output/server/_ssr/{StreamingChunkSequence-BA4zTLE4.mjs → StreamingChunkSequence-BUUo6vU0.mjs} +4 -2
  23. package/.output/server/_ssr/{index-CzxhDjlq.mjs → index-DTwMEEXO.mjs} +4 -2
  24. package/.output/server/_ssr/index.mjs +2 -2
  25. package/.output/server/_ssr/{json-viewer-B3qV6iEJ.mjs → json-viewer-BqF1pSQD.mjs} +5 -3
  26. package/.output/server/_ssr/{router-CZe_R31M.mjs → router-C8BOns7y.mjs} +839 -368
  27. package/.output/server/{_tanstack-start-manifest_v-B50VTLrH.mjs → _tanstack-start-manifest_v-BBf2nRhb.mjs} +1 -1
  28. package/.output/server/index.mjs +70 -70
  29. package/README.md +8 -0
  30. package/package.json +4 -5
  31. package/src/cli.ts +43 -9
  32. package/src/components/ProxyViewer.tsx +57 -1
  33. package/src/components/clients/ClientLogo.tsx +43 -4
  34. package/src/components/inspector-pet/InspectorPet.tsx +0 -7
  35. package/src/components/providers/ProviderCard.tsx +3 -36
  36. package/src/components/providers/ProviderForm.tsx +13 -12
  37. package/src/components/providers/ProvidersPanel.tsx +2 -2
  38. package/src/components/providers/SettingsDialog.tsx +3 -3
  39. package/src/components/proxy-viewer/ConversationGroup.tsx +1 -1
  40. package/src/components/proxy-viewer/ConversationGroupList.tsx +233 -152
  41. package/src/components/proxy-viewer/ConversationHeader.tsx +29 -13
  42. package/src/components/proxy-viewer/ProviderLogoStack.tsx +0 -3
  43. package/src/contracts/anthropic.ts +0 -5
  44. package/src/contracts/index.ts +0 -4
  45. package/src/contracts/log.ts +0 -1
  46. package/src/contracts/openai.ts +0 -3
  47. package/src/knowledge/openclawClient.ts +22 -9
  48. package/src/knowledge/openclawGatewayClient.ts +20 -13
  49. package/src/lib/alertContract.ts +0 -3
  50. package/src/lib/ecosystemContract.ts +0 -3
  51. package/src/lib/export-logs.ts +1 -4
  52. package/src/lib/jsonFile.ts +46 -0
  53. package/src/lib/safeFetch.ts +100 -0
  54. package/src/lib/ssrfGuard.ts +133 -0
  55. package/src/lib/stopReason.ts +1 -4
  56. package/src/lib/unknown.ts +27 -0
  57. package/src/lib/useProviders.ts +1 -1
  58. package/src/mcp/mode.ts +3 -9
  59. package/src/mcp/server.ts +5 -14
  60. package/src/mcp/toolHandlers.ts +45 -54
  61. package/src/proxy/constants.ts +17 -0
  62. package/src/proxy/evidenceAnalysis.ts +116 -117
  63. package/src/proxy/formats/anthropic/handler.ts +5 -1
  64. package/src/proxy/formats/anthropic/schemas.ts +1 -7
  65. package/src/proxy/formats/index.ts +1 -1
  66. package/src/proxy/formats/openai/schemas.ts +0 -3
  67. package/src/proxy/formats/registry.ts +0 -3
  68. package/src/proxy/groupEvidenceExporter.ts +4 -8
  69. package/src/proxy/groupStore.ts +3 -10
  70. package/src/proxy/handler.ts +91 -12
  71. package/src/proxy/identityProxy.ts +74 -1
  72. package/src/proxy/logImporter.ts +82 -12
  73. package/src/proxy/logIndex.ts +1 -4
  74. package/src/proxy/providerSecretStore.ts +177 -0
  75. package/src/proxy/providers.ts +84 -11
  76. package/src/proxy/runFailures.ts +4 -10
  77. package/src/proxy/runStore.ts +4 -11
  78. package/src/proxy/schemas.ts +1 -8
  79. package/src/proxy/sqliteLogIndex.ts +0 -16
  80. package/src/proxy/store.ts +1 -5
  81. package/src/proxy/toolSchemaWarnings.ts +1 -9
  82. package/src/routes/api/logs.$id.replay.ts +17 -5
  83. package/src/routes/api/providers.$providerId.model-metadata.ts +11 -1
  84. package/src/routes/api/providers.$providerId.ts +18 -5
  85. package/src/routes/api/providers.ts +18 -7
  86. package/.output/public/assets/index-CmeF5XXS.css +0 -1
package/.output/cli.js CHANGED
@@ -3038,6 +3038,7 @@ function shouldSuppressServerOutputLine(line, context) {
3038
3038
  // src/proxy/identityProxy.ts
3039
3039
  import http from "node:http";
3040
3040
  import { Buffer as Buffer2 } from "node:buffer";
3041
+ import { timingSafeEqual } from "node:crypto";
3041
3042
 
3042
3043
  // src/proxy/socketTracker.ts
3043
3044
  import { execFile } from "node:child_process";
@@ -17891,6 +17892,31 @@ var RESPONSE_HOP_BY_HOP = /* @__PURE__ */ new Set([
17891
17892
  "transfer-encoding",
17892
17893
  "upgrade"
17893
17894
  ]);
17895
+ function isLoopbackPeer(address) {
17896
+ if (address === void 0) return false;
17897
+ const normalized = address.toLowerCase();
17898
+ return normalized === "::1" || normalized.startsWith("127.") || normalized.startsWith("::ffff:127.");
17899
+ }
17900
+ function bearerToken(authorization) {
17901
+ if (authorization === void 0) return null;
17902
+ const match = /^Bearer\s+(.+)$/i.exec(authorization.trim());
17903
+ return match?.[1] ?? null;
17904
+ }
17905
+ function tokensMatch(received, expected) {
17906
+ if (received === null || expected === void 0 || expected === "") return false;
17907
+ const receivedBuffer = Buffer2.from(received);
17908
+ const expectedBuffer = Buffer2.from(expected);
17909
+ return receivedBuffer.byteLength === expectedBuffer.byteLength && timingSafeEqual(receivedBuffer, expectedBuffer);
17910
+ }
17911
+ function isIdentityProxyRequestAllowed(input) {
17912
+ if (input.options.restrictRemoteControl !== true) return true;
17913
+ if (input.options.allowRemoteControl === true) return true;
17914
+ if (isLoopbackPeer(input.remoteAddress)) return true;
17915
+ const pathname = new URL(input.path, "http://localhost").pathname;
17916
+ if (pathname === "/proxy" || pathname.startsWith("/proxy/")) return true;
17917
+ if (pathname === "/api/health") return true;
17918
+ return tokensMatch(bearerToken(input.authorization), input.options.controlToken);
17919
+ }
17894
17920
  function startIdentityProxy(options) {
17895
17921
  return new Promise((resolve2, reject) => {
17896
17922
  const server = http.createServer();
@@ -17910,13 +17936,30 @@ function startIdentityProxy(options) {
17910
17936
  });
17911
17937
  });
17912
17938
  server.once("error", reject);
17913
- server.listen(options.listenPort, () => {
17939
+ server.listen(options.listenPort, options.listenHost, () => {
17914
17940
  server.removeListener("error", reject);
17915
17941
  resolve2(server);
17916
17942
  });
17917
17943
  });
17918
17944
  }
17919
17945
  async function handleRequest(req, res, options) {
17946
+ if (!isIdentityProxyRequestAllowed({
17947
+ path: req.url ?? "/",
17948
+ remoteAddress: req.socket.remoteAddress,
17949
+ authorization: req.headers.authorization,
17950
+ options
17951
+ })) {
17952
+ res.writeHead(403, {
17953
+ "content-type": "application/json; charset=utf-8",
17954
+ "cache-control": "no-store"
17955
+ });
17956
+ res.end(
17957
+ JSON.stringify({
17958
+ error: "Remote control-plane access is disabled. Use the proxy endpoint or connect locally."
17959
+ })
17960
+ );
17961
+ return;
17962
+ }
17920
17963
  const remotePort = req.socket.remotePort;
17921
17964
  let identity = null;
17922
17965
  if (remotePort !== void 0 && remotePort > 0) {
@@ -17993,6 +18036,7 @@ var __dirname2 = dirname2(__filename2);
17993
18036
  var DEFAULT_PORT3 = 9527;
17994
18037
  var LEGACY_ALIAS_PORT = 9527;
17995
18038
  var DEFAULT_UPSTREAM_PORT = 9529;
18039
+ var DEFAULT_BIND_HOST = "127.0.0.1";
17996
18040
  var LOCAL_PROBE_TIMEOUT_MS = 2e3;
17997
18041
  var BRANDED_WINDOWS_RUNTIME_EXE = "agent-inspector.exe";
17998
18042
  var DEFAULT_CAPTURE_MODE = "simple";
@@ -18143,6 +18187,16 @@ function printAccessHints(port, host) {
18143
18187
  for (const line of formatAccessHintLines(port, networkUrls, host)) {
18144
18188
  console.log(line);
18145
18189
  }
18190
+ if (!isLoopbackHost(host)) {
18191
+ if (process.env["AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL"] === "1") {
18192
+ console.warn(" Control plane: REMOTE ACCESS ENABLED by administrator override");
18193
+ } else {
18194
+ console.log(" Control plane: local only; remote clients may use /proxy");
18195
+ if ((process.env["AGENT_INSPECTOR_CONTROL_TOKEN"] ?? "") !== "") {
18196
+ console.log(" Remote API: Bearer token authentication enabled");
18197
+ }
18198
+ }
18199
+ }
18146
18200
  }
18147
18201
  function buildBackgroundSupervisorArgs(options) {
18148
18202
  const args = ["--no-open", "--port", String(options.port), "--mode", options.captureMode];
@@ -18173,12 +18227,16 @@ function pickUpstreamPort(publicPort, legacyAliasPort) {
18173
18227
  }
18174
18228
  return DEFAULT_UPSTREAM_PORT;
18175
18229
  }
18176
- async function tryStartIdentityProxy(identityPort, upstreamPort, upstreamHost) {
18230
+ async function tryStartIdentityProxy(identityPort, upstreamPort, listenHost, upstreamHost) {
18177
18231
  try {
18178
18232
  const server = await startIdentityProxy({
18179
18233
  listenPort: identityPort,
18180
- upstreamHost: upstreamHost ?? "127.0.0.1",
18181
- upstreamPort
18234
+ listenHost,
18235
+ upstreamHost,
18236
+ upstreamPort,
18237
+ restrictRemoteControl: !isLoopbackHost(listenHost),
18238
+ allowRemoteControl: process.env["AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL"] === "1",
18239
+ controlToken: process.env["AGENT_INSPECTOR_CONTROL_TOKEN"]
18182
18240
  });
18183
18241
  return server;
18184
18242
  } catch (err) {
@@ -18195,7 +18253,7 @@ async function runStart(args) {
18195
18253
  const envHost = process.env["NITRO_HOST"] ?? process.env["HOST"];
18196
18254
  const envMode = process.env["AGENT_INSPECTOR_CAPTURE_MODE"] ?? process.env["AGENT_INSPECTOR_MODE"];
18197
18255
  let port = portDefault;
18198
- let host = envHost !== void 0 && envHost.trim().length > 0 ? envHost.trim() : void 0;
18256
+ let host = envHost !== void 0 && envHost.trim().length > 0 ? envHost.trim() : DEFAULT_BIND_HOST;
18199
18257
  let open = true;
18200
18258
  let openWasSpecified = false;
18201
18259
  let background = false;
@@ -18330,6 +18388,13 @@ async function runStart(args) {
18330
18388
  process.exitCode = 1;
18331
18389
  return;
18332
18390
  }
18391
+ if (!enableIdentityProxy && !isLoopbackHost(host) && process.env["AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL"] !== "1") {
18392
+ console.error(
18393
+ "Refusing an unprotected remote bind with --no-identity-proxy. Keep the identity proxy enabled or set AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL=1 explicitly."
18394
+ );
18395
+ process.exitCode = 1;
18396
+ return;
18397
+ }
18333
18398
  function killProcessOnPort(targetPort) {
18334
18399
  const pids = findPidsByPort(targetPort);
18335
18400
  for (const pid of pids) {
@@ -18339,6 +18404,7 @@ async function runStart(args) {
18339
18404
  }
18340
18405
  const legacyAliasPort = enableIdentityProxy && legacyAliasEnabled && port === DEFAULT_PORT3 ? LEGACY_ALIAS_PORT : null;
18341
18406
  const upstreamPort = enableIdentityProxy ? pickUpstreamPort(port, legacyAliasPort) : port;
18407
+ const upstreamHost = enableIdentityProxy ? DEFAULT_BIND_HOST : host;
18342
18408
  process.env["PORT"] = String(upstreamPort);
18343
18409
  const url2 = urlForHost(port, host);
18344
18410
  if (!forceRestart && await isInspectorHealthy(port, host)) {
@@ -18470,10 +18536,8 @@ async function runStart(args) {
18470
18536
  if (providersJson !== void 0) {
18471
18537
  serverEnv["AGENT_INSPECTOR_PROVIDERS_JSON"] = providersJson;
18472
18538
  }
18473
- if (host !== void 0) {
18474
- serverEnv["HOST"] = host;
18475
- serverEnv["NITRO_HOST"] = host;
18476
- }
18539
+ serverEnv["HOST"] = upstreamHost;
18540
+ serverEnv["NITRO_HOST"] = upstreamHost;
18477
18541
  serverEnv["AGENT_INSPECTOR_PUBLIC_PORT"] = String(port);
18478
18542
  serverEnv["PROXY_PORT"] = String(port);
18479
18543
  serverEnv["AGENT_INSPECTOR_CAPTURE_MODE"] = captureMode;
@@ -18496,12 +18560,17 @@ async function runStart(args) {
18496
18560
  }
18497
18561
  const identityProxies = [];
18498
18562
  if (enableIdentityProxy) {
18499
- const primaryProxy = await tryStartIdentityProxy(port, upstreamPort, host);
18563
+ const primaryProxy = await tryStartIdentityProxy(port, upstreamPort, host, upstreamHost);
18500
18564
  if (primaryProxy !== null) {
18501
18565
  identityProxies.push({ label: "primary", port, server: primaryProxy });
18502
18566
  }
18503
18567
  if (legacyAliasPort !== null) {
18504
- const legacyProxy = await tryStartIdentityProxy(legacyAliasPort, upstreamPort, host);
18568
+ const legacyProxy = await tryStartIdentityProxy(
18569
+ legacyAliasPort,
18570
+ upstreamPort,
18571
+ host,
18572
+ upstreamHost
18573
+ );
18505
18574
  if (legacyProxy !== null) {
18506
18575
  identityProxies.push({ label: "legacy", port: legacyAliasPort, server: legacyProxy });
18507
18576
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "date": "2026-07-11T00:25:10.463Z",
2
+ "date": "2026-07-11T07:25:29.184Z",
3
3
  "preset": "node-server",
4
4
  "framework": {
5
5
  "name": "nitro",
@@ -1 +1 @@
1
- import{r as h,j as t}from"./index-CSIL7-MK.js";import{c as Z,g as $,r as L,a as q,X as ee,b as m,B as te,f as P,R as re,C as ne,M as V,d as _,e as M,h as B,i as se,j as ae,k as oe,L as ie}from"./ProxyViewerContainer-BJvwOrSi.js";const de=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],le=Z("equal",de),ce="";function j(e){if(e.length===0)return ce;let r="";for(let n=0;n<e.length;n++){const a=e[n];a!==void 0&&(typeof a=="number"?r+=`[${a}]`:n===0?r+=a:r+=`.${a}`)}return r}function ue(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function D(e){if(typeof e=="string")try{return C(JSON.parse(e))}catch{return{kind:"primitive",value:e}}return C(e)}function C(e){if(e===null)return{kind:"primitive",value:null};if(typeof e=="string")return{kind:"primitive",value:e};if(typeof e=="number")return{kind:"primitive",value:e};if(typeof e=="boolean")return{kind:"primitive",value:e};if(Array.isArray(e))return{kind:"array",value:e.map(r=>C(r))};if(ue(e)){const r={};for(const n of Object.keys(e).sort())r[n]=C(e[n]);return{kind:"object",value:r}}return{kind:"primitive",value:null}}function xe(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,a){const d=j(e);if(S(r,n)){a.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){a.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){a.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const i=Object.keys(r.value),s=Object.keys(n.value),o=new Set(s);for(const l of i){const f=r.value[l];if(f!==void 0)if(!o.has(l))a.push({kind:"removed",path:j([...e,l]),value:f});else{const p=n.value[l];if(p===void 0)continue;R([...e,l],f,p,a)}}for(const l of s){if(i.includes(l))continue;const f=n.value[l];f!==void 0&&a.push({kind:"added",path:j([...e,l]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const i=Math.min(r.value.length,n.value.length);for(let s=0;s<i;s++){const o=r.value[s],l=n.value[s];o===void 0||l===void 0||R([...e,s],o,l,a)}for(let s=i;s<n.value.length;s++){const o=n.value[s];o!==void 0&&a.push({kind:"added",path:j([...e,s]),value:o})}for(let s=i;s<r.value.length;s++){const o=r.value[s];o!==void 0&&a.push({kind:"removed",path:j([...e,s]),value:o})}}}function S(e,r){if(e.kind!==r.kind)return!1;if(e.kind==="primitive"&&r.kind==="primitive")return e.value===r.value;if(e.kind==="array"&&r.kind==="array"){if(e.value.length!==r.value.length)return!1;for(let n=0;n<e.value.length;n++){const a=e.value[n],d=r.value[n];if(a===void 0||d===void 0||!S(a,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),a=Object.keys(r.value);if(n.length!==a.length)return!1;for(const d of n){const i=e.value[d],s=r.value[d];if(i===void 0||s===void 0||!S(i,s))return!1}return!0}return!1}function v(e,r=80){let n;switch(e.kind){case"primitive":n=e.value===null?"null":JSON.stringify(e.value);break;case"array":n=`[… ${e.value.length} items]`;break;case"object":n=`{… ${Object.keys(e.value).length} keys}`;break}return n.length>r&&(n=`${n.slice(0,r-1)}…`),n}function N(e,r=2){return JSON.stringify(E(e),null,r)}function E(e){switch(e.kind){case"primitive":return e.value;case"array":return e.value.map(E);case"object":{const r={};for(const[n,a]of Object.entries(e.value))r[n]=E(a);return r}}}function w({text:e,defaultExpandDepth:r}){return t.jsx(h.Suspense,{fallback:t.jsx("div",{className:"text-xs text-muted-foreground",children:"Loading JSON..."}),children:t.jsx(ie,{text:e,defaultExpandDepth:r})})}function K(e){if(e==="")return"";for(let r=e.length-1;r>=0;r--){const n=e[r];if(n==="."||n==="[")return e.substring(0,r)}return""}function A(e){return e.kind==="equal"&&(e.value.kind==="object"||e.value.kind==="array")}function me(e){const r=[];let n=0;for(;n<e.length;){const a=e[n];if(a!==void 0&&A(a)){const d=K(a.path);let i=n+1;for(;i<e.length;){const s=e[i];if(s===void 0||!A(s)||K(s.path)!==d)break;i++}if(i-n>1){const s=[];for(let o=n;o<i;o++){const l=e[o];l!==void 0&&l.kind==="equal"&&s.push(l)}r.push({kind:"equal-run",ops:s}),n=i;continue}}a!==void 0&&r.push({kind:"single",op:a}),n++}return r}const F={added:{icon:_,accent:"text-emerald-600 dark:text-emerald-400",bg:"bg-emerald-500/5 hover:bg-emerald-500/10",border:"border-l-emerald-500",label:"ADDED"},removed:{icon:V,accent:"text-rose-600 dark:text-rose-400",bg:"bg-rose-500/5 hover:bg-rose-500/10",border:"border-l-rose-500",label:"REMOVED"},changed:{icon:M,accent:"text-amber-600 dark:text-amber-400",bg:"bg-amber-500/5 hover:bg-amber-500/10",border:"border-l-amber-500",label:"CHANGED"},equal:{icon:le,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function fe({ops:e,expanded:r,onToggle:n}){const a=e[0],d=e[e.length-1];if(a===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const i=a.path,s=d.path,o=e.length===1?i:`${i} … ${s}`,l=a.value.kind==="array"?`${e.length} equal arrays`:a.value.kind==="object"?`${e.length} equal objects`:"equal",f=F.equal;return t.jsxs("div",{className:m("border-l-4 rounded-sm",f.border,f.bg),children:[t.jsxs("button",{type:"button",onClick:n,className:"w-full text-left flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground cursor-pointer",children:[t.jsx(B,{className:m("size-3 transition-transform shrink-0",r&&"rotate-90")}),t.jsx(f.icon,{className:m("size-3 shrink-0",f.accent)}),t.jsx("span",{className:"font-mono truncate flex-1",title:`${i} … ${s}`,children:o}),t.jsx("span",{className:m("text-[10px] uppercase tracking-wider shrink-0",f.accent),children:f.label}),t.jsxs("span",{className:"text-muted-foreground/60 shrink-0",children:["(",l,")"]})]}),r&&t.jsx("div",{className:"ml-5 mt-1 mb-2 space-y-2 pr-2",children:e.map(p=>t.jsxs("div",{className:"border border-border/50 rounded p-2 bg-muted/20",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:p.path}),t.jsx(w,{text:N(p.value),defaultExpandDepth:0})]},p.path))})]})}function pe({op:e,idx:r,copiedPath:n,onCopyPath:a,expanded:d,onToggle:i}){const s=F[e.kind],o=s.icon,l=e.kind==="added"||e.kind==="removed"?e.value.kind==="object"||e.value.kind==="array":e.kind==="changed"?e.left.kind==="object"||e.left.kind==="array"||e.right.kind==="object"||e.right.kind==="array":!1,f=e.kind==="changed"?[{text:v(e.left,400),tone:"text-rose-700 dark:text-rose-300 line-through"},{text:v(e.right,400),tone:"text-emerald-700 dark:text-emerald-300"}]:e.kind==="removed"?[{text:v(e.value,400),tone:"text-rose-700 dark:text-rose-300 line-through"}]:e.kind==="added"?[{text:v(e.value,400),tone:"text-emerald-700 dark:text-emerald-300"}]:[{text:v(e.value,400),tone:"text-muted-foreground"}],p=n===e.path&&e.path!=="";return t.jsxs("div",{"data-diff-idx":r,"data-diff-kind":e.kind,className:m("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors",s.border,s.bg),children:[t.jsxs("button",{type:"button",onClick:i,disabled:!l,className:m("w-full flex items-center gap-2 text-xs text-left rounded-sm",l?"cursor-pointer":"cursor-default"),"aria-expanded":l?d:void 0,"aria-label":l?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[l?t.jsx(B,{className:m("size-3 shrink-0 transition-transform",s.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(o,{className:m("size-3.5 shrink-0",s.accent),strokeWidth:2.5}),t.jsx("span",{className:"font-mono truncate flex-1 min-w-0",title:e.path||"(root)",children:e.path===""?"(root)":e.path}),t.jsx("span",{className:m("text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",s.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:s.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),a(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),a(e.path))},className:m("shrink-0 p-1 rounded transition-colors cursor-pointer inline-flex items-center justify-center",p?"text-emerald-500":"text-muted-foreground/50 hover:text-foreground hover:bg-muted"),"aria-label":p?"Copied":"Copy",title:p?"Copied!":"Copy",children:p?t.jsx(se,{className:"size-3"}):t.jsx(ae,{className:"size-3"})})]}),f.map((b,y)=>t.jsx("div",{className:m("font-mono text-xs mt-1 break-all pl-5",b.tone),children:b.text},y)),t.jsx("div",{className:"overflow-hidden transition-all duration-200",style:{maxHeight:d&&l?"2000px":"0"},"aria-hidden":!d,children:d&&l&&e.kind!=="equal"?t.jsx(he,{op:e}):null})]})}function he({op:e}){if(e.kind==="added"||e.kind==="removed")return t.jsx("div",{className:"pl-5 mt-2 border border-border/50 rounded p-2 bg-muted/20",children:t.jsx(w,{text:N(e.value),defaultExpandDepth:0})});const r=e.left.kind==="object"||e.left.kind==="array",n=e.right.kind==="object"||e.right.kind==="array";return!r&&!n?t.jsx("div",{className:"pl-5 mt-2 text-xs text-muted-foreground/70 italic",children:"Primitive values are shown inline above."}):t.jsxs("div",{className:"pl-5 mt-2 grid grid-cols-1 md:grid-cols-2 gap-2",children:[t.jsxs("div",{className:"border border-rose-500/30 rounded p-2 bg-rose-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-rose-500 mb-1",children:"Old"}),t.jsx(w,{text:N(e.left),defaultExpandDepth:0})]}),t.jsxs("div",{className:"border border-emerald-500/30 rounded p-2 bg-emerald-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-emerald-500 mb-1",children:"New"}),t.jsx(w,{text:N(e.right),defaultExpandDepth:0})]})]})}function be({counts:e,onJumpTo:r}){const n=e.added+e.removed+e.changed;return t.jsxs("div",{className:"px-4 py-2 border-b border-border bg-muted/20 flex items-center gap-2 text-xs flex-wrap",children:[t.jsxs("span",{className:"text-muted-foreground font-medium",children:[n," ",n===1?"change":"changes"]}),t.jsxs("button",{type:"button",onClick:()=>r("removed"),disabled:e.removed===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.removed>0?"border-rose-500/40 text-rose-600 dark:text-rose-400 bg-rose-500/10 hover:bg-rose-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.removed>0?"Jump to first removed":"No removals",children:[t.jsx(V,{className:"size-3"}),e.removed," removed"]}),t.jsxs("button",{type:"button",onClick:()=>r("added"),disabled:e.added===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.added>0?"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.added>0?"Jump to first added":"No additions",children:[t.jsx(_,{className:"size-3"}),e.added," added"]}),t.jsxs("button",{type:"button",onClick:()=>r("changed"),disabled:e.changed===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.changed>0?"border-amber-500/40 text-amber-600 dark:text-amber-400 bg-amber-500/10 hover:bg-amber-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.changed>0?"Jump to first changed":"No changes",children:[t.jsx(M,{className:"size-3"}),e.changed," changed"]})]})}function ve({mode:e,onChange:r}){return t.jsxs("div",{className:"inline-flex rounded-md border border-border overflow-hidden",children:[t.jsxs("button",{type:"button",onClick:()=>r("unified"),"aria-pressed":e==="unified",className:m("flex items-center gap-1 px-2 py-1 text-xs transition-colors cursor-pointer",e==="unified"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Unified view (single column, emphasized diffs)",children:[t.jsx(re,{className:"size-3"}),"Unified"]}),t.jsxs("button",{type:"button",onClick:()=>r("split"),"aria-pressed":e==="split",className:m("flex items-center gap-1 px-2 py-1 text-xs transition-colors border-l border-border cursor-pointer",e==="split"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Split view (path | left | right)",children:[t.jsx(ne,{className:"size-3"}),"Split"]})]})}function J({log:e,side:r,displayNumber:n}){const a=q(e);return t.jsxs("div",{className:"flex-1 min-w-0 space-y-1 text-xs",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(te,{variant:"outline",className:m("text-[10px] px-1.5 py-0 h-5 font-mono shrink-0",r==="left"?"border-rose-500/40 text-rose-400":"border-emerald-500/40 text-emerald-400"),children:r==="left"?"← Left":"Right →"}),t.jsxs("span",{className:"font-mono text-blue-400/80",title:`Log ID ${String(e.id)}`,children:["#",n]}),e.model!==null&&t.jsx("span",{className:"font-mono leading-snug text-muted-foreground",children:e.model})]}),t.jsxs("div",{className:"flex items-center gap-3 text-muted-foreground font-mono",children:[e.cacheCreationInputTokens!==null&&e.cacheCreationInputTokens>0&&t.jsxs("span",{className:"text-emerald-400",children:["KV Cache +",P(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["KV Cache ~",P(e.cacheReadInputTokens)]}),t.jsx("span",{className:"truncate",title:e.timestamp,children:e.timestamp})]}),t.jsxs("div",{className:"text-muted-foreground/70 font-mono truncate",title:a,children:["session: ",a]})]})}function ye({left:e,right:r,leftDisplayNumber:n,rightDisplayNumber:a,onClose:d}){const i=h.useMemo(()=>{const c=$(L(e)).analyzeRequest(e.rawRequestBody),u=$(L(r)).analyzeRequest(r.rawRequestBody),x=D(c.comparisonValue),g=D(u.comparisonValue);return xe(x,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),s=h.useMemo(()=>me(i),[i]),o=h.useMemo(()=>{let c=0,u=0,x=0;for(const g of s)if(g.kind==="single")switch(g.op.kind){case"added":c++;break;case"removed":u++;break;case"changed":x++;break}return{added:c,removed:u,changed:x}},[s]),[l,f]=h.useState(new Set),p=c=>{f(u=>{const x=new Set(u);return x.has(c)?x.delete(c):x.add(c),x})},[b,y]=h.useState(new Set),U=c=>{y(u=>{const x=new Set(u);return x.has(c)?x.delete(c):x.add(c),x})};h.useEffect(()=>{y(new Set)},[e.id,r.id]);const[T,H]=h.useState("unified"),I=h.useRef(null),[G,z]=h.useState(null),k=h.useRef(null),Q=c=>{oe(c).then(u=>{u&&(z(c),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500))})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const W=c=>{const u=s.findIndex(O=>O.kind==="single"&&O.op.kind===c);if(u===-1)return;const x=I.current;if(x===null)return;const g=x.querySelector(`[data-diff-idx="${u}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const c=x=>{x.key==="Escape"&&d()};document.addEventListener("keydown",c);const u=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",c),document.body.style.overflow=u}},[d]);const X=q(e)===q(r),Y=i.length===1&&i[0]?.kind==="equal";return t.jsxs("div",{className:"fixed inset-0 z-50 flex justify-end",role:"dialog","aria-modal":"true","aria-label":"Compare two log requests",children:[t.jsx("button",{type:"button",onClick:d,"aria-label":"Close compare drawer",className:"absolute inset-0 bg-black/40 cursor-default",tabIndex:-1}),t.jsxs("div",{className:m("relative bg-background border-l border-border shadow-xl","w-full md:w-[70vw] max-w-[1100px] flex flex-col h-full"),onClick:c=>c.stopPropagation(),onKeyDown:c=>c.stopPropagation(),children:[t.jsxs("div",{className:"flex items-start gap-4 px-4 py-3 border-b border-border",children:[t.jsxs("div",{className:"flex-1 flex gap-4 min-w-0",children:[t.jsx(J,{log:e,side:"left",displayNumber:n}),t.jsx(J,{log:r,side:"right",displayNumber:a})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(ve,{mode:T,onChange:H}),t.jsx("button",{type:"button",onClick:d,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(ee,{className:"size-4"})})]})]}),!X&&t.jsx("div",{className:"px-4 py-1.5 text-xs text-amber-400 bg-amber-500/10 border-b border-border",children:"Heads up: the two selected logs are from different sessions."}),Y?t.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto flex items-center justify-center text-muted-foreground text-sm",children:"The two Request payloads are identical."}):t.jsxs(t.Fragment,{children:[t.jsx(be,{counts:o,onJumpTo:W}),t.jsx("div",{ref:I,className:"flex-1 min-h-0 overflow-y-auto",children:T==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:s.map((c,u)=>{if(c.kind==="equal-run")return t.jsx(fe,{ops:c.ops,expanded:l.has(u),onToggle:()=>p(u)},`r${u}`);const x=c.op;return t.jsx(pe,{op:x,idx:u,copiedPath:G,onCopyPath:Q,expanded:b.has(u),onToggle:()=>U(u)},`o${u}`)})}):t.jsx(ge,{grouped:s,left:e,right:r,leftDisplayNumber:n,rightDisplayNumber:a})})]})]})]})}function ge({grouped:e,left:r,right:n,leftDisplayNumber:a,rightDisplayNumber:d}){return t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 gap-y-0.5 px-3 py-2 text-xs",children:[t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 col-span-3 pb-2 mb-2 border-b border-border text-[10px] uppercase tracking-wider text-muted-foreground",children:[t.jsx("span",{children:"Path"}),t.jsxs("span",{title:`Log ID ${String(r.id)}`,children:["Left (Log #",a,")"]}),t.jsxs("span",{title:`Log ID ${String(n.id)}`,children:["Right (Log #",d,")"]})]}),e.map((i,s)=>{if(i.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[i.ops.length," equal siblings collapsed — switch to Unified to expand"]},s);const o=i.op;return o.kind==="equal"?t.jsxs("div",{className:"col-span-3 grid grid-cols-[200px_1fr_1fr] gap-x-2 px-2 py-0.5 text-muted-foreground",children:[t.jsx("span",{className:"font-mono text-xs truncate",title:o.path,children:o.path}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)})]},s):o.kind==="added"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-emerald-400/70 bg-emerald-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-emerald-300/90",children:["+ ",v(o.value,400)]})]},s):o.kind==="removed"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-rose-400/70 bg-rose-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-rose-300/90 line-through",children:["− ",v(o.value,400)]})]},s):t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-amber-400/70 bg-amber-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:o.path}),t.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[t.jsx("div",{className:"font-mono text-rose-300/90 break-all line-through",children:v(o.left,400)}),t.jsx("div",{className:"font-mono text-emerald-300/90 break-all",children:v(o.right,400)})]})]},s)})]})}export{ye as CompareDrawer};
1
+ import{r as h,j as t}from"./index-DzARL2Fi.js";import{c as Z,g as $,r as L,a as q,X as ee,b as m,B as te,f as P,R as re,C as ne,M as V,d as _,e as M,h as B,i as se,j as ae,k as oe,L as ie}from"./ProxyViewerContainer-fShBAZjj.js";const de=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],le=Z("equal",de),ce="";function j(e){if(e.length===0)return ce;let r="";for(let n=0;n<e.length;n++){const a=e[n];a!==void 0&&(typeof a=="number"?r+=`[${a}]`:n===0?r+=a:r+=`.${a}`)}return r}function ue(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function D(e){if(typeof e=="string")try{return C(JSON.parse(e))}catch{return{kind:"primitive",value:e}}return C(e)}function C(e){if(e===null)return{kind:"primitive",value:null};if(typeof e=="string")return{kind:"primitive",value:e};if(typeof e=="number")return{kind:"primitive",value:e};if(typeof e=="boolean")return{kind:"primitive",value:e};if(Array.isArray(e))return{kind:"array",value:e.map(r=>C(r))};if(ue(e)){const r={};for(const n of Object.keys(e).sort())r[n]=C(e[n]);return{kind:"object",value:r}}return{kind:"primitive",value:null}}function xe(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,a){const d=j(e);if(S(r,n)){a.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){a.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){a.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const i=Object.keys(r.value),s=Object.keys(n.value),o=new Set(s);for(const l of i){const f=r.value[l];if(f!==void 0)if(!o.has(l))a.push({kind:"removed",path:j([...e,l]),value:f});else{const p=n.value[l];if(p===void 0)continue;R([...e,l],f,p,a)}}for(const l of s){if(i.includes(l))continue;const f=n.value[l];f!==void 0&&a.push({kind:"added",path:j([...e,l]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const i=Math.min(r.value.length,n.value.length);for(let s=0;s<i;s++){const o=r.value[s],l=n.value[s];o===void 0||l===void 0||R([...e,s],o,l,a)}for(let s=i;s<n.value.length;s++){const o=n.value[s];o!==void 0&&a.push({kind:"added",path:j([...e,s]),value:o})}for(let s=i;s<r.value.length;s++){const o=r.value[s];o!==void 0&&a.push({kind:"removed",path:j([...e,s]),value:o})}}}function S(e,r){if(e.kind!==r.kind)return!1;if(e.kind==="primitive"&&r.kind==="primitive")return e.value===r.value;if(e.kind==="array"&&r.kind==="array"){if(e.value.length!==r.value.length)return!1;for(let n=0;n<e.value.length;n++){const a=e.value[n],d=r.value[n];if(a===void 0||d===void 0||!S(a,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),a=Object.keys(r.value);if(n.length!==a.length)return!1;for(const d of n){const i=e.value[d],s=r.value[d];if(i===void 0||s===void 0||!S(i,s))return!1}return!0}return!1}function v(e,r=80){let n;switch(e.kind){case"primitive":n=e.value===null?"null":JSON.stringify(e.value);break;case"array":n=`[… ${e.value.length} items]`;break;case"object":n=`{… ${Object.keys(e.value).length} keys}`;break}return n.length>r&&(n=`${n.slice(0,r-1)}…`),n}function N(e,r=2){return JSON.stringify(E(e),null,r)}function E(e){switch(e.kind){case"primitive":return e.value;case"array":return e.value.map(E);case"object":{const r={};for(const[n,a]of Object.entries(e.value))r[n]=E(a);return r}}}function w({text:e,defaultExpandDepth:r}){return t.jsx(h.Suspense,{fallback:t.jsx("div",{className:"text-xs text-muted-foreground",children:"Loading JSON..."}),children:t.jsx(ie,{text:e,defaultExpandDepth:r})})}function K(e){if(e==="")return"";for(let r=e.length-1;r>=0;r--){const n=e[r];if(n==="."||n==="[")return e.substring(0,r)}return""}function A(e){return e.kind==="equal"&&(e.value.kind==="object"||e.value.kind==="array")}function me(e){const r=[];let n=0;for(;n<e.length;){const a=e[n];if(a!==void 0&&A(a)){const d=K(a.path);let i=n+1;for(;i<e.length;){const s=e[i];if(s===void 0||!A(s)||K(s.path)!==d)break;i++}if(i-n>1){const s=[];for(let o=n;o<i;o++){const l=e[o];l!==void 0&&l.kind==="equal"&&s.push(l)}r.push({kind:"equal-run",ops:s}),n=i;continue}}a!==void 0&&r.push({kind:"single",op:a}),n++}return r}const F={added:{icon:_,accent:"text-emerald-600 dark:text-emerald-400",bg:"bg-emerald-500/5 hover:bg-emerald-500/10",border:"border-l-emerald-500",label:"ADDED"},removed:{icon:V,accent:"text-rose-600 dark:text-rose-400",bg:"bg-rose-500/5 hover:bg-rose-500/10",border:"border-l-rose-500",label:"REMOVED"},changed:{icon:M,accent:"text-amber-600 dark:text-amber-400",bg:"bg-amber-500/5 hover:bg-amber-500/10",border:"border-l-amber-500",label:"CHANGED"},equal:{icon:le,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function fe({ops:e,expanded:r,onToggle:n}){const a=e[0],d=e[e.length-1];if(a===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const i=a.path,s=d.path,o=e.length===1?i:`${i} … ${s}`,l=a.value.kind==="array"?`${e.length} equal arrays`:a.value.kind==="object"?`${e.length} equal objects`:"equal",f=F.equal;return t.jsxs("div",{className:m("border-l-4 rounded-sm",f.border,f.bg),children:[t.jsxs("button",{type:"button",onClick:n,className:"w-full text-left flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground cursor-pointer",children:[t.jsx(B,{className:m("size-3 transition-transform shrink-0",r&&"rotate-90")}),t.jsx(f.icon,{className:m("size-3 shrink-0",f.accent)}),t.jsx("span",{className:"font-mono truncate flex-1",title:`${i} … ${s}`,children:o}),t.jsx("span",{className:m("text-[10px] uppercase tracking-wider shrink-0",f.accent),children:f.label}),t.jsxs("span",{className:"text-muted-foreground/60 shrink-0",children:["(",l,")"]})]}),r&&t.jsx("div",{className:"ml-5 mt-1 mb-2 space-y-2 pr-2",children:e.map(p=>t.jsxs("div",{className:"border border-border/50 rounded p-2 bg-muted/20",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:p.path}),t.jsx(w,{text:N(p.value),defaultExpandDepth:0})]},p.path))})]})}function pe({op:e,idx:r,copiedPath:n,onCopyPath:a,expanded:d,onToggle:i}){const s=F[e.kind],o=s.icon,l=e.kind==="added"||e.kind==="removed"?e.value.kind==="object"||e.value.kind==="array":e.kind==="changed"?e.left.kind==="object"||e.left.kind==="array"||e.right.kind==="object"||e.right.kind==="array":!1,f=e.kind==="changed"?[{text:v(e.left,400),tone:"text-rose-700 dark:text-rose-300 line-through"},{text:v(e.right,400),tone:"text-emerald-700 dark:text-emerald-300"}]:e.kind==="removed"?[{text:v(e.value,400),tone:"text-rose-700 dark:text-rose-300 line-through"}]:e.kind==="added"?[{text:v(e.value,400),tone:"text-emerald-700 dark:text-emerald-300"}]:[{text:v(e.value,400),tone:"text-muted-foreground"}],p=n===e.path&&e.path!=="";return t.jsxs("div",{"data-diff-idx":r,"data-diff-kind":e.kind,className:m("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors",s.border,s.bg),children:[t.jsxs("button",{type:"button",onClick:i,disabled:!l,className:m("w-full flex items-center gap-2 text-xs text-left rounded-sm",l?"cursor-pointer":"cursor-default"),"aria-expanded":l?d:void 0,"aria-label":l?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[l?t.jsx(B,{className:m("size-3 shrink-0 transition-transform",s.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(o,{className:m("size-3.5 shrink-0",s.accent),strokeWidth:2.5}),t.jsx("span",{className:"font-mono truncate flex-1 min-w-0",title:e.path||"(root)",children:e.path===""?"(root)":e.path}),t.jsx("span",{className:m("text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",s.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:s.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),a(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),a(e.path))},className:m("shrink-0 p-1 rounded transition-colors cursor-pointer inline-flex items-center justify-center",p?"text-emerald-500":"text-muted-foreground/50 hover:text-foreground hover:bg-muted"),"aria-label":p?"Copied":"Copy",title:p?"Copied!":"Copy",children:p?t.jsx(se,{className:"size-3"}):t.jsx(ae,{className:"size-3"})})]}),f.map((b,y)=>t.jsx("div",{className:m("font-mono text-xs mt-1 break-all pl-5",b.tone),children:b.text},y)),t.jsx("div",{className:"overflow-hidden transition-all duration-200",style:{maxHeight:d&&l?"2000px":"0"},"aria-hidden":!d,children:d&&l&&e.kind!=="equal"?t.jsx(he,{op:e}):null})]})}function he({op:e}){if(e.kind==="added"||e.kind==="removed")return t.jsx("div",{className:"pl-5 mt-2 border border-border/50 rounded p-2 bg-muted/20",children:t.jsx(w,{text:N(e.value),defaultExpandDepth:0})});const r=e.left.kind==="object"||e.left.kind==="array",n=e.right.kind==="object"||e.right.kind==="array";return!r&&!n?t.jsx("div",{className:"pl-5 mt-2 text-xs text-muted-foreground/70 italic",children:"Primitive values are shown inline above."}):t.jsxs("div",{className:"pl-5 mt-2 grid grid-cols-1 md:grid-cols-2 gap-2",children:[t.jsxs("div",{className:"border border-rose-500/30 rounded p-2 bg-rose-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-rose-500 mb-1",children:"Old"}),t.jsx(w,{text:N(e.left),defaultExpandDepth:0})]}),t.jsxs("div",{className:"border border-emerald-500/30 rounded p-2 bg-emerald-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-emerald-500 mb-1",children:"New"}),t.jsx(w,{text:N(e.right),defaultExpandDepth:0})]})]})}function be({counts:e,onJumpTo:r}){const n=e.added+e.removed+e.changed;return t.jsxs("div",{className:"px-4 py-2 border-b border-border bg-muted/20 flex items-center gap-2 text-xs flex-wrap",children:[t.jsxs("span",{className:"text-muted-foreground font-medium",children:[n," ",n===1?"change":"changes"]}),t.jsxs("button",{type:"button",onClick:()=>r("removed"),disabled:e.removed===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.removed>0?"border-rose-500/40 text-rose-600 dark:text-rose-400 bg-rose-500/10 hover:bg-rose-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.removed>0?"Jump to first removed":"No removals",children:[t.jsx(V,{className:"size-3"}),e.removed," removed"]}),t.jsxs("button",{type:"button",onClick:()=>r("added"),disabled:e.added===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.added>0?"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.added>0?"Jump to first added":"No additions",children:[t.jsx(_,{className:"size-3"}),e.added," added"]}),t.jsxs("button",{type:"button",onClick:()=>r("changed"),disabled:e.changed===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.changed>0?"border-amber-500/40 text-amber-600 dark:text-amber-400 bg-amber-500/10 hover:bg-amber-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.changed>0?"Jump to first changed":"No changes",children:[t.jsx(M,{className:"size-3"}),e.changed," changed"]})]})}function ve({mode:e,onChange:r}){return t.jsxs("div",{className:"inline-flex rounded-md border border-border overflow-hidden",children:[t.jsxs("button",{type:"button",onClick:()=>r("unified"),"aria-pressed":e==="unified",className:m("flex items-center gap-1 px-2 py-1 text-xs transition-colors cursor-pointer",e==="unified"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Unified view (single column, emphasized diffs)",children:[t.jsx(re,{className:"size-3"}),"Unified"]}),t.jsxs("button",{type:"button",onClick:()=>r("split"),"aria-pressed":e==="split",className:m("flex items-center gap-1 px-2 py-1 text-xs transition-colors border-l border-border cursor-pointer",e==="split"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Split view (path | left | right)",children:[t.jsx(ne,{className:"size-3"}),"Split"]})]})}function J({log:e,side:r,displayNumber:n}){const a=q(e);return t.jsxs("div",{className:"flex-1 min-w-0 space-y-1 text-xs",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(te,{variant:"outline",className:m("text-[10px] px-1.5 py-0 h-5 font-mono shrink-0",r==="left"?"border-rose-500/40 text-rose-400":"border-emerald-500/40 text-emerald-400"),children:r==="left"?"← Left":"Right →"}),t.jsxs("span",{className:"font-mono text-blue-400/80",title:`Log ID ${String(e.id)}`,children:["#",n]}),e.model!==null&&t.jsx("span",{className:"font-mono leading-snug text-muted-foreground",children:e.model})]}),t.jsxs("div",{className:"flex items-center gap-3 text-muted-foreground font-mono",children:[e.cacheCreationInputTokens!==null&&e.cacheCreationInputTokens>0&&t.jsxs("span",{className:"text-emerald-400",children:["KV Cache +",P(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["KV Cache ~",P(e.cacheReadInputTokens)]}),t.jsx("span",{className:"truncate",title:e.timestamp,children:e.timestamp})]}),t.jsxs("div",{className:"text-muted-foreground/70 font-mono truncate",title:a,children:["session: ",a]})]})}function ye({left:e,right:r,leftDisplayNumber:n,rightDisplayNumber:a,onClose:d}){const i=h.useMemo(()=>{const c=$(L(e)).analyzeRequest(e.rawRequestBody),u=$(L(r)).analyzeRequest(r.rawRequestBody),x=D(c.comparisonValue),g=D(u.comparisonValue);return xe(x,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),s=h.useMemo(()=>me(i),[i]),o=h.useMemo(()=>{let c=0,u=0,x=0;for(const g of s)if(g.kind==="single")switch(g.op.kind){case"added":c++;break;case"removed":u++;break;case"changed":x++;break}return{added:c,removed:u,changed:x}},[s]),[l,f]=h.useState(new Set),p=c=>{f(u=>{const x=new Set(u);return x.has(c)?x.delete(c):x.add(c),x})},[b,y]=h.useState(new Set),U=c=>{y(u=>{const x=new Set(u);return x.has(c)?x.delete(c):x.add(c),x})};h.useEffect(()=>{y(new Set)},[e.id,r.id]);const[T,H]=h.useState("unified"),I=h.useRef(null),[G,z]=h.useState(null),k=h.useRef(null),Q=c=>{oe(c).then(u=>{u&&(z(c),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500))})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const W=c=>{const u=s.findIndex(O=>O.kind==="single"&&O.op.kind===c);if(u===-1)return;const x=I.current;if(x===null)return;const g=x.querySelector(`[data-diff-idx="${u}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const c=x=>{x.key==="Escape"&&d()};document.addEventListener("keydown",c);const u=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",c),document.body.style.overflow=u}},[d]);const X=q(e)===q(r),Y=i.length===1&&i[0]?.kind==="equal";return t.jsxs("div",{className:"fixed inset-0 z-50 flex justify-end",role:"dialog","aria-modal":"true","aria-label":"Compare two log requests",children:[t.jsx("button",{type:"button",onClick:d,"aria-label":"Close compare drawer",className:"absolute inset-0 bg-black/40 cursor-default",tabIndex:-1}),t.jsxs("div",{className:m("relative bg-background border-l border-border shadow-xl","w-full md:w-[70vw] max-w-[1100px] flex flex-col h-full"),onClick:c=>c.stopPropagation(),onKeyDown:c=>c.stopPropagation(),children:[t.jsxs("div",{className:"flex items-start gap-4 px-4 py-3 border-b border-border",children:[t.jsxs("div",{className:"flex-1 flex gap-4 min-w-0",children:[t.jsx(J,{log:e,side:"left",displayNumber:n}),t.jsx(J,{log:r,side:"right",displayNumber:a})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(ve,{mode:T,onChange:H}),t.jsx("button",{type:"button",onClick:d,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(ee,{className:"size-4"})})]})]}),!X&&t.jsx("div",{className:"px-4 py-1.5 text-xs text-amber-400 bg-amber-500/10 border-b border-border",children:"Heads up: the two selected logs are from different sessions."}),Y?t.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto flex items-center justify-center text-muted-foreground text-sm",children:"The two Request payloads are identical."}):t.jsxs(t.Fragment,{children:[t.jsx(be,{counts:o,onJumpTo:W}),t.jsx("div",{ref:I,className:"flex-1 min-h-0 overflow-y-auto",children:T==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:s.map((c,u)=>{if(c.kind==="equal-run")return t.jsx(fe,{ops:c.ops,expanded:l.has(u),onToggle:()=>p(u)},`r${u}`);const x=c.op;return t.jsx(pe,{op:x,idx:u,copiedPath:G,onCopyPath:Q,expanded:b.has(u),onToggle:()=>U(u)},`o${u}`)})}):t.jsx(ge,{grouped:s,left:e,right:r,leftDisplayNumber:n,rightDisplayNumber:a})})]})]})]})}function ge({grouped:e,left:r,right:n,leftDisplayNumber:a,rightDisplayNumber:d}){return t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 gap-y-0.5 px-3 py-2 text-xs",children:[t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 col-span-3 pb-2 mb-2 border-b border-border text-[10px] uppercase tracking-wider text-muted-foreground",children:[t.jsx("span",{children:"Path"}),t.jsxs("span",{title:`Log ID ${String(r.id)}`,children:["Left (Log #",a,")"]}),t.jsxs("span",{title:`Log ID ${String(n.id)}`,children:["Right (Log #",d,")"]})]}),e.map((i,s)=>{if(i.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[i.ops.length," equal siblings collapsed — switch to Unified to expand"]},s);const o=i.op;return o.kind==="equal"?t.jsxs("div",{className:"col-span-3 grid grid-cols-[200px_1fr_1fr] gap-x-2 px-2 py-0.5 text-muted-foreground",children:[t.jsx("span",{className:"font-mono text-xs truncate",title:o.path,children:o.path}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)})]},s):o.kind==="added"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-emerald-400/70 bg-emerald-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-emerald-300/90",children:["+ ",v(o.value,400)]})]},s):o.kind==="removed"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-rose-400/70 bg-rose-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-rose-300/90 line-through",children:["− ",v(o.value,400)]})]},s):t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-amber-400/70 bg-amber-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:o.path}),t.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[t.jsx("div",{className:"font-mono text-rose-300/90 break-all line-through",children:v(o.left,400)}),t.jsx("div",{className:"font-mono text-emerald-300/90 break-all",children:v(o.right,400)})]})]},s)})]})}export{ye as CompareDrawer};