itismyskillmarket 1.3.25 → 1.3.27

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 CHANGED
@@ -135,11 +135,30 @@ var SKILL_SCOPES = process.env.SKM_NPM_SCOPES ? process.env.SKM_NPM_SCOPES.split
135
135
  var SKM_URL = process.env.SKM_URL || fileConfig.skmUrl || `https://www.npmjs.com/package/${NPM_SCOPE}`;
136
136
 
137
137
  // src/commands/npm.ts
138
+ var npmCache = /* @__PURE__ */ new Map();
139
+ function getCached(key) {
140
+ const entry = npmCache.get(key);
141
+ if (!entry) return null;
142
+ if (Date.now() > entry.expiry) {
143
+ npmCache.delete(key);
144
+ return null;
145
+ }
146
+ return entry.data;
147
+ }
148
+ function setCache(key, data, ttlMs = 3e4) {
149
+ npmCache.set(key, { data, expiry: Date.now() + ttlMs });
150
+ }
138
151
  async function fetchNpmPackage(packageName, retries = 1) {
152
+ const cacheKey = `pkg:${packageName}`;
153
+ const cached = getCached(cacheKey);
154
+ if (cached) return cached;
139
155
  for (let attempt = 0; attempt <= retries; attempt++) {
140
156
  try {
141
157
  const result = await fetchNpmPackageOnce(packageName);
142
- if (result !== null) return result;
158
+ if (result !== null) {
159
+ setCache(cacheKey, result);
160
+ return result;
161
+ }
143
162
  } catch {
144
163
  if (attempt === retries) return null;
145
164
  }
@@ -452,8 +471,8 @@ Status: Not installed (use skm install ${skillId} to install)`);
452
471
  }
453
472
 
454
473
  // src/commands/install.ts
455
- import fs7 from "fs-extra";
456
- import path6 from "path";
474
+ import fs9 from "fs-extra";
475
+ import path8 from "path";
457
476
  import { exec } from "child_process";
458
477
  import { promisify } from "util";
459
478
 
@@ -599,52 +618,48 @@ var VSCodeAdapter = class extends BaseAdapter {
599
618
  };
600
619
 
601
620
  // src/adapters/openclaw.ts
602
- import { readdirSync, existsSync as existsSync2, cpSync, rmSync } from "fs";
603
- import { join as join2 } from "path";
604
- import { homedir } from "os";
605
- import { ensureDirSync } from "fs-extra";
606
- var OpenClawAdapter = class {
621
+ import path6 from "path";
622
+ import os6 from "os";
623
+ import fs7 from "fs-extra";
624
+ var OpenClawAdapter = class extends BaseAdapter {
607
625
  id = "openclaw";
608
626
  name = "OpenClaw";
609
- skillDir = join2(homedir(), ".openclaw", "skills");
627
+ skillDir = path6.join(os6.homedir(), ".openclaw", "skills");
610
628
  async isAvailable() {
611
629
  try {
612
- return existsSync2(join2(homedir(), ".openclaw"));
630
+ return await fs7.pathExists(path6.join(os6.homedir(), ".openclaw"));
613
631
  } catch {
614
632
  return false;
615
633
  }
616
634
  }
617
635
  async isInstalled(skillId) {
618
636
  try {
619
- const skillPath = join2(this.skillDir, skillId);
620
- return existsSync2(skillPath);
637
+ return await fs7.pathExists(path6.join(this.skillDir, skillId));
621
638
  } catch {
622
639
  return false;
623
640
  }
624
641
  }
625
642
  async install(skillId, sourceDir) {
626
- ensureDirSync(this.skillDir);
627
- const targetDir = join2(this.skillDir, skillId);
628
- if (existsSync2(targetDir)) {
629
- rmSync(targetDir, { recursive: true, force: true });
643
+ await fs7.ensureDir(this.skillDir);
644
+ const targetDir = path6.join(this.skillDir, skillId);
645
+ if (await fs7.pathExists(targetDir)) {
646
+ await fs7.remove(targetDir);
630
647
  }
631
- cpSync(sourceDir, targetDir, { recursive: true });
648
+ await fs7.copy(sourceDir, targetDir, { recursive: true });
632
649
  }
633
650
  async uninstall(skillId) {
634
- const targetDir = join2(this.skillDir, skillId);
635
- if (existsSync2(targetDir)) {
636
- rmSync(targetDir, { recursive: true, force: true });
651
+ const targetDir = path6.join(this.skillDir, skillId);
652
+ if (await fs7.pathExists(targetDir)) {
653
+ await fs7.remove(targetDir);
637
654
  }
638
655
  }
639
656
  async listInstalled() {
640
657
  try {
641
- if (!existsSync2(this.skillDir)) {
658
+ if (!await fs7.pathExists(this.skillDir)) {
642
659
  return [];
643
660
  }
644
- return readdirSync(this.skillDir).filter((name) => {
645
- const fullPath = join2(this.skillDir, name);
646
- return existsSync2(fullPath) && name !== ".";
647
- });
661
+ const entries = await fs7.readdir(this.skillDir, { withFileTypes: true });
662
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
648
663
  } catch {
649
664
  return [];
650
665
  }
@@ -652,55 +667,48 @@ var OpenClawAdapter = class {
652
667
  };
653
668
 
654
669
  // src/adapters/hermes.ts
655
- import { readdirSync as readdirSync2, existsSync as existsSync3, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
656
- import { join as join3 } from "path";
657
- import { homedir as homedir2 } from "os";
658
- import { ensureDirSync as ensureDirSync2 } from "fs-extra";
659
- var HermesAdapter = class {
670
+ import path7 from "path";
671
+ import os7 from "os";
672
+ import fs8 from "fs-extra";
673
+ var HermesAdapter = class extends BaseAdapter {
660
674
  id = "hermes";
661
675
  name = "Hermes Agent";
662
- skillDir = join3(homedir2(), ".hermes", "skills");
676
+ skillDir = path7.join(os7.homedir(), ".hermes", "skills");
663
677
  async isAvailable() {
664
678
  try {
665
- if (existsSync3(join3(homedir2(), ".hermes"))) {
666
- return true;
667
- }
668
- return false;
679
+ return await fs8.pathExists(path7.join(os7.homedir(), ".hermes"));
669
680
  } catch {
670
681
  return false;
671
682
  }
672
683
  }
673
684
  async isInstalled(skillId) {
674
685
  try {
675
- const skillPath = join3(this.skillDir, skillId);
676
- return existsSync3(skillPath);
686
+ return await fs8.pathExists(path7.join(this.skillDir, skillId));
677
687
  } catch {
678
688
  return false;
679
689
  }
680
690
  }
681
691
  async install(skillId, sourceDir) {
682
- ensureDirSync2(this.skillDir);
683
- const targetDir = join3(this.skillDir, skillId);
684
- if (existsSync3(targetDir)) {
685
- rmSync2(targetDir, { recursive: true, force: true });
692
+ await fs8.ensureDir(this.skillDir);
693
+ const targetDir = path7.join(this.skillDir, skillId);
694
+ if (await fs8.pathExists(targetDir)) {
695
+ await fs8.remove(targetDir);
686
696
  }
687
- cpSync2(sourceDir, targetDir, { recursive: true });
697
+ await fs8.copy(sourceDir, targetDir, { recursive: true });
688
698
  }
689
699
  async uninstall(skillId) {
690
- const targetDir = join3(this.skillDir, skillId);
691
- if (existsSync3(targetDir)) {
692
- rmSync2(targetDir, { recursive: true, force: true });
700
+ const targetDir = path7.join(this.skillDir, skillId);
701
+ if (await fs8.pathExists(targetDir)) {
702
+ await fs8.remove(targetDir);
693
703
  }
694
704
  }
695
705
  async listInstalled() {
696
706
  try {
697
- if (!existsSync3(this.skillDir)) {
707
+ if (!await fs8.pathExists(this.skillDir)) {
698
708
  return [];
699
709
  }
700
- return readdirSync2(this.skillDir).filter((name) => {
701
- const fullPath = join3(this.skillDir, name);
702
- return existsSync3(fullPath) && name !== ".";
703
- });
710
+ const entries = await fs8.readdir(this.skillDir, { withFileTypes: true });
711
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
704
712
  } catch {
705
713
  return [];
706
714
  }
@@ -766,52 +774,52 @@ async function installSkill(skillId, version, options) {
766
774
  throw new Error(`No version found for ${packageName}`);
767
775
  }
768
776
  const cacheDir = getCacheDir();
769
- const targetDir = path6.join(cacheDir, `${packageName}@${targetVersion}`);
770
- if (!await fs7.pathExists(targetDir)) {
777
+ const targetDir = path8.join(cacheDir, `${packageName}@${targetVersion}`);
778
+ if (!await fs9.pathExists(targetDir)) {
771
779
  console.log("Downloading package...");
772
- await fs7.ensureDir(cacheDir);
780
+ await fs9.ensureDir(cacheDir);
773
781
  try {
774
782
  await execAsync(`npm pack ${packageName}@${targetVersion} --pack-destination ${cacheDir}`);
775
- const files = await fs7.readdir(cacheDir);
783
+ const files = await fs9.readdir(cacheDir);
776
784
  const tarball = files.find(
777
785
  (f) => f.endsWith(".tgz") && f.includes(packageName.replace(/^@/, "").replace("/", "-"))
778
786
  );
779
787
  if (tarball) {
780
- await execAsync(`tar -xzf "${path6.join(cacheDir, tarball)}" -C "${cacheDir}"`);
781
- await fs7.remove(path6.join(cacheDir, tarball));
782
- const extractedDir = path6.join(cacheDir, "package");
788
+ await execAsync(`tar -xzf "${path8.join(cacheDir, tarball)}" -C "${cacheDir}"`);
789
+ await fs9.remove(path8.join(cacheDir, tarball));
790
+ const extractedDir = path8.join(cacheDir, "package");
783
791
  const finalDir = targetDir;
784
- await fs7.move(extractedDir, finalDir, { overwrite: true });
792
+ await fs9.move(extractedDir, finalDir, { overwrite: true });
785
793
  }
786
794
  } catch (err) {
787
795
  throw new Error(`Failed to download package: ${err}`);
788
796
  }
789
797
  }
790
798
  const skillsDir = getSkillsDir();
791
- const skillVersionDir = path6.join(skillsDir, `${skillId}@${targetVersion}`);
799
+ const skillVersionDir = path8.join(skillsDir, `${skillId}@${targetVersion}`);
792
800
  console.log("Setting up skill...");
793
- await fs7.ensureDir(skillVersionDir);
801
+ await fs9.ensureDir(skillVersionDir);
794
802
  const pkgRoot = targetDir;
795
- if (await fs7.pathExists(path6.join(pkgRoot, "SKILL.md"))) {
796
- await fs7.copy(
797
- path6.join(pkgRoot, "SKILL.md"),
798
- path6.join(skillVersionDir, "SKILL.md")
803
+ if (await fs9.pathExists(path8.join(pkgRoot, "SKILL.md"))) {
804
+ await fs9.copy(
805
+ path8.join(pkgRoot, "SKILL.md"),
806
+ path8.join(skillVersionDir, "SKILL.md")
799
807
  );
800
808
  }
801
- if (await fs7.pathExists(path6.join(pkgRoot, "metadata.json"))) {
802
- await fs7.copy(
803
- path6.join(pkgRoot, "metadata.json"),
804
- path6.join(skillVersionDir, "metadata.json")
809
+ if (await fs9.pathExists(path8.join(pkgRoot, "metadata.json"))) {
810
+ await fs9.copy(
811
+ path8.join(pkgRoot, "metadata.json"),
812
+ path8.join(skillVersionDir, "metadata.json")
805
813
  );
806
814
  }
807
- const skillDir = path6.join(skillsDir, skillId);
808
- await fs7.ensureDir(skillDir);
809
- const latestLink = path6.join(skillDir, LATEST_LINK);
815
+ const skillDir = path8.join(skillsDir, skillId);
816
+ await fs9.ensureDir(skillDir);
817
+ const latestLink = path8.join(skillDir, LATEST_LINK);
810
818
  try {
811
- await fs7.remove(latestLink);
812
- await fs7.symlink(skillVersionDir, latestLink, "junction");
819
+ await fs9.remove(latestLink);
820
+ await fs9.symlink(skillVersionDir, latestLink, "junction");
813
821
  } catch {
814
- await fs7.copy(skillVersionDir, path6.join(skillDir, LATEST_LINK), { overwrite: true });
822
+ await fs9.copy(skillVersionDir, path8.join(skillDir, LATEST_LINK), { overwrite: true });
815
823
  }
816
824
  let targetAdapters = [];
817
825
  if (options?.platforms && options.platforms.length > 0) {
@@ -872,8 +880,8 @@ Installing to ${targetAdapters.length} platform(s)...
872
880
  }
873
881
 
874
882
  // src/commands/sync.ts
875
- import fs8 from "fs-extra";
876
- import path7 from "path";
883
+ import fs10 from "fs-extra";
884
+ import path9 from "path";
877
885
  async function syncPlatformLinks() {
878
886
  await ensureMarketDirs();
879
887
  const skillsDir = getSkillsDir();
@@ -881,20 +889,20 @@ async function syncPlatformLinks() {
881
889
  const registry = await loadRegistry();
882
890
  console.log("Syncing platform links...\n");
883
891
  for (const platform of PLATFORMS) {
884
- const platformDir = path7.join(platformLinksDir, platform, "skills");
885
- await fs8.ensureDir(platformDir);
892
+ const platformDir = path9.join(platformLinksDir, platform, "skills");
893
+ await fs10.ensureDir(platformDir);
886
894
  for (const [skillId, skillInfo] of Object.entries(registry.skills)) {
887
- const skillLatestLink = path7.join(skillsDir, skillId, LATEST_LINK);
888
- const targetPlatformDir = path7.join(skillLatestLink, platform);
889
- const platformSkillDir = path7.join(platformDir, skillId);
890
- if (await fs8.pathExists(skillLatestLink)) {
891
- if (await fs8.pathExists(targetPlatformDir)) {
895
+ const skillLatestLink = path9.join(skillsDir, skillId, LATEST_LINK);
896
+ const targetPlatformDir = path9.join(skillLatestLink, platform);
897
+ const platformSkillDir = path9.join(platformDir, skillId);
898
+ if (await fs10.pathExists(skillLatestLink)) {
899
+ if (await fs10.pathExists(targetPlatformDir)) {
892
900
  try {
893
- await fs8.remove(platformSkillDir);
894
- await fs8.symlink(targetPlatformDir, platformSkillDir, "junction");
901
+ await fs10.remove(platformSkillDir);
902
+ await fs10.symlink(targetPlatformDir, platformSkillDir, "junction");
895
903
  console.log(` Linked: ${platform}/${skillId}`);
896
904
  } catch {
897
- await fs8.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
905
+ await fs10.copy(targetPlatformDir, platformSkillDir, { overwrite: true });
898
906
  console.log(` Copied: ${platform}/${skillId}`);
899
907
  }
900
908
  }
@@ -923,11 +931,17 @@ async function syncSkill(skillId) {
923
931
  // src/commands/update.ts
924
932
  async function updateSkill(skillId) {
925
933
  if (skillId) {
926
- const pkgInfo = await fetchNpmPackage(`${NPM_SCOPE}/${skillId}`);
934
+ const pkgInfo = await fetchSkillPackage(skillId);
927
935
  if (pkgInfo) {
928
936
  const latestVersion = pkgInfo["dist-tags"]?.latest;
937
+ if (!latestVersion) {
938
+ console.log(`No latest version found for ${skillId}.`);
939
+ return;
940
+ }
929
941
  console.log(`Updating ${skillId} to ${latestVersion}...`);
930
942
  await installSkill(skillId, latestVersion);
943
+ } else {
944
+ console.log(`Skill "${skillId}" not found in any configured scope.`);
931
945
  }
932
946
  return;
933
947
  }
@@ -940,7 +954,7 @@ async function updateSkill(skillId) {
940
954
  `);
941
955
  let hasUpdates = false;
942
956
  for (const skill of installed) {
943
- const pkgInfo = await fetchNpmPackage(`${NPM_SCOPE_FALLBACK}/${skill.id}`);
957
+ const pkgInfo = await fetchSkillPackage(skill.id);
944
958
  if (pkgInfo) {
945
959
  const latestVersion = pkgInfo["dist-tags"]?.latest;
946
960
  if (latestVersion && latestVersion !== skill.version) {
@@ -954,6 +968,8 @@ async function updateSkill(skillId) {
954
968
  } else {
955
969
  console.log(` ${skill.id}: ${skill.version} (up to date)`);
956
970
  }
971
+ } else {
972
+ console.log(` ${skill.id}: ${skill.version} (failed to fetch remote)`);
957
973
  }
958
974
  }
959
975
  if (!hasUpdates) {
@@ -962,8 +978,8 @@ async function updateSkill(skillId) {
962
978
  }
963
979
 
964
980
  // src/commands/uninstall.ts
965
- import fs9 from "fs-extra";
966
- import path8 from "path";
981
+ import fs11 from "fs-extra";
982
+ import path10 from "path";
967
983
  import readline from "readline";
968
984
  async function askConfirmation(message) {
969
985
  const rl = readline.createInterface({
@@ -988,12 +1004,12 @@ async function getUninstallPreview(skillId, options) {
988
1004
  platformNames = adapters2.map((a) => a.name);
989
1005
  }
990
1006
  const skillsDir = getSkillsDir();
991
- const localPath = path8.join(skillsDir, skillId);
1007
+ const localPath = path10.join(skillsDir, skillId);
992
1008
  const platformLinksDir = getPlatformLinksDir();
993
1009
  const platformLinks = [];
994
1010
  for (const platform of PLATFORMS) {
995
- const linkPath = path8.join(platformLinksDir, platform, "skills", skillId);
996
- if (await fs9.pathExists(linkPath)) {
1011
+ const linkPath = path10.join(platformLinksDir, platform, "skills", skillId);
1012
+ if (await fs11.pathExists(linkPath)) {
997
1013
  platformLinks.push(linkPath);
998
1014
  }
999
1015
  }
@@ -1072,17 +1088,17 @@ Uninstalling from ${validAdapters.length} platform(s)...
1072
1088
  }
1073
1089
  }
1074
1090
  const skillsDir = getSkillsDir();
1075
- const skillDir = path8.join(skillsDir, skillId);
1076
- if (await fs9.pathExists(skillDir)) {
1077
- await fs9.remove(skillDir);
1091
+ const skillDir = path10.join(skillsDir, skillId);
1092
+ if (await fs11.pathExists(skillDir)) {
1093
+ await fs11.remove(skillDir);
1078
1094
  console.log(`\u2705 Removed local files: ${skillDir}`);
1079
1095
  }
1080
1096
  const platformLinksDir = getPlatformLinksDir();
1081
1097
  let removedLinks = 0;
1082
1098
  for (const platform of PLATFORMS) {
1083
- const linkPath = path8.join(platformLinksDir, platform, "skills", skillId);
1084
- if (await fs9.pathExists(linkPath)) {
1085
- await fs9.remove(linkPath);
1099
+ const linkPath = path10.join(platformLinksDir, platform, "skills", skillId);
1100
+ if (await fs11.pathExists(linkPath)) {
1101
+ await fs11.remove(linkPath);
1086
1102
  removedLinks++;
1087
1103
  }
1088
1104
  }
@@ -1152,8 +1168,8 @@ Uninstalling all skills...
1152
1168
  }
1153
1169
 
1154
1170
  // src/commands/github-install.ts
1155
- import fs10 from "fs-extra";
1156
- import path9 from "path";
1171
+ import fs12 from "fs-extra";
1172
+ import path11 from "path";
1157
1173
  var GITHUB_URL_PATTERNS = [
1158
1174
  /^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)(?:\/(.+))?)?$/,
1159
1175
  /^([^/]+)\/([^/]+)(?:#(.+))?$/,
@@ -1170,13 +1186,13 @@ function parseGitHubUrl(input) {
1170
1186
  const repo = match[2].replace(/\.git$/, "");
1171
1187
  const branch = match[3] || "main";
1172
1188
  const commitOrPath = match[4] || match[3];
1173
- const path12 = match[5] || void 0;
1189
+ const path14 = match[5] || void 0;
1174
1190
  return {
1175
1191
  owner,
1176
1192
  repo,
1177
1193
  branch: commitOrPath && !commitOrPath.includes("/") ? commitOrPath : branch,
1178
1194
  commit: commitOrPath?.match(/^[0-9a-f]{40}$/) ? commitOrPath : void 0,
1179
- path: path12
1195
+ path: path14
1180
1196
  };
1181
1197
  }
1182
1198
  }
@@ -1275,17 +1291,17 @@ async function detectSkillFromGitHub(source) {
1275
1291
  }
1276
1292
  async function generatePlatformAdapters(skillId, existingPlatforms, targetPlatforms, sourceDir) {
1277
1293
  const skillsDir = getSkillsDir();
1278
- const skillVersionDir = path9.join(skillsDir, `${skillId}@github`);
1294
+ const skillVersionDir = path11.join(skillsDir, `${skillId}@github`);
1279
1295
  for (const platform of targetPlatforms) {
1280
1296
  if (existingPlatforms.includes(platform)) {
1281
1297
  continue;
1282
1298
  }
1283
- const platformDir = path9.join(skillVersionDir, platform);
1284
- await fs10.ensureDir(platformDir);
1285
- const sourceSkillMd = path9.join(sourceDir, "SKILL.md");
1286
- const targetSkillMd = path9.join(platformDir, "SKILL.md");
1287
- if (await fs10.pathExists(sourceSkillMd)) {
1288
- await fs10.copy(sourceSkillMd, targetSkillMd);
1299
+ const platformDir = path11.join(skillVersionDir, platform);
1300
+ await fs12.ensureDir(platformDir);
1301
+ const sourceSkillMd = path11.join(sourceDir, "SKILL.md");
1302
+ const targetSkillMd = path11.join(platformDir, "SKILL.md");
1303
+ if (await fs12.pathExists(sourceSkillMd)) {
1304
+ await fs12.copy(sourceSkillMd, targetSkillMd);
1289
1305
  }
1290
1306
  if (platform === "opencode" || platform === "cursor" || platform === "codex" || platform === "antigravity") {
1291
1307
  } else if (platform === "vscode") {
@@ -1294,14 +1310,14 @@ async function generatePlatformAdapters(skillId, existingPlatforms, targetPlatfo
1294
1310
  description: `Skill: ${skillId}`,
1295
1311
  version: "1.0.0"
1296
1312
  };
1297
- await fs10.writeJson(path9.join(platformDir, "skill.json"), skillJson, { spaces: 2 });
1313
+ await fs12.writeJson(path11.join(platformDir, "skill.json"), skillJson, { spaces: 2 });
1298
1314
  } else if (platform === "claude") {
1299
1315
  const skillJson = {
1300
1316
  name: skillId,
1301
1317
  description: `Skill: ${skillId}`,
1302
1318
  version: "1.0.0"
1303
1319
  };
1304
- await fs10.writeJson(path9.join(platformDir, "skill.json"), skillJson, { spaces: 2 });
1320
+ await fs12.writeJson(path11.join(platformDir, "skill.json"), skillJson, { spaces: 2 });
1305
1321
  }
1306
1322
  }
1307
1323
  }
@@ -1330,26 +1346,26 @@ async function installFromGitHub(input, options) {
1330
1346
  Setting up skill: ${skillId}@${version}`);
1331
1347
  await ensureMarketDirs();
1332
1348
  const skillsDir = getSkillsDir();
1333
- const skillVersionDir = path9.join(skillsDir, `${skillId}@${version}`);
1334
- await fs10.ensureDir(skillVersionDir);
1349
+ const skillVersionDir = path11.join(skillsDir, `${skillId}@${version}`);
1350
+ await fs12.ensureDir(skillVersionDir);
1335
1351
  console.log("Downloading files...");
1336
1352
  const basePath = source.path || "";
1337
1353
  const skillMdPath = basePath ? `${basePath}/SKILL.md` : "SKILL.md";
1338
1354
  const skillMdContent = await fetchGitHubFile(source, skillMdPath);
1339
1355
  if (skillMdContent) {
1340
- await fs10.writeFile(path9.join(skillVersionDir, "SKILL.md"), skillMdContent);
1356
+ await fs12.writeFile(path11.join(skillVersionDir, "SKILL.md"), skillMdContent);
1341
1357
  console.log(" \u2705 SKILL.md");
1342
1358
  }
1343
1359
  const packageJsonPath = basePath ? `${basePath}/package.json` : "package.json";
1344
1360
  const packageJsonContent = await fetchGitHubFile(source, packageJsonPath);
1345
1361
  if (packageJsonContent) {
1346
- await fs10.writeFile(path9.join(skillVersionDir, "package.json"), packageJsonContent);
1362
+ await fs12.writeFile(path11.join(skillVersionDir, "package.json"), packageJsonContent);
1347
1363
  console.log(" \u2705 package.json");
1348
1364
  }
1349
1365
  const metadataPath = basePath ? `${basePath}/metadata.json` : "metadata.json";
1350
1366
  const metadataContent = await fetchGitHubFile(source, metadataPath);
1351
1367
  if (metadataContent) {
1352
- await fs10.writeFile(path9.join(skillVersionDir, "metadata.json"), metadataContent);
1368
+ await fs12.writeFile(path11.join(skillVersionDir, "metadata.json"), metadataContent);
1353
1369
  console.log(" \u2705 metadata.json");
1354
1370
  }
1355
1371
  const targetPlatforms = options?.platforms || detected.platforms;
@@ -1361,14 +1377,14 @@ Generating adapters for missing platforms: ${missingPlatforms.join(", ")}`);
1361
1377
  await generatePlatformAdapters(skillId, existingPlatforms, targetPlatforms, skillVersionDir);
1362
1378
  console.log(" \u2705 Platform adapters generated");
1363
1379
  }
1364
- const skillDir = path9.join(skillsDir, skillId);
1365
- await fs10.ensureDir(skillDir);
1366
- const latestLink = path9.join(skillDir, "latest");
1380
+ const skillDir = path11.join(skillsDir, skillId);
1381
+ await fs12.ensureDir(skillDir);
1382
+ const latestLink = path11.join(skillDir, "latest");
1367
1383
  try {
1368
- await fs10.remove(latestLink);
1369
- await fs10.symlink(skillVersionDir, latestLink, "junction");
1384
+ await fs12.remove(latestLink);
1385
+ await fs12.symlink(skillVersionDir, latestLink, "junction");
1370
1386
  } catch {
1371
- await fs10.copy(skillVersionDir, path9.join(skillDir, "latest"), { overwrite: true });
1387
+ await fs12.copy(skillVersionDir, path11.join(skillDir, "latest"), { overwrite: true });
1372
1388
  }
1373
1389
  console.log(`
1374
1390
  Installing to ${targetPlatforms.length} platform(s)...
@@ -1401,9 +1417,6 @@ Installing to ${targetPlatforms.length} platform(s)...
1401
1417
  const failed = results.filter((r) => r.status === "failed").length;
1402
1418
  console.log(`
1403
1419
  \u{1F4CA} Summary: ${installed} installed, ${skipped} skipped, ${failed} failed`);
1404
- console.log(`
1405
- Installing to platforms: ${targetPlatforms.join(", ")}`);
1406
- console.log(" (Platform installation logic needs to be completed)");
1407
1420
  const registry = await loadRegistry();
1408
1421
  registry.skills[skillId] = {
1409
1422
  id: skillId,
@@ -1419,15 +1432,15 @@ Installing to platforms: ${targetPlatforms.join(", ")}`);
1419
1432
 
1420
1433
  // src/commands/publish.ts
1421
1434
  import { execSync } from "child_process";
1422
- import { existsSync as existsSync4 } from "fs";
1423
- import { join as join4 } from "path";
1435
+ import { existsSync as existsSync2 } from "fs";
1436
+ import { join as join2 } from "path";
1424
1437
  import { fileURLToPath } from "url";
1425
1438
  async function publishSkill(skillName, options) {
1426
1439
  const __dirname4 = fileURLToPath(new URL(".", import.meta.url));
1427
- const projectRoot = join4(__dirname4, "..", "..");
1428
- const skillDir = join4(projectRoot, "skills", skillName);
1440
+ const projectRoot = join2(__dirname4, "..", "..");
1441
+ const skillDir = join2(projectRoot, "skills", skillName);
1429
1442
  console.log(`Publishing ${skillName}...`);
1430
- if (!existsSync4(skillDir)) {
1443
+ if (!existsSync2(skillDir)) {
1431
1444
  throw new Error(`Skill '${skillName}' not found in skills/ directory`);
1432
1445
  }
1433
1446
  if (!options?.skipInstall) {
@@ -1467,29 +1480,29 @@ async function publishSkill(skillName, options) {
1467
1480
  }
1468
1481
 
1469
1482
  // src/commands/verify.ts
1470
- import fs11 from "fs-extra";
1471
- import path10 from "path";
1483
+ import fs13 from "fs-extra";
1484
+ import path12 from "path";
1472
1485
  import { fileURLToPath as fileURLToPath2 } from "url";
1473
1486
  var __filename = fileURLToPath2(import.meta.url);
1474
- var __dirname = path10.dirname(__filename);
1487
+ var __dirname = path12.dirname(__filename);
1475
1488
  async function verifySkill(skillName) {
1476
1489
  try {
1477
1490
  console.log(`
1478
1491
  \u{1F50D} Verifying skill: ${skillName}
1479
1492
  `);
1480
- const skillDir = path10.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "skills", skillName);
1481
- if (!await fs11.pathExists(skillDir)) {
1493
+ const skillDir = path12.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "skills", skillName);
1494
+ if (!await fs13.pathExists(skillDir)) {
1482
1495
  console.error(`\u274C Skill "${skillName}" not found locally.`);
1483
1496
  console.log(` Try: skm install ${skillName}`);
1484
1497
  process.exit(1);
1485
1498
  }
1486
1499
  let passed = 0;
1487
1500
  let failed = 0;
1488
- const skillMdPath = path10.join(skillDir, "SKILL.md");
1489
- if (await fs11.pathExists(skillMdPath)) {
1501
+ const skillMdPath = path12.join(skillDir, "SKILL.md");
1502
+ if (await fs13.pathExists(skillMdPath)) {
1490
1503
  console.log(`\u2705 SKILL.md exists`);
1491
1504
  passed++;
1492
- const content = await fs11.readFile(skillMdPath, "utf-8");
1505
+ const content = await fs13.readFile(skillMdPath, "utf-8");
1493
1506
  if (content.trim().length > 0) {
1494
1507
  console.log(`\u2705 SKILL.md is not empty (${content.length} chars)`);
1495
1508
  passed++;
@@ -1501,12 +1514,12 @@ async function verifySkill(skillName) {
1501
1514
  console.log(`\u274C SKILL.md not found`);
1502
1515
  failed++;
1503
1516
  }
1504
- const pkgPath = path10.join(skillDir, "package.json");
1505
- if (await fs11.pathExists(pkgPath)) {
1517
+ const pkgPath = path12.join(skillDir, "package.json");
1518
+ if (await fs13.pathExists(pkgPath)) {
1506
1519
  console.log(`\u2705 package.json exists`);
1507
1520
  passed++;
1508
1521
  try {
1509
- const pkg = await fs11.readJson(pkgPath);
1522
+ const pkg = await fs13.readJson(pkgPath);
1510
1523
  const requiredFields = ["name", "version", "description"];
1511
1524
  for (const field of requiredFields) {
1512
1525
  if (pkg[field]) {
@@ -1524,12 +1537,13 @@ async function verifySkill(skillName) {
1524
1537
  } else {
1525
1538
  console.log(`\u26A0\uFE0F package.json not found (optional for basic skills)`);
1526
1539
  }
1527
- const registryPath = path10.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "registry.json");
1528
- if (await fs11.pathExists(registryPath)) {
1540
+ const registryPath = path12.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "registry.json");
1541
+ if (await fs13.pathExists(registryPath)) {
1529
1542
  try {
1530
- const registry = await fs11.readJson(registryPath);
1531
- if (registry[skillName]) {
1532
- console.log(`\u2705 Skill registered in registry (v${registry[skillName].version})`);
1543
+ const registry = await fs13.readJson(registryPath);
1544
+ const registered = registry.skills?.[skillName];
1545
+ if (registered) {
1546
+ console.log(`\u2705 Skill registered in registry (v${registered.version})`);
1533
1547
  passed++;
1534
1548
  } else {
1535
1549
  console.log(`\u26A0\uFE0F Skill not found in registry`);
@@ -1561,9 +1575,10 @@ async function verifySkill(skillName) {
1561
1575
 
1562
1576
  // src/commands/ui.ts
1563
1577
  import { createServer } from "http";
1564
- import { readFileSync as readFileSync2, existsSync as existsSync5 } from "fs";
1565
- import { join as join5, extname, dirname } from "path";
1578
+ import { readFileSync as readFileSync2, existsSync as existsSync3, mkdirSync, rmSync } from "fs";
1579
+ import { join as join3, extname, dirname, basename } from "path";
1566
1580
  import { fileURLToPath as fileURLToPath3 } from "url";
1581
+ import AdmZip from "adm-zip";
1567
1582
 
1568
1583
  // src/commands/admin.ts
1569
1584
  import { execSync as execSync2 } from "child_process";
@@ -2029,9 +2044,9 @@ async function adminAccess(skillId, level) {
2029
2044
  // src/commands/ui.ts
2030
2045
  var __filename2 = fileURLToPath3(import.meta.url);
2031
2046
  var __dirname2 = dirname(__filename2);
2032
- var guiDir = join5(__dirname2, "..", "gui");
2047
+ var guiDir = join3(__dirname2, "..", "gui");
2033
2048
  var cache = /* @__PURE__ */ new Map();
2034
- function getCached(key) {
2049
+ function getCached2(key) {
2035
2050
  const entry = cache.get(key);
2036
2051
  if (!entry) return null;
2037
2052
  if (Date.now() > entry.expiry) {
@@ -2040,7 +2055,7 @@ function getCached(key) {
2040
2055
  }
2041
2056
  return entry.data;
2042
2057
  }
2043
- function setCache(key, data, ttlMs = 6e4) {
2058
+ function setCache2(key, data, ttlMs = 6e4) {
2044
2059
  cache.set(key, { data, expiry: Date.now() + ttlMs });
2045
2060
  }
2046
2061
  async function throttledMap(items, fn, concurrency = 3) {
@@ -2100,7 +2115,7 @@ API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
2100
2115
  const sort = url.searchParams.get("sort") || "name";
2101
2116
  const platform = url.searchParams.get("platform") || "";
2102
2117
  const cacheKey = `search:${search}:limit:${limit}`;
2103
- let searchResult = getCached(cacheKey);
2118
+ let searchResult = getCached2(cacheKey);
2104
2119
  if (!searchResult) {
2105
2120
  searchResult = await searchSkillmarketPackages({
2106
2121
  from: 0,
@@ -2108,17 +2123,17 @@ API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
2108
2123
  // 一次拉取更多,避免分页
2109
2124
  keyword: search || void 0
2110
2125
  });
2111
- setCache(cacheKey, searchResult, 3e4);
2126
+ setCache2(cacheKey, searchResult, 3e4);
2112
2127
  }
2113
2128
  const { packages, total } = searchResult;
2114
2129
  let fetchErrors = 0;
2115
2130
  const skillDetails = await throttledMap(packages, async (pkgName) => {
2116
2131
  try {
2117
2132
  const pkgCacheKey = `pkg:${pkgName}`;
2118
- let info = getCached(pkgCacheKey);
2133
+ let info = getCached2(pkgCacheKey);
2119
2134
  if (!info) {
2120
2135
  info = await fetchNpmPackage(pkgName);
2121
- if (info) setCache(pkgCacheKey, info, 3e4);
2136
+ if (info) setCache2(pkgCacheKey, info, 3e4);
2122
2137
  }
2123
2138
  if (!info) {
2124
2139
  fetchErrors++;
@@ -2252,10 +2267,10 @@ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
2252
2267
  return;
2253
2268
  }
2254
2269
  const cacheKey = `skill-info:${skillName}`;
2255
- let info = getCached(cacheKey);
2270
+ let info = getCached2(cacheKey);
2256
2271
  if (!info) {
2257
2272
  info = await fetchSkillPackage(skillName);
2258
- if (info) setCache(cacheKey, info, 3e4);
2273
+ if (info) setCache2(cacheKey, info, 3e4);
2259
2274
  }
2260
2275
  if (!info) {
2261
2276
  jsonResponse(res, 404, { error: `Skill "${skillName}" not found` });
@@ -2286,7 +2301,7 @@ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
2286
2301
  };
2287
2302
  API_ROUTES.GET["/api/version"] = async (_req, res, _url) => {
2288
2303
  try {
2289
- const pkgPath = join5(__dirname2, "..", "package.json");
2304
+ const pkgPath = join3(__dirname2, "..", "package.json");
2290
2305
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
2291
2306
  jsonResponse(res, 200, { version: pkg.version || "1.0.0" });
2292
2307
  } catch {
@@ -2523,8 +2538,119 @@ API_ROUTES.POST["/api/update"] = async (req, res, _url) => {
2523
2538
  jsonResponse(res, 500, { error: String(err) });
2524
2539
  }
2525
2540
  };
2541
+ var PROJECT_ROOT = join3(__dirname2, "..");
2542
+ API_ROUTES.POST["/api/upload"] = async (req, res, _url) => {
2543
+ try {
2544
+ const body = await parseBody(req);
2545
+ const fileData = String(body.fileData || "");
2546
+ const fileName = String(body.fileName || "upload.zip");
2547
+ const skillNameOverride = body.skillNameOverride ? String(body.skillNameOverride).trim() : "";
2548
+ if (!fileData) {
2549
+ jsonResponse(res, 400, { error: "Missing fileData" });
2550
+ return;
2551
+ }
2552
+ const buffer = Buffer.from(fileData, "base64");
2553
+ if (buffer.length === 0) {
2554
+ jsonResponse(res, 400, { error: "Empty file data" });
2555
+ return;
2556
+ }
2557
+ const zip = new AdmZip(buffer);
2558
+ const entries = zip.getEntries();
2559
+ if (entries.length === 0) {
2560
+ jsonResponse(res, 400, { error: "ZIP archive is empty" });
2561
+ return;
2562
+ }
2563
+ const pkgEntry = entries.find((e) => e.entryName === "package.json" || e.entryName.endsWith("/package.json"));
2564
+ let skillName = "";
2565
+ let pkgInfo = {};
2566
+ if (pkgEntry) {
2567
+ try {
2568
+ pkgInfo = JSON.parse(pkgEntry.getData().toString("utf-8"));
2569
+ skillName = pkgInfo.skillmarket?.id || pkgInfo.name?.replace(/^@[^/]+\//, "") || "";
2570
+ } catch {
2571
+ }
2572
+ }
2573
+ if (skillNameOverride) {
2574
+ skillName = skillNameOverride;
2575
+ }
2576
+ if (!skillName) {
2577
+ const rootDirs = [...new Set(entries.map((e) => e.entryName.split("/")[0]))].filter(Boolean);
2578
+ skillName = rootDirs.length === 1 ? rootDirs[0] : basename(fileName, ".zip");
2579
+ }
2580
+ skillName = skillName.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
2581
+ if (!skillName) skillName = "untitled-skill";
2582
+ const skillDir = join3(PROJECT_ROOT, "skills", skillName);
2583
+ if (existsSync3(skillDir)) {
2584
+ rmSync(skillDir, { recursive: true, force: true });
2585
+ }
2586
+ mkdirSync(skillDir, { recursive: true });
2587
+ zip.extractAllTo(skillDir, true);
2588
+ const skillMdExists = existsSync3(join3(skillDir, "SKILL.md")) || entries.some((e) => e.entryName.endsWith("SKILL.md"));
2589
+ const pkgJsonPath = join3(skillDir, "package.json");
2590
+ if (existsSync3(pkgJsonPath)) {
2591
+ try {
2592
+ pkgInfo = JSON.parse(readFileSync2(pkgJsonPath, "utf-8"));
2593
+ } catch {
2594
+ }
2595
+ }
2596
+ const meta = pkgInfo?.skillmarket || {};
2597
+ const result = {
2598
+ skillName,
2599
+ displayName: meta.displayName || pkgInfo.displayName || skillName,
2600
+ version: pkgInfo.version || "0.0.0",
2601
+ description: pkgInfo.description || meta.description || "",
2602
+ platforms: meta.platforms || [],
2603
+ hasPackageJson: existsSync3(pkgJsonPath),
2604
+ hasSkillMd: skillMdExists,
2605
+ fileCount: entries.length
2606
+ };
2607
+ jsonResponse(res, 200, result);
2608
+ } catch (err) {
2609
+ jsonResponse(res, 500, { error: String(err) });
2610
+ }
2611
+ };
2612
+ API_ROUTES.POST["/api/upload/action"] = async (req, res, _url) => {
2613
+ try {
2614
+ const body = await parseBody(req);
2615
+ const skillName = String(body.skillName || "");
2616
+ const action = String(body.action || "");
2617
+ if (!skillName) {
2618
+ jsonResponse(res, 400, { error: "Missing skillName" });
2619
+ return;
2620
+ }
2621
+ if (!["publish", "install", "both"].includes(action)) {
2622
+ jsonResponse(res, 400, { error: 'action must be "publish", "install", or "both"' });
2623
+ return;
2624
+ }
2625
+ const skillDir = join3(PROJECT_ROOT, "skills", skillName);
2626
+ if (!existsSync3(skillDir)) {
2627
+ jsonResponse(res, 404, { error: `Skill "${skillName}" not found in skills/ directory. Upload first.` });
2628
+ return;
2629
+ }
2630
+ const results = {};
2631
+ if (action === "publish" || action === "both") {
2632
+ try {
2633
+ await publishSkill(skillName);
2634
+ results.publish = { success: true, message: `${skillName} published to npm` };
2635
+ } catch (err) {
2636
+ results.publish = { success: false, message: String(err) };
2637
+ }
2638
+ }
2639
+ if (action === "install" || action === "both") {
2640
+ try {
2641
+ await installSkill(skillName, void 0, { force: true });
2642
+ results.install = { success: true, message: `${skillName} installed locally` };
2643
+ } catch (err) {
2644
+ results.install = { success: false, message: String(err) };
2645
+ }
2646
+ }
2647
+ jsonResponse(res, 200, { success: true, skillName, action, results });
2648
+ } catch (err) {
2649
+ jsonResponse(res, 500, { error: String(err) });
2650
+ }
2651
+ };
2526
2652
  function serveStaticFile(res, filePath) {
2527
- if (!existsSync5(filePath)) {
2653
+ if (!existsSync3(filePath)) {
2528
2654
  res.writeHead(404, { "Content-Type": "text/plain" });
2529
2655
  res.end("Not Found");
2530
2656
  return;
@@ -2557,7 +2683,7 @@ async function handleRequest(req, res) {
2557
2683
  jsonResponse(res, 404, { error: `Unknown API endpoint: ${method} ${pathname}` });
2558
2684
  return;
2559
2685
  }
2560
- const filePath = join5(guiDir, pathname === "/" ? "index.html" : pathname);
2686
+ const filePath = join3(guiDir, pathname === "/" ? "index.html" : pathname);
2561
2687
  if (filePath.startsWith(guiDir)) {
2562
2688
  serveStaticFile(res, filePath);
2563
2689
  } else {
@@ -2586,9 +2712,9 @@ Press Ctrl+C to stop
2586
2712
  }
2587
2713
 
2588
2714
  // src/commands/config.ts
2589
- import path11 from "path";
2590
- import fs12 from "fs-extra";
2591
- import os6 from "os";
2715
+ import path13 from "path";
2716
+ import fs14 from "fs-extra";
2717
+ import os8 from "os";
2592
2718
  var CONFIG_DEFINITIONS = [
2593
2719
  {
2594
2720
  key: "npmScope",
@@ -2622,13 +2748,13 @@ var CONFIG_DEFINITIONS = [
2622
2748
  }
2623
2749
  ];
2624
2750
  function getConfigPath() {
2625
- return path11.join(os6.homedir(), ".skillmarket", "config.json");
2751
+ return path13.join(os8.homedir(), ".skillmarket", "config.json");
2626
2752
  }
2627
2753
  async function readConfigFile() {
2628
2754
  try {
2629
2755
  const configPath = getConfigPath();
2630
- if (await fs12.pathExists(configPath)) {
2631
- const data = await fs12.readJson(configPath);
2756
+ if (await fs14.pathExists(configPath)) {
2757
+ const data = await fs14.readJson(configPath);
2632
2758
  const valid = {};
2633
2759
  for (const def of CONFIG_DEFINITIONS) {
2634
2760
  if (data[def.key] !== void 0) {
@@ -2643,11 +2769,11 @@ async function readConfigFile() {
2643
2769
  }
2644
2770
  async function writeConfigFile(updates) {
2645
2771
  const configPath = getConfigPath();
2646
- await fs12.ensureDir(path11.dirname(configPath));
2772
+ await fs14.ensureDir(path13.dirname(configPath));
2647
2773
  let existing = {};
2648
2774
  try {
2649
- if (await fs12.pathExists(configPath)) {
2650
- existing = await fs12.readJson(configPath);
2775
+ if (await fs14.pathExists(configPath)) {
2776
+ existing = await fs14.readJson(configPath);
2651
2777
  }
2652
2778
  } catch {
2653
2779
  }
@@ -2657,25 +2783,25 @@ async function writeConfigFile(updates) {
2657
2783
  delete merged[key];
2658
2784
  }
2659
2785
  }
2660
- await fs12.writeJson(configPath, merged, { spaces: 2 });
2786
+ await fs14.writeJson(configPath, merged, { spaces: 2 });
2661
2787
  return merged;
2662
2788
  }
2663
2789
  async function removeConfigKeys(keys) {
2664
2790
  const configPath = getConfigPath();
2665
- if (!await fs12.pathExists(configPath)) return;
2791
+ if (!await fs14.pathExists(configPath)) return;
2666
2792
  try {
2667
- const existing = await fs12.readJson(configPath);
2793
+ const existing = await fs14.readJson(configPath);
2668
2794
  for (const key of keys) {
2669
2795
  delete existing[key];
2670
2796
  }
2671
- await fs12.writeJson(configPath, existing, { spaces: 2 });
2797
+ await fs14.writeJson(configPath, existing, { spaces: 2 });
2672
2798
  } catch {
2673
2799
  }
2674
2800
  }
2675
2801
  async function removeConfigFile() {
2676
2802
  const configPath = getConfigPath();
2677
- if (await fs12.pathExists(configPath)) {
2678
- await fs12.remove(configPath);
2803
+ if (await fs14.pathExists(configPath)) {
2804
+ await fs14.remove(configPath);
2679
2805
  }
2680
2806
  }
2681
2807
  async function getAllConfig() {