@gleanwork/mcp-server-tester 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,6 +29,216 @@ function sumUsage(a, b) {
29
29
  )
30
30
  };
31
31
  }
32
+ var KIND_DIRS = {
33
+ "eval-runner-result": "eval-runs",
34
+ "reporter-run": "reporter-runs",
35
+ "eval-run-comparison": "comparisons/eval-runs",
36
+ "server-comparison": "comparisons/servers"
37
+ };
38
+ function createEvalResultStore(config) {
39
+ if (config.provider === "file") {
40
+ return new FileEvalResultStore(config);
41
+ }
42
+ return new GCSEvalResultStore(config);
43
+ }
44
+ function resolveEvalResultStore(store) {
45
+ return isEvalResultStore(store) ? store : createEvalResultStore(store);
46
+ }
47
+ function isEvalResultStore(value) {
48
+ return typeof value === "object" && value !== null && "saveArtifact" in value && "loadArtifact" in value && "loadLatestArtifact" in value && "listArtifacts" in value;
49
+ }
50
+ function createStoredEvalArtifact(options) {
51
+ const createdAt = options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
52
+ return {
53
+ schemaVersion: 1,
54
+ kind: options.kind,
55
+ id: options.id ?? createDefaultArtifactId(createdAt),
56
+ createdAt,
57
+ metadata: {
58
+ ...defaultEnvironmentMetadata(),
59
+ ...options.metadata ?? {}
60
+ },
61
+ data: options.data
62
+ };
63
+ }
64
+ function createDefaultArtifactId(timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
65
+ const safeTimestamp = timestamp.replace(/[:.]/g, "-");
66
+ const runNumber = process.env.GITHUB_RUN_NUMBER;
67
+ const sha = process.env.GITHUB_SHA?.slice(0, 12);
68
+ const suffix = runNumber ?? sha;
69
+ return suffix ? `${safeTimestamp}-${suffix}` : safeTimestamp;
70
+ }
71
+ function defaultEnvironmentMetadata() {
72
+ return {
73
+ ...process.env.GITHUB_SHA !== void 0 && {
74
+ gitHash: process.env.GITHUB_SHA
75
+ },
76
+ ...process.env.GITHUB_REF_NAME !== void 0 && {
77
+ branch: process.env.GITHUB_REF_NAME
78
+ },
79
+ ...process.env.GITHUB_RUN_NUMBER !== void 0 && {
80
+ runNumber: process.env.GITHUB_RUN_NUMBER
81
+ },
82
+ ...process.env.GITHUB_EVENT_NAME !== void 0 && {
83
+ trigger: process.env.GITHUB_EVENT_NAME
84
+ }
85
+ };
86
+ }
87
+ var FileEvalResultStore = class {
88
+ dir;
89
+ constructor(config) {
90
+ this.dir = config.dir;
91
+ }
92
+ async saveArtifact(artifact) {
93
+ const artifactDir = join(this.dir, KIND_DIRS[artifact.kind]);
94
+ await mkdir(artifactDir, { recursive: true });
95
+ const serialized = JSON.stringify(artifact, null, 2);
96
+ await writeFile(
97
+ join(artifactDir, `${artifact.id}.json`),
98
+ serialized,
99
+ "utf8"
100
+ );
101
+ await writeFile(join(artifactDir, "latest.json"), serialized, "utf8");
102
+ }
103
+ async loadArtifact(kind, id) {
104
+ const raw = await readFile(
105
+ join(this.dir, KIND_DIRS[kind], `${id}.json`),
106
+ "utf8"
107
+ );
108
+ return JSON.parse(raw);
109
+ }
110
+ async loadLatestArtifact(kind) {
111
+ try {
112
+ const raw = await readFile(
113
+ join(this.dir, KIND_DIRS[kind], "latest.json"),
114
+ "utf8"
115
+ );
116
+ return JSON.parse(raw);
117
+ } catch (error) {
118
+ if (isMissingFileError(error)) {
119
+ return null;
120
+ }
121
+ throw error;
122
+ }
123
+ }
124
+ async listArtifacts(kind, options = {}) {
125
+ let files;
126
+ try {
127
+ files = await readdir(join(this.dir, KIND_DIRS[kind]));
128
+ } catch (error) {
129
+ if (isMissingFileError(error)) {
130
+ return [];
131
+ }
132
+ throw error;
133
+ }
134
+ const summaries = await Promise.all(
135
+ files.filter((f) => f.endsWith(".json") && f !== "latest.json").map(async (file) => {
136
+ const raw = await readFile(
137
+ join(this.dir, KIND_DIRS[kind], file),
138
+ "utf8"
139
+ );
140
+ return toSummary(JSON.parse(raw));
141
+ })
142
+ );
143
+ return summaries.sort((a, b) => b.createdAt.localeCompare(a.createdAt)).slice(0, options.limit);
144
+ }
145
+ };
146
+ var GCSEvalResultStore = class {
147
+ bucketName;
148
+ prefix;
149
+ storage;
150
+ constructor(config) {
151
+ this.bucketName = config.bucket;
152
+ this.prefix = trimSlashes(config.prefix ?? "");
153
+ }
154
+ async saveArtifact(artifact) {
155
+ const bucket = await this.getBucket();
156
+ const serialized = JSON.stringify(artifact, null, 2);
157
+ await bucket.file(
158
+ this.objectPath(
159
+ artifact.kind,
160
+ `${encodeURIComponent(artifact.id)}.json`
161
+ )
162
+ ).save(serialized, {
163
+ contentType: "application/json",
164
+ resumable: false,
165
+ validation: false
166
+ });
167
+ await bucket.file(this.objectPath(artifact.kind, "latest.json")).save(serialized, {
168
+ contentType: "application/json",
169
+ resumable: false,
170
+ validation: false
171
+ });
172
+ }
173
+ async loadArtifact(kind, id) {
174
+ const bucket = await this.getBucket();
175
+ const file = bucket.file(
176
+ this.objectPath(kind, `${encodeURIComponent(id)}.json`)
177
+ );
178
+ const [buffer] = await file.download();
179
+ return JSON.parse(buffer.toString("utf8"));
180
+ }
181
+ async loadLatestArtifact(kind) {
182
+ const bucket = await this.getBucket();
183
+ const file = bucket.file(this.objectPath(kind, "latest.json"));
184
+ const [exists] = await file.exists();
185
+ if (!exists) return null;
186
+ const [buffer] = await file.download();
187
+ return JSON.parse(buffer.toString("utf8"));
188
+ }
189
+ async listArtifacts(kind, options = {}) {
190
+ const bucket = await this.getBucket();
191
+ const [files] = await bucket.getFiles({
192
+ prefix: this.objectPath(kind, "")
193
+ });
194
+ const summaries = await Promise.all(
195
+ files.filter(
196
+ (f) => f.name.endsWith(".json") && !f.name.endsWith("/latest.json")
197
+ ).map(async (file) => {
198
+ const [buffer] = await file.download();
199
+ return toSummary(
200
+ JSON.parse(buffer.toString("utf8"))
201
+ );
202
+ })
203
+ );
204
+ return summaries.sort((a, b) => b.createdAt.localeCompare(a.createdAt)).slice(0, options.limit);
205
+ }
206
+ async getBucket() {
207
+ if (!this.storage) {
208
+ const moduleName = "@google-cloud/storage";
209
+ let Storage;
210
+ try {
211
+ const mod = await import(moduleName);
212
+ Storage = mod.Storage;
213
+ } catch (error) {
214
+ throw new Error(
215
+ `GCS result storage requires the optional \`@google-cloud/storage\` package. Install it and authenticate with Application Default Credentials via GOOGLE_APPLICATION_CREDENTIALS.
216
+ Original error: ${error instanceof Error ? error.message : String(error)}`
217
+ );
218
+ }
219
+ this.storage = new Storage();
220
+ }
221
+ return this.storage.bucket(this.bucketName);
222
+ }
223
+ objectPath(kind, filename) {
224
+ const parts = [this.prefix, KIND_DIRS[kind], filename].filter(Boolean);
225
+ return parts.join("/");
226
+ }
227
+ };
228
+ function toSummary(artifact) {
229
+ return {
230
+ kind: artifact.kind,
231
+ id: artifact.id,
232
+ createdAt: artifact.createdAt,
233
+ metadata: artifact.metadata
234
+ };
235
+ }
236
+ function trimSlashes(value) {
237
+ return value.replace(/^\/+|\/+$/g, "");
238
+ }
239
+ function isMissingFileError(error) {
240
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
241
+ }
32
242
 
33
243
  // src/reporters/mcpReporter.ts
34
244
  var MCPReporter = class {
@@ -43,7 +253,18 @@ var MCPReporter = class {
43
253
  autoOpen: options.autoOpen ?? false,
44
254
  historyLimit: options.historyLimit ?? 10,
45
255
  quiet: options.quiet ?? false,
46
- includeAutoTracking: options.includeAutoTracking ?? true
256
+ includeAutoTracking: options.includeAutoTracking ?? true,
257
+ resultStore: options.resultStore,
258
+ runId: options.runId,
259
+ runMetadata: options.runMetadata,
260
+ // Default true to match the eval-runner store path. Stored artifacts
261
+ // omit response bodies by default; opt in by passing
262
+ // `redactStoredResponses: false` if you need full responses for
263
+ // debugging or history comparison. Keeping this consistent across
264
+ // both write paths prevents users from getting a mix of
265
+ // redacted/non-redacted artifacts depending on which code path wrote
266
+ // them.
267
+ redactStoredResponses: options.redactStoredResponses ?? true
47
268
  };
48
269
  }
49
270
  log(message) {
@@ -199,6 +420,7 @@ var MCPReporter = class {
199
420
  });
200
421
  await this.saveRunData(runData);
201
422
  await this.cleanupOldRuns();
423
+ await this.saveRunDataToStore(runData);
202
424
  const reportDir = join(this.config.outputDir, "latest");
203
425
  await this.generateReport(runData, historical, reportDir);
204
426
  const reportPath = join(reportDir, "index.html");
@@ -286,6 +508,10 @@ var MCPReporter = class {
286
508
  };
287
509
  }
