@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.
- package/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/db/schema.d.ts +1 -1
- package/dist/src/db/schema.d.ts.map +1 -1
- package/dist/src/db/schema.js +41 -1
- package/dist/src/db/schema.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/repositories/SyncConfigRepository.d.ts +91 -0
- package/dist/src/repositories/SyncConfigRepository.d.ts.map +1 -0
- package/dist/src/repositories/SyncConfigRepository.js +202 -0
- package/dist/src/repositories/SyncConfigRepository.js.map +1 -0
- package/dist/src/repositories/SyncHistoryRepository.d.ts +104 -0
- package/dist/src/repositories/SyncHistoryRepository.d.ts.map +1 -0
- package/dist/src/repositories/SyncHistoryRepository.js +235 -0
- package/dist/src/repositories/SyncHistoryRepository.js.map +1 -0
- package/dist/src/scripts/github-import/github-client.d.ts +24 -0
- package/dist/src/scripts/github-import/github-client.d.ts.map +1 -1
- package/dist/src/scripts/github-import/github-client.js +103 -0
- package/dist/src/scripts/github-import/github-client.js.map +1 -1
- package/dist/src/scripts/github-import/index.js +3 -10
- package/dist/src/scripts/github-import/index.js.map +1 -1
- package/dist/src/scripts/merge-skills.d.ts +56 -0
- package/dist/src/scripts/merge-skills.d.ts.map +1 -0
- package/dist/src/scripts/merge-skills.js +411 -0
- package/dist/src/scripts/merge-skills.js.map +1 -0
- package/dist/src/scripts/skill-scanner/index.d.ts +9 -2
- package/dist/src/scripts/skill-scanner/index.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/index.js +98 -7
- package/dist/src/scripts/skill-scanner/index.js.map +1 -1
- package/dist/src/scripts/skill-scanner/logger.d.ts +51 -0
- package/dist/src/scripts/skill-scanner/logger.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/logger.js +255 -1
- package/dist/src/scripts/skill-scanner/logger.js.map +1 -1
- package/dist/src/scripts/skill-scanner/reporter.d.ts +1 -1
- package/dist/src/scripts/skill-scanner/reporter.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/reporter.js +67 -15
- package/dist/src/scripts/skill-scanner/reporter.js.map +1 -1
- package/dist/src/scripts/skill-scanner/scanner.d.ts +5 -2
- package/dist/src/scripts/skill-scanner/scanner.d.ts.map +1 -1
- package/dist/src/scripts/skill-scanner/scanner.js +156 -39
- package/dist/src/scripts/skill-scanner/scanner.js.map +1 -1
- package/dist/src/scripts/skill-scanner/types.d.ts +44 -0
- package/dist/src/scripts/skill-scanner/types.d.ts.map +1 -1
- package/dist/src/sync/BackgroundSyncService.d.ts +90 -0
- package/dist/src/sync/BackgroundSyncService.d.ts.map +1 -0
- package/dist/src/sync/BackgroundSyncService.js +214 -0
- package/dist/src/sync/BackgroundSyncService.js.map +1 -0
- package/dist/src/sync/SyncEngine.d.ts +76 -0
- package/dist/src/sync/SyncEngine.d.ts.map +1 -0
- package/dist/src/sync/SyncEngine.js +272 -0
- package/dist/src/sync/SyncEngine.js.map +1 -0
- package/dist/src/sync/index.d.ts +11 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +14 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/tests/sync/SyncConfigRepository.test.d.ts +7 -0
- package/dist/tests/sync/SyncConfigRepository.test.d.ts.map +1 -0
- package/dist/tests/sync/SyncConfigRepository.test.js +154 -0
- package/dist/tests/sync/SyncConfigRepository.test.js.map +1 -0
- package/dist/tests/sync/SyncEngine.test.d.ts +7 -0
- package/dist/tests/sync/SyncEngine.test.d.ts.map +1 -0
- package/dist/tests/sync/SyncEngine.test.js +298 -0
- package/dist/tests/sync/SyncEngine.test.js.map +1 -0
- package/dist/tests/sync/SyncHistoryRepository.test.d.ts +7 -0
- package/dist/tests/sync/SyncHistoryRepository.test.d.ts.map +1 -0
- package/dist/tests/sync/SyncHistoryRepository.test.js +220 -0
- package/dist/tests/sync/SyncHistoryRepository.test.js.map +1 -0
- 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
|
|
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
|
-
|
|
29
|
-
const inputPath =
|
|
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
|
-
|
|
35
|
-
|
|
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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/scripts/skill-scanner/index.ts"],"names":[],"mappings":"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"}
|