itismyskillmarket 1.2.8 → 1.2.10
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 +186 -536
- package/package.json +6 -1
- package/src/cli.ts +49 -128
- package/src/commands/info.ts +15 -4
- package/src/commands/install.ts +54 -93
- package/src/commands/ls.ts +17 -129
- package/src/commands/npm.ts +13 -97
- 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,105 +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
174
|
async function listSkills(options) {
|
|
227
|
-
const { installed, updates
|
|
175
|
+
const { installed, updates } = options;
|
|
228
176
|
if (installed) {
|
|
229
|
-
|
|
230
|
-
if (search) {
|
|
231
|
-
skills = filterInstalledSkills(skills, search);
|
|
232
|
-
}
|
|
233
|
-
const total = skills.length;
|
|
234
|
-
const totalPages = Math.ceil(total / limit) || 1;
|
|
235
|
-
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
177
|
+
const skills = await getInstalledSkills();
|
|
236
178
|
if (skills.length === 0) {
|
|
237
|
-
|
|
238
|
-
console.log(`No skills found matching "${search}".`);
|
|
239
|
-
} else {
|
|
240
|
-
console.log('No skills installed yet. Run "skm ls" to see available skills.');
|
|
241
|
-
}
|
|
179
|
+
console.log('No skills installed yet. Run "skm --ls" to see available skills.');
|
|
242
180
|
return;
|
|
243
181
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
`);
|
|
247
|
-
} else {
|
|
248
|
-
console.log(`Installed Skills (${total}):
|
|
249
|
-
`);
|
|
250
|
-
}
|
|
251
|
-
const start = (currentPage - 1) * limit;
|
|
252
|
-
const end = Math.min(start + limit, total);
|
|
253
|
-
const pageSkills = skills.slice(start, end);
|
|
254
|
-
for (const skill of pageSkills) {
|
|
182
|
+
console.log("Installed Skills:\n");
|
|
183
|
+
for (const skill of skills) {
|
|
255
184
|
console.log(` ${skill.id}@${skill.version}`);
|
|
256
185
|
console.log(` Platforms: ${skill.platforms.join(", ")}`);
|
|
257
186
|
console.log(` Installed: ${skill.installedAt}`);
|
|
258
187
|
console.log();
|
|
259
188
|
}
|
|
260
|
-
console.log(`Page ${currentPage}/${totalPages} (${limit} per page) | Use --page N to navigate`);
|
|
261
189
|
return;
|
|
262
190
|
}
|
|
263
|
-
|
|
264
|
-
console.log(`Searching npm for "${search}"...
|
|
265
|
-
`);
|
|
266
|
-
} else {
|
|
267
|
-
console.log("Searching npm registry...\n");
|
|
268
|
-
}
|
|
191
|
+
console.log("Searching npm registry...\n");
|
|
269
192
|
try {
|
|
270
|
-
const
|
|
271
|
-
const { packages, total } = await searchSkillmarketPackages({
|
|
272
|
-
from: offset,
|
|
273
|
-
size: limit,
|
|
274
|
-
keyword: search
|
|
275
|
-
});
|
|
276
|
-
const totalPages = Math.ceil(total / limit) || 1;
|
|
277
|
-
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
193
|
+
const packages = await searchSkillmarketPackages();
|
|
278
194
|
if (packages.length === 0) {
|
|
279
|
-
|
|
280
|
-
console.log(`No skills found matching "${search}".`);
|
|
281
|
-
} else {
|
|
282
|
-
console.log("No skills found. Check back later!");
|
|
283
|
-
}
|
|
195
|
+
console.log("No skills found. Check back later!");
|
|
284
196
|
return;
|
|
285
197
|
}
|
|
286
|
-
|
|
287
|
-
console.log(`Found ${total} match(es) for "${search}":
|
|
198
|
+
console.log(`Found ${packages.length} skill(s):
|
|
288
199
|
`);
|
|
289
|
-
} else {
|
|
290
|
-
console.log(`Found ${total} skill(s):
|
|
291
|
-
`);
|
|
292
|
-
}
|
|
293
200
|
for (const pkgName of packages) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
console.log(`\u{1F4E6} ${pkgName} (\u4FE1\u606F\u83B7\u53D6\u5931\u8D25)`);
|
|
298
|
-
console.log();
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
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;
|
|
302
204
|
const pkg = info.versions?.[latestVersion];
|
|
303
|
-
|
|
304
|
-
console.log(
|
|
305
|
-
const displayName = skillMeta?.displayName || info.name;
|
|
306
|
-
console.log(` \u540D\u79F0: ${displayName}`);
|
|
307
|
-
console.log(` \u63CF\u8FF0: ${pkg?.description || "N/A"}`);
|
|
308
|
-
const platforms = skillMeta?.platforms || [];
|
|
309
|
-
console.log(` \u5E73\u53F0: ${platforms.length > 0 ? platforms.join(", ") : "N/A"}`);
|
|
310
|
-
const npmLink = pkg?.links?.npm || `https://www.npmjs.com/package/${info.name}`;
|
|
311
|
-
console.log(` \u94FE\u63A5: ${npmLink}`);
|
|
312
|
-
console.log();
|
|
313
|
-
} catch (e) {
|
|
314
|
-
console.log(`\u{1F4E6} ${pkgName} (\u83B7\u53D6\u5931\u8D25: ${e})`);
|
|
205
|
+
console.log(` ${info.name}@${latestVersion}`);
|
|
206
|
+
console.log(` ${pkg?.description || "No description"}`);
|
|
315
207
|
console.log();
|
|
316
208
|
}
|
|
317
209
|
}
|
|
318
|
-
console.log(`Page ${currentPage}/${totalPages} (${limit} per page) | Use --page N to navigate`);
|
|
319
210
|
} catch (error) {
|
|
320
211
|
console.log(`Error fetching skills: ${error}`);
|
|
321
212
|
}
|
|
@@ -323,10 +214,11 @@ async function listSkills(options) {
|
|
|
323
214
|
|
|
324
215
|
// src/commands/info.ts
|
|
325
216
|
async function showSkillInfo(skillId) {
|
|
326
|
-
|
|
217
|
+
const packageName = skillId.startsWith("@") ? skillId : `@skillmarket/${skillId}`;
|
|
218
|
+
console.log(`Fetching info for: ${packageName}
|
|
327
219
|
`);
|
|
328
220
|
try {
|
|
329
|
-
const info = await
|
|
221
|
+
const info = await fetchNpmPackage(packageName);
|
|
330
222
|
if (!info) {
|
|
331
223
|
console.log(`Skill "${skillId}" not found in npm registry.`);
|
|
332
224
|
return;
|
|
@@ -366,344 +258,174 @@ Status: Not installed (use skm install ${skillId} to install)`);
|
|
|
366
258
|
}
|
|
367
259
|
|
|
368
260
|
// src/commands/install.ts
|
|
369
|
-
import
|
|
370
|
-
import
|
|
261
|
+
import fs4 from "fs-extra";
|
|
262
|
+
import path3 from "path";
|
|
371
263
|
import { exec } from "child_process";
|
|
372
264
|
import { promisify } from "util";
|
|
373
265
|
|
|
374
|
-
// 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
|
|
375
287
|
import fs3 from "fs-extra";
|
|
376
288
|
import path2 from "path";
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
async isAvailable() {
|
|
391
|
-
try {
|
|
392
|
-
await fs3.ensureDir(this.skillDir);
|
|
393
|
-
return true;
|
|
394
|
-
} catch {
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
async isInstalled(skillId) {
|
|
399
|
-
const skillFile = this.getSkillFilePath(skillId);
|
|
400
|
-
return fs3.pathExists(skillFile);
|
|
401
|
-
}
|
|
402
|
-
async install(skillId, sourceDir) {
|
|
403
|
-
const targetDir = this.getSkillPath(skillId);
|
|
404
|
-
const targetFile = this.getSkillFilePath(skillId);
|
|
405
|
-
await fs3.ensureDir(targetDir);
|
|
406
|
-
const sourceFile = path2.join(sourceDir, "SKILL.md");
|
|
407
|
-
if (!await fs3.pathExists(sourceFile)) {
|
|
408
|
-
throw new Error(`SKILL.md not found in ${sourceDir}`);
|
|
409
|
-
}
|
|
410
|
-
await fs3.copy(sourceFile, targetFile, { overwrite: true });
|
|
411
|
-
}
|
|
412
|
-
async uninstall(skillId) {
|
|
413
|
-
const targetDir = this.getSkillPath(skillId);
|
|
414
|
-
if (await fs3.pathExists(targetDir)) {
|
|
415
|
-
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];
|
|
416
302
|
}
|
|
303
|
+
} else {
|
|
304
|
+
platformsToSync = PLATFORMS;
|
|
417
305
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
for (const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
+
}
|
|
429
326
|
}
|
|
430
327
|
}
|
|
431
328
|
}
|
|
432
|
-
return skills;
|
|
433
329
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// src/adapters/opencode.ts
|
|
437
|
-
import path3 from "path";
|
|
438
|
-
import os2 from "os";
|
|
439
|
-
import fs4 from "fs-extra";
|
|
440
|
-
var OpenCodeAdapter = class extends BaseAdapter {
|
|
441
|
-
id = "opencode";
|
|
442
|
-
name = "OpenCode";
|
|
443
|
-
get skillDir() {
|
|
444
|
-
const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os2.homedir(), ".config", "opencode");
|
|
445
|
-
return path3.join(configDir, "skills");
|
|
446
|
-
}
|
|
447
|
-
async isAvailable() {
|
|
448
|
-
if (process.env.OPENCODE) return true;
|
|
449
|
-
const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os2.homedir(), ".config", "opencode");
|
|
450
|
-
try {
|
|
451
|
-
await fs4.ensureDir(path3.join(configDir, "skills"));
|
|
452
|
-
return true;
|
|
453
|
-
} catch {
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
// src/adapters/claude.ts
|
|
460
|
-
import path4 from "path";
|
|
461
|
-
import os3 from "os";
|
|
462
|
-
import fs5 from "fs-extra";
|
|
463
|
-
var ClaudeAdapter = class extends BaseAdapter {
|
|
464
|
-
id = "claude";
|
|
465
|
-
name = "Claude Code";
|
|
466
|
-
get skillDir() {
|
|
467
|
-
return path4.join(os3.homedir(), ".claude", "skills");
|
|
468
|
-
}
|
|
469
|
-
async isAvailable() {
|
|
470
|
-
if (process.env.CLAUDE_CODE) return true;
|
|
471
|
-
const claudeDir = path4.join(os3.homedir(), ".claude");
|
|
472
|
-
return fs5.pathExists(claudeDir);
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
// src/adapters/vscode.ts
|
|
477
|
-
import path5 from "path";
|
|
478
|
-
import os4 from "os";
|
|
479
|
-
import fs6 from "fs-extra";
|
|
480
|
-
var VSCodeAdapter = class extends BaseAdapter {
|
|
481
|
-
id = "vscode";
|
|
482
|
-
name = "VSCode";
|
|
483
|
-
get skillDir() {
|
|
484
|
-
return path5.join(os4.homedir(), ".copilot", "skills");
|
|
485
|
-
}
|
|
486
|
-
async isAvailable() {
|
|
487
|
-
const possibleDirs = [
|
|
488
|
-
path5.join(os4.homedir(), ".copilot", "skills"),
|
|
489
|
-
path5.join(os4.homedir(), ".claude", "skills")
|
|
490
|
-
];
|
|
491
|
-
for (const dir of possibleDirs) {
|
|
492
|
-
try {
|
|
493
|
-
await fs6.ensureDir(dir);
|
|
494
|
-
return true;
|
|
495
|
-
} catch {
|
|
496
|
-
continue;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
async install(skillId, sourceDir) {
|
|
502
|
-
await super.install(skillId, sourceDir);
|
|
503
|
-
const claudeSkillDir = path5.join(os4.homedir(), ".claude", "skills");
|
|
504
|
-
const targetPath = this.getSkillPath(skillId);
|
|
505
|
-
const claudeTargetPath = path5.join(claudeSkillDir, skillId);
|
|
506
|
-
try {
|
|
507
|
-
await fs6.ensureDir(claudeSkillDir);
|
|
508
|
-
await fs6.remove(claudeTargetPath);
|
|
509
|
-
await fs6.symlink(targetPath, claudeTargetPath, "junction");
|
|
510
|
-
} catch {
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
// src/adapters/registry.ts
|
|
516
|
-
var adapters = /* @__PURE__ */ new Map();
|
|
517
|
-
function registerAdapters() {
|
|
518
|
-
const opencode = new OpenCodeAdapter();
|
|
519
|
-
const claude = new ClaudeAdapter();
|
|
520
|
-
const vscode = new VSCodeAdapter();
|
|
521
|
-
adapters.set(opencode.id, opencode);
|
|
522
|
-
adapters.set(claude.id, claude);
|
|
523
|
-
adapters.set(vscode.id, vscode);
|
|
524
|
-
}
|
|
525
|
-
registerAdapters();
|
|
526
|
-
async function detectPlatforms() {
|
|
527
|
-
const available = [];
|
|
528
|
-
for (const adapter of adapters.values()) {
|
|
529
|
-
if (await adapter.isAvailable()) {
|
|
530
|
-
available.push(adapter);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return available;
|
|
534
|
-
}
|
|
535
|
-
function getAdapterByPlatform(platform) {
|
|
536
|
-
const idMap = {
|
|
537
|
-
opencode: "opencode",
|
|
538
|
-
claude: "claude",
|
|
539
|
-
vscode: "vscode",
|
|
540
|
-
cursor: "opencode",
|
|
541
|
-
// Cursor uses OpenCode-compatible structure
|
|
542
|
-
codex: "opencode",
|
|
543
|
-
// Codex uses OpenCode-compatible structure
|
|
544
|
-
antigravity: "opencode"
|
|
545
|
-
// Antigravity uses OpenCode-compatible structure
|
|
546
|
-
};
|
|
547
|
-
return adapters.get(idMap[platform]);
|
|
330
|
+
console.log("\n\u2705 Sync complete!");
|
|
548
331
|
}
|
|
549
332
|
|
|
550
333
|
// src/commands/install.ts
|
|
551
334
|
var execAsync = promisify(exec);
|
|
552
|
-
async function installSkill(skillId, version,
|
|
335
|
+
async function installSkill(skillId, version, targetPlatform) {
|
|
553
336
|
await ensureMarketDirs();
|
|
554
|
-
|
|
555
|
-
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);
|
|
556
342
|
if (!pkgInfo) {
|
|
557
|
-
throw new Error(`Package ${
|
|
343
|
+
throw new Error(`Package ${packageName} not found`);
|
|
558
344
|
}
|
|
559
|
-
const packageName = pkgInfo.name;
|
|
560
345
|
const targetVersion = version || pkgInfo["dist-tags"]?.latest;
|
|
561
346
|
if (!targetVersion) {
|
|
562
347
|
throw new Error(`No version found for ${packageName}`);
|
|
563
348
|
}
|
|
564
349
|
const cacheDir = getCacheDir();
|
|
565
|
-
const targetDir =
|
|
566
|
-
if (!await
|
|
350
|
+
const targetDir = path3.join(cacheDir, `${packageName}@${targetVersion}`);
|
|
351
|
+
if (!await fs4.pathExists(targetDir)) {
|
|
567
352
|
console.log("Downloading package...");
|
|
568
|
-
await
|
|
353
|
+
await fs4.ensureDir(cacheDir);
|
|
569
354
|
try {
|
|
570
355
|
await execAsync(`npm pack ${packageName}@${targetVersion} --pack-destination ${cacheDir}`);
|
|
571
|
-
const files = await
|
|
356
|
+
const files = await fs4.readdir(cacheDir);
|
|
572
357
|
const tarball = files.find(
|
|
573
|
-
(f) => f.endsWith(".tgz") && f.includes(packageName.replace(
|
|
358
|
+
(f) => f.endsWith(".tgz") && f.includes(packageName.replace("/", "-"))
|
|
574
359
|
);
|
|
575
360
|
if (tarball) {
|
|
576
|
-
await execAsync(`tar -xzf "${
|
|
577
|
-
await
|
|
578
|
-
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");
|
|
579
364
|
const finalDir = targetDir;
|
|
580
|
-
await
|
|
365
|
+
await fs4.move(extractedDir, finalDir, { overwrite: true });
|
|
581
366
|
}
|
|
582
367
|
} catch (err) {
|
|
583
368
|
throw new Error(`Failed to download package: ${err}`);
|
|
584
369
|
}
|
|
585
370
|
}
|
|
586
371
|
const skillsDir = getSkillsDir();
|
|
587
|
-
const skillVersionDir =
|
|
372
|
+
const skillVersionDir = path3.join(skillsDir, `${skillId}@${targetVersion}`);
|
|
588
373
|
console.log("Setting up skill...");
|
|
589
|
-
await
|
|
374
|
+
await fs4.ensureDir(skillVersionDir);
|
|
590
375
|
const pkgRoot = targetDir;
|
|
591
|
-
if (await
|
|
592
|
-
await
|
|
593
|
-
|
|
594
|
-
|
|
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")
|
|
595
380
|
);
|
|
596
381
|
}
|
|
597
|
-
if (await
|
|
598
|
-
await
|
|
599
|
-
|
|
600
|
-
|
|
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")
|
|
601
386
|
);
|
|
602
387
|
}
|
|
603
|
-
const skillDir =
|
|
604
|
-
await
|
|
605
|
-
const latestLink =
|
|
388
|
+
const skillDir = path3.join(skillsDir, skillId);
|
|
389
|
+
await fs4.ensureDir(skillDir);
|
|
390
|
+
const latestLink = path3.join(skillDir, LATEST_LINK);
|
|
606
391
|
try {
|
|
607
|
-
await
|
|
608
|
-
await
|
|
392
|
+
await fs4.remove(latestLink);
|
|
393
|
+
await fs4.symlink(skillVersionDir, latestLink, "junction");
|
|
609
394
|
} catch {
|
|
610
|
-
await
|
|
395
|
+
await fs4.copy(skillVersionDir, path3.join(skillDir, LATEST_LINK), { overwrite: true });
|
|
611
396
|
}
|
|
612
|
-
let
|
|
613
|
-
if (
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (adapter) {
|
|
618
|
-
targetAdapters.push(adapter);
|
|
619
|
-
} else {
|
|
620
|
-
console.warn(`\u26A0\uFE0F Unknown platform: ${platformStr}`);
|
|
621
|
-
}
|
|
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(", ")}`);
|
|
622
402
|
}
|
|
403
|
+
finalPlatform = parsed;
|
|
623
404
|
} else {
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
if (targetAdapters.length === 0) {
|
|
627
|
-
console.log("No target platforms detected.");
|
|
628
|
-
console.log("Use --platform to specify platforms manually.");
|
|
629
|
-
} else {
|
|
630
|
-
console.log(`
|
|
631
|
-
Installing to ${targetAdapters.length} platform(s)...
|
|
632
|
-
`);
|
|
633
|
-
const results = [];
|
|
634
|
-
for (const adapter of targetAdapters) {
|
|
635
|
-
try {
|
|
636
|
-
const isInstalled = await adapter.isInstalled(skillId);
|
|
637
|
-
if (isInstalled && !options?.force) {
|
|
638
|
-
console.log(`${adapter.name.padEnd(12)} \u26A0\uFE0F Already installed (use --force to overwrite)`);
|
|
639
|
-
results.push({ name: adapter.name, status: "skipped" });
|
|
640
|
-
continue;
|
|
641
|
-
}
|
|
642
|
-
await adapter.install(skillId, skillVersionDir);
|
|
643
|
-
console.log(`${adapter.name.padEnd(12)} \u2705 Installed successfully`);
|
|
644
|
-
results.push({ name: adapter.name, status: "installed" });
|
|
645
|
-
} catch (error) {
|
|
646
|
-
console.log(`${adapter.name.padEnd(12)} \u274C Failed: ${error}`);
|
|
647
|
-
results.push({ name: adapter.name, status: "failed", error: String(error) });
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
const installed = results.filter((r) => r.status === "installed").length;
|
|
651
|
-
const skipped = results.filter((r) => r.status === "skipped").length;
|
|
652
|
-
const failed = results.filter((r) => r.status === "failed").length;
|
|
653
|
-
console.log(`
|
|
654
|
-
\u{1F4CA} Summary: ${installed} installed, ${skipped} skipped, ${failed} failed`);
|
|
405
|
+
finalPlatform = detectPlatform();
|
|
655
406
|
}
|
|
407
|
+
console.log(`Target platform: ${finalPlatform}`);
|
|
656
408
|
const registry = await loadRegistry();
|
|
657
|
-
const
|
|
409
|
+
const existingSkill = registry.skills[skillId];
|
|
410
|
+
const existingPlatforms = existingSkill?.platforms || [];
|
|
658
411
|
registry.skills[skillId] = {
|
|
659
412
|
id: skillId,
|
|
660
413
|
version: targetVersion,
|
|
661
414
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
662
|
-
platforms:
|
|
415
|
+
platforms: existingPlatforms.includes(finalPlatform) ? existingPlatforms : [...existingPlatforms, finalPlatform]
|
|
663
416
|
};
|
|
664
417
|
await saveRegistry(registry);
|
|
418
|
+
console.log(`Syncing to ${finalPlatform}...`);
|
|
419
|
+
await syncPlatformLinks(finalPlatform);
|
|
665
420
|
console.log(`
|
|
666
421
|
\u2705 ${skillId}@${targetVersion} installed successfully!`);
|
|
667
422
|
console.log(` Use "skm info ${skillId}" for more details`);
|
|
668
423
|
}
|
|
669
424
|
|
|
670
|
-
// src/commands/sync.ts
|
|
671
|
-
import fs8 from "fs-extra";
|
|
672
|
-
import path7 from "path";
|
|
673
|
-
async function syncPlatformLinks() {
|
|
674
|
-
await ensureMarketDirs();
|
|
675
|
-
const skillsDir = getSkillsDir();
|
|
676
|
-
const platformLinksDir = getPlatformLinksDir();
|
|
677
|
-
const registry = await loadRegistry();
|
|
678
|
-
console.log("Syncing platform links...\n");
|
|
679
|
-
for (const platform of PLATFORMS) {
|
|
680
|
-
const platformDir = path7.join(platformLinksDir, platform, "skills");
|
|
681
|
-
await fs8.ensureDir(platformDir);
|
|
682
|
-
for (const [skillId, skillInfo] of Object.entries(registry.skills)) {
|
|
683
|
-
const skillLatestLink = path7.join(skillsDir, skillId, LATEST_LINK);
|
|
684
|
-
const targetPlatformDir = path7.join(skillLatestLink, platform);
|
|
685
|
-
const platformSkillDir = path7.join(platformDir, skillId);
|
|
686
|
-
if (await fs8.pathExists(skillLatestLink)) {
|
|
687
|
-
if (await fs8.pathExists(targetPlatformDir)) {
|
|
688
|
-
try {
|
|
689
|
-
await fs8.remove(platformSkillDir);
|
|
690
|
-
await fs8.symlink(targetPlatformDir, platformSkillDir, "junction");
|
|
691
|
-
console.log(` Linked: ${platform}/${skillId}`);
|
|
692
|
-
} catch {
|
|
693
|
-
await fs8.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
|
|
694
|
-
console.log(` Copied: ${platform}/${skillId}`);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
console.log("\n\u2705 Sync complete!");
|
|
701
|
-
}
|
|
702
|
-
|
|
703
425
|
// src/commands/update.ts
|
|
704
426
|
async function updateSkill(skillId) {
|
|
705
427
|
if (skillId) {
|
|
706
|
-
const pkgInfo = await fetchNpmPackage(`@
|
|
428
|
+
const pkgInfo = await fetchNpmPackage(`@skillmarket/${skillId}`);
|
|
707
429
|
if (pkgInfo) {
|
|
708
430
|
const latestVersion = pkgInfo["dist-tags"]?.latest;
|
|
709
431
|
console.log(`Updating ${skillId} to ${latestVersion}...`);
|
|
@@ -720,7 +442,7 @@ async function updateSkill(skillId) {
|
|
|
720
442
|
`);
|
|
721
443
|
let hasUpdates = false;
|
|
722
444
|
for (const skill of installed) {
|
|
723
|
-
const pkgInfo = await fetchNpmPackage(`@
|
|
445
|
+
const pkgInfo = await fetchNpmPackage(`@skillmarket/${skill.id}`);
|
|
724
446
|
if (pkgInfo) {
|
|
725
447
|
const latestVersion = pkgInfo["dist-tags"]?.latest;
|
|
726
448
|
if (latestVersion && latestVersion !== skill.version) {
|
|
@@ -742,9 +464,9 @@ async function updateSkill(skillId) {
|
|
|
742
464
|
}
|
|
743
465
|
|
|
744
466
|
// src/commands/uninstall.ts
|
|
745
|
-
import
|
|
746
|
-
import
|
|
747
|
-
async function uninstallSkill(skillId
|
|
467
|
+
import fs5 from "fs-extra";
|
|
468
|
+
import path4 from "path";
|
|
469
|
+
async function uninstallSkill(skillId) {
|
|
748
470
|
const registry = await loadRegistry();
|
|
749
471
|
if (!(skillId in registry.skills)) {
|
|
750
472
|
console.log(`Skill "${skillId}" is not installed.`);
|
|
@@ -752,37 +474,14 @@ async function uninstallSkill(skillId, options) {
|
|
|
752
474
|
}
|
|
753
475
|
const skillInfo = registry.skills[skillId];
|
|
754
476
|
console.log(`Uninstalling ${skillId}@${skillInfo.version}...`);
|
|
755
|
-
let targetAdapters = [];
|
|
756
|
-
if (options?.platforms && options.platforms.length > 0) {
|
|
757
|
-
for (const platformStr of options.platforms) {
|
|
758
|
-
const platform = platformStr;
|
|
759
|
-
targetAdapters.push(getAdapterByPlatform(platform));
|
|
760
|
-
}
|
|
761
|
-
} else {
|
|
762
|
-
targetAdapters = await detectPlatforms();
|
|
763
|
-
}
|
|
764
|
-
const validAdapters = targetAdapters.filter((a) => a !== void 0);
|
|
765
|
-
if (validAdapters.length > 0) {
|
|
766
|
-
console.log(`
|
|
767
|
-
Uninstalling from ${validAdapters.length} platform(s)...
|
|
768
|
-
`);
|
|
769
|
-
for (const adapter of validAdapters) {
|
|
770
|
-
try {
|
|
771
|
-
await adapter.uninstall(skillId);
|
|
772
|
-
console.log(`${adapter.name.padEnd(12)} \u2705 Uninstalled`);
|
|
773
|
-
} catch (error) {
|
|
774
|
-
console.log(`${adapter.name.padEnd(12)} \u274C Failed: ${error}`);
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
477
|
const skillsDir = getSkillsDir();
|
|
779
|
-
const skillDir =
|
|
780
|
-
await
|
|
478
|
+
const skillDir = path4.join(skillsDir, skillId);
|
|
479
|
+
await fs5.remove(skillDir);
|
|
781
480
|
const platformLinksDir = getPlatformLinksDir();
|
|
782
481
|
for (const platform of PLATFORMS) {
|
|
783
|
-
const linkPath =
|
|
784
|
-
if (await
|
|
785
|
-
await
|
|
482
|
+
const linkPath = path4.join(platformLinksDir, platform, "skills", skillId);
|
|
483
|
+
if (await fs5.pathExists(linkPath)) {
|
|
484
|
+
await fs5.remove(linkPath);
|
|
786
485
|
}
|
|
787
486
|
}
|
|
788
487
|
delete registry.skills[skillId];
|
|
@@ -792,89 +491,61 @@ Uninstalling from ${validAdapters.length} platform(s)...
|
|
|
792
491
|
}
|
|
793
492
|
|
|
794
493
|
// src/cli.ts
|
|
795
|
-
var __filename = fileURLToPath(import.meta.url);
|
|
796
|
-
var __dirname = dirname(__filename);
|
|
797
|
-
var packageJson = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf-8"));
|
|
798
|
-
var VERSION = packageJson.version;
|
|
799
494
|
var program = new Command();
|
|
800
|
-
program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version(
|
|
801
|
-
program.
|
|
802
|
-
|
|
803
|
-
|
|
495
|
+
program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version("1.2.0");
|
|
496
|
+
var helpCmd = program.command("help").description("Display help information");
|
|
497
|
+
helpCmd.action(() => {
|
|
498
|
+
console.log(`
|
|
804
499
|
SkillMarket CLI
|
|
805
500
|
|
|
806
501
|
Usage: skm <command> [options]
|
|
807
502
|
|
|
808
503
|
Commands:
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
update [options] Update skills
|
|
823
|
-
--all Update all skills
|
|
824
|
-
sync Synchronize platform links
|
|
825
|
-
platforms Show available platforms
|
|
504
|
+
--help, -h Display this help message
|
|
505
|
+
--ls [options] List available skills
|
|
506
|
+
--installed Show only installed skills
|
|
507
|
+
--updates Check for updates
|
|
508
|
+
--info <skill-id> Display skill information
|
|
509
|
+
--install <skill> Install a skill (e.g., skm --install brainstorming)
|
|
510
|
+
@version Install specific version
|
|
511
|
+
--all Install all available skills
|
|
512
|
+
--uninstall <skill> Remove an installed skill
|
|
513
|
+
--update [options] Update skills
|
|
514
|
+
--all Update all skills
|
|
515
|
+
--sync Synchronize platform links
|
|
516
|
+
--platform <name> Set target platform (${PLATFORMS.join(", ")})
|
|
826
517
|
|
|
827
518
|
Examples:
|
|
828
|
-
skm ls
|
|
829
|
-
skm ls --
|
|
830
|
-
skm
|
|
831
|
-
skm
|
|
832
|
-
skm
|
|
833
|
-
skm
|
|
834
|
-
skm
|
|
835
|
-
|
|
836
|
-
skm info brainstorming View skill details
|
|
837
|
-
skm install brainstorming Install to all platforms
|
|
838
|
-
skm install brainstorming --platform opencode Install to OpenCode only
|
|
839
|
-
skm install brainstorming --platform claude,vscode Install to multiple
|
|
840
|
-
skm uninstall brainstorming
|
|
841
|
-
skm platforms Show available platforms
|
|
842
|
-
`);
|
|
843
|
-
process.exit(0);
|
|
844
|
-
}
|
|
519
|
+
skm --ls List all available skills
|
|
520
|
+
skm --ls --installed Show installed skills only
|
|
521
|
+
skm --info brainstorming View skill details
|
|
522
|
+
skm --install brainstorming Install a skill
|
|
523
|
+
skm --install brainstorming@1.0.0 Install specific version
|
|
524
|
+
skm --update --all Update all installed skills
|
|
525
|
+
skm --sync Sync platform links
|
|
526
|
+
`);
|
|
845
527
|
});
|
|
846
528
|
var lsCmd = program.command("ls").description("List available skills");
|
|
847
|
-
lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").
|
|
848
|
-
|
|
849
|
-
...opts,
|
|
850
|
-
page: opts.page ?? 1,
|
|
851
|
-
limit: opts.limit ?? 20,
|
|
852
|
-
search: opts.search
|
|
853
|
-
};
|
|
854
|
-
listSkills(options);
|
|
529
|
+
lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").action((opts) => {
|
|
530
|
+
listSkills(opts);
|
|
855
531
|
});
|
|
856
532
|
var infoCmd = program.command("info").description("Display skill information");
|
|
857
533
|
infoCmd.argument("<skill-id>", "Skill ID to show info").action((skillId) => {
|
|
858
534
|
showSkillInfo(skillId);
|
|
859
535
|
});
|
|
860
|
-
var installCmd = program.command("install").description("Install a skill
|
|
861
|
-
installCmd.argument("<skill>", "Skill ID to install (e.g., brainstorming or @scope/name)").option("
|
|
536
|
+
var installCmd = program.command("install").description("Install a skill");
|
|
537
|
+
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) => {
|
|
862
538
|
try {
|
|
863
|
-
|
|
864
|
-
await installSkill(skill, opts.version, {
|
|
865
|
-
platforms,
|
|
866
|
-
force: opts.force
|
|
867
|
-
});
|
|
539
|
+
await installSkill(skill, void 0, opts.platform);
|
|
868
540
|
} catch (err) {
|
|
869
541
|
console.error("Installation failed:", err);
|
|
870
542
|
process.exit(1);
|
|
871
543
|
}
|
|
872
544
|
});
|
|
873
|
-
var uninstallCmd = program.command("uninstall").description("Remove an installed skill
|
|
874
|
-
uninstallCmd.argument("<skill>", "Skill ID to uninstall").
|
|
545
|
+
var uninstallCmd = program.command("uninstall").description("Remove an installed skill");
|
|
546
|
+
uninstallCmd.argument("<skill>", "Skill ID to uninstall").action(async (skill) => {
|
|
875
547
|
try {
|
|
876
|
-
|
|
877
|
-
await uninstallSkill(skill, { platforms });
|
|
548
|
+
await uninstallSkill(skill);
|
|
878
549
|
} catch (err) {
|
|
879
550
|
console.error("Uninstall failed:", err);
|
|
880
551
|
process.exit(1);
|
|
@@ -901,29 +572,8 @@ program.command("sync").description("Synchronize platform links").action(async (
|
|
|
901
572
|
process.exit(1);
|
|
902
573
|
}
|
|
903
574
|
});
|
|
904
|
-
var
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const available = await detectPlatforms();
|
|
908
|
-
console.log("\n\u{1F4CD} Available Platforms:\n");
|
|
909
|
-
const allPlatforms = [
|
|
910
|
-
{ name: "OpenCode", adapter: new OpenCodeAdapter() },
|
|
911
|
-
{ name: "Claude Code", adapter: new ClaudeAdapter() },
|
|
912
|
-
{ name: "VSCode", adapter: new VSCodeAdapter() }
|
|
913
|
-
];
|
|
914
|
-
for (const { name, adapter } of allPlatforms) {
|
|
915
|
-
const isAvailable = available.find((a) => a.id === adapter.id);
|
|
916
|
-
const installed = await adapter.listInstalled();
|
|
917
|
-
if (isAvailable) {
|
|
918
|
-
console.log(`${name.padEnd(12)} \u2705 Available (${installed.length} skills installed)`);
|
|
919
|
-
} else {
|
|
920
|
-
console.log(`${name.padEnd(12)} \u274C Not detected`);
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
console.log("");
|
|
924
|
-
} catch (err) {
|
|
925
|
-
console.error("Failed to list platforms:", err);
|
|
926
|
-
process.exit(1);
|
|
927
|
-
}
|
|
575
|
+
var platformCmd = program.command("platform").description("Set target platform");
|
|
576
|
+
platformCmd.argument("<name>", "Platform name").action((name) => {
|
|
577
|
+
console.log("Platform command - name:", name);
|
|
928
578
|
});
|
|
929
579
|
program.parse();
|