@tonyclaw/llm-inspector 1.19.3 → 1.20.0

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 (33) hide show
  1. package/.output/cli.js +478 -14
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-AMCFfwDw.js → CompareDrawer-DaEfZjXJ.js} +1 -1
  4. package/.output/public/assets/{ProxyViewerContainer-Bi1QXDYo.js → ProxyViewerContainer-RhHgw8Ej.js} +10 -10
  5. package/.output/public/assets/{ReplayDialog-C1x2-73A.js → ReplayDialog-BjQGoECv.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-CBNqMbxo.js → RequestAnatomy-QU9eugVN.js} +1 -1
  7. package/.output/public/assets/{ResponseView-BsBxYW8b.js → ResponseView-aYiH9vL2.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-BjX20-9R.js → StreamingChunkSequence-Cpx_Qp8w.js} +1 -1
  9. package/.output/public/assets/_sessionId-BloLpBNK.js +1 -0
  10. package/.output/public/assets/index-BKzkybBt.js +1 -0
  11. package/.output/public/assets/{index-Bqi9RAGS.css → index-DUZVFAL8.css} +1 -1
  12. package/.output/public/assets/{json-viewer-CyJ5nYhX.js → json-viewer-iMGYFtiP.js} +1 -1
  13. package/.output/public/assets/{main-DpODUL6C.js → main-DLMLYxyQ.js} +7 -7
  14. package/.output/server/{_sessionId-DJ9Eab2q.mjs → _sessionId-B-zUQeOo.mjs} +2 -2
  15. package/.output/server/_ssr/{CompareDrawer-CZjtgISX.mjs → CompareDrawer-CX6uQvQB.mjs} +3 -3
  16. package/.output/server/_ssr/{ProxyViewerContainer-PjfpTAwC.mjs → ProxyViewerContainer-DsQWgvwt.mjs} +77 -10
  17. package/.output/server/_ssr/{ReplayDialog-OiEK8Sbt.mjs → ReplayDialog-BrMgVKb9.mjs} +4 -4
  18. package/.output/server/_ssr/{RequestAnatomy-DN7d-srT.mjs → RequestAnatomy-ll7Vbnl7.mjs} +2 -2
  19. package/.output/server/_ssr/{ResponseView-7iJG8mU_.mjs → ResponseView-CdloAejU.mjs} +3 -3
  20. package/.output/server/_ssr/{StreamingChunkSequence-DgtV9nLT.mjs → StreamingChunkSequence-C9LC9S8C.mjs} +3 -3
  21. package/.output/server/_ssr/{index-YZwFhEEr.mjs → index-DBs4Nc1G.mjs} +2 -2
  22. package/.output/server/_ssr/index.mjs +2 -2
  23. package/.output/server/_ssr/{json-viewer-0GHTWO7g.mjs → json-viewer-l1tDAk7X.mjs} +2 -2
  24. package/.output/server/_ssr/{router-DCW8d1sw.mjs → router-O1ouXZtT.mjs} +4 -4
  25. package/.output/server/{_tanstack-start-manifest_v-CxTbhyJ_.mjs → _tanstack-start-manifest_v-OkvTTh2H.mjs} +1 -1
  26. package/.output/server/index.mjs +69 -69
  27. package/package.json +1 -1
  28. package/src/assets/favicon.svg +13 -0
  29. package/src/cli/doctor.ts +530 -0
  30. package/src/cli.ts +6 -0
  31. package/src/components/ui/crab-logo.tsx +50 -0
  32. package/.output/public/assets/_sessionId-DE0J5YHU.js +0 -1
  33. package/.output/public/assets/index-DqgTchf4.js +0 -1
package/.output/cli.js CHANGED
@@ -752,14 +752,473 @@ var init_onboard = __esm({
752
752
  }
753
753
  });
754
754
 
