@bryan-thompson/inspector-assessment-client 1.34.1 → 1.35.1

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/dist/assets/{OAuthCallback-C27_rGpA.js → OAuthCallback-DC1cIXHT.js} +1 -1
  2. package/dist/assets/{OAuthDebugCallback-DpgDVJTf.js → OAuthDebugCallback-C3gqJjgQ.js} +1 -1
  3. package/dist/assets/{index-BX8lZxC_.js → index-Dn2w887x.js} +5 -4
  4. package/dist/index.html +1 -1
  5. package/lib/lib/assessment/configSchemas.d.ts +12 -12
  6. package/lib/lib/assessment/jsonlEventSchemas.d.ts +79 -1
  7. package/lib/lib/assessment/jsonlEventSchemas.d.ts.map +1 -1
  8. package/lib/lib/assessment/jsonlEventSchemas.js +31 -1
  9. package/lib/lib/assessment/progressTypes.d.ts +17 -1
  10. package/lib/lib/assessment/progressTypes.d.ts.map +1 -1
  11. package/lib/lib/assessment/resultTypes.d.ts +64 -0
  12. package/lib/lib/assessment/resultTypes.d.ts.map +1 -1
  13. package/lib/lib/assessment/sharedSchemas.d.ts +13 -0
  14. package/lib/lib/assessment/sharedSchemas.d.ts.map +1 -1
  15. package/lib/lib/assessment/sharedSchemas.js +9 -0
  16. package/lib/lib/assessment/summarizer/AssessmentSummarizer.d.ts +112 -0
  17. package/lib/lib/assessment/summarizer/AssessmentSummarizer.d.ts.map +1 -0
  18. package/lib/lib/assessment/summarizer/AssessmentSummarizer.js +452 -0
  19. package/lib/lib/assessment/summarizer/index.d.ts +19 -0
  20. package/lib/lib/assessment/summarizer/index.d.ts.map +1 -0
  21. package/lib/lib/assessment/summarizer/index.js +19 -0
  22. package/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.d.ts +36 -0
  23. package/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.d.ts.map +1 -0
  24. package/lib/lib/assessment/summarizer/stageBEnrichmentBuilder.js +282 -0
  25. package/lib/lib/assessment/summarizer/stageBTypes.d.ts +154 -0
  26. package/lib/lib/assessment/summarizer/stageBTypes.d.ts.map +1 -0
  27. package/lib/lib/assessment/summarizer/stageBTypes.js +24 -0
  28. package/lib/lib/assessment/summarizer/tokenEstimator.d.ts +103 -0
  29. package/lib/lib/assessment/summarizer/tokenEstimator.d.ts.map +1 -0
  30. package/lib/lib/assessment/summarizer/tokenEstimator.js +225 -0
  31. package/lib/lib/assessment/summarizer/types.d.ts +187 -0
  32. package/lib/lib/assessment/summarizer/types.d.ts.map +1 -0
  33. package/lib/lib/assessment/summarizer/types.js +20 -0
  34. package/lib/lib/moduleScoring.d.ts +6 -1
  35. package/lib/lib/moduleScoring.d.ts.map +1 -1
  36. package/lib/lib/moduleScoring.js +6 -1
  37. package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
  38. package/lib/services/assessment/modules/SecurityAssessor.js +37 -3
  39. package/lib/services/assessment/modules/securityTests/TestValidityAnalyzer.d.ts +118 -0
  40. package/lib/services/assessment/modules/securityTests/TestValidityAnalyzer.d.ts.map +1 -0
  41. package/lib/services/assessment/modules/securityTests/TestValidityAnalyzer.js +403 -0
  42. package/lib/services/assessment/modules/securityTests/index.d.ts +1 -0
  43. package/lib/services/assessment/modules/securityTests/index.d.ts.map +1 -1
  44. package/lib/services/assessment/modules/securityTests/index.js +1 -0
  45. package/package.json +1 -1
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Test Validity Analyzer
3
+ *
4
+ * Detects when security test responses are suspiciously uniform,
5
+ * indicating tests may not have reached security-relevant code paths.
6
+ *
7
+ * @see Issue #134: Detect identical security test responses (test validity masking)
8
+ */
9
+ const DEFAULT_CONFIG = {
10
+ warningThresholdPercent: 80,
11
+ confidenceReduceThresholdPercent: 90,
12
+ minimumTestsForAnalysis: 10,
13
+ maxResponseCompareLength: 1000,
14
+ // Issue #135: Enhanced data defaults
15
+ maxSamplePairs: 10,
16
+ maxDistributionEntries: 5,
17
+ };
18
+ /**
19
+ * Analyzes security test results for response uniformity.
20
+ *
21
+ * When a high percentage of test responses are identical, it indicates
22
+ * that tests may be hitting a configuration error, connection issue,
23
+ * or other problem that prevents them from reaching security-relevant code.
24
+ */
25
+ export class TestValidityAnalyzer {
26
+ config;
27
+ constructor(config) {
28
+ this.config = { ...DEFAULT_CONFIG, ...config };
29
+ }
30
+ /**
31
+ * Analyze test results for response uniformity
32
+ *
33
+ * @param testResults - Array of security test results with responses
34
+ * @returns Analysis result with warning details if uniformity detected
35
+ */
36
+ analyze(testResults) {
37
+ // Filter to tests with responses
38
+ const testsWithResponses = testResults.filter((t) => t.response !== undefined && t.response !== null);
39
+ // Need minimum number of tests for meaningful analysis
40
+ if (testsWithResponses.length < this.config.minimumTestsForAnalysis) {
41
+ return {
42
+ isCompromised: false,
43
+ warningLevel: "none",
44
+ recommendedConfidence: "high",
45
+ };
46
+ }
47
+ // Count response frequency with normalization
48
+ const responseCounts = this.countNormalizedResponses(testsWithResponses);
49
+ // Find most common response
50
+ const [mostCommonResponse, mostCommonCount] = this.findMostCommon(responseCounts);
51
+ const percentageIdentical = (mostCommonCount / testsWithResponses.length) * 100;
52
+ // Detect pattern category
53
+ const detectedPattern = this.detectPatternCategory(mostCommonResponse);
54
+ // Per-tool analysis
55
+ const toolUniformity = this.analyzePerTool(testResults);
56
+ // Determine warning level
57
+ let warningLevel = "none";
58
+ let recommendedConfidence = "high";
59
+ if (percentageIdentical >= this.config.confidenceReduceThresholdPercent) {
60
+ warningLevel = "critical";
61
+ recommendedConfidence = "low";
62
+ }
63
+ else if (percentageIdentical >= this.config.warningThresholdPercent) {
64
+ warningLevel = "warning";
65
+ recommendedConfidence = "medium";
66
+ }
67
+ const isCompromised = warningLevel !== "none";
68
+ // Find the original (non-normalized) sample response for display
69
+ const sampleResponse = this.findOriginalSample(testsWithResponses, mostCommonResponse);
70
+ return {
71
+ isCompromised,
72
+ warningLevel,
73
+ recommendedConfidence,
74
+ warning: isCompromised
75
+ ? {
76
+ // Existing fields
77
+ identicalResponseCount: mostCommonCount,
78
+ totalResponses: testsWithResponses.length,
79
+ percentageIdentical: Math.round(percentageIdentical * 10) / 10,
80
+ sampleResponse: sampleResponse.substring(0, 500),
81
+ detectedPattern,
82
+ explanation: this.generateExplanation(percentageIdentical, detectedPattern, mostCommonCount, testsWithResponses.length),
83
+ // Issue #135: Enhanced fields for Stage B semantic analysis
84
+ responseDiversity: {
85
+ uniqueResponses: responseCounts.size,
86
+ entropyScore: Math.round(this.calculateEntropy(responseCounts) * 100) / 100,
87
+ distribution: this.buildResponseDistribution(responseCounts, testsWithResponses.length),
88
+ },
89
+ toolUniformity: Object.fromEntries(toolUniformity),
90
+ attackPatternCorrelation: this.analyzeAttackPatterns(testsWithResponses),
91
+ samplePairs: this.collectSamplePairs(testsWithResponses),
92
+ responseMetadata: this.collectResponseMetadata(testsWithResponses),
93
+ }
94
+ : undefined,
95
+ toolUniformity,
96
+ };
97
+ }
98
+ /**
99
+ * Normalize response for comparison.
100
+ * Removes timestamps, UUIDs, request IDs, and other variable content.
101
+ */
102
+ normalizeResponse(response) {
103
+ let normalized = response.substring(0, this.config.maxResponseCompareLength);
104
+ // Remove common variable patterns
105
+ normalized = normalized
106
+ // ISO timestamps
107
+ .replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[.\d]*Z?/g, "<TIMESTAMP>")
108
+ // Unix timestamps (10-13 digits)
109
+ .replace(/\b\d{10,13}\b/g, "<TIMESTAMP>")
110
+ // UUIDs
111
+ .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "<UUID>")
112
+ // Request/correlation IDs (common patterns)
113
+ .replace(/"(?:request_?id|correlation_?id|trace_?id)"\s*:\s*"[^"]+"/gi, '"<ID>": "<VALUE>"')
114
+ // Generic hex IDs (16+ chars)
115
+ .replace(/\b[0-9a-f]{16,}\b/gi, "<HEX_ID>")
116
+ // Normalize whitespace
117
+ .replace(/\s+/g, " ")
118
+ .trim()
119
+ .toLowerCase();
120
+ return normalized;
121
+ }
122
+ /**
123
+ * Count occurrences of normalized responses
124
+ */
125
+ countNormalizedResponses(tests) {
126
+ const counts = new Map();
127
+ for (const test of tests) {
128
+ if (test.response) {
129
+ const normalized = this.normalizeResponse(test.response);
130
+ counts.set(normalized, (counts.get(normalized) ?? 0) + 1);
131
+ }
132
+ }
133
+ return counts;
134
+ }
135
+ /**
136
+ * Find the most common response
137
+ */
138
+ findMostCommon(counts) {
139
+ let maxCount = 0;
140
+ let mostCommon = "";
141
+ for (const [response, count] of counts) {
142
+ if (count > maxCount) {
143
+ maxCount = count;
144
+ mostCommon = response;
145
+ }
146
+ }
147
+ return [mostCommon, maxCount];
148
+ }
149
+ /**
150
+ * Find original (non-normalized) sample that matches the normalized pattern
151
+ */
152
+ findOriginalSample(tests, normalizedPattern) {
153
+ for (const test of tests) {
154
+ if (test.response) {
155
+ const normalized = this.normalizeResponse(test.response);
156
+ if (normalized === normalizedPattern) {
157
+ return test.response;
158
+ }
159
+ }
160
+ }
161
+ return normalizedPattern;
162
+ }
163
+ /**
164
+ * Detect the category of the response pattern
165
+ */
166
+ detectPatternCategory(response) {
167
+ const lower = response.toLowerCase();
168
+ // Configuration errors
169
+ if (/api[_\s]?key|credentials?|auth|token|secret|config/i.test(lower) &&
170
+ /missing|invalid|required|not found|error/i.test(lower)) {
171
+ return "configuration_error";
172
+ }
173
+ // Connection errors
174
+ if (/connection|refused|econnrefused|timeout|unreachable|network|socket/i.test(lower)) {
175
+ return "connection_error";
176
+ }
177
+ // Timeout
178
+ if (/timeout|timed?\s*out|exceeded/i.test(lower)) {
179
+ return "timeout";
180
+ }
181
+ // Empty responses
182
+ if (response.length < 50 ||
183
+ /^(\s*\{\s*\}|\s*\[\s*\]|\s*null\s*|)$/i.test(response.trim())) {
184
+ return "empty_response";
185
+ }
186
+ // Generic error
187
+ if (/error|exception|fail|invalid/i.test(lower)) {
188
+ return "generic_error";
189
+ }
190
+ return "unknown";
191
+ }
192
+ /**
193
+ * Analyze uniformity per tool
194
+ */
195
+ analyzePerTool(tests) {
196
+ const result = new Map();
197
+ const toolTests = new Map();
198
+ // Group by tool
199
+ for (const test of tests) {
200
+ const toolName = test.toolName ?? "unknown";
201
+ if (!toolTests.has(toolName)) {
202
+ toolTests.set(toolName, []);
203
+ }
204
+ toolTests.get(toolName).push(test);
205
+ }
206
+ // Analyze each tool
207
+ for (const [toolName, toolTestResults] of toolTests) {
208
+ const testsWithResponse = toolTestResults.filter((t) => t.response);
209
+ const counts = this.countNormalizedResponses(testsWithResponse);
210
+ const [, maxCount] = this.findMostCommon(counts);
211
+ const total = testsWithResponse.length;
212
+ if (total > 0) {
213
+ result.set(toolName, {
214
+ identicalCount: maxCount,
215
+ totalCount: total,
216
+ percentageIdentical: Math.round((maxCount / total) * 100 * 10) / 10,
217
+ });
218
+ }
219
+ }
220
+ return result;
221
+ }
222
+ /**
223
+ * Generate human-readable explanation
224
+ */
225
+ generateExplanation(percentage, pattern, identicalCount, totalCount) {
226
+ const patternDescriptions = {
227
+ configuration_error: "a configuration error (e.g., missing API key)",
228
+ connection_error: "a connection failure",
229
+ timeout: "request timeouts",
230
+ empty_response: "empty responses",
231
+ generic_error: "a generic error",
232
+ unknown: "an unknown pattern",
233
+ };
234
+ const patternDesc = patternDescriptions[pattern] ?? patternDescriptions.unknown;
235
+ return `${Math.round(percentage)}% of security tests (${identicalCount}/${totalCount}) returned identical responses indicating ${patternDesc}. Tests may not have reached security-relevant code paths. Resolve the underlying issue and re-run the assessment for valid security analysis.`;
236
+ }
237
+ // ==========================================================================
238
+ // Issue #135: Enhanced data methods for Stage B semantic analysis
239
+ // ==========================================================================
240
+ /**
241
+ * Calculate Shannon entropy for response diversity (0=uniform, 1=max diversity)
242
+ */
243
+ calculateEntropy(counts) {
244
+ const total = Array.from(counts.values()).reduce((a, b) => a + b, 0);
245
+ if (total === 0)
246
+ return 0;
247
+ let entropy = 0;
248
+ for (const count of counts.values()) {
249
+ if (count > 0) {
250
+ const p = count / total;
251
+ entropy -= p * Math.log2(p);
252
+ }
253
+ }
254
+ // Normalize to 0-1 scale based on max possible entropy
255
+ const maxEntropy = Math.log2(counts.size);
256
+ return maxEntropy > 0 ? entropy / maxEntropy : 0;
257
+ }
258
+ /**
259
+ * Build response distribution sorted by frequency
260
+ */
261
+ buildResponseDistribution(counts, total) {
262
+ return Array.from(counts.entries())
263
+ .sort((a, b) => b[1] - a[1])
264
+ .slice(0, this.config.maxDistributionEntries)
265
+ .map(([response, count]) => ({
266
+ response: response.substring(0, 200),
267
+ count,
268
+ percentage: Math.round((count / total) * 1000) / 10,
269
+ }));
270
+ }
271
+ /**
272
+ * Extract attack category from test name
273
+ */
274
+ extractAttackCategory(testName) {
275
+ const lower = testName.toLowerCase();
276
+ if (lower.includes("injection") || lower.includes("sqli"))
277
+ return "injection";
278
+ if (lower.includes("xss") || lower.includes("script"))
279
+ return "xss";
280
+ if (lower.includes("path") || lower.includes("traversal"))
281
+ return "path_traversal";
282
+ if (lower.includes("command") || lower.includes("rce"))
283
+ return "command_injection";
284
+ if (lower.includes("ssrf"))
285
+ return "ssrf";
286
+ if (lower.includes("auth"))
287
+ return "authentication";
288
+ return "other";
289
+ }
290
+ /**
291
+ * Analyze attack pattern correlation by category
292
+ */
293
+ analyzeAttackPatterns(tests) {
294
+ const patterns = new Map();
295
+ // Group by attack category
296
+ for (const test of tests) {
297
+ const category = this.extractAttackCategory(test.testName);
298
+ if (!patterns.has(category))
299
+ patterns.set(category, []);
300
+ patterns.get(category).push(test);
301
+ }
302
+ // Build correlation stats
303
+ const result = {};
304
+ for (const [category, categoryTests] of patterns) {
305
+ const withResponse = categoryTests.filter((t) => t.response);
306
+ const counts = this.countNormalizedResponses(withResponse);
307
+ result[category] = {
308
+ testCount: categoryTests.length,
309
+ uniqueResponses: counts.size,
310
+ samplePayload: categoryTests[0]?.payload?.substring(0, 100),
311
+ sampleResponse: categoryTests[0]?.response?.substring(0, 200),
312
+ };
313
+ }
314
+ return result;
315
+ }
316
+ /**
317
+ * Collect sample payload-response pairs with category diversity
318
+ */
319
+ collectSamplePairs(tests) {
320
+ const pairs = [];
321
+ const seenCategories = new Set();
322
+ // Prioritize diverse categories
323
+ for (const test of tests) {
324
+ if (pairs.length >= this.config.maxSamplePairs)
325
+ break;
326
+ if (!test.response || !test.payload)
327
+ continue;
328
+ const category = this.extractAttackCategory(test.testName);
329
+ if (!seenCategories.has(category)) {
330
+ seenCategories.add(category);
331
+ pairs.push({
332
+ attackCategory: category,
333
+ payload: test.payload.substring(0, 100),
334
+ response: test.response.substring(0, 300),
335
+ vulnerable: test.vulnerable,
336
+ });
337
+ }
338
+ }
339
+ // Fill remaining slots with additional samples
340
+ for (const test of tests) {
341
+ if (pairs.length >= this.config.maxSamplePairs)
342
+ break;
343
+ if (!test.response || !test.payload)
344
+ continue;
345
+ const truncatedPayload = test.payload.substring(0, 100);
346
+ if (!pairs.some((p) => p.payload === truncatedPayload)) {
347
+ pairs.push({
348
+ attackCategory: this.extractAttackCategory(test.testName),
349
+ payload: truncatedPayload,
350
+ response: test.response.substring(0, 300),
351
+ vulnerable: test.vulnerable,
352
+ });
353
+ }
354
+ }
355
+ return pairs;
356
+ }
357
+ /**
358
+ * Collect response metadata statistics
359
+ */
360
+ collectResponseMetadata(tests) {
361
+ if (tests.length === 0) {
362
+ return {
363
+ avgLength: 0,
364
+ minLength: 0,
365
+ maxLength: 0,
366
+ emptyCount: 0,
367
+ errorCount: 0,
368
+ };
369
+ }
370
+ let totalLength = 0;
371
+ let minLength = Infinity;
372
+ let maxLength = 0;
373
+ let emptyCount = 0;
374
+ let errorCount = 0;
375
+ let nonEmptyCount = 0;
376
+ for (const test of tests) {
377
+ const response = test.response ?? "";
378
+ const len = response.length;
379
+ // Check for empty/minimal responses
380
+ if (len === 0 ||
381
+ /^(\s*\{\s*\}|\s*\[\s*\]|\s*null\s*|)$/i.test(response.trim())) {
382
+ emptyCount++;
383
+ }
384
+ else {
385
+ totalLength += len;
386
+ minLength = Math.min(minLength, len);
387
+ maxLength = Math.max(maxLength, len);
388
+ nonEmptyCount++;
389
+ }
390
+ // Check for error indicators
391
+ if (/error|exception|fail/i.test(response)) {
392
+ errorCount++;
393
+ }
394
+ }
395
+ return {
396
+ avgLength: nonEmptyCount > 0 ? Math.round(totalLength / nonEmptyCount) : 0,
397
+ minLength: minLength === Infinity ? 0 : minLength,
398
+ maxLength,
399
+ emptyCount,
400
+ errorCount,
401
+ };
402
+ }
403
+ }
@@ -12,4 +12,5 @@ export { SecurityPayloadTester, type TestProgressCallback, type PayloadTestConfi
12
12
  export { SecurityPayloadGenerator } from "./SecurityPayloadGenerator.js";
13
13
  export { CrossToolStateTester, type CrossToolTestResult, type ToolPair, type CallToolFunction, type CrossToolTestConfig, } from "./CrossToolStateTester.js";
14
14
  export { ChainExecutionTester, type ChainExecutionTestResult, type ChainExploitationSummary, type ChainExecutionTesterConfig, type ChainTestReason, } from "./ChainExecutionTester.js";
15
+ export { TestValidityAnalyzer, type TestValidityConfig, type TestValidityResult, } from "./TestValidityAnalyzer.js";
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,UAAU,GAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,UAAU,GAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,wBAAwB,CAAC"}
@@ -12,3 +12,4 @@ export { SecurityPayloadTester, } from "./SecurityPayloadTester.js";
12
12
  export { SecurityPayloadGenerator } from "./SecurityPayloadGenerator.js";
13
13
  export { CrossToolStateTester, } from "./CrossToolStateTester.js";
14
14
  export { ChainExecutionTester, } from "./ChainExecutionTester.js";
15
+ export { TestValidityAnalyzer, } from "./TestValidityAnalyzer.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-client",
3
- "version": "1.34.1",
3
+ "version": "1.35.1",
4
4
  "description": "Client-side application for the Enhanced MCP Inspector with assessment capabilities",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",