@tonyclaw/agent-inspector 2.0.29 → 2.0.31

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 (45) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-DcqxlgSQ.js → CompareDrawer-tIUf2EJm.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-BxRaXhKR.js +115 -0
  4. package/.output/public/assets/{ReplayDialog-CBcnPgx1.js → ReplayDialog-D6v1xcuC.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-DSgSqCYt.js → RequestAnatomy-D6PniTlx.js} +1 -1
  6. package/.output/public/assets/{ResponseView-CjqzBSoF.js → ResponseView-Sx8PjuvU.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-DdBBKolI.js → StreamingChunkSequence-D-Rbfnxh.js} +1 -1
  8. package/.output/public/assets/_sessionId-BhNTuZ31.js +1 -0
  9. package/.output/public/assets/index-Byk60-jA.css +1 -0
  10. package/.output/public/assets/index-Kxptlkpg.js +1 -0
  11. package/.output/public/assets/{main-B6OLZCp9.js → main-B1kdhY98.js} +2 -2
  12. package/.output/server/_libs/lucide-react.mjs +159 -134
  13. package/.output/server/{_sessionId-CCfKJJ19.mjs → _sessionId-BceHFKf4.mjs} +3 -3
  14. package/.output/server/_ssr/{CompareDrawer-uaPI5R6e.mjs → CompareDrawer-uSxK5Ei5.mjs} +3 -3
  15. package/.output/server/_ssr/{ProxyViewerContainer-BV2nIxXy.mjs → ProxyViewerContainer-_npQ_f2i.mjs} +566 -17
  16. package/.output/server/_ssr/{ReplayDialog-eE2Hy2Nl.mjs → ReplayDialog-BHAzSLCT.mjs} +4 -4
  17. package/.output/server/_ssr/{RequestAnatomy-B7vwWo57.mjs → RequestAnatomy-DjlZLXBd.mjs} +3 -3
  18. package/.output/server/_ssr/{ResponseView-Bm6Qp8mo.mjs → ResponseView-BuDEJ3fl.mjs} +3 -3
  19. package/.output/server/_ssr/{StreamingChunkSequence-CbAJKJQx.mjs → StreamingChunkSequence-DFcu0bD8.mjs} +3 -3
  20. package/.output/server/_ssr/{index-u14_Aj60.mjs → index-Bw6Fw33c.mjs} +2 -2
  21. package/.output/server/_ssr/index.mjs +2 -2
  22. package/.output/server/_ssr/{router-qgeGUp1k.mjs → router-D90tMCb3.mjs} +1236 -143
  23. package/.output/server/_tanstack-start-manifest_v-BVM4AUlx.mjs +4 -0
  24. package/.output/server/index.mjs +60 -60
  25. package/README.md +24 -1
  26. package/package.json +1 -1
  27. package/src/components/ProxyViewer.tsx +9 -2
  28. package/src/components/groups/GroupsDialog.tsx +732 -0
  29. package/src/lib/groupContract.ts +148 -0
  30. package/src/lib/runContract.ts +2 -0
  31. package/src/lib/useGroupEvidence.ts +33 -0
  32. package/src/lib/useGroups.ts +28 -0
  33. package/src/mcp/server.ts +282 -1
  34. package/src/mcp/toolHandlers.ts +123 -0
  35. package/src/proxy/groupEvidenceExporter.ts +354 -0
  36. package/src/proxy/groupStore.ts +259 -0
  37. package/src/routes/api/groups.$groupId.evidence.ts +74 -0
  38. package/src/routes/api/groups.$groupId.sessions.ts +50 -0
  39. package/src/routes/api/groups.$groupId.ts +50 -0
  40. package/src/routes/api/groups.ts +39 -0
  41. package/.output/public/assets/ProxyViewerContainer-D650kQlv.js +0 -115
  42. package/.output/public/assets/_sessionId-wctOoGh_.js +0 -1
  43. package/.output/public/assets/index-BhQGSdhG.js +0 -1
  44. package/.output/public/assets/index-CwlHPmgL.css +0 -1
  45. package/.output/server/_tanstack-start-manifest_v-BrfUXnre.mjs +0 -4
@@ -50,8 +50,8 @@ import "../_libs/mimic-function.mjs";
50
50
  import "../_libs/semver.mjs";
51
51
  import "../_libs/uint8array-extras.mjs";
52
52
  const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2064'%20role='img'%20aria-label='Agent%20Inspector'%3e%3crect%20width='64'%20height='64'%20rx='14'%20fill='%23111827'%20/%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='4.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20fill='%23f59e0b'%20d='M15%2036c0-11%207-18%2017-18s17%207%2017%2018c0%208-7%2013-17%2013s-17-5-17-13z'%20/%3e%3cpath%20d='M16%2031c-6-5-12-3-12%204%200%205%206%206%2011%202'%20/%3e%3cpath%20d='M48%2031c6-5%2012-3%2012%204%200%205-6%206-11%202'%20/%3e%3cpath%20d='M27%2019l-3-7'%20/%3e%3cpath%20d='M37%2019l3-7'%20/%3e%3cpath%20d='M19%2045l-6%209'%20/%3e%3cpath%20d='M27%2048l-3%209'%20/%3e%3cpath%20d='M37%2048l3%209'%20/%3e%3cpath%20d='M45%2045l6%209'%20/%3e%3c/g%3e%3cpath%20d='M14%2047l9-8%208%209c-5%203.5-12%203-17-1z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M18%2046l5-5%205%206c-3%201.6-7%201.4-10-1z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M23%2041v10'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.6'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='31'%20cy='48'%20r='1.8'%20fill='%23c2412d'%20/%3e%3cpath%20d='M24%2044l13-11%2014%2013c-8%205.8-18%205.3-27-2z'%20fill='%232f6b3f'%20opacity='.97'%20/%3e%3cpath%20d='M30%2043l7-7%209%209c-5%202.7-11%202.5-16-2z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M37%2036v14'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='2'%20stroke-linecap='round'%20/%3e%3cpath%20d='M30%2043c5-2%2011-1.5%2016%202'%20fill='none'%20stroke='%239fca78'%20stroke-width='1.8'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='51'%20cy='46'%20r='2'%20fill='%23c2412d'%20/%3e%3cpath%20d='M40%2050l8-8%207%208c-4.2%203.2-10%203-15%200z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M43%2049l5-5%204.5%205.5c-3%201.5-6%201.2-9.5-.5z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M48%2044v9'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.5'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='55'%20cy='50'%20r='1.7'%20fill='%23c2412d'%20/%3e%3ccircle%20cx='24'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='40'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='25'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3ccircle%20cx='39'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3c/svg%3e";
