@skillsmith/core 2.0.2 → 2.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.
Files changed (71) hide show
  1. package/README.md +1 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/db/schema.d.ts +1 -1
  4. package/dist/src/db/schema.d.ts.map +1 -1
  5. package/dist/src/db/schema.js +41 -1
  6. package/dist/src/db/schema.js.map +1 -1
  7. package/dist/src/index.d.ts +1 -0
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js +2 -0
  10. package/dist/src/index.js.map +1 -1
  11. package/dist/src/repositories/SyncConfigRepository.d.ts +91 -0
  12. package/dist/src/repositories/SyncConfigRepository.d.ts.map +1 -0
  13. package/dist/src/repositories/SyncConfigRepository.js +202 -0
  14. package/dist/src/repositories/SyncConfigRepository.js.map +1 -0
  15. package/dist/src/repositories/SyncHistoryRepository.d.ts +104 -0
  16. package/dist/src/repositories/SyncHistoryRepository.d.ts.map +1 -0
  17. package/dist/src/repositories/SyncHistoryRepository.js +235 -0
  18. package/dist/src/repositories/SyncHistoryRepository.js.map +1 -0
  19. package/dist/src/scripts/github-import/github-client.d.ts +24 -0
  20. package/dist/src/scripts/github-import/github-client.d.ts.map +1 -1
  21. package/dist/src/scripts/github-import/github-client.js +103 -0
  22. package/dist/src/scripts/github-import/github-client.js.map +1 -1
  23. package/dist/src/scripts/github-import/index.js +3 -10
  24. package/dist/src/scripts/github-import/index.js.map +1 -1
  25. package/dist/src/scripts/merge-skills.d.ts +56 -0
  26. package/dist/src/scripts/merge-skills.d.ts.map +1 -0
  27. package/dist/src/scripts/merge-skills.js +411 -0
  28. package/dist/src/scripts/merge-skills.js.map +1 -0
  29. package/dist/src/scripts/skill-scanner/index.d.ts +9 -2
  30. package/dist/src/scripts/skill-scanner/index.d.ts.map +1 -1
  31. package/dist/src/scripts/skill-scanner/index.js +98 -7
  32. package/dist/src/scripts/skill-scanner/index.js.map +1 -1
  33. package/dist/src/scripts/skill-scanner/logger.d.ts +51 -0
  34. package/dist/src/scripts/skill-scanner/logger.d.ts.map +1 -1
  35. package/dist/src/scripts/skill-scanner/logger.js +255 -1
  36. package/dist/src/scripts/skill-scanner/logger.js.map +1 -1
  37. package/dist/src/scripts/skill-scanner/reporter.d.ts +1 -1
  38. package/dist/src/scripts/skill-scanner/reporter.d.ts.map +1 -1
  39. package/dist/src/scripts/skill-scanner/reporter.js +67 -15
  40. package/dist/src/scripts/skill-scanner/reporter.js.map +1 -1
  41. package/dist/src/scripts/skill-scanner/scanner.d.ts +5 -2
  42. package/dist/src/scripts/skill-scanner/scanner.d.ts.map +1 -1
  43. package/dist/src/scripts/skill-scanner/scanner.js +156 -39
  44. package/dist/src/scripts/skill-scanner/scanner.js.map +1 -1
  45. package/dist/src/scripts/skill-scanner/types.d.ts +44 -0
  46. package/dist/src/scripts/skill-scanner/types.d.ts.map +1 -1
  47. package/dist/src/sync/BackgroundSyncService.d.ts +90 -0
  48. package/dist/src/sync/BackgroundSyncService.d.ts.map +1 -0
  49. package/dist/src/sync/BackgroundSyncService.js +214 -0
  50. package/dist/src/sync/BackgroundSyncService.js.map +1 -0
  51. package/dist/src/sync/SyncEngine.d.ts +76 -0
  52. package/dist/src/sync/SyncEngine.d.ts.map +1 -0
  53. package/dist/src/sync/SyncEngine.js +272 -0
  54. package/dist/src/sync/SyncEngine.js.map +1 -0
  55. package/dist/src/sync/index.d.ts +11 -0
  56. package/dist/src/sync/index.d.ts.map +1 -0
  57. package/dist/src/sync/index.js +14 -0
  58. package/dist/src/sync/index.js.map +1 -0
  59. package/dist/tests/sync/SyncConfigRepository.test.d.ts +7 -0
  60. package/dist/tests/sync/SyncConfigRepository.test.d.ts.map +1 -0
  61. package/dist/tests/sync/SyncConfigRepository.test.js +154 -0
  62. package/dist/tests/sync/SyncConfigRepository.test.js.map +1 -0
  63. package/dist/tests/sync/SyncEngine.test.d.ts +7 -0
  64. package/dist/tests/sync/SyncEngine.test.d.ts.map +1 -0
  65. package/dist/tests/sync/SyncEngine.test.js +298 -0
  66. package/dist/tests/sync/SyncEngine.test.js.map +1 -0
  67. package/dist/tests/sync/SyncHistoryRepository.test.d.ts +7 -0
  68. package/dist/tests/sync/SyncHistoryRepository.test.d.ts.map +1 -0
  69. package/dist/tests/sync/SyncHistoryRepository.test.js +220 -0
  70. package/dist/tests/sync/SyncHistoryRepository.test.js.map +1 -0
  71. package/package.json +1 -1
