@bryan-thompson/inspector-assessment-client 1.6.0 → 1.7.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.
- package/dist/assets/{OAuthCallback-ZcXdfhZQ.js → OAuthCallback-cGhwkoyY.js} +1 -1
- package/dist/assets/{OAuthDebugCallback-xt1SlIHS.js → OAuthDebugCallback-2rmUqser.js} +1 -1
- package/dist/assets/{index-B3lTiDVe.js → index-BnFixpvH.js} +4 -4
- package/dist/index.html +1 -1
- package/lib/lib/assessmentTypes.d.ts +670 -0
- package/lib/lib/assessmentTypes.d.ts.map +1 -0
- package/lib/lib/assessmentTypes.js +220 -0
- package/lib/lib/aupPatterns.d.ts +63 -0
- package/lib/lib/aupPatterns.d.ts.map +1 -0
- package/lib/lib/aupPatterns.js +344 -0
- package/lib/lib/prohibitedLibraries.d.ts +76 -0
- package/lib/lib/prohibitedLibraries.d.ts.map +1 -0
- package/lib/lib/prohibitedLibraries.js +364 -0
- package/lib/lib/securityPatterns.d.ts +64 -0
- package/lib/lib/securityPatterns.d.ts.map +1 -0
- package/lib/lib/securityPatterns.js +453 -0
- package/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
- package/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
- package/lib/services/assessment/AssessmentOrchestrator.js +418 -0
- package/lib/services/assessment/ResponseValidator.d.ts +69 -0
- package/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
- package/lib/services/assessment/ResponseValidator.js +1038 -0
- package/lib/services/assessment/TestDataGenerator.d.ts +86 -0
- package/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
- package/lib/services/assessment/TestDataGenerator.js +669 -0
- package/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
- package/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
- package/lib/services/assessment/TestScenarioEngine.js +505 -0
- package/lib/services/assessment/ToolClassifier.d.ts +61 -0
- package/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
- package/lib/services/assessment/ToolClassifier.js +349 -0
- package/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
- package/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
- package/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
- package/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
- package/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
- package/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
- package/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/BaseAssessor.js +171 -0
- package/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
- package/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
- package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
- package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
- package/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
- package/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
- package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
- package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
- package/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
- package/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
- package/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
- package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
- package/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
- package/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
- package/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
- package/lib/services/assessment/modules/index.d.ts +33 -0
- package/lib/services/assessment/modules/index.d.ts.map +1 -0
- package/lib/services/assessment/modules/index.js +35 -0
- package/package.json +15 -3
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest Validation Assessor
|
|
3
|
+
* Validates MCPB manifest.json against spec requirements
|
|
4
|
+
*
|
|
5
|
+
* Checks:
|
|
6
|
+
* - manifest_version (must be 0.3)
|
|
7
|
+
* - Required fields: name, version, description, author
|
|
8
|
+
* - mcp_config structure
|
|
9
|
+
* - icon.png presence
|
|
10
|
+
*
|
|
11
|
+
* Reference: MCPB Specification
|
|
12
|
+
*/
|
|
13
|
+
import { BaseAssessor } from "./BaseAssessor.js";
|
|
14
|
+
const REQUIRED_FIELDS = ["name", "version", "mcp_config"];
|
|
15
|
+
const RECOMMENDED_FIELDS = ["description", "author", "repository"];
|
|
16
|
+
const CURRENT_MANIFEST_VERSION = "0.3";
|
|
17
|
+
export class ManifestValidationAssessor extends BaseAssessor {
|
|
18
|
+
/**
|
|
19
|
+
* Run manifest validation assessment
|
|
20
|
+
*/
|
|
21
|
+
async assess(context) {
|
|
22
|
+
this.log("Starting manifest validation assessment");
|
|
23
|
+
this.testCount = 0;
|
|
24
|
+
// Check if manifest is available
|
|
25
|
+
if (!context.manifestJson && !context.manifestRaw) {
|
|
26
|
+
return this.createNoManifestResult();
|
|
27
|
+
}
|
|
28
|
+
const validationResults = [];
|
|
29
|
+
let hasIcon = false;
|
|
30
|
+
let hasRequiredFields = true;
|
|
31
|
+
const missingFields = [];
|
|
32
|
+
// Parse manifest if raw string provided
|
|
33
|
+
let manifest = null;
|
|
34
|
+
if (context.manifestJson) {
|
|
35
|
+
manifest = context.manifestJson;
|
|
36
|
+
}
|
|
37
|
+
else if (context.manifestRaw) {
|
|
38
|
+
try {
|
|
39
|
+
manifest = JSON.parse(context.manifestRaw);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
this.testCount++;
|
|
43
|
+
validationResults.push({
|
|
44
|
+
field: "manifest.json",
|
|
45
|
+
valid: false,
|
|
46
|
+
issue: `Invalid JSON: ${error instanceof Error ? error.message : "Parse error"}`,
|
|
47
|
+
severity: "ERROR",
|
|
48
|
+
});
|
|
49
|
+
return this.createInvalidJsonResult(validationResults);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!manifest) {
|
|
53
|
+
return this.createNoManifestResult();
|
|
54
|
+
}
|
|
55
|
+
// Validate manifest_version
|
|
56
|
+
this.testCount++;
|
|
57
|
+
validationResults.push(this.validateManifestVersion(manifest));
|
|
58
|
+
// Validate required fields
|
|
59
|
+
for (const field of REQUIRED_FIELDS) {
|
|
60
|
+
this.testCount++;
|
|
61
|
+
const result = this.validateRequiredField(manifest, field);
|
|
62
|
+
validationResults.push(result);
|
|
63
|
+
if (!result.valid) {
|
|
64
|
+
hasRequiredFields = false;
|
|
65
|
+
missingFields.push(field);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Validate recommended fields
|
|
69
|
+
for (const field of RECOMMENDED_FIELDS) {
|
|
70
|
+
this.testCount++;
|
|
71
|
+
validationResults.push(this.validateRecommendedField(manifest, field));
|
|
72
|
+
}
|
|
73
|
+
// Validate mcp_config structure
|
|
74
|
+
if (manifest.mcp_config) {
|
|
75
|
+
this.testCount++;
|
|
76
|
+
validationResults.push(this.validateMcpConfig(manifest.mcp_config));
|
|
77
|
+
}
|
|
78
|
+
// Check for icon
|
|
79
|
+
this.testCount++;
|
|
80
|
+
const iconResult = this.validateIcon(manifest, context);
|
|
81
|
+
validationResults.push(iconResult);
|
|
82
|
+
hasIcon = iconResult.valid;
|
|
83
|
+
// Validate name format
|
|
84
|
+
this.testCount++;
|
|
85
|
+
validationResults.push(this.validateNameFormat(manifest.name));
|
|
86
|
+
// Validate version format
|
|
87
|
+
this.testCount++;
|
|
88
|
+
validationResults.push(this.validateVersionFormat(manifest.version));
|
|
89
|
+
const status = this.determineManifestStatus(validationResults, hasRequiredFields);
|
|
90
|
+
const explanation = this.generateExplanation(validationResults, hasRequiredFields, hasIcon);
|
|
91
|
+
const recommendations = this.generateRecommendations(validationResults);
|
|
92
|
+
this.log(`Assessment complete: ${validationResults.filter((r) => r.valid).length}/${validationResults.length} checks passed`);
|
|
93
|
+
return {
|
|
94
|
+
hasManifest: true,
|
|
95
|
+
manifestVersion: manifest.manifest_version,
|
|
96
|
+
validationResults,
|
|
97
|
+
hasIcon,
|
|
98
|
+
hasRequiredFields,
|
|
99
|
+
missingFields,
|
|
100
|
+
status,
|
|
101
|
+
explanation,
|
|
102
|
+
recommendations,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create result when no manifest is available
|
|
107
|
+
*/
|
|
108
|
+
createNoManifestResult() {
|
|
109
|
+
return {
|
|
110
|
+
hasManifest: false,
|
|
111
|
+
validationResults: [
|
|
112
|
+
{
|
|
113
|
+
field: "manifest.json",
|
|
114
|
+
valid: false,
|
|
115
|
+
issue: "No manifest.json found - required for MCPB bundles",
|
|
116
|
+
severity: "ERROR",
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
hasIcon: false,
|
|
120
|
+
hasRequiredFields: false,
|
|
121
|
+
missingFields: [...REQUIRED_FIELDS],
|
|
122
|
+
status: "FAIL",
|
|
123
|
+
explanation: "No manifest.json found. This file is required for MCPB bundle validation.",
|
|
124
|
+
recommendations: [
|
|
125
|
+
"Create a manifest.json file following the MCPB specification",
|
|
126
|
+
"Required fields: manifest_version, name, version, mcp_config",
|
|
127
|
+
"Recommended: description, author, repository, icon",
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create result when manifest JSON is invalid
|
|
133
|
+
*/
|
|
134
|
+
createInvalidJsonResult(validationResults) {
|
|
135
|
+
return {
|
|
136
|
+
hasManifest: true,
|
|
137
|
+
validationResults,
|
|
138
|
+
hasIcon: false,
|
|
139
|
+
hasRequiredFields: false,
|
|
140
|
+
missingFields: [...REQUIRED_FIELDS],
|
|
141
|
+
status: "FAIL",
|
|
142
|
+
explanation: "manifest.json contains invalid JSON and could not be parsed.",
|
|
143
|
+
recommendations: [
|
|
144
|
+
"Fix JSON syntax errors in manifest.json",
|
|
145
|
+
"Validate JSON using a JSON linter",
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Validate manifest_version field
|
|
151
|
+
*/
|
|
152
|
+
validateManifestVersion(manifest) {
|
|
153
|
+
if (!manifest.manifest_version) {
|
|
154
|
+
return {
|
|
155
|
+
field: "manifest_version",
|
|
156
|
+
valid: false,
|
|
157
|
+
issue: "Missing manifest_version field",
|
|
158
|
+
expectedType: "string",
|
|
159
|
+
severity: "ERROR",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (manifest.manifest_version !== CURRENT_MANIFEST_VERSION) {
|
|
163
|
+
return {
|
|
164
|
+
field: "manifest_version",
|
|
165
|
+
valid: false,
|
|
166
|
+
value: manifest.manifest_version,
|
|
167
|
+
issue: `Expected manifest_version "${CURRENT_MANIFEST_VERSION}", got "${manifest.manifest_version}"`,
|
|
168
|
+
expectedType: "string",
|
|
169
|
+
severity: "WARNING",
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
field: "manifest_version",
|
|
174
|
+
valid: true,
|
|
175
|
+
value: manifest.manifest_version,
|
|
176
|
+
severity: "INFO",
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Validate required field presence
|
|
181
|
+
*/
|
|
182
|
+
validateRequiredField(manifest, field) {
|
|
183
|
+
const value = manifest[field];
|
|
184
|
+
if (value === undefined || value === null) {
|
|
185
|
+
return {
|
|
186
|
+
field,
|
|
187
|
+
valid: false,
|
|
188
|
+
issue: `Missing required field: ${field}`,
|
|
189
|
+
severity: "ERROR",
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (typeof value === "string" && value.trim() === "") {
|
|
193
|
+
return {
|
|
194
|
+
field,
|
|
195
|
+
valid: false,
|
|
196
|
+
value,
|
|
197
|
+
issue: `Required field ${field} is empty`,
|
|
198
|
+
severity: "ERROR",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
field,
|
|
203
|
+
valid: true,
|
|
204
|
+
value,
|
|
205
|
+
severity: "INFO",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Validate recommended field presence
|
|
210
|
+
*/
|
|
211
|
+
validateRecommendedField(manifest, field) {
|
|
212
|
+
const value = manifest[field];
|
|
213
|
+
if (value === undefined || value === null) {
|
|
214
|
+
return {
|
|
215
|
+
field,
|
|
216
|
+
valid: true, // Recommended fields don't fail validation
|
|
217
|
+
issue: `Missing recommended field: ${field}`,
|
|
218
|
+
severity: "WARNING",
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (typeof value === "string" && value.trim() === "") {
|
|
222
|
+
return {
|
|
223
|
+
field,
|
|
224
|
+
valid: true,
|
|
225
|
+
value,
|
|
226
|
+
issue: `Recommended field ${field} is empty`,
|
|
227
|
+
severity: "WARNING",
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
field,
|
|
232
|
+
valid: true,
|
|
233
|
+
value,
|
|
234
|
+
severity: "INFO",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Validate mcp_config structure
|
|
239
|
+
*/
|
|
240
|
+
validateMcpConfig(mcpConfig) {
|
|
241
|
+
if (!mcpConfig.command) {
|
|
242
|
+
return {
|
|
243
|
+
field: "mcp_config.command",
|
|
244
|
+
valid: false,
|
|
245
|
+
issue: "Missing required mcp_config.command field",
|
|
246
|
+
severity: "ERROR",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
// Check for ${BUNDLE_ROOT} anti-pattern
|
|
250
|
+
const configStr = JSON.stringify(mcpConfig);
|
|
251
|
+
if (configStr.includes("${BUNDLE_ROOT}")) {
|
|
252
|
+
return {
|
|
253
|
+
field: "mcp_config",
|
|
254
|
+
valid: false,
|
|
255
|
+
issue: "Uses ${BUNDLE_ROOT} which is not supported - use ${__dirname} instead",
|
|
256
|
+
severity: "ERROR",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// Check for hardcoded absolute paths
|
|
260
|
+
if (mcpConfig.command.startsWith("/") ||
|
|
261
|
+
mcpConfig.command.match(/^[A-Z]:\\/)) {
|
|
262
|
+
return {
|
|
263
|
+
field: "mcp_config.command",
|
|
264
|
+
valid: false,
|
|
265
|
+
value: mcpConfig.command,
|
|
266
|
+
issue: "Command uses hardcoded absolute path - use relative or ${__dirname}",
|
|
267
|
+
severity: "ERROR",
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
field: "mcp_config",
|
|
272
|
+
valid: true,
|
|
273
|
+
value: mcpConfig,
|
|
274
|
+
severity: "INFO",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Validate icon presence
|
|
279
|
+
*/
|
|
280
|
+
validateIcon(manifest, context) {
|
|
281
|
+
// Check manifest icon field
|
|
282
|
+
if (manifest.icon) {
|
|
283
|
+
return {
|
|
284
|
+
field: "icon",
|
|
285
|
+
valid: true,
|
|
286
|
+
value: manifest.icon,
|
|
287
|
+
severity: "INFO",
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
// Check if icon.png exists in source files
|
|
291
|
+
if (context.sourceCodeFiles) {
|
|
292
|
+
for (const filePath of context.sourceCodeFiles.keys()) {
|
|
293
|
+
if (filePath.endsWith("icon.png") || filePath.endsWith("icon.svg")) {
|
|
294
|
+
return {
|
|
295
|
+
field: "icon",
|
|
296
|
+
valid: true,
|
|
297
|
+
value: filePath,
|
|
298
|
+
issue: "Icon file found but not referenced in manifest",
|
|
299
|
+
severity: "WARNING",
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
field: "icon",
|
|
306
|
+
valid: false,
|
|
307
|
+
issue: "Missing icon.png - recommended for MCPB bundles",
|
|
308
|
+
severity: "WARNING",
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Validate name format
|
|
313
|
+
*/
|
|
314
|
+
validateNameFormat(name) {
|
|
315
|
+
if (!name) {
|
|
316
|
+
return {
|
|
317
|
+
field: "name (format)",
|
|
318
|
+
valid: false,
|
|
319
|
+
issue: "Name is required",
|
|
320
|
+
severity: "ERROR",
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
// Check for valid npm-style name
|
|
324
|
+
const validNamePattern = /^[a-z0-9][a-z0-9._-]*$/;
|
|
325
|
+
if (!validNamePattern.test(name.toLowerCase())) {
|
|
326
|
+
return {
|
|
327
|
+
field: "name (format)",
|
|
328
|
+
valid: false,
|
|
329
|
+
value: name,
|
|
330
|
+
issue: "Name should be lowercase, alphanumeric, and may include .-_ characters",
|
|
331
|
+
severity: "WARNING",
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
field: "name (format)",
|
|
336
|
+
valid: true,
|
|
337
|
+
value: name,
|
|
338
|
+
severity: "INFO",
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Validate version format (semver)
|
|
343
|
+
*/
|
|
344
|
+
validateVersionFormat(version) {
|
|
345
|
+
if (!version) {
|
|
346
|
+
return {
|
|
347
|
+
field: "version (format)",
|
|
348
|
+
valid: false,
|
|
349
|
+
issue: "Version is required",
|
|
350
|
+
severity: "ERROR",
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
// Check for semver format
|
|
354
|
+
const semverPattern = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?$/;
|
|
355
|
+
if (!semverPattern.test(version)) {
|
|
356
|
+
return {
|
|
357
|
+
field: "version (format)",
|
|
358
|
+
valid: false,
|
|
359
|
+
value: version,
|
|
360
|
+
issue: "Version should follow semver format (e.g., 1.0.0)",
|
|
361
|
+
severity: "WARNING",
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
field: "version (format)",
|
|
366
|
+
valid: true,
|
|
367
|
+
value: version,
|
|
368
|
+
severity: "INFO",
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Determine overall status
|
|
373
|
+
*/
|
|
374
|
+
determineManifestStatus(results, hasRequiredFields) {
|
|
375
|
+
const errors = results.filter((r) => !r.valid && r.severity === "ERROR").length;
|
|
376
|
+
const warnings = results.filter((r) => !r.valid && r.severity === "WARNING").length;
|
|
377
|
+
if (errors > 0 || !hasRequiredFields) {
|
|
378
|
+
return "FAIL";
|
|
379
|
+
}
|
|
380
|
+
if (warnings > 0) {
|
|
381
|
+
return "NEED_MORE_INFO";
|
|
382
|
+
}
|
|
383
|
+
return "PASS";
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Generate explanation
|
|
387
|
+
*/
|
|
388
|
+
generateExplanation(results, hasRequiredFields, hasIcon) {
|
|
389
|
+
const parts = [];
|
|
390
|
+
const passed = results.filter((r) => r.valid).length;
|
|
391
|
+
const total = results.length;
|
|
392
|
+
parts.push(`Manifest validation: ${passed}/${total} checks passed.`);
|
|
393
|
+
if (!hasRequiredFields) {
|
|
394
|
+
parts.push("Missing required fields in manifest.json.");
|
|
395
|
+
}
|
|
396
|
+
if (!hasIcon) {
|
|
397
|
+
parts.push("No icon found - recommended for MCPB bundles.");
|
|
398
|
+
}
|
|
399
|
+
const errors = results.filter((r) => !r.valid && r.severity === "ERROR");
|
|
400
|
+
if (errors.length > 0) {
|
|
401
|
+
parts.push(`${errors.length} error(s) require attention.`);
|
|
402
|
+
}
|
|
403
|
+
return parts.join(" ");
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Generate recommendations
|
|
407
|
+
*/
|
|
408
|
+
generateRecommendations(results) {
|
|
409
|
+
const recommendations = [];
|
|
410
|
+
// Group by severity
|
|
411
|
+
const errors = results.filter((r) => !r.valid && r.severity === "ERROR");
|
|
412
|
+
const warnings = results.filter((r) => r.severity === "WARNING" && r.issue);
|
|
413
|
+
if (errors.length > 0) {
|
|
414
|
+
recommendations.push("FIX REQUIRED - Manifest errors:");
|
|
415
|
+
for (const error of errors) {
|
|
416
|
+
recommendations.push(`- ${error.field}: ${error.issue}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (warnings.length > 0) {
|
|
420
|
+
recommendations.push("RECOMMENDED - Manifest improvements:");
|
|
421
|
+
for (const warning of warnings.slice(0, 3)) {
|
|
422
|
+
recommendations.push(`- ${warning.field}: ${warning.issue}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (recommendations.length === 0) {
|
|
426
|
+
recommendations.push("Manifest validation passed. All required fields are present and valid.");
|
|
427
|
+
}
|
|
428
|
+
return recommendations;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portability Assessor
|
|
3
|
+
* Detects hardcoded paths and platform-specific code
|
|
4
|
+
*
|
|
5
|
+
* Checks:
|
|
6
|
+
* - Hardcoded absolute paths
|
|
7
|
+
* - User home directory references
|
|
8
|
+
* - ${BUNDLE_ROOT} anti-pattern (should use ${__dirname})
|
|
9
|
+
* - Platform-specific code without fallbacks
|
|
10
|
+
* - ${__dirname} usage (correct pattern)
|
|
11
|
+
*
|
|
12
|
+
* Reference: MCPB Bundle Portability Requirements
|
|
13
|
+
*/
|
|
14
|
+
import { BaseAssessor } from "./BaseAssessor.js";
|
|
15
|
+
import { AssessmentContext } from "../AssessmentOrchestrator.js";
|
|
16
|
+
import type { PortabilityAssessment } from "../../../lib/assessmentTypes.js";
|
|
17
|
+
export declare class PortabilityAssessor extends BaseAssessor {
|
|
18
|
+
/**
|
|
19
|
+
* Run portability assessment
|
|
20
|
+
*/
|
|
21
|
+
assess(context: AssessmentContext): Promise<PortabilityAssessment>;
|
|
22
|
+
/**
|
|
23
|
+
* Scan a file for portability issues
|
|
24
|
+
*/
|
|
25
|
+
private scanFile;
|
|
26
|
+
/**
|
|
27
|
+
* Check if file should be skipped
|
|
28
|
+
*/
|
|
29
|
+
private shouldSkipFile;
|
|
30
|
+
/**
|
|
31
|
+
* Determine overall status
|
|
32
|
+
*/
|
|
33
|
+
private determinePortabilityStatus;
|
|
34
|
+
/**
|
|
35
|
+
* Generate explanation
|
|
36
|
+
*/
|
|
37
|
+
private generateExplanation;
|
|
38
|
+
/**
|
|
39
|
+
* Generate recommendations
|
|
40
|
+
*/
|
|
41
|
+
private generateRecommendations;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=PortabilityAssessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortabilityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/PortabilityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,uBAAuB,CAAC;AA2C/B,qBAAa,mBAAoB,SAAQ,YAAY;IACnD;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAgHxE;;OAEG;IACH,OAAO,CAAC,QAAQ;IAgIhB;;OAEG;IACH,OAAO,CAAC,cAAc;IAkBtB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAmClC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAmDhC"}
|