itismyskillmarket 1.3.30 → 1.3.32
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 +91 -40
- package/gui/app.js +13 -5
- package/package.json +3 -2
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
|
-
|
|
784
|
-
|
|
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
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
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
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
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
|
-
|
|
998
|
+
return { id: skill.id, success: false, error: err };
|
|
968
999
|
}
|
|
969
|
-
}
|
|
970
|
-
|
|
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 (
|
|
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
|
|
|
@@ -1432,10 +1469,12 @@ Installing to ${targetPlatforms.length} platform(s)...
|
|
|
1432
1469
|
}
|
|
1433
1470
|
|
|
1434
1471
|
// src/commands/publish.ts
|
|
1435
|
-
import {
|
|
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
1480
|
const projectRoot = join2(__dirname4, "..");
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1935
|
-
|
|
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 = {}) {
|
|
@@ -2561,11 +2600,17 @@ API_ROUTES.POST["/api/upload"] = async (req, res, _url) => {
|
|
|
2561
2600
|
jsonResponse(res, 400, { error: "ZIP archive is empty" });
|
|
2562
2601
|
return;
|
|
2563
2602
|
}
|
|
2564
|
-
const
|
|
2603
|
+
const normalizeEntryName = (name) => name.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
2604
|
+
const pkgEntry = entries.find((e) => {
|
|
2605
|
+
const normalized = normalizeEntryName(e.entryName);
|
|
2606
|
+
return normalized === "package.json" || normalized.endsWith("/package.json");
|
|
2607
|
+
});
|
|
2565
2608
|
let skillName = "";
|
|
2566
2609
|
let pkgInfo = {};
|
|
2610
|
+
let pkgEntryRelativePath = "";
|
|
2567
2611
|
if (pkgEntry) {
|
|
2568
2612
|
try {
|
|
2613
|
+
pkgEntryRelativePath = normalizeEntryName(pkgEntry.entryName);
|
|
2569
2614
|
pkgInfo = JSON.parse(pkgEntry.getData().toString("utf-8"));
|
|
2570
2615
|
skillName = pkgInfo.skillmarket?.id || pkgInfo.name?.replace(/^@[^/]+\//, "") || "";
|
|
2571
2616
|
} catch {
|
|
@@ -2587,7 +2632,13 @@ API_ROUTES.POST["/api/upload"] = async (req, res, _url) => {
|
|
|
2587
2632
|
mkdirSync(skillDir, { recursive: true });
|
|
2588
2633
|
zip.extractAllTo(skillDir, true);
|
|
2589
2634
|
const skillMdExists = existsSync3(join3(skillDir, "SKILL.md")) || entries.some((e) => e.entryName.endsWith("SKILL.md"));
|
|
2590
|
-
|
|
2635
|
+
let pkgJsonPath = join3(skillDir, "package.json");
|
|
2636
|
+
if (pkgEntryRelativePath) {
|
|
2637
|
+
const extractedPkgPath = join3(skillDir, pkgEntryRelativePath);
|
|
2638
|
+
if (existsSync3(extractedPkgPath)) {
|
|
2639
|
+
pkgJsonPath = extractedPkgPath;
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2591
2642
|
if (existsSync3(pkgJsonPath)) {
|
|
2592
2643
|
try {
|
|
2593
2644
|
pkgInfo = JSON.parse(readFileSync2(pkgJsonPath, "utf-8"));
|
package/gui/app.js
CHANGED
|
@@ -220,6 +220,10 @@ const translations = {
|
|
|
220
220
|
'upload.id': 'ID',
|
|
221
221
|
'upload.version': 'Version',
|
|
222
222
|
'upload.description': 'Description',
|
|
223
|
+
'upload.validation': 'Validation',
|
|
224
|
+
'upload.stats': 'Stats',
|
|
225
|
+
'upload.done': '✅ Done',
|
|
226
|
+
'upload.noSkillUploaded': 'No skill uploaded. Please upload first.',
|
|
223
227
|
'upload.platforms': 'Platforms',
|
|
224
228
|
'upload.fileCount': 'Files',
|
|
225
229
|
'upload.hasPackageJson': 'package.json',
|
|
@@ -444,6 +448,10 @@ const translations = {
|
|
|
444
448
|
'upload.id': 'ID',
|
|
445
449
|
'upload.version': '版本',
|
|
446
450
|
'upload.description': '描述',
|
|
451
|
+
'upload.validation': '验证',
|
|
452
|
+
'upload.stats': '统计',
|
|
453
|
+
'upload.done': '✅ 完成',
|
|
454
|
+
'upload.noSkillUploaded': '未上传技能,请先上传。',
|
|
447
455
|
'upload.platforms': '支持平台',
|
|
448
456
|
'upload.fileCount': '文件数',
|
|
449
457
|
'upload.hasPackageJson': 'package.json',
|
|
@@ -1149,7 +1157,7 @@ function goBackFromPlatformDetail() {
|
|
|
1149
1157
|
|
|
1150
1158
|
async function loadHelp() {
|
|
1151
1159
|
const container = document.getElementById('help-content');
|
|
1152
|
-
container.innerHTML =
|
|
1160
|
+
container.innerHTML = `<div class="loading">${t('loading.generic')}</div>`;
|
|
1153
1161
|
|
|
1154
1162
|
try {
|
|
1155
1163
|
const response = await fetch('/api/config');
|
|
@@ -2056,7 +2064,7 @@ async function handleUpload(file, skillNameOverride) {
|
|
|
2056
2064
|
}
|
|
2057
2065
|
|
|
2058
2066
|
progressFill.style.width = '100%';
|
|
2059
|
-
progressText.textContent = '
|
|
2067
|
+
progressText.textContent = t('upload.done');
|
|
2060
2068
|
|
|
2061
2069
|
uploadState.data = result;
|
|
2062
2070
|
uploadState.skillName = skillNameOverride || result.skillName;
|
|
@@ -2097,7 +2105,7 @@ function renderUploadPreview(data) {
|
|
|
2097
2105
|
</div>
|
|
2098
2106
|
|
|
2099
2107
|
<div class="upload-preview-section">
|
|
2100
|
-
<h3
|
|
2108
|
+
<h3>${t('upload.validation')}</h3>
|
|
2101
2109
|
<div>
|
|
2102
2110
|
<span class="upload-preview-badge ${data.hasPackageJson ? 'success' : 'warning'}">
|
|
2103
2111
|
📦 ${t('upload.hasPackageJson')}: ${data.hasPackageJson ? t('upload.yes') : t('upload.no')}
|
|
@@ -2109,7 +2117,7 @@ function renderUploadPreview(data) {
|
|
|
2109
2117
|
</div>
|
|
2110
2118
|
|
|
2111
2119
|
<div class="upload-preview-section" style="border-bottom:none;margin-bottom:0;padding-bottom:0;">
|
|
2112
|
-
<h3
|
|
2120
|
+
<h3>${t('upload.stats')}</h3>
|
|
2113
2121
|
<div class="upload-preview-stats">
|
|
2114
2122
|
<div class="upload-preview-stat">
|
|
2115
2123
|
<div class="upload-preview-stat-value">${data.fileCount}</div>
|
|
@@ -2127,7 +2135,7 @@ function renderUploadPreview(data) {
|
|
|
2127
2135
|
/** 执行上传后的操作 */
|
|
2128
2136
|
async function executeUploadAction(action) {
|
|
2129
2137
|
if (!uploadState.data || !uploadState.skillName) {
|
|
2130
|
-
showToast('
|
|
2138
|
+
showToast(t('upload.noSkillUploaded'), 'error');
|
|
2131
2139
|
return;
|
|
2132
2140
|
}
|
|
2133
2141
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itismyskillmarket",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.32",
|
|
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",
|