53
- const appCss = "/assets/index-CwlHPmgL.css";
54
- const Route$v = createRootRoute({
53
+ const appCss = "/assets/index-Byk60-jA.css";
54
+ const Route$z = createRootRoute({
55
55
  head: () => ({
56
56
  meta: [
57
57
  { charSet: "utf-8" },
@@ -93,8 +93,8 @@ function RootDocument({ children }) {
93
93
  ] })
94
94
  ] });
95
95
  }
96
- const $$splitComponentImporter$1 = () => import("./index-u14_Aj60.mjs");
97
- const Route$u = createFileRoute("/")({
96
+ const $$splitComponentImporter$1 = () => import("./index-Bw6Fw33c.mjs");
97
+ const Route$y = createFileRoute("/")({
98
98
  component: lazyRouteComponent($$splitComponentImporter$1, "component")
99
99
  });
100
100
  const B64URL_RE = /^[A-Za-z0-9_-]+$/;
@@ -136,8 +136,8 @@ function decodeSessionIdFromPath(encoded) {
136
136
  function getSessionPath(sessionId) {
137
137
  return `/session/${encodeSessionIdForPath(sessionId)}`;
138
138
  }
139
- const $$splitComponentImporter = () => import("../_sessionId-CCfKJJ19.mjs");
140
- const Route$t = createFileRoute("/session/$sessionId")({
139
+ const $$splitComponentImporter = () => import("../_sessionId-BceHFKf4.mjs");
140
+ const Route$x = createFileRoute("/session/$sessionId")({
141
141
  component: lazyRouteComponent($$splitComponentImporter, "component"),
142
142
  parseParams: (params) => ({
143
143
  sessionId: decodeSessionIdFromPath(params.sessionId)
@@ -1085,7 +1085,7 @@ function nonNegativeInteger(value) {
1085
1085
  if (value === null || !Number.isFinite(value) || value < 0) return 0;
1086
1086
  return Math.floor(value);
1087
1087
  }
1088
- function addTokenUsage(total, summary) {
1088
+ function addTokenUsage$1(total, summary) {
1089
1089
  const input = nonNegativeInteger(summary.tokens.input);
1090
1090
  const output = nonNegativeInteger(summary.tokens.output);
1091
1091
  const cacheCreate = nonNegativeInteger(summary.tokens.cacheCreate);
@@ -1115,7 +1115,7 @@ function buildApiPath(sessionId) {
1115
1115
  function buildCompactLogsPath(sessionId) {
1116
1116
  return buildRelativePath("/api/logs", new URLSearchParams({ compact: "1", sessionId }));
1117
1117
  }
1118
- function collectSortedValues(values) {
1118
+ function collectSortedValues$1(values) {
1119
1119
  const set = /* @__PURE__ */ new Set();
1120
1120
  for (const value of values) {
1121
1121
  if (value !== null && value.length > 0) {
@@ -1159,7 +1159,7 @@ function buildSessionInfo(input) {
1159
1159
  const errorCount = Math.max(countErrorLogs(summaries), input.snapshot?.failedRequests ?? 0);
1160
1160
  const completedLogCount = countCompletedLogs(summaries);
1161
1161
  const tokenUsage = summaries.reduce(
1162
- (total, summary) => addTokenUsage(total, summary),
1162
+ (total, summary) => addTokenUsage$1(total, summary),
1163
1163
  { input: 0, output: 0, cacheCreate: 0, cacheRead: 0, total: 0 }
1164
1164
  );
1165
1165
  const requestCount = Math.max(input.snapshot?.requestCount ?? 0, logCount);
@@ -1197,8 +1197,8 @@ function buildSessionInfo(input) {
1197
1197
  lastTaskError,
1198
1198
  logCount,
1199
1199
  errorCount,
1200
- models: collectSortedValues(summaries.map((summary) => summary.model)),
1201
- providers: collectSortedValues(summaries.map((summary) => summary.provider)),
1200
+ models: collectSortedValues$1(summaries.map((summary) => summary.model)),
1201
+ providers: collectSortedValues$1(summaries.map((summary) => summary.provider)),
1202
1202
  tokenUsage,
1203
1203
  lastLogId: input.snapshot?.lastLogId ?? latestLog?.id ?? null,
1204
1204
  lastModel: normalizeString(input.snapshot?.lastModel) ?? latestLog?.model ?? null,
@@ -4935,7 +4935,7 @@ async function handleProxy(req) {
4935
4935
  }
4936
4936
  return handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log, captureFullDetails);
4937
4937
  }
4938
- const Route$s = createFileRoute("/proxy/$")({
4938
+ const Route$w = createFileRoute("/proxy/$")({
4939
4939
  server: {
4940
4940
  handlers: {
4941
4941
  GET: ({ request }) => handleProxy(request),
@@ -4956,7 +4956,7 @@ function parsePositiveInt$2(value) {
4956
4956
  function parseBooleanFlag(value) {
4957
4957
  return value === "1" || value === "true";
4958
4958
  }
4959
- const Route$r = createFileRoute("/api/sessions")({
4959
+ const Route$v = createFileRoute("/api/sessions")({
4960
4960
  server: {
4961
4961
  handlers: {
4962
4962
  GET: async ({ request }) => {
@@ -5111,6 +5111,7 @@ const JenkinsReportSchema = object({
5111
5111
  summary: string(),
5112
5112
  markdown: string()
5113
5113
  });
5114
+ const EvidenceReportSchema = JenkinsReportSchema;
5114
5115
  const InspectorRunSchema = object({
5115
5116
  id: string(),
5116
5117
  sessionId: string(),
@@ -5179,10 +5180,10 @@ const RunsFileSchema = object({
5179
5180
  function runsFilePath() {
5180
5181
  return join(getDataDir(), "runs.json");
5181
5182
  }
5182
- function nowIso() {
5183
+ function nowIso$1() {
5183
5184
  return (/* @__PURE__ */ new Date()).toISOString();
5184
5185
  }
5185
- function stableId(input) {
5186
+ function stableId$1(input) {
5186
5187
  return input.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
5187
5188
  }
5188
5189
  function createRunId() {
@@ -5190,7 +5191,7 @@ function createRunId() {
5190
5191
  }
5191
5192
  function normalizeRunId(input) {
5192
5193
  if (input === void 0) return createRunId();
5193
- const normalized = stableId(input);
5194
+ const normalized = stableId$1(input);
5194
5195
  return normalized.length > 0 ? normalized : createRunId();
5195
5196
  }
5196
5197
  function normalizeSessionId(input, runId) {
@@ -5225,7 +5226,7 @@ function createRun(input) {
5225
5226
  const runId = normalizeRunId(parsed?.runId);
5226
5227
  const existing = getRun(runId);
5227
5228
  if (existing !== null) return existing;
5228
- const timestamp = nowIso();
5229
+ const timestamp = nowIso$1();
5229
5230
  const sessionId = normalizeSessionId(parsed?.sessionId, runId);
5230
5231
  const run = {
5231
5232
  id: runId,
@@ -5264,7 +5265,7 @@ function updateRun(runId, input) {
5264
5265
  const parsed = UpdateInspectorRunInputSchema.parse(input);
5265
5266
  const runs = readRuns();
5266
5267
  let updatedRun = null;
5267
- const updatedAt = nowIso();
5268
+ const updatedAt = nowIso$1();
5268
5269
  const updatedRuns = runs.map((run) => {
5269
5270
  if (run.id !== runId) return run;
5270
5271
  updatedRun = {
@@ -5351,7 +5352,7 @@ function listRecentFailures(limit) {
5351
5352
  limit: clampedLimit
5352
5353
  };
5353
5354
  }
5354
- async function readJsonBody$2(request) {
5355
+ async function readJsonBody$6(request) {
5355
5356
  try {
5356
5357
  const raw = await request.text();
5357
5358
  if (raw.trim().length === 0) return { ok: true, value: void 0 };
@@ -5366,7 +5367,7 @@ function parsePositiveInt$1(value, fallback) {
5366
5367
  if (!Number.isInteger(parsed) || parsed < 1) return fallback;
5367
5368
  return parsed;
5368
5369
  }
5369
- const Route$q = createFileRoute("/api/runs")({
5370
+ const Route$u = createFileRoute("/api/runs")({
5370
5371
  server: {
5371
5372
  handlers: {
5372
5373
  GET: ({ request }) => {
@@ -5381,7 +5382,7 @@ const Route$q = createFileRoute("/api/runs")({
5381
5382
  return Response.json({ runs: listRuns() });
5382
5383
  },
5383
5384
  POST: async ({ request }) => {
5384
- const body = await readJsonBody$2(request);
5385
+ const body = await readJsonBody$6(request);
5385
5386
  if (!body.ok) {
5386
5387
  return Response.json({ error: "Invalid JSON body" }, { status: 400 });
5387
5388
  }
@@ -5411,7 +5412,7 @@ const ProviderInputSchema = object({
5411
5412
  modelMetadata: array(ProviderModelMetadataSchema).optional(),
5412
5413
  source: _enum(["company", "personal"]).optional()
5413
5414
  });
5414
- const Route$p = createFileRoute("/api/providers")({
5415
+ const Route$t = createFileRoute("/api/providers")({
5415
5416
  server: {
5416
5417
  handlers: {
5417
5418
  GET: ({ request }) => {
@@ -5445,13 +5446,128 @@ const Route$p = createFileRoute("/api/providers")({
5445
5446
  }
5446
5447
  }
5447
5448
  });
5448
- const Route$o = createFileRoute("/api/models")({
5449
+ const Route$s = createFileRoute("/api/models")({
5449
5450
  server: {
5450
5451
  handlers: {
5451
5452
  GET: () => Response.json(getModels())
5452
5453
  }
5453
5454
  }
5454
5455
  });
5456
+ const version = "2.0.31";
5457
+ const packageJson = {
5458
+ version
5459
+ };
5460
+ const InspectorGroupStatusSchema = _enum([
5461
+ "created",
5462
+ "running",
5463
+ "completed",
5464
+ "failed",
5465
+ "cancelled"
5466
+ ]);
5467
+ const InspectorGroupKindSchema = _enum(["evaluation", "batch", "manual"]);
5468
+ const InspectorGroupEvidenceSchema = object({
5469
+ jsonPath: string(),
5470
+ markdownPath: string(),
5471
+ htmlPath: string(),
5472
+ exportedAt: string()
5473
+ });
5474
+ const InspectorGroupMemberSchema = object({
5475
+ id: string(),
5476
+ groupId: string(),
5477
+ sessionId: string(),
5478
+ runId: string().nullable(),
5479
+ label: string().nullable(),
5480
+ agent: string().nullable(),
5481
+ provider: string().nullable(),
5482
+ model: string().nullable(),
5483
+ status: InspectorRunStatusSchema.nullable(),
5484
+ metadata: record(string(), JsonValueSchema),
5485
+ addedAt: string(),
5486
+ updatedAt: string()
5487
+ });
5488
+ const InspectorGroupSchema = object({
5489
+ id: string(),
5490
+ title: string(),
5491
+ kind: InspectorGroupKindSchema,
5492
+ task: string().nullable(),
5493
+ project: string().nullable(),
5494
+ status: InspectorGroupStatusSchema,
5495
+ tags: array(string()),
5496
+ metadata: record(string(), JsonValueSchema),
5497
+ evidence: InspectorGroupEvidenceSchema.nullable(),
5498
+ members: array(InspectorGroupMemberSchema),
5499
+ createdAt: string(),
5500
+ updatedAt: string()
5501
+ });
5502
+ const CreateInspectorGroupInputSchema = object({
5503
+ groupId: string().min(1).optional(),
5504
+ title: string().min(1).optional(),
5505
+ kind: InspectorGroupKindSchema.optional(),
5506
+ task: string().nullable().optional(),
5507
+ project: string().nullable().optional(),
5508
+ status: InspectorGroupStatusSchema.optional(),
5509
+ tags: array(string()).optional(),
5510
+ metadata: record(string(), JsonValueSchema).optional()
5511
+ }).optional();
5512
+ const UpdateInspectorGroupInputSchema = object({
5513
+ title: string().min(1).optional(),
5514
+ kind: InspectorGroupKindSchema.optional(),
5515
+ task: string().nullable().optional(),
5516
+ project: string().nullable().optional(),
5517
+ status: InspectorGroupStatusSchema.optional(),
5518
+ tags: array(string()).optional(),
5519
+ metadata: record(string(), JsonValueSchema).optional()
5520
+ });
5521
+ const AddInspectorGroupSessionInputSchema = object({
5522
+ memberId: string().min(1).optional(),
5523
+ sessionId: string().min(1),
5524
+ runId: string().min(1).nullable().optional(),
5525
+ label: string().min(1).nullable().optional(),
5526
+ agent: string().min(1).nullable().optional(),
5527
+ provider: string().min(1).nullable().optional(),
5528
+ model: string().min(1).nullable().optional(),
5529
+ status: InspectorRunStatusSchema.nullable().optional(),
5530
+ metadata: record(string(), JsonValueSchema).optional()
5531
+ });
5532
+ const GroupEvidenceExportOptionsSchema = object({
5533
+ includeHistory: boolean().optional(),
5534
+ latestLogLimit: number().int().positive().max(50).optional()
5535
+ }).optional();
5536
+ const InspectorGroupExportMemberSchema = object({
5537
+ member: InspectorGroupMemberSchema,
5538
+ run: InspectorRunSchema.nullable(),
5539
+ session: SessionInfoSchema.nullable()
5540
+ });
5541
+ const InspectorGroupEvidenceSummarySchema = object({
5542
+ memberCount: number().int().nonnegative(),
5543
+ sessionsWithData: number().int().nonnegative(),
5544
+ missingSessions: number().int().nonnegative(),
5545
+ requestCount: number().int().nonnegative(),
5546
+ errorCount: number().int().nonnegative(),
5547
+ tokenUsage: SessionTokenUsageSchema,
5548
+ models: array(string()),
5549
+ providers: array(string()),
5550
+ completedMembers: number().int().nonnegative(),
5551
+ failedMembers: number().int().nonnegative(),
5552
+ runningMembers: number().int().nonnegative()
5553
+ });
5554
+ const GroupEvidenceReadResponseSchema$1 = object({
5555
+ group: InspectorGroupSchema,
5556
+ evidence: InspectorGroupEvidenceSchema,
5557
+ markdown: string(),
5558
+ summary: InspectorGroupEvidenceSummarySchema.nullable(),
5559
+ report: EvidenceReportSchema.nullable()
5560
+ });
5561
+ const GroupEvidenceExportResultSchema = object({
5562
+ group: InspectorGroupSchema,
5563
+ evidence: InspectorGroupEvidenceSchema,
5564
+ members: array(InspectorGroupExportMemberSchema),
5565
+ summary: InspectorGroupEvidenceSummarySchema,
5566
+ jenkinsReport: EvidenceReportSchema
5567
+ });
5568
+ const InspectorGroupsListResponseSchema = object({
5569
+ groups: array(InspectorGroupSchema)
5570
+ });
5455
5571
  let overridePort = null;
5456
5572
  function setCurrentPort(port) {
5457
5573
  if (!Number.isInteger(port) || port <= 0 || port > 65535) {
@@ -5851,6 +5967,85 @@ async function exportEvidenceImpl(callApi2, args) {
5851
5967
  }
5852
5968
  return textJson(parsed.data);
5853
5969
  }
5970
+ async function listGroupsImpl(callApi2) {
5971
+ const res = await callApi2("/api/groups");
5972
+ if (!res.ok) return toolError(`GET /api/groups returned ${res.status}`);
5973
+ const rawBody = await res.json();
5974
+ const parsed = InspectorGroupsListResponseSchema.safeParse(rawBody);
5975
+ if (!parsed.success) return toolError("GET /api/groups returned an unparseable group list");
5976
+ return textJson(parsed.data);
5977
+ }
5978
+ async function createGroupImpl(callApi2, args) {
5979
+ const res = await callApi2("/api/groups", {
5980
+ method: "POST",
5981
+ headers: { "content-type": "application/json" },
5982
+ body: JSON.stringify(args ?? {})
5983
+ });
5984
+ if (!res.ok) return toolError(`POST /api/groups returned ${res.status}`);
5985
+ const rawBody = await res.json();
5986
+ const parsed = InspectorGroupSchema.safeParse(rawBody);
5987
+ if (!parsed.success) return toolError("POST /api/groups returned an unparseable group");
5988
+ return textJson(parsed.data);
5989
+ }
5990
+ async function getGroupImpl(callApi2, args) {
5991
+ const path2 = `/api/groups/${encodeURIComponent(args.groupId)}`;
5992
+ const res = await callApi2(path2);
5993
+ if (!res.ok) return toolError(`GET ${path2} returned ${res.status}`);
5994
+ const rawBody = await res.json();
5995
+ const parsed = InspectorGroupSchema.safeParse(rawBody);
5996
+ if (!parsed.success) return toolError("GET /api/groups/{groupId} returned an unparseable group");
5997
+ return textJson(parsed.data);
5998
+ }
5999
+ async function updateGroupImpl(callApi2, args) {
6000
+ const { groupId, ...patch } = args;
6001
+ const path2 = `/api/groups/${encodeURIComponent(groupId)}`;
6002
+ const res = await callApi2(path2, {
6003
+ method: "PATCH",
6004
+ headers: { "content-type": "application/json" },
6005
+ body: JSON.stringify(patch)
6006
+ });
6007
+ if (!res.ok) return toolError(`PATCH ${path2} returned ${res.status}`);
6008
+ const rawBody = await res.json();
6009
+ const parsed = InspectorGroupSchema.safeParse(rawBody);
6010
+ if (!parsed.success) {
6011
+ return toolError("PATCH /api/groups/{groupId} returned an unparseable group");
6012
+ }
6013
+ return textJson(parsed.data);
6014
+ }
6015
+ async function addGroupSessionImpl(callApi2, args) {
6016
+ const { groupId, ...session } = args;
6017
+ const path2 = `/api/groups/${encodeURIComponent(groupId)}/sessions`;
6018
+ const res = await callApi2(path2, {
6019
+ method: "POST",
6020
+ headers: { "content-type": "application/json" },
6021
+ body: JSON.stringify(session)
6022
+ });
6023
+ if (!res.ok) return toolError(`POST ${path2} returned ${res.status}`);
6024
+ const rawBody = await res.json();
6025
+ const parsed = InspectorGroupSchema.safeParse(rawBody);
6026
+ if (!parsed.success) {
6027
+ return toolError("POST /api/groups/{groupId}/sessions returned an unparseable group");
6028
+ }
6029
+ return textJson(parsed.data);
6030
+ }
6031
+ async function exportGroupEvidenceImpl(callApi2, args) {
6032
+ const path2 = `/api/groups/${encodeURIComponent(args.groupId)}/evidence`;
6033
+ const res = await callApi2(path2, {
6034
+ method: "POST",
6035
+ headers: { "content-type": "application/json" },
6036
+ body: JSON.stringify({
6037
+ includeHistory: args.includeHistory,
6038
+ latestLogLimit: args.latestLogLimit
6039
+ })
6040
+ });
6041
+ if (!res.ok) return toolError(`POST ${path2} returned ${res.status}`);
6042
+ const rawBody = await res.json();
6043
+ const parsed = GroupEvidenceExportResultSchema.safeParse(rawBody);
6044
+ if (!parsed.success) {
6045
+ return toolError("POST /api/groups/{groupId}/evidence returned an unparseable evidence result");
6046
+ }
6047
+ return textJson(parsed.data);
6048
+ }
5854
6049
  async function listModelsImpl(callApi2) {
5855
6050
  const res = await callApi2("/api/models");
5856
6051
  if (!res.ok) return toolError(`GET /api/models returned ${res.status}`);
@@ -5976,11 +6171,12 @@ async function safeCall(fn) {
5976
6171
  return toolError(`Tool execution failed: ${message}`);
5977
6172
  }
5978
6173
  }
6174
+ const MCP_SERVER_VERSION = packageJson.version;
5979
6175
  let initialized = null;
5980
6176
  let initPromise = null;
5981
6177
  function buildServer() {
5982
6178
  const server = new McpServer(
5983
- { name: "agent-inspector", version: "1.0.0" },
6179
+ { name: "agent-inspector", version: MCP_SERVER_VERSION },
5984
6180
  { capabilities: { tools: {}, resources: {}, prompts: {} } }
5985
6181
  );
5986
6182
  registerTools(server);
@@ -6042,6 +6238,9 @@ const LogResourceListResponseSchema = object({
6042
6238
  const EvidenceReadResponseSchema = object({
6043
6239
  markdown: string()
6044
6240
  });
6241
+ const GroupEvidenceReadResponseSchema = object({
6242
+ markdown: string()
6243
+ });
6045
6244
  function textResource(uri, mimeType, text) {
6046
6245
  return {
6047
6246
  contents: [{ uri: uri.href, mimeType, text }]
@@ -6124,6 +6323,61 @@ async function listRunResources() {
6124
6323
  return listResult([]);
6125
6324
  }
6126
6325
  }
6326
+ async function listGroupResources() {
6327
+ try {
6328
+ const response = await callApi("/api/groups");
6329
+ if (!response.ok) return listResult([]);
6330
+ const parsed = InspectorGroupsListResponseSchema.safeParse(await response.json());
6331
+ if (!parsed.success) return listResult([]);
6332
+ return listResult(
6333
+ parsed.data.groups.map((group) => ({
6334
+ uri: `inspector://groups/${encodeURIComponent(group.id)}`,
6335
+ name: `group:${group.id}`,
6336
+ title: group.title,
6337
+ mimeType: "application/json"
6338
+ }))
6339
+ );
6340
+ } catch {
6341
+ return listResult([]);
6342
+ }
6343
+ }
6344
+ async function listGroupSessionResources() {
6345
+ try {
6346
+ const response = await callApi("/api/groups");
6347
+ if (!response.ok) return listResult([]);
6348
+ const parsed = InspectorGroupsListResponseSchema.safeParse(await response.json());
6349
+ if (!parsed.success) return listResult([]);
6350
+ return listResult(
6351
+ parsed.data.groups.map((group) => ({
6352
+ uri: `inspector://groups/${encodeURIComponent(group.id)}/sessions`,
6353
+ name: `group-sessions:${group.id}`,
6354
+ title: `${group.title} sessions`,
6355
+ mimeType: "application/json"
6356
+ }))
6357
+ );
6358
+ } catch {
6359
+ return listResult([]);
6360
+ }
6361
+ }
6362
+ async function listGroupEvidenceResources() {
6363
+ try {
6364
+ const response = await callApi("/api/groups");
6365
+ if (!response.ok) return listResult([]);
6366
+ const parsed = InspectorGroupsListResponseSchema.safeParse(await response.json());
6367
+ if (!parsed.success) return listResult([]);
6368
+ return listResult(
6369
+ parsed.data.groups.filter((group) => group.evidence !== null).map((group) => ({
6370
+ uri: `inspector://groups/${encodeURIComponent(group.id)}/evidence`,
6371
+ name: `group-evidence:${group.id}`,
6372
+ title: `${group.title} evidence pack`,
6373
+ mimeType: "text/markdown",
6374
+ description: group.evidence?.markdownPath
6375
+ }))
6376
+ );
6377
+ } catch {
6378
+ return listResult([]);
6379
+ }
6380
+ }
6127
6381
  async function listEvidenceResources() {
6128
6382
  try {
6129
6383
  const response = await callApi("/api/runs");
@@ -6296,6 +6550,77 @@ function registerTools(server) {
6296
6550
  },
6297
6551
  (args) => safeCall(() => getRecentFailuresImpl(callApi, args))
6298
6552
  );
6553
+ server.registerTool(
6554
+ "inspector_list_groups",
6555
+ {
6556
+ title: "List Inspector groups",
6557
+ description: "Lists declared Inspector groups. Groups aggregate multiple sessions/runs, commonly one evaluation matrix spanning several providers or models.",
6558
+ inputSchema: object({})
6559
+ },
6560
+ () => safeCall(() => listGroupsImpl(callApi))
6561
+ );
6562
+ server.registerTool(
6563
+ "inspector_create_group",
6564
+ {
6565
+ title: "Create or declare an Inspector group",
6566
+ description: "Creates an evaluation/batch group that external systems can use to aggregate multiple OpenCode/Codex sessions across models such as MiniMax, DeepSeek, or GLM.",
6567
+ inputSchema: object({
6568
+ groupId: string().min(1).optional().describe("Stable group id. Generated when omitted."),
6569
+ title: string().min(1).optional().describe("Human-readable group title."),
6570
+ kind: _enum(["evaluation", "batch", "manual"]).optional().describe("Group kind. Defaults to evaluation."),
6571
+ task: string().nullable().optional().describe("Task, benchmark, or evaluation goal."),
6572
+ project: string().nullable().optional().describe("Project or repository under test."),
6573
+ status: InspectorGroupStatusSchema.optional().describe("Initial group status."),
6574
+ tags: array(string()).optional().describe("Free-form group labels."),
6575
+ metadata: record(string(), JsonValueSchema).optional().describe("JSON metadata.")
6576
+ })
6577
+ },
6578
+ (args) => safeCall(() => createGroupImpl(callApi, args))
6579
+ );
6580
+ server.registerTool(
6581
+ "inspector_get_group",
6582
+ {
6583
+ title: "Get an Inspector group",
6584
+ description: "Returns one declared Inspector group with its attached session/run members and exported evidence paths when available.",
6585
+ inputSchema: object({
6586
+ groupId: string().min(1).describe("The Inspector group id.")
6587
+ })
6588
+ },
6589
+ (args) => safeCall(() => getGroupImpl(callApi, args))
6590
+ );
6591
+ server.registerTool(
6592
+ "inspector_update_group",
6593
+ {
6594
+ title: "Update an Inspector group",
6595
+ description: "PATCH-style update for a declared group. Use this to mark a whole evaluation running, failed, completed, or to merge CI metadata.",
6596
+ inputSchema: UpdateInspectorGroupInputSchema.extend({
6597
+ groupId: string().min(1).describe("The Inspector group id.")
6598
+ })
6599
+ },
6600
+ (args) => safeCall(() => updateGroupImpl(callApi, args))
6601
+ );
6602
+ server.registerTool(
6603
+ "inspector_add_group_session",
6604
+ {
6605
+ title: "Attach a session to an Inspector group",
6606
+ description: "Adds or updates one group member. Use it after each OpenCode process discovers its session id, or while an evaluation matrix is running to attach model/provider labels.",
6607
+ inputSchema: AddInspectorGroupSessionInputSchema.extend({
6608
+ groupId: string().min(1).describe("The Inspector group id.")
6609
+ })
6610
+ },
6611
+ (args) => safeCall(() => addGroupSessionImpl(callApi, args))
6612
+ );
6613
+ server.registerTool(
6614
+ "inspector_export_group_evidence",
6615
+ {
6616
+ title: "Export an Inspector group evidence pack",
6617
+ description: "Exports a whole group's evidence pack to local JSON, Markdown, and HTML files under <dataDir>/evidence/groups/<groupId>. The export contains a provider/model matrix and compact session summaries.",
6618
+ inputSchema: GroupEvidenceExportOptionsSchema.unwrap().extend({
6619
+ groupId: string().min(1).describe("The Inspector group id.")
6620
+ })
6621
+ },
6622
+ (args) => safeCall(() => exportGroupEvidenceImpl(callApi, args))
6623
+ );
6299
6624
  server.registerTool(
6300
6625
  "inspector_list_models",
6301
6626
  {
@@ -6503,6 +6828,46 @@ function registerResources(server) {
6503
6828
  },
6504
6829
  (uri) => readApiJsonResource(uri, "/api/runs")
6505
6830
  );
6831
+ server.registerResource(
6832
+ "inspector_groups",
6833
+ "inspector://groups",
6834
+ {
6835
+ title: "Inspector groups",
6836
+ description: "Declared Inspector groups aggregating multiple sessions or runs.",
6837
+ mimeType: "application/json"
6838
+ },
6839
+ (uri) => readApiJsonResource(uri, "/api/groups")
6840
+ );
6841
+ server.registerResource(
6842
+ "inspector_group",
6843
+ new ResourceTemplate("inspector://groups/{groupId}", { list: listGroupResources }),
6844
+ {
6845
+ title: "Inspector group",
6846
+ description: "One declared Inspector group with attached session/run members.",
6847
+ mimeType: "application/json"
6848
+ },
6849
+ (uri, variables) => {
6850
+ const groupId = variableString(variables, "groupId");
6851
+ if (groupId === null) return textResource(uri, "text/plain", "Missing groupId");
6852
+ return readApiJsonResource(uri, `/api/groups/${encodeURIComponent(groupId)}`);
6853
+ }
6854
+ );
6855
+ server.registerResource(
6856
+ "inspector_group_sessions",
6857
+ new ResourceTemplate("inspector://groups/{groupId}/sessions", {
6858
+ list: listGroupSessionResources
6859
+ }),
6860
+ {
6861
+ title: "Inspector group sessions",
6862
+ description: "Attached session/run members for one Inspector group.",
6863
+ mimeType: "application/json"
6864
+ },
6865
+ (uri, variables) => {
6866
+ const groupId = variableString(variables, "groupId");
6867
+ if (groupId === null) return textResource(uri, "text/plain", "Missing groupId");
6868
+ return readApiJsonResource(uri, `/api/groups/${encodeURIComponent(groupId)}/sessions`);
6869
+ }
6870
+ );
6506
6871
  server.registerResource(
6507
6872
  "inspector_recent_failures",
6508
6873
  "inspector://failures/recent",
@@ -6555,6 +6920,36 @@ function registerResources(server) {
6555
6920
  }
6556
6921
  }
6557
6922
  );
6923
+ server.registerResource(
6924
+ "inspector_group_evidence",
6925
+ new ResourceTemplate("inspector://groups/{groupId}/evidence", {
6926
+ list: listGroupEvidenceResources
6927
+ }),
6928
+ {
6929
+ title: "Inspector group evidence pack",
6930
+ description: "Markdown evidence pack for an Inspector group. Generate it first with inspector_export_group_evidence.",
6931
+ mimeType: "text/markdown"
6932
+ },
6933
+ async (uri, variables) => {
6934
+ const groupId = variableString(variables, "groupId");
6935
+ if (groupId === null) return textResource(uri, "text/plain", "Missing groupId");
6936
+ const path2 = `/api/groups/${encodeURIComponent(groupId)}/evidence`;
6937
+ try {
6938
+ const response = await callApi(path2);
6939
+ if (!response.ok) {
6940
+ return textResource(uri, "text/plain", `GET ${path2} returned ${response.status}`);
6941
+ }
6942
+ const parsed = GroupEvidenceReadResponseSchema.safeParse(await response.json());
6943
+ if (!parsed.success) {
6944
+ return textResource(uri, "text/plain", "Evidence endpoint returned an unparseable body");
6945
+ }
6946
+ return textResource(uri, "text/markdown", parsed.data.markdown);
6947
+ } catch (err) {
6948
+ const message = err instanceof Error ? err.message : String(err);
6949
+ return textResource(uri, "text/plain", `Resource read failed: ${message}`);
6950
+ }
6951
+ }
6952
+ );
6558
6953
  }
6559
6954
  function registerPrompts(server) {
6560
6955
  server.registerPrompt(
@@ -6627,6 +7022,31 @@ The report should include:
6627
7022
  3. Models/providers used, token totals, request counts, and error counts
6628
7023
  4. Failure analysis or success evidence
6629
7024
  5. Reproducible next action for a developer`)
7025
+ );
7026
+ server.registerPrompt(
7027
+ "inspector_generate_group_report",
7028
+ {
7029
+ title: "Generate group report",
7030
+ description: "Generate a model/provider evaluation report from an Inspector group and group evidence pack.",
7031
+ argsSchema: object({
7032
+ groupId: string().min(1).describe("The Inspector group id.")
7033
+ })
7034
+ },
7035
+ ({ groupId }) => userPrompt(`Generate a model/provider evaluation report for this Inspector group.
7036
+
7037
+ Evidence to read:
7038
+ - Group resource: inspector://groups/${encodeURIComponent(groupId)}
7039
+ - Group session members: inspector://groups/${encodeURIComponent(groupId)}/sessions
7040
+ - Group evidence pack: inspector://groups/${encodeURIComponent(groupId)}/evidence
7041
+
7042
+ If the evidence pack resource says it has not been exported, call inspector_export_group_evidence for this group first.
7043
+
7044
+ The report should include:
7045
+ 1. Evaluation status summary
7046
+ 2. Provider/model matrix with session links
7047
+ 3. Request counts, token totals, streaming timing, and error counts
7048
+ 4. Winner/loser observations when the evidence supports them
7049
+ 5. Concrete next actions for failed or missing sessions`)
6630
7050
  );
6631
7051
  server.registerPrompt(
6632
7052
  "inspector_extract_repro_steps",
@@ -6651,7 +7071,7 @@ Return:
6651
7071
  5. Minimal verification command or UI check`)
6652
7072
  );
6653
7073
  }
6654
- const Route$n = createFileRoute("/api/mcp")({
7074
+ const Route$r = createFileRoute("/api/mcp")({
6655
7075
  server: {
6656
7076
  handlers: {
6657
7077
  // The SDK may issue either POST, GET, or DELETE. TanStack Start only
@@ -6761,7 +7181,7 @@ function parsePositiveInt(value, fallback) {
6761
7181
  if (!Number.isInteger(parsed) || parsed < 1) return fallback;
6762
7182
  return parsed;
6763
7183
  }
6764
- const Route$m = createFileRoute("/api/logs")({
7184
+ const Route$q = createFileRoute("/api/logs")({
6765
7185
  server: {
6766
7186
  handlers: {
6767
7187
  GET: async ({ request }) => {
@@ -6837,7 +7257,7 @@ const Route$m = createFileRoute("/api/logs")({
6837
7257
  }
6838
7258
  });
6839
7259
  logger.debug("Health endpoint loaded");
6840
- const Route$l = createFileRoute("/api/health")({
7260
+ const Route$p = createFileRoute("/api/health")({
6841
7261
  server: {
6842
7262
  handlers: {
6843
7263
  GET: () => {
@@ -6846,33 +7266,246 @@ const Route$l = createFileRoute("/api/health")({
6846
7266
  }
6847
7267
  }
6848
7268
  });
6849
- const RuntimeConfigPatchSchema = object({
6850
- stripClaudeCodeBillingHeader: boolean().optional(),
6851
- hasSeenOnboarding: boolean().optional(),
6852
- slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).optional(),
6853
- providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).optional(),
6854
- timeDisplayFormat: TimeDisplayFormatSchema.optional()
6855
- }).strict().refine((v) => Object.keys(v).length > 0, {
6856
- message: "At least one field must be provided"
7269
+ const GroupsFileSchema = object({
7270
+ groups: array(InspectorGroupSchema)
6857
7271
  });
6858
- const Route$k = createFileRoute("/api/config")({
6859
- server: {
6860
- handlers: {
6861
- GET: () => {
6862
- return Response.json(getConfig());
6863
- },
6864
- PATCH: async ({ request }) => {
6865
- let body;
6866
- try {
6867
- body = await request.json();
6868
- } catch {
6869
- return Response.json({ error: "Invalid JSON body" }, { status: 400 });
6870
- }
6871
- const result = RuntimeConfigPatchSchema.safeParse(body);
6872
- if (!result.success) {
6873
- return Response.json(
6874
- {
6875
- error: "Invalid config payload",
7272
+ function groupsFilePath() {
7273
+ return join(getDataDir(), "groups.json");
7274
+ }
7275
+ function nowIso() {
7276
+ return (/* @__PURE__ */ new Date()).toISOString();
7277
+ }
7278
+ function stableId(input) {
7279
+ return input.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
7280
+ }
7281
+ function createGroupId() {
7282
+ return `grp_${Date.now().toString(36)}_${randomUUID$1().slice(0, 8)}`;
7283
+ }
7284
+ function createMemberId() {
7285
+ return `mem_${Date.now().toString(36)}_${randomUUID$1().slice(0, 8)}`;
7286
+ }
7287
+ function normalizeGroupId(input) {
7288
+ if (input === void 0) return createGroupId();
7289
+ const normalized = stableId(input);
7290
+ return normalized.length > 0 ? normalized : createGroupId();
7291
+ }
7292
+ function normalizeMemberId(input, sessionId) {
7293
+ if (input === void 0) {
7294
+ const normalizedSession = stableId(sessionId);
7295
+ return normalizedSession.length > 0 ? `mem_${normalizedSession}` : createMemberId();
7296
+ }
7297
+ const normalized = stableId(input);
7298
+ return normalized.length > 0 ? normalized : createMemberId();
7299
+ }
7300
+ function nullableText(value) {
7301
+ if (value === void 0 || value === null) return null;
7302
+ const trimmed = value.trim();
7303
+ return trimmed.length > 0 ? trimmed : null;
7304
+ }
7305
+ function readGroups() {
7306
+ const filePath = groupsFilePath();
7307
+ if (!existsSync(filePath)) return [];
7308
+ try {
7309
+ const parsed = JSON.parse(readFileSync(filePath, "utf8"));
7310
+ const result = GroupsFileSchema.safeParse(parsed);
7311
+ return result.success ? result.data.groups : [];
7312
+ } catch {
7313
+ return [];
7314
+ }
7315
+ }
7316
+ function writeGroups(groups) {
7317
+ const filePath = groupsFilePath();
7318
+ mkdirSync(dirname(filePath), { recursive: true });
7319
+ writeFileSync(filePath, `${JSON.stringify({ groups }, null, 2)}
7320
+ `, "utf8");
7321
+ }
7322
+ function sortedGroups(groups) {
7323
+ return [...groups].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
7324
+ }
7325
+ function listGroups() {
7326
+ return sortedGroups(readGroups());
7327
+ }
7328
+ function getGroup(groupId) {
7329
+ return readGroups().find((group) => group.id === groupId) ?? null;
7330
+ }
7331
+ function createGroup(input) {
7332
+ const parsed = CreateInspectorGroupInputSchema.parse(input);
7333
+ const groupId = normalizeGroupId(parsed?.groupId);
7334
+ const existing = getGroup(groupId);
7335
+ if (existing !== null) return existing;
7336
+ const timestamp = nowIso();
7337
+ const group = {
7338
+ id: groupId,
7339
+ title: parsed?.title ?? `Inspector Group ${groupId}`,
7340
+ kind: parsed?.kind ?? "evaluation",
7341
+ task: parsed?.task ?? null,
7342
+ project: parsed?.project ?? null,
7343
+ status: parsed?.status ?? "created",
7344
+ tags: parsed?.tags ?? [],
7345
+ metadata: parsed?.metadata ?? {},
7346
+ evidence: null,
7347
+ members: [],
7348
+ createdAt: timestamp,
7349
+ updatedAt: timestamp
7350
+ };
7351
+ writeGroups([...readGroups(), group]);
7352
+ return group;
7353
+ }
7354
+ function updateGroup(groupId, input) {
7355
+ const parsed = UpdateInspectorGroupInputSchema.parse(input);
7356
+ const groups = readGroups();
7357
+ let updatedGroup = null;
7358
+ const updatedAt = nowIso();
7359
+ const updatedGroups = groups.map((group) => {
7360
+ if (group.id !== groupId) return group;
7361
+ updatedGroup = {
7362
+ ...group,
7363
+ title: parsed.title ?? group.title,
7364
+ kind: parsed.kind ?? group.kind,
7365
+ task: parsed.task === void 0 ? group.task : parsed.task,
7366
+ project: parsed.project === void 0 ? group.project : parsed.project,
7367
+ status: parsed.status ?? group.status,
7368
+ tags: parsed.tags ?? group.tags,
7369
+ metadata: parsed.metadata === void 0 ? group.metadata : { ...group.metadata, ...parsed.metadata },
7370
+ updatedAt
7371
+ };
7372
+ return updatedGroup;
7373
+ });
7374
+ if (updatedGroup === null) return null;
7375
+ writeGroups(updatedGroups);
7376
+ return updatedGroup;
7377
+ }
7378
+ function matchesExistingMember(member, memberId, sessionId, runId) {
7379
+ if (member.id === memberId) return true;
7380
+ if (member.sessionId !== sessionId) return false;
7381
+ return member.runId === runId;
7382
+ }
7383
+ function upsertMember(group, input, updatedAt) {
7384
+ const parsed = AddInspectorGroupSessionInputSchema.parse(input);
7385
+ const sessionId = parsed.sessionId.trim();
7386
+ const runId = nullableText(parsed.runId);
7387
+ const memberId = normalizeMemberId(parsed.memberId, sessionId);
7388
+ let matched = false;
7389
+ const members = group.members.map((member) => {
7390
+ if (!matchesExistingMember(member, memberId, sessionId, runId)) return member;
7391
+ matched = true;
7392
+ return {
7393
+ ...member,
7394
+ sessionId,
7395
+ runId,
7396
+ label: parsed.label === void 0 ? member.label : nullableText(parsed.label),
7397
+ agent: parsed.agent === void 0 ? member.agent : nullableText(parsed.agent),
7398
+ provider: parsed.provider === void 0 ? member.provider : nullableText(parsed.provider),
7399
+ model: parsed.model === void 0 ? member.model : nullableText(parsed.model),
7400
+ status: parsed.status === void 0 ? member.status : parsed.status,
7401
+ metadata: parsed.metadata === void 0 ? member.metadata : { ...member.metadata, ...parsed.metadata },
7402
+ updatedAt
7403
+ };
7404
+ });
7405
+ if (!matched) {
7406
+ members.push({
7407
+ id: memberId,
7408
+ groupId: group.id,
7409
+ sessionId,
7410
+ runId,
7411
+ label: nullableText(parsed.label),
7412
+ agent: nullableText(parsed.agent),
7413
+ provider: nullableText(parsed.provider),
7414
+ model: nullableText(parsed.model),
7415
+ status: parsed.status ?? null,
7416
+ metadata: parsed.metadata ?? {},
7417
+ addedAt: updatedAt,
7418
+ updatedAt
7419
+ });
7420
+ }
7421
+ return { ...group, members, updatedAt };
7422
+ }
7423
+ function addGroupSession(groupId, input) {
7424
+ const groups = readGroups();
7425
+ let updatedGroup = null;
7426
+ const updatedAt = nowIso();
7427
+ const updatedGroups = groups.map((group) => {
7428
+ if (group.id !== groupId) return group;
7429
+ updatedGroup = upsertMember(group, input, updatedAt);
7430
+ return updatedGroup;
7431
+ });
7432
+ if (updatedGroup === null) return null;
7433
+ writeGroups(updatedGroups);
7434
+ return updatedGroup;
7435
+ }
7436
+ function updateGroupEvidence(groupId, evidence) {
7437
+ const groups = readGroups();
7438
+ let updatedGroup = null;
7439
+ const updatedGroups = groups.map((group) => {
7440
+ if (group.id !== groupId) return group;
7441
+ updatedGroup = {
7442
+ ...group,
7443
+ evidence,
7444
+ updatedAt: evidence.exportedAt
7445
+ };
7446
+ return updatedGroup;
7447
+ });
7448
+ if (updatedGroup === null) return null;
7449
+ writeGroups(updatedGroups);
7450
+ return updatedGroup;
7451
+ }
7452
+ async function readJsonBody$5(request) {
7453
+ try {
7454
+ const raw = await request.text();
7455
+ if (raw.trim().length === 0) return { ok: true, value: void 0 };
7456
+ return { ok: true, value: JSON.parse(raw) };
7457
+ } catch {
7458
+ return { ok: false };
7459
+ }
7460
+ }
7461
+ const Route$o = createFileRoute("/api/groups")({
7462
+ server: {
7463
+ handlers: {
7464
+ GET: () => Response.json({ groups: listGroups() }),
7465
+ POST: async ({ request }) => {
7466
+ const body = await readJsonBody$5(request);
7467
+ if (!body.ok) {
7468
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
7469
+ }
7470
+ const parsed = CreateInspectorGroupInputSchema.safeParse(body.value);
7471
+ if (!parsed.success) {
7472
+ return Response.json(
7473
+ { error: "Invalid request body", details: parsed.error.format() },
7474
+ { status: 400 }
7475
+ );
7476
+ }
7477
+ return Response.json(createGroup(parsed.data), { status: 201 });
7478
+ }
7479
+ }
7480
+ }
7481
+ });
7482
+ const RuntimeConfigPatchSchema = object({
7483
+ stripClaudeCodeBillingHeader: boolean().optional(),
7484
+ hasSeenOnboarding: boolean().optional(),
7485
+ slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).optional(),
7486
+ providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).optional(),
7487
+ timeDisplayFormat: TimeDisplayFormatSchema.optional()
7488
+ }).strict().refine((v) => Object.keys(v).length > 0, {
7489
+ message: "At least one field must be provided"
7490
+ });
7491
+ const Route$n = createFileRoute("/api/config")({
7492
+ server: {
7493
+ handlers: {
7494
+ GET: () => {
7495
+ return Response.json(getConfig());
7496
+ },
7497
+ PATCH: async ({ request }) => {
7498
+ let body;
7499
+ try {
7500
+ body = await request.json();
7501
+ } catch {
7502
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
7503
+ }
7504
+ const result = RuntimeConfigPatchSchema.safeParse(body);
7505
+ if (!result.success) {
7506
+ return Response.json(
7507
+ {
7508
+ error: "Invalid config payload",
6876
7509
  issues: result.error.issues
6877
7510
  },
6878
7511
  { status: 400 }
@@ -6884,7 +7517,7 @@ const Route$k = createFileRoute("/api/config")({
6884
7517
  }
6885
7518
  }
6886
7519
  });
6887
- async function readJsonBody$1(request) {
7520
+ async function readJsonBody$4(request) {
6888
7521
  try {
6889
7522
  const raw = await request.text();
6890
7523
  if (raw.trim().length === 0) return { ok: true, value: {} };
@@ -6893,7 +7526,7 @@ async function readJsonBody$1(request) {
6893
7526
  return { ok: false };
6894
7527
  }
6895
7528
  }
6896
- const Route$j = createFileRoute("/api/runs/$runId")({
7529
+ const Route$m = createFileRoute("/api/runs/$runId")({
6897
7530
  server: {
6898
7531
  handlers: {
6899
7532
  GET: ({ params }) => {
@@ -6904,7 +7537,7 @@ const Route$j = createFileRoute("/api/runs/$runId")({
6904
7537
  return Response.json(run);
6905
7538
  },
6906
7539
  PATCH: async ({ params, request }) => {
6907
- const body = await readJsonBody$1(request);
7540
+ const body = await readJsonBody$4(request);
6908
7541
  if (!body.ok) {
6909
7542
  return Response.json({ error: "Invalid JSON body" }, { status: 400 });
6910
7543
  }
@@ -7350,7 +7983,7 @@ function scanExternalProviders() {
7350
7983
  }
7351
7984
  return { providers: filteredProviders, warnings };
7352
7985
  }
7353
- const Route$i = createFileRoute("/api/providers/scan")({
7986
+ const Route$l = createFileRoute("/api/providers/scan")({
7354
7987
  server: {
7355
7988
  handlers: {
7356
7989
  GET: () => {
@@ -7371,7 +8004,7 @@ const Route$i = createFileRoute("/api/providers/scan")({
7371
8004
  }
7372
8005
  });
7373
8006
  union([string(), object({ providers: unknown() })]);
7374
- const Route$h = createFileRoute("/api/providers/import")({
8007
+ const Route$k = createFileRoute("/api/providers/import")({
7375
8008
  server: {
7376
8009
  handlers: {
7377
8010
  POST: async ({ request }) => {
@@ -7404,7 +8037,7 @@ const Route$h = createFileRoute("/api/providers/import")({
7404
8037
  }
7405
8038
  }
7406
8039
  });
7407
- const Route$g = createFileRoute("/api/providers/export")({
8040
+ const Route$j = createFileRoute("/api/providers/export")({
7408
8041
  server: {
7409
8042
  handlers: {
7410
8043
  GET: ({ request }) => {
@@ -7437,7 +8070,7 @@ const ProviderUpdateSchema = object({
7437
8070
  modelMetadata: array(ProviderModelMetadataSchema).optional(),
7438
8071
  source: _enum(["company", "personal"]).optional()
7439
8072
  });
7440
- const Route$f = createFileRoute("/api/providers/$providerId")({
8073
+ const Route$i = createFileRoute("/api/providers/$providerId")({
7441
8074
  server: {
7442
8075
  handlers: {
7443
8076
  GET: ({ params, request }) => {
@@ -7472,7 +8105,7 @@ const Route$f = createFileRoute("/api/providers/$providerId")({
7472
8105
  }
7473
8106
  });
7474
8107
  const INITIAL_STREAM_LOG_LIMIT = 100;
7475
- const Route$e = createFileRoute("/api/logs/stream")({
8108
+ const Route$h = createFileRoute("/api/logs/stream")({
7476
8109
  server: {
7477
8110
  handlers: {
7478
8111
  GET: ({ request }) => {
@@ -7545,7 +8178,7 @@ const Route$e = createFileRoute("/api/logs/stream")({
7545
8178
  }
7546
8179
  }
7547
8180
  });
7548
- const Route$d = createFileRoute("/api/logs/$id")({
8181
+ const Route$g = createFileRoute("/api/logs/$id")({
7549
8182
  server: {
7550
8183
  handlers: {
7551
8184
  GET: async ({ params }) => {
@@ -8082,7 +8715,7 @@ const SearchBodySchema = object({
8082
8715
  query: string().min(1),
8083
8716
  project: string().optional()
8084
8717
  });
8085
- const Route$c = createFileRoute("/api/knowledge/search")({
8718
+ const Route$f = createFileRoute("/api/knowledge/search")({
8086
8719
  server: {
8087
8720
  handlers: {
8088
8721
  GET: async ({ request }) => {
@@ -8104,7 +8737,7 @@ const Route$c = createFileRoute("/api/knowledge/search")({
8104
8737
  }
8105
8738
  }
8106
8739
  });
8107
- const Route$b = createFileRoute("/api/knowledge/project-context")({
8740
+ const Route$e = createFileRoute("/api/knowledge/project-context")({
8108
8741
  server: {
8109
8742
  handlers: {
8110
8743
  GET: async ({ request }) => {
@@ -8186,14 +8819,54 @@ function updateCandidateDraft(id, updates) {
8186
8819
  candidates.set(id, updated);
8187
8820
  return updated;
8188
8821
  }
8189
- const Route$a = createFileRoute("/api/knowledge/candidates")({
8822
+ const Route$d = createFileRoute("/api/knowledge/candidates")({
8190
8823
  server: {
8191
8824
  handlers: {
8192
8825
  GET: () => Response.json({ candidates: listCandidates() })
8193
8826
  }
8194
8827
  }
8195
8828
  });
8196
- const Route$9 = createFileRoute("/api/config/paths")({
8829
+ async function readJsonBody$3(request) {
8830
+ try {
8831
+ const raw = await request.text();
8832
+ if (raw.trim().length === 0) return { ok: true, value: {} };
8833
+ return { ok: true, value: JSON.parse(raw) };
8834
+ } catch {
8835
+ return { ok: false };
8836
+ }
8837
+ }
8838
+ const Route$c = createFileRoute("/api/groups/$groupId")({
8839
+ server: {
8840
+ handlers: {
8841
+ GET: ({ params }) => {
8842
+ const group = getGroup(params.groupId);
8843
+ if (group === null) {
8844
+ return Response.json({ error: "Group not found" }, { status: 404 });
8845
+ }
8846
+ return Response.json(group);
8847
+ },
8848
+ PATCH: async ({ params, request }) => {
8849
+ const body = await readJsonBody$3(request);
8850
+ if (!body.ok) {
8851
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
8852
+ }
8853
+ const parsed = UpdateInspectorGroupInputSchema.safeParse(body.value);
8854
+ if (!parsed.success) {
8855
+ return Response.json(
8856
+ { error: "Invalid request body", details: parsed.error.format() },
8857
+ { status: 400 }
8858
+ );
8859
+ }
8860
+ const updated = updateGroup(params.groupId, parsed.data);
8861
+ if (updated === null) {
8862
+ return Response.json({ error: "Group not found" }, { status: 404 });
8863
+ }
8864
+ return Response.json(updated);
8865
+ }
8866
+ }
8867
+ }
8868
+ });
8869
+ const Route$b = createFileRoute("/api/config/paths")({
8197
8870
  server: {
8198
8871
  handlers: {
8199
8872
  GET: () => {
@@ -8576,7 +9249,7 @@ function timelineMarkdown(timeline) {
8576
9249
  })
8577
9250
  ];
8578
9251
  }
8579
- function buildJenkinsReport(input) {
9252
+ function buildJenkinsReport$1(input) {
8580
9253
  const status = reportStatus(input.classification);
8581
9254
  const session = input.session;
8582
9255
  const summary = `[${status}] ${input.classification.summary}`;
@@ -8624,7 +9297,7 @@ function buildJenkinsReport(input) {
8624
9297
  function analyzeEvidence(input) {
8625
9298
  const classification = classifyRunFailure(input.run, input.session);
8626
9299
  const timeline = buildRunTimeline(input.run, input.session, input.exportedAt);
8627
- const jenkinsReport = buildJenkinsReport({
9300
+ const jenkinsReport = buildJenkinsReport$1({
8628
9301
  run: input.run,
8629
9302
  session: input.session,
8630
9303
  timeline,
@@ -8636,22 +9309,22 @@ function analyzeEvidence(input) {
8636
9309
  function evidenceDir(runId) {
8637
9310
  return join(getDataDir(), "evidence", runId);
8638
9311
  }
8639
- function jsonPath(runId) {
9312
+ function jsonPath$1(runId) {
8640
9313
  return join(evidenceDir(runId), "evidence.json");
8641
9314
  }
8642
- function markdownPath(runId) {
9315
+ function markdownPath$1(runId) {
8643
9316
  return join(evidenceDir(runId), "evidence.md");
8644
9317
  }
8645
- function htmlPath(runId) {
9318
+ function htmlPath$1(runId) {
8646
9319
  return join(evidenceDir(runId), "evidence.html");
8647
9320
  }
8648
9321
  function formatList(values) {
8649
9322
  return values.length > 0 ? values.join(", ") : "n/a";
8650
9323
  }
8651
- function escapeHtml(value) {
9324
+ function escapeHtml$1(value) {
8652
9325
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
8653
9326
  }
8654
- function buildMarkdown(document) {
9327
+ function buildMarkdown$1(document) {
8655
9328
  const session = document.session;
8656
9329
  const lines = [
8657
9330
  `# ${document.run.title}`,
@@ -8733,19 +9406,19 @@ function buildMarkdown(document) {
8733
9406
  return `${lines.join("\n")}
8734
9407
  `;
8735
9408
  }
8736
- function buildHtml(markdown, title) {
9409
+ function buildHtml$1(markdown, title) {
8737
9410
  return `<!doctype html>
8738
9411
  <html lang="en">
8739
9412
  <head>
8740
9413
  <meta charset="utf-8">
8741
- <title>${escapeHtml(title)}</title>
9414
+ <title>${escapeHtml$1(title)}</title>
8742
9415
  <style>
8743
9416
  body { font-family: system-ui, sans-serif; max-width: 960px; margin: 40px auto; line-height: 1.5; }
8744
9417
  pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
8745
9418
  </style>
8746
9419
  </head>
8747
9420
  <body>
8748
- <pre>${escapeHtml(markdown)}</pre>
9421
+ <pre>${escapeHtml$1(markdown)}</pre>
8749
9422
  </body>
8750
9423
  </html>
8751
9424
  `;
@@ -8758,9 +9431,9 @@ async function exportRunEvidence(run, options, baseUrl) {
8758
9431
  });
8759
9432
  const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
8760
9433
  const evidence = {
8761
- jsonPath: jsonPath(run.id),
8762
- markdownPath: markdownPath(run.id),
8763
- htmlPath: htmlPath(run.id),
9434
+ jsonPath: jsonPath$1(run.id),
9435
+ markdownPath: markdownPath$1(run.id),
9436
+ htmlPath: htmlPath$1(run.id),
8764
9437
  exportedAt
8765
9438
  };
8766
9439
  const documentRun = {
@@ -8786,7 +9459,7 @@ async function exportRunEvidence(run, options, baseUrl) {
8786
9459
  classification: analysis.classification,
8787
9460
  jenkinsReport: analysis.jenkinsReport
8788
9461
  };
8789
- const markdown = buildMarkdown(document);
9462
+ const markdown = buildMarkdown$1(document);
8790
9463
  mkdirSync(evidenceDir(run.id), { recursive: true });
8791
9464
  writeFileSync(
8792
9465
  evidence.jsonPath,
@@ -8795,7 +9468,7 @@ async function exportRunEvidence(run, options, baseUrl) {
8795
9468
  "utf8"
8796
9469
  );
8797
9470
  writeFileSync(evidence.markdownPath, markdown, "utf8");
8798
- writeFileSync(evidence.htmlPath, buildHtml(markdown, run.title), "utf8");
9471
+ writeFileSync(evidence.htmlPath, buildHtml$1(markdown, run.title), "utf8");
8799
9472
  const updatedRun = updateRunEvidence(run.id, evidence) ?? documentRun;
8800
9473
  return { ...document, run: updatedRun };
8801
9474
  }
@@ -8808,7 +9481,7 @@ function readEvidenceMarkdown(run) {
8808
9481
  return null;
8809
9482
  }
8810
9483
  }
8811
- async function readJsonBody(request) {
9484
+ async function readJsonBody$2(request) {
8812
9485
  try {
8813
9486
  const raw = await request.text();
8814
9487
  if (raw.trim().length === 0) return { ok: true, value: void 0 };
@@ -8817,7 +9490,7 @@ async function readJsonBody(request) {
8817
9490
  return { ok: false };
8818
9491
  }
8819
9492
  }
8820
- const Route$8 = createFileRoute("/api/runs/$runId/evidence")({
9493
+ const Route$a = createFileRoute("/api/runs/$runId/evidence")({
8821
9494
  server: {
8822
9495
  handlers: {
8823
9496
  GET: ({ params }) => {
@@ -8839,7 +9512,7 @@ const Route$8 = createFileRoute("/api/runs/$runId/evidence")({
8839
9512
  if (run === null) {
8840
9513
  return Response.json({ error: "Run not found" }, { status: 404 });
8841
9514
  }
8842
- const body = await readJsonBody(request);
9515
+ const body = await readJsonBody$2(request);
8843
9516
  if (!body.ok) {
8844
9517
  return Response.json({ error: "Invalid JSON body" }, { status: 400 });
8845
9518
  }
@@ -9473,7 +10146,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
9473
10146
  clearTimeout(timeoutId);
9474
10147
  }
9475
10148
  }
9476
- const Route$7 = createFileRoute("/api/providers/$providerId/test")({
10149
+ const Route$9 = createFileRoute("/api/providers/$providerId/test")({
9477
10150
  server: {
9478
10151
  handlers: {
9479
10152
  POST: async ({ params }) => {
@@ -9567,7 +10240,7 @@ async function readRegistryJson(response) {
9567
10240
  return null;
9568
10241
  }
9569
10242
  }
9570
- const Route$6 = createFileRoute("/api/providers/$providerId/model-metadata")({
10243
+ const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
9571
10244
  server: {
9572
10245
  handlers: {
9573
10246
  POST: async ({ params, request }) => {
@@ -9657,7 +10330,7 @@ const Route$6 = createFileRoute("/api/providers/$providerId/model-metadata")({
9657
10330
  const ReplayRequestSchema = object({
9658
10331
  modifiedBody: string()
9659
10332
  });
9660
- const Route$5 = createFileRoute("/api/logs/$id/replay")({
10333
+ const Route$7 = createFileRoute("/api/logs/$id/replay")({
9661
10334
  server: {
9662
10335
  handlers: {
9663
10336
  POST: async ({ params, request }) => {
@@ -9858,7 +10531,7 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
9858
10531
  }
9859
10532
  }
9860
10533
  });
9861
- const Route$4 = createFileRoute("/api/logs/$id/chunks")({
10534
+ const Route$6 = createFileRoute("/api/logs/$id/chunks")({
9862
10535
  server: {
9863
10536
  handlers: {
9864
10537
  GET: async ({ params }) => {
@@ -9893,7 +10566,7 @@ const CandidateUpdateSchema = object({
9893
10566
  object({
9894
10567
  candidate: KnowledgeCandidateSchema
9895
10568
  });
9896
- const Route$3 = createFileRoute("/api/knowledge/candidates/$candidateId")({
10569
+ const Route$5 = createFileRoute("/api/knowledge/candidates/$candidateId")({
9897
10570
  server: {
9898
10571
  handlers: {
9899
10572
  PATCH: async ({ params, request }) => {
@@ -9921,6 +10594,390 @@ const Route$3 = createFileRoute("/api/knowledge/candidates/$candidateId")({
9921
10594
  }
9922
10595
  }
9923
10596
  });
10597
+ async function readJsonBody$1(request) {
10598
+ try {
10599
+ const raw = await request.text();
10600
+ if (raw.trim().length === 0) return { ok: true, value: {} };
10601
+ return { ok: true, value: JSON.parse(raw) };
10602
+ } catch {
10603
+ return { ok: false };
10604
+ }
10605
+ }
10606
+ const Route$4 = createFileRoute("/api/groups/$groupId/sessions")({
10607
+ server: {
10608
+ handlers: {
10609
+ GET: ({ params }) => {
10610
+ const group = getGroup(params.groupId);
10611
+ if (group === null) {
10612
+ return Response.json({ error: "Group not found" }, { status: 404 });
10613
+ }
10614
+ return Response.json({ groupId: group.id, members: group.members });
10615
+ },
10616
+ POST: async ({ params, request }) => {
10617
+ const body = await readJsonBody$1(request);
10618
+ if (!body.ok) {
10619
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
10620
+ }
10621
+ const parsed = AddInspectorGroupSessionInputSchema.safeParse(body.value);
10622
+ if (!parsed.success) {
10623
+ return Response.json(
10624
+ { error: "Invalid request body", details: parsed.error.format() },
10625
+ { status: 400 }
10626
+ );
10627
+ }
10628
+ const updated = addGroupSession(params.groupId, parsed.data);
10629
+ if (updated === null) {
10630
+ return Response.json({ error: "Group not found" }, { status: 404 });
10631
+ }
10632
+ return Response.json(updated);
10633
+ }
10634
+ }
10635
+ }
10636
+ });
10637
+ function groupEvidenceDir(groupId) {
10638
+ return join(getDataDir(), "evidence", "groups", groupId);
10639
+ }
10640
+ function jsonPath(groupId) {
10641
+ return join(groupEvidenceDir(groupId), "evidence.json");
10642
+ }
10643
+ function markdownPath(groupId) {
10644
+ return join(groupEvidenceDir(groupId), "evidence.md");
10645
+ }
10646
+ function htmlPath(groupId) {
10647
+ return join(groupEvidenceDir(groupId), "evidence.html");
10648
+ }
10649
+ function escapeMarkdownCell(value) {
10650
+ return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
10651
+ }
10652
+ function escapeHtml(value) {
10653
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
10654
+ }
10655
+ function formatText(value) {
10656
+ if (value === null || value === void 0 || value.length === 0) return "n/a";
10657
+ return value;
10658
+ }
10659
+ function formatNumber(value) {
10660
+ if (value === null || value === void 0) return "n/a";
10661
+ return String(value);
10662
+ }
10663
+ function collectSortedValues(values) {
10664
+ const set = /* @__PURE__ */ new Set();
10665
+ for (const value of values) {
10666
+ if (value !== null && value !== void 0 && value.length > 0) {
10667
+ set.add(value);
10668
+ }
10669
+ }
10670
+ return [...set].sort();
10671
+ }
10672
+ function addTokenUsage(total, session) {
10673
+ if (session === null) return total;
10674
+ return {
10675
+ input: total.input + session.tokenUsage.input,
10676
+ output: total.output + session.tokenUsage.output,
10677
+ cacheCreate: total.cacheCreate + session.tokenUsage.cacheCreate,
10678
+ cacheRead: total.cacheRead + session.tokenUsage.cacheRead,
10679
+ total: total.total + session.tokenUsage.total
10680
+ };
10681
+ }
10682
+ function memberEffectiveStatus(member) {
10683
+ if (member.member.status !== null) return member.member.status;
10684
+ if (member.run !== null) return member.run.status;
10685
+ return member.session?.status ?? "unknown";
10686
+ }
10687
+ function isCompletedMember(member) {
10688
+ const status = memberEffectiveStatus(member);
10689
+ return status === "completed";
10690
+ }
10691
+ function isFailedMember(member) {
10692
+ const status = memberEffectiveStatus(member);
10693
+ return status === "failed" || status === "cancelled";
10694
+ }
10695
+ function isRunningMember(member) {
10696
+ const status = memberEffectiveStatus(member);
10697
+ return status === "running" || status === "active";
10698
+ }
10699
+ function latestLogMetric(session, field) {
10700
+ if (session === null) return null;
10701
+ for (const log of session.latestLogs) {
10702
+ const value = log[field];
10703
+ if (value !== void 0 && value !== null) return value;
10704
+ }
10705
+ return null;
10706
+ }
10707
+ function buildSummary(members) {
10708
+ const tokenUsage = members.reduce(
10709
+ (total, member) => addTokenUsage(total, member.session),
10710
+ { input: 0, output: 0, cacheCreate: 0, cacheRead: 0, total: 0 }
10711
+ );
10712
+ const sessionsWithData = members.filter((member) => member.session !== null).length;
10713
+ const requestCount = members.reduce(
10714
+ (total, member) => total + (member.session?.requestCount ?? 0),
10715
+ 0
10716
+ );
10717
+ const errorCount = members.reduce(
10718
+ (total, member) => total + (member.session?.errorCount ?? 0),
10719
+ 0
10720
+ );
10721
+ return {
10722
+ memberCount: members.length,
10723
+ sessionsWithData,
10724
+ missingSessions: members.length - sessionsWithData,
10725
+ requestCount,
10726
+ errorCount,
10727
+ tokenUsage,
10728
+ models: collectSortedValues(
10729
+ members.flatMap((member) => [member.member.model, ...member.session?.models ?? []])
10730
+ ),
10731
+ providers: collectSortedValues(
10732
+ members.flatMap((member) => [member.member.provider, ...member.session?.providers ?? []])
10733
+ ),
10734
+ completedMembers: members.filter(isCompletedMember).length,
10735
+ failedMembers: members.filter(isFailedMember).length,
10736
+ runningMembers: members.filter(isRunningMember).length
10737
+ };
10738
+ }
10739
+ function buildJenkinsReport(group, summary) {
10740
+ if (summary.failedMembers > 0 || summary.errorCount > 0 || group.status === "failed") {
10741
+ return {
10742
+ status: "FAIL",
10743
+ summary: `[FAIL] ${summary.failedMembers} failed members, ${summary.errorCount} captured errors.`,
10744
+ markdown: `# Jenkins Report: ${group.title}
10745
+
10746
+ Status: FAIL
10747
+
10748
+ ${summary.failedMembers} failed members and ${summary.errorCount} captured errors need triage.`
10749
+ };
10750
+ }
10751
+ if (summary.runningMembers > 0 || group.status === "running") {
10752
+ return {
10753
+ status: "RUNNING",
10754
+ summary: `[RUNNING] ${summary.runningMembers} group members are still active.`,
10755
+ markdown: `# Jenkins Report: ${group.title}
10756
+
10757
+ Status: RUNNING
10758
+
10759
+ ${summary.runningMembers} group members are still active.`
10760
+ };
10761
+ }
10762
+ if (summary.memberCount > 0 && summary.sessionsWithData > 0 && summary.errorCount === 0 && group.status === "completed") {
10763
+ return {
10764
+ status: "PASS",
10765
+ summary: `[PASS] ${summary.memberCount} group members completed with no captured errors.`,
10766
+ markdown: `# Jenkins Report: ${group.title}
10767
+
10768
+ Status: PASS
10769
+
10770
+ ${summary.memberCount} group members completed with no captured errors.`
10771
+ };
10772
+ }
10773
+ return {
10774
+ status: "UNKNOWN",
10775
+ summary: `[UNKNOWN] Group has ${summary.memberCount} members and ${summary.missingSessions} missing sessions.`,
10776
+ markdown: `# Jenkins Report: ${group.title}
10777
+
10778
+ Status: UNKNOWN
10779
+
10780
+ Exported group evidence, but the outcome is not conclusive yet.`
10781
+ };
10782
+ }
10783
+ function buildMemberRows(members) {
10784
+ if (members.length === 0) return ["No sessions have been attached to this group.", ""];
10785
+ const rows = [
10786
+ "| Label | Provider | Model | Session | Run | Status | Requests | Errors | Tokens | First Chunk | Stream Total | TPS | Inspector |",
10787
+ "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |"
10788
+ ];
10789
+ for (const member of members) {
10790
+ const session = member.session;
10791
+ rows.push(
10792
+ [
10793
+ formatText(member.member.label),
10794
+ formatText(member.member.provider ?? session?.providers[0]),
10795
+ formatText(member.member.model ?? session?.lastModel),
10796
+ member.member.sessionId,
10797
+ formatText(member.member.runId),
10798
+ memberEffectiveStatus(member),
10799
+ formatNumber(session?.requestCount),
10800
+ formatNumber(session?.errorCount),
10801
+ formatNumber(session?.tokenUsage.total),
10802
+ formatNumber(latestLogMetric(session, "firstChunkMs")),
10803
+ formatNumber(latestLogMetric(session, "totalStreamMs")),
10804
+ formatNumber(latestLogMetric(session, "tokensPerSecond")),
10805
+ formatText(session?.inspectorUrl)
10806
+ ].map(escapeMarkdownCell).join(" | ").replace(/^/, "| ").replace(/$/, " |")
10807
+ );
10808
+ }
10809
+ rows.push("");
10810
+ return rows;
10811
+ }
10812
+ function buildMarkdown(document) {
10813
+ const group = document.group;
10814
+ const summary = document.summary;
10815
+ const lines = [
10816
+ `# ${group.title}`,
10817
+ "",
10818
+ `- Group ID: ${group.id}`,
10819
+ `- Kind: ${group.kind}`,
10820
+ `- Status: ${group.status}`,
10821
+ `- Project: ${group.project ?? "n/a"}`,
10822
+ `- Created: ${group.createdAt}`,
10823
+ `- Members: ${summary.memberCount}`,
10824
+ `- Sessions With Data: ${summary.sessionsWithData}`,
10825
+ `- Missing Sessions: ${summary.missingSessions}`,
10826
+ `- Requests: ${summary.requestCount}`,
10827
+ `- Errors: ${summary.errorCount}`,
10828
+ `- Tokens: ${summary.tokenUsage.total}`,
10829
+ `- Models: ${summary.models.length > 0 ? summary.models.join(", ") : "n/a"}`,
10830
+ `- Providers: ${summary.providers.length > 0 ? summary.providers.join(", ") : "n/a"}`,
10831
+ `- Evidence JSON: ${document.evidence.jsonPath}`,
10832
+ `- Evidence HTML: ${document.evidence.htmlPath}`,
10833
+ ""
10834
+ ];
10835
+ if (group.task !== null) {
10836
+ lines.push("## Task", "", group.task, "");
10837
+ }
10838
+ lines.push("## Evaluation Matrix", "", ...buildMemberRows(document.members));
10839
+ lines.push("## Jenkins Report", "", document.jenkinsReport.markdown, "");
10840
+ return `${lines.join("\n")}
10841
+ `;
10842
+ }
10843
+ function buildHtml(markdown, title) {
10844
+ return `<!doctype html>
10845
+ <html lang="en">
10846
+ <head>
10847
+ <meta charset="utf-8">
10848
+ <title>${escapeHtml(title)}</title>
10849
+ <style>
10850
+ body { font-family: system-ui, sans-serif; max-width: 1120px; margin: 40px auto; line-height: 1.5; }
10851
+ pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
10852
+ </style>
10853
+ </head>
10854
+ <body>
10855
+ <pre>${escapeHtml(markdown)}</pre>
10856
+ </body>
10857
+ </html>
10858
+ `;
10859
+ }
10860
+ async function buildExportMembers(group, options, baseUrl) {
10861
+ const members = [];
10862
+ for (const member of group.members) {
10863
+ const run = member.runId === null ? null : getRun(member.runId);
10864
+ const session = await getSessionInfo(member.sessionId, {
10865
+ baseUrl,
10866
+ includeHistory: options?.includeHistory,
10867
+ latestLogLimit: options?.latestLogLimit
10868
+ });
10869
+ members.push({ member, run, session });
10870
+ }
10871
+ return members;
10872
+ }
10873
+ async function exportGroupEvidence(group, options, baseUrl) {
10874
+ const members = await buildExportMembers(group, options, baseUrl);
10875
+ const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
10876
+ const evidence = {
10877
+ jsonPath: jsonPath(group.id),
10878
+ markdownPath: markdownPath(group.id),
10879
+ htmlPath: htmlPath(group.id),
10880
+ exportedAt
10881
+ };
10882
+ const documentGroup = {
10883
+ ...group,
10884
+ evidence,
10885
+ updatedAt: exportedAt
10886
+ };
10887
+ const summary = buildSummary(members);
10888
+ const jenkinsReport = buildJenkinsReport(documentGroup, summary);
10889
+ const document = {
10890
+ group: documentGroup,
10891
+ evidence,
10892
+ members,
10893
+ summary,
10894
+ jenkinsReport
10895
+ };
10896
+ const markdown = buildMarkdown(document);
10897
+ mkdirSync(groupEvidenceDir(group.id), { recursive: true });
10898
+ writeFileSync(evidence.jsonPath, `${JSON.stringify(document, null, 2)}
10899
+ `, "utf8");
10900
+ writeFileSync(evidence.markdownPath, markdown, "utf8");
10901
+ writeFileSync(evidence.htmlPath, buildHtml(markdown, group.title), "utf8");
10902
+ const updatedGroup = updateGroupEvidence(group.id, evidence) ?? documentGroup;
10903
+ return { ...document, group: updatedGroup };
10904
+ }
10905
+ function readGroupEvidenceMarkdown(group) {
10906
+ const path2 = group.evidence?.markdownPath;
10907
+ if (path2 === void 0 || !existsSync(path2)) return null;
10908
+ try {
10909
+ return readFileSync(path2, "utf8");
10910
+ } catch {
10911
+ return null;
10912
+ }
10913
+ }
10914
+ function readGroupEvidenceDocument(group) {
10915
+ const path2 = group.evidence?.jsonPath;
10916
+ if (path2 === void 0 || !existsSync(path2)) return null;
10917
+ try {
10918
+ const raw = JSON.parse(readFileSync(path2, "utf8"));
10919
+ const parsed = GroupEvidenceExportResultSchema.safeParse(raw);
10920
+ return parsed.success ? parsed.data : null;
10921
+ } catch {
10922
+ return null;
10923
+ }
10924
+ }
10925
+ async function readJsonBody(request) {
10926
+ try {
10927
+ const raw = await request.text();
10928
+ if (raw.trim().length === 0) return { ok: true, value: void 0 };
10929
+ return { ok: true, value: JSON.parse(raw) };
10930
+ } catch {
10931
+ return { ok: false };
10932
+ }
10933
+ }
10934
+ const Route$3 = createFileRoute("/api/groups/$groupId/evidence")({
10935
+ server: {
10936
+ handlers: {
10937
+ GET: ({ params }) => {
10938
+ const group = getGroup(params.groupId);
10939
+ if (group === null) {
10940
+ return Response.json({ error: "Group not found" }, { status: 404 });
10941
+ }
10942
+ const markdown = readGroupEvidenceMarkdown(group);
10943
+ if (group.evidence === null || markdown === null) {
10944
+ return Response.json(
10945
+ { error: "Evidence has not been exported for this group" },
10946
+ { status: 404 }
10947
+ );
10948
+ }
10949
+ const document = readGroupEvidenceDocument(group);
10950
+ return Response.json({
10951
+ group,
10952
+ evidence: group.evidence,
10953
+ markdown,
10954
+ summary: document?.summary ?? null,
10955
+ report: document?.jenkinsReport ?? null
10956
+ });
10957
+ },
10958
+ POST: async ({ params, request }) => {
10959
+ const group = getGroup(params.groupId);
10960
+ if (group === null) {
10961
+ return Response.json({ error: "Group not found" }, { status: 404 });
10962
+ }
10963
+ const body = await readJsonBody(request);
10964
+ if (!body.ok) {
10965
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
10966
+ }
10967
+ const parsed = GroupEvidenceExportOptionsSchema.safeParse(body.value);
10968
+ if (!parsed.success) {
10969
+ return Response.json(
10970
+ { error: "Invalid request body", details: parsed.error.format() },
10971
+ { status: 400 }
10972
+ );
10973
+ }
10974
+ return Response.json(
10975
+ await exportGroupEvidence(group, parsed.data, new URL(request.url).origin)
10976
+ );
10977
+ }
10978
+ }
10979
+ }
10980
+ });
9924
10981
  const ProviderTestErrorTypeSchema = _enum([
9925
10982
  "timeout",
9926
10983
  "network_unreachable",
@@ -10344,146 +11401,166 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
10344
11401
  }
10345
11402
  }
10346
11403
  });
10347
- const IndexRoute = Route$u.update({
11404
+ const IndexRoute = Route$y.update({
10348
11405
  id: "/",
10349
11406
  path: "/",
10350
- getParentRoute: () => Route$v
11407
+ getParentRoute: () => Route$z
10351
11408
  });
10352
- const SessionSessionIdRoute = Route$t.update({
11409
+ const SessionSessionIdRoute = Route$x.update({
10353
11410
  id: "/session/$sessionId",
10354
11411
  path: "/session/$sessionId",
10355
- getParentRoute: () => Route$v
11412
+ getParentRoute: () => Route$z
10356
11413
  });
10357
- const ProxySplatRoute = Route$s.update({
11414
+ const ProxySplatRoute = Route$w.update({
10358
11415
  id: "/proxy/$",
10359
11416
  path: "/proxy/$",
10360
- getParentRoute: () => Route$v
11417
+ getParentRoute: () => Route$z
10361
11418
  });
10362
- const ApiSessionsRoute = Route$r.update({
11419
+ const ApiSessionsRoute = Route$v.update({
10363
11420
  id: "/api/sessions",
10364
11421
  path: "/api/sessions",
10365
- getParentRoute: () => Route$v
11422
+ getParentRoute: () => Route$z
10366
11423
  });
10367
- const ApiRunsRoute = Route$q.update({
11424
+ const ApiRunsRoute = Route$u.update({
10368
11425
  id: "/api/runs",
10369
11426
  path: "/api/runs",
10370
- getParentRoute: () => Route$v
11427
+ getParentRoute: () => Route$z
10371
11428
  });
10372
- const ApiProvidersRoute = Route$p.update({
11429
+ const ApiProvidersRoute = Route$t.update({
10373
11430
  id: "/api/providers",
10374
11431
  path: "/api/providers",
10375
- getParentRoute: () => Route$v
11432
+ getParentRoute: () => Route$z
10376
11433
  });
10377
- const ApiModelsRoute = Route$o.update({
11434
+ const ApiModelsRoute = Route$s.update({
10378
11435
  id: "/api/models",
10379
11436
  path: "/api/models",
10380
- getParentRoute: () => Route$v
11437
+ getParentRoute: () => Route$z
10381
11438
  });
10382
- const ApiMcpRoute = Route$n.update({
11439
+ const ApiMcpRoute = Route$r.update({
10383
11440
  id: "/api/mcp",
10384
11441
  path: "/api/mcp",
10385
- getParentRoute: () => Route$v
11442
+ getParentRoute: () => Route$z
10386
11443
  });
10387
- const ApiLogsRoute = Route$m.update({
11444
+ const ApiLogsRoute = Route$q.update({
10388
11445
  id: "/api/logs",
10389
11446
  path: "/api/logs",
10390
- getParentRoute: () => Route$v
11447
+ getParentRoute: () => Route$z
10391
11448
  });
10392
- const ApiHealthRoute = Route$l.update({
11449
+ const ApiHealthRoute = Route$p.update({
10393
11450
  id: "/api/health",
10394
11451
  path: "/api/health",
10395
- getParentRoute: () => Route$v
11452
+ getParentRoute: () => Route$z
11453
+ });
11454
+ const ApiGroupsRoute = Route$o.update({
11455
+ id: "/api/groups",
11456
+ path: "/api/groups",
11457
+ getParentRoute: () => Route$z
10396
11458
  });
10397
- const ApiConfigRoute = Route$k.update({
11459
+ const ApiConfigRoute = Route$n.update({
10398
11460
  id: "/api/config",
10399
11461
  path: "/api/config",
10400
- getParentRoute: () => Route$v
11462
+ getParentRoute: () => Route$z
10401
11463
  });
10402
- const ApiRunsRunIdRoute = Route$j.update({
11464
+ const ApiRunsRunIdRoute = Route$m.update({
10403
11465
  id: "/$runId",
10404
11466
  path: "/$runId",
10405
11467
  getParentRoute: () => ApiRunsRoute
10406
11468
  });
10407
- const ApiProvidersScanRoute = Route$i.update({
11469
+ const ApiProvidersScanRoute = Route$l.update({
10408
11470
  id: "/scan",
10409
11471
  path: "/scan",
10410
11472
  getParentRoute: () => ApiProvidersRoute
10411
11473
  });
10412
- const ApiProvidersImportRoute = Route$h.update({
11474
+ const ApiProvidersImportRoute = Route$k.update({
10413
11475
  id: "/import",
10414
11476
  path: "/import",
10415
11477
  getParentRoute: () => ApiProvidersRoute
10416
11478
  });
10417
- const ApiProvidersExportRoute = Route$g.update({
11479
+ const ApiProvidersExportRoute = Route$j.update({
10418
11480
  id: "/export",
10419
11481
  path: "/export",
10420
11482
  getParentRoute: () => ApiProvidersRoute
10421
11483
  });
10422
- const ApiProvidersProviderIdRoute = Route$f.update({
11484
+ const ApiProvidersProviderIdRoute = Route$i.update({
10423
11485
  id: "/$providerId",
10424
11486
  path: "/$providerId",
10425
11487
  getParentRoute: () => ApiProvidersRoute
10426
11488
  });
10427
- const ApiLogsStreamRoute = Route$e.update({
11489
+ const ApiLogsStreamRoute = Route$h.update({
10428
11490
  id: "/stream",
10429
11491
  path: "/stream",
10430
11492
  getParentRoute: () => ApiLogsRoute
10431
11493
  });
10432
- const ApiLogsIdRoute = Route$d.update({
11494
+ const ApiLogsIdRoute = Route$g.update({
10433
11495
  id: "/$id",
10434
11496
  path: "/$id",
10435
11497
  getParentRoute: () => ApiLogsRoute
10436
11498
  });
10437
- const ApiKnowledgeSearchRoute = Route$c.update({
11499
+ const ApiKnowledgeSearchRoute = Route$f.update({
10438
11500
  id: "/api/knowledge/search",
10439
11501
  path: "/api/knowledge/search",
10440
- getParentRoute: () => Route$v
11502
+ getParentRoute: () => Route$z
10441
11503
  });
10442
- const ApiKnowledgeProjectContextRoute = Route$b.update({
11504
+ const ApiKnowledgeProjectContextRoute = Route$e.update({
10443
11505
  id: "/api/knowledge/project-context",
10444
11506
  path: "/api/knowledge/project-context",
10445
- getParentRoute: () => Route$v
11507
+ getParentRoute: () => Route$z
10446
11508
  });
10447
- const ApiKnowledgeCandidatesRoute = Route$a.update({
11509
+ const ApiKnowledgeCandidatesRoute = Route$d.update({
10448
11510
  id: "/api/knowledge/candidates",
10449
11511
  path: "/api/knowledge/candidates",
10450
- getParentRoute: () => Route$v
11512
+ getParentRoute: () => Route$z
10451
11513
  });
10452
- const ApiConfigPathsRoute = Route$9.update({
11514
+ const ApiGroupsGroupIdRoute = Route$c.update({
11515
+ id: "/$groupId",
11516
+ path: "/$groupId",
11517
+ getParentRoute: () => ApiGroupsRoute
11518
+ });
11519
+ const ApiConfigPathsRoute = Route$b.update({
10453
11520
  id: "/paths",
10454
11521
  path: "/paths",
10455
11522
  getParentRoute: () => ApiConfigRoute
10456
11523
  });
10457
- const ApiRunsRunIdEvidenceRoute = Route$8.update({
11524
+ const ApiRunsRunIdEvidenceRoute = Route$a.update({
10458
11525
  id: "/evidence",
10459
11526
  path: "/evidence",
10460
11527
  getParentRoute: () => ApiRunsRunIdRoute
10461
11528
  });
10462
- const ApiProvidersProviderIdTestRoute = Route$7.update({
11529
+ const ApiProvidersProviderIdTestRoute = Route$9.update({
10463
11530
  id: "/test",
10464
11531
  path: "/test",
10465
11532
  getParentRoute: () => ApiProvidersProviderIdRoute
10466
11533
  });
10467
- const ApiProvidersProviderIdModelMetadataRoute = Route$6.update({
11534
+ const ApiProvidersProviderIdModelMetadataRoute = Route$8.update({
10468
11535
  id: "/model-metadata",
10469
11536
  path: "/model-metadata",
10470
11537
  getParentRoute: () => ApiProvidersProviderIdRoute
10471
11538
  });
10472
- const ApiLogsIdReplayRoute = Route$5.update({
11539
+ const ApiLogsIdReplayRoute = Route$7.update({
10473
11540
  id: "/replay",
10474
11541
  path: "/replay",
10475
11542
  getParentRoute: () => ApiLogsIdRoute
10476
11543
  });
10477
- const ApiLogsIdChunksRoute = Route$4.update({
11544
+ const ApiLogsIdChunksRoute = Route$6.update({
10478
11545
  id: "/chunks",
10479
11546
  path: "/chunks",
10480
11547
  getParentRoute: () => ApiLogsIdRoute
10481
11548
  });
10482
- const ApiKnowledgeCandidatesCandidateIdRoute = Route$3.update({
11549
+ const ApiKnowledgeCandidatesCandidateIdRoute = Route$5.update({
10483
11550
  id: "/$candidateId",
10484
11551
  path: "/$candidateId",
10485
11552
  getParentRoute: () => ApiKnowledgeCandidatesRoute
10486
11553
  });
11554
+ const ApiGroupsGroupIdSessionsRoute = Route$4.update({
11555
+ id: "/sessions",
11556
+ path: "/sessions",
11557
+ getParentRoute: () => ApiGroupsGroupIdRoute
11558
+ });
11559
+ const ApiGroupsGroupIdEvidenceRoute = Route$3.update({
11560
+ id: "/evidence",
11561
+ path: "/evidence",
11562
+ getParentRoute: () => ApiGroupsGroupIdRoute
11563
+ });
10487
11564
  const ApiProvidersProviderIdTestLogRoute = Route$2.update({
10488
11565
  id: "/log",
10489
11566
  path: "/log",
@@ -10492,7 +11569,7 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
10492
11569
  const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
10493
11570
  id: "/api/knowledge/sessions/$sessionId/candidates",
10494
11571
  path: "/api/knowledge/sessions/$sessionId/candidates",
10495
- getParentRoute: () => Route$v
11572
+ getParentRoute: () => Route$z
10496
11573
  });
10497
11574
  const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
10498
11575
  id: "/promote",
@@ -10505,6 +11582,17 @@ const ApiConfigRouteChildren = {
10505
11582
  const ApiConfigRouteWithChildren = ApiConfigRoute._addFileChildren(
10506
11583
  ApiConfigRouteChildren
10507
11584
  );
11585
+ const ApiGroupsGroupIdRouteChildren = {
11586
+ ApiGroupsGroupIdEvidenceRoute,
11587
+ ApiGroupsGroupIdSessionsRoute
11588
+ };
11589
+ const ApiGroupsGroupIdRouteWithChildren = ApiGroupsGroupIdRoute._addFileChildren(ApiGroupsGroupIdRouteChildren);
11590
+ const ApiGroupsRouteChildren = {
11591
+ ApiGroupsGroupIdRoute: ApiGroupsGroupIdRouteWithChildren
11592
+ };
11593
+ const ApiGroupsRouteWithChildren = ApiGroupsRoute._addFileChildren(
11594
+ ApiGroupsRouteChildren
11595
+ );
10508
11596
  const ApiLogsIdRouteChildren = {
10509
11597
  ApiLogsIdChunksRoute,
10510
11598
  ApiLogsIdReplayRoute
@@ -10564,6 +11652,7 @@ const ApiKnowledgeCandidatesRouteWithChildren = ApiKnowledgeCandidatesRoute._add
10564
11652
  const rootRouteChildren = {
10565
11653
  IndexRoute,
10566
11654
  ApiConfigRoute: ApiConfigRouteWithChildren,
11655
+ ApiGroupsRoute: ApiGroupsRouteWithChildren,
10567
11656
  ApiHealthRoute,
10568
11657
  ApiLogsRoute: ApiLogsRouteWithChildren,
10569
11658
  ApiMcpRoute,
@@ -10578,7 +11667,7 @@ const rootRouteChildren = {
10578
11667
  ApiKnowledgeSearchRoute,
10579
11668
  ApiKnowledgeSessionsSessionIdCandidatesRoute
10580
11669
  };
10581
- const routeTree = Route$v._addFileChildren(rootRouteChildren)._addFileTypes();
11670
+ const routeTree = Route$z._addFileChildren(rootRouteChildren)._addFileTypes();
10582
11671
  function getRouter() {
10583
11672
  const router2 = createRouter({
10584
11673
  routeTree,
@@ -10594,11 +11683,13 @@ export {
10594
11683
  AnthropicResponseSchema$1 as A,
10595
11684
  CapturedLogSchema as C,
10596
11685
  DEFAULT_CAPTURE_MODE as D,
11686
+ GroupEvidenceReadResponseSchema$1 as G,
11687
+ InspectorGroupsListResponseSchema as I,
10597
11688
  KnowledgeCandidateSchema as K,
10598
11689
  MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
10599
11690
  OpenAIRequestSchema as O,
10600
11691
  ProviderConfigSchema as P,
10601
- Route$t as R,
11692
+ Route$x as R,
10602
11693
  TimeDisplayFormatSchema as T,
10603
11694
  DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
10604
11695
  DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
@@ -10607,17 +11698,19 @@ export {
10607
11698
  AnthropicRequestSchema as e,
10608
11699
  stripClaudeCodeBillingHeader as f,
10609
11700
  getSessionPath as g,
10610
- providerHasContextMetadata as h,
10611
- findProviderModelMetadata as i,
10612
- createPendingProviderTestResults as j,
10613
- ProviderTestResultsSchema as k,
10614
- createFailedProviderTestResults as l,
11701
+ GroupEvidenceExportResultSchema as h,
11702
+ providerHasContextMetadata as i,
11703
+ findProviderModelMetadata as j,
11704
+ createPendingProviderTestResults as k,
11705
+ ProviderTestResultsSchema as l,
10615
11706
  maskApiKey as m,
10616
- MAX_PROVIDER_TEST_TIMEOUT_SECONDS as n,
10617
- resolveProviderContextWindow as o,
11707
+ createFailedProviderTestResults as n,
11708
+ MAX_PROVIDER_TEST_TIMEOUT_SECONDS as o,
10618
11709
  parseOpenAIResponse as p,
10619
- isPlainRecord as q,
11710
+ resolveProviderContextWindow as q,
10620
11711
  requestFormatForPath as r,
10621
11712
  safeGetOwnProperty as s,
10622
- router as t
11713
+ isPlainRecord as t,
11714
+ packageJson as u,
11715
+ router as v
10623
11716
  };