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.
Files changed (47) hide show
  1. package/README.md +6 -75
  2. package/dist/index.js +221 -577
  3. package/package.json +6 -1
  4. package/src/cli.ts +74 -148
  5. package/src/commands/info.ts +15 -4
  6. package/src/commands/install.ts +54 -93
  7. package/src/commands/ls.ts +17 -182
  8. package/src/commands/npm.ts +13 -97
  9. package/src/commands/search.ts +98 -0
  10. package/src/commands/sync.ts +27 -6
  11. package/src/commands/uninstall.ts +7 -60
  12. package/src/commands/update.ts +2 -2
  13. package/src/index.ts +0 -27
  14. package/src/types.ts +0 -35
  15. package/.github/workflows/publish-npm.yml +0 -54
  16. package/.github/workflows/publish-skill.yml +0 -72
  17. package/5e51cb7aa8b8e60d49d86f4689f5d4d1.png +0 -0
  18. package/CHANGELOG.md +0 -255
  19. package/DEVELOPMENT.md +0 -376
  20. package/SKILLMARKET-GUIDE.md +0 -288
  21. package/docs/plans/2026-04-01-skillmarket-design.md +0 -267
  22. package/docs/plans/2026-04-01-skillmarket-implementation.md +0 -1031
  23. package/docs/plans/2026-04-15-cross-platform-adapter-design.md +0 -416
  24. package/docs/plans/2026-04-15-cross-platform-adapter-plan.md +0 -833
  25. package/docs/plans/2026-04-16-keyword-search-design.md +0 -143
  26. package/skills/README.md +0 -54
  27. package/skills/test-skill/SKILL.md +0 -25
  28. package/skills/test-skill/index.js +0 -66
  29. package/skills/test-skill/metadata.json +0 -9
  30. package/skills/test-skill/package.json +0 -19
  31. package/skills/test-skill-1/SKILL.md +0 -24
  32. package/skills/test-skill-1/index.js +0 -13
  33. package/skills/test-skill-1/metadata.json +0 -9
  34. package/skills/test-skill-1/package.json +0 -16
  35. package/skills/test-skill-2/SKILL.md +0 -25
  36. package/skills/test-skill-2/index.js +0 -13
  37. package/skills/test-skill-2/metadata.json +0 -9
  38. package/skills/test-skill-2/package.json +0 -16
  39. package/src/adapters/base.ts +0 -87
  40. package/src/adapters/claude.ts +0 -31
  41. package/src/adapters/index.ts +0 -9
  42. package/src/adapters/opencode.ts +0 -40
  43. package/src/adapters/registry.ts +0 -77
  44. package/src/adapters/vscode.ts +0 -62
  45. package/tsconfig.json +0 -10
  46. package/tsup.config.ts +0 -22
  47. 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((resolve2, reject) => {
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
- resolve2(null);
124
+ resolve(null);
130
125
  return;
131
126
  }
132
- resolve2(parsed);
127
+ resolve(parsed);
133
128
  } catch {
134
- resolve2(null);
129
+ resolve(null);
135
130
  }
136
131
  });
137
132
  });
@@ -142,50 +137,12 @@ async function fetchNpmPackage(packageName) {
142
137
  });
143
138
  });
144
139
  }
