@tonyclaw/agent-inspector 2.1.3 → 2.1.4

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 (56) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-BLYcm6Dg.js → CompareDrawer-BihEPd3v.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-DYqXb6WW.js +117 -0
  4. package/.output/public/assets/{ReplayDialog-_kCy9L9E.js → ReplayDialog-DnX-6kY8.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-DWp5pWsv.js → RequestAnatomy-CIkHAxZO.js} +1 -1
  6. package/.output/public/assets/{ResponseView-Ci92o6mt.js → ResponseView-BFc8jjZM.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-C-1ZQl_b.js → StreamingChunkSequence-p8qkpF6K.js} +1 -1
  8. package/.output/public/assets/_sessionId-Csx4T_y6.js +1 -0
  9. package/.output/public/assets/index-Bcq8bZoK.css +1 -0
  10. package/.output/public/assets/index-KMuh-31x.js +1 -0
  11. package/.output/public/assets/{main-RgLvmIQk.js → main-xlSdu7_I.js} +2 -2
  12. package/.output/server/_libs/lucide-react.mjs +204 -173
  13. package/.output/server/_libs/radix-ui__react-dialog.mjs +2 -0
  14. package/.output/server/{_sessionId-DnOYbKO7.mjs → _sessionId-CwVQgxoK.mjs} +3 -3
  15. package/.output/server/_ssr/{CompareDrawer-D44_F13_.mjs → CompareDrawer-Br9Ec0ah.mjs} +3 -3
  16. package/.output/server/_ssr/{ProxyViewerContainer-Cx4p_awW.mjs → ProxyViewerContainer-Oe5Tr3C2.mjs} +982 -70
  17. package/.output/server/_ssr/{ReplayDialog-wScCF3Oc.mjs → ReplayDialog-C1_QsoA-.mjs} +4 -4
  18. package/.output/server/_ssr/{RequestAnatomy-Cf7R7PXS.mjs → RequestAnatomy-cn08QSoz.mjs} +2 -2
  19. package/.output/server/_ssr/{ResponseView-7pVIZLL-.mjs → ResponseView-CIqUCCTG.mjs} +3 -3
  20. package/.output/server/_ssr/{StreamingChunkSequence-Bs57_GbC.mjs → StreamingChunkSequence-0MhVWD2F.mjs} +3 -3
  21. package/.output/server/_ssr/{index-6eY__la9.mjs → index-jpnI5ghp.mjs} +2 -2
  22. package/.output/server/_ssr/index.mjs +2 -2
  23. package/.output/server/_ssr/{router-DRZPhZB6.mjs → router-SSOn7c09.mjs} +1970 -221
  24. package/.output/server/_tanstack-start-manifest_v-BCgy_9er.mjs +4 -0
  25. package/.output/server/index.mjs +64 -64
  26. package/package.json +2 -1
  27. package/src/components/ProxyViewer.tsx +87 -1
  28. package/src/components/ProxyViewerContainer.tsx +26 -0
  29. package/src/components/alerts/AlertsDialog.tsx +610 -0
  30. package/src/components/proxy-viewer/LogEntry.tsx +324 -51
  31. package/src/components/ui/dialog.tsx +1 -0
  32. package/src/contracts/index.ts +15 -2
  33. package/src/contracts/log.ts +18 -0
  34. package/src/lib/alertContract.ts +79 -0
  35. package/src/lib/apiClient.ts +39 -0
  36. package/src/lib/export-logs.ts +47 -9
  37. package/src/lib/logImportContract.ts +12 -0
  38. package/src/lib/useAlerts.ts +82 -0
  39. package/src/lib/useGroupEvidence.ts +6 -2
  40. package/src/lib/useGroups.ts +6 -2
  41. package/src/proxy/alerts.ts +664 -0
  42. package/src/proxy/logBodyChunks.ts +91 -0
  43. package/src/proxy/logImporter.ts +491 -0
  44. package/src/proxy/logIndex.ts +63 -2
  45. package/src/proxy/sqliteLogIndex.ts +612 -0
  46. package/src/proxy/store.ts +32 -7
  47. package/src/routes/api/alerts.summary.ts +24 -0
  48. package/src/routes/api/alerts.ts +52 -0
  49. package/src/routes/api/logs.$id.body.ts +44 -0
  50. package/src/routes/api/logs.import.ts +50 -0
  51. package/src/services/alerts.ts +12 -0
  52. package/.output/public/assets/ProxyViewerContainer-Ba5wFn00.js +0 -117
  53. package/.output/public/assets/_sessionId-DKzAmSNP.js +0 -1
  54. package/.output/public/assets/index-B-MZ9lQM.css +0 -1
  55. package/.output/public/assets/index-ZZHwgkWJ.js +0 -1
  56. package/.output/server/_tanstack-start-manifest_v-DfAVFkZ5.mjs +0 -4
@@ -5,14 +5,14 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync, copyFil
5
5
  import fs, { mkdir, appendFile, readFile, writeFile, readdir, open, stat, unlink, rename } from "node:fs/promises";
6
6
  import { createInterface } from "node:readline";
7
7
  import { Buffer } from "node:buffer";
8
- import path, { join, isAbsolute, dirname, resolve, relative } from "node:path";
8
+ import path, { basename, join, isAbsolute, dirname, resolve, relative } from "node:path";
9
9
  import { execFile, exec, spawn } from "node:child_process";
10
10
  import { fileURLToPath } from "node:url";
11
11
  import { C as Conf } from "../_libs/conf.mjs";
12
12
  import { randomUUID } from "crypto";
13
13
  import { promisify } from "node:util";
14
14
  import { Worker } from "node:worker_threads";
15
- import { randomUUID as randomUUID$1 } from "node:crypto";
15
+ import { randomUUID as randomUUID$1, createHash } from "node:crypto";
16
16
  import { M as McpServer, W as WebStandardStreamableHTTPServerTransport, R as ResourceTemplate } from "../_libs/modelcontextprotocol__server.mjs";
17
17
  import { J as JSZip } from "../_libs/jszip.mjs";
18
18
  import { homedir } from "node:os";
@@ -65,8 +65,8 @@ import "../_libs/immediate.mjs";
65
65
  import "../_libs/setimmediate.mjs";
66
66
  import "../_libs/pako.mjs";
67
67
  const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20role='img'%20aria-label='Agent%20Inspector'%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='1.5'%20stroke-linecap='round'%20stroke-linejoin='round'%20%3e%3cpath%20d='M5%2013%20C5%209%208%207%2012%207%20C16%207%2019%209%2019%2013%20C19%2016%2016%2018%2012%2018%20C8%2018%205%2016%205%2013%20Z'%20/%3e%3cpath%20d='M5%2011%20C3.5%209.5%201.5%2010%202%2012.5%20C2.5%2014%204%2013.5%205%2012.5'%20/%3e%3cpath%20d='M19%2011%20C20.5%209.5%2022.5%2010%2022%2012.5%20C21.5%2014%2020%2013.5%2019%2012.5'%20/%3e%3cline%20x1='10'%20y1='7'%20x2='9.5'%20y2='5'%20/%3e%3cline%20x1='14'%20y1='7'%20x2='14.5'%20y2='5'%20/%3e%3cline%20x1='6.5'%20y1='16'%20x2='4.5'%20y2='19.5'%20/%3e%3cline%20x1='9'%20y1='17.5'%20x2='8'%20y2='20.5'%20/%3e%3cline%20x1='15'%20y1='17.5'%20x2='16'%20y2='20.5'%20/%3e%3cline%20x1='17.5'%20y1='16'%20x2='19.5'%20y2='19.5'%20/%3e%3c/g%3e%3ccircle%20cx='9.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='14.5'%20cy='4.5'%20r='0.9'%20fill='%23f59e0b'%20/%3e%3c/svg%3e";