755
+ // src/cli/doctor.ts
756
+ var doctor_exports = {};
757
+ __export(doctor_exports, {
758
+ buildDoctorReport: () => buildDoctorReport,
759
+ createDoctorDeps: () => createDoctorDeps,
760
+ doctorHelp: () => doctorHelp,
761
+ formatDoctorReport: () => formatDoctorReport,
762
+ parseDoctorArgs: () => parseDoctorArgs,
763
+ runDoctor: () => runDoctor
764
+ });
765
+ import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync } from "node:fs";
766
+ import { homedir as homedir3 } from "node:os";
767
+ import { isAbsolute, join as join3, resolve } from "node:path";
768
+ import { createConnection } from "node:net";
769
+ function check(name, severity, message, hint = "") {
770
+ return {
771
+ name,
772
+ severity,
773
+ message,
774
+ hint: hint === "" ? null : hint
775
+ };
776
+ }
777
+ function parsePort(raw) {
778
+ if (raw === void 0 || raw.trim() === "") return null;
779
+ const port = Number(raw);
780
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
781
+ return port;
782
+ }
783
+ function parseDoctorArgs(argv, env = process.env) {
784
+ const envPort = parsePort(env["PORT"]);
785
+ const options = {
786
+ port: envPort ?? DEFAULT_PORT2,
787
+ configDir: null,
788
+ providersJson: null,
789
+ help: false
790
+ };
791
+ for (let i = 0; i < argv.length; i++) {
792
+ const arg = argv[i];
793
+ switch (arg) {
794
+ case void 0:
795
+ continue;
796
+ case "--help":
797
+ case "-h":
798
+ options.help = true;
799
+ break;
800
+ case "--port":
801
+ case "-p": {
802
+ const parsed = parsePort(argv[i + 1]);
803
+ if (parsed === null) {
804
+ return { kind: "error", message: "doctor: --port must be an integer from 1 to 65535" };
805
+ }
806
+ options.port = parsed;
807
+ i++;
808
+ break;
809
+ }
810
+ case "--config-dir": {
811
+ const next = argv[i + 1];
812
+ if (next === void 0 || next.trim() === "") {
813
+ return { kind: "error", message: "doctor: --config-dir requires a path argument" };
814
+ }
815
+ options.configDir = next;
816
+ i++;
817
+ break;
818
+ }
819
+ case "--providers": {
820
+ const next = argv[i + 1];
821
+ if (next === void 0 || next.trim() === "") {
822
+ return { kind: "error", message: "doctor: --providers requires a JSON argument" };
823
+ }
824
+ options.providersJson = next;
825
+ i++;
826
+ break;
827
+ }
828
+ default:
829
+ return { kind: "error", message: `doctor: unknown option ${arg}` };
830
+ }
831
+ }
832
+ return { kind: "ok", options };
833
+ }
834
+ function isObject2(value) {
835
+ return typeof value === "object" && value !== null && !Array.isArray(value);
836
+ }
837
+ function providerCountFromParsed(value) {
838
+ if (Array.isArray(value)) return value.length;
839
+ if (isObject2(value)) {
840
+ const providers = value["providers"];
841
+ if (Array.isArray(providers)) return providers.length;
842
+ }
843
+ return null;
844
+ }
845
+ function providerCountFromJson(raw) {
846
+ try {
847
+ const parsed = JSON.parse(raw);
848
+ return providerCountFromParsed(parsed);
849
+ } catch {
850
+ return "invalid";
851
+ }
852
+ }
853
+ function resolveMaybeRelative(base, value) {
854
+ return isAbsolute(value) ? value : resolve(base, value);
855
+ }
856
+ function resolveDefaultDataDir(env, platform) {
857
+ const isWindows = platform === "win32";
858
+ const home = isWindows ? env["USERPROFILE"] ?? homedir3() : env["HOME"] ?? homedir3();
859
+ const dataDir = env["LLM_INSPECTOR_DATA_DIR"];
860
+ if (dataDir !== void 0 && dataDir !== "") {
861
+ return isAbsolute(dataDir) ? dataDir : join3(home, dataDir);
862
+ }
863
+ const legacyConfigDir = env["LLM_INSPECTOR_CONFIG_DIR"];
864
+ if (legacyConfigDir !== void 0 && legacyConfigDir !== "") {
865
+ return isAbsolute(legacyConfigDir) ? legacyConfigDir : join3(home, legacyConfigDir);
866
+ }
867
+ return join3(home, ".llm-inspector");
868
+ }
869
+ function providerConfigCandidates(options, deps) {
870
+ const explicitPath = deps.env["LLM_INSPECTOR_CONFIG_PATH"];
871
+ if (explicitPath !== void 0 && explicitPath !== "") {
872
+ return [resolveMaybeRelative(deps.cwd, explicitPath)];
873
+ }
874
+ if (options.configDir !== null) {
875
+ const dir = resolveMaybeRelative(deps.cwd, options.configDir);
876
+ return [join3(dir, "providers.json"), join3(dir, "config.json")];
877
+ }
878
+ const dataDir = resolveDefaultDataDir(deps.env, deps.platform);
879
+ return [join3(dataDir, "providers.json")];
880
+ }
881
+ function checkProviderConfig(options, deps) {
882
+ const providersJson = options.providersJson ?? deps.env["LLM_INSPECTOR_PROVIDERS_JSON"] ?? null;
883
+ if (providersJson !== null) {
884
+ const count = providerCountFromJson(providersJson);
885
+ if (count === "invalid") {
886
+ return check(
887
+ "Provider config",
888
+ "fail",
889
+ "Provider JSON override is not valid JSON.",
890
+ "Fix --providers or LLM_INSPECTOR_PROVIDERS_JSON; doctor never prints the raw value."
891
+ );
892
+ }
893
+ if (count !== null) {
894
+ return check("Provider config", "pass", `${count} provider(s) found in JSON override.`);
895
+ }
896
+ return check(
897
+ "Provider config",
898
+ "fail",
899
+ "Provider JSON override does not look like a provider array or { providers } object.",
900
+ "Use an exported providers JSON payload or configure providers in the UI."
901
+ );
902
+ }
903
+ const candidates = providerConfigCandidates(options, deps);
904
+ for (const candidate of candidates) {
905
+ if (!deps.exists(candidate)) continue;
906
+ const text = deps.readText(candidate);
907
+ if (text === null) {
908
+ return check(
909
+ "Provider config",
910
+ "fail",
911
+ `Provider config exists but could not be read: ${candidate}`
912
+ );
913
+ }
914
+ const count = providerCountFromJson(text);
915
+ if (count === "invalid") {
916
+ return check("Provider config", "fail", `Provider config is invalid JSON: ${candidate}`);
917
+ }
918
+ if (count !== null && count > 0) {
919
+ return check("Provider config", "pass", `${count} provider(s) configured.`);
920
+ }
921
+ return check(
922
+ "Provider config",
923
+ "warn",
924
+ `Provider config exists but no providers were found: ${candidate}`,
925
+ "Add a provider in Settings or import provider settings."
926
+ );
927
+ }
928
+ return check(
929
+ "Provider config",
930
+ "warn",
931
+ "No provider config was found.",
932
+ "Add a provider in the web UI, import providers, or pass --providers for this check."
933
+ );
934
+ }
935
+ async function checkProxyHealth(port, deps) {
936
+ const health = await deps.fetchHealth(port);
937
+ const url = `http://localhost:${port}`;
938
+ if (health.ok) {
939
+ return check(
940
+ "Proxy health",
941
+ "pass",
942
+ `llm-inspector is healthy at ${url}.`,
943
+ `Proxy URL: ${url}/proxy`
944
+ );
945
+ }
946
+ if (await deps.isPortOpen(port)) {
947
+ const suffix = health.status === null ? "" : ` (HTTP ${health.status})`;
948
+ return check(
949
+ "Proxy health",
950
+ "fail",
951
+ `Port ${port} is accepting connections, but /api/health is not healthy${suffix}.`,
952
+ "Stop that process, choose --port <n>, or start llm-inspector with --force-restart."
953
+ );
954
+ }
955
+ return check(
956
+ "Proxy health",
957
+ "warn",
958
+ `No process is listening on port ${port}.`,
959
+ "Start with `llm-inspector`, `llm-inspector --background`, or `bun run dev`."
960
+ );
961
+ }
962
+ function findProjectRoot(startDir, deps) {
963
+ let current = resolve(startDir);
964
+ for (let i = 0; i < 6; i++) {
965
+ if (deps.exists(join3(current, "package.json"))) return current;
966
+ const next = resolve(current, "..");
967
+ if (next === current) return startDir;
968
+ current = next;
969
+ }
970
+ return startDir;
971
+ }
972
+ function checkPackage(rootDir, deps) {
973
+ const packagePath = join3(rootDir, "package.json");
974
+ const text = deps.readText(packagePath);
975
+ if (text === null) {
976
+ return check("Package metadata", "warn", "package.json was not found near the CLI bundle.");
977
+ }
978
+ try {
979
+ const parsed = JSON.parse(text);
980
+ if (!isObject2(parsed)) {
981
+ return check("Package metadata", "warn", "package.json is not an object.");
982
+ }
983
+ const name = parsed["name"];
984
+ const version = parsed["version"];
985
+ if (typeof name === "string" && typeof version === "string") {
986
+ return check("Package metadata", "pass", `${name}@${version}`);
987
+ }
988
+ return check("Package metadata", "warn", "package.json is missing name or version.");
989
+ } catch {
990
+ return check("Package metadata", "warn", "package.json is not valid JSON.");
991
+ }
992
+ }
993
+ function checkExtensionSource(rootDir, deps) {
994
+ const extensionDir = join3(rootDir, "extensions", "chrome");
995
+ const missing = EXTENSION_REQUIRED_FILES.filter((file) => !deps.exists(join3(extensionDir, file)));
996
+ if (missing.length === 0) {
997
+ return check(
998
+ "Chrome extension source",
999
+ "pass",
1000
+ "Manifest, side panel, service worker, and icons are present."
1001
+ );
1002
+ }
1003
+ return check(
1004
+ "Chrome extension source",
1005
+ "fail",
1006
+ `Missing ${missing.length} Chrome extension file(s): ${missing.join(", ")}`,
1007
+ "Restore the extension files before packaging or loading unpacked."
1008
+ );
1009
+ }
1010
+ function extensionManifestVersion(rootDir, deps) {
1011
+ const manifestText = deps.readText(join3(rootDir, "extensions", "chrome", "manifest.json"));
1012
+ if (manifestText === null) return null;
1013
+ try {
1014
+ const manifest = JSON.parse(manifestText);
1015
+ if (!isObject2(manifest)) return null;
1016
+ const version = manifest["version"];
1017
+ return typeof version === "string" && version !== "" ? version : null;
1018
+ } catch {
1019
+ return null;
1020
+ }
1021
+ }
1022
+ function checkExtensionPackage(rootDir, deps) {
1023
+ const distDir = join3(rootDir, "dist", "chrome-extension");
1024
+ const files = deps.listDir(distDir);
1025
+ if (files === null) {
1026
+ return check(
1027
+ "Chrome extension package",
1028
+ "warn",
1029
+ "No packaged Chrome extension artifact was found.",
1030
+ "Run `npm run extension:zip` before Chrome Web Store upload."
1031
+ );
1032
+ }
1033
+ const manifestVersion = extensionManifestVersion(rootDir, deps);
1034
+ if (manifestVersion !== null) {
1035
+ const zipName = `llm-inspector-companion-v${manifestVersion}.zip`;
1036
+ const checksumName = `${zipName}.sha256`;
1037
+ const hasZip = files.includes(zipName);
1038
+ const hasChecksum = files.includes(checksumName);
1039
+ if (hasZip && hasChecksum) {
1040
+ return check("Chrome extension package", "pass", `${zipName} with checksum is present.`);
1041
+ }
1042
+ if (hasZip) {
1043
+ return check(
1044
+ "Chrome extension package",
1045
+ "warn",
1046
+ `${zipName} exists but no .sha256 checksum was found.`,
1047
+ "Run `npm run extension:zip` to regenerate the zip and checksum."
1048
+ );
1049
+ }
1050
+ return check(
1051
+ "Chrome extension package",
1052
+ "warn",
1053
+ `Current Chrome extension package was not found: ${zipName}`,
1054
+ "Run `npm run extension:zip` before Chrome Web Store upload."
1055
+ );
1056
+ }
1057
+ const zip = files.find((file) => file.endsWith(".zip"));
1058
+ const checksum = files.find((file) => file.endsWith(".zip.sha256"));
1059
+ if (zip !== void 0 && checksum !== void 0) {
1060
+ return check("Chrome extension package", "pass", `${zip} with checksum is present.`);
1061
+ }
1062
+ if (zip !== void 0) {
1063
+ return check(
1064
+ "Chrome extension package",
1065
+ "warn",
1066
+ `${zip} exists but no .sha256 checksum was found.`,
1067
+ "Run `npm run extension:zip` to regenerate the zip and checksum."
1068
+ );
1069
+ }
1070
+ return check(
1071
+ "Chrome extension package",
1072
+ "warn",
1073
+ "No Chrome extension zip artifact was found.",
1074
+ "Run `npm run extension:zip` before Chrome Web Store upload."
1075
+ );
1076
+ }
1077
+ async function buildDoctorReport(options, deps = createDoctorDeps()) {
1078
+ const rootDir = findProjectRoot(deps.cwd, deps);
1079
+ const checks = [
1080
+ await checkProxyHealth(options.port, deps),
1081
+ checkProviderConfig(options, deps),
1082
+ checkPackage(rootDir, deps),
1083
+ checkExtensionSource(rootDir, deps),
1084
+ checkExtensionPackage(rootDir, deps)
1085
+ ];
1086
+ const passCount = checks.filter((item) => item.severity === "pass").length;
1087
+ const warnCount = checks.filter((item) => item.severity === "warn").length;
1088
+ const failCount = checks.filter((item) => item.severity === "fail").length;
1089
+ return {
1090
+ checks,
1091
+ passCount,
1092
+ warnCount,
1093
+ failCount,
1094
+ exitCode: failCount > 0 ? 1 : 0
1095
+ };
1096
+ }
1097
+ function formatDoctorReport(report) {
1098
+ const lines = ["llm-inspector doctor", ""];
1099
+ for (const item of report.checks) {
1100
+ lines.push(`${item.severity.toUpperCase().padEnd(4)} ${item.name}: ${item.message}`);
1101
+ if (item.hint !== null) {
1102
+ lines.push(` ${item.hint}`);
1103
+ }
1104
+ }
1105
+ lines.push("");
1106
+ lines.push(
1107
+ `Summary: ${report.passCount} pass, ${report.warnCount} warn, ${report.failCount} fail`
1108
+ );
1109
+ return `${lines.join("\n")}
1110
+ `;
1111
+ }
1112
+ function doctorHelp() {
1113
+ return [
1114
+ "llm-inspector doctor",
1115
+ "",
1116
+ "Usage:",
1117
+ " llm-inspector doctor [--port <port>] [--config-dir <dir>] [--providers <json>]",
1118
+ "",
1119
+ "Checks local proxy health, provider config presence, package metadata, and Chrome companion readiness.",
1120
+ ""
1121
+ ].join("\n");
1122
+ }
1123
+ async function fetchHealth(port) {
1124
+ const controller = new AbortController();
1125
+ const timeout = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
1126
+ try {
1127
+ const response = await fetch(`http://127.0.0.1:${port}/api/health`, {
1128
+ cache: "no-store",
1129
+ signal: controller.signal
1130
+ });
1131
+ return { ok: response.ok, status: response.status };
1132
+ } catch {
1133
+ return { ok: false, status: null };
1134
+ } finally {
1135
+ clearTimeout(timeout);
1136
+ }
1137
+ }
1138
+ function isPortOpen(port) {
1139
+ return new Promise((resolveOpen) => {
1140
+ const socket = createConnection({ host: "127.0.0.1", port });
1141
+ const finish = (value) => {
1142
+ socket.removeAllListeners();
1143
+ socket.destroy();
1144
+ resolveOpen(value);
1145
+ };
1146
+ socket.setTimeout(PROBE_TIMEOUT_MS);
1147
+ socket.once("connect", () => finish(true));
1148
+ socket.once("timeout", () => finish(false));
1149
+ socket.once("error", () => finish(false));
1150
+ });
1151
+ }
1152
+ function readText(path) {
1153
+ try {
1154
+ return readFileSync2(path, "utf8");
1155
+ } catch {
1156
+ return null;
1157
+ }
1158
+ }
1159
+ function listDir(path) {
1160
+ try {
1161
+ return readdirSync(path);
1162
+ } catch {
1163
+ return null;
1164
+ }
1165
+ }
1166
+ function createDoctorDeps() {
1167
+ return {
1168
+ env: process.env,
1169
+ platform: process.platform,
1170
+ cwd: process.cwd(),
1171
+ exists: existsSync3,
1172
+ readText,
1173
+ listDir,
1174
+ fetchHealth,
1175
+ isPortOpen
1176
+ };
1177
+ }
1178
+ async function runDoctor(argv) {
1179
+ const parsed = parseDoctorArgs(argv);
1180
+ if (parsed.kind === "error") {
1181
+ process.stderr.write(`${parsed.message}
1182
+ `);
1183
+ return 2;
1184
+ }
1185
+ if (parsed.options.help) {
1186
+ process.stdout.write(doctorHelp());
1187
+ return 0;
1188
+ }
1189
+ const report = await buildDoctorReport(parsed.options);
1190
+ process.stdout.write(formatDoctorReport(report));
1191
+ return report.exitCode;
1192
+ }
1193
+ var DEFAULT_PORT2, PROBE_TIMEOUT_MS, EXTENSION_REQUIRED_FILES;
1194
+ var init_doctor = __esm({
1195
+ "src/cli/doctor.ts"() {
1196
+ "use strict";
1197
+ DEFAULT_PORT2 = 25947;
1198
+ PROBE_TIMEOUT_MS = 2e3;
1199
+ EXTENSION_REQUIRED_FILES = [
1200
+ "manifest.json",
1201
+ "sidepanel.html",
1202
+ "sidepanel.js",
1203
+ "sidepanel.css",
1204
+ "service-worker.js",
1205
+ "icons/icon.svg",
1206
+ "icons/icon-16.png",
1207
+ "icons/icon-32.png",
1208
+ "icons/icon-48.png",
1209
+ "icons/icon-128.png"
1210
+ ];
1211
+ }
1212
+ });
1213
+
755
1214
  // src/cli.ts
