itismyskillmarket 1.3.29 → 1.3.31

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
@@ -476,6 +476,7 @@ import fs9 from "fs-extra";
476
476
  import path8 from "path";
477
477
  import { exec } from "child_process";
478
478
  import { promisify } from "util";
479
+ import * as tar from "tar";
479
480
 
480
481
  // src/adapters/base.ts
481
482
  import fs3 from "fs-extra";
@@ -780,17 +781,18 @@ async function installSkill(skillId, version, options) {
780
781
  console.log("Downloading package...");
781
782
  await fs9.ensureDir(cacheDir);
782
783
  try {
783
- await execAsync(`npm pack ${packageName}@${targetVersion} --pack-destination ${cacheDir}`);
784
- const files = await fs9.readdir(cacheDir);
785
- const tarball = files.find(
786
- (f) => f.endsWith(".tgz") && f.includes(packageName.replace(/^@/, "").replace("/", "-"))
784
+ const { stdout } = await execAsync(
785
+ `npm pack ${packageName}@${targetVersion} --pack-destination "${cacheDir}"`
787
786
  );
788
- if (tarball) {
789
- await execAsync(`tar -xzf "${path8.join(cacheDir, tarball)}" -C "${cacheDir}"`);
790
- await fs9.remove(path8.join(cacheDir, tarball));
791
- const extractedDir = path8.join(cacheDir, "package");
792
- const finalDir = targetDir;
793
- await fs9.move(extractedDir, finalDir, { overwrite: true });
787
+ const tarballName = stdout.trim();
788
+ const tarballPath = path8.join(cacheDir, tarballName);
789
+ if (await fs9.pathExists(tarballPath)) {
790
+ await tar.extract({
791
+ file: tarballPath,
792
+ cwd: cacheDir
793
+ });
794
+ await fs9.remove(tarballPath);
795
+ await fs9.move(path8.join(cacheDir, "package"), targetDir, { overwrite: true });
794
796
  }
795
797
  } catch (err) {
796
798
  throw new Error(`Failed to download package: ${err}`);
@@ -953,28 +955,63 @@ async function updateSkill(skillId) {
953
955
  }
954
956
  console.log(`Checking updates for ${installed.length} skill(s)...
955
957
  `);
956
- let hasUpdates = false;
957
- for (const skill of installed) {
958
- const pkgInfo = await fetchSkillPackage(skill.id);
959
- if (pkgInfo) {
960
- const latestVersion = pkgInfo["dist-tags"]?.latest;
961
- if (latestVersion && latestVersion !== skill.version) {
962
- console.log(` ${skill.id}: ${skill.version} \u2192 ${latestVersion} [UPDATE]`);
963
- hasUpdates = true;
958
+ const checkResults = await Promise.allSettled(
959
+ installed.map(async (skill) => {
960
+ const pkgInfo = await fetchSkillPackage(skill.id);
961
+ if (!pkgInfo) {
962
+ return { skill, latestVersion: null, error: "failed to fetch remote" };
963
+ }
964
+ const latestVersion = pkgInfo["dist-tags"]?.latest || null;
965
+ return { skill, latestVersion, error: null };
966
+ })
967
+ );
968
+ const toUpdate = [];
969
+ let upToDate = 0;
970
+ let fetchFailed = 0;
971
+ for (const result of checkResults) {
972
+ if (result.status === "rejected") {
973
+ fetchFailed++;
974
+ continue;
975
+ }
976
+ const { skill, latestVersion, error } = result.value;
977
+ if (error) {
978
+ console.log(` ${skill.id}: ${skill.version} (${error})`);
979
+ fetchFailed++;
980
+ } else if (latestVersion && latestVersion !== skill.version) {
981
+ console.log(` ${skill.id}: ${skill.version} \u2192 ${latestVersion} [UPDATE]`);
982
+ toUpdate.push({ skill, latestVersion });
983
+ } else {
984
+ console.log(` ${skill.id}: ${skill.version} (up to date)`);
985
+ upToDate++;
986
+ }
987
+ }
988
+ if (toUpdate.length > 0) {
989
+ console.log(`
990
+ Updating ${toUpdate.length} skill(s)...
991
+ `);
992
+ const updateResults = await Promise.allSettled(
993
+ toUpdate.map(async ({ skill, latestVersion }) => {
964
994
  try {
965
995
  await installSkill(skill.id, latestVersion);
996
+ return { id: skill.id, success: true };
966
997
  } catch (err) {
967
- console.error(` Failed to update ${skill.id}:`, err);
998
+ return { id: skill.id, success: false, error: err };
968
999
  }
969
- } else {
970
- console.log(` ${skill.id}: ${skill.version} (up to date)`);
1000
+ })
1001
+ );
1002
+ for (const result of updateResults) {
1003
+ if (result.status === "fulfilled" && result.value.success) {
1004
+ console.log(` \u2705 ${result.value.id} updated`);
1005
+ } else if (result.status === "fulfilled" && !result.value.success) {
1006
+ console.error(` \u274C Failed to update ${result.value.id}:`, result.value.error);
971
1007
  }
972
- } else {
973
- console.log(` ${skill.id}: ${skill.version} (failed to fetch remote)`);
974
1008
  }
975
1009
  }
976
- if (!hasUpdates) {
1010
+ if (toUpdate.length === 0) {
977
1011
  console.log("\nAll skills are up to date!");
1012
+ } else {
1013
+ console.log(`
1014
+ \u{1F4CA} Update summary: ${toUpdate.length} updated, ${upToDate} up-to-date, ${fetchFailed} failed`);
978
1015
  }
979
1016
  }
980
1017
 
@@ -1172,11 +1209,11 @@ Uninstalling all skills...
1172
1209
  import fs12 from "fs-extra";
1173
1210
  import path11 from "path";
1174
1211
  var GITHUB_URL_PATTERNS = [
1175
- /^https?:\/\/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)(?:\/(.+))?)?$/,
1176
- /^([^/]+)\/([^/]+)(?:#(.+))?$/,
1212
+ /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\/tree\/([^/]+)(?:\/(.+))?)?$/,
1213
+ /^([^/]+)\/([^/@]+)@(.+)$/,
1214
+ // owner/repo@commit (must come before # pattern)
1215
+ /^([^/]+)\/([^/#]+)(?:#(.+))?$/
1177
1216
  // owner/repo#branch
1178
- /^([^/]+)\/([^/]+)@(.+)$/
1179
- // owner/repo@commit
1180
1217
  ];
1181
1218
  function parseGitHubUrl(input) {
1182
1219
  input = input.replace(/\/$/, "");
@@ -1187,7 +1224,7 @@ function parseGitHubUrl(input) {
1187
1224
  const repo = match[2].replace(/\.git$/, "");
1188
1225
  const branch = match[3] || "main";
1189
1226
  const commitOrPath = match[4] || match[3];
1190
- const path14 = match[5] || void 0;
1227
+ const path14 = match[4] || void 0;
1191
1228
  return {
1192
1229
  owner,
1193
1230
  repo,
@@ -1432,13 +1469,15 @@ Installing to ${targetPlatforms.length} platform(s)...
1432
1469
  }
1433
1470
 
1434
1471
  // src/commands/publish.ts
1435
- import { execSync } from "child_process";
1472
+ import { exec as exec2 } from "child_process";
1436
1473
  import { existsSync as existsSync2 } from "fs";
1437
1474
  import { join as join2 } from "path";
1438
1475
  import { fileURLToPath } from "url";
1476
+ import { promisify as promisify2 } from "util";
1477
+ var execAsync2 = promisify2(exec2);
1439
1478
  async function publishSkill(skillName, options) {
1440
1479
  const __dirname4 = fileURLToPath(new URL(".", import.meta.url));
1441
- const projectRoot = join2(__dirname4, "..", "..");
1480
+ const projectRoot = join2(__dirname4, "..");
1442
1481
  const skillDir = join2(projectRoot, "skills", skillName);
1443
1482
  console.log(`Publishing ${skillName}...`);
1444
1483
  if (!existsSync2(skillDir)) {
@@ -1447,10 +1486,7 @@ async function publishSkill(skillName, options) {
1447
1486
  if (!options?.skipInstall) {
1448
1487
  console.log("Running npm install...");
1449
1488
  try {
1450
- execSync("npm install", {
1451
- cwd: skillDir,
1452
- stdio: "inherit"
1453
- });
1489
+ await execAsync2("npm install", { cwd: skillDir });
1454
1490
  } catch (err) {
1455
1491
  console.warn("Warning: npm install failed, continuing anyway...");
1456
1492
  }
@@ -1458,9 +1494,8 @@ async function publishSkill(skillName, options) {
1458
1494
  if (options?.version) {
1459
1495
  console.log(`Updating version to ${options.version}...`);
1460
1496
  try {
1461
- execSync(`npm version ${options.version} --no-git-tag-version`, {
1462
- cwd: skillDir,
1463
- stdio: "inherit"
1497
+ await execAsync2(`npm version ${options.version} --no-git-tag-version`, {
1498
+ cwd: skillDir
1464
1499
  });
1465
1500
  } catch (err) {
1466
1501
  throw new Error(`Failed to update version: ${err}`);
@@ -1468,10 +1503,7 @@ async function publishSkill(skillName, options) {
1468
1503
  }
1469
1504
  console.log("Publishing to npm...");
1470
1505
  try {
1471
- execSync("npm publish --access=public", {
1472
- cwd: skillDir,
1473
- stdio: "inherit"
1474
- });
1506
+ await execAsync2("npm publish --access=public", { cwd: skillDir });
1475
1507
  } catch (err) {
1476
1508
  throw new Error(`Failed to publish: ${err}`);
1477
1509
  }
@@ -1931,8 +1963,15 @@ function npmExec(command) {
1931
1963
  try {
1932
1964
  return execSync2(command, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).trim();
1933
1965
  } catch (err) {
1934
- const msg = err.stderr?.toString() || err.message || "Unknown error";
1935
- throw new Error(`npm command failed: ${msg.trim()}`);
1966
+ if (err && typeof err === "object" && "stderr" in err) {
1967
+ const stderr = err.stderr;
1968
+ const msg = Buffer.isBuffer(stderr) ? stderr.toString() : stderr;
1969
+ throw new Error(`npm command failed: ${msg.trim()}`);
1970
+ }
1971
+ if (err instanceof Error) {
1972
+ throw new Error(`npm command failed: ${err.message}`);
1973
+ }
1974
+ throw new Error("npm command failed with an unknown error");
1936
1975
  }
1937
1976
  }
1938
1977
  async function adminDeprecate(skillId, options = {}) {
package/gui/app.js CHANGED
@@ -601,6 +601,31 @@ function applyI18nToStaticElements() {
601
601
  if (refreshAdmin) refreshAdmin.innerHTML = `🔄 ${t('btn.refresh')}`;
602
602
  if (updateAll) updateAll.innerHTML = `🔄 ${t('btn.updateAll')}`;
603
603
  if (backBtn) backBtn.innerHTML = `← ${t('nav.back')}`;
604
+
605
+ // Upload 视图静态文本
606
+ const uploadDropzoneText = document.getElementById('upload-dropzone-text');
607
+ const uploadDropzoneHint = document.getElementById('upload-dropzone-hint');
608
+ const uploadSelectBtn = document.getElementById('upload-select-btn');
609
+ const uploadSkillNameLabel = document.getElementById('upload-skill-name-label');
610
+ const uploadSkillNameInput = document.getElementById('upload-skill-name');
611
+ const uploadSubmitBtn = document.getElementById('upload-submit-btn');
612
+ const uploadActionPublish = document.getElementById('upload-action-publish');
613
+ const uploadActionInstall = document.getElementById('upload-action-install');
614
+ const uploadActionBoth = document.getElementById('upload-action-both');
615
+ const uploadActionDiscard = document.getElementById('upload-action-discard');
616
+ const uploadProgressText = document.getElementById('upload-progress-text');
617
+
618
+ if (uploadDropzoneText) uploadDropzoneText.textContent = t('upload.dropzoneText');
619
+ if (uploadDropzoneHint) uploadDropzoneHint.textContent = t('upload.dropzoneHint');
620
+ if (uploadSelectBtn) uploadSelectBtn.textContent = t('upload.chooseFile');
621
+ if (uploadSkillNameLabel) uploadSkillNameLabel.textContent = t('upload.skillNameLabel');
622
+ if (uploadSkillNameInput) uploadSkillNameInput.placeholder = t('upload.skillNamePlaceholder');
623
+ if (uploadSubmitBtn) uploadSubmitBtn.innerHTML = t('upload.uploadParse');
624
+ if (uploadActionPublish) uploadActionPublish.innerHTML = t('upload.actionPublish');
625
+ if (uploadActionInstall) uploadActionInstall.innerHTML = t('upload.actionInstall');
626
+ if (uploadActionBoth) uploadActionBoth.innerHTML = t('upload.actionBoth');
627
+ if (uploadActionDiscard) uploadActionDiscard.innerHTML = t('upload.actionDiscard');
628
+ if (uploadProgressText) uploadProgressText.textContent = t('upload.processing');
604
629
  }
605
630
 
606
631
  // -----------------------------------------------------------------------------
package/gui/index.html CHANGED
@@ -104,13 +104,13 @@
104
104
  <div id="upload-phase1" class="upload-phase">
105
105
  <div class="upload-dropzone" id="upload-dropzone">
106
106
  <div class="upload-dropzone-icon">📦</div>
107
- <p class="upload-dropzone-text">Drop a skill .zip file here, or click to select</p>
108
- <p class="upload-dropzone-hint">The zip should contain SKILL.md and optionally package.json</p>
107
+ <p class="upload-dropzone-text" id="upload-dropzone-text">Drop a skill .zip file here, or click to select</p>
108
+ <p class="upload-dropzone-hint" id="upload-dropzone-hint">The zip should contain SKILL.md and optionally package.json</p>
109
109
  <input type="file" id="upload-file-input" accept=".zip" style="display:none">
110
110
  <button id="upload-select-btn" class="btn btn-primary" style="margin-top:12px;">Choose File</button>
111
111
  </div>
112
112
  <div class="upload-skill-name-input">
113
- <label for="upload-skill-name">Skill Name</label>
113
+ <label for="upload-skill-name" id="upload-skill-name-label">Skill Name</label>
114
114
  <input type="text" id="upload-skill-name" placeholder="Auto-detected from zip, or override here">
115
115
  </div>
116
116
  <button id="upload-submit-btn" class="btn btn-success" disabled style="align-self:center;margin-top:8px;">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itismyskillmarket",
3
- "version": "1.3.29",
3
+ "version": "1.3.31",
4
4
  "description": "Cross-platform skill manager for AI coding tools",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,7 +15,8 @@
15
15
  "dependencies": {
16
16
  "adm-zip": "^0.5.17",
17
17
  "commander": "^12.0.0",
18
- "fs-extra": "^11.2.0"
18
+ "fs-extra": "^11.2.0",
19
+ "tar": "^7.5.15"
19
20
  },
20
21
  "devDependencies": {
21
22
  "@types/fs-extra": "^11.0.4",