68
- const appCss = "/assets/index-B-MZ9lQM.css";
69
- const Route$z = createRootRoute({
68
+ const appCss = "/assets/index-Bcq8bZoK.css";
69
+ const Route$D = createRootRoute({
70
70
  head: () => ({
71
71
  meta: [
72
72
  { charSet: "utf-8" },
@@ -108,8 +108,8 @@ function RootDocument({ children }) {
108
108
  ] })
109
109
  ] });
110
110
  }
111
- const $$splitComponentImporter$1 = () => import("./index-6eY__la9.mjs");
112
- const Route$y = createFileRoute("/")({
111
+ const $$splitComponentImporter$1 = () => import("./index-jpnI5ghp.mjs");
112
+ const Route$C = createFileRoute("/")({
113
113
  component: lazyRouteComponent($$splitComponentImporter$1, "component")
114
114
  });
115
115
  const B64URL_RE = /^[A-Za-z0-9_-]+$/;
@@ -151,8 +151,8 @@ function decodeSessionIdFromPath(encoded) {
151
151
  function getSessionPath(sessionId) {
152
152
  return `/session/${encodeSessionIdForPath(sessionId)}`;
153
153
  }
154
- const $$splitComponentImporter = () => import("../_sessionId-DnOYbKO7.mjs");
155
- const Route$x = createFileRoute("/session/$sessionId")({
154
+ const $$splitComponentImporter = () => import("../_sessionId-CwVQgxoK.mjs");
155
+ const Route$B = createFileRoute("/session/$sessionId")({
156
156
  component: lazyRouteComponent($$splitComponentImporter, "component"),
157
157
  parseParams: (params) => ({
158
158
  sessionId: decodeSessionIdFromPath(params.sessionId)
@@ -385,6 +385,19 @@ const StreamingChunksArraySchema = object({
385
385
  chunks: array(StreamingChunkSchema$1),
386
386
  truncated: boolean().optional().default(false)
387
387
  });
388
+ const LogBodyPartSchema = _enum(["request", "response"]);
389
+ const LogBodyChunkSchema = object({
390
+ logId: number().int().positive(),
391
+ part: LogBodyPartSchema,
392
+ text: string(),
393
+ offset: number().int().nonnegative(),
394
+ limit: number().int().positive(),
395
+ totalBytes: number().int().nonnegative(),
396
+ textBytes: number().int().nonnegative(),
397
+ nextOffset: number().int().nonnegative().nullable(),
398
+ hasMore: boolean(),
399
+ contentMode: _enum(["empty", "partial", "full"])
400
+ });
388
401
  const CapturedLogSchema = object({
389
402
  id: number(),
390
403
  timestamp: string(),
@@ -851,12 +864,530 @@ function readChunks(path2) {
851
864
  return null;
852
865
  }
853
866
  }
867
+ const SQLITE_INDEX_FILE = "inspector.sqlite";
868
+ const SQLITE_PACKAGE_NAME = "better-sqlite3";
869
+ const BUN_SQLITE_MODULE_NAME = "bun:sqlite";
870
+ const CREATE_SCHEMA_SQL = `
871
+ CREATE TABLE IF NOT EXISTS log_index (
872
+ id INTEGER PRIMARY KEY,
873
+ file TEXT NOT NULL,
874
+ byte_offset INTEGER NOT NULL,
875
+ byte_length INTEGER NOT NULL,
876
+ session_id TEXT,
877
+ model TEXT,
878
+ timestamp TEXT NOT NULL,
879
+ method TEXT NOT NULL,
880
+ path TEXT NOT NULL,
881
+ response_status INTEGER,
882
+ input_tokens INTEGER,
883
+ output_tokens INTEGER,
884
+ cache_creation_input_tokens INTEGER,
885
+ cache_read_input_tokens INTEGER,
886
+ elapsed_ms INTEGER,
887
+ first_chunk_ms INTEGER,
888
+ total_stream_ms INTEGER,
889
+ tokens_per_second REAL,
890
+ streaming INTEGER NOT NULL,
891
+ user_agent TEXT,
892
+ origin TEXT,
893
+ api_format TEXT NOT NULL,
894
+ is_test INTEGER NOT NULL,
895
+ replay_of_log_id INTEGER,
896
+ provider_name TEXT,
897
+ client_port INTEGER,
898
+ client_pid INTEGER,
899
+ client_cwd TEXT,
900
+ client_project_folder TEXT,
901
+ streaming_chunks_path TEXT,
902
+ raw_request_body_bytes INTEGER,
903
+ response_text_bytes INTEGER,
904
+ warnings_json TEXT,
905
+ error TEXT
906
+ );
907
+ CREATE INDEX IF NOT EXISTS idx_log_index_session_id_id ON log_index(session_id, id);
908
+ CREATE INDEX IF NOT EXISTS idx_log_index_model_id ON log_index(model, id);
909
+ CREATE INDEX IF NOT EXISTS idx_log_index_timestamp ON log_index(timestamp);
910
+ `;
911
+ const UPSERT_SQL = `
912
+ INSERT INTO log_index (
913
+ id,
914
+ file,
915
+ byte_offset,
916
+ byte_length,
917
+ session_id,
918
+ model,
919
+ timestamp,
920
+ method,
921
+ path,
922
+ response_status,
923
+ input_tokens,
924
+ output_tokens,
925
+ cache_creation_input_tokens,
926
+ cache_read_input_tokens,
927
+ elapsed_ms,
928
+ first_chunk_ms,
929
+ total_stream_ms,
930
+ tokens_per_second,
931
+ streaming,
932
+ user_agent,
933
+ origin,
934
+ api_format,
935
+ is_test,
936
+ replay_of_log_id,
937
+ provider_name,
938
+ client_port,
939
+ client_pid,
940
+ client_cwd,
941
+ client_project_folder,
942
+ streaming_chunks_path,
943
+ raw_request_body_bytes,
944
+ response_text_bytes,
945
+ warnings_json,
946
+ error
947
+ ) VALUES (
948
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
949
+ )
950
+ ON CONFLICT(id) DO UPDATE SET
951
+ file = excluded.file,
952
+ byte_offset = excluded.byte_offset,
953
+ byte_length = excluded.byte_length,
954
+ session_id = excluded.session_id,
955
+ model = excluded.model,
956
+ timestamp = excluded.timestamp,
957
+ method = excluded.method,
958
+ path = excluded.path,
959
+ response_status = excluded.response_status,
960
+ input_tokens = excluded.input_tokens,
961
+ output_tokens = excluded.output_tokens,
962
+ cache_creation_input_tokens = excluded.cache_creation_input_tokens,
963
+ cache_read_input_tokens = excluded.cache_read_input_tokens,
964
+ elapsed_ms = excluded.elapsed_ms,
965
+ first_chunk_ms = excluded.first_chunk_ms,
966
+ total_stream_ms = excluded.total_stream_ms,
967
+ tokens_per_second = excluded.tokens_per_second,
968
+ streaming = excluded.streaming,
969
+ user_agent = excluded.user_agent,
970
+ origin = excluded.origin,
971
+ api_format = excluded.api_format,
972
+ is_test = excluded.is_test,
973
+ replay_of_log_id = excluded.replay_of_log_id,
974
+ provider_name = excluded.provider_name,
975
+ client_port = excluded.client_port,
976
+ client_pid = excluded.client_pid,
977
+ client_cwd = excluded.client_cwd,
978
+ client_project_folder = excluded.client_project_folder,
979
+ streaming_chunks_path = excluded.streaming_chunks_path,
980
+ raw_request_body_bytes = excluded.raw_request_body_bytes,
981
+ response_text_bytes = excluded.response_text_bytes,
982
+ warnings_json = excluded.warnings_json,
983
+ error = excluded.error
984
+ `;
985
+ let sqliteStatePromise = null;
986
+ let sqliteStatePath = null;
987
+ let activeDb = null;
988
+ let didLogUnavailable = false;
989
+ function isSqliteLogIndexEnabled() {
990
+ const configured = process.env["AGENT_INSPECTOR_SQLITE_INDEX"];
991
+ if (configured === "1") return true;
992
+ if (configured === "0") return false;
993
+ return process.env["NODE_ENV"] !== "test";
994
+ }
995
+ function getSqlitePath() {
996
+ return join(resolveLogDir(), SQLITE_INDEX_FILE);
997
+ }
998
+ function objectFromUnknown(value) {
999
+ if (value === null) return null;
1000
+ if (typeof value === "object" || typeof value === "function") return value;
1001
+ return null;
1002
+ }
1003
+ function readProperty$1(value, name) {
1004
+ let current = objectFromUnknown(value);
1005
+ while (current !== null) {
1006
+ const desc = Object.getOwnPropertyDescriptor(current, name);
1007
+ if (desc !== void 0) {
1008
+ const propertyValue = Reflect.get(current, name);
1009
+ return propertyValue;
1010
+ }
1011
+ const nextPrototype = Object.getPrototypeOf(current);
1012
+ current = objectFromUnknown(nextPrototype);
1013
+ }
1014
+ return void 0;
1015
+ }
1016
+ function readFunction(value, name) {
1017
+ const property = readProperty$1(value, name);
1018
+ return typeof property === "function" ? property : null;
1019
+ }
1020
+ function callMethod(target, methodName, args) {
1021
+ const method = readFunction(target, methodName);
1022
+ if (method === null) return void 0;
1023
+ try {
1024
+ return Reflect.apply(method, target, [...args]);
1025
+ } catch (err) {
1026
+ logger.warn("[sqliteLogIndex] SQLite method failed:", methodName, String(err));
1027
+ return void 0;
1028
+ }
1029
+ }
1030
+ function prepareStatement(db, sql) {
1031
+ return callMethod(db, "prepare", [sql]);
1032
+ }
1033
+ function runPrepared(db, sql, params = []) {
1034
+ const statement = prepareStatement(db, sql);
1035
+ if (statement === void 0) return false;
1036
+ const result = callMethod(statement, "run", params);
1037
+ callMethod(statement, "finalize", []);
1038
+ return result !== void 0;
1039
+ }
1040
+ function getPrepared(db, sql, params = []) {
1041
+ const statement = prepareStatement(db, sql);
1042
+ if (statement === void 0) return void 0;
1043
+ const result = callMethod(statement, "get", params);
1044
+ callMethod(statement, "finalize", []);
1045
+ return result;
1046
+ }
1047
+ function allPrepared(db, sql, params = []) {
1048
+ const statement = prepareStatement(db, sql);
1049
+ if (statement === void 0) return null;
1050
+ const result = callMethod(statement, "all", params);
1051
+ callMethod(statement, "finalize", []);
1052
+ return Array.isArray(result) ? result : null;
1053
+ }
1054
+ function execSql(db, sql) {
1055
+ const result = callMethod(db, "exec", [sql]);
1056
+ return result !== void 0;
1057
+ }
1058
+ function sqliteConstructorFromModule(moduleValue, exportName) {
1059
+ const exportedValue = readProperty$1(moduleValue, exportName);
1060
+ if (typeof exportedValue === "function") {
1061
+ return (path2) => Reflect.construct(exportedValue, [path2]);
1062
+ }
1063
+ return null;
1064
+ }
1065
+ async function loadSqliteModuleConstructor(moduleName, exportName) {
1066
+ try {
1067
+ const importedModule = await import(
1068
+ /* @vite-ignore */
1069
+ moduleName
1070
+ );
1071
+ const exportedConstructor = sqliteConstructorFromModule(importedModule, exportName);
1072
+ if (exportedConstructor !== null) return { constructor: exportedConstructor, reason: null };
1073
+ if (exportName === "default" && typeof importedModule === "function") {
1074
+ return {
1075
+ constructor: (path2) => Reflect.construct(importedModule, [path2]),
1076
+ reason: null
1077
+ };
1078
+ }
1079
+ return { constructor: null, reason: `${moduleName} did not expose ${exportName}` };
1080
+ } catch (err) {
1081
+ return { constructor: null, reason: String(err) };
1082
+ }
1083
+ }
1084
+ async function loadSqliteConstructor() {
1085
+ const bunRuntimeDesc = Object.getOwnPropertyDescriptor(process.versions, "bun");
1086
+ if (bunRuntimeDesc !== void 0) {
1087
+ const bunSqlite2 = await loadSqliteModuleConstructor(BUN_SQLITE_MODULE_NAME, "Database");
1088
+ if (bunSqlite2.constructor !== null) return bunSqlite2;
1089
+ const betterSqlite2 = await loadSqliteModuleConstructor(SQLITE_PACKAGE_NAME, "default");
1090
+ if (betterSqlite2.constructor !== null) return betterSqlite2;
1091
+ const reason2 = [bunSqlite2.reason, betterSqlite2.reason].filter((item) => item !== null).join("; ");
1092
+ if (!didLogUnavailable) {
1093
+ didLogUnavailable = true;
1094
+ logger.warn("[sqliteLogIndex] Optional SQLite index unavailable:", reason2);
1095
+ }
1096
+ return { constructor: null, reason: reason2 };
1097
+ }
1098
+ const betterSqlite = await loadSqliteModuleConstructor(SQLITE_PACKAGE_NAME, "default");
1099
+ if (betterSqlite.constructor !== null) return betterSqlite;
1100
+ const bunSqlite = await loadSqliteModuleConstructor(BUN_SQLITE_MODULE_NAME, "Database");
1101
+ if (bunSqlite.constructor !== null) return bunSqlite;
1102
+ const reason = [betterSqlite.reason, bunSqlite.reason].filter((item) => item !== null).join("; ");
1103
+ if (!didLogUnavailable) {
1104
+ didLogUnavailable = true;
1105
+ logger.warn("[sqliteLogIndex] Optional SQLite index unavailable:", reason);
1106
+ }
1107
+ return { constructor: null, reason };
1108
+ }
1109
+ async function initializeSqliteState() {
1110
+ const path2 = getSqlitePath();
1111
+ if (!isSqliteLogIndexEnabled()) {
1112
+ return { status: "unavailable", path: path2, reason: "SQLite log index is disabled" };
1113
+ }
1114
+ const sqliteConstructor = await loadSqliteConstructor();
1115
+ if (sqliteConstructor.constructor === null) {
1116
+ return {
1117
+ status: "unavailable",
1118
+ path: path2,
1119
+ reason: sqliteConstructor.reason ?? "SQLite runtime is not available"
1120
+ };
1121
+ }
1122
+ try {
1123
+ await mkdir(dirname(path2), { recursive: true });
1124
+ const db = sqliteConstructor.constructor(path2);
1125
+ execSql(db, "PRAGMA journal_mode = WAL");
1126
+ execSql(db, "PRAGMA synchronous = NORMAL");
1127
+ if (!execSql(db, CREATE_SCHEMA_SQL)) {
1128
+ return { status: "unavailable", path: path2, reason: "SQLite schema initialization failed" };
1129
+ }
1130
+ activeDb = db;
1131
+ return { status: "ready", db, path: path2 };
1132
+ } catch (err) {
1133
+ logger.warn("[sqliteLogIndex] Failed to initialize SQLite index:", String(err));
1134
+ return { status: "unavailable", path: path2, reason: String(err) };
1135
+ }
1136
+ }
1137
+ async function getSqliteState() {
1138
+ const path2 = getSqlitePath();
1139
+ if (sqliteStatePromise !== null && sqliteStatePath !== path2) {
1140
+ closeSqliteLogIndex();
1141
+ }
1142
+ if (sqliteStatePromise === null) {
1143
+ sqliteStatePath = path2;
1144
+ sqliteStatePromise = initializeSqliteState();
1145
+ }
1146
+ return await sqliteStatePromise;
1147
+ }
1148
+ function closeSqliteLogIndex() {
1149
+ if (activeDb !== null) {
1150
+ callMethod(activeDb, "close", []);
1151
+ }
1152
+ activeDb = null;
1153
+ sqliteStatePromise = null;
1154
+ sqliteStatePath = null;
1155
+ }
1156
+ function warningJson(warnings) {
1157
+ return warnings === void 0 ? null : JSON.stringify(warnings);
1158
+ }
1159
+ function boolToInt(value) {
1160
+ return value ? 1 : 0;
1161
+ }
1162
+ function entryParams(entry) {
1163
+ const summary = entry.summary;
1164
+ return [
1165
+ entry.id,
1166
+ entry.file,
1167
+ entry.byteOffset,
1168
+ entry.byteLength,
1169
+ entry.sessionId ?? summary?.sessionId ?? null,
1170
+ entry.model ?? summary?.model ?? null,
1171
+ summary?.timestamp ?? "",
1172
+ summary?.method ?? "",
1173
+ summary?.path ?? "",
1174
+ summary?.responseStatus ?? null,
1175
+ summary?.inputTokens ?? null,
1176
+ summary?.outputTokens ?? null,
1177
+ summary?.cacheCreationInputTokens ?? null,
1178
+ summary?.cacheReadInputTokens ?? null,
1179
+ summary?.elapsedMs ?? null,
1180
+ summary?.firstChunkMs ?? null,
1181
+ summary?.totalStreamMs ?? null,
1182
+ summary?.tokensPerSecond ?? null,
1183
+ boolToInt(summary?.streaming ?? false),
1184
+ summary?.userAgent ?? null,
1185
+ summary?.origin ?? null,
1186
+ summary?.apiFormat ?? "unknown",
1187
+ boolToInt(summary?.isTest ?? false),
1188
+ summary?.replayOfLogId ?? null,
1189
+ summary?.providerName ?? null,
1190
+ summary?.clientPort ?? null,
1191
+ summary?.clientPid ?? null,
1192
+ summary?.clientCwd ?? null,
1193
+ summary?.clientProjectFolder ?? null,
1194
+ summary?.streamingChunksPath ?? null,
1195
+ summary?.rawRequestBodyBytes ?? null,
1196
+ summary?.responseTextBytes ?? null,
1197
+ warningJson(summary?.warnings),
1198
+ summary?.error ?? null
1199
+ ];
1200
+ }
1201
+ function readNumber(row, name) {
1202
+ const value = readProperty$1(row, name);
1203
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
1204
+ }
1205
+ function readString$1(row, name) {
1206
+ const value = readProperty$1(row, name);
1207
+ return typeof value === "string" ? value : null;
1208
+ }
1209
+ function readBoolean(row, name) {
1210
+ return readNumber(row, name) === 1;
1211
+ }
1212
+ function readApiFormat(row) {
1213
+ const value = readString$1(row, "api_format");
1214
+ switch (value) {
1215
+ case "anthropic":
1216
+ return "anthropic";
1217
+ case "openai":
1218
+ return "openai";
1219
+ case "unknown":
1220
+ case null:
1221
+ return "unknown";
1222
+ default:
1223
+ return "unknown";
1224
+ }
1225
+ }
1226
+ function readWarnings(row) {
1227
+ const value = readString$1(row, "warnings_json");
1228
+ if (value === null) return void 0;
1229
+ try {
1230
+ const parsed = JSON.parse(value);
1231
+ if (!Array.isArray(parsed)) return void 0;
1232
+ const warnings = [];
1233
+ for (const item of parsed) {
1234
+ if (typeof item !== "string") return void 0;
1235
+ warnings.push(item);
1236
+ }
1237
+ return warnings;
1238
+ } catch {
1239
+ return void 0;
1240
+ }
1241
+ }
1242
+ function readRequiredNumber(row, name) {
1243
+ const value = readNumber(row, name);
1244
+ return value === null || !Number.isInteger(value) ? null : value;
1245
+ }
1246
+ function summaryFromRow(row, id) {
1247
+ return {
1248
+ id,
1249
+ timestamp: readString$1(row, "timestamp") ?? "",
1250
+ method: readString$1(row, "method") ?? "",
1251
+ path: readString$1(row, "path") ?? "",
1252
+ model: readString$1(row, "model"),
1253
+ sessionId: readString$1(row, "session_id"),
1254
+ responseStatus: readNumber(row, "response_status"),
1255
+ inputTokens: readNumber(row, "input_tokens"),
1256
+ outputTokens: readNumber(row, "output_tokens"),
1257
+ cacheCreationInputTokens: readNumber(row, "cache_creation_input_tokens"),
1258
+ cacheReadInputTokens: readNumber(row, "cache_read_input_tokens"),
1259
+ elapsedMs: readNumber(row, "elapsed_ms"),
1260
+ firstChunkMs: readNumber(row, "first_chunk_ms"),
1261
+ totalStreamMs: readNumber(row, "total_stream_ms"),
1262
+ tokensPerSecond: readNumber(row, "tokens_per_second"),
1263
+ streaming: readBoolean(row, "streaming"),
1264
+ userAgent: readString$1(row, "user_agent"),
1265
+ origin: readString$1(row, "origin"),
1266
+ apiFormat: readApiFormat(row),
1267
+ isTest: readBoolean(row, "is_test"),
1268
+ replayOfLogId: readNumber(row, "replay_of_log_id"),
1269
+ providerName: readString$1(row, "provider_name"),
1270
+ clientPort: readNumber(row, "client_port"),
1271
+ clientPid: readNumber(row, "client_pid"),
1272
+ clientCwd: readString$1(row, "client_cwd"),
1273
+ clientProjectFolder: readString$1(row, "client_project_folder"),
1274
+ streamingChunksPath: readString$1(row, "streaming_chunks_path"),
1275
+ rawRequestBodyBytes: readNumber(row, "raw_request_body_bytes"),
1276
+ responseTextBytes: readNumber(row, "response_text_bytes"),
1277
+ warnings: readWarnings(row),
1278
+ error: readString$1(row, "error")
1279
+ };
1280
+ }
1281
+ function entryFromRow(row) {
1282
+ const id = readRequiredNumber(row, "id");
1283
+ const file = readString$1(row, "file");
1284
+ const byteOffset = readRequiredNumber(row, "byte_offset");
1285
+ const byteLength = readRequiredNumber(row, "byte_length");
1286
+ if (id === null || file === null || byteOffset === null || byteLength === null) return null;
1287
+ return {
1288
+ id,
1289
+ file,
1290
+ byteOffset,
1291
+ byteLength,
1292
+ sessionId: readString$1(row, "session_id"),
1293
+ model: readString$1(row, "model"),
1294
+ summary: summaryFromRow(row, id)
1295
+ };
1296
+ }
1297
+ async function getSqliteLogIndexMaxId() {
1298
+ const state = await getSqliteState();
1299
+ if (state.status !== "ready") return null;
1300
+ const row = getPrepared(state.db, "SELECT MAX(id) AS max_id FROM log_index");
1301
+ return readNumber(row, "max_id") ?? 0;
1302
+ }
1303
+ async function upsertSqliteLogIndexEntry(entry) {
1304
+ if (entry.summary === void 0) return false;
1305
+ const state = await getSqliteState();
1306
+ if (state.status !== "ready") return false;
1307
+ return runPrepared(state.db, UPSERT_SQL, entryParams(entry));
1308
+ }
1309
+ async function syncSqliteLogIndexEntries(entries) {
1310
+ const state = await getSqliteState();
1311
+ if (state.status !== "ready") return false;
1312
+ if (entries.length === 0) return true;
1313
+ if (!execSql(state.db, "BEGIN IMMEDIATE")) return false;
1314
+ try {
1315
+ for (const entry of entries) {
1316
+ if (entry.summary === void 0) continue;
1317
+ if (!runPrepared(state.db, UPSERT_SQL, entryParams(entry))) {
1318
+ execSql(state.db, "ROLLBACK");
1319
+ return false;
1320
+ }
1321
+ }
1322
+ return execSql(state.db, "COMMIT");
1323
+ } catch (err) {
1324
+ execSql(state.db, "ROLLBACK");
1325
+ logger.warn("[sqliteLogIndex] Failed to sync SQLite index:", String(err));
1326
+ return false;
1327
+ }
1328
+ }
1329
+ async function findSqliteLogIndexEntry(id) {
1330
+ const state = await getSqliteState();
1331
+ if (state.status !== "ready") return null;
1332
+ const row = getPrepared(state.db, "SELECT * FROM log_index WHERE id = ?", [id]);
1333
+ return entryFromRow(row);
1334
+ }
1335
+ async function listSqliteLogIndexEntries({
1336
+ sessionId,
1337
+ model
1338
+ } = {}) {
1339
+ const state = await getSqliteState();
1340
+ if (state.status !== "ready") return null;
1341
+ const clauses = [];
1342
+ const params = [];
1343
+ if (sessionId !== void 0) {
1344
+ clauses.push("session_id = ?");
1345
+ params.push(sessionId);
1346
+ }
1347
+ if (model !== void 0) {
1348
+ clauses.push("model = ?");
1349
+ params.push(model);
1350
+ }
1351
+ const where = clauses.length === 0 ? "" : ` WHERE ${clauses.join(" AND ")}`;
1352
+ const rows = allPrepared(state.db, `SELECT * FROM log_index${where} ORDER BY id ASC`, params);
1353
+ if (rows === null) return null;
1354
+ const entries = [];
1355
+ for (const row of rows) {
1356
+ const entry = entryFromRow(row);
1357
+ if (entry !== null) entries.push(entry);
1358
+ }
1359
+ return entries;
1360
+ }
1361
+ async function replaceSqliteLogIndexEntries(entries) {
1362
+ const state = await getSqliteState();
1363
+ if (state.status !== "ready") return false;
1364
+ if (!execSql(state.db, "BEGIN IMMEDIATE")) return false;
1365
+ try {
1366
+ if (!runPrepared(state.db, "DELETE FROM log_index")) {
1367
+ execSql(state.db, "ROLLBACK");
1368
+ return false;
1369
+ }
1370
+ for (const entry of entries) {
1371
+ if (entry.summary === void 0) continue;
1372
+ if (!runPrepared(state.db, UPSERT_SQL, entryParams(entry))) {
1373
+ execSql(state.db, "ROLLBACK");
1374
+ return false;
1375
+ }
1376
+ }
1377
+ return execSql(state.db, "COMMIT");
1378
+ } catch (err) {
1379
+ execSql(state.db, "ROLLBACK");
1380
+ logger.warn("[sqliteLogIndex] Failed to replace SQLite index:", String(err));
1381
+ return false;
1382
+ }
1383
+ }
854
1384
  const INDEX_VERSION = 1;
855
1385
  const INDEX_FILE = "logs.idx";
856
1386
  function getIndexPath() {
857
1387
  return join(resolveLogDir(), INDEX_FILE);
858
1388
  }
859
1389
  let cachedIndex = null;
1390
+ let sqliteBackfillScheduledMaxId = 0;
860
1391
  function textByteLength$2(value) {
861
1392
  return value === null ? null : Buffer.byteLength(value, "utf8");
862
1393
  }
@@ -950,10 +1481,12 @@ async function saveIndex(index) {
950
1481
  }
951
1482
  async function addToIndex(id, file, byteOffset, byteLength, metadata) {
952
1483
  const index = await loadIndex();
953
- index.entries[id] = metadata === void 0 ? { id, file, byteOffset, byteLength } : { id, file, byteOffset, byteLength, ...metadata };
1484
+ const entry = metadata === void 0 ? { id, file, byteOffset, byteLength } : { id, file, byteOffset, byteLength, ...metadata };
1485
+ index.entries[id] = entry;
954
1486
  if (id > index.maxId) {
955
1487
  index.maxId = id;
956
1488
  }
1489
+ void upsertSqliteLogIndexEntry(entry);
957
1490
  scheduleIndexFlush();
958
1491
  }
959
1492
  let indexFlushScheduled = false;
@@ -981,13 +1514,50 @@ async function flushIndex() {
981
1514
  await saveIndex(index);
982
1515
  }
983
1516
  async function findInIndex(id) {
1517
+ const sqliteEntry = await findSqliteLogIndexEntry(id);
1518
+ if (sqliteEntry !== null) return sqliteEntry;
984
1519
  const index = await loadIndex();
985
1520
  return index.entries[id] ?? null;
986
1521
  }
987
1522
  async function listIndexEntries() {
988
1523
  const index = await loadIndex();
1524
+ const sqliteMaxId = await getSqliteLogIndexMaxId();
1525
+ if (sqliteMaxId !== null && sqliteMaxId >= index.maxId) {
1526
+ const sqliteEntries = await listSqliteLogIndexEntries();
1527
+ if (sqliteEntries !== null) return sqliteEntries;
1528
+ }
1529
+ maybeBackfillSqliteIndex(index, sqliteMaxId);
989
1530
  return Object.values(index.entries).sort((left, right) => left.id - right.id);
990
1531
  }
1532
+ async function listFilteredIndexEntries({
1533
+ sessionId,
1534
+ model
1535
+ }) {
1536
+ const index = await loadIndex();
1537
+ const sqliteMaxId = await getSqliteLogIndexMaxId();
1538
+ if (sqliteMaxId !== null && sqliteMaxId >= index.maxId) {
1539
+ const sqliteEntries = await listSqliteLogIndexEntries({ sessionId, model });
1540
+ if (sqliteEntries !== null) return sqliteEntries;
1541
+ }
1542
+ maybeBackfillSqliteIndex(index, sqliteMaxId);
1543
+ return Object.values(index.entries).sort((left, right) => left.id - right.id).filter((entry) => {
1544
+ if (sessionId !== void 0 && entry.sessionId !== sessionId) return false;
1545
+ if (model !== void 0 && entry.model !== model) return false;
1546
+ return true;
1547
+ });
1548
+ }
1549
+ function maybeBackfillSqliteIndex(index, sqliteMaxId) {
1550
+ if (sqliteMaxId === null) return;
1551
+ if (index.maxId <= sqliteMaxId) return;
1552
+ if (index.maxId <= sqliteBackfillScheduledMaxId) return;
1553
+ sqliteBackfillScheduledMaxId = index.maxId;
1554
+ const entries = Object.values(index.entries);
1555
+ void syncSqliteLogIndexEntries(entries).then((ok) => {
1556
+ if (!ok && sqliteMaxId < sqliteBackfillScheduledMaxId) {
1557
+ sqliteBackfillScheduledMaxId = sqliteMaxId;
1558
+ }
1559
+ });
1560
+ }
991
1561
  function readStringOrNullField(entry, field) {
992
1562
  const desc = Object.getOwnPropertyDescriptor(entry, field);
993
1563
  if (desc === void 0) return null;
@@ -1113,6 +1683,7 @@ async function rebuildIndex() {
1113
1683
  if (!existsSync(logDir)) {
1114
1684
  cachedIndex = newIndex;
1115
1685
  await saveIndex(newIndex);
1686
+ await replaceSqliteLogIndexEntries([]);
1116
1687
  return newIndex;
1117
1688
  }
1118
1689
  const files = (await readdir(logDir)).filter((f) => f.endsWith(".jsonl")).sort();
@@ -1127,6 +1698,7 @@ async function rebuildIndex() {
1127
1698
  }
1128
1699
  cachedIndex = newIndex;
1129
1700
  await saveIndex(newIndex);
1701
+ await replaceSqliteLogIndexEntries(Object.values(newIndex.entries));
1130
1702
  return newIndex;
1131
1703
  }
1132
1704
  let idGenerationPromise = null;
@@ -1155,7 +1727,8 @@ async function getNextLogId() {
1155
1727
  await acquireLock();
1156
1728
  try {
1157
1729
  const index = await loadIndex();
1158
- const nextId = index.maxId + 1;
1730
+ const sqliteMaxId = await getSqliteLogIndexMaxId();
1731
+ const nextId = Math.max(index.maxId, sqliteMaxId ?? 0) + 1;
1159
1732
  index.maxId = nextId;
1160
1733
  cachedIndex = index;
1161
1734
  return nextId;
@@ -1624,7 +2197,7 @@ function rememberLogSession(log) {
1624
2197
  knownLogSessions.set(log.id, sessionId);
1625
2198
  return true;
1626
2199
  }
1627
- function isFailedLog(log) {
2200
+ function isFailedLog$1(log) {
1628
2201
  const hasError = log.error !== null && log.error !== void 0 && log.error.length > 0;
1629
2202
  const hasErrorStatus = log.responseStatus !== null && log.responseStatus >= 400;
1630
2203
  return hasError || hasErrorStatus;
@@ -1648,7 +2221,7 @@ function markSessionFinished(log, sourceOverride) {
1648
2221
  completedLogIds.add(log.id);
1649
2222
  session.completedRequests += 1;
1650
2223
  }
1651
- if (isFailedLog(log) && failedLogIds.has(log.id) === false) {
2224
+ if (isFailedLog$1(log) && failedLogIds.has(log.id) === false) {
1652
2225
  failedLogIds.add(log.id);
1653
2226
  session.failedRequests += 1;
1654
2227
  }
@@ -1798,8 +2371,8 @@ function compactLogForList(log) {
1798
2371
  rawHeaders: void 0,
1799
2372
  headers: void 0,
1800
2373
  streamingChunks: void 0,
1801
- rawRequestBodyBytes: textByteLength$1(log.rawRequestBody),
1802
- responseTextBytes: textByteLength$1(log.responseText),
2374
+ rawRequestBodyBytes: log.rawRequestBodyBytes ?? textByteLength$1(log.rawRequestBody),
2375
+ responseTextBytes: log.responseTextBytes ?? textByteLength$1(log.responseText),
1803
2376
  bodyContentMode: "compact"
1804
2377
  };
1805
2378
  }
@@ -1874,6 +2447,19 @@ async function addTestLogEntry(entry) {
1874
2447
  emitLogUpdate(log);
1875
2448
  return log;
1876
2449
  }
2450
+ async function importCapturedLogs(entries, sessionId) {
2451
+ const imported = [];
2452
+ for (const entry of entries) {
2453
+ const log = await addTestLogEntry({
2454
+ ...entry,
2455
+ sessionId,
2456
+ isTest: false,
2457
+ replayOfLogId: null
2458
+ });
2459
+ imported.push(log);
2460
+ }
2461
+ return imported;
2462
+ }
1877
2463
  async function createLog(method, path2, requestBody, headers, clientInfo, rawHeaders, upstreamHeaders, apiFormat = "unknown", model = null, sessionId = null, preAcquiredId) {
1878
2464
  const userAgent = headers.get("user-agent");
1879
2465
  const origin = headers.get("origin");
@@ -2164,10 +2750,10 @@ function matchesLogIndexEntryFilters(entry, sessionId, model) {
2164
2750
  return true;
2165
2751
  }
2166
2752
  async function buildLogCursorPageIndexFromLogIndex(options, allowRebuild) {
2167
- let entries = await listIndexEntries();
2753
+ let entries = await listFilteredIndexEntries(options);
2168
2754
  if (entries.length === 0 && allowRebuild) {
2169
2755
  await rebuildIndex();
2170
- entries = await listIndexEntries();
2756
+ entries = await listFilteredIndexEntries(options);
2171
2757
  }
2172
2758
  if (entries.some((entry) => !hasLogIndexFilterMetadata(entry))) {
2173
2759
  if (!allowRebuild) return null;
@@ -2325,7 +2911,7 @@ async function collectSessionLogSummaries(sessionId, includeHistory) {
2325
2911
  return [...summariesById.values()];
2326
2912
  }
2327
2913
  async function collectIndexedSessionLogSummaries(sessionId) {
2328
- let entries = await listIndexEntries();
2914
+ let entries = await listFilteredIndexEntries({ sessionId });
2329
2915
  if (entries.length === 0) return [];
2330
2916
  const needsMetadataRebuild = entries.some((entry) => !hasLogIndexFilterMetadata(entry));
2331
2917
  const needsSummaryRebuild = entries.some((entry) => {
@@ -2334,7 +2920,7 @@ async function collectIndexedSessionLogSummaries(sessionId) {
2334
2920
  });
2335
2921
  if (needsMetadataRebuild || needsSummaryRebuild) {
2336
2922
  await rebuildIndex();
2337
- entries = await listIndexEntries();
2923
+ entries = await listFilteredIndexEntries({ sessionId });
2338
2924
  }
2339
2925
  const summaries = [];
2340
2926
  for (const entry of entries) {
@@ -2430,6 +3016,7 @@ function clearAllLogs() {
2430
3016
  memoryCache.clear();
2431
3017
  clearLogCursorPageIndexes();
2432
3018
  clearSessionRegistry();
3019
+ closeSqliteLogIndex();
2433
3020
  return { cleared: count };
2434
3021
  }
2435
3022
  async function deleteMatchingFiles(dir, shouldDelete) {
@@ -2460,7 +3047,7 @@ async function clearPersistedLogStorage() {
2460
3047
  const [logFilesDeleted, chunkFilesDeleted] = await Promise.all([
2461
3048
  deleteMatchingFiles(
2462
3049
  resolveLogDir(),
2463
- (fileName) => fileName.endsWith(".jsonl") || fileName === "logs.idx"
3050
+ (fileName) => fileName.endsWith(".jsonl") || fileName === "logs.idx" || fileName === "inspector.sqlite" || fileName.startsWith("inspector.sqlite-")
2464
3051
  ),
2465
3052
  deleteMatchingFiles(
2466
3053
  getChunksDir(),
@@ -4604,7 +5191,7 @@ function firstChunkMsFromChunks(chunks) {
4604
5191
  if (!Number.isFinite(first.timestamp) || first.timestamp < 0) return null;
4605
5192
  return Math.floor(first.timestamp);
4606
5193
  }
4607
- function parseJson(raw) {
5194
+ function parseJson$1(raw) {
4608
5195
  if (raw === null) return { ok: false };
4609
5196
  try {
4610
5197
  return { ok: true, value: JSON.parse(raw) };
@@ -4963,8 +5550,8 @@ function uniqueWarnings(warnings) {
4963
5550
  return unique2;
4964
5551
  }
4965
5552
  function analyzeToolSchemaWarnings(input) {
4966
- const request = parseJson(input.rawRequestBody);
4967
- const response = parseJson(input.responseText);
5553
+ const request = parseJson$1(input.rawRequestBody);
5554
+ const response = parseJson$1(input.responseText);
4968
5555
  if (!request.ok || !response.ok) return [];
4969
5556
  const toolSchemas = extractToolSchemas(request.value, input.apiFormat);
4970
5557
  const toolCalls = extractToolCalls(response.value, input.apiFormat);
@@ -5794,7 +6381,7 @@ async function handleProxy(req) {
5794
6381
  }
5795
6382
  return handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log, captureFullDetails);
5796
6383
  }
5797
- const Route$w = createFileRoute("/proxy/$")({
6384
+ const Route$A = createFileRoute("/proxy/$")({
5798
6385
  server: {
5799
6386
  handlers: {
5800
6387
  GET: ({ request }) => handleProxy(request),
@@ -5806,7 +6393,7 @@ const Route$w = createFileRoute("/proxy/$")({
5806
6393
  }
5807
6394
  }
5808
6395
  });
5809
- function parsePositiveInt$2(value) {
6396
+ function parsePositiveInt$4(value) {
5810
6397
  if (value === null) return void 0;
5811
6398
  const parsed = Number(value);
5812
6399
  if (!Number.isInteger(parsed) || parsed < 1) return void 0;
@@ -5815,7 +6402,7 @@ function parsePositiveInt$2(value) {
5815
6402
  function parseBooleanFlag(value) {
5816
6403
  return value === "1" || value === "true";
5817
6404
  }
5818
- const Route$v = createFileRoute("/api/sessions")({
6405
+ const Route$z = createFileRoute("/api/sessions")({
5819
6406
  server: {
5820
6407
  handlers: {
5821
6408
  GET: async ({ request }) => {
@@ -5828,7 +6415,7 @@ const Route$v = createFileRoute("/api/sessions")({
5828
6415
  const info = await getSessionInfo(sessionId, {
5829
6416
  baseUrl: url.origin,
5830
6417
  includeHistory: parseBooleanFlag(url.searchParams.get("includeHistory")),
5831
- latestLogLimit: parsePositiveInt$2(url.searchParams.get("limit"))
6418
+ latestLogLimit: parsePositiveInt$4(url.searchParams.get("limit"))
5832
6419
  });
5833
6420
  if (info === null) {
5834
6421
  return Response.json({ error: "Session not found" }, { status: 404 });
@@ -7246,19 +7833,19 @@ async function readJsonBody$6(request) {
7246
7833
  return { ok: false };
7247
7834
  }
7248
7835
  }
7249
- function parsePositiveInt$1(value, fallback) {
7836
+ function parsePositiveInt$3(value, fallback) {
7250
7837
  if (value === null) return fallback;
7251
7838
  const parsed = Number(value);
7252
7839
  if (!Number.isInteger(parsed) || parsed < 1) return fallback;
7253
7840
  return parsed;
7254
7841
  }
7255
- const Route$u = createFileRoute("/api/runs")({
7842
+ const Route$y = createFileRoute("/api/runs")({
7256
7843
  server: {
7257
7844
  handlers: {
7258
7845
  GET: ({ request }) => {
7259
7846
  const url = new URL(request.url);
7260
7847
  if (url.searchParams.get("failures") === "1") {
7261
- const limit = parsePositiveInt$1(
7848
+ const limit = parsePositiveInt$3(
7262
7849
  url.searchParams.get("limit"),
7263
7850
  RECENT_FAILURES_DEFAULT_LIMIT
7264
7851
  );
@@ -7297,7 +7884,7 @@ const ProviderInputSchema = object({
7297
7884
  modelMetadata: array(ProviderModelMetadataSchema).optional(),
7298
7885
  source: _enum(["company", "personal"]).optional()
7299
7886
  });
7300
- const Route$t = createFileRoute("/api/providers")({
7887
+ const Route$x = createFileRoute("/api/providers")({
7301
7888
  server: {
7302
7889
  handlers: {
7303
7890
  GET: ({ request }) => {
@@ -7331,14 +7918,14 @@ const Route$t = createFileRoute("/api/providers")({
7331
7918
  }
7332
7919
  }
7333
7920
  });
7334
- const Route$s = createFileRoute("/api/models")({
7921
+ const Route$w = createFileRoute("/api/models")({
7335
7922
  server: {
7336
7923
  handlers: {
7337
7924
  GET: () => Response.json(getModels())
7338
7925
  }
7339
7926
  }
7340
7927
  });
7341
- const version = "2.1.3";
7928
+ const version = "2.1.4";
7342
7929
  const packageJson = {
7343
7930
  version
7344
7931
  };
@@ -7483,7 +8070,7 @@ function isCompletedMember(member) {
7483
8070
  const status = memberEffectiveStatus(member);
7484
8071
  return status === "completed";
7485
8072
  }
7486
- function isFailedMember(member) {
8073
+ function isFailedMember$1(member) {
7487
8074
  const status = memberEffectiveStatus(member);
7488
8075
  return status === "failed" || status === "cancelled";
7489
8076
  }
@@ -7527,7 +8114,7 @@ function buildSummary(members) {
7527
8114
  members.flatMap((member) => [member.member.provider, ...member.session?.providers ?? []])
7528
8115
  ),
7529
8116
  completedMembers: members.filter(isCompletedMember).length,
7530
- failedMembers: members.filter(isFailedMember).length,
8117
+ failedMembers: members.filter(isFailedMember$1).length,
7531
8118
  runningMembers: members.filter(isRunningMember).length
7532
8119
  };
7533
8120
  }
@@ -9839,7 +10426,7 @@ const PROMPT_NAMES = [
9839
10426
  "inspector_generate_group_report",
9840
10427
  "inspector_extract_repro_steps"
9841
10428
  ];
9842
- const Route$r = createFileRoute("/api/mcp")({
10429
+ const Route$v = createFileRoute("/api/mcp")({
9843
10430
  server: {
9844
10431
  handlers: {
9845
10432
  // The SDK may issue either POST, GET, or DELETE. TanStack Start only
@@ -9855,15 +10442,15 @@ const LOG_SEARCH_DEFAULT_LIMIT = 10;
9855
10442
  const LOG_SEARCH_MAX_LIMIT = 50;
9856
10443
  const LOG_SEARCH_DEFAULT_SCAN_LIMIT = 200;
9857
10444
  const LOG_SEARCH_MAX_SCAN_LIMIT = 1e3;
9858
- function clampPositiveInt(value, fallback, max) {
10445
+ function clampPositiveInt$1(value, fallback, max) {
9859
10446
  if (!Number.isInteger(value) || value < 1) return fallback;
9860
10447
  return Math.min(value, max);
9861
10448
  }
9862
10449
  function clampLogSearchLimit(value) {
9863
- return clampPositiveInt(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
10450
+ return clampPositiveInt$1(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
9864
10451
  }
9865
10452
  function clampLogSearchScanLimit(value) {
9866
- return clampPositiveInt(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
10453
+ return clampPositiveInt$1(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
9867
10454
  }
9868
10455
  function queryTerms(query) {
9869
10456
  return query.trim().toLowerCase().split(/\s+/).filter((term) => term.length > 0);
@@ -9944,7 +10531,7 @@ function parseNonNegativeInt(value, fallback) {
9944
10531
  if (!Number.isInteger(parsed) || parsed < 0) return fallback;
9945
10532
  return parsed;
9946
10533
  }
9947
- function parsePositiveInt(value, fallback) {
10534
+ function parsePositiveInt$2(value, fallback) {
9948
10535
  if (value === null) return fallback;
9949
10536
  const parsed = Number(value);
9950
10537
  if (!Number.isInteger(parsed) || parsed < 1) return fallback;
@@ -9956,7 +10543,7 @@ function parseOptionalPositiveInt(value) {
9956
10543
  if (!Number.isInteger(parsed) || parsed < 1) return { ok: false };
9957
10544
  return { ok: true, value: parsed };
9958
10545
  }
9959
- const Route$q = createFileRoute("/api/logs")({
10546
+ const Route$u = createFileRoute("/api/logs")({
9960
10547
  server: {
9961
10548
  handlers: {
9962
10549
  GET: async ({ request }) => {
@@ -9978,8 +10565,8 @@ const Route$q = createFileRoute("/api/logs")({
9978
10565
  const query = url.searchParams.get("q") ?? url.searchParams.get("search");
9979
10566
  const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
9980
10567
  if (query !== null) {
9981
- const limit2 = parsePositiveInt(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
9982
- const scanLimit = parsePositiveInt(
10568
+ const limit2 = parsePositiveInt$2(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
10569
+ const scanLimit = parsePositiveInt$2(
9983
10570
  url.searchParams.get("scanLimit"),
9984
10571
  LOG_SEARCH_DEFAULT_SCAN_LIMIT
9985
10572
  );
@@ -9987,7 +10574,7 @@ const Route$q = createFileRoute("/api/logs")({
9987
10574
  await searchLogsPage({ query, sessionId, model, offset, limit: limit2, scanLimit })
9988
10575
  );
9989
10576
  }
9990
- const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
10577
+ const limit = parsePositiveInt$2(url.searchParams.get("limit"), 50);
9991
10578
  const includeBodies = url.searchParams.get("compact") !== "1";
9992
10579
  if (url.searchParams.get("cursor") === "1" || url.searchParams.get("cursor") === "true") {
9993
10580
  const beforeLogId = parseOptionalPositiveInt(url.searchParams.get("beforeLogId"));
@@ -10057,7 +10644,7 @@ const Route$q = createFileRoute("/api/logs")({
10057
10644
  }
10058
10645
  });
10059
10646
  logger.debug("Health endpoint loaded");
10060
- const Route$p = createFileRoute("/api/health")({
10647
+ const Route$t = createFileRoute("/api/health")({
10061
10648
  server: {
10062
10649
  handlers: {
10063
10650
  GET: () => {
@@ -10075,7 +10662,7 @@ async function readJsonBody$5(request) {
10075
10662
  return { ok: false };
10076
10663
  }
10077
10664
  }
10078
- const Route$o = createFileRoute("/api/groups")({
10665
+ const Route$s = createFileRoute("/api/groups")({
10079
10666
  server: {
10080
10667
  handlers: {
10081
10668
  GET: () => Response.json(listInspectorGroups()),
@@ -10105,7 +10692,7 @@ const RuntimeConfigPatchSchema = object({
10105
10692
  }).strict().refine((v) => Object.keys(v).length > 0, {
10106
10693
  message: "At least one field must be provided"
10107
10694
  });
10108
- const Route$n = createFileRoute("/api/config")({
10695
+ const Route$r = createFileRoute("/api/config")({
10109
10696
  server: {
10110
10697
  handlers: {
10111
10698
  GET: () => {
@@ -10134,107 +10721,703 @@ const Route$n = createFileRoute("/api/config")({
10134
10721
  }
10135
10722
  }
10136
10723
  });
10137
- async function readJsonBody$4(request) {
10138
- try {
10139
- const raw = await request.text();
10140
- if (raw.trim().length === 0) return { ok: true, value: {} };
10141
- return { ok: true, value: JSON.parse(raw) };
10142
- } catch {
10143
- return { ok: false };
10144
- }
10145
- }
10146
- const Route$m = createFileRoute("/api/runs/$runId")({
10147
- server: {
10148
- handlers: {
10149
- GET: ({ params }) => {
10150
- const run = getInspectorRun(params.runId);
10151
- if (!run.ok) {
10152
- return Response.json({ error: run.message }, { status: run.status });
10153
- }
10154
- return Response.json(run.value);
10155
- },
10156
- PATCH: async ({ params, request }) => {
10157
- const body = await readJsonBody$4(request);
10158
- if (!body.ok) {
10159
- return Response.json({ error: "Invalid JSON body" }, { status: 400 });
10160
- }
10161
- const parsed = UpdateInspectorRunInputSchema.safeParse(body.value);
10162
- if (!parsed.success) {
10163
- return Response.json(
10164
- { error: "Invalid request body", details: parsed.error.format() },
10165
- { status: 400 }
10166
- );
10167
- }
10168
- const updated = updateInspectorRun(params.runId, parsed.data);
10169
- if (!updated.ok) {
10170
- return Response.json({ error: updated.message }, { status: updated.status });
10171
- }
10172
- return Response.json(updated.value);
10173
- }
10174
- }
10175
- }
10724
+ const AlertSeveritySchema = _enum(["critical", "warning", "notice"]);
10725
+ const AlertStatusSchema = _enum(["open"]);
10726
+ const AlertSourceSchema = _enum(["proxy", "tool-schema", "run", "group"]);
10727
+ const AlertCategorySchema = _enum([
10728
+ "request-failure",
10729
+ "request-timeout",
10730
+ "slow-response",
10731
+ "tool-schema",
10732
+ "run-failure",
10733
+ "group-failure",
10734
+ "group-incomplete"
10735
+ ]);
10736
+ const AlertEvidenceKindSchema = _enum(["log", "session", "run", "group"]);
10737
+ const AlertApiFormatSchema = _enum(["anthropic", "openai", "unknown"]);
10738
+ const AlertEvidenceLinkSchema = object({
10739
+ kind: AlertEvidenceKindSchema,
10740
+ id: string(),
10741
+ label: string(),
10742
+ href: string().nullable()
10176
10743
  });
10177
- const ZHIPU_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
10178
- const ZHIPU_CODING_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
10179
- const ZHIPU_CODING_ANTHROPIC_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
10180
- function readJsonSafe(filePath) {
10181
- try {
10182
- if (!existsSync(filePath)) return null;
10183
- const raw = readFileSync(filePath, "utf-8");
10184
- const parsed = JSON.parse(raw);
10185
- return isPlainRecord(parsed) ? parsed : null;
10186
- } catch {
10187
- return null;
10744
+ const AlertSchema = object({
10745
+ id: string(),
10746
+ fingerprint: string(),
10747
+ severity: AlertSeveritySchema,
10748
+ category: AlertCategorySchema,
10749
+ source: AlertSourceSchema,
10750
+ status: AlertStatusSchema,
10751
+ title: string(),
10752
+ message: string(),
10753
+ count: number().int().positive(),
10754
+ firstSeenAt: string(),
10755
+ lastSeenAt: string(),
10756
+ logIds: array(number().int().positive()),
10757
+ sessionIds: array(string()),
10758
+ runIds: array(string()),
10759
+ groupIds: array(string()),
10760
+ provider: string().nullable(),
10761
+ model: string().nullable(),
10762
+ apiFormat: AlertApiFormatSchema.nullable(),
10763
+ evidence: array(AlertEvidenceLinkSchema),
10764
+ metadata: record(string(), JsonValueSchema)
10765
+ });
10766
+ const AlertCategoryCountSchema = object({
10767
+ category: AlertCategorySchema,
10768
+ count: number().int().nonnegative()
10769
+ });
10770
+ const AlertSummarySchema = object({
10771
+ total: number().int().nonnegative(),
10772
+ open: number().int().nonnegative(),
10773
+ critical: number().int().nonnegative(),
10774
+ warning: number().int().nonnegative(),
10775
+ notice: number().int().nonnegative(),
10776
+ byCategory: array(AlertCategoryCountSchema)
10777
+ });
10778
+ const AlertListResponseSchema = object({
10779
+ alerts: array(AlertSchema),
10780
+ total: number().int().nonnegative(),
10781
+ limit: number().int().positive(),
10782
+ summary: AlertSummarySchema
10783
+ });
10784
+ const DEFAULT_ALERT_LIMIT = 50;
10785
+ const MAX_ALERT_LIMIT = 200;
10786
+ const DEFAULT_ALERT_SCAN_LIMIT = 500;
10787
+ const MAX_ALERT_SCAN_LIMIT = 2e3;
10788
+ function clampPositiveInt(value, fallback, max) {
10789
+ if (value === void 0) return fallback;
10790
+ if (!Number.isInteger(value) || value < 1) return fallback;
10791
+ return Math.min(value, max);
10792
+ }
10793
+ function clampAlertLimit(value) {
10794
+ return clampPositiveInt(value, DEFAULT_ALERT_LIMIT, MAX_ALERT_LIMIT);
10795
+ }
10796
+ function clampAlertScanLimit(value) {
10797
+ return clampPositiveInt(value, DEFAULT_ALERT_SCAN_LIMIT, MAX_ALERT_SCAN_LIMIT);
10798
+ }
10799
+ function alertIdFor(value) {
10800
+ const digest = createHash("sha1").update(value).digest("hex").slice(0, 16);
10801
+ return `alert_${digest}`;
10802
+ }
10803
+ function sanitizeFingerprintPart(value) {
10804
+ if (value === null) return "-";
10805
+ return String(value).trim().toLowerCase().replace(/\s+/g, " ").slice(0, 240);
10806
+ }
10807
+ function fingerprint(parts) {
10808
+ return parts.map(sanitizeFingerprintPart).join("|");
10809
+ }
10810
+ function uniqueStrings$1(values) {
10811
+ return [...new Set(values)].sort();
10812
+ }
10813
+ function uniqueNumbers(values) {
10814
+ return [...new Set(values)].sort((left, right) => left - right);
10815
+ }
10816
+ function logEvidence(logId) {
10817
+ const id = String(logId);
10818
+ return { kind: "log", id, label: `Log #${id}`, href: `#log-${id}` };
10819
+ }
10820
+ function sessionEvidence(sessionId) {
10821
+ return {
10822
+ kind: "session",
10823
+ id: sessionId,
10824
+ label: `Session ${sessionId}`,
10825
+ href: getSessionPath(sessionId)
10826
+ };
10827
+ }
10828
+ function runEvidence(runId) {
10829
+ return { kind: "run", id: runId, label: `Run ${runId}`, href: null };
10830
+ }
10831
+ function groupEvidence(groupId) {
10832
+ return { kind: "group", id: groupId, label: `Group ${groupId}`, href: null };
10833
+ }
10834
+ function baseEvidence(logId, sessionId, runId, groupId) {
10835
+ const links = [];
10836
+ if (logId !== null) links.push(logEvidence(logId));
10837
+ if (sessionId !== null) links.push(sessionEvidence(sessionId));
10838
+ if (runId !== null) links.push(runEvidence(runId));
10839
+ if (groupId !== null) links.push(groupEvidence(groupId));
10840
+ return links;
10841
+ }
10842
+ function hasEquivalentEvidence(links, candidate) {
10843
+ return links.some((link) => link.kind === candidate.kind && link.id === candidate.id);
10844
+ }
10845
+ function mergeEvidence(left, right) {
10846
+ const merged = [...left];
10847
+ for (const link of right) {
10848
+ if (!hasEquivalentEvidence(merged, link)) merged.push(link);
10188
10849
  }
10850
+ return merged;
10189
10851
  }
10190
- function getEnvValue(envObj, key) {
10191
- if (!isPlainRecord(envObj)) return void 0;
10192
- const val = envObj[key];
10193
- return typeof val === "string" ? val.trim() : void 0;
10852
+ function firstString(left, right) {
10853
+ return left ?? right;
10194
10854
  }
10195
- const KNOWN_PROVIDER_NAMES = {
10196
- deepseek: "DeepSeek",
10197
- minimaxi: "MiniMax",
10198
- openai: "OpenAI",
10199
- anthropic: "Anthropic",
10200
- openrouter: "OpenRouter",
10201
- groq: "Groq",
10202
- together: "Together",
10203
- fireworks: "Fireworks",
10204
- bedrock: "Bedrock",
10205
- vertexai: "Vertex AI",
10206
- azure: "Azure",
10207
- moonshot: "Moonshot",
10208
- zhipu: "ZhipuAI",
10209
- zhipuai: "ZhipuAI",
10210
- bigmodel: "ZhipuAI",
10211
- zai: "Z.AI",
10212
- qwen: "Qwen",
10213
- baichuan: "Baichuan",
10214
- iflytek: "iFlytek",
10215
- doubao: "Doubao",
10216
- lingyiwanwu: "LingyiWanwu",
10217
- stepfun: "StepFun"
10218
- };
10219
- function deriveNameFromUrl(url) {
10220
- try {
10221
- const hostname = new URL(url).hostname;
10222
- const parts = hostname.split(".");
10223
- const domain = parts.length >= 2 ? parts[parts.length - 2] ?? hostname : hostname;
10224
- const domainLower = domain.toLowerCase();
10225
- if (KNOWN_PROVIDER_NAMES[domainLower] !== void 0) {
10226
- return KNOWN_PROVIDER_NAMES[domainLower];
10227
- }
10228
- return domain.charAt(0).toUpperCase() + domain.slice(1);
10229
- } catch {
10230
- return "Imported Provider";
10855
+ function mergeAlert(existing, observation) {
10856
+ const logIds = observation.logId === null ? existing.logIds : [...existing.logIds, observation.logId];
10857
+ const sessionIds = observation.sessionId === null ? existing.sessionIds : [...existing.sessionIds, observation.sessionId];
10858
+ const runIds = observation.runId === null ? existing.runIds : [...existing.runIds, observation.runId];
10859
+ const groupIds = observation.groupId === null ? existing.groupIds : [...existing.groupIds, observation.groupId];
10860
+ return {
10861
+ ...existing,
10862
+ count: existing.count + 1,
10863
+ firstSeenAt: observation.observedAt < existing.firstSeenAt ? observation.observedAt : existing.firstSeenAt,
10864
+ lastSeenAt: observation.observedAt > existing.lastSeenAt ? observation.observedAt : existing.lastSeenAt,
10865
+ logIds: uniqueNumbers(logIds),
10866
+ sessionIds: uniqueStrings$1(sessionIds),
10867
+ runIds: uniqueStrings$1(runIds),
10868
+ groupIds: uniqueStrings$1(groupIds),
10869
+ provider: firstString(existing.provider, observation.provider),
10870
+ model: firstString(existing.model, observation.model),
10871
+ apiFormat: existing.apiFormat ?? observation.apiFormat,
10872
+ evidence: mergeEvidence(existing.evidence, observation.evidence),
10873
+ metadata: { ...existing.metadata, ...observation.metadata }
10874
+ };
10875
+ }
10876
+ function observationToAlert(observation) {
10877
+ return {
10878
+ id: alertIdFor(observation.fingerprint),
10879
+ fingerprint: observation.fingerprint,
10880
+ severity: observation.severity,
10881
+ category: observation.category,
10882
+ source: observation.source,
10883
+ status: "open",
10884
+ title: observation.title,
10885
+ message: observation.message,
10886
+ count: 1,
10887
+ firstSeenAt: observation.observedAt,
10888
+ lastSeenAt: observation.observedAt,
10889
+ logIds: observation.logId === null ? [] : [observation.logId],
10890
+ sessionIds: observation.sessionId === null ? [] : [observation.sessionId],
10891
+ runIds: observation.runId === null ? [] : [observation.runId],
10892
+ groupIds: observation.groupId === null ? [] : [observation.groupId],
10893
+ provider: observation.provider,
10894
+ model: observation.model,
10895
+ apiFormat: observation.apiFormat,
10896
+ evidence: observation.evidence,
10897
+ metadata: observation.metadata
10898
+ };
10899
+ }
10900
+ function addObservation(map, observation) {
10901
+ const existing = map.get(observation.fingerprint);
10902
+ if (existing === void 0) {
10903
+ map.set(observation.fingerprint, observationToAlert(observation));
10904
+ return;
10231
10905
  }
10906
+ map.set(observation.fingerprint, mergeAlert(existing, observation));
10232
10907
  }
10233
- function detectClaudeCodeProviders() {
10234
- const home = homedir();
10235
- const results = [];
10236
- const globalConfig = readJsonSafe(join(home, ".claude", "settings.json"));
10237
- const localConfig = readJsonSafe(join(home, ".claude", "settings.local.json"));
10908
+ function lowerText(value) {
10909
+ if (value === null || value === void 0) return "";
10910
+ return value.toLowerCase();
10911
+ }
10912
+ function isTimeoutStatus(status) {
10913
+ return status === 408 || status === 504;
10914
+ }
10915
+ function isTimeoutLog(log) {
10916
+ const text = `${lowerText(log.error)} ${lowerText(log.responseText)}`;
10917
+ return isTimeoutStatus(log.responseStatus) || text.includes("timeout") || text.includes("timed out") || text.includes("abort");
10918
+ }
10919
+ function hasFailureStatus(status) {
10920
+ return status !== null && status >= 400;
10921
+ }
10922
+ function isFailedLog(log) {
10923
+ return log.error !== null && log.error !== void 0 && log.error.length > 0 ? true : hasFailureStatus(log.responseStatus);
10924
+ }
10925
+ function statusLabel(status) {
10926
+ return status === null ? "no status" : `HTTP ${String(status)}`;
10927
+ }
10928
+ function errorDetail(log) {
10929
+ if (log.error !== null && log.error !== void 0 && log.error.length > 0) return log.error;
10930
+ return statusLabel(log.responseStatus);
10931
+ }
10932
+ function requestFailureTitle(log, timeout) {
10933
+ if (log.isTest === true && timeout) return "Provider test timed out";
10934
+ if (log.isTest === true) return "Provider test failed";
10935
+ return timeout ? "Request timed out" : "Request failed";
10936
+ }
10937
+ function requestFailureCategory(timeout) {
10938
+ return timeout ? "request-timeout" : "request-failure";
10939
+ }
10940
+ function logProvider(log) {
10941
+ return log.providerName ?? null;
10942
+ }
10943
+ function requestFailureObservation(log) {
10944
+ if (!isFailedLog(log)) return null;
10945
+ const timeout = isTimeoutLog(log);
10946
+ const category = requestFailureCategory(timeout);
10947
+ const message = `${errorDetail(log)} while calling ${log.path}.`;
10948
+ return {
10949
+ fingerprint: fingerprint([
10950
+ "proxy",
10951
+ category,
10952
+ logProvider(log),
10953
+ log.model,
10954
+ log.responseStatus,
10955
+ errorDetail(log)
10956
+ ]),
10957
+ severity: "critical",
10958
+ category,
10959
+ source: "proxy",
10960
+ title: requestFailureTitle(log, timeout),
10961
+ message,
10962
+ observedAt: log.timestamp,
10963
+ logId: log.id,
10964
+ sessionId: log.sessionId,
10965
+ runId: null,
10966
+ groupId: null,
10967
+ provider: logProvider(log),
10968
+ model: log.model,
10969
+ apiFormat: log.apiFormat,
10970
+ evidence: baseEvidence(log.id, log.sessionId, null, null),
10971
+ metadata: {
10972
+ path: log.path,
10973
+ status: log.responseStatus,
10974
+ error: log.error ?? null,
10975
+ isTest: log.isTest,
10976
+ streaming: log.streaming
10977
+ }
10978
+ };
10979
+ }
10980
+ function slowResponseObservation(log, slowResponseThresholdSeconds) {
10981
+ if (slowResponseThresholdSeconds <= 0) return null;
10982
+ if (isFailedLog(log)) return null;
10983
+ if (log.elapsedMs === null) return null;
10984
+ const thresholdMs = slowResponseThresholdSeconds * 1e3;
10985
+ if (log.elapsedMs < thresholdMs) return null;
10986
+ const elapsedSeconds = (log.elapsedMs / 1e3).toFixed(1);
10987
+ return {
10988
+ fingerprint: fingerprint(["proxy", "slow-response", logProvider(log), log.model, log.path]),
10989
+ severity: "warning",
10990
+ category: "slow-response",
10991
+ source: "proxy",
10992
+ title: "Slow model response",
10993
+ message: `Response took ${elapsedSeconds}s, above the ${String(
10994
+ slowResponseThresholdSeconds
10995
+ )}s threshold.`,
10996
+ observedAt: log.timestamp,
10997
+ logId: log.id,
10998
+ sessionId: log.sessionId,
10999
+ runId: null,
11000
+ groupId: null,
11001
+ provider: logProvider(log),
11002
+ model: log.model,
11003
+ apiFormat: log.apiFormat,
11004
+ evidence: baseEvidence(log.id, log.sessionId, null, null),
11005
+ metadata: {
11006
+ path: log.path,
11007
+ elapsedMs: log.elapsedMs,
11008
+ thresholdMs,
11009
+ streaming: log.streaming,
11010
+ firstChunkMs: log.firstChunkMs ?? null,
11011
+ totalStreamMs: log.totalStreamMs ?? null
11012
+ }
11013
+ };
11014
+ }
11015
+ function warningObservation(log, warning) {
11016
+ return {
11017
+ fingerprint: fingerprint(["tool-schema", logProvider(log), log.model, warning]),
11018
+ severity: "warning",
11019
+ category: "tool-schema",
11020
+ source: "tool-schema",
11021
+ title: "Tool calling argument warning",
11022
+ message: warning,
11023
+ observedAt: log.timestamp,
11024
+ logId: log.id,
11025
+ sessionId: log.sessionId,
11026
+ runId: null,
11027
+ groupId: null,
11028
+ provider: logProvider(log),
11029
+ model: log.model,
11030
+ apiFormat: log.apiFormat,
11031
+ evidence: baseEvidence(log.id, log.sessionId, null, null),
11032
+ metadata: {
11033
+ path: log.path,
11034
+ warning
11035
+ }
11036
+ };
11037
+ }
11038
+ function addLogObservations(map, logs, slowResponseThresholdSeconds) {
11039
+ for (const log of logs) {
11040
+ const failure = requestFailureObservation(log);
11041
+ if (failure !== null) addObservation(map, failure);
11042
+ const slow = slowResponseObservation(log, slowResponseThresholdSeconds);
11043
+ if (slow !== null) addObservation(map, slow);
11044
+ for (const warning of log.warnings ?? []) {
11045
+ addObservation(map, warningObservation(log, warning));
11046
+ }
11047
+ }
11048
+ }
11049
+ function alertSeverityFromFailure(failure) {
11050
+ switch (failure.classification.severity) {
11051
+ case "high":
11052
+ return "critical";
11053
+ case "medium":
11054
+ case "low":
11055
+ return "warning";
11056
+ case "none":
11057
+ return "notice";
11058
+ }
11059
+ }
11060
+ function providerFromRun(failure) {
11061
+ const provider = failure.run.metadata["provider"] ?? failure.run.metadata["providerName"];
11062
+ return typeof provider === "string" && provider.length > 0 ? provider : null;
11063
+ }
11064
+ function modelFromRun(failure) {
11065
+ const model = failure.run.metadata["model"] ?? failure.run.metadata["modelName"];
11066
+ return typeof model === "string" && model.length > 0 ? model : null;
11067
+ }
11068
+ function runFailureObservation(failure) {
11069
+ const groupId = failure.run.groupId;
11070
+ const logEvidenceLinks = failure.classification.evidenceLogIds.map(logEvidence);
11071
+ const links = mergeEvidence(
11072
+ baseEvidence(null, failure.sessionId, failure.run.id, groupId),
11073
+ logEvidenceLinks
11074
+ );
11075
+ return {
11076
+ fingerprint: fingerprint(["run", failure.run.id, failure.classification.category]),
11077
+ severity: alertSeverityFromFailure(failure),
11078
+ category: "run-failure",
11079
+ source: "run",
11080
+ title: `Run ${failure.run.status}`,
11081
+ message: failure.classification.summary,
11082
+ observedAt: failure.updatedAt,
11083
+ logId: failure.classification.evidenceLogIds[0] ?? null,
11084
+ sessionId: failure.sessionId,
11085
+ runId: failure.run.id,
11086
+ groupId,
11087
+ provider: providerFromRun(failure),
11088
+ model: modelFromRun(failure),
11089
+ apiFormat: null,
11090
+ evidence: links,
11091
+ metadata: {
11092
+ runStatus: failure.run.status,
11093
+ failureCategory: failure.classification.category,
11094
+ evidenceMarkdownPath: failure.evidenceMarkdownPath
11095
+ }
11096
+ };
11097
+ }
11098
+ function addRunFailureObservations(map, recentFailures) {
11099
+ for (const failure of recentFailures) {
11100
+ addObservation(map, runFailureObservation(failure));
11101
+ }
11102
+ }
11103
+ function memberProvider(member) {
11104
+ return member.provider !== null && member.provider.length > 0 ? member.provider : null;
11105
+ }
11106
+ function memberModel(member) {
11107
+ return member.model !== null && member.model.length > 0 ? member.model : null;
11108
+ }
11109
+ function isFailedMember(member) {
11110
+ return member.status === "failed" || member.status === "cancelled";
11111
+ }
11112
+ function groupFailureObservation(group) {
11113
+ if (group.status !== "failed" && group.status !== "cancelled") return null;
11114
+ return {
11115
+ fingerprint: fingerprint(["group", group.id, group.status]),
11116
+ severity: "critical",
11117
+ category: "group-failure",
11118
+ source: "group",
11119
+ title: `Group ${group.status}`,
11120
+ message: `${group.title} is marked ${group.status}.`,
11121
+ observedAt: group.updatedAt,
11122
+ logId: null,
11123
+ sessionId: null,
11124
+ runId: null,
11125
+ groupId: group.id,
11126
+ provider: null,
11127
+ model: null,
11128
+ apiFormat: null,
11129
+ evidence: baseEvidence(null, null, null, group.id),
11130
+ metadata: {
11131
+ groupStatus: group.status,
11132
+ memberCount: group.members.length
11133
+ }
11134
+ };
11135
+ }
11136
+ function groupMemberFailureObservation(group, member) {
11137
+ return {
11138
+ fingerprint: fingerprint(["group-member", group.id, member.id, member.status]),
11139
+ severity: "critical",
11140
+ category: "group-failure",
11141
+ source: "group",
11142
+ title: "Group member failed",
11143
+ message: `${member.label ?? member.sessionId} is marked ${member.status ?? "unknown"}.`,
11144
+ observedAt: member.updatedAt,
11145
+ logId: null,
11146
+ sessionId: member.sessionId,
11147
+ runId: member.runId,
11148
+ groupId: group.id,
11149
+ provider: memberProvider(member),
11150
+ model: memberModel(member),
11151
+ apiFormat: null,
11152
+ evidence: baseEvidence(null, member.sessionId, member.runId, group.id),
11153
+ metadata: {
11154
+ groupTitle: group.title,
11155
+ memberId: member.id,
11156
+ memberStatus: member.status
11157
+ }
11158
+ };
11159
+ }
11160
+ function groupIncompleteObservation(group, missingStatusCount) {
11161
+ return {
11162
+ fingerprint: fingerprint(["group-incomplete", group.id, missingStatusCount]),
11163
+ severity: "notice",
11164
+ category: "group-incomplete",
11165
+ source: "group",
11166
+ title: "Group has unclassified members",
11167
+ message: `${group.title} has ${String(missingStatusCount)} member(s) without a final status.`,
11168
+ observedAt: group.updatedAt,
11169
+ logId: null,
11170
+ sessionId: null,
11171
+ runId: null,
11172
+ groupId: group.id,
11173
+ provider: null,
11174
+ model: null,
11175
+ apiFormat: null,
11176
+ evidence: baseEvidence(null, null, null, group.id),
11177
+ metadata: {
11178
+ groupTitle: group.title,
11179
+ missingStatusCount
11180
+ }
11181
+ };
11182
+ }
11183
+ function addGroupObservations(map, groups) {
11184
+ for (const group of groups) {
11185
+ const groupFailure = groupFailureObservation(group);
11186
+ if (groupFailure !== null) addObservation(map, groupFailure);
11187
+ let missingStatusCount = 0;
11188
+ for (const member of group.members) {
11189
+ if (isFailedMember(member)) {
11190
+ addObservation(map, groupMemberFailureObservation(group, member));
11191
+ }
11192
+ if (member.status === null) missingStatusCount += 1;
11193
+ }
11194
+ if (missingStatusCount > 0) {
11195
+ addObservation(map, groupIncompleteObservation(group, missingStatusCount));
11196
+ }
11197
+ }
11198
+ }
11199
+ function alertMatchesFilters(alert, filters) {
11200
+ if (filters.severity !== void 0 && alert.severity !== filters.severity) return false;
11201
+ if (filters.category !== void 0 && alert.category !== filters.category) return false;
11202
+ if (filters.source !== void 0 && alert.source !== filters.source) return false;
11203
+ return true;
11204
+ }
11205
+ function sortAlerts(alerts) {
11206
+ return [...alerts].sort((left, right) => {
11207
+ const timeCompare = right.lastSeenAt.localeCompare(left.lastSeenAt);
11208
+ if (timeCompare !== 0) return timeCompare;
11209
+ return left.id.localeCompare(right.id);
11210
+ });
11211
+ }
11212
+ function buildAlertSummary(alerts) {
11213
+ let critical = 0;
11214
+ let warning = 0;
11215
+ let notice = 0;
11216
+ const byCategory = /* @__PURE__ */ new Map();
11217
+ for (const alert of alerts) {
11218
+ switch (alert.severity) {
11219
+ case "critical":
11220
+ critical += 1;
11221
+ break;
11222
+ case "warning":
11223
+ warning += 1;
11224
+ break;
11225
+ case "notice":
11226
+ notice += 1;
11227
+ break;
11228
+ }
11229
+ byCategory.set(alert.category, (byCategory.get(alert.category) ?? 0) + 1);
11230
+ }
11231
+ return {
11232
+ total: alerts.length,
11233
+ open: alerts.length,
11234
+ critical,
11235
+ warning,
11236
+ notice,
11237
+ byCategory: [...byCategory.entries()].map(([category, count]) => ({ category, count })).sort(
11238
+ (left, right) => right.count - left.count || left.category.localeCompare(right.category)
11239
+ )
11240
+ };
11241
+ }
11242
+ function collectAlertsFromEvidence(input) {
11243
+ const map = /* @__PURE__ */ new Map();
11244
+ addLogObservations(map, input.logs, input.slowResponseThresholdSeconds);
11245
+ addRunFailureObservations(map, input.recentFailures);
11246
+ addGroupObservations(map, input.groups);
11247
+ return sortAlerts([...map.values()]);
11248
+ }
11249
+ function filterAlerts(alerts, filters) {
11250
+ return alerts.filter((alert) => alertMatchesFilters(alert, filters));
11251
+ }
11252
+ async function listAlerts(options = {}) {
11253
+ const limit = clampAlertLimit(options.limit);
11254
+ const scanLimit = clampAlertScanLimit(options.scanLimit);
11255
+ const logPage = await listLogsCursorPage({
11256
+ limit: scanLimit,
11257
+ includeBodies: false,
11258
+ anchor: "newest"
11259
+ });
11260
+ const config = getConfig();
11261
+ const alerts = collectAlertsFromEvidence({
11262
+ logs: logPage.logs,
11263
+ recentFailures: listRecentFailures(scanLimit).failures,
11264
+ groups: listGroups(),
11265
+ slowResponseThresholdSeconds: config.slowResponseThresholdSeconds
11266
+ });
11267
+ const filtered = filterAlerts(alerts, options);
11268
+ return {
11269
+ alerts: filtered.slice(0, limit),
11270
+ total: filtered.length,
11271
+ limit,
11272
+ summary: buildAlertSummary(filtered)
11273
+ };
11274
+ }
11275
+ async function getAlertSummary(options = {}) {
11276
+ const response = await listAlerts({
11277
+ limit: MAX_ALERT_LIMIT,
11278
+ scanLimit: options.scanLimit
11279
+ });
11280
+ return response.summary;
11281
+ }
11282
+ function listInspectorAlerts(options) {
11283
+ return listAlerts(options);
11284
+ }
11285
+ function getInspectorAlertSummary(options) {
11286
+ return getAlertSummary(options);
11287
+ }
11288
+ function parsePositiveInt$1(value) {
11289
+ if (value === null) return void 0;
11290
+ const parsed = Number(value);
11291
+ if (!Number.isInteger(parsed) || parsed < 1) return void 0;
11292
+ return parsed;
11293
+ }
11294
+ function parseFilters(url) {
11295
+ const severityResult = AlertSeveritySchema.safeParse(url.searchParams.get("severity"));
11296
+ const categoryResult = AlertCategorySchema.safeParse(url.searchParams.get("category"));
11297
+ const sourceResult = AlertSourceSchema.safeParse(url.searchParams.get("source"));
11298
+ return {
11299
+ severity: severityResult.success ? severityResult.data : void 0,
11300
+ category: categoryResult.success ? categoryResult.data : void 0,
11301
+ source: sourceResult.success ? sourceResult.data : void 0
11302
+ };
11303
+ }
11304
+ const Route$q = createFileRoute("/api/alerts")({
11305
+ server: {
11306
+ handlers: {
11307
+ GET: async ({ request }) => {
11308
+ const url = new URL(request.url);
11309
+ return Response.json(
11310
+ await listInspectorAlerts({
11311
+ ...parseFilters(url),
11312
+ limit: parsePositiveInt$1(url.searchParams.get("limit")),
11313
+ scanLimit: parsePositiveInt$1(url.searchParams.get("scanLimit"))
11314
+ })
11315
+ );
11316
+ }
11317
+ }
11318
+ }
11319
+ });
11320
+ async function readJsonBody$4(request) {
11321
+ try {
11322
+ const raw = await request.text();
11323
+ if (raw.trim().length === 0) return { ok: true, value: {} };
11324
+ return { ok: true, value: JSON.parse(raw) };
11325
+ } catch {
11326
+ return { ok: false };
11327
+ }
11328
+ }
11329
+ const Route$p = createFileRoute("/api/runs/$runId")({
11330
+ server: {
11331
+ handlers: {
11332
+ GET: ({ params }) => {
11333
+ const run = getInspectorRun(params.runId);
11334
+ if (!run.ok) {
11335
+ return Response.json({ error: run.message }, { status: run.status });
11336
+ }
11337
+ return Response.json(run.value);
11338
+ },
11339
+ PATCH: async ({ params, request }) => {
11340
+ const body = await readJsonBody$4(request);
11341
+ if (!body.ok) {
11342
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
11343
+ }
11344
+ const parsed = UpdateInspectorRunInputSchema.safeParse(body.value);
11345
+ if (!parsed.success) {
11346
+ return Response.json(
11347
+ { error: "Invalid request body", details: parsed.error.format() },
11348
+ { status: 400 }
11349
+ );
11350
+ }
11351
+ const updated = updateInspectorRun(params.runId, parsed.data);
11352
+ if (!updated.ok) {
11353
+ return Response.json({ error: updated.message }, { status: updated.status });
11354
+ }
11355
+ return Response.json(updated.value);
11356
+ }
11357
+ }
11358
+ }
11359
+ });
11360
+ const ZHIPU_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
11361
+ const ZHIPU_CODING_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
11362
+ const ZHIPU_CODING_ANTHROPIC_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
11363
+ function readJsonSafe(filePath) {
11364
+ try {
11365
+ if (!existsSync(filePath)) return null;
11366
+ const raw = readFileSync(filePath, "utf-8");
11367
+ const parsed = JSON.parse(raw);
11368
+ return isPlainRecord(parsed) ? parsed : null;
11369
+ } catch {
11370
+ return null;
11371
+ }
11372
+ }
11373
+ function getEnvValue(envObj, key) {
11374
+ if (!isPlainRecord(envObj)) return void 0;
11375
+ const val = envObj[key];
11376
+ return typeof val === "string" ? val.trim() : void 0;
11377
+ }
11378
+ const KNOWN_PROVIDER_NAMES = {
11379
+ deepseek: "DeepSeek",
11380
+ minimaxi: "MiniMax",
11381
+ openai: "OpenAI",
11382
+ anthropic: "Anthropic",
11383
+ openrouter: "OpenRouter",
11384
+ groq: "Groq",
11385
+ together: "Together",
11386
+ fireworks: "Fireworks",
11387
+ bedrock: "Bedrock",
11388
+ vertexai: "Vertex AI",
11389
+ azure: "Azure",
11390
+ moonshot: "Moonshot",
11391
+ zhipu: "ZhipuAI",
11392
+ zhipuai: "ZhipuAI",
11393
+ bigmodel: "ZhipuAI",
11394
+ zai: "Z.AI",
11395
+ qwen: "Qwen",
11396
+ baichuan: "Baichuan",
11397
+ iflytek: "iFlytek",
11398
+ doubao: "Doubao",
11399
+ lingyiwanwu: "LingyiWanwu",
11400
+ stepfun: "StepFun"
11401
+ };
11402
+ function deriveNameFromUrl(url) {
11403
+ try {
11404
+ const hostname = new URL(url).hostname;
11405
+ const parts = hostname.split(".");
11406
+ const domain = parts.length >= 2 ? parts[parts.length - 2] ?? hostname : hostname;
11407
+ const domainLower = domain.toLowerCase();
11408
+ if (KNOWN_PROVIDER_NAMES[domainLower] !== void 0) {
11409
+ return KNOWN_PROVIDER_NAMES[domainLower];
11410
+ }
11411
+ return domain.charAt(0).toUpperCase() + domain.slice(1);
11412
+ } catch {
11413
+ return "Imported Provider";
11414
+ }
11415
+ }
11416
+ function detectClaudeCodeProviders() {
11417
+ const home = homedir();
11418
+ const results = [];
11419
+ const globalConfig = readJsonSafe(join(home, ".claude", "settings.json"));
11420
+ const localConfig = readJsonSafe(join(home, ".claude", "settings.local.json"));
10238
11421
  const mergedEnv = {};
10239
11422
  if (isPlainRecord(globalConfig)) {
10240
11423
  const env = globalConfig["env"];
@@ -10600,7 +11783,7 @@ function scanExternalProviders() {
10600
11783
  }
10601
11784
  return { providers: filteredProviders, warnings };
10602
11785
  }
10603
- const Route$l = createFileRoute("/api/providers/scan")({
11786
+ const Route$o = createFileRoute("/api/providers/scan")({
10604
11787
  server: {
10605
11788
  handlers: {
10606
11789
  GET: () => {
@@ -10621,7 +11804,7 @@ const Route$l = createFileRoute("/api/providers/scan")({
10621
11804
  }
10622
11805
  });
10623
11806
  union([string(), object({ providers: unknown() })]);
10624
- const Route$k = createFileRoute("/api/providers/import")({
11807
+ const Route$n = createFileRoute("/api/providers/import")({
10625
11808
  server: {
10626
11809
  handlers: {
10627
11810
  POST: async ({ request }) => {
@@ -10654,7 +11837,7 @@ const Route$k = createFileRoute("/api/providers/import")({
10654
11837
  }
10655
11838
  }
10656
11839
  });
10657
- const Route$j = createFileRoute("/api/providers/export")({
11840
+ const Route$m = createFileRoute("/api/providers/export")({
10658
11841
  server: {
10659
11842
  handlers: {
10660
11843
  GET: ({ request }) => {
@@ -10687,7 +11870,7 @@ const ProviderUpdateSchema = object({
10687
11870
  modelMetadata: array(ProviderModelMetadataSchema).optional(),
10688
11871
  source: _enum(["company", "personal"]).optional()
10689
11872
  });
10690
- const Route$i = createFileRoute("/api/providers/$providerId")({
11873
+ const Route$l = createFileRoute("/api/providers/$providerId")({
10691
11874
  server: {
10692
11875
  handlers: {
10693
11876
  GET: ({ params, request }) => {
@@ -10722,7 +11905,7 @@ const Route$i = createFileRoute("/api/providers/$providerId")({
10722
11905
  }
10723
11906
  });
10724
11907
  const INITIAL_STREAM_LOG_LIMIT = 100;
10725
- const Route$h = createFileRoute("/api/logs/stream")({
11908
+ const Route$k = createFileRoute("/api/logs/stream")({
10726
11909
  server: {
10727
11910
  handlers: {
10728
11911
  GET: ({ request }) => {
@@ -10795,7 +11978,411 @@ const Route$h = createFileRoute("/api/logs/stream")({
10795
11978
  }
10796
11979
  }
10797
11980
  });
10798
- const Route$g = createFileRoute("/api/logs/$id")({
11981
+ const ManifestSchema = object({
11982
+ version: string().optional(),
11983
+ exportedAt: string().optional(),
11984
+ mode: string().optional(),
11985
+ redacted: boolean().optional(),
11986
+ logIds: array(number().int().positive()).optional()
11987
+ }).passthrough();
11988
+ const LogsArraySchema = array(CapturedLogSchema);
11989
+ const LogsEnvelopeSchema = object({ logs: array(CapturedLogSchema) }).passthrough();
11990
+ const StreamingChunksImportSchema = object({
11991
+ chunks: array(StreamingChunkSchema$1),
11992
+ truncated: boolean().optional().default(false)
11993
+ });
11994
+ const SEMVER_MAJOR_PATTERN = /^([0-9]+)\.[0-9]+\.[0-9]+(?:[-+].*)?$/;
11995
+ function readRecordProperty(value, name) {
11996
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
11997
+ const desc = Object.getOwnPropertyDescriptor(value, name);
11998
+ return desc === void 0 ? void 0 : desc.value;
11999
+ }
12000
+ function parseJson(text) {
12001
+ if (text === null) return null;
12002
+ try {
12003
+ const parsed = JSON.parse(text);
12004
+ return parsed;
12005
+ } catch {
12006
+ return null;
12007
+ }
12008
+ }
12009
+ function parseJsonLogs(text) {
12010
+ const parsed = parseJson(text);
12011
+ const direct = LogsArraySchema.safeParse(parsed);
12012
+ if (direct.success) return direct.data;
12013
+ const envelope = LogsEnvelopeSchema.safeParse(parsed);
12014
+ if (envelope.success) return envelope.data.logs;
12015
+ return null;
12016
+ }
12017
+ function parseJsonlLogs(text) {
12018
+ const logs = [];
12019
+ let skipped = 0;
12020
+ for (const line of text.split(/\r?\n/)) {
12021
+ if (line.trim() === "") continue;
12022
+ const parsed = CapturedLogSchema.safeParse(parseJson(line));
12023
+ if (parsed.success) {
12024
+ logs.push(parsed.data);
12025
+ } else {
12026
+ skipped += 1;
12027
+ }
12028
+ }
12029
+ return { logs, skipped };
12030
+ }
12031
+ function readStringProperty(value, name) {
12032
+ const property = readRecordProperty(value, name);
12033
+ return typeof property === "string" ? property : null;
12034
+ }
12035
+ function hasProperty(value, name) {
12036
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
12037
+ return Object.getOwnPropertyDescriptor(value, name) !== void 0;
12038
+ }
12039
+ function modelFromRequestText(requestText) {
12040
+ return readStringProperty(parseJson(requestText), "model");
12041
+ }
12042
+ function inferApiFormatFromBody(path2, model, requestText) {
12043
+ const pathFormat = apiFormatForPath(path2);
12044
+ if (pathFormat !== "unknown") return pathFormat;
12045
+ const normalizedModel = model?.toLowerCase() ?? "";
12046
+ if (normalizedModel.startsWith("claude-")) return "anthropic";
12047
+ if (normalizedModel.startsWith("gpt-") || normalizedModel.startsWith("o1-") || normalizedModel.startsWith("o3-") || normalizedModel.startsWith("o4-") || normalizedModel.startsWith("deepseek-") || normalizedModel.startsWith("glm-") || normalizedModel.startsWith("qwen")) {
12048
+ return "openai";
12049
+ }
12050
+ const parsedRequest = parseJson(requestText);
12051
+ if (hasProperty(parsedRequest, "system") || hasProperty(parsedRequest, "max_tokens")) {
12052
+ return "anthropic";
12053
+ }
12054
+ return "openai";
12055
+ }
12056
+ function defaultPathForApiFormat(apiFormat) {
12057
+ switch (apiFormat) {
12058
+ case "anthropic":
12059
+ return "/v1/messages";
12060
+ case "openai":
12061
+ return "/v1/chat/completions";
12062
+ case "unknown":
12063
+ return "/v1/chat/completions";
12064
+ }
12065
+ }
12066
+ function normalizeTimestamp(value, fallback) {
12067
+ return Number.isNaN(new Date(value).getTime()) ? fallback : value;
12068
+ }
12069
+ function responseStatusFromText(responseText) {
12070
+ if (responseText === null) return null;
12071
+ const parsed = parseJson(responseText);
12072
+ return hasProperty(parsed, "error") ? 500 : 200;
12073
+ }
12074
+ function mergeWarnings(existing, generated) {
12075
+ const values = [];
12076
+ for (const warning of existing ?? []) {
12077
+ if (!values.includes(warning)) values.push(warning);
12078
+ }
12079
+ for (const warning of generated) {
12080
+ if (!values.includes(warning)) values.push(warning);
12081
+ }
12082
+ return values.length === 0 ? void 0 : values;
12083
+ }
12084
+ function withToolWarnings(log) {
12085
+ const warnings = analyzeToolSchemaWarnings({
12086
+ rawRequestBody: log.rawRequestBody,
12087
+ responseText: log.responseText,
12088
+ apiFormat: log.apiFormat
12089
+ });
12090
+ return {
12091
+ ...log,
12092
+ warnings: mergeWarnings(log.warnings, warnings)
12093
+ };
12094
+ }
12095
+ function streamingChunksFromText(text) {
12096
+ const parsed = StreamingChunksImportSchema.safeParse(parseJson(text));
12097
+ return parsed.success ? parsed.data : void 0;
12098
+ }
12099
+ function draftFromCapturedLog(log, requestText, responseText, streamingChunks) {
12100
+ const rawRequestBody = requestText ?? log.rawRequestBody;
12101
+ const response = responseText ?? log.responseText;
12102
+ const model = log.model ?? modelFromRequestText(rawRequestBody);
12103
+ const apiFormat = log.apiFormat === "unknown" ? inferApiFormatFromBody(log.path, model, rawRequestBody) : log.apiFormat;
12104
+ const path2 = log.path.trim() === "" ? defaultPathForApiFormat(apiFormat) : log.path;
12105
+ return withToolWarnings({
12106
+ timestamp: normalizeTimestamp(log.timestamp, (/* @__PURE__ */ new Date()).toISOString()),
12107
+ method: log.method.trim() === "" ? "POST" : log.method,
12108
+ path: path2,
12109
+ model,
12110
+ sessionId: null,
12111
+ rawRequestBody,
12112
+ responseStatus: log.responseStatus ?? responseStatusFromText(response),
12113
+ responseText: response,
12114
+ inputTokens: log.inputTokens,
12115
+ outputTokens: log.outputTokens,
12116
+ cacheCreationInputTokens: log.cacheCreationInputTokens,
12117
+ cacheReadInputTokens: log.cacheReadInputTokens,
12118
+ elapsedMs: log.elapsedMs,
12119
+ firstChunkMs: log.firstChunkMs ?? null,
12120
+ totalStreamMs: log.totalStreamMs ?? null,
12121
+ tokensPerSecond: log.tokensPerSecond ?? null,
12122
+ streaming: log.streaming || streamingChunks !== void 0,
12123
+ userAgent: log.userAgent,
12124
+ origin: log.origin,
12125
+ rawHeaders: log.rawHeaders,
12126
+ headers: log.headers,
12127
+ apiFormat,
12128
+ isTest: false,
12129
+ replayOfLogId: null,
12130
+ providerName: log.providerName ?? null,
12131
+ clientPort: log.clientPort ?? null,
12132
+ clientPid: log.clientPid ?? null,
12133
+ clientCwd: log.clientCwd ?? null,
12134
+ clientProjectFolder: log.clientProjectFolder ?? null,
12135
+ streamingChunks,
12136
+ streamingChunksPath: null,
12137
+ rawRequestBodyBytes: log.rawRequestBodyBytes,
12138
+ responseTextBytes: log.responseTextBytes,
12139
+ bodyContentMode: "full",
12140
+ warnings: log.warnings,
12141
+ error: log.error ?? null
12142
+ });
12143
+ }
12144
+ function legacyDraftFromParts(input) {
12145
+ const model = modelFromRequestText(input.requestText);
12146
+ const apiFormat = inferApiFormatFromBody("", model, input.requestText);
12147
+ return withToolWarnings({
12148
+ timestamp: input.exportedAt,
12149
+ method: "POST",
12150
+ path: defaultPathForApiFormat(apiFormat),
12151
+ model,
12152
+ sessionId: null,
12153
+ rawRequestBody: input.requestText,
12154
+ responseStatus: responseStatusFromText(input.responseText),
12155
+ responseText: input.responseText,
12156
+ inputTokens: null,
12157
+ outputTokens: null,
12158
+ cacheCreationInputTokens: null,
12159
+ cacheReadInputTokens: null,
12160
+ elapsedMs: null,
12161
+ firstChunkMs: null,
12162
+ totalStreamMs: null,
12163
+ tokensPerSecond: null,
12164
+ streaming: input.streamingChunks !== void 0,
12165
+ userAgent: "agent-inspector-import",
12166
+ origin: null,
12167
+ apiFormat,
12168
+ isTest: false,
12169
+ replayOfLogId: null,
12170
+ providerName: null,
12171
+ clientPort: null,
12172
+ clientPid: null,
12173
+ clientCwd: null,
12174
+ clientProjectFolder: null,
12175
+ streamingChunks: input.streamingChunks,
12176
+ streamingChunksPath: null,
12177
+ bodyContentMode: "full",
12178
+ error: null
12179
+ });
12180
+ }
12181
+ async function readZipText(zip, path2) {
12182
+ const file = zip.file(path2);
12183
+ return file === null ? null : await file.async("text");
12184
+ }
12185
+ async function readManifest(zip) {
12186
+ const text = await readZipText(zip, "manifest.json");
12187
+ const parsed = ManifestSchema.safeParse(parseJson(text));
12188
+ return parsed.success ? parsed.data : null;
12189
+ }
12190
+ function versionMajor(version2) {
12191
+ const match = SEMVER_MAJOR_PATTERN.exec(version2);
12192
+ if (match === null) return null;
12193
+ const major = match[1];
12194
+ return major === void 0 ? null : Number.parseInt(major, 10);
12195
+ }
12196
+ function validateManifestVersion(manifest) {
12197
+ const exportedVersion = manifest?.version;
12198
+ if (exportedVersion === void 0) {
12199
+ return {
12200
+ ok: true,
12201
+ warning: "Imported legacy export without version metadata. Compatibility could not be verified."
12202
+ };
12203
+ }
12204
+ const exportedMajor = versionMajor(exportedVersion);
12205
+ if (exportedMajor === null) {
12206
+ return {
12207
+ ok: false,
12208
+ message: `Unsupported export version "${exportedVersion}".`
12209
+ };
12210
+ }
12211
+ const currentMajor = versionMajor(packageJson.version);
12212
+ if (currentMajor === null) {
12213
+ return {
12214
+ ok: true,
12215
+ warning: `Current Agent Inspector version "${packageJson.version}" could not be verified against export version "${exportedVersion}".`
12216
+ };
12217
+ }
12218
+ if (exportedMajor !== currentMajor) {
12219
+ return {
12220
+ ok: false,
12221
+ message: `Export version mismatch: archive was created by Agent Inspector v${exportedVersion}, current version is v${packageJson.version}. Import with a matching major version.`
12222
+ };
12223
+ }
12224
+ if (exportedVersion !== packageJson.version) {
12225
+ return {
12226
+ ok: true,
12227
+ warning: `Imported export from Agent Inspector v${exportedVersion}; current version is v${packageJson.version}.`
12228
+ };
12229
+ }
12230
+ return { ok: true, warning: null };
12231
+ }
12232
+ async function parseZipLogImport(data) {
12233
+ const warnings = [];
12234
+ const zip = await JSZip.loadAsync(data);
12235
+ const manifest = await readManifest(zip);
12236
+ const versionCheck = validateManifestVersion(manifest);
12237
+ if (!versionCheck.ok) {
12238
+ return {
12239
+ ok: false,
12240
+ message: versionCheck.message,
12241
+ warnings
12242
+ };
12243
+ }
12244
+ if (versionCheck.warning !== null) {
12245
+ warnings.push(versionCheck.warning);
12246
+ }
12247
+ const exportedAt = normalizeTimestamp(manifest?.exportedAt ?? "", (/* @__PURE__ */ new Date()).toISOString());
12248
+ if (manifest?.redacted === true) {
12249
+ warnings.push("Imported redacted export. Secrets and some replay details may be unavailable.");
12250
+ }
12251
+ const metadataText2 = await readZipText(zip, "logs.json");
12252
+ const metadataLogs = metadataText2 === null ? null : parseJsonLogs(metadataText2);
12253
+ const logs = [];
12254
+ let skipped = 0;
12255
+ if (metadataLogs !== null) {
12256
+ for (const log of metadataLogs) {
12257
+ const requestText = await readZipText(zip, `#${String(log.id)}.Request.json`);
12258
+ const responseText = await readZipText(zip, `#${String(log.id)}.Response.json`);
12259
+ const streamingText = await readZipText(zip, `#${String(log.id)}.SSE.Response.json`);
12260
+ logs.push(
12261
+ draftFromCapturedLog(
12262
+ log,
12263
+ requestText,
12264
+ responseText,
12265
+ streamingChunksFromText(streamingText)
12266
+ )
12267
+ );
12268
+ }
12269
+ return { ok: true, logs, skipped, warnings };
12270
+ }
12271
+ for (const originalId of manifest?.logIds ?? []) {
12272
+ const requestText = await readZipText(zip, `#${String(originalId)}.Request.json`);
12273
+ const responseText = await readZipText(zip, `#${String(originalId)}.Response.json`);
12274
+ const streamingText = await readZipText(zip, `#${String(originalId)}.SSE.Response.json`);
12275
+ if (requestText === null && responseText === null && streamingText === null) {
12276
+ skipped += 1;
12277
+ continue;
12278
+ }
12279
+ logs.push(
12280
+ legacyDraftFromParts({
12281
+ exportedAt,
12282
+ requestText,
12283
+ responseText,
12284
+ streamingChunks: streamingChunksFromText(streamingText)
12285
+ })
12286
+ );
12287
+ }
12288
+ if (logs.length === 0) {
12289
+ return {
12290
+ ok: false,
12291
+ message: "No importable logs were found in the archive.",
12292
+ warnings
12293
+ };
12294
+ }
12295
+ return { ok: true, logs, skipped, warnings };
12296
+ }
12297
+ function looksLikeZip(data, fileName) {
12298
+ if (fileName.toLowerCase().endsWith(".zip")) return true;
12299
+ return data[0] === 80 && data[1] === 75;
12300
+ }
12301
+ function parseTextLogImport(text) {
12302
+ const jsonLogs = parseJsonLogs(text);
12303
+ if (jsonLogs !== null) {
12304
+ return {
12305
+ ok: true,
12306
+ logs: jsonLogs.map((log) => draftFromCapturedLog(log, null, null, void 0)),
12307
+ skipped: 0,
12308
+ warnings: []
12309
+ };
12310
+ }
12311
+ const jsonl = parseJsonlLogs(text);
12312
+ if (jsonl.logs.length > 0) {
12313
+ return {
12314
+ ok: true,
12315
+ logs: jsonl.logs.map((log) => draftFromCapturedLog(log, null, null, void 0)),
12316
+ skipped: jsonl.skipped,
12317
+ warnings: []
12318
+ };
12319
+ }
12320
+ return {
12321
+ ok: false,
12322
+ message: "Unsupported import file. Use an Agent Inspector export ZIP, logs.json, or JSONL file.",
12323
+ warnings: []
12324
+ };
12325
+ }
12326
+ async function parseImportedLogFile(input) {
12327
+ try {
12328
+ if (looksLikeZip(input.data, input.fileName)) {
12329
+ return await parseZipLogImport(input.data);
12330
+ }
12331
+ return parseTextLogImport(new TextDecoder("utf-8").decode(input.data));
12332
+ } catch (err) {
12333
+ return {
12334
+ ok: false,
12335
+ message: err instanceof Error ? err.message : "Failed to parse import file.",
12336
+ warnings: []
12337
+ };
12338
+ }
12339
+ }
12340
+ function sessionNameFromImportFileName(fileName) {
12341
+ const normalized = fileName.replaceAll("\\", "/");
12342
+ const base = basename(normalized).replace(/\.(zip|json|jsonl)$/i, "").trim();
12343
+ return base === "" ? `import-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}` : base;
12344
+ }
12345
+ function isUploadedFile(value) {
12346
+ return value instanceof File;
12347
+ }
12348
+ const Route$j = createFileRoute("/api/logs/import")({
12349
+ server: {
12350
+ handlers: {
12351
+ POST: async ({ request }) => {
12352
+ let formData;
12353
+ try {
12354
+ formData = await request.formData();
12355
+ } catch {
12356
+ return Response.json({ error: "Expected multipart form data" }, { status: 400 });
12357
+ }
12358
+ const upload = formData.get("file");
12359
+ if (!isUploadedFile(upload)) {
12360
+ return Response.json({ error: "Missing import file" }, { status: 400 });
12361
+ }
12362
+ const sessionId = sessionNameFromImportFileName(upload.name);
12363
+ const parsed = await parseImportedLogFile({
12364
+ fileName: upload.name,
12365
+ data: Buffer.from(await upload.arrayBuffer())
12366
+ });
12367
+ if (!parsed.ok) {
12368
+ return Response.json(
12369
+ { error: parsed.message, warnings: parsed.warnings },
12370
+ { status: 400 }
12371
+ );
12372
+ }
12373
+ const imported = await importCapturedLogs(parsed.logs, sessionId);
12374
+ return Response.json({
12375
+ sessionId,
12376
+ imported: imported.length,
12377
+ skipped: parsed.skipped,
12378
+ warnings: parsed.warnings,
12379
+ logs: imported.map((log) => compactLogForList(log))
12380
+ });
12381
+ }
12382
+ }
12383
+ }
12384
+ });
12385
+ const Route$i = createFileRoute("/api/logs/$id")({
10799
12386
  server: {
10800
12387
  handlers: {
10801
12388
  GET: async ({ params }) => {
@@ -11332,7 +12919,7 @@ const SearchBodySchema = object({
11332
12919
  query: string().min(1),
11333
12920
  project: string().optional()
11334
12921
  });
11335
- const Route$f = createFileRoute("/api/knowledge/search")({
12922
+ const Route$h = createFileRoute("/api/knowledge/search")({
11336
12923
  server: {
11337
12924
  handlers: {
11338
12925
  GET: async ({ request }) => {
@@ -11354,7 +12941,7 @@ const Route$f = createFileRoute("/api/knowledge/search")({
11354
12941
  }
11355
12942
  }
11356
12943
  });
11357
- const Route$e = createFileRoute("/api/knowledge/project-context")({
12944
+ const Route$g = createFileRoute("/api/knowledge/project-context")({
11358
12945
  server: {
11359
12946
  handlers: {
11360
12947
  GET: async ({ request }) => {
@@ -11436,7 +13023,7 @@ function updateCandidateDraft(id, updates) {
11436
13023
  candidates.set(id, updated);
11437
13024
  return updated;
11438
13025
  }
11439
- const Route$d = createFileRoute("/api/knowledge/candidates")({
13026
+ const Route$f = createFileRoute("/api/knowledge/candidates")({
11440
13027
  server: {
11441
13028
  handlers: {
11442
13029
  GET: () => Response.json({ candidates: listCandidates() })
@@ -11471,7 +13058,7 @@ function readDeleteEvidenceFlag(request) {
11471
13058
  return { ok: false };
11472
13059
  }
11473
13060
  }
11474
- const Route$c = createFileRoute("/api/groups/$groupId")({
13061
+ const Route$e = createFileRoute("/api/groups/$groupId")({
11475
13062
  server: {
11476
13063
  handlers: {
11477
13064
  GET: ({ params }) => {
@@ -11518,7 +13105,7 @@ const Route$c = createFileRoute("/api/groups/$groupId")({
11518
13105
  }
11519
13106
  }
11520
13107
  });
11521
- const Route$b = createFileRoute("/api/config/paths")({
13108
+ const Route$d = createFileRoute("/api/config/paths")({
11522
13109
  server: {
11523
13110
  handlers: {
11524
13111
  GET: () => {
@@ -11529,6 +13116,26 @@ const Route$b = createFileRoute("/api/config/paths")({
11529
13116
  }
11530
13117
  }
11531
13118
  });
13119
+ function parsePositiveInt(value) {
13120
+ if (value === null) return void 0;
13121
+ const parsed = Number(value);
13122
+ if (!Number.isInteger(parsed) || parsed < 1) return void 0;
13123
+ return parsed;
13124
+ }
13125
+ const Route$c = createFileRoute("/api/alerts/summary")({
13126
+ server: {
13127
+ handlers: {
13128
+ GET: async ({ request }) => {
13129
+ const url = new URL(request.url);
13130
+ return Response.json(
13131
+ await getInspectorAlertSummary({
13132
+ scanLimit: parsePositiveInt(url.searchParams.get("scanLimit"))
13133
+ })
13134
+ );
13135
+ }
13136
+ }
13137
+ }
13138
+ });
11532
13139
  async function readJsonBody$2(request) {
11533
13140
  try {
11534
13141
  const raw = await request.text();
@@ -11538,7 +13145,7 @@ async function readJsonBody$2(request) {
11538
13145
  return { ok: false };
11539
13146
  }
11540
13147
  }
11541
- const Route$a = createFileRoute("/api/runs/$runId/evidence")({
13148
+ const Route$b = createFileRoute("/api/runs/$runId/evidence")({
11542
13149
  server: {
11543
13150
  handlers: {
11544
13151
  GET: ({ params }) => {
@@ -12189,7 +13796,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
12189
13796
  clearTimeout(timeoutId);
12190
13797
  }
12191
13798
  }
12192
- const Route$9 = createFileRoute("/api/providers/$providerId/test")({
13799
+ const Route$a = createFileRoute("/api/providers/$providerId/test")({
12193
13800
  server: {
12194
13801
  handlers: {
12195
13802
  POST: async ({ params }) => {
@@ -12283,7 +13890,7 @@ async function readRegistryJson(response) {
12283
13890
  return null;
12284
13891
  }
12285
13892
  }
12286
- const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
13893
+ const Route$9 = createFileRoute("/api/providers/$providerId/model-metadata")({
12287
13894
  server: {
12288
13895
  handlers: {
12289
13896
  POST: async ({ params, request }) => {
@@ -12373,7 +13980,7 @@ const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
12373
13980
  const ReplayRequestSchema = object({
12374
13981
  modifiedBody: string()
12375
13982
  });
12376
- const Route$7 = createFileRoute("/api/logs/$id/replay")({
13983
+ const Route$8 = createFileRoute("/api/logs/$id/replay")({
12377
13984
  server: {
12378
13985
  handlers: {
12379
13986
  POST: async ({ params, request }) => {
@@ -12574,7 +14181,7 @@ const Route$7 = createFileRoute("/api/logs/$id/replay")({
12574
14181
  }
12575
14182
  }
12576
14183
  });
12577
- const Route$6 = createFileRoute("/api/logs/$id/chunks")({
14184
+ const Route$7 = createFileRoute("/api/logs/$id/chunks")({
12578
14185
  server: {
12579
14186
  handlers: {
12580
14187
  GET: async ({ params }) => {
@@ -12600,6 +14207,116 @@ const Route$6 = createFileRoute("/api/logs/$id/chunks")({
12600
14207
  }
12601
14208
  }
12602
14209
  });
14210
+ const DEFAULT_LOG_BODY_CHUNK_BYTES = 256 * 1024;
14211
+ const MAX_LOG_BODY_CHUNK_BYTES = 1024 * 1024;
14212
+ function normalizeLogBodyChunkOffset(offset) {
14213
+ if (!Number.isInteger(offset) || offset < 0) return 0;
14214
+ return offset;
14215
+ }
14216
+ function normalizeLogBodyChunkLimit(limit) {
14217
+ if (!Number.isInteger(limit) || limit < 1) return DEFAULT_LOG_BODY_CHUNK_BYTES;
14218
+ return Math.min(limit, MAX_LOG_BODY_CHUNK_BYTES);
14219
+ }
14220
+ function bodyTextForPart(log, part) {
14221
+ switch (part) {
14222
+ case "request":
14223
+ return log.rawRequestBody;
14224
+ case "response":
14225
+ return log.responseText;
14226
+ }
14227
+ }
14228
+ function isUtf8ContinuationByte(byte) {
14229
+ return byte !== void 0 && (byte & 192) === 128;
14230
+ }
14231
+ function expandToUtf8Boundary(buffer, end) {
14232
+ if (end >= buffer.byteLength) return buffer.byteLength;
14233
+ let safeEnd = end;
14234
+ while (safeEnd < buffer.byteLength && isUtf8ContinuationByte(buffer[safeEnd])) {
14235
+ safeEnd++;
14236
+ }
14237
+ return safeEnd;
14238
+ }
14239
+ function createLogBodyChunk({
14240
+ log,
14241
+ part,
14242
+ offset,
14243
+ limit
14244
+ }) {
14245
+ const text = bodyTextForPart(log, part);
14246
+ const normalizedLimit = normalizeLogBodyChunkLimit(limit);
14247
+ if (text === null || text === "") {
14248
+ return {
14249
+ logId: log.id,
14250
+ part,
14251
+ text: "",
14252
+ offset: 0,
14253
+ limit: normalizedLimit,
14254
+ totalBytes: 0,
14255
+ textBytes: 0,
14256
+ nextOffset: null,
14257
+ hasMore: false,
14258
+ contentMode: "empty"
14259
+ };
14260
+ }
14261
+ const bodyBytes = Buffer.from(text, "utf8");
14262
+ const totalBytes = bodyBytes.byteLength;
14263
+ const normalizedOffset = Math.min(normalizeLogBodyChunkOffset(offset), totalBytes);
14264
+ const end = expandToUtf8Boundary(
14265
+ bodyBytes,
14266
+ Math.min(normalizedOffset + normalizedLimit, totalBytes)
14267
+ );
14268
+ const chunkText = bodyBytes.toString("utf8", normalizedOffset, end);
14269
+ const textBytes = end - normalizedOffset;
14270
+ const hasMore = end < totalBytes;
14271
+ const contentMode = hasMore || normalizedOffset > 0 ? "partial" : "full";
14272
+ return {
14273
+ logId: log.id,
14274
+ part,
14275
+ text: chunkText,
14276
+ offset: normalizedOffset,
14277
+ limit: normalizedLimit,
14278
+ totalBytes,
14279
+ textBytes,
14280
+ nextOffset: hasMore ? end : null,
14281
+ hasMore,
14282
+ contentMode
14283
+ };
14284
+ }
14285
+ function parseIntegerParam(value, fallback) {
14286
+ if (value === null) return fallback;
14287
+ const parsed = Number(value);
14288
+ if (!Number.isInteger(parsed)) return fallback;
14289
+ return parsed;
14290
+ }
14291
+ const Route$6 = createFileRoute("/api/logs/$id/body")({
14292
+ server: {
14293
+ handlers: {
14294
+ GET: async ({ params, request }) => {
14295
+ const id = Number(params.id);
14296
+ if (!Number.isInteger(id) || id <= 0) {
14297
+ return Response.json({ error: "Invalid log ID" }, { status: 400 });
14298
+ }
14299
+ const url = new URL(request.url);
14300
+ const partResult = LogBodyPartSchema.safeParse(url.searchParams.get("part"));
14301
+ if (!partResult.success) {
14302
+ return Response.json({ error: "Invalid body part" }, { status: 400 });
14303
+ }
14304
+ const log = await getLogById(id);
14305
+ if (log === null) {
14306
+ return Response.json({ error: "Log not found" }, { status: 404 });
14307
+ }
14308
+ return Response.json(
14309
+ createLogBodyChunk({
14310
+ log,
14311
+ part: partResult.data,
14312
+ offset: parseIntegerParam(url.searchParams.get("offset"), 0),
14313
+ limit: parseIntegerParam(url.searchParams.get("limit"), 0)
14314
+ })
14315
+ );
14316
+ }
14317
+ }
14318
+ }
14319
+ });
12603
14320
  const CandidateUpdateSchema = object({
12604
14321
  type: KnowledgeCandidateTypeSchema.optional(),
12605
14322
  title: string().trim().min(1).max(160).optional(),
@@ -13144,151 +14861,171 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
13144
14861
  }
13145
14862
  }
13146
14863
  });
13147
- const IndexRoute = Route$y.update({
14864
+ const IndexRoute = Route$C.update({
13148
14865
  id: "/",
13149
14866
  path: "/",
13150
- getParentRoute: () => Route$z
14867
+ getParentRoute: () => Route$D
13151
14868
  });
13152
- const SessionSessionIdRoute = Route$x.update({
14869
+ const SessionSessionIdRoute = Route$B.update({
13153
14870
  id: "/session/$sessionId",
13154
14871
  path: "/session/$sessionId",
13155
- getParentRoute: () => Route$z
14872
+ getParentRoute: () => Route$D
13156
14873
  });
13157
- const ProxySplatRoute = Route$w.update({
14874
+ const ProxySplatRoute = Route$A.update({
13158
14875
  id: "/proxy/$",
13159
14876
  path: "/proxy/$",
13160
- getParentRoute: () => Route$z
14877
+ getParentRoute: () => Route$D
13161
14878
  });
13162
- const ApiSessionsRoute = Route$v.update({
14879
+ const ApiSessionsRoute = Route$z.update({
13163
14880
  id: "/api/sessions",
13164
14881
  path: "/api/sessions",
13165
- getParentRoute: () => Route$z
14882
+ getParentRoute: () => Route$D
13166
14883
  });
13167
- const ApiRunsRoute = Route$u.update({
14884
+ const ApiRunsRoute = Route$y.update({
13168
14885
  id: "/api/runs",
13169
14886
  path: "/api/runs",
13170
- getParentRoute: () => Route$z
14887
+ getParentRoute: () => Route$D
13171
14888
  });
13172
- const ApiProvidersRoute = Route$t.update({
14889
+ const ApiProvidersRoute = Route$x.update({
13173
14890
  id: "/api/providers",
13174
14891
  path: "/api/providers",
13175
- getParentRoute: () => Route$z
14892
+ getParentRoute: () => Route$D
13176
14893
  });
13177
- const ApiModelsRoute = Route$s.update({
14894
+ const ApiModelsRoute = Route$w.update({
13178
14895
  id: "/api/models",
13179
14896
  path: "/api/models",
13180
- getParentRoute: () => Route$z
14897
+ getParentRoute: () => Route$D
13181
14898
  });
13182
- const ApiMcpRoute = Route$r.update({
14899
+ const ApiMcpRoute = Route$v.update({
13183
14900
  id: "/api/mcp",
13184
14901
  path: "/api/mcp",
13185
- getParentRoute: () => Route$z
14902
+ getParentRoute: () => Route$D
13186
14903
  });
13187
- const ApiLogsRoute = Route$q.update({
14904
+ const ApiLogsRoute = Route$u.update({
13188
14905
  id: "/api/logs",
13189
14906
  path: "/api/logs",
13190
- getParentRoute: () => Route$z
14907
+ getParentRoute: () => Route$D
13191
14908
  });
13192
- const ApiHealthRoute = Route$p.update({
14909
+ const ApiHealthRoute = Route$t.update({
13193
14910
  id: "/api/health",
13194
14911
  path: "/api/health",
13195
- getParentRoute: () => Route$z
14912
+ getParentRoute: () => Route$D
13196
14913
  });
13197
- const ApiGroupsRoute = Route$o.update({
14914
+ const ApiGroupsRoute = Route$s.update({
13198
14915
  id: "/api/groups",
13199
14916
  path: "/api/groups",
13200
- getParentRoute: () => Route$z
14917
+ getParentRoute: () => Route$D
13201
14918
  });
13202
- const ApiConfigRoute = Route$n.update({
14919
+ const ApiConfigRoute = Route$r.update({
13203
14920
  id: "/api/config",
13204
14921
  path: "/api/config",
13205
- getParentRoute: () => Route$z
14922
+ getParentRoute: () => Route$D
13206
14923
  });
13207
- const ApiRunsRunIdRoute = Route$m.update({
14924
+ const ApiAlertsRoute = Route$q.update({
14925
+ id: "/api/alerts",
14926
+ path: "/api/alerts",
14927
+ getParentRoute: () => Route$D
14928
+ });
14929
+ const ApiRunsRunIdRoute = Route$p.update({
13208
14930
  id: "/$runId",
13209
14931
  path: "/$runId",
13210
14932
  getParentRoute: () => ApiRunsRoute
13211
14933
  });
13212
- const ApiProvidersScanRoute = Route$l.update({
14934
+ const ApiProvidersScanRoute = Route$o.update({
13213
14935
  id: "/scan",
13214
14936
  path: "/scan",
13215
14937
  getParentRoute: () => ApiProvidersRoute
13216
14938
  });
13217
- const ApiProvidersImportRoute = Route$k.update({
14939
+ const ApiProvidersImportRoute = Route$n.update({
13218
14940
  id: "/import",
13219
14941
  path: "/import",
13220
14942
  getParentRoute: () => ApiProvidersRoute
13221
14943
  });
13222
- const ApiProvidersExportRoute = Route$j.update({
14944
+ const ApiProvidersExportRoute = Route$m.update({
13223
14945
  id: "/export",
13224
14946
  path: "/export",
13225
14947
  getParentRoute: () => ApiProvidersRoute
13226
14948
  });
13227
- const ApiProvidersProviderIdRoute = Route$i.update({
14949
+ const ApiProvidersProviderIdRoute = Route$l.update({
13228
14950
  id: "/$providerId",
13229
14951
  path: "/$providerId",
13230
14952
  getParentRoute: () => ApiProvidersRoute
13231
14953
  });
13232
- const ApiLogsStreamRoute = Route$h.update({
14954
+ const ApiLogsStreamRoute = Route$k.update({
13233
14955
  id: "/stream",
13234
14956
  path: "/stream",
13235
14957
  getParentRoute: () => ApiLogsRoute
13236
14958
  });
13237
- const ApiLogsIdRoute = Route$g.update({
14959
+ const ApiLogsImportRoute = Route$j.update({
14960
+ id: "/import",
14961
+ path: "/import",
14962
+ getParentRoute: () => ApiLogsRoute
14963
+ });
14964
+ const ApiLogsIdRoute = Route$i.update({
13238
14965
  id: "/$id",
13239
14966
  path: "/$id",
13240
14967
  getParentRoute: () => ApiLogsRoute
13241
14968
  });
13242
- const ApiKnowledgeSearchRoute = Route$f.update({
14969
+ const ApiKnowledgeSearchRoute = Route$h.update({
13243
14970
  id: "/api/knowledge/search",
13244
14971
  path: "/api/knowledge/search",
13245
- getParentRoute: () => Route$z
14972
+ getParentRoute: () => Route$D
13246
14973
  });
13247
- const ApiKnowledgeProjectContextRoute = Route$e.update({
14974
+ const ApiKnowledgeProjectContextRoute = Route$g.update({
13248
14975
  id: "/api/knowledge/project-context",
13249
14976
  path: "/api/knowledge/project-context",
13250
- getParentRoute: () => Route$z
14977
+ getParentRoute: () => Route$D
13251
14978
  });
13252
- const ApiKnowledgeCandidatesRoute = Route$d.update({
14979
+ const ApiKnowledgeCandidatesRoute = Route$f.update({
13253
14980
  id: "/api/knowledge/candidates",
13254
14981
  path: "/api/knowledge/candidates",
13255
- getParentRoute: () => Route$z
14982
+ getParentRoute: () => Route$D
13256
14983
  });
13257
- const ApiGroupsGroupIdRoute = Route$c.update({
14984
+ const ApiGroupsGroupIdRoute = Route$e.update({
13258
14985
  id: "/$groupId",
13259
14986
  path: "/$groupId",
13260
14987
  getParentRoute: () => ApiGroupsRoute
13261
14988
  });
13262
- const ApiConfigPathsRoute = Route$b.update({
14989
+ const ApiConfigPathsRoute = Route$d.update({
13263
14990
  id: "/paths",
13264
14991
  path: "/paths",
13265
14992
  getParentRoute: () => ApiConfigRoute
13266
14993
  });
13267
- const ApiRunsRunIdEvidenceRoute = Route$a.update({
14994
+ const ApiAlertsSummaryRoute = Route$c.update({
14995
+ id: "/summary",
14996
+ path: "/summary",
14997
+ getParentRoute: () => ApiAlertsRoute
14998
+ });
14999
+ const ApiRunsRunIdEvidenceRoute = Route$b.update({
13268
15000
  id: "/evidence",
13269
15001
  path: "/evidence",
13270
15002
  getParentRoute: () => ApiRunsRunIdRoute
13271
15003
  });
13272
- const ApiProvidersProviderIdTestRoute = Route$9.update({
15004
+ const ApiProvidersProviderIdTestRoute = Route$a.update({
13273
15005
  id: "/test",
13274
15006
  path: "/test",
13275
15007
  getParentRoute: () => ApiProvidersProviderIdRoute
13276
15008
  });
13277
- const ApiProvidersProviderIdModelMetadataRoute = Route$8.update({
15009
+ const ApiProvidersProviderIdModelMetadataRoute = Route$9.update({
13278
15010
  id: "/model-metadata",
13279
15011
  path: "/model-metadata",
13280
15012
  getParentRoute: () => ApiProvidersProviderIdRoute
13281
15013
  });
13282
- const ApiLogsIdReplayRoute = Route$7.update({
15014
+ const ApiLogsIdReplayRoute = Route$8.update({
13283
15015
  id: "/replay",
13284
15016
  path: "/replay",
13285
15017
  getParentRoute: () => ApiLogsIdRoute
13286
15018
  });
13287
- const ApiLogsIdChunksRoute = Route$6.update({
15019
+ const ApiLogsIdChunksRoute = Route$7.update({
13288
15020
  id: "/chunks",
13289
15021
  path: "/chunks",
13290
15022
  getParentRoute: () => ApiLogsIdRoute
13291
15023
  });
15024
+ const ApiLogsIdBodyRoute = Route$6.update({
15025
+ id: "/body",
15026
+ path: "/body",
15027
+ getParentRoute: () => ApiLogsIdRoute
15028
+ });
13292
15029
  const ApiKnowledgeCandidatesCandidateIdRoute = Route$5.update({
13293
15030
  id: "/$candidateId",
13294
15031
  path: "/$candidateId",
@@ -13312,13 +15049,19 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
13312
15049
  const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
13313
15050
  id: "/api/knowledge/sessions/$sessionId/candidates",
13314
15051
  path: "/api/knowledge/sessions/$sessionId/candidates",
13315
- getParentRoute: () => Route$z
15052
+ getParentRoute: () => Route$D
13316
15053
  });
13317
15054
  const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
13318
15055
  id: "/promote",
13319
15056
  path: "/promote",
13320
15057
  getParentRoute: () => ApiKnowledgeCandidatesCandidateIdRoute
13321
15058
  });
15059
+ const ApiAlertsRouteChildren = {
15060
+ ApiAlertsSummaryRoute
15061
+ };
15062
+ const ApiAlertsRouteWithChildren = ApiAlertsRoute._addFileChildren(
15063
+ ApiAlertsRouteChildren
15064
+ );
13322
15065
  const ApiConfigRouteChildren = {
13323
15066
  ApiConfigPathsRoute
13324
15067
  };
@@ -13337,6 +15080,7 @@ const ApiGroupsRouteWithChildren = ApiGroupsRoute._addFileChildren(
13337
15080
  ApiGroupsRouteChildren
13338
15081
  );
13339
15082
  const ApiLogsIdRouteChildren = {
15083
+ ApiLogsIdBodyRoute,
13340
15084
  ApiLogsIdChunksRoute,
13341
15085
  ApiLogsIdReplayRoute
13342
15086
  };
@@ -13345,6 +15089,7 @@ const ApiLogsIdRouteWithChildren = ApiLogsIdRoute._addFileChildren(
13345
15089
  );
13346
15090
  const ApiLogsRouteChildren = {
13347
15091
  ApiLogsIdRoute: ApiLogsIdRouteWithChildren,
15092
+ ApiLogsImportRoute,
13348
15093
  ApiLogsStreamRoute
13349
15094
  };
13350
15095
  const ApiLogsRouteWithChildren = ApiLogsRoute._addFileChildren(ApiLogsRouteChildren);
@@ -13394,6 +15139,7 @@ const ApiKnowledgeCandidatesRouteWithChildren = ApiKnowledgeCandidatesRoute._add
13394
15139
  );
13395
15140
  const rootRouteChildren = {
13396
15141
  IndexRoute,
15142
+ ApiAlertsRoute: ApiAlertsRouteWithChildren,
13397
15143
  ApiConfigRoute: ApiConfigRouteWithChildren,
13398
15144
  ApiGroupsRoute: ApiGroupsRouteWithChildren,
13399
15145
  ApiHealthRoute,
@@ -13410,7 +15156,7 @@ const rootRouteChildren = {
13410
15156
  ApiKnowledgeSearchRoute,
13411
15157
  ApiKnowledgeSessionsSessionIdCandidatesRoute
13412
15158
  };
13413
- const routeTree = Route$z._addFileChildren(rootRouteChildren)._addFileTypes();
15159
+ const routeTree = Route$D._addFileChildren(rootRouteChildren)._addFileTypes();
13414
15160
  function getRouter() {
13415
15161
  const router2 = createRouter({
13416
15162
  routeTree,
@@ -13442,32 +15188,35 @@ export {
13442
15188
  GroupEvidenceReadResponseSchema as G,
13443
15189
  InspectorGroupsListResponseSchema as I,
13444
15190
  KnowledgeCandidateSchema as K,
15191
+ LogBodyChunkSchema as L,
13445
15192
  MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
13446
15193
  OpenAIRequestSchema as O,
13447
15194
  ProviderConfigSchema as P,
13448
- Route$x as R,
15195
+ Route$B as R,
13449
15196
  TimeDisplayFormatSchema as T,
13450
15197
  DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
13451
15198
  DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
13452
15199
  DEFAULT_TIME_DISPLAY_FORMAT as c,
13453
15200
  RuntimeConfigSchema as d,
13454
15201
  AnthropicRequestSchema as e,
13455
- apiFormatForPath as f,
13456
- getSessionPath as g,
13457
- stripClaudeCodeBillingHeader as h,
13458
- GroupEvidenceExportResultSchema as i,
13459
- DeleteInspectorGroupResponseSchema as j,
13460
- providerHasContextMetadata as k,
13461
- findProviderModelMetadata as l,
13462
- maskApiKey as m,
13463
- createPendingProviderTestResults as n,
13464
- ProviderTestResultsSchema as o,
13465
- parseOpenAIResponse as p,
13466
- createFailedProviderTestResults as q,
13467
- MAX_PROVIDER_TEST_TIMEOUT_SECONDS as r,
15202
+ parseOpenAIResponse as f,
15203
+ apiFormatForPath as g,
15204
+ getSessionPath as h,
15205
+ stripClaudeCodeBillingHeader as i,
15206
+ AlertSummarySchema as j,
15207
+ AlertListResponseSchema as k,
15208
+ GroupEvidenceExportResultSchema as l,
15209
+ DeleteInspectorGroupResponseSchema as m,
15210
+ providerHasContextMetadata as n,
15211
+ findProviderModelMetadata as o,
15212
+ packageJson as p,
15213
+ maskApiKey as q,
15214
+ createPendingProviderTestResults as r,
13468
15215
  safeGetOwnProperty as s,
13469
- resolveProviderContextWindow as t,
13470
- isPlainRecord as u,
13471
- packageJson as v,
13472
- router as w
15216
+ ProviderTestResultsSchema as t,
15217
+ createFailedProviderTestResults as u,
15218
+ MAX_PROVIDER_TEST_TIMEOUT_SECONDS as v,
15219
+ resolveProviderContextWindow as w,
15220
+ isPlainRecord as x,
15221
+ router as y
13473
15222
  };