756
1215
  import { spawn, execSync } from "node:child_process";
757
- import { createConnection } from "node:net";
1216
+ import { createConnection as createConnection2 } from "node:net";
758
1217
  import { fileURLToPath as fileURLToPath2 } from "node:url";
759
- import { dirname as dirname2, join as join3 } from "node:path";
1218
+ import { dirname as dirname2, join as join4 } from "node:path";
760
1219
  var __filename2 = fileURLToPath2(import.meta.url);
761
1220
  var __dirname2 = dirname2(__filename2);
762
- var DEFAULT_PORT2 = 25947;
1221
+ var DEFAULT_PORT3 = 25947;
763
1222
  var LOCAL_PROBE_TIMEOUT_MS = 2e3;
764
1223
  var subcommand = process.argv[2];
765
1224
  if (subcommand === "onboard") {
@@ -767,6 +1226,11 @@ if (subcommand === "onboard") {
767
1226
  const code = await runOnboard2(process.argv.slice(3));
768
1227
  process.exit(code);
769
1228
  }
1229
+ if (subcommand === "doctor") {
1230
+ const { runDoctor: runDoctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
1231
+ const code = await runDoctor2(process.argv.slice(3));
1232
+ process.exit(code);
1233
+ }
770
1234
  await runStart(process.argv.slice(2));
771
1235
  async function isInspectorHealthy(port) {
772
1236
  const controller = new AbortController();
@@ -784,12 +1248,12 @@ async function isInspectorHealthy(port) {
784
1248
  }
785
1249
  }
786
1250
  function isPortAcceptingConnections(port) {
787
- return new Promise((resolve) => {
788
- const socket = createConnection({ host: "127.0.0.1", port });
1251
+ return new Promise((resolve2) => {
1252
+ const socket = createConnection2({ host: "127.0.0.1", port });
789
1253
  const finish = (value) => {
790
1254
  socket.removeAllListeners();
791
1255
  socket.destroy();
792
- resolve(value);
1256
+ resolve2(value);
793
1257
  };
794
1258
  socket.setTimeout(LOCAL_PROBE_TIMEOUT_MS);
795
1259
  socket.once("connect", () => finish(true));
@@ -798,8 +1262,8 @@ function isPortAcceptingConnections(port) {
798
1262
  });
799
1263
  }
800
1264
  function sleep(ms) {
801
- return new Promise((resolve) => {
802
- setTimeout(resolve, ms);
1265
+ return new Promise((resolve2) => {
1266
+ setTimeout(resolve2, ms);
803
1267
  });
804
1268
  }
805
1269
  async function waitForInspectorHealthy(port, timeoutMs) {
@@ -836,18 +1300,18 @@ function openBrowser(targetUrl) {
836
1300
  browserProcess.unref();
837
1301
  }
838
1302
  function waitForProcessExit(child) {
839
- return new Promise((resolve) => {
1303
+ return new Promise((resolve2) => {
840
1304
  child.once("exit", (code) => {
841
- resolve(code ?? 1);
1305
+ resolve2(code ?? 1);
842
1306
  });
843
1307
  child.once("error", () => {
844
- resolve(1);
1308
+ resolve2(1);
845
1309
  });
846
1310
  });
847
1311
  }
848
1312
  async function runStart(args) {
849
1313
  const envPort = process.env["PORT"];
850
- const portDefault = envPort !== void 0 ? Number(envPort) : DEFAULT_PORT2;
1314
+ const portDefault = envPort !== void 0 ? Number(envPort) : DEFAULT_PORT3;
851
1315
  let port = portDefault;
852
1316
  let open = true;
853
1317
  let openWasSpecified = false;
@@ -992,10 +1456,10 @@ async function runStart(args) {
992
1456
  openBrowser(url);
993
1457
  }
994
1458
  const outputDir = __dirname2;
995
- const serverPath = join3(outputDir, "../.output/server/index.mjs");
1459
+ const serverPath = join4(outputDir, "../.output/server/index.mjs");
996
1460
  const serverEnv = { ...process.env };
997
1461
  if (configDir !== void 0) {
998
- let resolvedPath = join3(configDir, "config.json");
1462
+ let resolvedPath = join4(configDir, "config.json");
999
1463
  const msysMatch = /^\\([a-z])\\(.*)$/i.exec(resolvedPath);
1000
1464
  if (msysMatch !== null) {
1001
1465
  const drive = (msysMatch[1] ?? "").toUpperCase();
@@ -1,5 +1,5 @@
1
1
  {
2
- "date": "2026-06-18T09:12:29.690Z",
2
+ "date": "2026-06-20T00:50:46.358Z",
3
3
  "preset": "node-server",
4
4
  "framework": {
5
5
  "name": "nitro",
@@ -1 +1 @@
1
- import{r as h,j as t}from"./main-DpODUL6C.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-Bi1QXDYo.js";import{J as N}from"./json-viewer-CyJ5nYhX.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-DLMLYxyQ.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-RhHgw8Ej.js";import{J as N}from"./json-viewer-iMGYFtiP.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};