@bryan-thompson/inspector-assessment-client 1.25.4 → 1.25.6

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 (126) hide show
  1. package/dist/assets/{OAuthCallback-DE62cdTZ.js → OAuthCallback-D6y8tFfF.js} +1 -1
  2. package/dist/assets/{OAuthDebugCallback-CWjFdCIE.js → OAuthDebugCallback-DHegnqTa.js} +1 -1
  3. package/dist/assets/{index-PCQVSwHa.js → index-Cu02Ah3g.js} +4 -4
  4. package/dist/assets/{index-Df9Sx1jt.css → index-cHhcEXbr.css} +4 -0
  5. package/dist/index.html +2 -2
  6. package/lib/lib/assessment/coreTypes.d.ts +65 -0
  7. package/lib/lib/assessment/coreTypes.d.ts.map +1 -1
  8. package/lib/lib/assessment/extendedTypes.d.ts +127 -0
  9. package/lib/lib/assessment/extendedTypes.d.ts.map +1 -1
  10. package/lib/lib/assessment/resultTypes.d.ts +45 -0
  11. package/lib/lib/assessment/resultTypes.d.ts.map +1 -1
  12. package/lib/lib/moduleScoring.d.ts +2 -2
  13. package/lib/lib/moduleScoring.d.ts.map +1 -1
  14. package/lib/lib/moduleScoring.js +3 -2
  15. package/lib/services/assessment/AssessmentOrchestrator.d.ts +3 -7
  16. package/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -1
  17. package/lib/services/assessment/AssessmentOrchestrator.js +13 -2
  18. package/lib/services/assessment/TestDataGenerator.d.ts +9 -1
  19. package/lib/services/assessment/TestDataGenerator.d.ts.map +1 -1
  20. package/lib/services/assessment/TestDataGenerator.js +32 -6
  21. package/lib/services/assessment/TestScenarioEngine.d.ts +9 -1
  22. package/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -1
  23. package/lib/services/assessment/TestScenarioEngine.js +17 -14
  24. package/lib/services/assessment/config/annotationPatterns.d.ts +3 -1
  25. package/lib/services/assessment/config/annotationPatterns.d.ts.map +1 -1
  26. package/lib/services/assessment/config/annotationPatterns.js +5 -2
  27. package/lib/services/assessment/config/architecturePatterns.d.ts +101 -0
  28. package/lib/services/assessment/config/architecturePatterns.d.ts.map +1 -0
  29. package/lib/services/assessment/config/architecturePatterns.js +248 -0
  30. package/lib/services/assessment/config/performanceConfig.d.ts +122 -0
  31. package/lib/services/assessment/config/performanceConfig.d.ts.map +1 -0
  32. package/lib/services/assessment/config/performanceConfig.js +154 -0
  33. package/lib/services/assessment/config/sanitizationPatterns.d.ts +63 -0
  34. package/lib/services/assessment/config/sanitizationPatterns.d.ts.map +1 -0
  35. package/lib/services/assessment/config/sanitizationPatterns.js +223 -0
  36. package/lib/services/assessment/lib/claudeCodeBridge.d.ts +40 -3
  37. package/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -1
  38. package/lib/services/assessment/lib/claudeCodeBridge.js +149 -8
  39. package/lib/services/assessment/lib/concurrencyLimit.d.ts +6 -2
  40. package/lib/services/assessment/lib/concurrencyLimit.d.ts.map +1 -1
  41. package/lib/services/assessment/lib/concurrencyLimit.js +13 -6
  42. package/lib/services/assessment/lib/errors.d.ts +90 -0
  43. package/lib/services/assessment/lib/errors.d.ts.map +1 -0
  44. package/lib/services/assessment/lib/errors.js +136 -0
  45. package/lib/services/assessment/lib/timeoutUtils.d.ts +69 -0
  46. package/lib/services/assessment/lib/timeoutUtils.d.ts.map +1 -0
  47. package/lib/services/assessment/lib/timeoutUtils.js +103 -0
  48. package/lib/services/assessment/modules/BaseAssessor.d.ts +43 -8
  49. package/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -1
  50. package/lib/services/assessment/modules/BaseAssessor.js +103 -34
  51. package/lib/services/assessment/modules/DeveloperExperienceAssessor.d.ts +38 -1
  52. package/lib/services/assessment/modules/DeveloperExperienceAssessor.d.ts.map +1 -1
  53. package/lib/services/assessment/modules/DeveloperExperienceAssessor.js +185 -19
  54. package/lib/services/assessment/modules/DocumentationAssessor.d.ts +5 -0
  55. package/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -1
  56. package/lib/services/assessment/modules/DocumentationAssessor.js +11 -0
  57. package/lib/services/assessment/modules/ErrorHandlingAssessor.js +1 -1
  58. package/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -1
  59. package/lib/services/assessment/modules/FunctionalityAssessor.js +6 -3
  60. package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +3 -0
  61. package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -1
  62. package/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +14 -2
  63. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -1
  64. package/lib/services/assessment/modules/ManifestValidationAssessor.js +7 -2
  65. package/lib/services/assessment/modules/PromptAssessor.d.ts +1 -0
  66. package/lib/services/assessment/modules/PromptAssessor.d.ts.map +1 -1
  67. package/lib/services/assessment/modules/PromptAssessor.js +26 -16
  68. package/lib/services/assessment/modules/ProtocolComplianceAssessor.d.ts.map +1 -1
  69. package/lib/services/assessment/modules/ProtocolComplianceAssessor.js +6 -2
  70. package/lib/services/assessment/modules/ProtocolConformanceAssessor.d.ts +5 -0
  71. package/lib/services/assessment/modules/ProtocolConformanceAssessor.d.ts.map +1 -1
  72. package/lib/services/assessment/modules/ProtocolConformanceAssessor.js +15 -0
  73. package/lib/services/assessment/modules/ResourceAssessor.d.ts.map +1 -1
  74. package/lib/services/assessment/modules/ResourceAssessor.js +8 -2
  75. package/lib/services/assessment/modules/SecurityAssessor.d.ts +3 -171
  76. package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
  77. package/lib/services/assessment/modules/SecurityAssessor.js +25 -1480
  78. package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +27 -28
  79. package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -1
  80. package/lib/services/assessment/modules/ToolAnnotationAssessor.js +340 -863
  81. package/lib/services/assessment/modules/UsabilityAssessor.d.ts +5 -0
  82. package/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -1
  83. package/lib/services/assessment/modules/UsabilityAssessor.js +11 -0
  84. package/lib/services/assessment/modules/annotations/AnnotationDeceptionDetector.d.ts +57 -0
  85. package/lib/services/assessment/modules/annotations/AnnotationDeceptionDetector.d.ts.map +1 -0
  86. package/lib/services/assessment/modules/annotations/AnnotationDeceptionDetector.js +176 -0
  87. package/lib/services/assessment/modules/annotations/ArchitectureDetector.d.ts +67 -0
  88. package/lib/services/assessment/modules/annotations/ArchitectureDetector.d.ts.map +1 -0
  89. package/lib/services/assessment/modules/annotations/ArchitectureDetector.js +239 -0
  90. package/lib/services/assessment/modules/annotations/BehaviorInference.d.ts +46 -0
  91. package/lib/services/assessment/modules/annotations/BehaviorInference.d.ts.map +1 -0
  92. package/lib/services/assessment/modules/annotations/BehaviorInference.js +394 -0
  93. package/lib/services/assessment/modules/annotations/DescriptionAnalyzer.d.ts +64 -0
  94. package/lib/services/assessment/modules/annotations/DescriptionAnalyzer.d.ts.map +1 -0
  95. package/lib/services/assessment/modules/annotations/DescriptionAnalyzer.js +304 -0
  96. package/lib/services/assessment/modules/annotations/DescriptionPoisoningDetector.d.ts +43 -0
  97. package/lib/services/assessment/modules/annotations/DescriptionPoisoningDetector.d.ts.map +1 -0
  98. package/lib/services/assessment/modules/annotations/DescriptionPoisoningDetector.js +276 -0
  99. package/lib/services/assessment/modules/annotations/SchemaAnalyzer.d.ts +122 -0
  100. package/lib/services/assessment/modules/annotations/SchemaAnalyzer.d.ts.map +1 -0
  101. package/lib/services/assessment/modules/annotations/SchemaAnalyzer.js +388 -0
  102. package/lib/services/assessment/modules/annotations/index.d.ts +13 -0
  103. package/lib/services/assessment/modules/annotations/index.d.ts.map +1 -0
  104. package/lib/services/assessment/modules/annotations/index.js +15 -0
  105. package/lib/services/assessment/modules/index.d.ts +10 -0
  106. package/lib/services/assessment/modules/index.d.ts.map +1 -1
  107. package/lib/services/assessment/modules/index.js +13 -0
  108. package/lib/services/assessment/modules/securityTests/SanitizationDetector.d.ts +125 -0
  109. package/lib/services/assessment/modules/securityTests/SanitizationDetector.d.ts.map +1 -0
  110. package/lib/services/assessment/modules/securityTests/SanitizationDetector.js +345 -0
  111. package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.d.ts +33 -0
  112. package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.d.ts.map +1 -0
  113. package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.js +128 -0
  114. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts +67 -0
  115. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts.map +1 -0
  116. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.js +372 -0
  117. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +178 -0
  118. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -0
  119. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +1207 -0
  120. package/lib/services/assessment/modules/securityTests/index.d.ts +8 -0
  121. package/lib/services/assessment/modules/securityTests/index.d.ts.map +1 -0
  122. package/lib/services/assessment/modules/securityTests/index.js +7 -0
  123. package/lib/services/assessment/tool-classifier-patterns.d.ts +1 -0
  124. package/lib/services/assessment/tool-classifier-patterns.d.ts.map +1 -1
  125. package/lib/services/assessment/tool-classifier-patterns.js +17 -0
  126. package/package.json +1 -1
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Behavior Inference
3
+ * Infers expected tool behavior from name patterns and descriptions
4
+ *
5
+ * Extracted from ToolAnnotationAssessor.ts for maintainability.
6
+ * Handles persistence model detection and behavior classification.
7
+ *
8
+ * Enhanced in Issue #57 with multi-signal inference from descriptions and schemas.
9
+ */
10
+ import { analyzeDescription } from "./DescriptionAnalyzer.js";
11
+ import { analyzeInputSchema, analyzeOutputSchema, } from "./SchemaAnalyzer.js";
12
+ import { getDefaultCompiledPatterns, matchToolPattern, checkDescriptionForImmediatePersistence, } from "../../config/annotationPatterns.js";
13
+ import { isRunKeywordExempt } from "./AnnotationDeceptionDetector.js";
14
+ /**
15
+ * Infer expected behavior from tool name and description
16
+ * Returns confidence level and ambiguity flag for better handling
17
+ */
18
+ export function inferBehavior(toolName, description, compiledPatterns, persistenceContext) {
19
+ const patterns = compiledPatterns ?? getDefaultCompiledPatterns();
20
+ const lowerDesc = (description || "").toLowerCase();
21
+ // Issue #18: Early check for run + analysis suffix pattern
22
+ // Tools like "runAccessibilityAudit" are genuinely read-only (fetch analysis data)
23
+ // Check this BEFORE pattern matching to override the generic "run_" write pattern
24
+ if (isRunKeywordExempt(toolName)) {
25
+ return {
26
+ expectedReadOnly: true,
27
+ expectedDestructive: false,
28
+ reason: `Tool name contains 'run' with analysis suffix (audit, check, scan, etc.) - this is a read-only analysis operation`,
29
+ confidence: "medium",
30
+ isAmbiguous: false,
31
+ };
32
+ }
33
+ // Use the configurable pattern matching system
34
+ const patternMatch = matchToolPattern(toolName, patterns);
35
+ // Handle pattern match results
36
+ switch (patternMatch.category) {
37
+ case "ambiguous":
38
+ // Ambiguous patterns - don't make strong assertions
39
+ return {
40
+ expectedReadOnly: false,
41
+ expectedDestructive: false,
42
+ reason: `Tool name matches ambiguous pattern '${patternMatch.pattern}' - behavior varies by implementation context`,
43
+ confidence: "low",
44
+ isAmbiguous: true,
45
+ };
46
+ case "destructive":
47
+ return {
48
+ expectedReadOnly: false,
49
+ expectedDestructive: true,
50
+ reason: `Tool name matches destructive pattern: ${patternMatch.pattern}`,
51
+ confidence: "high",
52
+ isAmbiguous: false,
53
+ };
54
+ case "readOnly":
55
+ return {
56
+ expectedReadOnly: true,
57
+ expectedDestructive: false,
58
+ reason: `Tool name matches read-only pattern: ${patternMatch.pattern}`,
59
+ confidence: "high",
60
+ isAmbiguous: false,
61
+ };
62
+ case "write": {
63
+ // CREATE operations are NEVER destructive - they only ADD new data
64
+ // Only UPDATE/MODIFY operations can be considered destructive when they modify existing data
65
+ const isCreateOperation = /^(create|add|insert|new|generate)[_-]/i.test(toolName);
66
+ if (isCreateOperation) {
67
+ return {
68
+ expectedReadOnly: false,
69
+ expectedDestructive: false,
70
+ reason: `Tool name matches create pattern: ${patternMatch.pattern} - create operations only add data and are not destructive`,
71
+ confidence: "high",
72
+ isAmbiguous: false,
73
+ };
74
+ }
75
+ // Three-Tier Classification: Check persistence model for UPDATE/MODIFY operations
76
+ // If immediate persistence detected, update operations should be marked destructive
77
+ const descriptionCheck = checkDescriptionForImmediatePersistence(description || "");
78
+ // Priority 1: Description explicitly indicates deferred persistence
79
+ if (descriptionCheck.indicatesDeferred) {
80
+ return {
81
+ expectedReadOnly: false,
82
+ expectedDestructive: false,
83
+ reason: `Tool name matches write pattern (${patternMatch.pattern}), description indicates deferred/in-memory operation`,
84
+ confidence: "medium",
85
+ isAmbiguous: false,
86
+ };
87
+ }
88
+ // Priority 2: Description explicitly indicates immediate persistence
89
+ if (descriptionCheck.indicatesImmediate) {
90
+ return {
91
+ expectedReadOnly: false,
92
+ expectedDestructive: true,
93
+ reason: `Tool name matches write pattern (${patternMatch.pattern}), description indicates immediate persistence to storage (${descriptionCheck.matchedPatterns.slice(0, 2).join(", ")})`,
94
+ confidence: "medium",
95
+ isAmbiguous: false,
96
+ };
97
+ }
98
+ // Priority 3: Server-level persistence model (no save operations = immediate)
99
+ if (persistenceContext?.model === "immediate") {
100
+ return {
101
+ expectedReadOnly: false,
102
+ expectedDestructive: true,
103
+ reason: `Tool name matches write pattern (${patternMatch.pattern}), server has no save operations → write operations likely persist immediately`,
104
+ confidence: "medium",
105
+ isAmbiguous: false,
106
+ };
107
+ }
108
+ // Priority 4: Server has save operations = deferred (in-memory until save)
109
+ if (persistenceContext?.model === "deferred") {
110
+ return {
111
+ expectedReadOnly: false,
112
+ expectedDestructive: false,
113
+ reason: `Tool name matches write pattern (${patternMatch.pattern}), server has save operations → write operations likely in-memory until explicit save`,
114
+ confidence: "medium",
115
+ isAmbiguous: false,
116
+ };
117
+ }
118
+ // Default: Unknown persistence model - conservative approach (not destructive)
119
+ return {
120
+ expectedReadOnly: false,
121
+ expectedDestructive: false,
122
+ reason: `Tool name matches write pattern: ${patternMatch.pattern}`,
123
+ confidence: "medium",
124
+ isAmbiguous: false,
125
+ };
126
+ }
127
+ case "unknown":
128
+ default:
129
+ // Fall through to description-based analysis
130
+ break;
131
+ }
132
+ // Check description for hints (medium confidence)
133
+ if (lowerDesc.includes("delete") || lowerDesc.includes("remove")) {
134
+ return {
135
+ expectedReadOnly: false,
136
+ expectedDestructive: true,
137
+ reason: "Description mentions delete/remove operations",
138
+ confidence: "medium",
139
+ isAmbiguous: false,
140
+ };
141
+ }
142
+ // Check for read-only indicators, but write operations take precedence
143
+ const hasReadIndicators = lowerDesc.includes("read") ||
144
+ lowerDesc.includes("get") ||
145
+ lowerDesc.includes("fetch");
146
+ const hasWriteIndicators = lowerDesc.includes("update") ||
147
+ lowerDesc.includes("create") ||
148
+ lowerDesc.includes("increment") ||
149
+ lowerDesc.includes("modify") ||
150
+ lowerDesc.includes("set") ||
151
+ lowerDesc.includes("change");
152
+ if (hasReadIndicators && !hasWriteIndicators) {
153
+ return {
154
+ expectedReadOnly: true,
155
+ expectedDestructive: false,
156
+ reason: "Description suggests read-only operation",
157
+ confidence: "medium",
158
+ isAmbiguous: false,
159
+ };
160
+ }
161
+ // Default: assume write with low confidence (ambiguous)
162
+ return {
163
+ expectedReadOnly: false,
164
+ expectedDestructive: false,
165
+ reason: "Could not infer behavior from name pattern",
166
+ confidence: "low",
167
+ isAmbiguous: true,
168
+ };
169
+ }
170
+ /**
171
+ * Enhanced behavior inference using multiple signals.
172
+ *
173
+ * Analyzes tool name patterns, descriptions, and schemas to provide
174
+ * a more accurate behavior inference with aggregated confidence.
175
+ *
176
+ * Part of Issue #57: Architecture detection and behavior inference modules
177
+ *
178
+ * @param toolName - Name of the tool
179
+ * @param description - Tool description (optional)
180
+ * @param inputSchema - Input parameter schema (optional)
181
+ * @param outputSchema - Output/return schema (optional)
182
+ * @param compiledPatterns - Compiled regex patterns for name matching
183
+ * @param persistenceContext - Server-level persistence context
184
+ * @returns EnhancedBehaviorInferenceResult with multi-signal analysis
185
+ */
186
+ export function inferBehaviorEnhanced(toolName, description, inputSchema, outputSchema, compiledPatterns, persistenceContext) {
187
+ // Get the basic name-pattern inference
188
+ const baseResult = inferBehavior(toolName, description, compiledPatterns, persistenceContext);
189
+ // Initialize signals collection
190
+ const signals = {};
191
+ // Convert base result to name pattern signal
192
+ signals.namePatternSignal = {
193
+ expectedReadOnly: baseResult.expectedReadOnly,
194
+ expectedDestructive: baseResult.expectedDestructive,
195
+ confidence: confidenceToNumber(baseResult.confidence),
196
+ evidence: [baseResult.reason],
197
+ };
198
+ // Analyze description if provided
199
+ if (description && description.trim().length > 0) {
200
+ signals.descriptionSignal = analyzeDescription(description);
201
+ }
202
+ // Analyze input schema if provided
203
+ if (inputSchema) {
204
+ signals.inputSchemaSignal = analyzeInputSchema(inputSchema);
205
+ }
206
+ // Analyze output schema if provided
207
+ if (outputSchema) {
208
+ signals.outputSchemaSignal = analyzeOutputSchema(outputSchema);
209
+ }
210
+ // Aggregate signals to determine final result
211
+ const aggregated = aggregateSignals(signals);
212
+ // Preserve persistence model info from base result if present
213
+ let finalReason = aggregated.reason;
214
+ if (baseResult.reason.includes("deferred") ||
215
+ baseResult.reason.includes("immediate persistence")) {
216
+ // Append persistence context to aggregated reason
217
+ const persistenceInfo = baseResult.reason.includes("deferred")
218
+ ? " (deferred persistence model)"
219
+ : " (immediate persistence model)";
220
+ finalReason = aggregated.reason + persistenceInfo;
221
+ }
222
+ return {
223
+ expectedReadOnly: aggregated.expectedReadOnly,
224
+ expectedDestructive: aggregated.expectedDestructive,
225
+ reason: finalReason,
226
+ confidence: numberToConfidence(aggregated.confidence),
227
+ isAmbiguous: aggregated.isAmbiguous,
228
+ signals,
229
+ aggregatedConfidence: aggregated.confidence,
230
+ };
231
+ }
232
+ /**
233
+ * Convert string confidence to numeric value (0-100).
234
+ */
235
+ function confidenceToNumber(confidence) {
236
+ switch (confidence) {
237
+ case "high":
238
+ return 90;
239
+ case "medium":
240
+ return 70;
241
+ case "low":
242
+ return 40;
243
+ default:
244
+ return 0;
245
+ }
246
+ }
247
+ /**
248
+ * Convert numeric confidence (0-100) to string confidence level.
249
+ */
250
+ function numberToConfidence(confidence) {
251
+ if (confidence >= 80)
252
+ return "high";
253
+ if (confidence >= 50)
254
+ return "medium";
255
+ return "low";
256
+ }
257
+ /**
258
+ * Aggregate multiple signals into a final inference result.
259
+ *
260
+ * Signal aggregation rules:
261
+ * 1. Destructive signals take priority if confidence >= 70
262
+ * 2. Read-only signals are aggregated when no destructive signals
263
+ * 3. Conflicting signals decrease overall confidence
264
+ * 4. Multiple agreeing signals increase confidence
265
+ */
266
+ function aggregateSignals(signals) {
267
+ const activeSignals = Object.entries(signals).filter(([_, signal]) => signal && signal.confidence > 0);
268
+ if (activeSignals.length === 0) {
269
+ return {
270
+ expectedReadOnly: false,
271
+ expectedDestructive: false,
272
+ reason: "No signals detected",
273
+ confidence: 0,
274
+ isAmbiguous: true,
275
+ };
276
+ }
277
+ // If only one weak signal exists, treat as ambiguous
278
+ if (activeSignals.length === 1 && activeSignals[0][1].confidence < 50) {
279
+ return {
280
+ expectedReadOnly: false,
281
+ expectedDestructive: false,
282
+ reason: "Only weak signal detected - behavior is ambiguous",
283
+ confidence: activeSignals[0][1].confidence,
284
+ isAmbiguous: true,
285
+ };
286
+ }
287
+ // Count signals by behavior type
288
+ let readOnlySignals = [];
289
+ let destructiveSignals = [];
290
+ let writeSignals = [];
291
+ for (const [name, signal] of activeSignals) {
292
+ if (signal.expectedDestructive) {
293
+ destructiveSignals.push({ name, signal });
294
+ }
295
+ else if (signal.expectedReadOnly) {
296
+ readOnlySignals.push({ name, signal });
297
+ }
298
+ else {
299
+ writeSignals.push({ name, signal });
300
+ }
301
+ }
302
+ // Determine final behavior
303
+ let expectedReadOnly = false;
304
+ let expectedDestructive = false;
305
+ let reason;
306
+ let confidence;
307
+ let isAmbiguous = false;
308
+ // Priority 1: Strong destructive signals
309
+ const strongDestructive = destructiveSignals.filter((s) => s.signal.confidence >= 70);
310
+ if (strongDestructive.length > 0) {
311
+ expectedDestructive = true;
312
+ const avgConfidence = strongDestructive.reduce((sum, s) => sum + s.signal.confidence, 0) /
313
+ strongDestructive.length;
314
+ // Gentle boost for multiple signals (prevents saturation at 100)
315
+ const boostMultiplier = Math.max(0, strongDestructive.length - 1);
316
+ confidence = Math.min(100, avgConfidence + boostMultiplier * 3);
317
+ reason = `Destructive behavior detected from: ${strongDestructive.map((s) => formatSignalName(s.name)).join(", ")}`;
318
+ // Check for conflicts
319
+ if (readOnlySignals.length > 0) {
320
+ confidence -= 10;
321
+ reason += ` (conflicts with read-only signals)`;
322
+ isAmbiguous = true;
323
+ }
324
+ }
325
+ // Priority 2: Read-only vs Write signals
326
+ // If there are strong write signals, they should take precedence
327
+ else if (readOnlySignals.length > 0) {
328
+ const strongWriteSignals = writeSignals.filter((s) => s.signal.confidence >= 70);
329
+ // Write signals of high confidence override read-only (multi-operation tools)
330
+ if (strongWriteSignals.length > 0) {
331
+ const writeAvg = strongWriteSignals.reduce((sum, s) => sum + s.signal.confidence, 0) /
332
+ strongWriteSignals.length;
333
+ const readAvg = readOnlySignals.reduce((sum, s) => sum + s.signal.confidence, 0) /
334
+ readOnlySignals.length;
335
+ // When both read-only and write signals present, it's always a conflict
336
+ // Mark as ambiguous and let the dominant signal determine behavior
337
+ isAmbiguous = true;
338
+ if (writeAvg >= readAvg * 0.9) {
339
+ // Write is dominant - but still a conflict
340
+ expectedReadOnly = false;
341
+ confidence = Math.max(0, Math.round(writeAvg - 10)); // Reduce due to conflict, prevent underflow
342
+ reason = `Write behavior detected from: ${strongWriteSignals.map((s) => formatSignalName(s.name)).join(", ")} (conflicts with read-only signals)`;
343
+ }
344
+ else {
345
+ // Read-only is dominant - still a conflict
346
+ expectedReadOnly = true;
347
+ confidence = Math.max(0, Math.round(readAvg - 15)); // Reduce due to conflict, prevent underflow
348
+ reason = `Read-only behavior detected from: ${readOnlySignals.map((s) => formatSignalName(s.name)).join(", ")} (conflicts with write signals)`;
349
+ }
350
+ }
351
+ else {
352
+ // Pure read-only, no write conflicts
353
+ expectedReadOnly = true;
354
+ const avgConfidence = readOnlySignals.reduce((sum, s) => sum + s.signal.confidence, 0) /
355
+ readOnlySignals.length;
356
+ // Gentle boost for multiple signals (prevents saturation at 100)
357
+ const boostMultiplier = Math.max(0, readOnlySignals.length - 1);
358
+ confidence = Math.min(100, avgConfidence + boostMultiplier * 3);
359
+ reason = `Read-only behavior detected from: ${readOnlySignals.map((s) => formatSignalName(s.name)).join(", ")}`;
360
+ }
361
+ }
362
+ // Priority 3: Write signals (not destructive)
363
+ else if (writeSignals.length > 0) {
364
+ const avgConfidence = writeSignals.reduce((sum, s) => sum + s.signal.confidence, 0) /
365
+ writeSignals.length;
366
+ confidence = avgConfidence;
367
+ reason = `Write behavior detected from: ${writeSignals.map((s) => formatSignalName(s.name)).join(", ")}`;
368
+ }
369
+ // Fallback: No clear signals
370
+ else {
371
+ confidence = 30;
372
+ reason = "No clear behavior signals detected";
373
+ isAmbiguous = true;
374
+ }
375
+ // Ensure confidence is in valid range
376
+ confidence = Math.max(0, Math.min(100, confidence));
377
+ return {
378
+ expectedReadOnly,
379
+ expectedDestructive,
380
+ reason,
381
+ confidence: Math.round(confidence),
382
+ isAmbiguous,
383
+ };
384
+ }
385
+ /**
386
+ * Format signal name for display.
387
+ */
388
+ function formatSignalName(name) {
389
+ return name
390
+ .replace(/Signal$/, "")
391
+ .replace(/([A-Z])/g, " $1")
392
+ .trim()
393
+ .toLowerCase();
394
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Description Analyzer
3
+ *
4
+ * Analyzes tool descriptions for behavioral keywords to infer expected behavior.
5
+ * This provides a more robust inference than name-pattern matching alone.
6
+ *
7
+ * Part of Issue #57: Architecture detection and behavior inference modules
8
+ */
9
+ import type { InferenceSignal } from "../../../../lib/assessment/extendedTypes.js";
10
+ /**
11
+ * Keyword categories with confidence levels.
12
+ * Keywords in 'high' have strong semantic association with the behavior.
13
+ * Keywords in 'medium' are indicative but may have context-dependent meanings.
14
+ * Keywords in 'low' are weak indicators.
15
+ */
16
+ export declare const DESCRIPTION_BEHAVIOR_KEYWORDS: {
17
+ readOnly: {
18
+ high: string[];
19
+ medium: string[];
20
+ low: string[];
21
+ };
22
+ destructive: {
23
+ high: string[];
24
+ medium: string[];
25
+ low: string[];
26
+ };
27
+ write: {
28
+ high: string[];
29
+ medium: string[];
30
+ low: string[];
31
+ };
32
+ };
33
+ /**
34
+ * Analyze a tool description for behavioral signals.
35
+ *
36
+ * @param description - Tool description to analyze
37
+ * @returns InferenceSignal with read-only/destructive expectations
38
+ */
39
+ export declare function analyzeDescription(description: string): InferenceSignal;
40
+ /**
41
+ * Quick check if description contains read-only indicators.
42
+ * Useful for fast filtering before full analysis.
43
+ *
44
+ * @param description - Tool description to check
45
+ * @returns True if any read-only keywords are present
46
+ */
47
+ export declare function hasReadOnlyIndicators(description: string): boolean;
48
+ /**
49
+ * Quick check if description contains destructive indicators.
50
+ * Useful for fast filtering before full analysis.
51
+ *
52
+ * @param description - Tool description to check
53
+ * @returns True if any destructive keywords are present
54
+ */
55
+ export declare function hasDestructiveIndicators(description: string): boolean;
56
+ /**
57
+ * Quick check if description contains write indicators.
58
+ * Useful for fast filtering before full analysis.
59
+ *
60
+ * @param description - Tool description to check
61
+ * @returns True if any write keywords are present
62
+ */
63
+ export declare function hasWriteIndicators(description: string): boolean;
64
+ //# sourceMappingURL=DescriptionAnalyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DescriptionAnalyzer.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/annotations/DescriptionAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;CAoGzC,CAAC;AAiFF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CA6GvE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAYlE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAYrE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAY/D"}