@tonyclaw/llm-inspector 1.19.1 → 1.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +146 -37
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DtERUdIt.js → CompareDrawer-BzTsEelr.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-DfxRK7Nt.js → ProxyViewerContainer-BHm-n-_W.js} +9 -9
- package/.output/public/assets/{ReplayDialog-VMsGnJSI.js → ReplayDialog-Dxxo80xO.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-Cx_vluvK.js → RequestAnatomy-D-swiaii.js} +1 -1
- package/.output/public/assets/{ResponseView-5F8Ms5z4.js → ResponseView-DvdH2bGk.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-CKDCWfu9.js → StreamingChunkSequence-D_RzgyKq.js} +1 -1
- package/.output/public/assets/_sessionId-DdODJCYY.js +1 -0
- package/.output/public/assets/{index-DeJyypsp.css → index-Bqi9RAGS.css} +1 -1
- package/.output/public/assets/index-EvnsNPOK.js +1 -0
- package/.output/public/assets/{json-viewer-CztuZ9cT.js → json-viewer-DIHZbEId.js} +1 -1
- package/.output/public/assets/{main-CR9IJlz1.js → main-Br2EjrqZ.js} +2 -2
- package/.output/server/{_sessionId-DvWQaDEm.mjs → _sessionId-CPkCxTP8.mjs} +4 -3
- package/.output/server/_ssr/{CompareDrawer-C5FsxSDS.mjs → CompareDrawer-DKHgXC5-.mjs} +4 -4
- package/.output/server/_ssr/{ProxyViewerContainer-v0cvR8f5.mjs → ProxyViewerContainer-B41D-2Eo.mjs} +57 -9
- package/.output/server/_ssr/{ReplayDialog-C3KOv9OW.mjs → ReplayDialog-D2piRWb0.mjs} +5 -5
- package/.output/server/_ssr/{RequestAnatomy-BYRe33eG.mjs → RequestAnatomy-Ce7QdQNP.mjs} +4 -3
- package/.output/server/_ssr/{ResponseView-va7yQDeL.mjs → ResponseView-D50UPv-r.mjs} +5 -5
- package/.output/server/_ssr/{StreamingChunkSequence-BJlI-gWl.mjs → StreamingChunkSequence-CDlNFS3Z.mjs} +4 -4
- package/.output/server/_ssr/{index-CS0fA2GT.mjs → index-DhAQxjnZ.mjs} +4 -3
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-Dg8rqrxL.mjs → json-viewer-BZRjG_f7.mjs} +4 -4
- package/.output/server/_ssr/{router-D_Boe9Bu.mjs → router-yP98-Gq-.mjs} +126 -105
- package/.output/server/{_tanstack-start-manifest_v-KFXyNRGC.mjs → _tanstack-start-manifest_v-d4a4xlOi.mjs} +1 -1
- package/.output/server/index.mjs +65 -65
- package/README.md +22 -0
- package/package.json +3 -1
- package/src/cli/detect-tools.ts +1 -0
- package/src/cli/templates/skill-onboard.ts +6 -6
- package/src/cli.ts +152 -35
- package/src/components/ProxyViewerContainer.tsx +52 -0
- package/src/components/proxy-viewer/LogEntryHeader.tsx +1 -0
- package/src/proxy/logFinalizer.ts +7 -3
- package/src/proxy/sessionProcess.ts +14 -7
- package/src/proxy/sessionSupervisor.ts +3 -2
- package/src/proxy/socketTracker.ts +19 -7
- package/styles/globals.css +14 -7
- package/.output/public/assets/_sessionId-C-aKd1Ky.js +0 -1
- package/.output/public/assets/index-B8ttyigz.js +0 -1
package/.output/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ function which(bin) {
|
|
|
20
20
|
const out2 = execFileSync("where", [bin], {
|
|
21
21
|
encoding: "utf8",
|
|
22
22
|
timeout: 3e3,
|
|
23
|
+
windowsHide: true,
|
|
23
24
|
stdio: ["ignore", "pipe", "ignore"]
|
|
24
25
|
});
|
|
25
26
|
const first = out2.split(/\r?\n/).find((line) => line.trim().length > 0);
|
|
@@ -326,15 +327,15 @@ New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
|
326
327
|
|
|
327
328
|
## Phase 3: Start proxy
|
|
328
329
|
|
|
329
|
-
**EXPLAIN:** "Time to start the proxy. It binds to port ${port} by default,
|
|
330
|
+
**EXPLAIN:** "Time to start the proxy. It binds to port ${port} by default, reuses an already-running healthy llm-inspector, and prints the URL. Use \`--force-restart\` only when you intentionally want to replace the existing process."
|
|
330
331
|
|
|
331
332
|
**DO:** Skip this phase entirely if the Phase 0 health check already reported \`PROXY: up\` and the user opted to skip done phases.
|
|
332
333
|
|
|
333
|
-
**DO:** Otherwise, start the proxy
|
|
334
|
+
**DO:** Otherwise, start the proxy with the explicit \`--background --no-open\` flags. On Windows, resolve the npm shim first and launch it through \`Start-Process -WindowStyle Hidden\` so setup does not flash a command window.
|
|
334
335
|
|
|
335
336
|
\`\`\`bash
|
|
336
337
|
# Unix / macOS / WSL
|
|
337
|
-
|
|
338
|
+
llm-inspector --background --no-open > /tmp/llm-inspector.log 2>&1
|
|
338
339
|
\`\`\`
|
|
339
340
|
|
|
340
341
|
\`\`\`powershell
|
|
@@ -347,14 +348,14 @@ $err = Join-Path $env:TEMP 'llm-inspector.err.log'
|
|
|
347
348
|
$found = Get-Command llm-inspector -ErrorAction SilentlyContinue
|
|
348
349
|
if ($found) {
|
|
349
350
|
$shim = $found.Source
|
|
350
|
-
$args = '--no-open'
|
|
351
|
+
$args = '--background','--no-open'
|
|
351
352
|
} elseif (Test-Path (Join-Path $env:APPDATA 'npm/llm-inspector.cmd')) {
|
|
352
353
|
$shim = Join-Path $env:APPDATA 'npm/llm-inspector.cmd'
|
|
353
|
-
$args = '--no-open'
|
|
354
|
+
$args = '--background','--no-open'
|
|
354
355
|
} else {
|
|
355
356
|
# bin not on PATH and not at the default npm prefix \u2014 let cmd resolve it
|
|
356
357
|
$shim = 'cmd.exe'
|
|
357
|
-
$args = '/c','
|
|
358
|
+
$args = '/c','llm-inspector','--background','--no-open'
|
|
358
359
|
}
|
|
359
360
|
Start-Process -FilePath $shim -ArgumentList $args -RedirectStandardOutput $log -RedirectStandardError $err -WindowStyle Hidden
|
|
360
361
|
\`\`\`
|
|
@@ -753,23 +754,105 @@ var init_onboard = __esm({
|
|
|
753
754
|
|
|
754
755
|
// src/cli.ts
|
|
755
756
|
import { spawn, execSync } from "node:child_process";
|
|
757
|
+
import { createConnection } from "node:net";
|
|
756
758
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
757
759
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
758
760
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
759
761
|
var __dirname2 = dirname2(__filename2);
|
|
760
762
|
var DEFAULT_PORT2 = 25947;
|
|
763
|
+
var LOCAL_PROBE_TIMEOUT_MS = 2e3;
|
|
761
764
|
var subcommand = process.argv[2];
|
|
762
765
|
if (subcommand === "onboard") {
|
|
763
766
|
const { runOnboard: runOnboard2 } = await Promise.resolve().then(() => (init_onboard(), onboard_exports));
|
|
764
767
|
const code = await runOnboard2(process.argv.slice(3));
|
|
765
768
|
process.exit(code);
|
|
766
769
|
}
|
|
767
|
-
runStart(process.argv.slice(2));
|
|
768
|
-
function
|
|
770
|
+
await runStart(process.argv.slice(2));
|
|
771
|
+
async function isInspectorHealthy(port) {
|
|
772
|
+
const controller = new AbortController();
|
|
773
|
+
const timeout = setTimeout(() => controller.abort(), LOCAL_PROBE_TIMEOUT_MS);
|
|
774
|
+
try {
|
|
775
|
+
const response = await fetch(`http://127.0.0.1:${port}/api/health`, {
|
|
776
|
+
cache: "no-store",
|
|
777
|
+
signal: controller.signal
|
|
778
|
+
});
|
|
779
|
+
return response.ok;
|
|
780
|
+
} catch {
|
|
781
|
+
return false;
|
|
782
|
+
} finally {
|
|
783
|
+
clearTimeout(timeout);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
function isPortAcceptingConnections(port) {
|
|
787
|
+
return new Promise((resolve) => {
|
|
788
|
+
const socket = createConnection({ host: "127.0.0.1", port });
|
|
789
|
+
const finish = (value) => {
|
|
790
|
+
socket.removeAllListeners();
|
|
791
|
+
socket.destroy();
|
|
792
|
+
resolve(value);
|
|
793
|
+
};
|
|
794
|
+
socket.setTimeout(LOCAL_PROBE_TIMEOUT_MS);
|
|
795
|
+
socket.once("connect", () => finish(true));
|
|
796
|
+
socket.once("timeout", () => finish(false));
|
|
797
|
+
socket.once("error", () => finish(false));
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
function sleep(ms) {
|
|
801
|
+
return new Promise((resolve) => {
|
|
802
|
+
setTimeout(resolve, ms);
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
async function waitForInspectorHealthy(port, timeoutMs) {
|
|
806
|
+
const start = Date.now();
|
|
807
|
+
while (Date.now() - start < timeoutMs) {
|
|
808
|
+
if (await isInspectorHealthy(port)) return true;
|
|
809
|
+
await sleep(250);
|
|
810
|
+
}
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
function openBrowser(targetUrl) {
|
|
814
|
+
let command;
|
|
815
|
+
switch (process.platform) {
|
|
816
|
+
case "darwin":
|
|
817
|
+
command = ["open", targetUrl];
|
|
818
|
+
break;
|
|
819
|
+
case "linux":
|
|
820
|
+
command = ["xdg-open", targetUrl];
|
|
821
|
+
break;
|
|
822
|
+
case "win32":
|
|
823
|
+
command = ["cmd", "/c", "start", "", targetUrl];
|
|
824
|
+
break;
|
|
825
|
+
default:
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
if (command === void 0) return;
|
|
829
|
+
const [bin, ...cmdArgs] = command;
|
|
830
|
+
if (bin === void 0) return;
|
|
831
|
+
const browserProcess = spawn(bin, cmdArgs, {
|
|
832
|
+
stdio: "ignore",
|
|
833
|
+
detached: true,
|
|
834
|
+
windowsHide: true
|
|
835
|
+
});
|
|
836
|
+
browserProcess.unref();
|
|
837
|
+
}
|
|
838
|
+
function waitForProcessExit(child) {
|
|
839
|
+
return new Promise((resolve) => {
|
|
840
|
+
child.once("exit", (code) => {
|
|
841
|
+
resolve(code ?? 1);
|
|
842
|
+
});
|
|
843
|
+
child.once("error", () => {
|
|
844
|
+
resolve(1);
|
|
845
|
+
});
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
async function runStart(args) {
|
|
769
849
|
const envPort = process.env["PORT"];
|
|
770
850
|
const portDefault = envPort !== void 0 ? Number(envPort) : DEFAULT_PORT2;
|
|
771
851
|
let port = portDefault;
|
|
772
852
|
let open = true;
|
|
853
|
+
let openWasSpecified = false;
|
|
854
|
+
let background = false;
|
|
855
|
+
let forceRestart = false;
|
|
773
856
|
let configDir;
|
|
774
857
|
let providersJson;
|
|
775
858
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -782,9 +865,18 @@ function runStart(args) {
|
|
|
782
865
|
break;
|
|
783
866
|
case "--no-open":
|
|
784
867
|
open = false;
|
|
868
|
+
openWasSpecified = true;
|
|
785
869
|
break;
|
|
786
870
|
case "--open":
|
|
787
871
|
open = true;
|
|
872
|
+
openWasSpecified = true;
|
|
873
|
+
break;
|
|
874
|
+
case "--force-restart":
|
|
875
|
+
case "--restart":
|
|
876
|
+
forceRestart = true;
|
|
877
|
+
break;
|
|
878
|
+
case "--background":
|
|
879
|
+
background = true;
|
|
788
880
|
break;
|
|
789
881
|
case "--config-dir":
|
|
790
882
|
configDir = args[i + 1];
|
|
@@ -798,6 +890,11 @@ function runStart(args) {
|
|
|
798
890
|
break;
|
|
799
891
|
}
|
|
800
892
|
}
|
|
893
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
894
|
+
console.error(`Invalid port: ${String(port)}. Use --port <1-65535>.`);
|
|
895
|
+
process.exitCode = 1;
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
801
898
|
function killProcessOnPort(targetPort) {
|
|
802
899
|
const platform = process.platform;
|
|
803
900
|
try {
|
|
@@ -805,7 +902,8 @@ function runStart(args) {
|
|
|
805
902
|
if (platform === "win32") {
|
|
806
903
|
const output = execSync(`netstat -ano | findstr :${targetPort}`, {
|
|
807
904
|
encoding: "utf8",
|
|
808
|
-
timeout: 5e3
|
|
905
|
+
timeout: 5e3,
|
|
906
|
+
windowsHide: true
|
|
809
907
|
});
|
|
810
908
|
const lines = output.trim().split("\n");
|
|
811
909
|
for (const line of lines) {
|
|
@@ -824,8 +922,12 @@ function runStart(args) {
|
|
|
824
922
|
pids = [...new Set(pids)];
|
|
825
923
|
for (const pid of pids) {
|
|
826
924
|
try {
|
|
827
|
-
console.log(`Killing process ${pid} on port ${
|
|
828
|
-
execSync(`taskkill /PID ${pid} /F`, {
|
|
925
|
+
console.log(`Killing process ${pid} on port ${targetPort}...`);
|
|
926
|
+
execSync(`taskkill /PID ${pid} /F`, {
|
|
927
|
+
encoding: "utf8",
|
|
928
|
+
timeout: 5e3,
|
|
929
|
+
windowsHide: true
|
|
930
|
+
});
|
|
829
931
|
} catch {
|
|
830
932
|
}
|
|
831
933
|
}
|
|
@@ -841,7 +943,7 @@ function runStart(args) {
|
|
|
841
943
|
pids = [...new Set(pids)];
|
|
842
944
|
for (const pid of pids) {
|
|
843
945
|
try {
|
|
844
|
-
console.log(`Killing process ${pid} on port ${
|
|
946
|
+
console.log(`Killing process ${pid} on port ${targetPort}...`);
|
|
845
947
|
execSync(`kill -9 ${pid}`, { encoding: "utf8", timeout: 5e3 });
|
|
846
948
|
} catch {
|
|
847
949
|
}
|
|
@@ -851,8 +953,24 @@ function runStart(args) {
|
|
|
851
953
|
}
|
|
852
954
|
}
|
|
853
955
|
process.env["PORT"] = String(port);
|
|
854
|
-
killProcessOnPort(port);
|
|
855
956
|
const url = `http://localhost:${port}`;
|
|
957
|
+
if (!forceRestart && await isInspectorHealthy(port)) {
|
|
958
|
+
console.log(`llm-inspector is already running at ${url}`);
|
|
959
|
+
console.log(`Use --force-restart to restart the existing instance.`);
|
|
960
|
+
if (open && openWasSpecified) {
|
|
961
|
+
openBrowser(url);
|
|
962
|
+
}
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
if (!forceRestart && await isPortAcceptingConnections(port)) {
|
|
966
|
+
console.error(`Port ${port} is already in use, but it is not a healthy llm-inspector.`);
|
|
967
|
+
console.error(`Stop that process, choose --port <n>, or re-run with --force-restart.`);
|
|
968
|
+
process.exitCode = 1;
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
if (forceRestart) {
|
|
972
|
+
killProcessOnPort(port);
|
|
973
|
+
}
|
|
856
974
|
console.log(`Server running at ${url}`);
|
|
857
975
|
console.log(` Proxy: ${url}/proxy`);
|
|
858
976
|
console.log(``);
|
|
@@ -870,26 +988,6 @@ function runStart(args) {
|
|
|
870
988
|
console.log(
|
|
871
989
|
` Example: ROUTES='{"claude-":"https://api.anthropic.com","MiniMax":"https://api.minimaxi.com/anthropic"}'`
|
|
872
990
|
);
|
|
873
|
-
const openBrowser = (targetUrl) => {
|
|
874
|
-
let command;
|
|
875
|
-
switch (process.platform) {
|
|
876
|
-
case "darwin":
|
|
877
|
-
command = ["open", targetUrl];
|
|
878
|
-
break;
|
|
879
|
-
case "linux":
|
|
880
|
-
command = ["xdg-open", targetUrl];
|
|
881
|
-
break;
|
|
882
|
-
case "win32":
|
|
883
|
-
command = ["cmd", "/c", "start", targetUrl];
|
|
884
|
-
break;
|
|
885
|
-
default:
|
|
886
|
-
break;
|
|
887
|
-
}
|
|
888
|
-
if (command === void 0) return;
|
|
889
|
-
const [bin, ...cmdArgs] = command;
|
|
890
|
-
if (bin === void 0) return;
|
|
891
|
-
spawn(bin, cmdArgs, { stdio: "ignore", detached: true });
|
|
892
|
-
};
|
|
893
991
|
if (open) {
|
|
894
992
|
openBrowser(url);
|
|
895
993
|
}
|
|
@@ -910,9 +1008,20 @@ function runStart(args) {
|
|
|
910
1008
|
serverEnv["LLM_INSPECTOR_PROVIDERS_JSON"] = providersJson;
|
|
911
1009
|
}
|
|
912
1010
|
const serverProcess = spawn(process.execPath, [serverPath], {
|
|
913
|
-
stdio: ["ignore", "
|
|
914
|
-
detached:
|
|
915
|
-
env: serverEnv
|
|
1011
|
+
stdio: background ? ["ignore", "ignore", "ignore"] : "inherit",
|
|
1012
|
+
detached: background,
|
|
1013
|
+
env: serverEnv,
|
|
1014
|
+
windowsHide: background
|
|
916
1015
|
});
|
|
917
|
-
|
|
1016
|
+
if (background) {
|
|
1017
|
+
serverProcess.unref();
|
|
1018
|
+
if (await waitForInspectorHealthy(port, 5e3)) {
|
|
1019
|
+
console.log(`llm-inspector background server is ready at ${url}`);
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
console.error(`llm-inspector background server did not become ready at ${url}.`);
|
|
1023
|
+
process.exitCode = 1;
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
process.exitCode = await waitForProcessExit(serverProcess);
|
|
918
1027
|
}
|
package/.output/nitro.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as h,j as t}from"./main-CR9IJlz1.js";import{c as X,g as O,r as P,a as q,X as Y,b as x,B as Z,f as $,R as ee,C as te,M as _,d as J,e as M,h as B,i as re,j as ne}from"./ProxyViewerContainer-DfxRK7Nt.js";import{J as N}from"./json-viewer-CztuZ9cT.js";const se=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],ae=X("equal",se),oe="";function j(e){if(e.length===0)return oe;let r="";for(let n=0;n<e.length;n++){const s=e[n];s!==void 0&&(typeof s=="number"?r+=`[${s}]`:n===0?r+=s:r+=`.${s}`)}return r}function de(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(de(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 ie(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,s){const d=j(e);if(E(r,n)){s.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const o=Object.keys(r.value),a=Object.keys(n.value),m=new Set(a);for(const i of o){const f=r.value[i];if(f!==void 0)if(!m.has(i))s.push({kind:"removed",path:j([...e,i]),value:f});else{const p=n.value[i];if(p===void 0)continue;R([...e,i],f,p,s)}}for(const i of a){if(o.includes(i))continue;const f=n.value[i];f!==void 0&&s.push({kind:"added",path:j([...e,i]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const o=Math.min(r.value.length,n.value.length);for(let a=0;a<o;a++){const m=r.value[a],i=n.value[a];m===void 0||i===void 0||R([...e,a],m,i,s)}for(let a=o;a<n.value.length;a++){const m=n.value[a];m!==void 0&&s.push({kind:"added",path:j([...e,a]),value:m})}for(let a=o;a<r.value.length;a++){const m=r.value[a];m!==void 0&&s.push({kind:"removed",path:j([...e,a]),value:m})}}}function E(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 s=e.value[n],d=r.value[n];if(s===void 0||d===void 0||!E(s,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),s=Object.keys(r.value);if(n.length!==s.length)return!1;for(const d of n){const o=e.value[d],a=r.value[d];if(o===void 0||a===void 0||!E(o,a))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 w(e,r=2){return JSON.stringify(S(e),null,r)}function S(e){switch(e.kind){case"primitive":return e.value;case"array":return e.value.map(S);case"object":{const r={};for(const[n,s]of Object.entries(e.value))r[n]=S(s);return r}}}function L(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 le(e){const r=[];let n=0;for(;n<e.length;){const s=e[n];if(s!==void 0&&A(s)){const d=L(s.path);let o=n+1;for(;o<e.length;){const a=e[o];if(a===void 0||!A(a)||L(a.path)!==d)break;o++}if(o-n>1){const a=[];for(let m=n;m<o;m++){const i=e[m];i!==void 0&&i.kind==="equal"&&a.push(i)}r.push({kind:"equal-run",ops:a}),n=o;continue}}s!==void 0&&r.push({kind:"single",op:s}),n++}return r}const V={added:{icon:J,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:_,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:ae,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function ce({ops:e,expanded:r,onToggle:n}){const s=e[0],d=e[e.length-1];if(s===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const o=s.path,a=d.path,m=e.length===1?o:`${o} … ${a}`,i=s.value.kind==="array"?`${e.length} equal arrays`:s.value.kind==="object"?`${e.length} equal objects`:"equal",f=V.equal;return t.jsxs("div",{className:x("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:x("size-3 transition-transform shrink-0",r&&"rotate-90")}),t.jsx(f.icon,{className:x("size-3 shrink-0",f.accent)}),t.jsx("span",{className:"font-mono truncate flex-1",title:`${o} … ${a}`,children:m}),t.jsx("span",{className:x("text-[10px] uppercase tracking-wider shrink-0",f.accent),children:f.label}),t.jsxs("span",{className:"text-muted-foreground/60 shrink-0",children:["(",i,")"]})]}),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(N,{text:w(p.value),defaultExpandDepth:0})]},p.path))})]})}function ue({op:e,idx:r,copiedPath:n,onCopyPath:s,expanded:d,onToggle:o}){const a=V[e.kind],m=a.icon,i=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:x("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors",a.border,a.bg),children:[t.jsxs("button",{type:"button",onClick:o,disabled:!i,className:x("w-full flex items-center gap-2 text-xs text-left rounded-sm",i?"cursor-pointer":"cursor-default"),"aria-expanded":i?d:void 0,"aria-label":i?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[i?t.jsx(B,{className:x("size-3 shrink-0 transition-transform",a.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(m,{className:x("size-3.5 shrink-0",a.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:x("text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",a.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:a.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),s(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),s(e.path))},className:x("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(re,{className:"size-3"}):t.jsx(ne,{className:"size-3"})})]}),f.map((b,y)=>t.jsx("div",{className:x("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&&i?"2000px":"0"},"aria-hidden":!d,children:d&&i&&e.kind!=="equal"?t.jsx(me,{op:e}):null})]})}function me({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(N,{text:w(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(N,{text:w(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(N,{text:w(e.right),defaultExpandDepth:0})]})]})}function xe({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:x("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(_,{className:"size-3"}),e.removed," removed"]}),t.jsxs("button",{type:"button",onClick:()=>r("added"),disabled:e.added===0,className:x("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(J,{className:"size-3"}),e.added," added"]}),t.jsxs("button",{type:"button",onClick:()=>r("changed"),disabled:e.changed===0,className:x("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 fe({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:x("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(ee,{className:"size-3"}),"Unified"]}),t.jsxs("button",{type:"button",onClick:()=>r("split"),"aria-pressed":e==="split",className:x("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(te,{className:"size-3"}),"Split"]})]})}function K({log:e,side:r}){const n=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(Z,{variant:"outline",className:x("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",children:["#",e.id]}),e.model!==null&&t.jsx("span",{className:"font-mono text-muted-foreground truncate",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:["Cache +",$(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["Cache ~",$(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:n,children:["session: ",n]})]})}function ge({left:e,right:r,onClose:n}){const s=h.useMemo(()=>{const l=O(P(e)).analyzeRequest(e.rawRequestBody),c=O(P(r)).analyzeRequest(r.rawRequestBody),u=D(l.comparisonValue),g=D(c.comparisonValue);return ie(u,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),d=h.useMemo(()=>le(s),[s]),o=h.useMemo(()=>{let l=0,c=0,u=0;for(const g of d)if(g.kind==="single")switch(g.op.kind){case"added":l++;break;case"removed":c++;break;case"changed":u++;break}return{added:l,removed:c,changed:u}},[d]),[a,m]=h.useState(new Set),i=l=>{m(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})},[f,p]=h.useState(new Set),b=l=>{p(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})};h.useEffect(()=>{p(new Set)},[e.id,r.id]);const[y,F]=h.useState("unified"),T=h.useRef(null),[U,z]=h.useState(null),k=h.useRef(null),H=l=>{window.navigator.clipboard.writeText(l).then(()=>{z(l),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500)})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const G=l=>{const c=d.findIndex(I=>I.kind==="single"&&I.op.kind===l);if(c===-1)return;const u=T.current;if(u===null)return;const g=u.querySelector(`[data-diff-idx="${c}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const l=u=>{u.key==="Escape"&&n()};document.addEventListener("keydown",l);const c=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",l),document.body.style.overflow=c}},[n]);const Q=q(e)===q(r),W=s.length===1&&s[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:n,"aria-label":"Close compare drawer",className:"absolute inset-0 bg-black/40 cursor-default",tabIndex:-1}),t.jsxs("div",{className:x("relative bg-background border-l border-border shadow-xl","w-full md:w-[70vw] max-w-[1100px] flex flex-col h-full"),onClick:l=>l.stopPropagation(),onKeyDown:l=>l.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(K,{log:e,side:"left"}),t.jsx(K,{log:r,side:"right"})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(fe,{mode:y,onChange:F}),t.jsx("button",{type:"button",onClick:n,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(Y,{className:"size-4"})})]})]}),!Q&&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."}),W?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(xe,{counts:o,onJumpTo:G}),t.jsx("div",{ref:T,className:"flex-1 min-h-0 overflow-y-auto",children:y==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:d.map((l,c)=>{if(l.kind==="equal-run")return t.jsx(ce,{ops:l.ops,expanded:a.has(c),onToggle:()=>i(c)},`r${c}`);const u=l.op;return t.jsx(ue,{op:u,idx:c,copiedPath:U,onCopyPath:H,expanded:f.has(c),onToggle:()=>b(c)},`o${c}`)})}):t.jsx(pe,{grouped:d,left:e,right:r})})]})]})]})}function pe({grouped:e,left:r,right:n}){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",{children:["Left (Log #",r.id,")"]}),t.jsxs("span",{children:["Right (Log #",n.id,")"]})]}),e.map((s,d)=>{if(s.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[s.ops.length," equal siblings collapsed — switch to Unified to expand"]},d);const o=s.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)})]},d):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)]})]},d):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)]})]},d):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)})]})]},d)})]})}export{ge as CompareDrawer};
|
|
1
|
+
import{r as h,j as t}from"./main-Br2EjrqZ.js";import{c as X,g as O,r as P,a as q,X as Y,b as x,B as Z,f as $,R as ee,C as te,M as _,d as J,e as M,h as B,i as re,j as ne}from"./ProxyViewerContainer-BHm-n-_W.js";import{J as N}from"./json-viewer-DIHZbEId.js";const se=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],ae=X("equal",se),oe="";function j(e){if(e.length===0)return oe;let r="";for(let n=0;n<e.length;n++){const s=e[n];s!==void 0&&(typeof s=="number"?r+=`[${s}]`:n===0?r+=s:r+=`.${s}`)}return r}function de(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(de(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 ie(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,s){const d=j(e);if(E(r,n)){s.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const o=Object.keys(r.value),a=Object.keys(n.value),m=new Set(a);for(const i of o){const f=r.value[i];if(f!==void 0)if(!m.has(i))s.push({kind:"removed",path:j([...e,i]),value:f});else{const p=n.value[i];if(p===void 0)continue;R([...e,i],f,p,s)}}for(const i of a){if(o.includes(i))continue;const f=n.value[i];f!==void 0&&s.push({kind:"added",path:j([...e,i]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const o=Math.min(r.value.length,n.value.length);for(let a=0;a<o;a++){const m=r.value[a],i=n.value[a];m===void 0||i===void 0||R([...e,a],m,i,s)}for(let a=o;a<n.value.length;a++){const m=n.value[a];m!==void 0&&s.push({kind:"added",path:j([...e,a]),value:m})}for(let a=o;a<r.value.length;a++){const m=r.value[a];m!==void 0&&s.push({kind:"removed",path:j([...e,a]),value:m})}}}function E(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 s=e.value[n],d=r.value[n];if(s===void 0||d===void 0||!E(s,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),s=Object.keys(r.value);if(n.length!==s.length)return!1;for(const d of n){const o=e.value[d],a=r.value[d];if(o===void 0||a===void 0||!E(o,a))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 w(e,r=2){return JSON.stringify(S(e),null,r)}function S(e){switch(e.kind){case"primitive":return e.value;case"array":return e.value.map(S);case"object":{const r={};for(const[n,s]of Object.entries(e.value))r[n]=S(s);return r}}}function L(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 le(e){const r=[];let n=0;for(;n<e.length;){const s=e[n];if(s!==void 0&&A(s)){const d=L(s.path);let o=n+1;for(;o<e.length;){const a=e[o];if(a===void 0||!A(a)||L(a.path)!==d)break;o++}if(o-n>1){const a=[];for(let m=n;m<o;m++){const i=e[m];i!==void 0&&i.kind==="equal"&&a.push(i)}r.push({kind:"equal-run",ops:a}),n=o;continue}}s!==void 0&&r.push({kind:"single",op:s}),n++}return r}const V={added:{icon:J,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:_,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:ae,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function ce({ops:e,expanded:r,onToggle:n}){const s=e[0],d=e[e.length-1];if(s===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const o=s.path,a=d.path,m=e.length===1?o:`${o} … ${a}`,i=s.value.kind==="array"?`${e.length} equal arrays`:s.value.kind==="object"?`${e.length} equal objects`:"equal",f=V.equal;return t.jsxs("div",{className:x("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:x("size-3 transition-transform shrink-0",r&&"rotate-90")}),t.jsx(f.icon,{className:x("size-3 shrink-0",f.accent)}),t.jsx("span",{className:"font-mono truncate flex-1",title:`${o} … ${a}`,children:m}),t.jsx("span",{className:x("text-[10px] uppercase tracking-wider shrink-0",f.accent),children:f.label}),t.jsxs("span",{className:"text-muted-foreground/60 shrink-0",children:["(",i,")"]})]}),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(N,{text:w(p.value),defaultExpandDepth:0})]},p.path))})]})}function ue({op:e,idx:r,copiedPath:n,onCopyPath:s,expanded:d,onToggle:o}){const a=V[e.kind],m=a.icon,i=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:x("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors",a.border,a.bg),children:[t.jsxs("button",{type:"button",onClick:o,disabled:!i,className:x("w-full flex items-center gap-2 text-xs text-left rounded-sm",i?"cursor-pointer":"cursor-default"),"aria-expanded":i?d:void 0,"aria-label":i?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[i?t.jsx(B,{className:x("size-3 shrink-0 transition-transform",a.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(m,{className:x("size-3.5 shrink-0",a.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:x("text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",a.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:a.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),s(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),s(e.path))},className:x("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(re,{className:"size-3"}):t.jsx(ne,{className:"size-3"})})]}),f.map((b,y)=>t.jsx("div",{className:x("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&&i?"2000px":"0"},"aria-hidden":!d,children:d&&i&&e.kind!=="equal"?t.jsx(me,{op:e}):null})]})}function me({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(N,{text:w(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(N,{text:w(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(N,{text:w(e.right),defaultExpandDepth:0})]})]})}function xe({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:x("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(_,{className:"size-3"}),e.removed," removed"]}),t.jsxs("button",{type:"button",onClick:()=>r("added"),disabled:e.added===0,className:x("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(J,{className:"size-3"}),e.added," added"]}),t.jsxs("button",{type:"button",onClick:()=>r("changed"),disabled:e.changed===0,className:x("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 fe({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:x("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(ee,{className:"size-3"}),"Unified"]}),t.jsxs("button",{type:"button",onClick:()=>r("split"),"aria-pressed":e==="split",className:x("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(te,{className:"size-3"}),"Split"]})]})}function K({log:e,side:r}){const n=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(Z,{variant:"outline",className:x("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",children:["#",e.id]}),e.model!==null&&t.jsx("span",{className:"font-mono text-muted-foreground truncate",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:["Cache +",$(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["Cache ~",$(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:n,children:["session: ",n]})]})}function ge({left:e,right:r,onClose:n}){const s=h.useMemo(()=>{const l=O(P(e)).analyzeRequest(e.rawRequestBody),c=O(P(r)).analyzeRequest(r.rawRequestBody),u=D(l.comparisonValue),g=D(c.comparisonValue);return ie(u,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),d=h.useMemo(()=>le(s),[s]),o=h.useMemo(()=>{let l=0,c=0,u=0;for(const g of d)if(g.kind==="single")switch(g.op.kind){case"added":l++;break;case"removed":c++;break;case"changed":u++;break}return{added:l,removed:c,changed:u}},[d]),[a,m]=h.useState(new Set),i=l=>{m(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})},[f,p]=h.useState(new Set),b=l=>{p(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})};h.useEffect(()=>{p(new Set)},[e.id,r.id]);const[y,F]=h.useState("unified"),T=h.useRef(null),[U,z]=h.useState(null),k=h.useRef(null),H=l=>{window.navigator.clipboard.writeText(l).then(()=>{z(l),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500)})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const G=l=>{const c=d.findIndex(I=>I.kind==="single"&&I.op.kind===l);if(c===-1)return;const u=T.current;if(u===null)return;const g=u.querySelector(`[data-diff-idx="${c}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const l=u=>{u.key==="Escape"&&n()};document.addEventListener("keydown",l);const c=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",l),document.body.style.overflow=c}},[n]);const Q=q(e)===q(r),W=s.length===1&&s[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:n,"aria-label":"Close compare drawer",className:"absolute inset-0 bg-black/40 cursor-default",tabIndex:-1}),t.jsxs("div",{className:x("relative bg-background border-l border-border shadow-xl","w-full md:w-[70vw] max-w-[1100px] flex flex-col h-full"),onClick:l=>l.stopPropagation(),onKeyDown:l=>l.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(K,{log:e,side:"left"}),t.jsx(K,{log:r,side:"right"})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(fe,{mode:y,onChange:F}),t.jsx("button",{type:"button",onClick:n,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(Y,{className:"size-4"})})]})]}),!Q&&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."}),W?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(xe,{counts:o,onJumpTo:G}),t.jsx("div",{ref:T,className:"flex-1 min-h-0 overflow-y-auto",children:y==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:d.map((l,c)=>{if(l.kind==="equal-run")return t.jsx(ce,{ops:l.ops,expanded:a.has(c),onToggle:()=>i(c)},`r${c}`);const u=l.op;return t.jsx(ue,{op:u,idx:c,copiedPath:U,onCopyPath:H,expanded:f.has(c),onToggle:()=>b(c)},`o${c}`)})}):t.jsx(pe,{grouped:d,left:e,right:r})})]})]})]})}function pe({grouped:e,left:r,right:n}){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",{children:["Left (Log #",r.id,")"]}),t.jsxs("span",{children:["Right (Log #",n.id,")"]})]}),e.map((s,d)=>{if(s.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[s.ops.length," equal siblings collapsed — switch to Unified to expand"]},d);const o=s.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)})]},d):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)]})]},d):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)]})]},d):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)})]})]},d)})]})}export{ge as CompareDrawer};
|