@bryan-thompson/inspector-assessment-cli 1.20.2 → 1.20.3

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.
@@ -25,6 +25,7 @@ import { generatePolicyComplianceReport } from "../../client/lib/services/assess
25
25
  import { compareAssessments } from "../../client/lib/lib/assessmentDiffer.js";
26
26
  import { formatDiffAsMarkdown } from "../../client/lib/lib/reportFormatters/DiffReportFormatter.js";
27
27
  import { AssessmentStateManager } from "./assessmentState.js";
28
+ import { emitServerConnected, emitToolDiscovered, emitToolsDiscoveryComplete, emitAssessmentComplete, emitTestBatch, emitVulnerabilityFound, emitAnnotationMissing, emitAnnotationMisaligned, emitAnnotationReviewRecommended, } from "./lib/jsonl-events.js";
28
29
  /**
29
30
  * Load server configuration from Claude Code's MCP settings
30
31
  */
@@ -293,18 +294,17 @@ async function runFullAssessment(options) {
293
294
  console.log("✅ Server config loaded");
294
295
  }
295
296
  const client = await connectToServer(serverConfig);
297
+ emitServerConnected(options.serverName, serverConfig.transport || "stdio");
296
298
  if (!options.jsonOnly) {
297
299
  console.log("✅ Connected to MCP server");
298
300
  }
299
301
  const response = await client.listTools();
300
302
  const tools = response.tools || [];
301
- // Always emit tool discovery events to stderr for audit-worker parsing
302
- // Format: TOOL_DISCOVERED:name|description|param1,param2,... (works even with --json flag)
303
+ // Emit JSONL tool discovery events for audit-worker parsing
303
304
  for (const tool of tools) {
304
- const description = tool.description || "";
305
- const params = Object.keys(tool.inputSchema?.properties || {}).join(",");
306
- console.error(`TOOL_DISCOVERED:${tool.name}|${description}|${params}`);
305
+ emitToolDiscovered(tool);
307
306
  }
307
+ emitToolsDiscoveryComplete(tools.length);
308
308
  if (!options.jsonOnly) {
309
309
  console.log(`🔧 Found ${tools.length} tool${tools.length !== 1 ? "s" : ""}`);
310
310
  }
@@ -483,12 +483,32 @@ async function runFullAssessment(options) {
483
483
  })),
484
484
  };
485
485
  };
486
+ // Progress callback to emit JSONL events for real-time monitoring
487
+ const onProgress = (event) => {
488
+ if (event.type === "test_batch") {
489
+ emitTestBatch(event.module, event.completed, event.total, event.batchSize, event.elapsed);
490
+ }
491
+ else if (event.type === "vulnerability_found") {
492
+ emitVulnerabilityFound(event.tool, event.pattern, event.confidence, event.evidence, event.riskLevel, event.requiresReview, event.payload);
493
+ }
494
+ else if (event.type === "annotation_missing") {
495
+ emitAnnotationMissing(event.tool, event.title, event.description, event.parameters, event.inferredBehavior);
496
+ }
497
+ else if (event.type === "annotation_misaligned") {
498
+ emitAnnotationMisaligned(event.tool, event.title, event.description, event.parameters, event.field, event.actual, event.expected, event.confidence, event.reason);
499
+ }
500
+ else if (event.type === "annotation_review_recommended") {
501
+ emitAnnotationReviewRecommended(event.tool, event.title, event.description, event.parameters, event.field, event.actual, event.inferred, event.confidence, event.isAmbiguous, event.reason);
502
+ }
503
+ // module_started and module_complete are handled by orchestrator directly
504
+ };
486
505
  const context = {
487
506
  serverName: options.serverName,
488
507
  tools,
489
508
  callTool: createCallToolWrapper(client),
490
509
  config,
491
510
  sourceCodePath: options.sourceCodePath,
511
+ onProgress,
492
512
  ...sourceFiles,
493
513
  // New capability assessment data
494
514
  resources,
@@ -502,6 +522,9 @@ async function runFullAssessment(options) {
502
522
  console.log("");
503
523
  }
504
524
  const results = await orchestrator.runFullAssessment(context);
525
+ // Emit assessment complete event
526
+ const defaultOutputPath = `/tmp/inspector-full-assessment-${options.serverName}.json`;
527
+ emitAssessmentComplete(results.overallStatus, results.totalTestsRun, results.executionTime, options.outputPath || defaultOutputPath);
505
528
  await client.close();
506
529
  return results;
507
530
  }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * JSONL Event Emission Helpers for CLI