288
510
  async loadHistoricalData() {
511
+ const storeHistorical = await this.loadHistoricalDataFromStore();
512
+ if (storeHistorical) {
513
+ return storeHistorical;
514
+ }
289
515
  try {
290
516
  const files = await readdir(this.config.outputDir);
291
517
  const runFiles = files.filter((f) => f.startsWith("run-") && f.endsWith(".json")).sort().slice(-(this.config.historyLimit - 1));
@@ -319,6 +545,55 @@ var MCPReporter = class {
319
545
  const filepath = join(this.config.outputDir, filename);
320
546
  await writeFile(filepath, JSON.stringify(runData, null, 2), "utf-8");
321
547
  }
548
+ async saveRunDataToStore(runData) {
549
+ if (!this.config.resultStore) {
550
+ return;
551
+ }
552
+ try {
553
+ const store = resolveEvalResultStore(this.config.resultStore);
554
+ await store.saveArtifact(
555
+ createStoredEvalArtifact({
556
+ kind: "reporter-run",
557
+ id: this.config.runId,
558
+ data: this.config.redactStoredResponses ? redactResponses(runData) : runData,
559
+ metadata: {
560
+ ...this.config.runMetadata ?? {}
561
+ }
562
+ })
563
+ );
564
+ } catch (error) {
565
+ this.logError(
566
+ "[MCP Reporter] Failed to save run to result store:",
567
+ error
568
+ );
569
+ }
570
+ }
571
+ async loadHistoricalDataFromStore() {
572
+ if (!this.config.resultStore) {
573
+ return null;
574
+ }
575
+ try {
576
+ const store = resolveEvalResultStore(this.config.resultStore);
577
+ const summaries = await store.listArtifacts("reporter-run", {
578
+ limit: this.config.historyLimit - 1
579
+ });
580
+ const historical = [];
581
+ for (const summary of summaries.reverse()) {
582
+ const artifact = await store.loadArtifact(
583
+ "reporter-run",
584
+ summary.id
585
+ );
586
+ historical.push(toHistoricalSummary(artifact.data));
587
+ }
588
+ return historical;
589
+ } catch (error) {
590
+ this.logError(
591
+ "[MCP Reporter] Failed to load history from result store:",
592
+ error
593
+ );
594
+ return null;
595
+ }
596
+ }
322
597
  async cleanupOldRuns() {
323
598
  try {
324
599
  const files = await readdir(this.config.outputDir);
@@ -343,6 +618,24 @@ var MCPReporter = class {
343
618
  }
344
619
  }
345
620
  };
621
+ function toHistoricalSummary(runData) {
622
+ return {
623
+ timestamp: runData.timestamp,
624
+ total: runData.metrics.total,
625
+ passed: runData.metrics.passed,
626
+ failed: runData.metrics.failed,
627
+ passRate: runData.metrics.passRate,
628
+ durationMs: runData.durationMs
629
+ };
630
+ }
631
+ function redactResponses(value) {
632
+ return JSON.parse(
633
+ JSON.stringify(
634
+ value,
635
+ (key, currentValue) => key === "response" ? void 0 : currentValue
636
+ )
637
+ );
638
+ }
346
639
 
347
640
  export { MCPReporter as default };
348
641
  //# sourceMappingURL=mcpReporter.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/usageUtils.ts","../../src/reporters/mcpReporter.ts"],"names":["__filename","__dirname"],"mappings":"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","file":"mcpReporter.js","sourcesContent":["import type { UsageMetrics } from '../types/index.js';\n\nfunction optionalSum(a?: number, b?: number): number | undefined {\n if (a === undefined && b === undefined) return undefined;\n return (a ?? 0) + (b ?? 0);\n}\n\nexport function sumUsage(\n a: UsageMetrics | undefined,\n b: UsageMetrics | undefined\n): UsageMetrics | undefined {\n if (!a && !b) return undefined;\n if (!a) return b ? { ...b } : undefined;\n if (!b) return { ...a };\n return {\n inputTokens: a.inputTokens + b.inputTokens,\n outputTokens: a.outputTokens + b.outputTokens,\n totalCostUsd: a.totalCostUsd + b.totalCostUsd,\n durationMs: a.durationMs + b.durationMs,\n durationApiMs: optionalSum(a.durationApiMs, b.durationApiMs),\n cacheReadInputTokens: optionalSum(\n a.cacheReadInputTokens,\n b.cacheReadInputTokens\n ),\n cacheCreationInputTokens: optionalSum(\n a.cacheCreationInputTokens,\n b.cacheCreationInputTokens\n ),\n };\n}\n","import type {\n Reporter,\n FullConfig,\n Suite,\n TestCase,\n TestResult,\n FullResult,\n} from '@playwright/test/reporter';\nimport { mkdir, writeFile, readdir, readFile, unlink, cp } from 'fs/promises';\nimport { join, resolve, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport type { MCPEvalReporterConfig } from './types.js';\nimport type { AuthType } from '../types/index.js';\nimport type {\n MCPEvalRunData,\n MCPEvalHistoricalSummary,\n MCPConformanceResultData,\n MCPServerCapabilitiesData,\n EvalCaseResult,\n MCPConformanceCheck,\n} from '../types/reporter.js';\nimport type { UsageMetrics } from '../types/index.js';\nimport { sumUsage } from '../utils/usageUtils.js';\n\n/**\n * Custom Playwright reporter for MCP eval results\n *\n * Generates HTML reports with historical tracking\n *\n * @example\n * ```typescript\n * // playwright.config.ts\n * export default defineConfig({\n * reporter: [\n * ['@gleanwork/mcp-server-tester/reporters/mcpReporter', {\n * outputDir: '.mcp-test-results',\n * historyLimit: 10\n * }]\n * ]\n * });\n * ```\n */\nexport default class MCPReporter implements Reporter {\n private config: Required<MCPEvalReporterConfig>;\n private startTime: number = 0;\n private allResults: Array<EvalCaseResult> = [];\n private conformanceChecks: Array<MCPConformanceResultData> = [];\n private serverCapabilities: Array<MCPServerCapabilitiesData> = [];\n\n constructor(options: MCPEvalReporterConfig = {}) {\n this.config = {\n outputDir: options.outputDir ?? '.mcp-test-results',\n autoOpen: options.autoOpen ?? false,\n historyLimit: options.historyLimit ?? 10,\n quiet: options.quiet ?? false,\n includeAutoTracking: options.includeAutoTracking ?? true,\n };\n }\n\n private log(message: string): void {\n if (!this.config.quiet) {\n console.log(message);\n }\n }\n\n private logError(message: string, error?: unknown): void {\n if (!this.config.quiet) {\n console.error(message, error ?? '');\n }\n }\n\n /**\n * Reads attachment content from either in-memory body (Playwright < 1.43)\n * or from the file path on disk (Playwright ≥ 1.43, which writes large\n * attachments to disk and exposes path instead of body).\n */\n private async getAttachmentContent(attachment: {\n body?: Buffer;\n path?: string;\n }): Promise<string | null> {\n if (attachment.body) return attachment.body.toString('utf-8');\n if (attachment.path) {\n try {\n return await readFile(attachment.path, 'utf-8');\n } catch {\n return null;\n }\n }\n return null;\n }\n\n async onBegin(_config: FullConfig, _suite: Suite): Promise<void> {\n this.startTime = Date.now();\n this.allResults = [];\n this.conformanceChecks = [];\n this.serverCapabilities = [];\n\n // Ensure output directory exists\n await mkdir(this.config.outputDir, { recursive: true });\n }\n\n async onTestEnd(test: TestCase, result: TestResult): Promise<void> {\n // Strategy 1: Extract MCP eval results from runEvalDataset() attachments\n const evalAttachment = result.attachments.find(\n (a) =>\n a.name === 'mcp-test-results' && a.contentType === 'application/json'\n );\n\n let hasEvalDataset = false;\n\n const evalContent = evalAttachment\n ? await this.getAttachmentContent(evalAttachment)\n : null;\n if (evalContent) {\n try {\n const evalResults = JSON.parse(evalContent) as {\n caseResults: Array<EvalCaseResult>;\n };\n\n // Trust the data from the attachment - evalRunner now includes\n // authType and project from the mcp fixture (Playwright is source of truth)\n this.allResults.push(...evalResults.caseResults);\n hasEvalDataset = true;\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse eval results from test \"${test.title}\":`,\n error\n );\n }\n }\n\n // Strategy 2: Extract conformance check results\n // These are created by runConformanceChecks() when testInfo is passed\n const conformanceAttachment = result.attachments.find(\n (a) =>\n a.name === 'mcp-conformance-checks' &&\n a.contentType === 'application/json'\n );\n\n const conformanceContent = conformanceAttachment\n ? await this.getAttachmentContent(conformanceAttachment)\n : null;\n if (conformanceContent) {\n try {\n const conformanceData = JSON.parse(conformanceContent) as {\n operation: string;\n pass: boolean;\n checks: MCPConformanceCheck[];\n serverInfo?: { name?: string; version?: string };\n toolCount: number;\n authType?: AuthType;\n project?: string;\n };\n\n // Only push if checks array is valid\n if (Array.isArray(conformanceData.checks)) {\n this.conformanceChecks.push({\n testTitle: test.title,\n pass: conformanceData.pass,\n checks: conformanceData.checks,\n serverInfo: conformanceData.serverInfo,\n toolCount: conformanceData.toolCount,\n authType: conformanceData.authType,\n project: conformanceData.project,\n });\n }\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse conformance check attachment for \"${test.title}\":`,\n error\n );\n }\n }\n\n // Strategy 2b: Extract server capabilities from mcp-list-tools attachments\n // These are created by createMCPFixture().listTools()\n const listToolsAttachment = result.attachments.find(\n (a) => a.name === 'mcp-list-tools' && a.contentType === 'application/json'\n );\n\n const listToolsContent = listToolsAttachment\n ? await this.getAttachmentContent(listToolsAttachment)\n : null;\n if (listToolsContent) {\n try {\n const listToolsData = JSON.parse(listToolsContent) as {\n operation: string;\n toolCount: number;\n tools: Array<{ name: string; description?: string }>;\n };\n\n // Only push if tools array is valid\n if (Array.isArray(listToolsData.tools)) {\n this.serverCapabilities.push({\n testTitle: test.title,\n tools: listToolsData.tools,\n toolCount: listToolsData.toolCount,\n // Note: authType and project are available from the mcp fixture\n // but not currently included in the listTools attachment\n });\n }\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse mcp-list-tools attachment for \"${test.title}\":`,\n error\n );\n }\n }\n\n // Strategy 3: Extract MCP tool calls from auto-tracking attachments\n // These are created by createMCPFixture()\n // Skip if:\n // - This test already has eval dataset results (to avoid duplicates)\n // - Auto-tracking is disabled in config\n if (hasEvalDataset || !this.config.includeAutoTracking) {\n return;\n }\n\n const mcpCallAttachments = result.attachments.filter(\n (a) =>\n a.name &&\n a.name.startsWith('mcp-call-') &&\n a.contentType === 'application/json'\n );\n\n for (const attachment of mcpCallAttachments) {\n const callContent = await this.getAttachmentContent(attachment);\n if (!callContent) continue;\n\n try {\n // Attachment now includes authType and project from the mcp fixture\n const callData = JSON.parse(callContent) as {\n operation: string;\n toolName: string;\n args: Record<string, unknown>;\n result: unknown;\n durationMs: number;\n isError: boolean;\n authType?: AuthType;\n project?: string;\n };\n\n const suiteName = test.parent?.title || 'Uncategorized Tests';\n const testPassed = result.status === 'passed';\n\n const syntheticResult: EvalCaseResult = {\n id: test.title,\n datasetName: suiteName,\n toolName: callData.toolName,\n source: 'test',\n pass: testPassed,\n response: callData.result,\n error: !testPassed ? 'Test failed' : undefined,\n expectations: {},\n authType: callData.authType,\n project: callData.project,\n durationMs: callData.durationMs,\n };\n\n this.allResults.push(syntheticResult);\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse MCP call attachment \"${attachment.name}\":`,\n error\n );\n }\n }\n }\n\n async onEnd(_result: FullResult): Promise<void> {\n const endTime = Date.now();\n const durationMs = endTime - this.startTime;\n\n // Skip if no eval results collected\n if (this.allResults.length === 0) {\n this.log('[MCP Reporter] No MCP eval results found in test run');\n return;\n }\n\n // Build run data\n const runData = this.buildRunData(durationMs);\n\n // Load historical data\n const historical = await this.loadHistoricalData();\n\n // Add current run to historical\n historical.push({\n timestamp: runData.timestamp,\n total: runData.metrics.total,\n passed: runData.metrics.passed,\n failed: runData.metrics.failed,\n passRate: runData.metrics.passRate,\n durationMs: runData.durationMs,\n });\n\n // Save current run data\n await this.saveRunData(runData);\n\n // Clean up old runs\n await this.cleanupOldRuns();\n\n // Generate report using copy + inject pattern\n const reportDir = join(this.config.outputDir, 'latest');\n await this.generateReport(runData, historical, reportDir);\n\n const reportPath = join(reportDir, 'index.html');\n this.log(`\\n[MCP Reporter] Report generated: ${reportPath}`);\n this.log(\n `[MCP Reporter] Results: ${runData.metrics.passed}/${runData.metrics.total} passed (${(runData.metrics.passRate * 100).toFixed(1)}%)`\n );\n\n // Auto-open browser if configured and not in CI\n if (this.config.autoOpen && !process.env.CI) {\n await this.openReport(reportPath);\n }\n }\n\n private async generateReport(\n runData: MCPEvalRunData,\n historical: Array<MCPEvalHistoricalSummary>,\n outputDir: string\n ): Promise<void> {\n // Get the UI dist path (relative to this file)\n // In ESM, we need to use import.meta.url\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const uiDistPath = join(__dirname, 'ui-dist');\n\n // Step 1: Copy pre-built UI template\n await mkdir(outputDir, { recursive: true });\n await cp(uiDistPath, outputDir, { recursive: true, force: true });\n\n // Step 2: Inject test data as JavaScript\n const dataScript = `window.MCP_EVAL_DATA = ${JSON.stringify(\n {\n runData,\n historical,\n },\n null,\n 2\n )};`;\n\n await writeFile(join(outputDir, 'data.js'), dataScript, 'utf-8');\n }\n\n private buildRunData(durationMs: number): MCPEvalRunData {\n const total = this.allResults.length;\n const datasetBreakdown: Record<string, number> = {};\n const expectationBreakdown = {\n exact: 0,\n schema: 0,\n textContains: 0,\n regex: 0,\n snapshot: 0,\n judge: 0,\n error: 0,\n size: 0,\n toolsTriggered: 0,\n toolCallCount: 0,\n };\n\n let passed = 0;\n for (const r of this.allResults) {\n if (r.pass) passed++;\n\n const datasetName = r.datasetName || 'Unknown Dataset';\n datasetBreakdown[datasetName] = (datasetBreakdown[datasetName] || 0) + 1;\n\n if (r.expectations.exact) expectationBreakdown.exact++;\n if (r.expectations.schema) expectationBreakdown.schema++;\n if (r.expectations.textContains) expectationBreakdown.textContains++;\n if (r.expectations.regex) expectationBreakdown.regex++;\n if (r.expectations.snapshot) expectationBreakdown.snapshot++;\n if (r.expectations.judge) expectationBreakdown.judge++;\n if (r.expectations.error) expectationBreakdown.error++;\n if (r.expectations.size) expectationBreakdown.size++;\n if (r.expectations.toolsTriggered) expectationBreakdown.toolsTriggered++;\n if (r.expectations.toolCallCount) expectationBreakdown.toolCallCount++;\n }\n\n const failed = total - passed;\n\n const totalHostUsage = this.allResults.reduce(\n (acc, r) => sumUsage(acc, r.hostUsage),\n undefined as UsageMetrics | undefined\n );\n\n return {\n timestamp: new Date().toISOString(),\n durationMs,\n environment: {\n ci: !!process.env.CI,\n node: process.version,\n platform: process.platform,\n },\n metrics: {\n total,\n passed,\n failed,\n passRate: passed / total,\n datasetBreakdown,\n expectationBreakdown,\n totalHostUsage,\n },\n results: this.allResults,\n conformanceChecks:\n this.conformanceChecks.length > 0 ? this.conformanceChecks : undefined,\n serverCapabilities:\n this.serverCapabilities.length > 0\n ? this.serverCapabilities\n : undefined,\n };\n }\n\n private async loadHistoricalData(): Promise<Array<MCPEvalHistoricalSummary>> {\n try {\n const files = await readdir(this.config.outputDir);\n const runFiles = files\n .filter((f) => f.startsWith('run-') && f.endsWith('.json'))\n .sort()\n .slice(-(this.config.historyLimit - 1)); // Keep most recent, leave room for current run\n\n const historical: Array<MCPEvalHistoricalSummary> = [];\n\n for (const file of runFiles) {\n try {\n const content = await readFile(\n join(this.config.outputDir, file),\n 'utf-8'\n );\n const runData = JSON.parse(content) as MCPEvalRunData;\n\n historical.push({\n timestamp: runData.timestamp,\n total: runData.metrics.total,\n passed: runData.metrics.passed,\n failed: runData.metrics.failed,\n passRate: runData.metrics.passRate,\n durationMs: runData.durationMs,\n });\n } catch (error) {\n this.logError(`[MCP Reporter] Failed to load ${file}:`, error);\n }\n }\n\n return historical;\n } catch {\n return [];\n }\n }\n\n private async saveRunData(runData: MCPEvalRunData): Promise<void> {\n const filename = `run-${runData.timestamp.replace(/:/g, '-')}.json`;\n const filepath = join(this.config.outputDir, filename);\n\n await writeFile(filepath, JSON.stringify(runData, null, 2), 'utf-8');\n }\n\n private async cleanupOldRuns(): Promise<void> {\n try {\n const files = await readdir(this.config.outputDir);\n const runFiles = files\n .filter((f) => f.startsWith('run-') && f.endsWith('.json'))\n .sort()\n .reverse();\n\n // Keep only historyLimit most recent runs\n const toDelete = runFiles.slice(this.config.historyLimit);\n\n for (const file of toDelete) {\n await unlink(join(this.config.outputDir, file));\n }\n } catch (error) {\n this.logError('[MCP Reporter] Failed to cleanup old runs:', error);\n }\n }\n\n private async openReport(reportPath: string): Promise<void> {\n try {\n // Dynamic import to avoid bundling issues\n const { default: open } = await import('open');\n const absolutePath = resolve(reportPath);\n\n await open(absolutePath);\n this.log('[MCP Reporter] Opened report in browser');\n } catch (error) {\n this.logError('[MCP Reporter] Failed to open report:', error);\n this.log(`[MCP Reporter] Open manually: file://${resolve(reportPath)}`);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/usageUtils.ts","../../src/evals/resultStore.ts","../../src/reporters/mcpReporter.ts"],"names":["readFile","mkdir","join","__filename","__dirname","writeFile","readdir"],"mappings":"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","file":"mcpReporter.js","sourcesContent":["import type { UsageMetrics } from '../types/index.js';\n\nfunction optionalSum(a?: number, b?: number): number | undefined {\n if (a === undefined && b === undefined) return undefined;\n return (a ?? 0) + (b ?? 0);\n}\n\nexport function sumUsage(\n a: UsageMetrics | undefined,\n b: UsageMetrics | undefined\n): UsageMetrics | undefined {\n if (!a && !b) return undefined;\n if (!a) return b ? { ...b } : undefined;\n if (!b) return { ...a };\n return {\n inputTokens: a.inputTokens + b.inputTokens,\n outputTokens: a.outputTokens + b.outputTokens,\n totalCostUsd: a.totalCostUsd + b.totalCostUsd,\n durationMs: a.durationMs + b.durationMs,\n durationApiMs: optionalSum(a.durationApiMs, b.durationApiMs),\n cacheReadInputTokens: optionalSum(\n a.cacheReadInputTokens,\n b.cacheReadInputTokens\n ),\n cacheCreationInputTokens: optionalSum(\n a.cacheCreationInputTokens,\n b.cacheCreationInputTokens\n ),\n };\n}\n","import { mkdir, readFile, readdir, writeFile } from 'fs/promises';\nimport { join } from 'path';\n\nexport type StoredArtifactKind =\n | 'eval-runner-result'\n | 'reporter-run'\n | 'eval-run-comparison'\n | 'server-comparison';\n\nexport interface StoredEvalArtifactMetadata {\n datasetName?: string;\n gitHash?: string;\n branch?: string;\n runNumber?: string;\n trigger?: string;\n packageVersion?: string;\n toolOverrideVariantId?: string;\n mcpHostModel?: string;\n judgeModel?: string;\n labels?: Record<string, string>;\n [key: string]: unknown;\n}\n\nexport interface StoredEvalArtifact<T> {\n schemaVersion: 1;\n kind: StoredArtifactKind;\n id: string;\n createdAt: string;\n metadata: StoredEvalArtifactMetadata;\n data: T;\n}\n\nexport interface StoredArtifactSummary {\n kind: StoredArtifactKind;\n id: string;\n createdAt: string;\n metadata: StoredEvalArtifactMetadata;\n}\n\nexport interface ListStoredArtifactsOptions {\n limit?: number;\n}\n\nexport interface EvalResultStore {\n saveArtifact<T>(artifact: StoredEvalArtifact<T>): Promise<void>;\n loadArtifact<T>(\n kind: StoredArtifactKind,\n id: string\n ): Promise<StoredEvalArtifact<T>>;\n loadLatestArtifact<T>(\n kind: StoredArtifactKind\n ): Promise<StoredEvalArtifact<T> | null>;\n listArtifacts(\n kind: StoredArtifactKind,\n options?: ListStoredArtifactsOptions\n ): Promise<StoredArtifactSummary[]>;\n}\n\nexport interface FileEvalResultStoreConfig {\n provider: 'file';\n dir: string;\n}\n\nexport interface GCSEvalResultStoreConfig {\n provider: 'gcs';\n bucket: string;\n prefix?: string;\n}\n\nexport type EvalResultStoreConfig =\n | FileEvalResultStoreConfig\n | GCSEvalResultStoreConfig;\n\nexport type EvalResultStoreLike = EvalResultStore | EvalResultStoreConfig;\n\nconst KIND_DIRS: Record<StoredArtifactKind, string> = {\n 'eval-runner-result': 'eval-runs',\n 'reporter-run': 'reporter-runs',\n 'eval-run-comparison': 'comparisons/eval-runs',\n 'server-comparison': 'comparisons/servers',\n};\n\nexport function createEvalResultStore(\n config: EvalResultStoreConfig\n): EvalResultStore {\n if (config.provider === 'file') {\n return new FileEvalResultStore(config);\n }\n return new GCSEvalResultStore(config);\n}\n\nexport function resolveEvalResultStore(\n store: EvalResultStoreLike\n): EvalResultStore {\n return isEvalResultStore(store) ? store : createEvalResultStore(store);\n}\n\nexport function isEvalResultStore(value: unknown): value is EvalResultStore {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'saveArtifact' in value &&\n 'loadArtifact' in value &&\n 'loadLatestArtifact' in value &&\n 'listArtifacts' in value\n );\n}\n\nexport function createStoredEvalArtifact<T>(options: {\n kind: StoredArtifactKind;\n data: T;\n id?: string;\n metadata?: StoredEvalArtifactMetadata;\n createdAt?: string;\n}): StoredEvalArtifact<T> {\n const createdAt = options.createdAt ?? new Date().toISOString();\n return {\n schemaVersion: 1,\n kind: options.kind,\n id: options.id ?? createDefaultArtifactId(createdAt),\n createdAt,\n metadata: {\n ...defaultEnvironmentMetadata(),\n ...(options.metadata ?? {}),\n },\n data: options.data,\n };\n}\n\nexport function createDefaultArtifactId(timestamp = new Date().toISOString()) {\n const safeTimestamp = timestamp.replace(/[:.]/g, '-');\n const runNumber = process.env.GITHUB_RUN_NUMBER;\n const sha = process.env.GITHUB_SHA?.slice(0, 12);\n const suffix = runNumber ?? sha;\n return suffix ? `${safeTimestamp}-${suffix}` : safeTimestamp;\n}\n\nexport function defaultEnvironmentMetadata(): StoredEvalArtifactMetadata {\n return {\n ...(process.env.GITHUB_SHA !== undefined && {\n gitHash: process.env.GITHUB_SHA,\n }),\n ...(process.env.GITHUB_REF_NAME !== undefined && {\n branch: process.env.GITHUB_REF_NAME,\n }),\n ...(process.env.GITHUB_RUN_NUMBER !== undefined && {\n runNumber: process.env.GITHUB_RUN_NUMBER,\n }),\n ...(process.env.GITHUB_EVENT_NAME !== undefined && {\n trigger: process.env.GITHUB_EVENT_NAME,\n }),\n };\n}\n\nexport class FileEvalResultStore implements EvalResultStore {\n private readonly dir: string;\n\n constructor(config: FileEvalResultStoreConfig) {\n this.dir = config.dir;\n }\n\n async saveArtifact<T>(artifact: StoredEvalArtifact<T>): Promise<void> {\n const artifactDir = join(this.dir, KIND_DIRS[artifact.kind]);\n await mkdir(artifactDir, { recursive: true });\n const serialized = JSON.stringify(artifact, null, 2);\n await writeFile(\n join(artifactDir, `${artifact.id}.json`),\n serialized,\n 'utf8'\n );\n await writeFile(join(artifactDir, 'latest.json'), serialized, 'utf8');\n }\n\n async loadArtifact<T>(\n kind: StoredArtifactKind,\n id: string\n ): Promise<StoredEvalArtifact<T>> {\n const raw = await readFile(\n join(this.dir, KIND_DIRS[kind], `${id}.json`),\n 'utf8'\n );\n return JSON.parse(raw) as StoredEvalArtifact<T>;\n }\n\n async loadLatestArtifact<T>(\n kind: StoredArtifactKind\n ): Promise<StoredEvalArtifact<T> | null> {\n try {\n const raw = await readFile(\n join(this.dir, KIND_DIRS[kind], 'latest.json'),\n 'utf8'\n );\n return JSON.parse(raw) as StoredEvalArtifact<T>;\n } catch (error) {\n if (isMissingFileError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n async listArtifacts(\n kind: StoredArtifactKind,\n options: ListStoredArtifactsOptions = {}\n ): Promise<StoredArtifactSummary[]> {\n let files: string[];\n try {\n files = await readdir(join(this.dir, KIND_DIRS[kind]));\n } catch (error) {\n if (isMissingFileError(error)) {\n return [];\n }\n throw error;\n }\n\n const summaries = await Promise.all(\n files\n .filter((f) => f.endsWith('.json') && f !== 'latest.json')\n .map(async (file) => {\n const raw = await readFile(\n join(this.dir, KIND_DIRS[kind], file),\n 'utf8'\n );\n return toSummary(JSON.parse(raw) as StoredEvalArtifact<unknown>);\n })\n );\n\n return summaries\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, options.limit);\n }\n}\n\ntype GCSStorageConstructor = new () => {\n bucket(name: string): GCSBucket;\n};\n\ninterface GCSBucket {\n file(name: string): GCSFile;\n getFiles(options: { prefix: string }): Promise<[GCSFile[]]>;\n}\n\ninterface GCSFile {\n name: string;\n save(\n data: string,\n options?: { contentType?: string; resumable?: boolean; validation?: false }\n ): Promise<unknown>;\n download(): Promise<[Buffer]>;\n exists(): Promise<[boolean]>;\n}\n\nexport class GCSEvalResultStore implements EvalResultStore {\n private readonly bucketName: string;\n private readonly prefix: string;\n private storage: { bucket(name: string): GCSBucket } | undefined;\n\n constructor(config: GCSEvalResultStoreConfig) {\n this.bucketName = config.bucket;\n this.prefix = trimSlashes(config.prefix ?? '');\n }\n\n async saveArtifact<T>(artifact: StoredEvalArtifact<T>): Promise<void> {\n const bucket = await this.getBucket();\n const serialized = JSON.stringify(artifact, null, 2);\n await bucket\n .file(\n this.objectPath(\n artifact.kind,\n `${encodeURIComponent(artifact.id)}.json`\n )\n )\n .save(serialized, {\n contentType: 'application/json',\n resumable: false,\n validation: false,\n });\n await bucket\n .file(this.objectPath(artifact.kind, 'latest.json'))\n .save(serialized, {\n contentType: 'application/json',\n resumable: false,\n validation: false,\n });\n }\n\n async loadArtifact<T>(\n kind: StoredArtifactKind,\n id: string\n ): Promise<StoredEvalArtifact<T>> {\n const bucket = await this.getBucket();\n const file = bucket.file(\n this.objectPath(kind, `${encodeURIComponent(id)}.json`)\n );\n const [buffer] = await file.download();\n return JSON.parse(buffer.toString('utf8')) as StoredEvalArtifact<T>;\n }\n\n async loadLatestArtifact<T>(\n kind: StoredArtifactKind\n ): Promise<StoredEvalArtifact<T> | null> {\n const bucket = await this.getBucket();\n const file = bucket.file(this.objectPath(kind, 'latest.json'));\n const [exists] = await file.exists();\n if (!exists) return null;\n\n const [buffer] = await file.download();\n return JSON.parse(buffer.toString('utf8')) as StoredEvalArtifact<T>;\n }\n\n async listArtifacts(\n kind: StoredArtifactKind,\n options: ListStoredArtifactsOptions = {}\n ): Promise<StoredArtifactSummary[]> {\n const bucket = await this.getBucket();\n const [files] = await bucket.getFiles({\n prefix: this.objectPath(kind, ''),\n });\n\n const summaries = await Promise.all(\n files\n .filter(\n (f) => f.name.endsWith('.json') && !f.name.endsWith('/latest.json')\n )\n .map(async (file) => {\n const [buffer] = await file.download();\n return toSummary(\n JSON.parse(buffer.toString('utf8')) as StoredEvalArtifact<unknown>\n );\n })\n );\n\n return summaries\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, options.limit);\n }\n\n private async getBucket(): Promise<GCSBucket> {\n if (!this.storage) {\n const moduleName = '@google-cloud/storage';\n let Storage: GCSStorageConstructor;\n try {\n const mod = (await import(moduleName)) as {\n Storage: GCSStorageConstructor;\n };\n Storage = mod.Storage;\n } catch (error) {\n throw new Error(\n 'GCS result storage requires the optional `@google-cloud/storage` package. ' +\n 'Install it and authenticate with Application Default Credentials via GOOGLE_APPLICATION_CREDENTIALS.\\n' +\n `Original error: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.storage = new Storage();\n }\n return this.storage.bucket(this.bucketName);\n }\n\n private objectPath(kind: StoredArtifactKind, filename: string): string {\n const parts = [this.prefix, KIND_DIRS[kind], filename].filter(Boolean);\n return parts.join('/');\n }\n}\n\nfunction toSummary(\n artifact: StoredEvalArtifact<unknown>\n): StoredArtifactSummary {\n return {\n kind: artifact.kind,\n id: artifact.id,\n createdAt: artifact.createdAt,\n metadata: artifact.metadata,\n };\n}\n\nfunction trimSlashes(value: string): string {\n return value.replace(/^\\/+|\\/+$/g, '');\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n (error as { code?: string }).code === 'ENOENT'\n );\n}\n","import type {\n Reporter,\n FullConfig,\n Suite,\n TestCase,\n TestResult,\n FullResult,\n} from '@playwright/test/reporter';\nimport { mkdir, writeFile, readdir, readFile, unlink, cp } from 'fs/promises';\nimport { join, resolve, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport type { MCPEvalReporterConfig } from './types.js';\nimport type { AuthType } from '../types/index.js';\nimport type {\n MCPEvalRunData,\n MCPEvalHistoricalSummary,\n MCPConformanceResultData,\n MCPServerCapabilitiesData,\n EvalCaseResult,\n MCPConformanceCheck,\n} from '../types/reporter.js';\nimport type { UsageMetrics } from '../types/index.js';\nimport { sumUsage } from '../utils/usageUtils.js';\nimport {\n createStoredEvalArtifact,\n resolveEvalResultStore,\n} from '../evals/resultStore.js';\n\ntype ResolvedReporterConfig = Required<\n Omit<\n MCPEvalReporterConfig,\n 'resultStore' | 'runId' | 'runMetadata' | 'redactStoredResponses'\n >\n> &\n Pick<\n MCPEvalReporterConfig,\n 'resultStore' | 'runId' | 'runMetadata' | 'redactStoredResponses'\n >;\n\n/**\n * Custom Playwright reporter for MCP eval results\n *\n * Generates HTML reports with historical tracking\n *\n * @example\n * ```typescript\n * // playwright.config.ts\n * export default defineConfig({\n * reporter: [\n * ['@gleanwork/mcp-server-tester/reporters/mcpReporter', {\n * outputDir: '.mcp-test-results',\n * historyLimit: 10\n * }]\n * ]\n * });\n * ```\n */\nexport default class MCPReporter implements Reporter {\n private config: ResolvedReporterConfig;\n private startTime: number = 0;\n private allResults: Array<EvalCaseResult> = [];\n private conformanceChecks: Array<MCPConformanceResultData> = [];\n private serverCapabilities: Array<MCPServerCapabilitiesData> = [];\n\n constructor(options: MCPEvalReporterConfig = {}) {\n this.config = {\n outputDir: options.outputDir ?? '.mcp-test-results',\n autoOpen: options.autoOpen ?? false,\n historyLimit: options.historyLimit ?? 10,\n quiet: options.quiet ?? false,\n includeAutoTracking: options.includeAutoTracking ?? true,\n resultStore: options.resultStore,\n runId: options.runId,\n runMetadata: options.runMetadata,\n // Default true to match the eval-runner store path. Stored artifacts\n // omit response bodies by default; opt in by passing\n // `redactStoredResponses: false` if you need full responses for\n // debugging or history comparison. Keeping this consistent across\n // both write paths prevents users from getting a mix of\n // redacted/non-redacted artifacts depending on which code path wrote\n // them.\n redactStoredResponses: options.redactStoredResponses ?? true,\n };\n }\n\n private log(message: string): void {\n if (!this.config.quiet) {\n console.log(message);\n }\n }\n\n private logError(message: string, error?: unknown): void {\n if (!this.config.quiet) {\n console.error(message, error ?? '');\n }\n }\n\n /**\n * Reads attachment content from either in-memory body (Playwright < 1.43)\n * or from the file path on disk (Playwright ≥ 1.43, which writes large\n * attachments to disk and exposes path instead of body).\n */\n private async getAttachmentContent(attachment: {\n body?: Buffer;\n path?: string;\n }): Promise<string | null> {\n if (attachment.body) return attachment.body.toString('utf-8');\n if (attachment.path) {\n try {\n return await readFile(attachment.path, 'utf-8');\n } catch {\n return null;\n }\n }\n return null;\n }\n\n async onBegin(_config: FullConfig, _suite: Suite): Promise<void> {\n this.startTime = Date.now();\n this.allResults = [];\n this.conformanceChecks = [];\n this.serverCapabilities = [];\n\n // Ensure output directory exists\n await mkdir(this.config.outputDir, { recursive: true });\n }\n\n async onTestEnd(test: TestCase, result: TestResult): Promise<void> {\n // Strategy 1: Extract MCP eval results from runEvalDataset() attachments\n const evalAttachment = result.attachments.find(\n (a) =>\n a.name === 'mcp-test-results' && a.contentType === 'application/json'\n );\n\n let hasEvalDataset = false;\n\n const evalContent = evalAttachment\n ? await this.getAttachmentContent(evalAttachment)\n : null;\n if (evalContent) {\n try {\n const evalResults = JSON.parse(evalContent) as {\n caseResults: Array<EvalCaseResult>;\n };\n\n // Trust the data from the attachment - evalRunner now includes\n // authType and project from the mcp fixture (Playwright is source of truth)\n this.allResults.push(...evalResults.caseResults);\n hasEvalDataset = true;\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse eval results from test \"${test.title}\":`,\n error\n );\n }\n }\n\n // Strategy 2: Extract conformance check results\n // These are created by runConformanceChecks() when testInfo is passed\n const conformanceAttachment = result.attachments.find(\n (a) =>\n a.name === 'mcp-conformance-checks' &&\n a.contentType === 'application/json'\n );\n\n const conformanceContent = conformanceAttachment\n ? await this.getAttachmentContent(conformanceAttachment)\n : null;\n if (conformanceContent) {\n try {\n const conformanceData = JSON.parse(conformanceContent) as {\n operation: string;\n pass: boolean;\n checks: MCPConformanceCheck[];\n serverInfo?: { name?: string; version?: string };\n toolCount: number;\n authType?: AuthType;\n project?: string;\n };\n\n // Only push if checks array is valid\n if (Array.isArray(conformanceData.checks)) {\n this.conformanceChecks.push({\n testTitle: test.title,\n pass: conformanceData.pass,\n checks: conformanceData.checks,\n serverInfo: conformanceData.serverInfo,\n toolCount: conformanceData.toolCount,\n authType: conformanceData.authType,\n project: conformanceData.project,\n });\n }\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse conformance check attachment for \"${test.title}\":`,\n error\n );\n }\n }\n\n // Strategy 2b: Extract server capabilities from mcp-list-tools attachments\n // These are created by createMCPFixture().listTools()\n const listToolsAttachment = result.attachments.find(\n (a) => a.name === 'mcp-list-tools' && a.contentType === 'application/json'\n );\n\n const listToolsContent = listToolsAttachment\n ? await this.getAttachmentContent(listToolsAttachment)\n : null;\n if (listToolsContent) {\n try {\n const listToolsData = JSON.parse(listToolsContent) as {\n operation: string;\n toolCount: number;\n tools: Array<{ name: string; description?: string }>;\n };\n\n // Only push if tools array is valid\n if (Array.isArray(listToolsData.tools)) {\n this.serverCapabilities.push({\n testTitle: test.title,\n tools: listToolsData.tools,\n toolCount: listToolsData.toolCount,\n // Note: authType and project are available from the mcp fixture\n // but not currently included in the listTools attachment\n });\n }\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse mcp-list-tools attachment for \"${test.title}\":`,\n error\n );\n }\n }\n\n // Strategy 3: Extract MCP tool calls from auto-tracking attachments\n // These are created by createMCPFixture()\n // Skip if:\n // - This test already has eval dataset results (to avoid duplicates)\n // - Auto-tracking is disabled in config\n if (hasEvalDataset || !this.config.includeAutoTracking) {\n return;\n }\n\n const mcpCallAttachments = result.attachments.filter(\n (a) =>\n a.name &&\n a.name.startsWith('mcp-call-') &&\n a.contentType === 'application/json'\n );\n\n for (const attachment of mcpCallAttachments) {\n const callContent = await this.getAttachmentContent(attachment);\n if (!callContent) continue;\n\n try {\n // Attachment now includes authType and project from the mcp fixture\n const callData = JSON.parse(callContent) as {\n operation: string;\n toolName: string;\n args: Record<string, unknown>;\n result: unknown;\n durationMs: number;\n isError: boolean;\n authType?: AuthType;\n project?: string;\n };\n\n const suiteName = test.parent?.title || 'Uncategorized Tests';\n const testPassed = result.status === 'passed';\n\n const syntheticResult: EvalCaseResult = {\n id: test.title,\n datasetName: suiteName,\n toolName: callData.toolName,\n source: 'test',\n pass: testPassed,\n response: callData.result,\n error: !testPassed ? 'Test failed' : undefined,\n expectations: {},\n authType: callData.authType,\n project: callData.project,\n durationMs: callData.durationMs,\n };\n\n this.allResults.push(syntheticResult);\n } catch (error) {\n this.logError(\n `[MCP Reporter] Failed to parse MCP call attachment \"${attachment.name}\":`,\n error\n );\n }\n }\n }\n\n async onEnd(_result: FullResult): Promise<void> {\n const endTime = Date.now();\n const durationMs = endTime - this.startTime;\n\n // Skip if no eval results collected\n if (this.allResults.length === 0) {\n this.log('[MCP Reporter] No MCP eval results found in test run');\n return;\n }\n\n // Build run data\n const runData = this.buildRunData(durationMs);\n\n // Load historical data\n const historical = await this.loadHistoricalData();\n\n // Add current run to historical\n historical.push({\n timestamp: runData.timestamp,\n total: runData.metrics.total,\n passed: runData.metrics.passed,\n failed: runData.metrics.failed,\n passRate: runData.metrics.passRate,\n durationMs: runData.durationMs,\n });\n\n // Save current run data\n await this.saveRunData(runData);\n\n // Clean up old runs\n await this.cleanupOldRuns();\n\n // Save current run to external storage, if configured. This is additive:\n // local report generation should still work if remote storage is down.\n await this.saveRunDataToStore(runData);\n\n // Generate report using copy + inject pattern\n const reportDir = join(this.config.outputDir, 'latest');\n await this.generateReport(runData, historical, reportDir);\n\n const reportPath = join(reportDir, 'index.html');\n this.log(`\\n[MCP Reporter] Report generated: ${reportPath}`);\n this.log(\n `[MCP Reporter] Results: ${runData.metrics.passed}/${runData.metrics.total} passed (${(runData.metrics.passRate * 100).toFixed(1)}%)`\n );\n\n // Auto-open browser if configured and not in CI\n if (this.config.autoOpen && !process.env.CI) {\n await this.openReport(reportPath);\n }\n }\n\n private async generateReport(\n runData: MCPEvalRunData,\n historical: Array<MCPEvalHistoricalSummary>,\n outputDir: string\n ): Promise<void> {\n // Get the UI dist path (relative to this file)\n // In ESM, we need to use import.meta.url\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const uiDistPath = join(__dirname, 'ui-dist');\n\n // Step 1: Copy pre-built UI template\n await mkdir(outputDir, { recursive: true });\n await cp(uiDistPath, outputDir, { recursive: true, force: true });\n\n // Step 2: Inject test data as JavaScript\n const dataScript = `window.MCP_EVAL_DATA = ${JSON.stringify(\n {\n runData,\n historical,\n },\n null,\n 2\n )};`;\n\n await writeFile(join(outputDir, 'data.js'), dataScript, 'utf-8');\n }\n\n private buildRunData(durationMs: number): MCPEvalRunData {\n const total = this.allResults.length;\n const datasetBreakdown: Record<string, number> = {};\n const expectationBreakdown = {\n exact: 0,\n schema: 0,\n textContains: 0,\n regex: 0,\n snapshot: 0,\n judge: 0,\n error: 0,\n size: 0,\n toolsTriggered: 0,\n toolCallCount: 0,\n };\n\n let passed = 0;\n for (const r of this.allResults) {\n if (r.pass) passed++;\n\n const datasetName = r.datasetName || 'Unknown Dataset';\n datasetBreakdown[datasetName] = (datasetBreakdown[datasetName] || 0) + 1;\n\n if (r.expectations.exact) expectationBreakdown.exact++;\n if (r.expectations.schema) expectationBreakdown.schema++;\n if (r.expectations.textContains) expectationBreakdown.textContains++;\n if (r.expectations.regex) expectationBreakdown.regex++;\n if (r.expectations.snapshot) expectationBreakdown.snapshot++;\n if (r.expectations.judge) expectationBreakdown.judge++;\n if (r.expectations.error) expectationBreakdown.error++;\n if (r.expectations.size) expectationBreakdown.size++;\n if (r.expectations.toolsTriggered) expectationBreakdown.toolsTriggered++;\n if (r.expectations.toolCallCount) expectationBreakdown.toolCallCount++;\n }\n\n const failed = total - passed;\n\n const totalHostUsage = this.allResults.reduce(\n (acc, r) => sumUsage(acc, r.hostUsage),\n undefined as UsageMetrics | undefined\n );\n\n return {\n timestamp: new Date().toISOString(),\n durationMs,\n environment: {\n ci: !!process.env.CI,\n node: process.version,\n platform: process.platform,\n },\n metrics: {\n total,\n passed,\n failed,\n passRate: passed / total,\n datasetBreakdown,\n expectationBreakdown,\n totalHostUsage,\n },\n results: this.allResults,\n conformanceChecks:\n this.conformanceChecks.length > 0 ? this.conformanceChecks : undefined,\n serverCapabilities:\n this.serverCapabilities.length > 0\n ? this.serverCapabilities\n : undefined,\n };\n }\n\n private async loadHistoricalData(): Promise<Array<MCPEvalHistoricalSummary>> {\n const storeHistorical = await this.loadHistoricalDataFromStore();\n if (storeHistorical) {\n return storeHistorical;\n }\n\n try {\n const files = await readdir(this.config.outputDir);\n const runFiles = files\n .filter((f) => f.startsWith('run-') && f.endsWith('.json'))\n .sort()\n .slice(-(this.config.historyLimit - 1)); // Keep most recent, leave room for current run\n\n const historical: Array<MCPEvalHistoricalSummary> = [];\n\n for (const file of runFiles) {\n try {\n const content = await readFile(\n join(this.config.outputDir, file),\n 'utf-8'\n );\n const runData = JSON.parse(content) as MCPEvalRunData;\n\n historical.push({\n timestamp: runData.timestamp,\n total: runData.metrics.total,\n passed: runData.metrics.passed,\n failed: runData.metrics.failed,\n passRate: runData.metrics.passRate,\n durationMs: runData.durationMs,\n });\n } catch (error) {\n this.logError(`[MCP Reporter] Failed to load ${file}:`, error);\n }\n }\n\n return historical;\n } catch {\n return [];\n }\n }\n\n private async saveRunData(runData: MCPEvalRunData): Promise<void> {\n const filename = `run-${runData.timestamp.replace(/:/g, '-')}.json`;\n const filepath = join(this.config.outputDir, filename);\n\n await writeFile(filepath, JSON.stringify(runData, null, 2), 'utf-8');\n }\n\n private async saveRunDataToStore(runData: MCPEvalRunData): Promise<void> {\n if (!this.config.resultStore) {\n return;\n }\n\n try {\n const store = resolveEvalResultStore(this.config.resultStore);\n await store.saveArtifact(\n createStoredEvalArtifact({\n kind: 'reporter-run',\n id: this.config.runId,\n data: this.config.redactStoredResponses\n ? redactResponses(runData)\n : runData,\n metadata: {\n ...(this.config.runMetadata ?? {}),\n },\n })\n );\n } catch (error) {\n this.logError(\n '[MCP Reporter] Failed to save run to result store:',\n error\n );\n }\n }\n\n private async loadHistoricalDataFromStore(): Promise<Array<MCPEvalHistoricalSummary> | null> {\n if (!this.config.resultStore) {\n return null;\n }\n\n try {\n const store = resolveEvalResultStore(this.config.resultStore);\n const summaries = await store.listArtifacts('reporter-run', {\n limit: this.config.historyLimit - 1,\n });\n\n const historical: Array<MCPEvalHistoricalSummary> = [];\n for (const summary of summaries.reverse()) {\n const artifact = await store.loadArtifact<MCPEvalRunData>(\n 'reporter-run',\n summary.id\n );\n historical.push(toHistoricalSummary(artifact.data));\n }\n return historical;\n } catch (error) {\n this.logError(\n '[MCP Reporter] Failed to load history from result store:',\n error\n );\n return null;\n }\n }\n\n private async cleanupOldRuns(): Promise<void> {\n try {\n const files = await readdir(this.config.outputDir);\n const runFiles = files\n .filter((f) => f.startsWith('run-') && f.endsWith('.json'))\n .sort()\n .reverse();\n\n // Keep only historyLimit most recent runs\n const toDelete = runFiles.slice(this.config.historyLimit);\n\n for (const file of toDelete) {\n await unlink(join(this.config.outputDir, file));\n }\n } catch (error) {\n this.logError('[MCP Reporter] Failed to cleanup old runs:', error);\n }\n }\n\n private async openReport(reportPath: string): Promise<void> {\n try {\n // Dynamic import to avoid bundling issues\n const { default: open } = await import('open');\n const absolutePath = resolve(reportPath);\n\n await open(absolutePath);\n this.log('[MCP Reporter] Opened report in browser');\n } catch (error) {\n this.logError('[MCP Reporter] Failed to open report:', error);\n this.log(`[MCP Reporter] Open manually: file://${resolve(reportPath)}`);\n }\n }\n}\n\nfunction toHistoricalSummary(\n runData: MCPEvalRunData\n): MCPEvalHistoricalSummary {\n return {\n timestamp: runData.timestamp,\n total: runData.metrics.total,\n passed: runData.metrics.passed,\n failed: runData.metrics.failed,\n passRate: runData.metrics.passRate,\n durationMs: runData.durationMs,\n };\n}\n\nfunction redactResponses<T>(value: T): T {\n return JSON.parse(\n JSON.stringify(value, (key, currentValue: unknown) =>\n key === 'response' ? undefined : currentValue\n )\n ) as T;\n}\n"]}
@@ -1,4 +1,4 @@
1
- "use strict";var MCPEvalApp=(()=>{var TN=Object.create;var sc=Object.defineProperty;var RN=Object.getOwnPropertyDescriptor;var NN=Object.getOwnPropertyNames;var _N=Object.getPrototypeOf,FN=Object.prototype.hasOwnProperty;var jN=(e,t,r)=>t in e?sc(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var G=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),BN=(e,t)=>{for(var r in t)sc(e,r,{get:t[r],enumerable:!0})},zN=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of NN(t))!FN.call(e,n)&&n!==r&&sc(e,n,{get:()=>t[n],enumerable:!(a=RN(t,n))||a.enumerable});return e};var D=(e,t,r)=>(r=e!=null?TN(_N(e)):{},zN(t||!e||!e.__esModule?sc(r,"default",{value:e,enumerable:!0}):r,e));var ui=(e,t,r)=>jN(e,typeof t!="symbol"?t+"":t,r);var ZS=G(ue=>{"use strict";var Hl=Symbol.for("react.element"),UN=Symbol.for("react.portal"),qN=Symbol.for("react.fragment"),HN=Symbol.for("react.strict_mode"),VN=Symbol.for("react.profiler"),WN=Symbol.for("react.provider"),$N=Symbol.for("react.context"),GN=Symbol.for("react.forward_ref"),KN=Symbol.for("react.suspense"),XN=Symbol.for("react.memo"),YN=Symbol.for("react.lazy"),zS=Symbol.iterator;function ZN(e){return e===null||typeof e!="object"?null:(e=zS&&e[zS]||e["@@iterator"],typeof e=="function"?e:null)}var HS={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},VS=Object.assign,WS={};function si(e,t,r){this.props=e,this.context=t,this.refs=WS,this.updater=r||HS}si.prototype.isReactComponent={};si.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};si.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function $S(){}$S.prototype=si.prototype;function nh(e,t,r){this.props=e,this.context=t,this.refs=WS,this.updater=r||HS}var oh=nh.prototype=new $S;oh.constructor=nh;VS(oh,si.prototype);oh.isPureReactComponent=!0;var US=Array.isArray,GS=Object.prototype.hasOwnProperty,ih={current:null},KS={key:!0,ref:!0,__self:!0,__source:!0};function XS(e,t,r){var a,n={},o=null,i=null;if(t!=null)for(a in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(o=""+t.key),t)GS.call(t,a)&&!KS.hasOwnProperty(a)&&(n[a]=t[a]);var l=arguments.length-2;if(l===1)n.children=r;else if(1<l){for(var u=Array(l),s=0;s<l;s++)u[s]=arguments[s+2];n.children=u}if(e&&e.defaultProps)for(a in l=e.defaultProps,l)n[a]===void 0&&(n[a]=l[a]);return{$$typeof:Hl,type:e,key:o,ref:i,props:n,_owner:ih.current}}function QN(e,t){return{$$typeof:Hl,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}function lh(e){return typeof e=="object"&&e!==null&&e.$$typeof===Hl}function JN(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(r){return t[r]})}var qS=/\/+/g;function ah(e,t){return typeof e=="object"&&e!==null&&e.key!=null?JN(""+e.key):t.toString(36)}function fc(e,t,r,a,n){var o=typeof e;(o==="undefined"||o==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(o){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Hl:case UN:i=!0}}if(i)return i=e,n=n(i),e=a===""?"."+ah(i,0):a,US(n)?(r="",e!=null&&(r=e.replace(qS,"$&/")+"/"),fc(n,t,r,"",function(s){return s})):n!=null&&(lh(n)&&(n=QN(n,r+(!n.key||i&&i.key===n.key?"":(""+n.key).replace(qS,"$&/")+"/")+e)),t.push(n)),1;if(i=0,a=a===""?".":a+":",US(e))for(var l=0;l<e.length;l++){o=e[l];var u=a+ah(o,l);i+=fc(o,t,r,u,n)}else if(u=ZN(e),typeof u=="function")for(e=u.call(e),l=0;!(o=e.next()).done;)o=o.value,u=a+ah(o,l++),i+=fc(o,t,r,u,n);else if(o==="object")throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return i}function cc(e,t,r){if(e==null)return e;var a=[],n=0;return fc(e,a,"","",function(o){return t.call(r,o,n++)}),a}function e_(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r)},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var $t={current:null},dc={transition:null},t_={ReactCurrentDispatcher:$t,ReactCurrentBatchConfig:dc,ReactCurrentOwner:ih};function YS(){throw Error("act(...) is not supported in production builds of React.")}ue.Children={map:cc,forEach:function(e,t,r){cc(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return cc(e,function(){t++}),t},toArray:function(e){return cc(e,function(t){return t})||[]},only:function(e){if(!lh(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};ue.Component=si;ue.Fragment=qN;ue.Profiler=VN;ue.PureComponent=nh;ue.StrictMode=HN;ue.Suspense=KN;ue.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=t_;ue.act=YS;ue.cloneElement=function(e,t,r){if(e==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var a=VS({},e.props),n=e.key,o=e.ref,i=e._owner;if(t!=null){if(t.ref!==void 0&&(o=t.ref,i=ih.current),t.key!==void 0&&(n=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(u in t)GS.call(t,u)&&!KS.hasOwnProperty(u)&&(a[u]=t[u]===void 0&&l!==void 0?l[u]:t[u])}var u=arguments.length-2;if(u===1)a.children=r;else if(1<u){l=Array(u);for(var s=0;s<u;s++)l[s]=arguments[s+2];a.children=l}return{$$typeof:Hl,type:e.type,key:n,ref:o,props:a,_owner:i}};ue.createContext=function(e){return e={$$typeof:$N,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null},e.Provider={$$typeof:WN,_context:e},e.Consumer=e};ue.createElement=XS;ue.createFactory=function(e){var t=XS.bind(null,e);return t.type=e,t};ue.createRef=function(){return{current:null}};ue.forwardRef=function(e){return{$$typeof:GN,render:e}};ue.isValidElement=lh;ue.lazy=function(e){return{$$typeof:YN,_payload:{_status:-1,_result:e},_init:e_}};ue.memo=function(e,t){return{$$typeof:XN,type:e,compare:t===void 0?null:t}};ue.startTransition=function(e){var t=dc.transition;dc.transition={};try{e()}finally{dc.transition=t}};ue.unstable_act=YS;ue.useCallback=function(e,t){return $t.current.useCallback(e,t)};ue.useContext=function(e){return $t.current.useContext(e)};ue.useDebugValue=function(){};ue.useDeferredValue=function(e){return $t.current.useDeferredValue(e)};ue.useEffect=function(e,t){return $t.current.useEffect(e,t)};ue.useId=function(){return $t.current.useId()};ue.useImperativeHandle=function(e,t,r){return $t.current.useImperativeHandle(e,t,r)};ue.useInsertionEffect=function(e,t){return $t.current.useInsertionEffect(e,t)};ue.useLayoutEffect=function(e,t){return $t.current.useLayoutEffect(e,t)};ue.useMemo=function(e,t){return $t.current.useMemo(e,t)};ue.useReducer=function(e,t,r){return $t.current.useReducer(e,t,r)};ue.useRef=function(e){return $t.current.useRef(e)};ue.useState=function(e){return $t.current.useState(e)};ue.useSyncExternalStore=function(e,t,r){return $t.current.useSyncExternalStore(e,t,r)};ue.useTransition=function(){return $t.current.useTransition()};ue.version="18.3.1"});var B=G((rK,QS)=>{"use strict";QS.exports=ZS()});var fb=G(Ee=>{"use strict";function fh(e,t){var r=e.length;e.push(t);e:for(;0<r;){var a=r-1>>>1,n=e[a];if(0<hc(n,t))e[a]=t,e[r]=n,r=a;else break e}}function Jr(e){return e.length===0?null:e[0]}function gc(e){if(e.length===0)return null;var t=e[0],r=e.pop();if(r!==t){e[0]=r;e:for(var a=0,n=e.length,o=n>>>1;a<o;){var i=2*(a+1)-1,l=e[i],u=i+1,s=e[u];if(0>hc(l,r))u<n&&0>hc(s,l)?(e[a]=s,e[u]=r,a=u):(e[a]=l,e[i]=r,a=i);else if(u<n&&0>hc(s,r))e[a]=s,e[u]=r,a=u;else break e}}return t}function hc(e,t){var r=e.sortIndex-t.sortIndex;return r!==0?r:e.id-t.id}typeof performance=="object"&&typeof performance.now=="function"?(rb=performance,Ee.unstable_now=function(){return rb.now()}):(uh=Date,ab=uh.now(),Ee.unstable_now=function(){return uh.now()-ab});var rb,uh,ab,xa=[],wn=[],r_=1,Dr=null,Dt=3,yc=!1,no=!1,Ql=!1,ib=typeof setTimeout=="function"?setTimeout:null,lb=typeof clearTimeout=="function"?clearTimeout:null,nb=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function dh(e){for(var t=Jr(wn);t!==null;){if(t.callback===null)gc(wn);else if(t.startTime<=e)gc(wn),t.sortIndex=t.expirationTime,fh(xa,t);else break;t=Jr(wn)}}function ph(e){if(Ql=!1,dh(e),!no)if(Jr(xa)!==null)no=!0,hh(mh);else{var t=Jr(wn);t!==null&&vh(ph,t.startTime-e)}}function mh(e,t){no=!1,Ql&&(Ql=!1,lb(Jl),Jl=-1),yc=!0;var r=Dt;try{for(dh(t),Dr=Jr(xa);Dr!==null&&(!(Dr.expirationTime>t)||e&&!cb());){var a=Dr.callback;if(typeof a=="function"){Dr.callback=null,Dt=Dr.priorityLevel;var n=a(Dr.expirationTime<=t);t=Ee.unstable_now(),typeof n=="function"?Dr.callback=n:Dr===Jr(xa)&&gc(xa),dh(t)}else gc(xa);Dr=Jr(xa)}if(Dr!==null)var o=!0;else{var i=Jr(wn);i!==null&&vh(ph,i.startTime-t),o=!1}return o}finally{Dr=null,Dt=r,yc=!1}}var xc=!1,vc=null,Jl=-1,ub=5,sb=-1;function cb(){return!(Ee.unstable_now()-sb<ub)}function sh(){if(vc!==null){var e=Ee.unstable_now();sb=e;var t=!0;try{t=vc(!0,e)}finally{t?Zl():(xc=!1,vc=null)}}else xc=!1}var Zl;typeof nb=="function"?Zl=function(){nb(sh)}:typeof MessageChannel<"u"?(ch=new MessageChannel,ob=ch.port2,ch.port1.onmessage=sh,Zl=function(){ob.postMessage(null)}):Zl=function(){ib(sh,0)};var ch,ob;function hh(e){vc=e,xc||(xc=!0,Zl())}function vh(e,t){Jl=ib(function(){e(Ee.unstable_now())},t)}Ee.unstable_IdlePriority=5;Ee.unstable_ImmediatePriority=1;Ee.unstable_LowPriority=4;Ee.unstable_NormalPriority=3;Ee.unstable_Profiling=null;Ee.unstable_UserBlockingPriority=2;Ee.unstable_cancelCallback=function(e){e.callback=null};Ee.unstable_continueExecution=function(){no||yc||(no=!0,hh(mh))};Ee.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):ub=0<e?Math.floor(1e3/e):5};Ee.unstable_getCurrentPriorityLevel=function(){return Dt};Ee.unstable_getFirstCallbackNode=function(){return Jr(xa)};Ee.unstable_next=function(e){switch(Dt){case 1:case 2:case 3:var t=3;break;default:t=Dt}var r=Dt;Dt=t;try{return e()}finally{Dt=r}};Ee.unstable_pauseExecution=function(){};Ee.unstable_requestPaint=function(){};Ee.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var r=Dt;Dt=e;try{return t()}finally{Dt=r}};Ee.unstable_scheduleCallback=function(e,t,r){var a=Ee.unstable_now();switch(typeof r=="object"&&r!==null?(r=r.delay,r=typeof r=="number"&&0<r?a+r:a):r=a,e){case 1:var n=-1;break;case 2:n=250;break;case 5:n=1073741823;break;case 4:n=1e4;break;default:n=5e3}return n=r+n,e={id:r_++,callback:t,priorityLevel:e,startTime:r,expirationTime:n,sortIndex:-1},r>a?(e.sortIndex=r,fh(wn,e),Jr(xa)===null&&e===Jr(wn)&&(Ql?(lb(Jl),Jl=-1):Ql=!0,vh(ph,r-a))):(e.sortIndex=n,fh(xa,e),no||yc||(no=!0,hh(mh))),e};Ee.unstable_shouldYield=cb;Ee.unstable_wrapCallback=function(e){var t=Dt;return function(){var r=Dt;Dt=t;try{return e.apply(this,arguments)}finally{Dt=r}}}});var pb=G((t7,db)=>{"use strict";db.exports=fb()});var gL=G(wr=>{"use strict";var a_=B(),yr=pb();function q(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=1;r<arguments.length;r++)t+="&args[]="+encodeURIComponent(arguments[r]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var wC=new Set,Su={};function yo(e,t){Ei(e,t),Ei(e+"Capture",t)}function Ei(e,t){for(Su[e]=t,e=0;e<t.length;e++)wC.add(t[e])}var qa=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Bh=Object.prototype.hasOwnProperty,n_=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,mb={},hb={};function o_(e){return Bh.call(hb,e)?!0:Bh.call(mb,e)?!1:n_.test(e)?hb[e]=!0:(mb[e]=!0,!1)}function i_(e,t,r,a){if(r!==null&&r.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return a?!1:r!==null?!r.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function l_(e,t,r,a){if(t===null||typeof t>"u"||i_(e,t,r,a))return!0;if(a)return!1;if(r!==null)switch(r.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Xt(e,t,r,a,n,o,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=a,this.attributeNamespace=n,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var Pt={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Pt[e]=new Xt(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Pt[t]=new Xt(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Pt[e]=new Xt(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Pt[e]=new Xt(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Pt[e]=new Xt(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Pt[e]=new Xt(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Pt[e]=new Xt(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Pt[e]=new Xt(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Pt[e]=new Xt(e,5,!1,e.toLowerCase(),null,!1,!1)});var Dv=/[\-:]([a-z])/g;function Mv(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Dv,Mv);Pt[t]=new Xt(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Dv,Mv);Pt[t]=new Xt(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Dv,Mv);Pt[t]=new Xt(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Pt[e]=new Xt(e,1,!1,e.toLowerCase(),null,!1,!1)});Pt.xlinkHref=new Xt("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Pt[e]=new Xt(e,1,!1,e.toLowerCase(),null,!0,!0)});function Tv(e,t,r,a){var n=Pt.hasOwnProperty(t)?Pt[t]:null;(n!==null?n.type!==0:a||!(2<t.length)||t[0]!=="o"&&t[0]!=="O"||t[1]!=="n"&&t[1]!=="N")&&(l_(t,r,n,a)&&(r=null),a||n===null?o_(t)&&(r===null?e.removeAttribute(t):e.setAttribute(t,""+r)):n.mustUseProperty?e[n.propertyName]=r===null?n.type===3?!1:"":r:(t=n.attributeName,a=n.attributeNamespace,r===null?e.removeAttribute(t):(n=n.type,r=n===3||n===4&&r===!0?"":""+r,a?e.setAttributeNS(a,t,r):e.setAttribute(t,r))))}var $a=a_.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,wc=Symbol.for("react.element"),di=Symbol.for("react.portal"),pi=Symbol.for("react.fragment"),Rv=Symbol.for("react.strict_mode"),zh=Symbol.for("react.profiler"),SC=Symbol.for("react.provider"),bC=Symbol.for("react.context"),Nv=Symbol.for("react.forward_ref"),Uh=Symbol.for("react.suspense"),qh=Symbol.for("react.suspense_list"),_v=Symbol.for("react.memo"),bn=Symbol.for("react.lazy"),CC=Symbol.for("react.offscreen"),vb=Symbol.iterator;function eu(e){return e===null||typeof e!="object"?null:(e=vb&&e[vb]||e["@@iterator"],typeof e=="function"?e:null)}var He=Object.assign,gh;function uu(e){if(gh===void 0)try{throw Error()}catch(r){var t=r.stack.trim().match(/\n( *(at )?)/);gh=t&&t[1]||""}return`
1
+ "use strict";var MCPEvalApp=(()=>{var TN=Object.create;var sc=Object.defineProperty;var RN=Object.getOwnPropertyDescriptor;var NN=Object.getOwnPropertyNames;var _N=Object.getPrototypeOf,FN=Object.prototype.hasOwnProperty;var jN=(e,t,r)=>t in e?sc(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var G=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}},BN=(e,t)=>{for(var r in t)sc(e,r,{get:t[r],enumerable:!0})},zN=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of NN(t))!FN.call(e,n)&&n!==r&&sc(e,n,{get:()=>t[n],enumerable:!(a=RN(t,n))||a.enumerable});return e};var D=(e,t,r)=>(r=e!=null?TN(_N(e)):{},zN(t||!e||!e.__esModule?sc(r,"default",{value:e,enumerable:!0}):r,e));var ui=(e,t,r)=>jN(e,typeof t!="symbol"?t+"":t,r);var ZS=G(ue=>{"use strict";var Hl=Symbol.for("react.element"),UN=Symbol.for("react.portal"),qN=Symbol.for("react.fragment"),HN=Symbol.for("react.strict_mode"),VN=Symbol.for("react.profiler"),WN=Symbol.for("react.provider"),$N=Symbol.for("react.context"),GN=Symbol.for("react.forward_ref"),KN=Symbol.for("react.suspense"),XN=Symbol.for("react.memo"),YN=Symbol.for("react.lazy"),zS=Symbol.iterator;function ZN(e){return e===null||typeof e!="object"?null:(e=zS&&e[zS]||e["@@iterator"],typeof e=="function"?e:null)}var HS={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},VS=Object.assign,WS={};function si(e,t,r){this.props=e,this.context=t,this.refs=WS,this.updater=r||HS}si.prototype.isReactComponent={};si.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};si.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function $S(){}$S.prototype=si.prototype;function nh(e,t,r){this.props=e,this.context=t,this.refs=WS,this.updater=r||HS}var oh=nh.prototype=new $S;oh.constructor=nh;VS(oh,si.prototype);oh.isPureReactComponent=!0;var US=Array.isArray,GS=Object.prototype.hasOwnProperty,ih={current:null},KS={key:!0,ref:!0,__self:!0,__source:!0};function XS(e,t,r){var a,n={},o=null,i=null;if(t!=null)for(a in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(o=""+t.key),t)GS.call(t,a)&&!KS.hasOwnProperty(a)&&(n[a]=t[a]);var l=arguments.length-2;if(l===1)n.children=r;else if(1<l){for(var u=Array(l),s=0;s<l;s++)u[s]=arguments[s+2];n.children=u}if(e&&e.defaultProps)for(a in l=e.defaultProps,l)n[a]===void 0&&(n[a]=l[a]);return{$$typeof:Hl,type:e,key:o,ref:i,props:n,_owner:ih.current}}function QN(e,t){return{$$typeof:Hl,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}function lh(e){return typeof e=="object"&&e!==null&&e.$$typeof===Hl}function JN(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(r){return t[r]})}var qS=/\/+/g;function ah(e,t){return typeof e=="object"&&e!==null&&e.key!=null?JN(""+e.key):t.toString(36)}function fc(e,t,r,a,n){var o=typeof e;(o==="undefined"||o==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(o){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Hl:case UN:i=!0}}if(i)return i=e,n=n(i),e=a===""?"."+ah(i,0):a,US(n)?(r="",e!=null&&(r=e.replace(qS,"$&/")+"/"),fc(n,t,r,"",function(s){return s})):n!=null&&(lh(n)&&(n=QN(n,r+(!n.key||i&&i.key===n.key?"":(""+n.key).replace(qS,"$&/")+"/")+e)),t.push(n)),1;if(i=0,a=a===""?".":a+":",US(e))for(var l=0;l<e.length;l++){o=e[l];var u=a+ah(o,l);i+=fc(o,t,r,u,n)}else if(u=ZN(e),typeof u=="function")for(e=u.call(e),l=0;!(o=e.next()).done;)o=o.value,u=a+ah(o,l++),i+=fc(o,t,r,u,n);else if(o==="object")throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return i}function cc(e,t,r){if(e==null)return e;var a=[],n=0;return fc(e,a,"","",function(o){return t.call(r,o,n++)}),a}function e_(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r)},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var $t={current:null},dc={transition:null},t_={ReactCurrentDispatcher:$t,ReactCurrentBatchConfig:dc,ReactCurrentOwner:ih};function YS(){throw Error("act(...) is not supported in production builds of React.")}ue.Children={map:cc,forEach:function(e,t,r){cc(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return cc(e,function(){t++}),t},toArray:function(e){return cc(e,function(t){return t})||[]},only:function(e){if(!lh(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};ue.Component=si;ue.Fragment=qN;ue.Profiler=VN;ue.PureComponent=nh;ue.StrictMode=HN;ue.Suspense=KN;ue.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=t_;ue.act=YS;ue.cloneElement=function(e,t,r){if(e==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var a=VS({},e.props),n=e.key,o=e.ref,i=e._owner;if(t!=null){if(t.ref!==void 0&&(o=t.ref,i=ih.current),t.key!==void 0&&(n=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(u in t)GS.call(t,u)&&!KS.hasOwnProperty(u)&&(a[u]=t[u]===void 0&&l!==void 0?l[u]:t[u])}var u=arguments.length-2;if(u===1)a.children=r;else if(1<u){l=Array(u);for(var s=0;s<u;s++)l[s]=arguments[s+2];a.children=l}return{$$typeof:Hl,type:e.type,key:n,ref:o,props:a,_owner:i}};ue.createContext=function(e){return e={$$typeof:$N,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null},e.Provider={$$typeof:WN,_context:e},e.Consumer=e};ue.createElement=XS;ue.createFactory=function(e){var t=XS.bind(null,e);return t.type=e,t};ue.createRef=function(){return{current:null}};ue.forwardRef=function(e){return{$$typeof:GN,render:e}};ue.isValidElement=lh;ue.lazy=function(e){return{$$typeof:YN,_payload:{_status:-1,_result:e},_init:e_}};ue.memo=function(e,t){return{$$typeof:XN,type:e,compare:t===void 0?null:t}};ue.startTransition=function(e){var t=dc.transition;dc.transition={};try{e()}finally{dc.transition=t}};ue.unstable_act=YS;ue.useCallback=function(e,t){return $t.current.useCallback(e,t)};ue.useContext=function(e){return $t.current.useContext(e)};ue.useDebugValue=function(){};ue.useDeferredValue=function(e){return $t.current.useDeferredValue(e)};ue.useEffect=function(e,t){return $t.current.useEffect(e,t)};ue.useId=function(){return $t.current.useId()};ue.useImperativeHandle=function(e,t,r){return $t.current.useImperativeHandle(e,t,r)};ue.useInsertionEffect=function(e,t){return $t.current.useInsertionEffect(e,t)};ue.useLayoutEffect=function(e,t){return $t.current.useLayoutEffect(e,t)};ue.useMemo=function(e,t){return $t.current.useMemo(e,t)};ue.useReducer=function(e,t,r){return $t.current.useReducer(e,t,r)};ue.useRef=function(e){return $t.current.useRef(e)};ue.useState=function(e){return $t.current.useState(e)};ue.useSyncExternalStore=function(e,t,r){return $t.current.useSyncExternalStore(e,t,r)};ue.useTransition=function(){return $t.current.useTransition()};ue.version="18.3.1"});var B=G((rK,QS)=>{"use strict";QS.exports=ZS()});var fb=G(Ee=>{"use strict";function fh(e,t){var r=e.length;e.push(t);e:for(;0<r;){var a=r-1>>>1,n=e[a];if(0<hc(n,t))e[a]=t,e[r]=n,r=a;else break e}}function Jr(e){return e.length===0?null:e[0]}function gc(e){if(e.length===0)return null;var t=e[0],r=e.pop();if(r!==t){e[0]=r;e:for(var a=0,n=e.length,o=n>>>1;a<o;){var i=2*(a+1)-1,l=e[i],u=i+1,s=e[u];if(0>hc(l,r))u<n&&0>hc(s,l)?(e[a]=s,e[u]=r,a=u):(e[a]=l,e[i]=r,a=i);else if(u<n&&0>hc(s,r))e[a]=s,e[u]=r,a=u;else break e}}return t}function hc(e,t){var r=e.sortIndex-t.sortIndex;return r!==0?r:e.id-t.id}typeof performance=="object"&&typeof performance.now=="function"?(rb=performance,Ee.unstable_now=function(){return rb.now()}):(uh=Date,ab=uh.now(),Ee.unstable_now=function(){return uh.now()-ab});var rb,uh,ab,xa=[],wn=[],r_=1,Dr=null,Dt=3,yc=!1,no=!1,Ql=!1,ib=typeof setTimeout=="function"?setTimeout:null,lb=typeof clearTimeout=="function"?clearTimeout:null,nb=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function dh(e){for(var t=Jr(wn);t!==null;){if(t.callback===null)gc(wn);else if(t.startTime<=e)gc(wn),t.sortIndex=t.expirationTime,fh(xa,t);else break;t=Jr(wn)}}function ph(e){if(Ql=!1,dh(e),!no)if(Jr(xa)!==null)no=!0,hh(mh);else{var t=Jr(wn);t!==null&&vh(ph,t.startTime-e)}}function mh(e,t){no=!1,Ql&&(Ql=!1,lb(Jl),Jl=-1),yc=!0;var r=Dt;try{for(dh(t),Dr=Jr(xa);Dr!==null&&(!(Dr.expirationTime>t)||e&&!cb());){var a=Dr.callback;if(typeof a=="function"){Dr.callback=null,Dt=Dr.priorityLevel;var n=a(Dr.expirationTime<=t);t=Ee.unstable_now(),typeof n=="function"?Dr.callback=n:Dr===Jr(xa)&&gc(xa),dh(t)}else gc(xa);Dr=Jr(xa)}if(Dr!==null)var o=!0;else{var i=Jr(wn);i!==null&&vh(ph,i.startTime-t),o=!1}return o}finally{Dr=null,Dt=r,yc=!1}}var xc=!1,vc=null,Jl=-1,ub=5,sb=-1;function cb(){return!(Ee.unstable_now()-sb<ub)}function sh(){if(vc!==null){var e=Ee.unstable_now();sb=e;var t=!0;try{t=vc(!0,e)}finally{t?Zl():(xc=!1,vc=null)}}else xc=!1}var Zl;typeof nb=="function"?Zl=function(){nb(sh)}:typeof MessageChannel<"u"?(ch=new MessageChannel,ob=ch.port2,ch.port1.onmessage=sh,Zl=function(){ob.postMessage(null)}):Zl=function(){ib(sh,0)};var ch,ob;function hh(e){vc=e,xc||(xc=!0,Zl())}function vh(e,t){Jl=ib(function(){e(Ee.unstable_now())},t)}Ee.unstable_IdlePriority=5;Ee.unstable_ImmediatePriority=1;Ee.unstable_LowPriority=4;Ee.unstable_NormalPriority=3;Ee.unstable_Profiling=null;Ee.unstable_UserBlockingPriority=2;Ee.unstable_cancelCallback=function(e){e.callback=null};Ee.unstable_continueExecution=function(){no||yc||(no=!0,hh(mh))};Ee.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):ub=0<e?Math.floor(1e3/e):5};Ee.unstable_getCurrentPriorityLevel=function(){return Dt};Ee.unstable_getFirstCallbackNode=function(){return Jr(xa)};Ee.unstable_next=function(e){switch(Dt){case 1:case 2:case 3:var t=3;break;default:t=Dt}var r=Dt;Dt=t;try{return e()}finally{Dt=r}};Ee.unstable_pauseExecution=function(){};Ee.unstable_requestPaint=function(){};Ee.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var r=Dt;Dt=e;try{return t()}finally{Dt=r}};Ee.unstable_scheduleCallback=function(e,t,r){var a=Ee.unstable_now();switch(typeof r=="object"&&r!==null?(r=r.delay,r=typeof r=="number"&&0<r?a+r:a):r=a,e){case 1:var n=-1;break;case 2:n=250;break;case 5:n=1073741823;break;case 4:n=1e4;break;default:n=5e3}return n=r+n,e={id:r_++,callback:t,priorityLevel:e,startTime:r,expirationTime:n,sortIndex:-1},r>a?(e.sortIndex=r,fh(wn,e),Jr(xa)===null&&e===Jr(wn)&&(Ql?(lb(Jl),Jl=-1):Ql=!0,vh(ph,r-a))):(e.sortIndex=n,fh(xa,e),no||yc||(no=!0,hh(mh))),e};Ee.unstable_shouldYield=cb;Ee.unstable_wrapCallback=function(e){var t=Dt;return function(){var r=Dt;Dt=t;try{return e.apply(this,arguments)}finally{Dt=r}}}});var pb=G((t7,db)=>{"use strict";db.exports=fb()});var gL=G(wr=>{"use strict";var a_=B(),yr=pb();function q(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,r=1;r<arguments.length;r++)t+="&args[]="+encodeURIComponent(arguments[r]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var wC=new Set,Su={};function yo(e,t){Ei(e,t),Ei(e+"Capture",t)}function Ei(e,t){for(Su[e]=t,e=0;e<t.length;e++)wC.add(t[e])}var qa=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Bh=Object.prototype.hasOwnProperty,n_=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,mb={},hb={};function o_(e){return Bh.call(hb,e)?!0:Bh.call(mb,e)?!1:n_.test(e)?hb[e]=!0:(mb[e]=!0,!1)}function i_(e,t,r,a){if(r!==null&&r.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return a?!1:r!==null?!r.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function l_(e,t,r,a){if(t===null||typeof t>"u"||i_(e,t,r,a))return!0;if(a)return!1;if(r!==null)switch(r.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Xt(e,t,r,a,n,o,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=a,this.attributeNamespace=n,this.mustUseProperty=r,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var Pt={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Pt[e]=new Xt(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Pt[t]=new Xt(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Pt[e]=new Xt(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Pt[e]=new Xt(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Pt[e]=new Xt(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Pt[e]=new Xt(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Pt[e]=new Xt(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Pt[e]=new Xt(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Pt[e]=new Xt(e,5,!1,e.toLowerCase(),null,!1,!1)});var Dv=/[\-:]([a-z])/g;function Mv(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Dv,Mv);Pt[t]=new Xt(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Dv,Mv);Pt[t]=new Xt(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Dv,Mv);Pt[t]=new Xt(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Pt[e]=new Xt(e,1,!1,e.toLowerCase(),null,!1,!1)});Pt.xlinkHref=new Xt("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Pt[e]=new Xt(e,1,!1,e.toLowerCase(),null,!0,!0)});function Tv(e,t,r,a){var n=Pt.hasOwnProperty(t)?Pt[t]:null;(n!==null?n.type!==0:a||!(2<t.length)||t[0]!=="o"&&t[0]!=="O"||t[1]!=="n"&&t[1]!=="N")&&(l_(t,r,n,a)&&(r=null),a||n===null?o_(t)&&(r===null?e.removeAttribute(t):e.setAttribute(t,""+r)):n.mustUseProperty?e[n.propertyName]=r===null?n.type===3?!1:"":r:(t=n.attributeName,a=n.attributeNamespace,r===null?e.removeAttribute(t):(n=n.type,r=n===3||n===4&&r===!0?"":""+r,a?e.setAttributeNS(a,t,r):e.setAttribute(t,r))))}var $a=a_.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,wc=Symbol.for("react.element"),di=Symbol.for("react.portal"),pi=Symbol.for("react.fragment"),Rv=Symbol.for("react.strict_mode"),zh=Symbol.for("react.profiler"),SC=Symbol.for("react.provider"),bC=Symbol.for("react.context"),Nv=Symbol.for("react.forward_ref"),Uh=Symbol.for("react.suspense"),qh=Symbol.for("react.suspense_list"),_v=Symbol.for("react.memo"),bn=Symbol.for("react.lazy"),CC=Symbol.for("react.offscreen"),vb=Symbol.iterator;function eu(e){return e===null||typeof e!="object"?null:(e=vb&&e[vb]||e["@@iterator"],typeof e=="function"?e:null)}var He=Object.assign,gh;function uu(e){if(gh===void 0)try{throw Error()}catch(r){var t=r.stack.trim().match(/\n( *(at )?)/);gh=t&&t[1]||""}return`
2
2
  `+gh+e}var yh=!1;function xh(e,t){if(!e||yh)return"";yh=!0;var r=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(t,[])}catch(s){var a=s}Reflect.construct(e,[],t)}else{try{t.call()}catch(s){a=s}e.call(t.prototype)}else{try{throw Error()}catch(s){a=s}e()}}catch(s){if(s&&a&&typeof s.stack=="string"){for(var n=s.stack.split(`
3
3
  `),o=a.stack.split(`
4
4
  `),i=n.length-1,l=o.length-1;1<=i&&0<=l&&n[i]!==o[l];)l--;for(;1<=i&&0<=l;i--,l--)if(n[i]!==o[l]){if(i!==1||l!==1)do if(i--,l--,0>l||n[i]!==o[l]){var u=`
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ // src/assertions/validators/types.ts
4
+ var SnapshotSanitizers = {
5
+ /** Replaces Unix timestamps (seconds and milliseconds) with a stable placeholder */
6
+ TIMESTAMP: "timestamp",
7
+ /** Replaces UUID v1-v5 strings with a stable placeholder */
8
+ UUID: "uuid",
9
+ /** Replaces ISO 8601 date/datetime strings with a stable placeholder */
10
+ ISO_DATE: "iso-date",
11
+ /** Replaces MongoDB ObjectId strings with a stable placeholder */
12
+ OBJECT_ID: "objectId",
13
+ /** Replaces JWT tokens with a stable placeholder */
14
+ JWT: "jwt"
15
+ };
16
+
17
+ exports.SnapshotSanitizers = SnapshotSanitizers;
18
+ //# sourceMappingURL=index.cjs.map
19
+ //# sourceMappingURL=index.cjs.map