@@ -0,0 +1,411 @@
1
+ /**
2
+ * Merge safe skills into the main database
3
+ *
4
+ * This script merges skills from a safe-skills.json file (security scan output)
5
+ * with full skill data from imported-skills.json into a SQLite database.
6
+ * Only adds skills that don't already exist (by repo_url).
7
+ *
8
+ * Usage:
9
+ * npx tsx packages/core/src/scripts/merge-skills.ts [options]
10
+ *
11
+ * Required Arguments:
12
+ * --safe-skills, -s <path> Path to safe skills JSON (from security scan)
13
+ * --imported-skills, -i <path> Path to imported skills JSON (full skill data)
14
+ * --database, -d <path> Path to target SQLite database
15
+ *
16
+ * Options:
17
+ * --dry-run, -n Preview changes without modifying database
18
+ * --verbose, -v Show detailed per-skill output
19
+ * --help, -h Show usage information
20
+ *
21
+ * Example:
22
+ * npx tsx packages/core/src/scripts/merge-skills.ts \
23
+ * -s data/safe-skills.json \
24
+ * -i data/imported-skills.json \
25
+ * -d data/skills.db \
26
+ * --dry-run
27
+ */
28
+ import Database from 'better-sqlite3';
29
+ import { existsSync, readFileSync } from 'fs';
30
+ import { resolve } from 'path';
31
+ // ============================================================================
32
+ // Argument Parsing
33
+ // ============================================================================
34
+ function printUsage() {
35
+ console.log(`
36
+ Merge Safe Skills - Database Merge Tool
37
+
38
+ Usage:
39
+ npx tsx packages/core/src/scripts/merge-skills.ts [options]
40
+
41
+ Required Arguments:
42
+ --safe-skills, -s <path> Path to safe skills JSON (from security scan)
43
+ --imported-skills, -i <path> Path to imported skills JSON (full skill data)
44
+ --database, -d <path> Path to target SQLite database
45
+
46
+ Options:
47
+ --dry-run, -n Preview changes without modifying database
48
+ --verbose, -v Show detailed per-skill output
49
+ --help, -h Show usage information
50
+
51
+ Example:
52
+ npx tsx packages/core/src/scripts/merge-skills.ts \\
53
+ -s data/safe-skills.json \\
54
+ -i data/imported-skills.json \\
55
+ -d data/skills.db \\
56
+ --dry-run
57
+ `);
58
+ }
59
+ function parseArgs(args) {
60
+ const options = {
61
+ safeSkillsPath: '',
62
+ importedSkillsPath: '',
63
+ databasePath: '',
64
+ dryRun: false,
65
+ verbose: false,
66
+ };
67
+ for (let i = 0; i < args.length; i++) {
68
+ const arg = args[i];
69
+ const nextArg = args[i + 1];
70
+ switch (arg) {
71
+ case '--help':
72
+ case '-h':
73
+ printUsage();
74
+ process.exit(0);
75
+ break;
76
+ case '--safe-skills':
77
+ case '-s':
78
+ if (!nextArg || nextArg.startsWith('-')) {
79
+ console.error('Error: --safe-skills requires a path argument');
80
+ return null;
81
+ }
82
+ options.safeSkillsPath = nextArg;
83
+ i++;
84
+ break;
85
+ case '--imported-skills':
86
+ case '-i':
87
+ if (!nextArg || nextArg.startsWith('-')) {
88
+ console.error('Error: --imported-skills requires a path argument');
89
+ return null;
90
+ }
91
+ options.importedSkillsPath = nextArg;
92
+ i++;
93
+ break;
94
+ case '--database':
95
+ case '-d':
96
+ if (!nextArg || nextArg.startsWith('-')) {
97
+ console.error('Error: --database requires a path argument');
98
+ return null;
99
+ }
100
+ options.databasePath = nextArg;
101
+ i++;
102
+ break;
103
+ case '--dry-run':
104
+ case '-n':
105
+ options.dryRun = true;
106
+ break;
107
+ case '--verbose':
108
+ case '-v':
109
+ options.verbose = true;
110
+ break;
111
+ default:
112
+ if (arg.startsWith('-')) {
113
+ console.error(`Error: Unknown option: ${arg}`);
114
+ printUsage();
115
+ return null;
116
+ }
117
+ }
118
+ }
119
+ // Validate required arguments
120
+ const missing = [];
121
+ if (!options.safeSkillsPath)
122
+ missing.push('--safe-skills (-s)');
123
+ if (!options.importedSkillsPath)
124
+ missing.push('--imported-skills (-i)');
125
+ if (!options.databasePath)
126
+ missing.push('--database (-d)');
127
+ if (missing.length > 0) {
128
+ console.error(`Error: Missing required arguments: ${missing.join(', ')}`);
129
+ printUsage();
130
+ return null;
131
+ }
132
+ return options;
133
+ }
134
+ // ============================================================================
135
+ // File Validation
136
+ // ============================================================================
137
+ function validateFiles(options) {
138
+ let valid = true;
139
+ if (!existsSync(options.safeSkillsPath)) {
140
+ console.error(`Error: Safe skills file not found: ${options.safeSkillsPath}`);
141
+ valid = false;
142
+ }
143
+ if (!existsSync(options.importedSkillsPath)) {
144
+ console.error(`Error: Imported skills file not found: ${options.importedSkillsPath}`);
145
+ valid = false;
146
+ }
147
+ if (!existsSync(options.databasePath)) {
148
+ console.error(`Error: Database file not found: ${options.databasePath}`);
149
+ valid = false;
150
+ }
151
+ return valid;
152
+ }
153
+ // ============================================================================
154
+ // JSON Parsing with Error Handling
155
+ // ============================================================================
156
+ function parseJsonFile(path, description) {
157
+ try {
158
+ const content = readFileSync(path, 'utf-8');
159
+ return JSON.parse(content);
160
+ }
161
+ catch (error) {
162
+ if (error instanceof SyntaxError) {
163
+ console.error(`Error: Invalid JSON in ${description}: ${error.message}`);
164
+ }
165
+ else {
166
+ console.error(`Error: Failed to read ${description}: ${error}`);
167
+ }
168
+ return null;
169
+ }
170
+ }
171
+ // ============================================================================
172
+ // Main Merge Logic
173
+ // ============================================================================
174
+ export async function mergeSkills(options) {
175
+ const startTime = Date.now();
176
+ const report = {
177
+ success: false,
178
+ timestamp: new Date().toISOString(),
179
+ options: {
180
+ ...options,
181
+ safeSkillsPath: resolve(options.safeSkillsPath),
182
+ importedSkillsPath: resolve(options.importedSkillsPath),
183
+ databasePath: resolve(options.databasePath),
184
+ },
185
+ stats: {
186
+ safeSkillsLoaded: 0,
187
+ importedSkillsLoaded: 0,
188
+ skillsWithFullData: 0,
189
+ existingInDatabase: 0,
190
+ newSkillsAdded: 0,
191
+ skippedDuplicates: 0,
192
+ errors: 0,
193
+ },
194
+ errors: [],
195
+ duration: 0,
196
+ };
197
+ const modeLabel = options.dryRun ? '[DRY-RUN]' : '[MERGE]';
198
+ try {
199
+ // ========================================================================
200
+ // Load Safe Skills
201
+ // ========================================================================
202
+ console.log(`${modeLabel} Loading safe skills from: ${options.safeSkillsPath}`);
203
+ const safeSkillsData = parseJsonFile(options.safeSkillsPath, 'safe skills file');
204
+ if (!safeSkillsData) {
205
+ throw new Error('Failed to parse safe skills file');
206
+ }
207
+ const safeRefs = safeSkillsData.skills || safeSkillsData;
208
+ if (!Array.isArray(safeRefs)) {
209
+ throw new Error('Safe skills file must contain a "skills" array or be an array');
210
+ }
211
+ const safeIds = new Set(safeRefs.map((s) => s.skillId));
212
+ report.stats.safeSkillsLoaded = safeIds.size;
213
+ console.log(`${modeLabel} Safe skill IDs loaded: ${safeIds.size}`);
214
+ // ========================================================================
215
+ // Load Imported Skills
216
+ // ========================================================================
217
+ console.log(`${modeLabel} Loading imported skills from: ${options.importedSkillsPath}`);
218
+ const importedData = parseJsonFile(options.importedSkillsPath, 'imported skills file');
219
+ if (!importedData) {
220
+ throw new Error('Failed to parse imported skills file');
221
+ }
222
+ const allSkills = importedData.skills || importedData;
223
+ if (!Array.isArray(allSkills)) {
224
+ throw new Error('Imported skills file must contain a "skills" array or be an array');
225
+ }
226
+ report.stats.importedSkillsLoaded = allSkills.length;
227
+ console.log(`${modeLabel} Total imported skills: ${allSkills.length}`);
228
+ // ========================================================================
229
+ // Filter to Safe Skills with Full Data
230
+ // ========================================================================
231
+ const safeSkills = allSkills.filter((s) => safeIds.has(s.id || ''));
232
+ report.stats.skillsWithFullData = safeSkills.length;
233
+ console.log(`${modeLabel} Safe skills with full data: ${safeSkills.length}`);
234
+ if (safeSkills.length === 0) {
235
+ console.warn(`${modeLabel} Warning: No skills matched between safe list and imported data`);
236
+ }
237
+ // ========================================================================
238
+ // Open Database and Get Existing Skills
239
+ // ========================================================================
240
+ console.log(`${modeLabel} Opening database: ${options.databasePath}`);
241
+ const db = new Database(options.databasePath, {
242
+ readonly: options.dryRun,
243
+ });
244
+ // Get existing repo URLs to avoid duplicates
245
+ const existingRows = db
246
+ .prepare('SELECT repo_url FROM skills WHERE repo_url IS NOT NULL')
247
+ .all();
248
+ const existingUrls = new Set(existingRows.map((row) => row.repo_url?.toLowerCase()));
249
+ report.stats.existingInDatabase = existingUrls.size;
250
+ console.log(`${modeLabel} Existing skills in database: ${existingUrls.size}`);
251
+ // ========================================================================
252
+ // Prepare Insert (if not dry-run)
253
+ // ========================================================================
254
+ let insert = null;
255
+ if (!options.dryRun) {
256
+ insert = db.prepare(`
257
+ INSERT OR IGNORE INTO skills (id, name, description, author, repo_url, quality_score, trust_tier, tags, source, stars, created_at)
258
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
259
+ `);
260
+ }
261
+ // ========================================================================
262
+ // Process Skills in Batches
263
+ // ========================================================================
264
+ const batchSize = 500;
265
+ let newCount = 0;
266
+ let skippedCount = 0;
267
+ const totalBatches = Math.ceil(safeSkills.length / batchSize);
268
+ console.log(`${modeLabel} Processing ${safeSkills.length} skills in ${totalBatches} batches...`);
269
+ const processSkills = options.dryRun
270
+ ? () => {
271
+ // Dry-run: just count what would happen
272
+ for (const skill of safeSkills) {
273
+ const repoUrl = (skill.repo_url || skill.repoUrl)?.toLowerCase();
274
+ if (repoUrl && !existingUrls.has(repoUrl)) {
275
+ newCount++;
276
+ if (options.verbose) {
277
+ console.log(` [WOULD ADD] ${skill.name} (${skill.author || 'unknown'})`);
278
+ }
279
+ }
280
+ else {
281
+ skippedCount++;
282
+ if (options.verbose) {
283
+ console.log(` [WOULD SKIP] ${skill.name} (duplicate)`);
284
+ }
285
+ }
286
+ }
287
+ }
288
+ : db.transaction(() => {
289
+ // Real merge: insert skills in batches
290
+ for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
291
+ const start = batchIndex * batchSize;
292
+ const end = Math.min(start + batchSize, safeSkills.length);
293
+ const batch = safeSkills.slice(start, end);
294
+ let batchNew = 0;
295
+ let batchSkipped = 0;
296
+ for (const skill of batch) {
297
+ const repoUrl = (skill.repo_url || skill.repoUrl)?.toLowerCase();
298
+ if (repoUrl && !existingUrls.has(repoUrl)) {
299
+ try {
300
+ insert.run(skill.id || 'github/' + (skill.author || 'unknown') + '/' + skill.name, skill.name, skill.description || null, skill.author || null, skill.repo_url || skill.repoUrl || null, skill.quality_score ?? skill.qualityScore ?? 0.5, skill.trust_tier ?? skill.trustTier ?? 'community', JSON.stringify(skill.tags || []), skill.source || 'github', skill.stars || 0, skill.created_at || new Date().toISOString());
301
+ newCount++;
302
+ batchNew++;
303
+ existingUrls.add(repoUrl); // Prevent duplicates within same run
304
+ if (options.verbose) {
305
+ console.log(` [ADDED] ${skill.name} (${skill.author || 'unknown'})`);
306
+ }
307
+ }
308
+ catch (error) {
309
+ report.errors.push({
310
+ skillId: skill.id || skill.name,
311
+ error: error instanceof Error ? error.message : String(error),
312
+ });
313
+ report.stats.errors++;
314
+ }
315
+ }
316
+ else {
317
+ skippedCount++;
318
+ batchSkipped++;
319
+ if (options.verbose) {
320
+ console.log(` [SKIPPED] ${skill.name} (duplicate)`);
321
+ }
322
+ }
323
+ }
324
+ console.log(`${modeLabel} Batch ${batchIndex + 1}/${totalBatches}: ${batchNew} added, ${batchSkipped} skipped`);
325
+ }
326
+ });
327
+ processSkills();
328
+ report.stats.newSkillsAdded = newCount;
329
+ report.stats.skippedDuplicates = skippedCount;
330
+ // ========================================================================
331
+ // Get Final Database Count
332
+ // ========================================================================
333
+ const finalCount = db.prepare('SELECT COUNT(*) as count FROM skills').get();
334
+ // Close database
335
+ db.close();
336
+ // Calculate duration
337
+ report.duration = Date.now() - startTime;
338
+ report.success = report.stats.errors === 0;
339
+ // ========================================================================
340
+ // Print Summary
341
+ // ========================================================================
342
+ console.log('');
343
+ console.log('='.repeat(50));
344
+ console.log(options.dryRun ? ' DRY-RUN SUMMARY (no changes made)' : ' MERGE SUMMARY');
345
+ console.log('='.repeat(50));
346
+ console.log(` Safe skills loaded: ${report.stats.safeSkillsLoaded}`);
347
+ console.log(` Imported skills loaded: ${report.stats.importedSkillsLoaded}`);
348
+ console.log(` Skills with full data: ${report.stats.skillsWithFullData}`);
349
+ console.log(` Existing in database: ${report.stats.existingInDatabase}`);
350
+ console.log(` ${options.dryRun ? 'Would add' : 'New skills added'}: ${report.stats.newSkillsAdded}`);
351
+ console.log(` ${options.dryRun ? 'Would skip' : 'Skipped (duplicates)'}: ${report.stats.skippedDuplicates}`);
352
+ console.log(` Errors: ${report.stats.errors}`);
353
+ console.log(` Duration: ${(report.duration / 1000).toFixed(2)}s`);
354
+ if (!options.dryRun) {
355
+ console.log(` Final skill count: ${finalCount.count}`);
356
+ }
357
+ console.log('='.repeat(50));
358
+ if (report.errors.length > 0) {
359
+ console.log('');
360
+ console.log(`Errors (${report.errors.length}):`);
361
+ report.errors.slice(0, 10).forEach((e) => console.log(` - ${e.skillId}: ${e.error}`));
362
+ if (report.errors.length > 10) {
363
+ console.log(` ... and ${report.errors.length - 10} more`);
364
+ }
365
+ }
366
+ console.log('');
367
+ console.log(`${modeLabel} ${options.dryRun ? 'Dry run complete!' : 'Merge complete!'}`);
368
+ }
369
+ catch (error) {
370
+ report.errors.push({
371
+ skillId: 'N/A',
372
+ error: error instanceof Error ? error.message : String(error),
373
+ });
374
+ report.stats.errors++;
375
+ report.duration = Date.now() - startTime;
376
+ console.error(`${modeLabel} Merge failed:`, error);
377
+ }
378
+ return report;
379
+ }
380
+ // ============================================================================
381
+ // Main Entry Point
382
+ // ============================================================================
383
+ async function main() {
384
+ const args = process.argv.slice(2);
385
+ // Handle no arguments
386
+ if (args.length === 0) {
387
+ printUsage();
388
+ process.exit(1);
389
+ }
390
+ // Parse arguments
391
+ const options = parseArgs(args);
392
+ if (!options) {
393
+ process.exit(1);
394
+ }
395
+ // Validate files exist
396
+ if (!validateFiles(options)) {
397
+ process.exit(1);
398
+ }
399
+ // Run merge
400
+ const report = await mergeSkills(options);
401
+ // Exit with appropriate code
402
+ process.exit(report.success ? 0 : 1);
403
+ }
404
+ // Run if executed directly
405
+ if (import.meta.url === `file://${process.argv[1]}`) {
406
+ main().catch((error) => {
407
+ console.error('Fatal error:', error);
408
+ process.exit(1);
409
+ });
410
+ }
411
+ //# sourceMappingURL=merge-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-skills.js","sourceRoot":"","sources":["../../../src/scripts/merge-skills.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,18 @@
1
1
  /**
2
2
  * SMI-864: Security Scanner for Imported Skills
3
3
  * SMI-1189: Refactored into modular structure
4
+ * SMI-XXX: Improved output format with progress bars, tables, and JSON support
4
5
  *
5
6
  * Scans all skills from imported-skills.json for security vulnerabilities
6
7
  * and categorizes them by severity level.
7
8
  *
8
- * Usage: npx tsx packages/core/src/scripts/skill-scanner/index.ts [path-to-imported-skills.json]
9
+ * Usage: npx tsx packages/core/src/scripts/skill-scanner/index.ts [options] [path-to-imported-skills.json]
10
+ *
11
+ * Options:
12
+ * --json Output results in JSON format (machine-readable, CI-friendly)
13
+ * --verbose Show detailed output including all findings
14
+ * --quiet Minimal output (only errors and final summary)
15
+ * --help Show this help message
9
16
  *
10
17
  * Output Files:
11
18
  * - data/security-report.json: Full security report with all findings
@@ -18,5 +25,5 @@ export * from './trust-scorer.js';
18
25
  export * from './file-scanner.js';
19
26
  export * from './logger.js';
20
27
  export * from './reporter.js';
21
- export { scanImportedSkills, DEFAULT_CONFIG } from './scanner.js';
28
+ export { scanImportedSkills, DEFAULT_CONFIG, DEFAULT_CLI_OPTIONS } from './scanner.js';
22
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/scripts/skill-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/scripts/skill-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA"}
@@ -1,11 +1,18 @@
1
1
  /**
2
2
  * SMI-864: Security Scanner for Imported Skills
3
3
  * SMI-1189: Refactored into modular structure
4
+ * SMI-XXX: Improved output format with progress bars, tables, and JSON support
4
5
  *
5
6
  * Scans all skills from imported-skills.json for security vulnerabilities
6
7
  * and categorizes them by severity level.
7
8
  *
8
- * Usage: npx tsx packages/core/src/scripts/skill-scanner/index.ts [path-to-imported-skills.json]
9
+ * Usage: npx tsx packages/core/src/scripts/skill-scanner/index.ts [options] [path-to-imported-skills.json]
10
+ *
11
+ * Options:
12
+ * --json Output results in JSON format (machine-readable, CI-friendly)
13
+ * --verbose Show detailed output including all findings
14
+ * --quiet Minimal output (only errors and final summary)
15
+ * --help Show this help message
9
16
  *
10
17
  * Output Files:
11
18
  * - data/security-report.json: Full security report with all findings
@@ -20,19 +27,103 @@ export * from './trust-scorer.js';
20
27
  export * from './file-scanner.js';
21
28
  export * from './logger.js';
22
29
  export * from './reporter.js';
23
- export { scanImportedSkills, DEFAULT_CONFIG } from './scanner.js';
30
+ export { scanImportedSkills, DEFAULT_CONFIG, DEFAULT_CLI_OPTIONS } from './scanner.js';
31
+ /**
32
+ * Parse command line arguments
33
+ *
34
+ * @param args - Command line arguments (process.argv.slice(2))
35
+ * @returns Parsed CLI options and input path
36
+ */
37
+ function parseArgs(args) {
38
+ const options = {};
39
+ let inputPath = DEFAULT_CONFIG.defaultInput;
40
+ for (const arg of args) {
41
+ if (arg === '--json') {
42
+ options.json = true;
43
+ }
44
+ else if (arg === '--verbose' || arg === '-v') {
45
+ options.verbose = true;
46
+ }
47
+ else if (arg === '--quiet' || arg === '-q') {
48
+ options.quiet = true;
49
+ }
50
+ else if (arg === '--help' || arg === '-h') {
51
+ printHelp();
52
+ process.exit(0);
53
+ }
54
+ else if (!arg.startsWith('-')) {
55
+ inputPath = arg;
56
+ }
57
+ else {
58
+ console.error(`Unknown option: ${arg}`);
59
+ console.error('Use --help for usage information');
60
+ process.exit(1);
61
+ }
62
+ }
63
+ // Validate conflicting options
64
+ if (options.verbose && options.quiet) {
65
+ console.error('Error: --verbose and --quiet cannot be used together');
66
+ process.exit(1);
67
+ }
68
+ return { options, inputPath };
69
+ }
70
+ /**
71
+ * Print help message
72
+ */
73
+ function printHelp() {
74
+ console.log(`
75
+ Skillsmith Security Scanner
76
+
77
+ Usage: npx tsx packages/core/src/scripts/scan-imported-skills.ts [options] [input-file]
78
+
79
+ Options:
80
+ --json Output results in JSON format (machine-readable, CI-friendly)
81
+ --verbose Show detailed output including all findings
82
+ --quiet Minimal output (only errors and final summary)
83
+ --help, -h Show this help message
84
+
85
+ Arguments:
86
+ input-file Path to imported-skills.json (default: ./data/imported-skills.json)
87
+
88
+ Examples:
89
+ # Basic scan with human-readable output
90
+ npx tsx packages/core/src/scripts/scan-imported-skills.ts
91
+
92
+ # JSON output for CI pipelines
93
+ npx tsx packages/core/src/scripts/scan-imported-skills.ts --json
94
+
95
+ # Scan specific file
96
+ npx tsx packages/core/src/scripts/scan-imported-skills.ts ./custom-skills.json
97
+
98
+ # JSON output to file
99
+ npx tsx packages/core/src/scripts/scan-imported-skills.ts --json > results.json
100
+
101
+ Output Files:
102
+ - data/security-report.json Full security report with all findings
103
+ - data/quarantine-skills.json Skills with HIGH/CRITICAL findings (blocked)
104
+ - data/safe-skills.json Skills approved for import (passed security scan)
105
+ `);
106
+ }
24
107
  /**
25
108
  * CLI entry point
26
109
  */