3
+ *
4
+ * These functions emit structured JSONL events to stderr for real-time
5
+ * machine parsing during CLI assessment runs.
6
+ *
7
+ * This is a CLI-local version that imports from the built client lib
8
+ * to avoid rootDir conflicts in TypeScript compilation.
9
+ */
10
+ import { INSPECTOR_VERSION } from "../../../client/lib/lib/moduleScoring.js";
11
+ // ============================================================================
12
+ // Core Functions
13
+ // ============================================================================
14
+ /**
15
+ * Emit a JSONL event to stderr for real-time machine parsing.
16
+ * Automatically includes version field for compatibility checking.
17
+ */
18
+ export function emitJSONL(event) {
19
+ console.error(JSON.stringify({ ...event, version: INSPECTOR_VERSION }));
20
+ }
21
+ /**
22
+ * Emit server_connected event after successful connection.
23
+ */
24
+ export function emitServerConnected(serverName, transport) {
25
+ emitJSONL({ event: "server_connected", serverName, transport });
26
+ }
27
+ /**
28
+ * Extract parameter metadata from tool input schema.
29
+ */
30
+ export function extractToolParams(schema) {
31
+ if (!schema || typeof schema !== "object")
32
+ return [];
33
+ const s = schema;
34
+ if (!s.properties || typeof s.properties !== "object")
35
+ return [];
36
+ const required = new Set(Array.isArray(s.required) ? s.required : []);
37
+ const properties = s.properties;
38
+ return Object.entries(properties).map(([name, prop]) => {
39
+ const param = {
40
+ name,
41
+ type: prop.type || "any",
42
+ required: required.has(name),
43
+ };
44
+ if (prop.description) {
45
+ param.description = prop.description;
46
+ }
47
+ return param;
48
+ });
49
+ }
50
+ /**
51
+ * Emit tool_discovered event for each tool found.
52
+ */
53
+ export function emitToolDiscovered(tool) {
54
+ const params = extractToolParams(tool.inputSchema);
55
+ emitJSONL({
56
+ event: "tool_discovered",
57
+ name: tool.name,
58
+ description: tool.description || null,
59
+ params,
60
+ });
61
+ }
62
+ /**
63
+ * Emit tools_discovery_complete event after all tools discovered.
64
+ */
65
+ export function emitToolsDiscoveryComplete(count) {
66
+ emitJSONL({ event: "tools_discovery_complete", count });
67
+ }
68
+ /**
69
+ * Emit assessment_complete event at the end of assessment.
70
+ */
71
+ export function emitAssessmentComplete(overallStatus, totalTests, executionTime, outputPath) {
72
+ emitJSONL({
73
+ event: "assessment_complete",
74
+ overallStatus,
75
+ totalTests,
76
+ executionTime,
77
+ outputPath,
78
+ });
79
+ }
80
+ /**
81
+ * Emit test_batch event during assessment for real-time progress.
82
+ */
83
+ export function emitTestBatch(module, completed, total, batchSize, elapsed) {
84
+ emitJSONL({
85
+ event: "test_batch",
86
+ module,
87
+ completed,
88
+ total,
89
+ batchSize,
90
+ elapsed,
91
+ });
92
+ }
93
+ /**
94
+ * Emit vulnerability_found event when security testing detects issues.
95
+ */
96
+ export function emitVulnerabilityFound(tool, pattern, confidence, evidence, riskLevel, requiresReview, payload) {
97
+ emitJSONL({
98
+ event: "vulnerability_found",
99
+ tool,
100
+ pattern,
101
+ confidence,
102
+ evidence,
103
+ riskLevel,
104
+ requiresReview,
105
+ ...(payload && { payload }),
106
+ });
107
+ }
108
+ /**
109
+ * Emit annotation_missing event when a tool lacks required annotations.
110
+ */
111
+ export function emitAnnotationMissing(tool, title, description, parameters, inferredBehavior) {
112
+ emitJSONL({
113
+ event: "annotation_missing",
114
+ tool,
115
+ ...(title && { title }),
116
+ ...(description && { description }),
117
+ parameters,
118
+ inferredBehavior,
119
+ });
120
+ }
121
+ /**
122
+ * Emit annotation_misaligned event when actual annotations contradict inferred behavior.
123
+ */
124
+ export function emitAnnotationMisaligned(tool, title, description, parameters, field, actual, expected, confidence, reason) {
125
+ emitJSONL({
126
+ event: "annotation_misaligned",
127
+ tool,
128
+ ...(title && { title }),
129
+ ...(description && { description }),
130
+ parameters,
131
+ field,
132
+ actual,
133
+ expected,
134
+ confidence,
135
+ reason,
136
+ });
137
+ }
138
+ /**
139
+ * Emit annotation_review_recommended event for ambiguous patterns.
140
+ * This indicates human review is suggested but no automated penalty applied.
141
+ * Used for patterns like store_*, queue_*, cache_* where behavior varies.
142
+ */
143
+ export function emitAnnotationReviewRecommended(tool, title, description, parameters, field, actual, inferred, confidence, isAmbiguous, reason) {
144
+ emitJSONL({
145
+ event: "annotation_review_recommended",
146
+ tool,
147
+ ...(title && { title }),
148
+ ...(description && { description }),
149
+ parameters,
150
+ field,
151
+ actual,
152
+ inferred,
153
+ confidence,
154
+ isAmbiguous,
155
+ reason,
156
+ });
157
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-cli",
3
- "version": "1.20.2",
3
+ "version": "1.20.3",
4
4
  "description": "CLI for the Enhanced MCP Inspector with assessment capabilities",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",