145
- var SKILL_SCOPES = [
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
- let total = 0;
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
- if (keyword) {
183
- url.searchParams.set("text", `${keyword} keywords:skillmarket`);
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
- total = result.total || 0;
198
- if (result.objects) {
199
- for (const item of result.objects) {
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
- resolve2({ packages, total });
159
+ resolve(packages);
206
160
  } catch {
207
- resolve2({ packages: [], total: 0 });
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, page = 1, limit = 20, search } = options;
175
+ const { installed, updates } = options;
268
176
  if (installed) {
269
- let skills = await getInstalledSkills();
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
- if (search) {
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
- if (search) {
285
- console.log(`Found ${total} match(es) for "${search}":
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
- if (search) {
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 offset = (page - 1) * limit;
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
- if (search) {
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
- if (search) {
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
- try {
335
- const info = await fetchNpmPackage(pkgName);
336
- if (!info) {
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
- const skillMeta = pkg?.skillmarket;
344
- console.log(`\u{1F4E6} ${info.name}@${latestVersion}`);
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
- console.log(`Fetching info for: ${skillId}
217
+ const packageName = skillId.startsWith("@") ? skillId : `@skillmarket/${skillId}`;
218
+ console.log(`Fetching info for: ${packageName}
367
219
  `);
368
220
  try {
369
- const info = await fetchSkillPackage(skillId);
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 fs7 from "fs-extra";
410
- import path6 from "path";
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/adapters/base.ts
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
- var BaseAdapter = class {
418
- /**
419
- * Get the path where a specific skill should be installed
420
- */
421
- getSkillPath(skillId) {
422
- return path2.join(this.skillDir, skillId);
423
- }
424
- /**
425
- * Get the path to the SKILL.md file for a skill
426
- */
427
- getSkillFilePath(skillId) {
428
- return path2.join(this.getSkillPath(skillId), "SKILL.md");
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
- async listInstalled() {
459
- if (!await fs3.pathExists(this.skillDir)) {
460
- return [];
461
- }
462
- const entries = await fs3.readdir(this.skillDir, { withFileTypes: true });
463
- const skills = [];
464
- for (const entry of entries) {
465
- if (entry.isDirectory()) {
466
- const skillFile = path2.join(this.skillDir, entry.name, "SKILL.md");
467
- if (await fs3.pathExists(skillFile)) {
468
- skills.push(entry.name);
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, options) {
335
+ async function installSkill(skillId, version, targetPlatform) {
593
336
  await ensureMarketDirs();
594
- console.log(`Installing ${skillId}${version ? `@${version}` : ""}...`);
595
- const pkgInfo = await fetchSkillPackage(skillId);
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 ${skillId} not found`);
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 = path6.join(cacheDir, `${packageName}@${targetVersion}`);
606
- if (!await fs7.pathExists(targetDir)) {
350
+ const targetDir = path3.join(cacheDir, `${packageName}@${targetVersion}`);
351
+ if (!await fs4.pathExists(targetDir)) {
607
352
  console.log("Downloading package...");
608
- await fs7.ensureDir(cacheDir);
353
+ await fs4.ensureDir(cacheDir);
609
354
  try {
610
355
  await execAsync(`npm pack ${packageName}@${targetVersion} --pack-destination ${cacheDir}`);
611
- const files = await fs7.readdir(cacheDir);
356
+ const files = await fs4.readdir(cacheDir);
612
357
  const tarball = files.find(
613
- (f) => f.endsWith(".tgz") && f.includes(packageName.replace(/^@/, "").replace("/", "-"))
358
+ (f) => f.endsWith(".tgz") && f.includes(packageName.replace("/", "-"))
614
359
  );
615
360
  if (tarball) {
616
- await execAsync(`tar -xzf "${path6.join(cacheDir, tarball)}" -C "${cacheDir}"`);
617
- await fs7.remove(path6.join(cacheDir, tarball));
618
- const extractedDir = path6.join(cacheDir, "package");
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 fs7.move(extractedDir, finalDir, { overwrite: true });
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 = path6.join(skillsDir, `${skillId}@${targetVersion}`);
372
+ const skillVersionDir = path3.join(skillsDir, `${skillId}@${targetVersion}`);
628
373
  console.log("Setting up skill...");
629
- await fs7.ensureDir(skillVersionDir);
374
+ await fs4.ensureDir(skillVersionDir);
630
375
  const pkgRoot = targetDir;
631
- if (await fs7.pathExists(path6.join(pkgRoot, "SKILL.md"))) {
632
- await fs7.copy(
633
- path6.join(pkgRoot, "SKILL.md"),
634
- path6.join(skillVersionDir, "SKILL.md")
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 fs7.pathExists(path6.join(pkgRoot, "metadata.json"))) {
638
- await fs7.copy(
639
- path6.join(pkgRoot, "metadata.json"),
640
- path6.join(skillVersionDir, "metadata.json")
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 = path6.join(skillsDir, skillId);
644
- await fs7.ensureDir(skillDir);
645
- const latestLink = path6.join(skillDir, LATEST_LINK);
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 fs7.remove(latestLink);
648
- await fs7.symlink(skillVersionDir, latestLink, "junction");
392
+ await fs4.remove(latestLink);
393
+ await fs4.symlink(skillVersionDir, latestLink, "junction");
649
394
  } catch {
650
- await fs7.copy(skillVersionDir, path6.join(skillDir, LATEST_LINK), { overwrite: true });
395
+ await fs4.copy(skillVersionDir, path3.join(skillDir, LATEST_LINK), { overwrite: true });
651
396
  }
652
- let targetAdapters = [];
653
- if (options?.platforms && options.platforms.length > 0) {
654
- for (const platformStr of options.platforms) {
655
- const platform = platformStr;
656
- const adapter = getAdapterByPlatform(platform);
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
- targetAdapters = await detectPlatforms();
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 installedPlatforms = targetAdapters.map((a) => a.id);
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: installedPlatforms
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(`@itismyskillmarket/${skillId}`);
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(`@wanxuchen/${skill.id}`);
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 fs9 from "fs-extra";
786
- import path8 from "path";
787
- async function uninstallSkill(skillId, options) {
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 = path8.join(skillsDir, skillId);
820
- await fs9.remove(skillDir);
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 = path8.join(platformLinksDir, platform, "skills", skillId);
824
- if (await fs9.pathExists(linkPath)) {
825
- await fs9.remove(linkPath);
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(VERSION);
841
- program.hook("preAction", (thisCommand) => {
842
- if (thisCommand.opts().help) {
843
- console.log(`
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
- ls [options] List available skills
850
- --installed Show only installed skills
851
- --updates Check for updates
852
- --page <n> Page number (default: 1)
853
- --limit <n> Items per page (default: 20)
854
- -s, --search Search by keyword
855
- info <skill-id> Display skill information
856
- install <skill> Install a skill
857
- @version Install specific version
858
- --platform Target platforms (opencode,claude,vscode)
859
- --force Overwrite if already installed
860
- uninstall <skill> Remove an installed skill
861
- --platform Target platforms
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 List all available skills (page 1)
869
- skm ls --page 2 Go to page 2
870
- skm ls --limit 10 Show 10 items per page
871
- skm ls --search brain Search skills by keyword
872
- skm ls -s brain Search with short form
873
- skm ls --installed Show installed skills only
874
- skm ls --installed --search test Search installed skills
875
- skm ls --installed --page 2
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").option("-p, --page <number>", "Page number (default: 1)", parseInt).option("-l, --limit <number>", "Items per page (default: 20)", parseInt).option("-s, --search <keyword>", "Search by keyword (id, displayName, description)").action((opts) => {
888
- const options = {
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 to local and platform directories");
906
- installCmd.argument("<skill>", "Skill ID to install (e.g., brainstorming or @scope/name)").option("-p, --platform <platforms>", "Target platforms (comma-separated: opencode,claude,vscode)").option("-f, --force", "Overwrite if already installed").option("-v, --version <version>", "Specific version to install").action(async (skill, opts) => {
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
- const platforms = opts.platform ? opts.platform.split(",").map((p) => p.trim()) : void 0;
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 from local and platform directories");
919
- uninstallCmd.argument("<skill>", "Skill ID to uninstall").option("-p, --platform <platforms>", "Target platforms (comma-separated)").action(async (skill, opts) => {
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
- const platforms = opts.platform ? opts.platform.split(",").map((p) => p.trim()) : void 0;
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 platformsCmd = program.command("platforms").description("Show available platforms");
950
- platformsCmd.action(async () => {
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
- const available = await detectPlatforms();
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("Failed to list platforms:", err);
614
+ console.error("Search failed:", err);
971
615
  process.exit(1);
972
616
  }
973
617
  });