27
110
  async function main() {
28
- // Get input file from command line args or use default
29
- const inputPath = process.argv[2] || DEFAULT_CONFIG.defaultInput;
111
+ const args = process.argv.slice(2);
112
+ const { options, inputPath } = parseArgs(args);
30
113
  try {
31
- await scanImportedSkills(inputPath);
114
+ await scanImportedSkills(inputPath, DEFAULT_CONFIG, options);
32
115
  }
33
116
  catch (error) {
34
- console.error('Fatal error:', error.message);
35
- console.error(error.stack);
117
+ if (options.json) {
118
+ console.log(JSON.stringify({
119
+ success: false,
120
+ error: error.message,
121
+ }));
122
+ }
123
+ else {
124
+ console.error('Fatal error:', error.message);
125
+ console.error(error.stack);
126
+ }
36
127
  process.exit(1);
37
128
  }
38
129
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/scripts/skill-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAEjE,2CAA2C;AAC3C,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAEjE;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,uDAAuD;IACvD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,YAAY,CAAA;IAEhE,IAAI,CAAC;QACH,MAAM,kBAAkB,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,cAAc,EAAG,KAAe,CAAC,OAAO,CAAC,CAAA;QACvD,OAAO,CAAC,KAAK,CAAE,KAAe,CAAC,KAAK,CAAC,CAAA;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAA;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/scripts/skill-scanner/index.ts"],"names":[],"mappings":"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"}