itismyskillmarket 1.3.45 → 1.3.47

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.
@@ -42,29 +42,63 @@ var fileScopes = fileConfig.npmScopes ? fileConfig.npmScopes.split(",").map((s)
42
42
  var SKILL_SCOPES = process.env.SKM_NPM_SCOPES ? process.env.SKM_NPM_SCOPES.split(",").map((s) => s.trim()).filter(Boolean) : fileScopes || DEFAULT_SCOPES;
43
43
  var SKM_URL = process.env.SKM_URL || fileConfig.skmUrl || `https://www.npmjs.com/package/${NPM_SCOPE}`;
44
44
 
45
- // src/commands/npm.ts
46
- var npmCache = /* @__PURE__ */ new Map();
47
- function getCached(key) {
48
- const entry = npmCache.get(key);
49
- if (!entry) return null;
50
- if (Date.now() > entry.expiry) {
51
- npmCache.delete(key);
52
- return null;
45
+ // src/utils/cache.ts
46
+ var TtlCache = class {
47
+ store = /* @__PURE__ */ new Map();
48
+ /**
49
+ * 获取缓存值。如果 key 不存在或已过期,返回 null
50
+ * 过期条目会被惰性删除。
51
+ */
52
+ get(key) {
53
+ const entry = this.store.get(key);
54
+ if (!entry) return null;
55
+ if (Date.now() > entry.expiry) {
56
+ this.store.delete(key);
57
+ return null;
58
+ }
59
+ return entry.data;
53
60
  }
54
- return entry.data;
55
- }
56
- function setCache(key, data, ttlMs = 3e4) {
57
- npmCache.set(key, { data, expiry: Date.now() + ttlMs });
58
- }
61
+ /**
62
+ * 设置缓存值
63
+ *
64
+ * @param key - 缓存键
65
+ * @param data - 缓存数据
66
+ * @param ttlMs - 生存时间(毫秒),默认 30 秒
67
+ */
68
+ set(key, data, ttlMs = 3e4) {
69
+ this.store.set(key, { data, expiry: Date.now() + ttlMs });
70
+ }
71
+ /**
72
+ * 删除指定的缓存条目
73
+ */
74
+ delete(key) {
75
+ this.store.delete(key);
76
+ }
77
+ /**
78
+ * 清空所有缓存
79
+ */
80
+ clear() {
81
+ this.store.clear();
82
+ }
83
+ /**
84
+ * 当前缓存条目数量
85
+ */
86
+ get size() {
87
+ return this.store.size;
88
+ }
89
+ };
90
+ var cache = new TtlCache();
91
+
92
+ // src/commands/npm.ts
59
93
  async function fetchNpmPackage(packageName, retries = 1) {
60
94
  const cacheKey = `pkg:${packageName}`;
61
- const cached = getCached(cacheKey);
95
+ const cached = cache.get(cacheKey);
62
96
  if (cached) return cached;
63
97
  for (let attempt = 0; attempt <= retries; attempt++) {
64
98
  try {
65
99
  const result = await fetchNpmPackageOnce(packageName);
66
100
  if (result !== null) {
67
- setCache(cacheKey, result);
101
+ cache.set(cacheKey, result);
68
102
  return result;
69
103
  }
70
104
  } catch {
@@ -311,8 +345,7 @@ var BaseAdapter = class {
311
345
  }
312
346
  async isAvailable() {
313
347
  try {
314
- await fs3.ensureDir(this.skillDir);
315
- return true;
348
+ return fs3.pathExists(this.skillDir);
316
349
  } catch {
317
350
  return false;
318
351
  }
@@ -687,6 +720,54 @@ import { exec } from "child_process";
687
720
  import { promisify } from "util";
688
721
  import * as tar from "tar";
689
722
  var execAsync = promisify(exec);
723
+ var CACHE_MAX_ENTRIES = 50;
724
+ var CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
725
+ async function cleanupCache() {
726
+ try {
727
+ const cacheDir = getCacheDir();
728
+ if (!await fs11.pathExists(cacheDir)) return;
729
+ const entries = await fs11.readdir(cacheDir, { withFileTypes: true });
730
+ const dirs = entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name, path: path10.join(cacheDir, e.name) }));
731
+ if (dirs.length <= CACHE_MAX_ENTRIES) {
732
+ const now = Date.now();
733
+ let removed = 0;
734
+ for (const dir of dirs) {
735
+ try {
736
+ const stat = await fs11.stat(dir.path);
737
+ if (now - stat.mtimeMs > CACHE_MAX_AGE_MS) {
738
+ await fs11.remove(dir.path);
739
+ removed++;
740
+ }
741
+ } catch {
742
+ }
743
+ }
744
+ if (removed > 0) {
745
+ console.log(` Cache cleanup: removed ${removed} expired entr${removed > 1 ? "ies" : "y"}`);
746
+ }
747
+ return;
748
+ }
749
+ const withMtime = await Promise.all(
750
+ dirs.map(async (dir) => {
751
+ try {
752
+ const stat = await fs11.stat(dir.path);
753
+ return { ...dir, mtime: stat.mtimeMs };
754
+ } catch {
755
+ return { ...dir, mtime: 0 };
756
+ }
757
+ })
758
+ );
759
+ withMtime.sort((a, b) => b.mtime - a.mtime);
760
+ const toRemove = withMtime.slice(CACHE_MAX_ENTRIES);
761
+ for (const dir of toRemove) {
762
+ try {
763
+ await fs11.remove(dir.path);
764
+ } catch {
765
+ }
766
+ }
767
+ console.log(` Cache cleanup: removed ${toRemove.length} old entr${toRemove.length > 1 ? "ies" : "y"}`);
768
+ } catch {
769
+ }
770
+ }
690
771
  async function installSkill(skillId, version, options) {
691
772
  await ensureMarketDirs();
692
773
  let targetVersion;
@@ -733,6 +814,7 @@ async function installSkill(skillId, version, options) {
733
814
  } catch (err) {
734
815
  throw new Error(`Failed to download package: ${err}`);
735
816
  }
817
+ await cleanupCache();
736
818
  }
737
819
  pkgRoot = targetDir;
738
820
  }
@@ -1182,6 +1264,24 @@ async function publishSkill(skillName, options) {
1182
1264
 
1183
1265
  // src/commands/admin.ts
1184
1266
  import { execSync as execSync2 } from "child_process";
1267
+
1268
+ // src/utils/concurrency.ts
1269
+ async function throttledMap(items, fn, concurrency = 3, batchDelayMs = 200) {
1270
+ const results = [];
1271
+ for (let i = 0; i < items.length; i += concurrency) {
1272
+ const batch = items.slice(i, i + concurrency);
1273
+ const batchResults = await Promise.all(
1274
+ batch.map((item, idx) => fn(item, i + idx))
1275
+ );
1276
+ results.push(...batchResults);
1277
+ if (i + concurrency < items.length) {
1278
+ await new Promise((r) => setTimeout(r, batchDelayMs));
1279
+ }
1280
+ }
1281
+ return results;
1282
+ }
1283
+
1284
+ // src/commands/admin.ts
1185
1285
  async function fetchScopePackages() {
1186
1286
  const all = /* @__PURE__ */ new Set();
1187
1287
  for (const scope of SKILL_SCOPES) {
@@ -1202,8 +1302,9 @@ async function adminList() {
1202
1302
  console.log("No published skills found.");
1203
1303
  return;
1204
1304
  }
1205
- const details = await Promise.all(
1206
- packages.map(async (pkg) => {
1305
+ const details = await throttledMap(
1306
+ packages,
1307
+ async (pkg) => {
1207
1308
  try {
1208
1309
  const info = await fetchNpmPackage(pkg);
1209
1310
  if (!info) return null;
@@ -1220,7 +1321,11 @@ async function adminList() {
1220
1321
  } catch {
1221
1322
  return null;
1222
1323
  }
1223
- })
1324
+ },
1325
+ 3,
1326
+ // 并发 3
1327
+ 200
1328
+ // 批次间 200ms
1224
1329
  );
1225
1330
  const valid = details.filter(Boolean);
1226
1331
  console.log(`\u{1F4E6} ${valid.length} published skill(s):
@@ -1347,15 +1452,20 @@ async function adminStats() {
1347
1452
  console.log("No published skills found.");
1348
1453
  return;
1349
1454
  }
1350
- const infos = (await Promise.all(
1351
- packages.map(async (pkg) => {
1455
+ const infos = (await throttledMap(
1456
+ packages,
1457
+ async (pkg) => {
1352
1458
  try {
1353
1459
  const info = await fetchNpmPackage(pkg);
1354
1460
  return info ? { name: pkg, info } : null;
1355
1461
  } catch {
1356
1462
  return null;
1357
1463
  }
1358
- })
1464
+ },
1465
+ 3,
1466
+ // 并发 3
1467
+ 200
1468
+ // 批次间 200ms
1359
1469
  )).filter(Boolean);
1360
1470
  const totalSkills = infos.length;
1361
1471
  let totalVersions = 0;
@@ -1872,30 +1982,16 @@ var MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
1872
1982
  var __filename = fileURLToPath2(import.meta.url);
1873
1983
  var __dirname = dirname(__filename);
1874
1984
  var guiDir = join3(__dirname, "..", "gui");
1875
- var cache = /* @__PURE__ */ new Map();
1876
- function getCached2(key) {
1877
- const entry = cache.get(key);
1878
- if (!entry) return null;
1879
- if (Date.now() > entry.expiry) {
1880
- cache.delete(key);
1881
- return null;
1882
- }
1883
- return entry.data;
1884
- }
1885
- function setCache2(key, data, ttlMs = 6e4) {
1886
- cache.set(key, { data, expiry: Date.now() + ttlMs });
1985
+ var uiCache = new TtlCache();
1986
+ function getAuthorName(author) {
1987
+ if (!author) return "";
1988
+ if (typeof author === "string") return author.replace(/<[^>]*>/g, "").trim();
1989
+ return author.name || "";
1887
1990
  }
1888
- async function throttledMap(items, fn, concurrency = 3) {
1889
- const results = [];
1890
- for (let i = 0; i < items.length; i += concurrency) {
1891
- const batch = items.slice(i, i + concurrency);
1892
- const batchResults = await Promise.all(batch.map((item, idx) => fn(item, i + idx)));
1893
- results.push(...batchResults);
1894
- if (i + concurrency < items.length) {
1895
- await new Promise((r) => setTimeout(r, 200));
1896
- }
1897
- }
1898
- return results;
1991
+ function getRepoUrl(repo) {
1992
+ if (!repo) return "";
1993
+ if (typeof repo === "string") return repo;
1994
+ return repo.url || "";
1899
1995
  }
1900
1996
  var MIME_TYPES = {
1901
1997
  ".html": "text/html; charset=utf-8",
@@ -1943,7 +2039,7 @@ API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
1943
2039
  const sort = url.searchParams.get("sort") || "name";
1944
2040
  const platform = url.searchParams.get("platform") || "";
1945
2041
  const cacheKey = `search:${search}:limit:${limit}`;
1946
- let searchResult = getCached2(cacheKey);
2042
+ let searchResult = uiCache.get(cacheKey);
1947
2043
  if (!searchResult) {
1948
2044
  searchResult = await searchSkillmarketPackages({
1949
2045
  from: 0,
@@ -1951,17 +2047,17 @@ API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
1951
2047
  // 一次拉取更多,避免分页
1952
2048
  keyword: search || void 0
1953
2049
  });
1954
- setCache2(cacheKey, searchResult, 3e4);
2050
+ uiCache.set(cacheKey, searchResult, 3e4);
1955
2051
  }
1956
2052
  const { packages, total } = searchResult;
1957
2053
  let fetchErrors = 0;
1958
2054
  const skillDetails = await throttledMap(packages, async (pkgName) => {
1959
2055
  try {
1960
2056
  const pkgCacheKey = `pkg:${pkgName}`;
1961
- let info = getCached2(pkgCacheKey);
2057
+ let info = uiCache.get(pkgCacheKey);
1962
2058
  if (!info) {
1963
2059
  info = await fetchNpmPackage(pkgName);
1964
- if (info) setCache2(pkgCacheKey, info, 3e4);
2060
+ if (info) uiCache.set(pkgCacheKey, info, 3e4);
1965
2061
  }
1966
2062
  if (!info) {
1967
2063
  fetchErrors++;
@@ -1977,9 +2073,9 @@ API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
1977
2073
  version: latestVersion,
1978
2074
  description: pkg?.description || "",
1979
2075
  platforms: meta?.platforms || [],
1980
- author: info.author?.name || pkg?.author?.name || "",
2076
+ author: getAuthorName(info.author) || getAuthorName(pkg?.author),
1981
2077
  homepage: pkg?.homepage || "",
1982
- repository: pkg?.repository?.url || "",
2078
+ repository: getRepoUrl(pkg?.repository),
1983
2079
  updated: info.time?.[latestVersion] || info.time?.modified || ""
1984
2080
  };
1985
2081
  } catch {
@@ -2095,10 +2191,10 @@ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
2095
2191
  return;
2096
2192
  }
2097
2193
  const cacheKey = `skill-info:${skillName}`;
2098
- let info = getCached2(cacheKey);
2194
+ let info = uiCache.get(cacheKey);
2099
2195
  if (!info) {
2100
2196
  info = await fetchSkillPackage(skillName);
2101
- if (info) setCache2(cacheKey, info, 3e4);
2197
+ if (info) uiCache.set(cacheKey, info, 3e4);
2102
2198
  }
2103
2199
  if (!info) {
2104
2200
  jsonResponse(res, 404, { error: `Skill "${skillName}" not found` });
@@ -2117,10 +2213,10 @@ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
2117
2213
  version: latestVersion,
2118
2214
  platforms: meta?.platforms || [],
2119
2215
  versions: recentVersions,
2120
- author: info.author?.name || pkg?.author?.name || "",
2216
+ author: getAuthorName(info.author) || getAuthorName(pkg?.author),
2121
2217
  license: info.license || "",
2122
2218
  homepage: pkg?.homepage || "",
2123
- repository: pkg?.repository?.url || "",
2219
+ repository: getRepoUrl(pkg?.repository),
2124
2220
  readme: info.readme || ""
2125
2221
  });
2126
2222
  } catch (err) {
@@ -2228,7 +2324,7 @@ API_ROUTES.GET["/api/admin/stats"] = async (_req, res, _url) => {
2228
2324
  return null;
2229
2325
  }
2230
2326
  })
2231
- )).filter(Boolean);
2327
+ )).filter((item) => item !== null);
2232
2328
  let totalVersions = 0;
2233
2329
  let totalSize = 0;
2234
2330
  const platformSet = /* @__PURE__ */ new Set();
@@ -2625,6 +2721,7 @@ export {
2625
2721
  LATEST_LINK,
2626
2722
  getSkillsDir,
2627
2723
  getPlatformLinksDir,
2724
+ getRegistryPath,
2628
2725
  ensureMarketDirs,
2629
2726
  loadRegistry,
2630
2727
  saveRegistry,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startGuiServer
4
- } from "./chunk-ALNUNP4E.js";
4
+ } from "./chunk-KDSWKP7T.js";
5
5
  export {
6
6
  startGuiServer
7
7
  };
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  getConfigValue,
25
25
  getInstalledSkills,
26
26
  getPlatformLinksDir,
27
+ getRegistryPath,
27
28
  getSkillsDir,
28
29
  installSkill,
29
30
  isSkillInstalled,
@@ -38,12 +39,12 @@ import {
38
39
  uninstallAll,
39
40
  uninstallSkill,
40
41
  updateSkill
41
- } from "./chunk-ALNUNP4E.js";
42
+ } from "./chunk-KDSWKP7T.js";
42
43
 
43
44
  // src/cli.ts
44
45
  import { Command } from "commander";
45
46
  import { readFileSync } from "fs";
46
- import { fileURLToPath as fileURLToPath2 } from "url";
47
+ import { fileURLToPath } from "url";
47
48
  import { dirname, resolve } from "path";
48
49
  import { execSync } from "child_process";
49
50
 
@@ -261,9 +262,14 @@ async function syncPlatformLinks() {
261
262
  await fs.remove(platformSkillDir);
262
263
  await fs.symlink(targetPlatformDir, platformSkillDir, "junction");
263
264
  console.log(` Linked: ${platform}/${skillId}`);
264
- } catch {
265
- await fs.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
266
- console.log(` Copied: ${platform}/${skillId}`);
265
+ } catch (err) {
266
+ const nodeErr = err;
267
+ if (nodeErr.code === "EPERM" || nodeErr.code === "EACCES" || nodeErr.code === "ENOTSUP") {
268
+ await fs.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
269
+ console.log(` Copied: ${platform}/${skillId}`);
270
+ } else {
271
+ throw err;
272
+ }
267
273
  }
268
274
  }
269
275
  }
@@ -554,15 +560,12 @@ Installing to ${targetPlatforms.length} platform(s)...
554
560
  // src/commands/verify.ts
555
561
  import fs3 from "fs-extra";
556
562
  import path3 from "path";
557
- import { fileURLToPath } from "url";
558
- var __filename = fileURLToPath(import.meta.url);
559
- var __dirname = path3.dirname(__filename);
560
563
  async function verifySkill(skillName) {
561
564
  try {
562
565
  console.log(`
563
566
  \u{1F50D} Verifying skill: ${skillName}
564
567
  `);
565
- const skillDir = path3.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "skills", skillName);
568
+ const skillDir = path3.join(getSkillsDir(), skillName);
566
569
  if (!await fs3.pathExists(skillDir)) {
567
570
  console.error(`\u274C Skill "${skillName}" not found locally.`);
568
571
  console.log(` Try: skm install ${skillName}`);
@@ -609,7 +612,7 @@ async function verifySkill(skillName) {
609
612
  } else {
610
613
  console.log(`\u26A0\uFE0F package.json not found (optional for basic skills)`);
611
614
  }
612
- const registryPath = path3.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "registry.json");
615
+ const registryPath = getRegistryPath();
613
616
  if (await fs3.pathExists(registryPath)) {
614
617
  try {
615
618
  const registry = await fs3.readJson(registryPath);
@@ -646,64 +649,13 @@ async function verifySkill(skillName) {
646
649
  }
647
650
 
648
651
  // src/cli.ts
649
- var __filename2 = fileURLToPath2(import.meta.url);
650
- var __dirname2 = dirname(__filename2);
651
- var packageJson = JSON.parse(readFileSync(resolve(__dirname2, "../package.json"), "utf-8"));
652
+ var __filename = fileURLToPath(import.meta.url);
653
+ var __dirname = dirname(__filename);
654
+ var packageJson = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf-8"));
652
655
  var VERSION = packageJson.version || "1.3.1";
653
656
  var program = new Command();
654
657
  program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version(VERSION);
655
- program.hook("preAction", (thisCommand) => {
656
- if (thisCommand.opts().help) {
657
- console.log(`
658
- SkillMarket CLI
659
-
660
- Usage: skm <command> [options]
661
-
662
- Commands:
663
- ls [options] List available skills
664
- --installed Show only installed skills
665
- --updates Check for updates
666
- --page <n> Page number (default: 1)
667
- --limit <n> Items per page (default: 20)
668
- -s, --search Search by keyword
669
- search <keyword> Search skills from npm registry
670
- -l, --limit Max results (default: 20)
671
- info <skill> Display skill information
672
- install <skill> Install a skill from npm or GitHub
673
- @<version> Install specific version
674
- --platform Target platforms (opencode,claude,vscode,codex,...)
675
- --force Overwrite if already installed
676
- -b, --branch GitHub branch to install from
677
- -c, --commit GitHub commit to install from
678
- uninstall <skill> Remove an installed skill
679
- --platform Target platforms
680
- --all Uninstall ALL installed skills
681
- --dry-run Preview without deleting
682
- -y, --yes Skip confirmation
683
- update [skill] Update installed skills (all if no skill specified)
684
- --all Update all skills
685
- publish <skill> Publish a skill to npm
686
- -v, --version Specify version
687
- verify <skill> Verify skill integrity and format
688
- sync [skill] Synchronize platform links (or sync a skill to latest)
689
- platforms Show available platforms
690
- gui [port] Start SkillMarket GUI web interface
691
- config View and manage configuration
692
- config [ls] List all configuration values
693
- config get <key> Get a config value
694
- config set <key> <val> Set a config value
695
- config reset [key] Reset config to defaults
696
- admin Admin: manage published skills
697
- admin ls List all published skills
698
- admin info <skill> Show detailed info for a published skill
699
- admin search <keyword> Search published skills
700
- admin stats Publishing statistics
701
- admin verify <skill> Verify a published skill
702
- admin deprecate <skill> Deprecate a skill (--version, --message)
703
- admin unpublish <skill> Unpublish a skill (--version, --force)
704
- admin tag set/tag rm/tag ls Manage dist-tags
705
- admin owner add/rm Manage package maintainers
706
- admin access <skill> Set package access (public|restricted)
658
+ program.addHelpText("afterAll", `
707
659
 
708
660
  Examples:
709
661
  skm ls List available skills
@@ -738,11 +690,7 @@ Examples:
738
690
  skm config reset --all Reset all config
739
691
  skm admin ls List all published skills
740
692
  skm admin stats Publishing statistics
741
- skm admin deprecate my-skill --message "Use v2" Deprecate a skill
742
- `);
743
- process.exit(0);
744
- }
745
- });
693
+ skm admin deprecate my-skill --message "Use v2" Deprecate a skill`);
746
694
  var lsCmd = program.command("ls").description("List available skills");
747
695
  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) => {
748
696
  const options = {
@@ -764,118 +712,82 @@ infoCmd.argument("<skill-id>", "Skill ID to show info").action((skillId) => {
764
712
  });
765
713
  var installCmd = program.command("install").description("Install a skill from npm or GitHub");
766
714
  installCmd.argument("<skill>", "Skill ID, npm package, or GitHub URL (owner/repo, https://github.com/owner/repo)").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 (npm only)").option("-b, --branch <branch>", "GitHub branch to install from").option("-c, --commit <commit>", "GitHub commit hash to install from").action(async (skill, opts) => {
767
- try {
768
- const platforms = opts.platform ? opts.platform.split(",").map((p) => p.trim()) : void 0;
769
- const githubSource = parseGitHubUrl(skill);
770
- if (githubSource) {
771
- await installFromGitHub(skill, {
772
- platforms,
773
- force: opts.force,
774
- branch: opts.branch,
775
- commit: opts.commit
776
- });
777
- } else {
778
- await installSkill(skill, opts.version, {
779
- platforms,
780
- force: opts.force
781
- });
782
- }
783
- } catch (err) {
784
- console.error("Installation failed:", err);
785
- process.exit(1);
715
+ const platforms = opts.platform ? opts.platform.split(",").map((p) => p.trim()) : void 0;
716
+ const githubSource = parseGitHubUrl(skill);
717
+ if (githubSource) {
718
+ await installFromGitHub(skill, {
719
+ platforms,
720
+ force: opts.force,
721
+ branch: opts.branch,
722
+ commit: opts.commit
723
+ });
724
+ } else {
725
+ await installSkill(skill, opts.version, {
726
+ platforms,
727
+ force: opts.force
728
+ });
786
729
  }
787
730
  });
788
731
  var uninstallCmd = program.command("uninstall").description("Remove an installed skill from local and platform directories");
789
732
  uninstallCmd.argument("[skill]", "Skill ID to uninstall (required unless using --all)").option("-p, --platform <platforms>", "Target platforms (comma-separated)").option("-a, --all", "Uninstall ALL installed skills (requires confirmation)").option("-d, --dry-run", "Preview what would be uninstalled without actually deleting").option("-y, --yes", "Skip confirmation prompts").action(async (skill, opts) => {
790
- try {
791
- const platforms = opts.platform ? opts.platform.split(",").map((p) => p.trim()) : void 0;
792
- if (opts.all) {
793
- await uninstallAll({
794
- platforms,
795
- dryRun: opts.dryRun,
796
- yes: opts.yes
797
- });
798
- return;
799
- }
800
- if (!skill) {
801
- console.error("Error: Skill ID is required (or use --all to uninstall all)");
802
- process.exit(1);
803
- }
804
- await uninstallSkill(skill, {
733
+ const platforms = opts.platform ? opts.platform.split(",").map((p) => p.trim()) : void 0;
734
+ if (opts.all) {
735
+ await uninstallAll({
805
736
  platforms,
806
737
  dryRun: opts.dryRun,
807
738
  yes: opts.yes
808
739
  });
809
- } catch (err) {
810
- console.error("Uninstall failed:", err);
811
- process.exit(1);
740
+ return;
741
+ }
742
+ if (!skill) {
743
+ throw new Error("Skill ID is required (or use --all to uninstall all)");
812
744
  }
745
+ await uninstallSkill(skill, {
746
+ platforms,
747
+ dryRun: opts.dryRun,
748
+ yes: opts.yes
749
+ });
813
750
  });
814
751
  var updateCmd = program.command("update").description("Update installed skills");
815
752
  updateCmd.argument("[skill]", "Skill ID to update (optional, updates all if not specified)").option("--all", "Update all skills").action(async (skill, opts) => {
816
- try {
817
- if (opts.all || !skill) {
818
- await updateSkill();
819
- } else {
820
- await updateSkill(skill);
821
- }
822
- } catch (err) {
823
- console.error("Update failed:", err);
824
- process.exit(1);
753
+ if (opts.all || !skill) {
754
+ await updateSkill();
755
+ } else {
756
+ await updateSkill(skill);
825
757
  }
826
758
  });
827
759
  program.command("sync [skill]").description("Synchronize platform links or sync skill to latest version").action(async (skill) => {
828
- try {
829
- if (skill) {
830
- await syncSkill(skill);
831
- } else {
832
- await syncPlatformLinks();
833
- }
834
- } catch (err) {
835
- console.error("Sync failed:", err);
836
- process.exit(1);
760
+ if (skill) {
761
+ await syncSkill(skill);
762
+ } else {
763
+ await syncPlatformLinks();
837
764
  }
838
765
  });
839
766
  var platformsCmd = program.command("platforms").description("Show available platforms");
840
767
  platformsCmd.action(async () => {
841
- try {
842
- const available = await detectPlatforms();
843
- const allAdapters = getAllAdapters();
844
- console.log("\n\u{1F4CD} Available Platforms:\n");
845
- for (const adapter of allAdapters) {
846
- const isAvailable = available.find((a) => a.id === adapter.id);
847
- const installed = await adapter.listInstalled();
848
- if (isAvailable) {
849
- console.log(`${adapter.name.padEnd(15)} \u2705 Available (${installed.length} skills installed)`);
850
- } else {
851
- console.log(`${adapter.name.padEnd(15)} \u274C Not detected`);
852
- }
768
+ const available = await detectPlatforms();
769
+ const allAdapters = getAllAdapters();
770
+ console.log("\n\u{1F4CD} Available Platforms:\n");
771
+ for (const adapter of allAdapters) {
772
+ const isAvailable = available.find((a) => a.id === adapter.id);
773
+ const installed = await adapter.listInstalled();
774
+ if (isAvailable) {
775
+ console.log(`${adapter.name.padEnd(15)} \u2705 Available (${installed.length} skills installed)`);
776
+ } else {
777
+ console.log(`${adapter.name.padEnd(15)} \u274C Not detected`);
853
778
  }
854
- console.log("");
855
- } catch (err) {
856
- console.error("Failed to list platforms:", err);
857
- process.exit(1);
858
779
  }
780
+ console.log("");
859
781
  });
860
782
  program.command("gui [port]").description("Start SkillMarket GUI (web interface)").action(async (port) => {
861
783
  const portNum = port ? parseInt(port) : 18770;
862
784
  startGuiServer(portNum);
863
785
  });
864
786
  program.command("publish <skill>").description("Publish a skill to npm").option("-v, --version <version>", "Specify version (optional, auto-increment patch if not specified)").action(async (skill, options) => {
865
- try {
866
- await publishSkill(skill, options.version ? { version: options.version } : void 0);
867
- } catch (err) {
868
- console.error("Publish failed:", err);
869
- process.exit(1);
870
- }
787
+ await publishSkill(skill, options.version ? { version: options.version } : void 0);
871
788
  });
872
789
  program.command("verify <skill>").description("Verify skill integrity and format").action(async (skill) => {
873
- try {
874
- await verifySkill(skill);
875
- } catch (err) {
876
- console.error("Verify failed:", err);
877
- process.exit(1);
878
- }
790
+ await verifySkill(skill);
879
791
  });
880
792
  var config = program.command("config").description("View and manage configuration");
881
793
  config.command("list").alias("ls").description("List all configuration values").action(async () => {
@@ -895,121 +807,56 @@ config.command("reset [key]").description("Reset configuration to default values
895
807
  });
896
808
  var admin = program.command("admin").description("Admin: manage published skills (cloud)");
897
809
  admin.command("ls").description("List all published skills").action(async () => {
898
- try {
899
- await adminList();
900
- } catch (err) {
901
- console.error("Admin ls failed:", err);
902
- process.exit(1);
903
- }
810
+ await adminList();
904
811
  });
905
812
  admin.command("info <skill>").description("Show detailed info for a published skill").action(async (skill) => {
906
- try {
907
- await adminInfo(skill);
908
- } catch (err) {
909
- console.error("Admin info failed:", err);
910
- process.exit(1);
911
- }
813
+ await adminInfo(skill);
912
814
  });
913
815
  admin.command("search <keyword>").description("Search across published skills").option("-l, --limit <number>", "Max results (default: 20)", parseInt).action(async (keyword, opts) => {
914
- try {
915
- await adminSearch(keyword, opts.limit ?? 20);
916
- } catch (err) {
917
- console.error("Admin search failed:", err);
918
- process.exit(1);
919
- }
816
+ await adminSearch(keyword, opts.limit ?? 20);
920
817
  });
921
818
  admin.command("stats").description("Show publishing statistics").action(async () => {
922
- try {
923
- await adminStats();
924
- } catch (err) {
925
- console.error("Admin stats failed:", err);
926
- process.exit(1);
927
- }
819
+ await adminStats();
928
820
  });
929
821
  admin.command("verify <skill>").description("Verify a published skill structure and metadata").action(async (skill) => {
930
- try {
931
- await adminVerify(skill);
932
- } catch (err) {
933
- console.error("Admin verify failed:", err);
934
- process.exit(1);
935
- }
822
+ await adminVerify(skill);
936
823
  });
937
824
  admin.command("deprecate <skill>").description("Deprecate a published skill (or specific version)").option("-v, --version <version>", "Deprecate a specific version only").option("-m, --message <message>", "Deprecation message").action(async (skill, opts) => {
938
- try {
939
- await adminDeprecate(skill, {
940
- version: opts.version,
941
- message: opts.message
942
- });
943
- } catch (err) {
944
- console.error("Admin deprecate failed:", err);
945
- process.exit(1);
946
- }
825
+ await adminDeprecate(skill, {
826
+ version: opts.version,
827
+ message: opts.message
828
+ });
947
829
  });
948
830
  admin.command("unpublish <skill>").description("Unpublish a skill (or specific version) from npm").option("-v, --version <version>", "Unpublish a specific version only").option("-f, --force", "Force unpublish entire package").action(async (skill, opts) => {
949
- try {
950
- await adminUnpublish(skill, {
951
- version: opts.version,
952
- force: opts.force
953
- });
954
- } catch (err) {
955
- console.error("Admin unpublish failed:", err);
956
- process.exit(1);
957
- }
831
+ await adminUnpublish(skill, {
832
+ version: opts.version,
833
+ force: opts.force
834
+ });
958
835
  });
959
836
  var adminTag = admin.command("tag").description("Manage dist-tags for a skill");
960
837
  adminTag.command("set <skill> <tag> <version>").description("Set a dist-tag for a specific version").action(async (skill, tag, version) => {
961
- try {
962
- await adminTagSet(skill, tag, version);
963
- } catch (err) {
964
- console.error("Admin tag set failed:", err);
965
- process.exit(1);
966
- }
838
+ await adminTagSet(skill, tag, version);
967
839
  });
968
840
  adminTag.command("rm <skill> <tag>").description("Remove a dist-tag").action(async (skill, tag) => {
969
- try {
970
- await adminTagRemove(skill, tag);
971
- } catch (err) {
972
- console.error("Admin tag rm failed:", err);
973
- process.exit(1);
974
- }
841
+ await adminTagRemove(skill, tag);
975
842
  });
976
843
  adminTag.command("ls <skill>").description("List all dist-tags for a skill").action(async (skill) => {
977
- try {
978
- await adminTagList(skill);
979
- } catch (err) {
980
- console.error("Admin tag ls failed:", err);
981
- process.exit(1);
982
- }
844
+ await adminTagList(skill);
983
845
  });
984
846
  var adminOwner = admin.command("owner").description("Manage package owners/maintainers");
985
847
  adminOwner.command("add <skill> <user>").description("Add an owner to a skill package").action(async (skill, user) => {
986
- try {
987
- await adminOwnerAdd(skill, user);
988
- } catch (err) {
989
- console.error("Admin owner add failed:", err);
990
- process.exit(1);
991
- }
848
+ await adminOwnerAdd(skill, user);
992
849
  });
993
850
  adminOwner.command("rm <skill> <user>").description("Remove an owner from a skill package").action(async (skill, user) => {
994
- try {
995
- await adminOwnerRemove(skill, user);
996
- } catch (err) {
997
- console.error("Admin owner rm failed:", err);
998
- process.exit(1);
999
- }
851
+ await adminOwnerRemove(skill, user);
1000
852
  });
1001
853
  admin.command("access <skill> <level>").description("Set package access (public|restricted)").action(async (skill, level) => {
1002
- try {
1003
- if (level !== "public" && level !== "restricted") {
1004
- console.error('\u274C Access level must be "public" or "restricted"');
1005
- process.exit(1);
1006
- }
1007
- await adminAccess(skill, level);
1008
- } catch (err) {
1009
- console.error("Admin access failed:", err);
1010
- process.exit(1);
854
+ if (level !== "public" && level !== "restricted") {
855
+ throw new Error('Access level must be "public" or "restricted"');
1011
856
  }
857
+ await adminAccess(skill, level);
1012
858
  });
859
+ program.exitOverride();
1013
860
  var hasArgs = process.argv.slice(2).length > 0;
1014
861
  if (!hasArgs) {
1015
862
  const port = 18770;
@@ -1021,5 +868,10 @@ if (!hasArgs) {
1021
868
  }, 1500);
1022
869
  startGuiServer(port);
1023
870
  } else {
1024
- program.parse();
871
+ try {
872
+ await program.parseAsync();
873
+ } catch (err) {
874
+ console.error(err instanceof Error ? err.message : String(err));
875
+ process.exit(1);
876
+ }
1025
877
  }
package/gui/app.js CHANGED
@@ -697,7 +697,7 @@ function applyI18nToStaticElements() {
697
697
  // 主题切换
698
698
  // -----------------------------------------------------------------------------
699
699
 
700
- const THEMES = ['ocean', 'purple', 'forest', 'amber', 'sepia', 'gray', 'teal', 'dusk'];
700
+ const THEMES = ['ocean', 'purple', 'forest', 'amber', 'sepia', 'gray', 'teal', 'dusk', 'light'];
701
701
 
702
702
  function detectTheme() {
703
703
  const saved = localStorage.getItem('skm-theme');
package/gui/index.html CHANGED
@@ -32,6 +32,7 @@
32
32
  <option value="gray">🌫 柔灰</option>
33
33
  <option value="teal">🦆 墨青</option>
34
34
  <option value="dusk">🌆 暮紫</option>
35
+ <option value="light">☀ 纯白</option>
35
36
  </select>
36
37
  </div>
37
38
  <div class="lang-switch">
package/gui/style.css CHANGED
@@ -144,6 +144,23 @@ body.theme-dusk {
144
144
  --danger: #b55373;
145
145
  }
146
146
 
147
+ /* 纯白 - 明亮模式 */
148
+ body.theme-light {
149
+ --bg-primary: #f0f2f5;
150
+ --bg-secondary: #ffffff;
151
+ --bg-card: #ffffff;
152
+ --bg-hover: #e4e6eb;
153
+ --text-primary: #e94560;
154
+ --text-secondary: #1a1a2e;
155
+ --text-muted: #8a8a9a;
156
+ --border-color: #d0d2d8;
157
+ --accent: #e94560;
158
+ --accent-hover: #d63850;
159
+ --success: #4caf50;
160
+ --warning: #ff9800;
161
+ --danger: #f44336;
162
+ }
163
+
147
164
  * {
148
165
  margin: 0;
149
166
  padding: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itismyskillmarket",
3
- "version": "1.3.45",
3
+ "version": "1.3.47",
4
4
  "description": "Cross-platform skill manager for AI coding tools",
5
5
  "type": "module",
6
6
  "bin": {