itismyskillmarket 1.0.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/dist/index.js ADDED
@@ -0,0 +1,561 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/constants.ts
7
+ var MARKET_DIR = "skillmarket";
8
+ var SUBDIRS = {
9
+ /** npm 包下载缓存目录,用于存储从 npm 下载的 skill 包 */
10
+ CACHE: "cache",
11
+ /** 已安装 skills 的主存储目录 */
12
+ SKILLS: "skills",
13
+ /** 各平台适配层软链接目录,用于跨平台共享 skills */
14
+ PLATFORM_LINKS: "platform-links"
15
+ };
16
+ var PLATFORMS = [
17
+ "cursor",
18
+ // Cursor IDE - AI 代码编辑器
19
+ "vscode",
20
+ // Visual Studio Code - 微软代码编辑器
21
+ "codex",
22
+ // OpenAI Codex - OpenAI 代码生成模型
23
+ "opencode",
24
+ // OpenCode - 开源 AI 编程工具
25
+ "claude",
26
+ // Claude Code - Anthropic CLI 工具
27
+ "antigravity"
28
+ // Antigravity - AI 编程助手
29
+ ];
30
+ var REGISTRY_FILE = "registry.json";
31
+ var LATEST_LINK = "latest";
32
+
33
+ // src/commands/registry.ts
34
+ import fs2 from "fs-extra";
35
+
36
+ // src/utils/dirs.ts
37
+ import os from "os";
38
+ import path from "path";
39
+ import fs from "fs-extra";
40
+ function getMarketHome() {
41
+ return path.join(os.homedir(), MARKET_DIR);
42
+ }
43
+ function getCacheDir() {
44
+ return path.join(getMarketHome(), SUBDIRS.CACHE);
45
+ }
46
+ function getSkillsDir() {
47
+ return path.join(getMarketHome(), SUBDIRS.SKILLS);
48
+ }
49
+ function getPlatformLinksDir() {
50
+ return path.join(getMarketHome(), SUBDIRS.PLATFORM_LINKS);
51
+ }
52
+ function getRegistryPath() {
53
+ return path.join(getMarketHome(), REGISTRY_FILE);
54
+ }
55
+ async function ensureMarketDirs() {
56
+ await fs.ensureDir(getCacheDir());
57
+ await fs.ensureDir(getSkillsDir());
58
+ await fs.ensureDir(getPlatformLinksDir());
59
+ }
60
+
61
+ // src/commands/registry.ts
62
+ var DEFAULT_REGISTRY = {
63
+ /** 空的 skills 字典,初始没有任何已安装的 skill */
64
+ skills: {},
65
+ /** 注册表创建时间 */
66
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
67
+ };
68
+ async function loadRegistry() {
69
+ const registryPath = getRegistryPath();
70
+ if (!await fs2.pathExists(registryPath)) {
71
+ return DEFAULT_REGISTRY;
72
+ }
73
+ try {
74
+ const data = await fs2.readJson(registryPath);
75
+ return data;
76
+ } catch {
77
+ return DEFAULT_REGISTRY;
78
+ }
79
+ }
80
+ async function saveRegistry(registry) {
81
+ await fs2.ensureDir(getMarketHome());
82
+ registry.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
83
+ await fs2.writeJson(getRegistryPath(), registry, { spaces: 2 });
84
+ }
85
+ async function getInstalledSkills() {
86
+ const registry = await loadRegistry();
87
+ return Object.values(registry.skills);
88
+ }
89
+ async function isSkillInstalled(skillId) {
90
+ const registry = await loadRegistry();
91
+ return skillId in registry.skills;
92
+ }
93
+
94
+ // src/commands/npm.ts
95
+ import https from "https";
96
+ import { URL } from "url";
97
+ async function fetchNpmPackage(packageName) {
98
+ return new Promise((resolve, reject) => {
99
+ const isScoped = packageName.startsWith("@");
100
+ let encodedName;
101
+ if (isScoped) {
102
+ const scopeAndName = packageName.substring(1);
103
+ const slashIndex = scopeAndName.indexOf("/");
104
+ if (slashIndex > 0) {
105
+ const scope = scopeAndName.substring(0, slashIndex);
106
+ const name = scopeAndName.substring(slashIndex + 1);
107
+ encodedName = `@${encodeURIComponent(scope)}%2F${encodeURIComponent(name)}`;
108
+ } else {
109
+ encodedName = packageName;
110
+ }
111
+ } else {
112
+ encodedName = encodeURIComponent(packageName);
113
+ }
114
+ const url = new URL(`https://registry.npmjs.org/${encodedName}`);
115
+ const req = https.get(url.toString(), { timeout: 1e4 }, (res) => {
116
+ let data = "";
117
+ res.on("data", (chunk) => {
118
+ data += chunk;
119
+ });
120
+ res.on("end", () => {
121
+ try {
122
+ const parsed = JSON.parse(data);
123
+ if (parsed.error) {
124
+ resolve(null);
125
+ return;
126
+ }
127
+ resolve(parsed);
128
+ } catch {
129
+ resolve(null);
130
+ }
131
+ });
132
+ });
133
+ req.on("error", reject);
134
+ req.on("timeout", () => {
135
+ req.destroy();
136
+ reject(new Error("Request timeout"));
137
+ });
138
+ });
139
+ }
140
+ async function searchSkillmarketPackages() {
141
+ const packages = [];
142
+ return new Promise((resolve, reject) => {
143
+ const url = new URL("https://registry.npmjs.org/-/v1/search");
144
+ url.searchParams.set("text", "keywords:skillmarket");
145
+ url.searchParams.set("size", "100");
146
+ const req = https.get(url.toString(), { timeout: 1e4 }, (res) => {
147
+ let data = "";
148
+ res.on("data", (chunk) => {
149
+ data += chunk;
150
+ });
151
+ res.on("end", () => {
152
+ try {
153
+ const result = JSON.parse(data);
154
+ if (result.objects) {
155
+ for (const item of result.objects) {
156
+ if (item?.package?.name) {
157
+ packages.push(item.package.name);
158
+ }
159
+ }
160
+ }
161
+ resolve(packages);
162
+ } catch {
163
+ resolve([]);
164
+ }
165
+ });
166
+ });
167
+ req.on("error", reject);
168
+ req.on("timeout", () => {
169
+ req.destroy();
170
+ reject(new Error("Request timeout"));
171
+ });
172
+ });
173
+ }
174
+
175
+ // src/commands/ls.ts
176
+ async function listSkills(options) {
177
+ const { installed, updates } = options;
178
+ if (installed) {
179
+ const skills = await getInstalledSkills();
180
+ if (skills.length === 0) {
181
+ console.log('No skills installed yet. Run "skm --ls" to see available skills.');
182
+ return;
183
+ }
184
+ console.log("Installed Skills:\n");
185
+ for (const skill of skills) {
186
+ console.log(` ${skill.id}@${skill.version}`);
187
+ console.log(` Platforms: ${skill.platforms.join(", ")}`);
188
+ console.log(` Installed: ${skill.installedAt}`);
189
+ console.log();
190
+ }
191
+ return;
192
+ }
193
+ console.log("Searching npm registry...\n");
194
+ try {
195
+ const packages = await searchSkillmarketPackages();
196
+ if (packages.length === 0) {
197
+ console.log("No skills found. Check back later!");
198
+ return;
199
+ }
200
+ console.log(`Found ${packages.length} skill(s):
201
+ `);
202
+ for (const pkgName of packages) {
203
+ try {
204
+ const info = await fetchNpmPackage(pkgName);
205
+ if (!info) {
206
+ console.log(`\u{1F4E6} ${pkgName} (\u4FE1\u606F\u83B7\u53D6\u5931\u8D25)`);
207
+ console.log();
208
+ continue;
209
+ }
210
+ const latestVersion = info["dist-tags"]?.latest || "unknown";
211
+ const pkg = info.versions?.[latestVersion];
212
+ const skillMeta = pkg?.skillmarket;
213
+ console.log(`\u{1F4E6} ${info.name}@${latestVersion}`);
214
+ const displayName = skillMeta?.displayName || info.name;
215
+ console.log(` \u540D\u79F0: ${displayName}`);
216
+ console.log(` \u63CF\u8FF0: ${pkg?.description || "N/A"}`);
217
+ const platforms = skillMeta?.platforms || [];
218
+ console.log(` \u5E73\u53F0: ${platforms.length > 0 ? platforms.join(", ") : "N/A"}`);
219
+ const npmLink = pkg?.links?.npm || `https://www.npmjs.com/package/${info.name}`;
220
+ console.log(` \u94FE\u63A5: ${npmLink}`);
221
+ console.log();
222
+ } catch (e) {
223
+ console.log(`\u{1F4E6} ${pkgName} (\u83B7\u53D6\u5931\u8D25: ${e})`);
224
+ console.log();
225
+ }
226
+ }
227
+ } catch (error) {
228
+ console.log(`Error fetching skills: ${error}`);
229
+ }
230
+ }
231
+
232
+ // src/commands/info.ts
233
+ async function showSkillInfo(skillId) {
234
+ const packageName = skillId.startsWith("@") ? skillId : `@itismyskillmarket/${skillId}`;
235
+ console.log(`Fetching info for: ${packageName}
236
+ `);
237
+ try {
238
+ const info = await fetchNpmPackage(packageName);
239
+ if (!info) {
240
+ console.log(`Skill "${skillId}" not found in npm registry.`);
241
+ return;
242
+ }
243
+ const latestVersion = info["dist-tags"]?.latest;
244
+ const versions = info.versions || {};
245
+ const pkg = latestVersion ? versions[latestVersion] : void 0;
246
+ const installed = await isSkillInstalled(skillId);
247
+ const installedSkills = await getInstalledSkills();
248
+ const installedSkill = installedSkills.find((s) => s.id === skillId);
249
+ console.log(`=== ${info.name} ===`);
250
+ const versionDisplay = installedSkill ? `${latestVersion} (installed: ${installedSkill.version})` : latestVersion;
251
+ console.log(`Version: ${versionDisplay}`);
252
+ console.log(`Description: ${pkg?.description || "N/A"}
253
+ `);
254
+ const skillmarketMeta = pkg?.skillmarket;
255
+ if (skillmarketMeta) {
256
+ console.log(`Platforms: ${skillmarketMeta.platforms?.join(", ") || "N/A"}`);
257
+ console.log(`Default Version: ${skillmarketMeta.defaultVersion || "N/A"}
258
+ `);
259
+ }
260
+ const versionKeys = Object.keys(versions);
261
+ if (versionKeys.length > 0) {
262
+ const recentVersions = versionKeys.slice(-10);
263
+ console.log(`Recent versions: ${recentVersions.join(", ")}`);
264
+ }
265
+ if (installed) {
266
+ console.log(`
267
+ Status: Installed (use skm update ${skillId} to update)`);
268
+ } else {
269
+ console.log(`
270
+ Status: Not installed (use skm install ${skillId} to install)`);
271
+ }
272
+ } catch (error) {
273
+ console.log(`Error fetching skill info: ${error}`);
274
+ }
275
+ }
276
+
277
+ // src/commands/install.ts
278
+ import fs3 from "fs-extra";
279
+ import path2 from "path";
280
+ import { exec } from "child_process";
281
+ import { promisify } from "util";
282
+
283
+ // src/utils/platform.ts
284
+ function detectPlatform() {
285
+ if (process.env.OPENCODE) return "opencode";
286
+ if (process.env.CURSOR) return "cursor";
287
+ if (process.env.VSCODE) return "vscode";
288
+ if (process.env.CLAUDE_CODE) return "claude";
289
+ if (process.env.ANTIGRAVITY) return "antigravity";
290
+ return "codex";
291
+ }
292
+
293
+ // src/commands/install.ts
294
+ var execAsync = promisify(exec);
295
+ async function installSkill(skillId, version) {
296
+ await ensureMarketDirs();
297
+ let packageName;
298
+ if (skillId.startsWith("@")) {
299
+ packageName = skillId;
300
+ } else {
301
+ packageName = `@itismyskillmarket/${skillId}`;
302
+ }
303
+ console.log(`Installing ${packageName}${version ? `@${version}` : ""}...`);
304
+ const pkgInfo = await fetchNpmPackage(packageName);
305
+ if (!pkgInfo) {
306
+ throw new Error(`Package ${packageName} not found`);
307
+ }
308
+ const targetVersion = version || pkgInfo["dist-tags"]?.latest;
309
+ if (!targetVersion) {
310
+ throw new Error(`No version found for ${packageName}`);
311
+ }
312
+ const cacheDir = getCacheDir();
313
+ const targetDir = path2.join(cacheDir, `${packageName}@${targetVersion}`);
314
+ if (!await fs3.pathExists(targetDir)) {
315
+ console.log("Downloading package...");
316
+ await fs3.ensureDir(cacheDir);
317
+ try {
318
+ await execAsync(`npm pack ${packageName}@${targetVersion} --pack-destination ${cacheDir}`);
319
+ const files = await fs3.readdir(cacheDir);
320
+ const tarball = files.find(
321
+ (f) => f.endsWith(".tgz") && f.includes(packageName.replace("/", "-"))
322
+ );
323
+ if (tarball) {
324
+ await execAsync(`tar -xzf "${path2.join(cacheDir, tarball)}" -C "${cacheDir}"`);
325
+ await fs3.remove(path2.join(cacheDir, tarball));
326
+ const extractedDir = path2.join(cacheDir, "package");
327
+ const finalDir = targetDir;
328
+ await fs3.move(extractedDir, finalDir, { overwrite: true });
329
+ }
330
+ } catch (err) {
331
+ throw new Error(`Failed to download package: ${err}`);
332
+ }
333
+ }
334
+ const skillsDir = getSkillsDir();
335
+ const skillVersionDir = path2.join(skillsDir, `${skillId}@${targetVersion}`);
336
+ console.log("Setting up skill...");
337
+ await fs3.ensureDir(skillVersionDir);
338
+ const pkgRoot = targetDir;
339
+ if (await fs3.pathExists(path2.join(pkgRoot, "SKILL.md"))) {
340
+ await fs3.copy(
341
+ path2.join(pkgRoot, "SKILL.md"),
342
+ path2.join(skillVersionDir, "SKILL.md")
343
+ );
344
+ }
345
+ if (await fs3.pathExists(path2.join(pkgRoot, "metadata.json"))) {
346
+ await fs3.copy(
347
+ path2.join(pkgRoot, "metadata.json"),
348
+ path2.join(skillVersionDir, "metadata.json")
349
+ );
350
+ }
351
+ const skillDir = path2.join(skillsDir, skillId);
352
+ await fs3.ensureDir(skillDir);
353
+ const latestLink = path2.join(skillDir, LATEST_LINK);
354
+ try {
355
+ await fs3.remove(latestLink);
356
+ await fs3.symlink(skillVersionDir, latestLink, "junction");
357
+ } catch {
358
+ await fs3.copy(skillVersionDir, path2.join(skillDir, LATEST_LINK), { overwrite: true });
359
+ }
360
+ const registry = await loadRegistry();
361
+ const currentPlatform = detectPlatform();
362
+ registry.skills[skillId] = {
363
+ id: skillId,
364
+ version: targetVersion,
365
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
366
+ platforms: [currentPlatform]
367
+ };
368
+ await saveRegistry(registry);
369
+ console.log(`
370
+ \u2705 ${skillId}@${targetVersion} installed successfully!`);
371
+ console.log(` Use "skm info ${skillId}" for more details`);
372
+ }
373
+
374
+ // src/commands/sync.ts
375
+ import fs4 from "fs-extra";
376
+ import path3 from "path";
377
+ async function syncPlatformLinks() {
378
+ await ensureMarketDirs();
379
+ const skillsDir = getSkillsDir();
380
+ const platformLinksDir = getPlatformLinksDir();
381
+ const registry = await loadRegistry();
382
+ console.log("Syncing platform links...\n");
383
+ for (const platform of PLATFORMS) {
384
+ const platformDir = path3.join(platformLinksDir, platform, "skills");
385
+ await fs4.ensureDir(platformDir);
386
+ for (const [skillId, skillInfo] of Object.entries(registry.skills)) {
387
+ const skillLatestLink = path3.join(skillsDir, skillId, LATEST_LINK);
388
+ const targetPlatformDir = path3.join(skillLatestLink, platform);
389
+ const platformSkillDir = path3.join(platformDir, skillId);
390
+ if (await fs4.pathExists(skillLatestLink)) {
391
+ if (await fs4.pathExists(targetPlatformDir)) {
392
+ try {
393
+ await fs4.remove(platformSkillDir);
394
+ await fs4.symlink(targetPlatformDir, platformSkillDir, "junction");
395
+ console.log(` Linked: ${platform}/${skillId}`);
396
+ } catch {
397
+ await fs4.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
398
+ console.log(` Copied: ${platform}/${skillId}`);
399
+ }
400
+ }
401
+ }
402
+ }
403
+ }
404
+ console.log("\n\u2705 Sync complete!");
405
+ }
406
+
407
+ // src/commands/update.ts
408
+ async function updateSkill(skillId) {
409
+ if (skillId) {
410
+ const pkgInfo = await fetchNpmPackage(`@itismyskillmarket/${skillId}`);
411
+ if (pkgInfo) {
412
+ const latestVersion = pkgInfo["dist-tags"]?.latest;
413
+ console.log(`Updating ${skillId} to ${latestVersion}...`);
414
+ await installSkill(skillId, latestVersion);
415
+ }
416
+ return;
417
+ }
418
+ const installed = await getInstalledSkills();
419
+ if (installed.length === 0) {
420
+ console.log("No skills installed to update.");
421
+ return;
422
+ }
423
+ console.log(`Checking updates for ${installed.length} skill(s)...
424
+ `);
425
+ let hasUpdates = false;
426
+ for (const skill of installed) {
427
+ const pkgInfo = await fetchNpmPackage(`@wanxuchen/${skill.id}`);
428
+ if (pkgInfo) {
429
+ const latestVersion = pkgInfo["dist-tags"]?.latest;
430
+ if (latestVersion && latestVersion !== skill.version) {
431
+ console.log(` ${skill.id}: ${skill.version} \u2192 ${latestVersion} [UPDATE]`);
432
+ hasUpdates = true;
433
+ try {
434
+ await installSkill(skill.id, latestVersion);
435
+ } catch (err) {
436
+ console.error(` Failed to update ${skill.id}:`, err);
437
+ }
438
+ } else {
439
+ console.log(` ${skill.id}: ${skill.version} (up to date)`);
440
+ }
441
+ }
442
+ }
443
+ if (!hasUpdates) {
444
+ console.log("\nAll skills are up to date!");
445
+ }
446
+ }
447
+
448
+ // src/commands/uninstall.ts
449
+ import fs5 from "fs-extra";
450
+ import path4 from "path";
451
+ async function uninstallSkill(skillId) {
452
+ const registry = await loadRegistry();
453
+ if (!(skillId in registry.skills)) {
454
+ console.log(`Skill "${skillId}" is not installed.`);
455
+ return;
456
+ }
457
+ const skillInfo = registry.skills[skillId];
458
+ console.log(`Uninstalling ${skillId}@${skillInfo.version}...`);
459
+ const skillsDir = getSkillsDir();
460
+ const skillDir = path4.join(skillsDir, skillId);
461
+ await fs5.remove(skillDir);
462
+ const platformLinksDir = getPlatformLinksDir();
463
+ for (const platform of PLATFORMS) {
464
+ const linkPath = path4.join(platformLinksDir, platform, "skills", skillId);
465
+ if (await fs5.pathExists(linkPath)) {
466
+ await fs5.remove(linkPath);
467
+ }
468
+ }
469
+ delete registry.skills[skillId];
470
+ await saveRegistry(registry);
471
+ console.log(`
472
+ \u2705 ${skillId} uninstalled successfully!`);
473
+ }
474
+
475
+ // src/cli.ts
476
+ var program = new Command();
477
+ program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version("1.0.0");
478
+ program.hook("preAction", (thisCommand) => {
479
+ if (thisCommand.opts().help) {
480
+ console.log(`
481
+ SkillMarket CLI
482
+
483
+ Usage: skm <command> [options]
484
+
485
+ Commands:
486
+ ls [options] List available skills
487
+ --installed Show only installed skills
488
+ --updates Check for updates
489
+ info <skill-id> Display skill information
490
+ install <skill> Install a skill (e.g., skm install brainstorming)
491
+ @version Install specific version
492
+ --all Install all available skills
493
+ uninstall <skill> Remove an installed skill
494
+ update [options] Update skills
495
+ --all Update all skills
496
+ sync Synchronize platform links
497
+ platform <name> Set target platform (${PLATFORMS.join(", ")})
498
+
499
+ Examples:
500
+ skm ls List all available skills
501
+ skm ls --installed Show installed skills only
502
+ skm info brainstorming View skill details
503
+ skm install brainstorming Install a skill
504
+ skm install brainstorming@1.0.0 Install specific version
505
+ skm update --all Update all installed skills
506
+ `);
507
+ process.exit(0);
508
+ }
509
+ });
510
+ var lsCmd = program.command("ls").description("List available skills");
511
+ lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").action((opts) => {
512
+ listSkills(opts);
513
+ });
514
+ var infoCmd = program.command("info").description("Display skill information");
515
+ infoCmd.argument("<skill-id>", "Skill ID to show info").action((skillId) => {
516
+ showSkillInfo(skillId);
517
+ });
518
+ var installCmd = program.command("install").description("Install a skill");
519
+ installCmd.argument("<skill>", "Skill ID to install (e.g., brainstorming or @scope/name)").option("--all", "Install all available skills").action(async (skill, opts) => {
520
+ try {
521
+ await installSkill(skill);
522
+ } catch (err) {
523
+ console.error("Installation failed:", err);
524
+ process.exit(1);
525
+ }
526
+ });
527
+ var uninstallCmd = program.command("uninstall").description("Remove an installed skill");
528
+ uninstallCmd.argument("<skill>", "Skill ID to uninstall").action(async (skill) => {
529
+ try {
530
+ await uninstallSkill(skill);
531
+ } catch (err) {
532
+ console.error("Uninstall failed:", err);
533
+ process.exit(1);
534
+ }
535
+ });
536
+ var updateCmd = program.command("update").description("Update installed skills");
537
+ updateCmd.argument("[skill]", "Skill ID to update (optional, updates all if not specified)").option("--all", "Update all skills").action(async (skill, opts) => {
538
+ try {
539
+ if (opts.all || !skill) {
540
+ await updateSkill();
541
+ } else {
542
+ await updateSkill(skill);
543
+ }
544
+ } catch (err) {
545
+ console.error("Update failed:", err);
546
+ process.exit(1);
547
+ }
548
+ });
549
+ program.command("sync").description("Synchronize platform links").action(async () => {
550
+ try {
551
+ await syncPlatformLinks();
552
+ } catch (err) {
553
+ console.error("Sync failed:", err);
554
+ process.exit(1);
555
+ }
556
+ });
557
+ var platformCmd = program.command("platform").description("Set target platform");
558
+ platformCmd.argument("<name>", "Platform name").action((name) => {
559
+ console.log("Platform command - name:", name);
560
+ });
561
+ program.parse();