itismyskillmarket 1.2.9 → 1.3.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 +6 -75
- package/dist/index.js +221 -577
- package/package.json +6 -1
- package/src/cli.ts +74 -148
- package/src/commands/info.ts +15 -4
- package/src/commands/install.ts +54 -93
- package/src/commands/ls.ts +17 -182
- package/src/commands/npm.ts +13 -97
- package/src/commands/search.ts +98 -0
- package/src/commands/sync.ts +27 -6
- package/src/commands/uninstall.ts +7 -60
- package/src/commands/update.ts +2 -2
- package/src/index.ts +0 -27
- package/src/types.ts +0 -35
- package/.github/workflows/publish-npm.yml +0 -54
- package/.github/workflows/publish-skill.yml +0 -72
- package/5e51cb7aa8b8e60d49d86f4689f5d4d1.png +0 -0
- package/CHANGELOG.md +0 -255
- package/DEVELOPMENT.md +0 -376
- package/SKILLMARKET-GUIDE.md +0 -288
- package/docs/plans/2026-04-01-skillmarket-design.md +0 -267
- package/docs/plans/2026-04-01-skillmarket-implementation.md +0 -1031
- package/docs/plans/2026-04-15-cross-platform-adapter-design.md +0 -416
- package/docs/plans/2026-04-15-cross-platform-adapter-plan.md +0 -833
- package/docs/plans/2026-04-16-keyword-search-design.md +0 -143
- package/skills/README.md +0 -54
- package/skills/test-skill/SKILL.md +0 -25
- package/skills/test-skill/index.js +0 -66
- package/skills/test-skill/metadata.json +0 -9
- package/skills/test-skill/package.json +0 -19
- package/skills/test-skill-1/SKILL.md +0 -24
- package/skills/test-skill-1/index.js +0 -13
- package/skills/test-skill-1/metadata.json +0 -9
- package/skills/test-skill-1/package.json +0 -16
- package/skills/test-skill-2/SKILL.md +0 -25
- package/skills/test-skill-2/index.js +0 -13
- package/skills/test-skill-2/metadata.json +0 -9
- package/skills/test-skill-2/package.json +0 -16
- package/src/adapters/base.ts +0 -87
- package/src/adapters/claude.ts +0 -31
- package/src/adapters/index.ts +0 -9
- package/src/adapters/opencode.ts +0 -40
- package/src/adapters/registry.ts +0 -77
- package/src/adapters/vscode.ts +0 -62
- package/tsconfig.json +0 -10
- package/tsup.config.ts +0 -22
- package/wanxuchen-skillmarket-1.0.1.tgz +0 -0
package/dist/index.js
CHANGED
|
@@ -2,17 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { readFileSync } from "fs";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
import { dirname, resolve } from "path";
|
|
8
|
-
|
|
9
|
-
// src/commands/registry.ts
|
|
10
|
-
import fs2 from "fs-extra";
|
|
11
|
-
|
|
12
|
-
// src/utils/dirs.ts
|
|
13
|
-
import os from "os";
|
|
14
|
-
import path from "path";
|
|
15
|
-
import fs from "fs-extra";
|
|
16
5
|
|
|
17
6
|
// src/constants.ts
|
|
18
7
|
var MARKET_DIR = "skillmarket";
|
|
@@ -41,7 +30,13 @@ var PLATFORMS = [
|
|
|
41
30
|
var REGISTRY_FILE = "registry.json";
|
|
42
31
|
var LATEST_LINK = "latest";
|
|
43
32
|
|
|
33
|
+
// src/commands/registry.ts
|
|
34
|
+
import fs2 from "fs-extra";
|
|
35
|
+
|
|
44
36
|
// src/utils/dirs.ts
|
|
37
|
+
import os from "os";
|
|
38
|
+
import path from "path";
|
|
39
|
+
import fs from "fs-extra";
|
|
45
40
|
function getMarketHome() {
|
|
46
41
|
return path.join(os.homedir(), MARKET_DIR);
|
|
47
42
|
}
|
|
@@ -100,7 +95,7 @@ async function isSkillInstalled(skillId) {
|
|
|
100
95
|
import https from "https";
|
|
101
96
|
import { URL } from "url";
|
|
102
97
|
async function fetchNpmPackage(packageName) {
|
|
103
|
-
return new Promise((
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
104
99
|
const isScoped = packageName.startsWith("@");
|
|
105
100
|
let encodedName;
|
|
106
101
|
if (isScoped) {
|
|
@@ -126,12 +121,12 @@ async function fetchNpmPackage(packageName) {
|
|
|
126
121
|
try {
|
|
127
122
|
const parsed = JSON.parse(data);
|
|
128
123
|
if (parsed.error) {
|
|
129
|
-
|
|
124
|
+
resolve(null);
|
|
130
125
|
return;
|
|
131
126
|
}
|
|
132
|
-
|
|
127
|
+
resolve(parsed);
|
|
133
128
|
} catch {
|
|
134
|
-
|
|
129
|
+
resolve(null);
|
|
135
130
|
}
|
|
136
131
|
});
|
|
137
132
|
});
|
|
@@ -142,50 +137,12 @@ async function fetchNpmPackage(packageName) {
|
|
|
142
137
|
});
|
|
143
138
|
});
|
|
144
139
|
}
|
|
145
|
-
|
|
146
|
-
"@wanxuchen",
|
|
147
|
-
// 原作者 scope
|
|
148
|
-
"@itismyskillmarket",
|
|
149
|
-
// 当前包名 scope
|
|
150
|
-
"@thisisskillmarket",
|
|
151
|
-
// 曾用 scope
|
|
152
|
-
"@this-is-skillmarket",
|
|
153
|
-
// 曾用 scope (带横线)
|
|
154
|
-
"@skillmarket"
|
|
155
|
-
// 通用 scope
|
|
156
|
-
];
|
|
157
|
-
function getPossiblePackageNames(skillId) {
|
|
158
|
-
if (skillId.startsWith("@")) {
|
|
159
|
-
return [skillId];
|
|
160
|
-
}
|
|
161
|
-
return SKILL_SCOPES.map((scope) => `${scope}/${skillId}`);
|
|
162
|
-
}
|
|
163
|
-
async function fetchSkillPackage(skillId) {
|
|
164
|
-
const packageNames = getPossiblePackageNames(skillId);
|
|
165
|
-
for (const packageName of packageNames) {
|
|
166
|
-
try {
|
|
167
|
-
const info = await fetchNpmPackage(packageName);
|
|
168
|
-
if (info) {
|
|
169
|
-
return info;
|
|
170
|
-
}
|
|
171
|
-
} catch {
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
async function searchSkillmarketPackages(options = {}) {
|
|
177
|
-
const { from = 0, size = 100, keyword } = options;
|
|
140
|
+
async function searchSkillmarketPackages() {
|
|
178
141
|
const packages = [];
|
|
179
|
-
|
|
180
|
-
return new Promise((resolve2, reject) => {
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
181
143
|
const url = new URL("https://registry.npmjs.org/-/v1/search");
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} else {
|
|
185
|
-
url.searchParams.set("text", "keywords:skillmarket");
|
|
186
|
-
}
|
|
187
|
-
url.searchParams.set("size", String(size));
|
|
188
|
-
url.searchParams.set("from", String(from));
|
|
144
|
+
url.searchParams.set("text", "keywords:skillmarket");
|
|
145
|
+
url.searchParams.set("size", "100");
|
|
189
146
|
const req = https.get(url.toString(), { timeout: 1e4 }, (res) => {
|
|
190
147
|
let data = "";
|
|
191
148
|
res.on("data", (chunk) => {
|
|
@@ -194,17 +151,14 @@ async function searchSkillmarketPackages(options = {}) {
|
|
|
194
151
|
res.on("end", () => {
|
|
195
152
|
try {
|
|
196
153
|
const result = JSON.parse(data);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (item?.package?.name) {
|
|
201
|
-
packages.push(item.package.name);
|
|
202
|
-
}
|
|
154
|
+
for (const item of result.objects || []) {
|
|
155
|
+
if (item?.package?.name) {
|
|
156
|
+
packages.push(item.package.name);
|
|
203
157
|
}
|
|
204
158
|
}
|
|
205
|
-
|
|
159
|
+
resolve(packages);
|
|
206
160
|
} catch {
|
|
207
|
-
|
|
161
|
+
resolve([]);
|
|
208
162
|
}
|
|
209
163
|
});
|
|
210
164
|
});
|
|
@@ -217,145 +171,42 @@ async function searchSkillmarketPackages(options = {}) {
|
|
|
217
171
|
}
|
|
218
172
|
|
|
219
173
|
// src/commands/ls.ts
|
|
220
|
-
function filterInstalledSkills(skills, keyword) {
|
|
221
|
-
const lower = keyword.toLowerCase();
|
|
222
|
-
return skills.filter(
|
|
223
|
-
(s) => s.id.toLowerCase().includes(lower) || s.displayName && s.displayName.toLowerCase().includes(lower) || s.description && s.description.toLowerCase().includes(lower)
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
async function searchSkills(keyword, limit = 20) {
|
|
227
|
-
console.log(`Searching npm for "${keyword}"...
|
|
228
|
-
`);
|
|
229
|
-
try {
|
|
230
|
-
const { packages, total } = await searchSkillmarketPackages({
|
|
231
|
-
from: 0,
|
|
232
|
-
size: limit,
|
|
233
|
-
keyword
|
|
234
|
-
});
|
|
235
|
-
if (packages.length === 0) {
|
|
236
|
-
console.log(`No skills found matching "${keyword}".`);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
console.log(`Found ${total} match(es) for "${keyword}":
|
|
240
|
-
`);
|
|
241
|
-
for (const pkgName of packages) {
|
|
242
|
-
try {
|
|
243
|
-
const info = await fetchNpmPackage(pkgName);
|
|
244
|
-
if (!info) {
|
|
245
|
-
console.log(`\u{1F4E6} ${pkgName} (\u4FE1\u606F\u83B7\u53D6\u5931\u8D25)`);
|
|
246
|
-
console.log();
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
const latestVersion = info["dist-tags"]?.latest || "unknown";
|
|
250
|
-
const pkg = info.versions?.[latestVersion];
|
|
251
|
-
const skillMeta = pkg?.skillmarket;
|
|
252
|
-
console.log(`\u{1F4E6} ${info.name}@${latestVersion}`);
|
|
253
|
-
console.log(` \u540D\u79F0: ${skillMeta?.displayName || info.name}`);
|
|
254
|
-
console.log(` \u63CF\u8FF0: ${pkg?.description || "N/A"}`);
|
|
255
|
-
console.log(` \u5E73\u53F0: ${(skillMeta?.platforms || []).join(", ") || "N/A"}`);
|
|
256
|
-
console.log();
|
|
257
|
-
} catch (e) {
|
|
258
|
-
console.log(`\u{1F4E6} ${pkgName} (\u83B7\u53D6\u5931\u8D25: ${e})`);
|
|
259
|
-
console.log();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
} catch (error) {
|
|
263
|
-
console.log(`Error searching skills: ${error}`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
174
|
async function listSkills(options) {
|
|
267
|
-
const { installed, updates
|
|
175
|
+
const { installed, updates } = options;
|
|
268
176
|
if (installed) {
|
|
269
|
-
|
|
270
|
-
if (search) {
|
|
271
|
-
skills = filterInstalledSkills(skills, search);
|
|
272
|
-
}
|
|
273
|
-
const total = skills.length;
|
|
274
|
-
const totalPages = Math.ceil(total / limit) || 1;
|
|
275
|
-
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
177
|
+
const skills = await getInstalledSkills();
|
|
276
178
|
if (skills.length === 0) {
|
|
277
|
-
|
|
278
|
-
console.log(`No skills found matching "${search}".`);
|
|
279
|
-
} else {
|
|
280
|
-
console.log('No skills installed yet. Run "skm ls" to see available skills.');
|
|
281
|
-
}
|
|
179
|
+
console.log('No skills installed yet. Run "skm --ls" to see available skills.');
|
|
282
180
|
return;
|
|
283
181
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
`);
|
|
287
|
-
} else {
|
|
288
|
-
console.log(`Installed Skills (${total}):
|
|
289
|
-
`);
|
|
290
|
-
}
|
|
291
|
-
const start = (currentPage - 1) * limit;
|
|
292
|
-
const end = Math.min(start + limit, total);
|
|
293
|
-
const pageSkills = skills.slice(start, end);
|
|
294
|
-
for (const skill of pageSkills) {
|
|
182
|
+
console.log("Installed Skills:\n");
|
|
183
|
+
for (const skill of skills) {
|
|
295
184
|
console.log(` ${skill.id}@${skill.version}`);
|
|
296
185
|
console.log(` Platforms: ${skill.platforms.join(", ")}`);
|
|
297
186
|
console.log(` Installed: ${skill.installedAt}`);
|
|
298
187
|
console.log();
|
|
299
188
|
}
|
|
300
|
-
console.log(`Page ${currentPage}/${totalPages} (${limit} per page) | Use --page N to navigate`);
|
|
301
189
|
return;
|
|
302
190
|
}
|
|
303
|
-
|
|
304
|
-
console.log(`Searching npm for "${search}"...
|
|
305
|
-
`);
|
|
306
|
-
} else {
|
|
307
|
-
console.log("Searching npm registry...\n");
|
|
308
|
-
}
|
|
191
|
+
console.log("Searching npm registry...\n");
|
|
309
192
|
try {
|
|
310
|
-
const
|
|
311
|
-
const { packages, total } = await searchSkillmarketPackages({
|
|
312
|
-
from: offset,
|
|
313
|
-
size: limit,
|
|
314
|
-
keyword: search
|
|
315
|
-
});
|
|
316
|
-
const totalPages = Math.ceil(total / limit) || 1;
|
|
317
|
-
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
193
|
+
const packages = await searchSkillmarketPackages();
|
|
318
194
|
if (packages.length === 0) {
|
|
319
|
-
|
|
320
|
-
console.log(`No skills found matching "${search}".`);
|
|
321
|
-
} else {
|
|
322
|
-
console.log("No skills found. Check back later!");
|
|
323
|
-
}
|
|
195
|
+
console.log("No skills found. Check back later!");
|
|
324
196
|
return;
|
|
325
197
|
}
|
|
326
|
-
|
|
327
|
-
console.log(`Found ${total} match(es) for "${search}":
|
|
328
|
-
`);
|
|
329
|
-
} else {
|
|
330
|
-
console.log(`Found ${total} skill(s):
|
|
198
|
+
console.log(`Found ${packages.length} skill(s):
|
|
331
199
|
`);
|
|
332
|
-
}
|
|
333
200
|
for (const pkgName of packages) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
console.log(`\u{1F4E6} ${pkgName} (\u4FE1\u606F\u83B7\u53D6\u5931\u8D25)`);
|
|
338
|
-
console.log();
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
const latestVersion = info["dist-tags"]?.latest || "unknown";
|
|
201
|
+
const info = await fetchNpmPackage(pkgName);
|
|
202
|
+
if (info && info["dist-tags"]?.latest) {
|
|
203
|
+
const latestVersion = info["dist-tags"].latest;
|
|
342
204
|
const pkg = info.versions?.[latestVersion];
|
|
343
|
-
|
|
344
|
-
console.log(
|
|
345
|
-
const displayName = skillMeta?.displayName || info.name;
|
|
346
|
-
console.log(` \u540D\u79F0: ${displayName}`);
|
|
347
|
-
console.log(` \u63CF\u8FF0: ${pkg?.description || "N/A"}`);
|
|
348
|
-
const platforms = skillMeta?.platforms || [];
|
|
349
|
-
console.log(` \u5E73\u53F0: ${platforms.length > 0 ? platforms.join(", ") : "N/A"}`);
|
|
350
|
-
const npmLink = pkg?.links?.npm || `https://www.npmjs.com/package/${info.name}`;
|
|
351
|
-
console.log(` \u94FE\u63A5: ${npmLink}`);
|
|
352
|
-
console.log();
|
|
353
|
-
} catch (e) {
|
|
354
|
-
console.log(`\u{1F4E6} ${pkgName} (\u83B7\u53D6\u5931\u8D25: ${e})`);
|
|
205
|
+
console.log(` ${info.name}@${latestVersion}`);
|
|
206
|
+
console.log(` ${pkg?.description || "No description"}`);
|
|
355
207
|
console.log();
|
|
356
208
|
}
|
|
357
209
|
}
|
|
358
|
-
console.log(`Page ${currentPage}/${totalPages} (${limit} per page) | Use --page N to navigate`);
|
|
359
210
|
} catch (error) {
|
|
360
211
|
console.log(`Error fetching skills: ${error}`);
|
|
361
212
|
}
|
|
@@ -363,10 +214,11 @@ async function listSkills(options) {
|
|
|
363
214
|
|
|
364
215
|
// src/commands/info.ts
|
|
365
216
|
async function showSkillInfo(skillId) {
|
|
366
|
-
|
|
217
|
+
const packageName = skillId.startsWith("@") ? skillId : `@skillmarket/${skillId}`;
|
|
218
|
+
console.log(`Fetching info for: ${packageName}
|
|
367
219
|
`);
|
|
368
220
|
try {
|
|
369
|
-
const info = await
|
|
221
|
+
const info = await fetchNpmPackage(packageName);
|
|
370
222
|
if (!info) {
|
|
371
223
|
console.log(`Skill "${skillId}" not found in npm registry.`);
|
|
372
224
|
return;
|
|
@@ -406,344 +258,174 @@ Status: Not installed (use skm install ${skillId} to install)`);
|
|
|
406
258
|
}
|
|
407
259
|
|
|
408
260
|
// src/commands/install.ts
|
|
409
|
-
import
|
|
410
|
-
import
|
|
261
|
+
import fs4 from "fs-extra";
|
|
262
|
+
import path3 from "path";
|
|
411
263
|
import { exec } from "child_process";
|
|
412
264
|
import { promisify } from "util";
|
|
413
265
|
|
|
414
|
-
// src/
|
|
266
|
+
// src/utils/platform.ts
|
|
267
|
+
function detectPlatform() {
|
|
268
|
+
if (process.env.OPENCODE) return "opencode";
|
|
269
|
+
if (process.env.CURSOR) return "cursor";
|
|
270
|
+
if (process.env.VSCODE) return "vscode";
|
|
271
|
+
if (process.env.CLAUDE_CODE) return "claude";
|
|
272
|
+
if (process.env.ANTIGRAVITY) return "antigravity";
|
|
273
|
+
return "codex";
|
|
274
|
+
}
|
|
275
|
+
function isValidPlatform(name) {
|
|
276
|
+
return PLATFORMS.includes(name);
|
|
277
|
+
}
|
|
278
|
+
function getPlatformFromInput(name) {
|
|
279
|
+
const lowerName = name.toLowerCase();
|
|
280
|
+
if (isValidPlatform(lowerName)) {
|
|
281
|
+
return lowerName;
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/commands/sync.ts
|
|
415
287
|
import fs3 from "fs-extra";
|
|
416
288
|
import path2 from "path";
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
async isAvailable() {
|
|
431
|
-
try {
|
|
432
|
-
await fs3.ensureDir(this.skillDir);
|
|
433
|
-
return true;
|
|
434
|
-
} catch {
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
async isInstalled(skillId) {
|
|
439
|
-
const skillFile = this.getSkillFilePath(skillId);
|
|
440
|
-
return fs3.pathExists(skillFile);
|
|
441
|
-
}
|
|
442
|
-
async install(skillId, sourceDir) {
|
|
443
|
-
const targetDir = this.getSkillPath(skillId);
|
|
444
|
-
const targetFile = this.getSkillFilePath(skillId);
|
|
445
|
-
await fs3.ensureDir(targetDir);
|
|
446
|
-
const sourceFile = path2.join(sourceDir, "SKILL.md");
|
|
447
|
-
if (!await fs3.pathExists(sourceFile)) {
|
|
448
|
-
throw new Error(`SKILL.md not found in ${sourceDir}`);
|
|
449
|
-
}
|
|
450
|
-
await fs3.copy(sourceFile, targetFile, { overwrite: true });
|
|
451
|
-
}
|
|
452
|
-
async uninstall(skillId) {
|
|
453
|
-
const targetDir = this.getSkillPath(skillId);
|
|
454
|
-
if (await fs3.pathExists(targetDir)) {
|
|
455
|
-
await fs3.remove(targetDir);
|
|
289
|
+
async function syncPlatformLinks(targetPlatform) {
|
|
290
|
+
await ensureMarketDirs();
|
|
291
|
+
const skillsDir = getSkillsDir();
|
|
292
|
+
const platformLinksDir = getPlatformLinksDir();
|
|
293
|
+
const registry = await loadRegistry();
|
|
294
|
+
let platformsToSync;
|
|
295
|
+
if (targetPlatform) {
|
|
296
|
+
const parsed = getPlatformFromInput(targetPlatform);
|
|
297
|
+
if (!parsed) {
|
|
298
|
+
console.warn(`Invalid platform: ${targetPlatform}, syncing all platforms`);
|
|
299
|
+
platformsToSync = PLATFORMS;
|
|
300
|
+
} else {
|
|
301
|
+
platformsToSync = [parsed];
|
|
456
302
|
}
|
|
303
|
+
} else {
|
|
304
|
+
platformsToSync = PLATFORMS;
|
|
457
305
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
for (const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
306
|
+
const targetDesc = targetPlatform ? targetPlatform : "all platforms";
|
|
307
|
+
console.log(`Syncing platform links to ${targetDesc}...
|
|
308
|
+
`);
|
|
309
|
+
for (const platform of platformsToSync) {
|
|
310
|
+
const platformDir = path2.join(platformLinksDir, platform, "skills");
|
|
311
|
+
await fs3.ensureDir(platformDir);
|
|
312
|
+
for (const [skillId, skillInfo] of Object.entries(registry.skills)) {
|
|
313
|
+
const skillLatestLink = path2.join(skillsDir, skillId, LATEST_LINK);
|
|
314
|
+
const targetPlatformDir = path2.join(skillLatestLink, platform);
|
|
315
|
+
const platformSkillDir = path2.join(platformDir, skillId);
|
|
316
|
+
if (await fs3.pathExists(skillLatestLink)) {
|
|
317
|
+
if (await fs3.pathExists(targetPlatformDir)) {
|
|
318
|
+
try {
|
|
319
|
+
await fs3.remove(platformSkillDir);
|
|
320
|
+
await fs3.symlink(targetPlatformDir, platformSkillDir, "junction");
|
|
321
|
+
console.log(` Linked: ${platform}/${skillId}`);
|
|
322
|
+
} catch {
|
|
323
|
+
await fs3.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
|
|
324
|
+
console.log(` Copied: ${platform}/${skillId}`);
|
|
325
|
+
}
|
|
469
326
|
}
|
|
470
327
|
}
|
|
471
328
|
}
|
|
472
|
-
return skills;
|
|
473
329
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
// src/adapters/opencode.ts
|
|
477
|
-
import path3 from "path";
|
|
478
|
-
import os2 from "os";
|
|
479
|
-
import fs4 from "fs-extra";
|
|
480
|
-
var OpenCodeAdapter = class extends BaseAdapter {
|
|
481
|
-
id = "opencode";
|
|
482
|
-
name = "OpenCode";
|
|
483
|
-
get skillDir() {
|
|
484
|
-
const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os2.homedir(), ".config", "opencode");
|
|
485
|
-
return path3.join(configDir, "skills");
|
|
486
|
-
}
|
|
487
|
-
async isAvailable() {
|
|
488
|
-
if (process.env.OPENCODE) return true;
|
|
489
|
-
const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os2.homedir(), ".config", "opencode");
|
|
490
|
-
try {
|
|
491
|
-
await fs4.ensureDir(path3.join(configDir, "skills"));
|
|
492
|
-
return true;
|
|
493
|
-
} catch {
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
// src/adapters/claude.ts
|
|
500
|
-
import path4 from "path";
|
|
501
|
-
import os3 from "os";
|
|
502
|
-
import fs5 from "fs-extra";
|
|
503
|
-
var ClaudeAdapter = class extends BaseAdapter {
|
|
504
|
-
id = "claude";
|
|
505
|
-
name = "Claude Code";
|
|
506
|
-
get skillDir() {
|
|
507
|
-
return path4.join(os3.homedir(), ".claude", "skills");
|
|
508
|
-
}
|
|
509
|
-
async isAvailable() {
|
|
510
|
-
if (process.env.CLAUDE_CODE) return true;
|
|
511
|
-
const claudeDir = path4.join(os3.homedir(), ".claude");
|
|
512
|
-
return fs5.pathExists(claudeDir);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
// src/adapters/vscode.ts
|
|
517
|
-
import path5 from "path";
|
|
518
|
-
import os4 from "os";
|
|
519
|
-
import fs6 from "fs-extra";
|
|
520
|
-
var VSCodeAdapter = class extends BaseAdapter {
|
|
521
|
-
id = "vscode";
|
|
522
|
-
name = "VSCode";
|
|
523
|
-
get skillDir() {
|
|
524
|
-
return path5.join(os4.homedir(), ".copilot", "skills");
|
|
525
|
-
}
|
|
526
|
-
async isAvailable() {
|
|
527
|
-
const possibleDirs = [
|
|
528
|
-
path5.join(os4.homedir(), ".copilot", "skills"),
|
|
529
|
-
path5.join(os4.homedir(), ".claude", "skills")
|
|
530
|
-
];
|
|
531
|
-
for (const dir of possibleDirs) {
|
|
532
|
-
try {
|
|
533
|
-
await fs6.ensureDir(dir);
|
|
534
|
-
return true;
|
|
535
|
-
} catch {
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return false;
|
|
540
|
-
}
|
|
541
|
-
async install(skillId, sourceDir) {
|
|
542
|
-
await super.install(skillId, sourceDir);
|
|
543
|
-
const claudeSkillDir = path5.join(os4.homedir(), ".claude", "skills");
|
|
544
|
-
const targetPath = this.getSkillPath(skillId);
|
|
545
|
-
const claudeTargetPath = path5.join(claudeSkillDir, skillId);
|
|
546
|
-
try {
|
|
547
|
-
await fs6.ensureDir(claudeSkillDir);
|
|
548
|
-
await fs6.remove(claudeTargetPath);
|
|
549
|
-
await fs6.symlink(targetPath, claudeTargetPath, "junction");
|
|
550
|
-
} catch {
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
// src/adapters/registry.ts
|
|
556
|
-
var adapters = /* @__PURE__ */ new Map();
|
|
557
|
-
function registerAdapters() {
|
|
558
|
-
const opencode = new OpenCodeAdapter();
|
|
559
|
-
const claude = new ClaudeAdapter();
|
|
560
|
-
const vscode = new VSCodeAdapter();
|
|
561
|
-
adapters.set(opencode.id, opencode);
|
|
562
|
-
adapters.set(claude.id, claude);
|
|
563
|
-
adapters.set(vscode.id, vscode);
|
|
564
|
-
}
|
|
565
|
-
registerAdapters();
|
|
566
|
-
async function detectPlatforms() {
|
|
567
|
-
const available = [];
|
|
568
|
-
for (const adapter of adapters.values()) {
|
|
569
|
-
if (await adapter.isAvailable()) {
|
|
570
|
-
available.push(adapter);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
return available;
|
|
574
|
-
}
|
|
575
|
-
function getAdapterByPlatform(platform) {
|
|
576
|
-
const idMap = {
|
|
577
|
-
opencode: "opencode",
|
|
578
|
-
claude: "claude",
|
|
579
|
-
vscode: "vscode",
|
|
580
|
-
cursor: "opencode",
|
|
581
|
-
// Cursor uses OpenCode-compatible structure
|
|
582
|
-
codex: "opencode",
|
|
583
|
-
// Codex uses OpenCode-compatible structure
|
|
584
|
-
antigravity: "opencode"
|
|
585
|
-
// Antigravity uses OpenCode-compatible structure
|
|
586
|
-
};
|
|
587
|
-
return adapters.get(idMap[platform]);
|
|
330
|
+
console.log("\n\u2705 Sync complete!");
|
|
588
331
|
}
|
|
589
332
|
|
|
590
333
|
// src/commands/install.ts
|
|
591
334
|
var execAsync = promisify(exec);
|
|
592
|
-
async function installSkill(skillId, version,
|
|
335
|
+
async function installSkill(skillId, version, targetPlatform) {
|
|
593
336
|
await ensureMarketDirs();
|
|
594
|
-
|
|
595
|
-
const
|
|
337
|
+
const isScoped = skillId.startsWith("@");
|
|
338
|
+
const packageName = isScoped ? skillId : `@skillmarket/${skillId}`;
|
|
339
|
+
const shortName = skillId;
|
|
340
|
+
console.log(`Installing ${packageName}${version ? `@${version}` : ""}...`);
|
|
341
|
+
const pkgInfo = await fetchNpmPackage(packageName);
|
|
596
342
|
if (!pkgInfo) {
|
|
597
|
-
throw new Error(`Package ${
|
|
343
|
+
throw new Error(`Package ${packageName} not found`);
|
|
598
344
|
}
|
|
599
|
-
const packageName = pkgInfo.name;
|
|
600
345
|
const targetVersion = version || pkgInfo["dist-tags"]?.latest;
|
|
601
346
|
if (!targetVersion) {
|
|
602
347
|
throw new Error(`No version found for ${packageName}`);
|
|
603
348
|
}
|
|
604
349
|
const cacheDir = getCacheDir();
|
|
605
|
-
const targetDir =
|
|
606
|
-
if (!await
|
|
350
|
+
const targetDir = path3.join(cacheDir, `${packageName}@${targetVersion}`);
|
|
351
|
+
if (!await fs4.pathExists(targetDir)) {
|
|
607
352
|
console.log("Downloading package...");
|
|
608
|
-
await
|
|
353
|
+
await fs4.ensureDir(cacheDir);
|
|
609
354
|
try {
|
|
610
355
|
await execAsync(`npm pack ${packageName}@${targetVersion} --pack-destination ${cacheDir}`);
|
|
611
|
-
const files = await
|
|
356
|
+
const files = await fs4.readdir(cacheDir);
|
|
612
357
|
const tarball = files.find(
|
|
613
|
-
(f) => f.endsWith(".tgz") && f.includes(packageName.replace(
|
|
358
|
+
(f) => f.endsWith(".tgz") && f.includes(packageName.replace("/", "-"))
|
|
614
359
|
);
|
|
615
360
|
if (tarball) {
|
|
616
|
-
await execAsync(`tar -xzf "${
|
|
617
|
-
await
|
|
618
|
-
const extractedDir =
|
|
361
|
+
await execAsync(`tar -xzf "${path3.join(cacheDir, tarball)}" -C "${cacheDir}"`);
|
|
362
|
+
await fs4.remove(path3.join(cacheDir, tarball));
|
|
363
|
+
const extractedDir = path3.join(cacheDir, "package");
|
|
619
364
|
const finalDir = targetDir;
|
|
620
|
-
await
|
|
365
|
+
await fs4.move(extractedDir, finalDir, { overwrite: true });
|
|
621
366
|
}
|
|
622
367
|
} catch (err) {
|
|
623
368
|
throw new Error(`Failed to download package: ${err}`);
|
|
624
369
|
}
|
|
625
370
|
}
|
|
626
371
|
const skillsDir = getSkillsDir();
|
|
627
|
-
const skillVersionDir =
|
|
372
|
+
const skillVersionDir = path3.join(skillsDir, `${skillId}@${targetVersion}`);
|
|
628
373
|
console.log("Setting up skill...");
|
|
629
|
-
await
|
|
374
|
+
await fs4.ensureDir(skillVersionDir);
|
|
630
375
|
const pkgRoot = targetDir;
|
|
631
|
-
if (await
|
|
632
|
-
await
|
|
633
|
-
|
|
634
|
-
|
|
376
|
+
if (await fs4.pathExists(path3.join(pkgRoot, "SKILL.md"))) {
|
|
377
|
+
await fs4.copy(
|
|
378
|
+
path3.join(pkgRoot, "SKILL.md"),
|
|
379
|
+
path3.join(skillVersionDir, "SKILL.md")
|
|
635
380
|
);
|
|
636
381
|
}
|
|
637
|
-
if (await
|
|
638
|
-
await
|
|
639
|
-
|
|
640
|
-
|
|
382
|
+
if (await fs4.pathExists(path3.join(pkgRoot, "metadata.json"))) {
|
|
383
|
+
await fs4.copy(
|
|
384
|
+
path3.join(pkgRoot, "metadata.json"),
|
|
385
|
+
path3.join(skillVersionDir, "metadata.json")
|
|
641
386
|
);
|
|
642
387
|
}
|
|
643
|
-
const skillDir =
|
|
644
|
-
await
|
|
645
|
-
const latestLink =
|
|
388
|
+
const skillDir = path3.join(skillsDir, skillId);
|
|
389
|
+
await fs4.ensureDir(skillDir);
|
|
390
|
+
const latestLink = path3.join(skillDir, LATEST_LINK);
|
|
646
391
|
try {
|
|
647
|
-
await
|
|
648
|
-
await
|
|
392
|
+
await fs4.remove(latestLink);
|
|
393
|
+
await fs4.symlink(skillVersionDir, latestLink, "junction");
|
|
649
394
|
} catch {
|
|
650
|
-
await
|
|
395
|
+
await fs4.copy(skillVersionDir, path3.join(skillDir, LATEST_LINK), { overwrite: true });
|
|
651
396
|
}
|
|
652
|
-
let
|
|
653
|
-
if (
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
if (adapter) {
|
|
658
|
-
targetAdapters.push(adapter);
|
|
659
|
-
} else {
|
|
660
|
-
console.warn(`\u26A0\uFE0F Unknown platform: ${platformStr}`);
|
|
661
|
-
}
|
|
397
|
+
let finalPlatform;
|
|
398
|
+
if (targetPlatform) {
|
|
399
|
+
const parsed = getPlatformFromInput(targetPlatform);
|
|
400
|
+
if (!parsed) {
|
|
401
|
+
throw new Error(`Invalid platform: ${targetPlatform}. Valid platforms: ${PLATFORMS.join(", ")}`);
|
|
662
402
|
}
|
|
403
|
+
finalPlatform = parsed;
|
|
663
404
|
} else {
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
if (targetAdapters.length === 0) {
|
|
667
|
-
console.log("No target platforms detected.");
|
|
668
|
-
console.log("Use --platform to specify platforms manually.");
|
|
669
|
-
} else {
|
|
670
|
-
console.log(`
|
|
671
|
-
Installing to ${targetAdapters.length} platform(s)...
|
|
672
|
-
`);
|
|
673
|
-
const results = [];
|
|
674
|
-
for (const adapter of targetAdapters) {
|
|
675
|
-
try {
|
|
676
|
-
const isInstalled = await adapter.isInstalled(skillId);
|
|
677
|
-
if (isInstalled && !options?.force) {
|
|
678
|
-
console.log(`${adapter.name.padEnd(12)} \u26A0\uFE0F Already installed (use --force to overwrite)`);
|
|
679
|
-
results.push({ name: adapter.name, status: "skipped" });
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
await adapter.install(skillId, skillVersionDir);
|
|
683
|
-
console.log(`${adapter.name.padEnd(12)} \u2705 Installed successfully`);
|
|
684
|
-
results.push({ name: adapter.name, status: "installed" });
|
|
685
|
-
} catch (error) {
|
|
686
|
-
console.log(`${adapter.name.padEnd(12)} \u274C Failed: ${error}`);
|
|
687
|
-
results.push({ name: adapter.name, status: "failed", error: String(error) });
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
const installed = results.filter((r) => r.status === "installed").length;
|
|
691
|
-
const skipped = results.filter((r) => r.status === "skipped").length;
|
|
692
|
-
const failed = results.filter((r) => r.status === "failed").length;
|
|
693
|
-
console.log(`
|
|
694
|
-
\u{1F4CA} Summary: ${installed} installed, ${skipped} skipped, ${failed} failed`);
|
|
405
|
+
finalPlatform = detectPlatform();
|
|
695
406
|
}
|
|
407
|
+
console.log(`Target platform: ${finalPlatform}`);
|
|
696
408
|
const registry = await loadRegistry();
|
|
697
|
-
const
|
|
409
|
+
const existingSkill = registry.skills[skillId];
|
|
410
|
+
const existingPlatforms = existingSkill?.platforms || [];
|
|
698
411
|
registry.skills[skillId] = {
|
|
699
412
|
id: skillId,
|
|
700
413
|
version: targetVersion,
|
|
701
414
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
702
|
-
platforms:
|
|
415
|
+
platforms: existingPlatforms.includes(finalPlatform) ? existingPlatforms : [...existingPlatforms, finalPlatform]
|
|
703
416
|
};
|
|
704
417
|
await saveRegistry(registry);
|
|
418
|
+
console.log(`Syncing to ${finalPlatform}...`);
|
|
419
|
+
await syncPlatformLinks(finalPlatform);
|
|
705
420
|
console.log(`
|
|
706
421
|
\u2705 ${skillId}@${targetVersion} installed successfully!`);
|
|
707
422
|
console.log(` Use "skm info ${skillId}" for more details`);
|
|
708
423
|
}
|
|
709
424
|
|
|
710
|
-
// src/commands/sync.ts
|
|
711
|
-
import fs8 from "fs-extra";
|
|
712
|
-
import path7 from "path";
|
|
713
|
-
async function syncPlatformLinks() {
|
|
714
|
-
await ensureMarketDirs();
|
|
715
|
-
const skillsDir = getSkillsDir();
|
|
716
|
-
const platformLinksDir = getPlatformLinksDir();
|
|
717
|
-
const registry = await loadRegistry();
|
|
718
|
-
console.log("Syncing platform links...\n");
|
|
719
|
-
for (const platform of PLATFORMS) {
|
|
720
|
-
const platformDir = path7.join(platformLinksDir, platform, "skills");
|
|
721
|
-
await fs8.ensureDir(platformDir);
|
|
722
|
-
for (const [skillId, skillInfo] of Object.entries(registry.skills)) {
|
|
723
|
-
const skillLatestLink = path7.join(skillsDir, skillId, LATEST_LINK);
|
|
724
|
-
const targetPlatformDir = path7.join(skillLatestLink, platform);
|
|
725
|
-
const platformSkillDir = path7.join(platformDir, skillId);
|
|
726
|
-
if (await fs8.pathExists(skillLatestLink)) {
|
|
727
|
-
if (await fs8.pathExists(targetPlatformDir)) {
|
|
728
|
-
try {
|
|
729
|
-
await fs8.remove(platformSkillDir);
|
|
730
|
-
await fs8.symlink(targetPlatformDir, platformSkillDir, "junction");
|
|
731
|
-
console.log(` Linked: ${platform}/${skillId}`);
|
|
732
|
-
} catch {
|
|
733
|
-
await fs8.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
|
|
734
|
-
console.log(` Copied: ${platform}/${skillId}`);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
console.log("\n\u2705 Sync complete!");
|
|
741
|
-
}
|
|
742
|
-
|
|
743
425
|
// src/commands/update.ts
|
|
744
426
|
async function updateSkill(skillId) {
|
|
745
427
|
if (skillId) {
|
|
746
|
-
const pkgInfo = await fetchNpmPackage(`@
|
|
428
|
+
const pkgInfo = await fetchNpmPackage(`@skillmarket/${skillId}`);
|
|
747
429
|
if (pkgInfo) {
|
|
748
430
|
const latestVersion = pkgInfo["dist-tags"]?.latest;
|
|
749
431
|
console.log(`Updating ${skillId} to ${latestVersion}...`);
|
|
@@ -760,7 +442,7 @@ async function updateSkill(skillId) {
|
|
|
760
442
|
`);
|
|
761
443
|
let hasUpdates = false;
|
|
762
444
|
for (const skill of installed) {
|
|
763
|
-
const pkgInfo = await fetchNpmPackage(`@
|
|
445
|
+
const pkgInfo = await fetchNpmPackage(`@skillmarket/${skill.id}`);
|
|
764
446
|
if (pkgInfo) {
|
|
765
447
|
const latestVersion = pkgInfo["dist-tags"]?.latest;
|
|
766
448
|
if (latestVersion && latestVersion !== skill.version) {
|
|
@@ -782,9 +464,9 @@ async function updateSkill(skillId) {
|
|
|
782
464
|
}
|
|
783
465
|
|
|
784
466
|
// src/commands/uninstall.ts
|
|
785
|
-
import
|
|
786
|
-
import
|
|
787
|
-
async function uninstallSkill(skillId
|
|
467
|
+
import fs5 from "fs-extra";
|
|
468
|
+
import path4 from "path";
|
|
469
|
+
async function uninstallSkill(skillId) {
|
|
788
470
|
const registry = await loadRegistry();
|
|
789
471
|
if (!(skillId in registry.skills)) {
|
|
790
472
|
console.log(`Skill "${skillId}" is not installed.`);
|
|
@@ -792,37 +474,14 @@ async function uninstallSkill(skillId, options) {
|
|
|
792
474
|
}
|
|
793
475
|
const skillInfo = registry.skills[skillId];
|
|
794
476
|
console.log(`Uninstalling ${skillId}@${skillInfo.version}...`);
|
|
795
|
-
let targetAdapters = [];
|
|
796
|
-
if (options?.platforms && options.platforms.length > 0) {
|
|
797
|
-
for (const platformStr of options.platforms) {
|
|
798
|
-
const platform = platformStr;
|
|
799
|
-
targetAdapters.push(getAdapterByPlatform(platform));
|
|
800
|
-
}
|
|
801
|
-
} else {
|
|
802
|
-
targetAdapters = await detectPlatforms();
|
|
803
|
-
}
|
|
804
|
-
const validAdapters = targetAdapters.filter((a) => a !== void 0);
|
|
805
|
-
if (validAdapters.length > 0) {
|
|
806
|
-
console.log(`
|
|
807
|
-
Uninstalling from ${validAdapters.length} platform(s)...
|
|
808
|
-
`);
|
|
809
|
-
for (const adapter of validAdapters) {
|
|
810
|
-
try {
|
|
811
|
-
await adapter.uninstall(skillId);
|
|
812
|
-
console.log(`${adapter.name.padEnd(12)} \u2705 Uninstalled`);
|
|
813
|
-
} catch (error) {
|
|
814
|
-
console.log(`${adapter.name.padEnd(12)} \u274C Failed: ${error}`);
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
477
|
const skillsDir = getSkillsDir();
|
|
819
|
-
const skillDir =
|
|
820
|
-
await
|
|
478
|
+
const skillDir = path4.join(skillsDir, skillId);
|
|
479
|
+
await fs5.remove(skillDir);
|
|
821
480
|
const platformLinksDir = getPlatformLinksDir();
|
|
822
481
|
for (const platform of PLATFORMS) {
|
|
823
|
-
const linkPath =
|
|
824
|
-
if (await
|
|
825
|
-
await
|
|
482
|
+
const linkPath = path4.join(platformLinksDir, platform, "skills", skillId);
|
|
483
|
+
if (await fs5.pathExists(linkPath)) {
|
|
484
|
+
await fs5.remove(linkPath);
|
|
826
485
|
}
|
|
827
486
|
}
|
|
828
487
|
delete registry.skills[skillId];
|
|
@@ -831,95 +490,92 @@ Uninstalling from ${validAdapters.length} platform(s)...
|
|
|
831
490
|
\u2705 ${skillId} uninstalled successfully!`);
|
|
832
491
|
}
|
|
833
492
|
|
|
493
|
+
// src/commands/search.ts
|
|
494
|
+
async function searchSkills(keyword) {
|
|
495
|
+
console.log(`Searching for "${keyword}"...
|
|
496
|
+
`);
|
|
497
|
+
try {
|
|
498
|
+
const packages = await searchSkillmarketPackages();
|
|
499
|
+
const filtered = packages.filter(
|
|
500
|
+
(pkg) => pkg.toLowerCase().includes(keyword.toLowerCase())
|
|
501
|
+
);
|
|
502
|
+
if (filtered.length === 0) {
|
|
503
|
+
console.log(`No skills found matching "${keyword}".`);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
console.log(`Found ${filtered.length} skill(s):
|
|
507
|
+
`);
|
|
508
|
+
for (const pkgName of filtered) {
|
|
509
|
+
const info = await fetchNpmPackage(pkgName);
|
|
510
|
+
if (info && info["dist-tags"]?.latest) {
|
|
511
|
+
const latestVersion = info["dist-tags"].latest;
|
|
512
|
+
const pkg = info.versions?.[latestVersion];
|
|
513
|
+
console.log(` ${info.name}@${latestVersion}`);
|
|
514
|
+
console.log(` ${pkg?.description || "No description"}`);
|
|
515
|
+
console.log();
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
} catch (error) {
|
|
519
|
+
console.log(`Error searching skills: ${error}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
834
523
|
// src/cli.ts
|
|
835
|
-
var __filename = fileURLToPath(import.meta.url);
|
|
836
|
-
var __dirname = dirname(__filename);
|
|
837
|
-
var packageJson = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf-8"));
|
|
838
|
-
var VERSION = packageJson.version;
|
|
839
524
|
var program = new Command();
|
|
840
|
-
program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version(
|
|
841
|
-
program.
|
|
842
|
-
|
|
843
|
-
|
|
525
|
+
program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version("1.2.10");
|
|
526
|
+
var helpCmd = program.command("help").description("Display help information");
|
|
527
|
+
helpCmd.action(() => {
|
|
528
|
+
console.log(`
|
|
844
529
|
SkillMarket CLI
|
|
845
530
|
|
|
846
531
|
Usage: skm <command> [options]
|
|
847
532
|
|
|
848
533
|
Commands:
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
update [options] Update skills
|
|
863
|
-
--all Update all skills
|
|
864
|
-
sync Synchronize platform links
|
|
865
|
-
platforms Show available platforms
|
|
534
|
+
--help, -h Display this help message
|
|
535
|
+
--ls [options] List available skills
|
|
536
|
+
--installed Show only installed skills
|
|
537
|
+
--updates Check for updates
|
|
538
|
+
--info <skill-id> Display skill information
|
|
539
|
+
--install <skill> Install a skill (e.g., skm --install brainstorming)
|
|
540
|
+
@version Install specific version
|
|
541
|
+
--all Install all available skills
|
|
542
|
+
--uninstall <skill> Remove an installed skill
|
|
543
|
+
--update [options] Update skills
|
|
544
|
+
--all Update all skills
|
|
545
|
+
--sync Synchronize platform links
|
|
546
|
+
--platform <name> Set target platform (${PLATFORMS.join(", ")})
|
|
866
547
|
|
|
867
548
|
Examples:
|
|
868
|
-
skm ls
|
|
869
|
-
skm ls --
|
|
870
|
-
skm
|
|
871
|
-
skm
|
|
872
|
-
skm
|
|
873
|
-
skm
|
|
874
|
-
skm
|
|
875
|
-
|
|
876
|
-
skm info brainstorming View skill details
|
|
877
|
-
skm install brainstorming Install to all platforms
|
|
878
|
-
skm install brainstorming --platform opencode Install to OpenCode only
|
|
879
|
-
skm install brainstorming --platform claude,vscode Install to multiple
|
|
880
|
-
skm uninstall brainstorming
|
|
881
|
-
skm platforms Show available platforms
|
|
882
|
-
`);
|
|
883
|
-
process.exit(0);
|
|
884
|
-
}
|
|
549
|
+
skm --ls List all available skills
|
|
550
|
+
skm --ls --installed Show installed skills only
|
|
551
|
+
skm --info brainstorming View skill details
|
|
552
|
+
skm --install brainstorming Install a skill
|
|
553
|
+
skm --install brainstorming@1.0.0 Install specific version
|
|
554
|
+
skm --update --all Update all installed skills
|
|
555
|
+
skm --sync Sync platform links
|
|
556
|
+
`);
|
|
885
557
|
});
|
|
886
558
|
var lsCmd = program.command("ls").description("List available skills");
|
|
887
|
-
lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").
|
|
888
|
-
|
|
889
|
-
...opts,
|
|
890
|
-
page: opts.page ?? 1,
|
|
891
|
-
limit: opts.limit ?? 20,
|
|
892
|
-
search: opts.search
|
|
893
|
-
};
|
|
894
|
-
listSkills(options);
|
|
895
|
-
});
|
|
896
|
-
var searchCmd = program.command("search").description("Search skills from npm registry");
|
|
897
|
-
searchCmd.argument("<keyword>", "Keyword to search").option("-l, --limit <number>", "Max results to show (default: 20)", parseInt).action(async (keyword, opts) => {
|
|
898
|
-
const limit = opts.limit ?? 20;
|
|
899
|
-
await searchSkills(keyword, limit);
|
|
559
|
+
lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").action((opts) => {
|
|
560
|
+
listSkills(opts);
|
|
900
561
|
});
|
|
901
562
|
var infoCmd = program.command("info").description("Display skill information");
|
|
902
563
|
infoCmd.argument("<skill-id>", "Skill ID to show info").action((skillId) => {
|
|
903
564
|
showSkillInfo(skillId);
|
|
904
565
|
});
|
|
905
|
-
var installCmd = program.command("install").description("Install a skill
|
|
906
|
-
installCmd.argument("<skill>", "Skill ID to install (e.g., brainstorming or @scope/name)").option("
|
|
566
|
+
var installCmd = program.command("install").description("Install a skill");
|
|
567
|
+
installCmd.argument("<skill>", "Skill ID to install (e.g., brainstorming or @scope/name)").option("--all", "Install all available skills").option("-p, --platform <platform>", `Target platform (${PLATFORMS.join(", ")})`).action(async (skill, opts) => {
|
|
907
568
|
try {
|
|
908
|
-
|
|
909
|
-
await installSkill(skill, opts.version, {
|
|
910
|
-
platforms,
|
|
911
|
-
force: opts.force
|
|
912
|
-
});
|
|
569
|
+
await installSkill(skill, void 0, opts.platform);
|
|
913
570
|
} catch (err) {
|
|
914
571
|
console.error("Installation failed:", err);
|
|
915
572
|
process.exit(1);
|
|
916
573
|
}
|
|
917
574
|
});
|
|
918
|
-
var uninstallCmd = program.command("uninstall").description("Remove an installed skill
|
|
919
|
-
uninstallCmd.argument("<skill>", "Skill ID to uninstall").
|
|
575
|
+
var uninstallCmd = program.command("uninstall").description("Remove an installed skill");
|
|
576
|
+
uninstallCmd.argument("<skill>", "Skill ID to uninstall").action(async (skill) => {
|
|
920
577
|
try {
|
|
921
|
-
|
|
922
|
-
await uninstallSkill(skill, { platforms });
|
|
578
|
+
await uninstallSkill(skill);
|
|
923
579
|
} catch (err) {
|
|
924
580
|
console.error("Uninstall failed:", err);
|
|
925
581
|
process.exit(1);
|
|
@@ -946,28 +602,16 @@ program.command("sync").description("Synchronize platform links").action(async (
|
|
|
946
602
|
process.exit(1);
|
|
947
603
|
}
|
|
948
604
|
});
|
|
949
|
-
var
|
|
950
|
-
|
|
605
|
+
var platformCmd = program.command("platform").description("Set target platform");
|
|
606
|
+
platformCmd.argument("<name>", "Platform name").action((name) => {
|
|
607
|
+
console.log("Platform command - name:", name);
|
|
608
|
+
});
|
|
609
|
+
var searchCmd = program.command("search").description("Search skills from npm registry");
|
|
610
|
+
searchCmd.argument("<keyword>", "Keyword to search").action(async (keyword) => {
|
|
951
611
|
try {
|
|
952
|
-
|
|
953
|
-
console.log("\n\u{1F4CD} Available Platforms:\n");
|
|
954
|
-
const allPlatforms = [
|
|
955
|
-
{ name: "OpenCode", adapter: new OpenCodeAdapter() },
|
|
956
|
-
{ name: "Claude Code", adapter: new ClaudeAdapter() },
|
|
957
|
-
{ name: "VSCode", adapter: new VSCodeAdapter() }
|
|
958
|
-
];
|
|
959
|
-
for (const { name, adapter } of allPlatforms) {
|
|
960
|
-
const isAvailable = available.find((a) => a.id === adapter.id);
|
|
961
|
-
const installed = await adapter.listInstalled();
|
|
962
|
-
if (isAvailable) {
|
|
963
|
-
console.log(`${name.padEnd(12)} \u2705 Available (${installed.length} skills installed)`);
|
|
964
|
-
} else {
|
|
965
|
-
console.log(`${name.padEnd(12)} \u274C Not detected`);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
console.log("");
|
|
612
|
+
await searchSkills(keyword);
|
|
969
613
|
} catch (err) {
|
|
970
|
-
console.error("
|
|
614
|
+
console.error("Search failed:", err);
|
|
971
615
|
process.exit(1);
|
|
972
616
|
}
|
|
973
617
|
});
|