itismyskillmarket 1.3.6 → 1.3.7
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/README.md +10 -5
- package/dist/index.js +440 -11
- package/gui/app.js +415 -0
- package/gui/index.html +84 -0
- package/gui/style.css +454 -0
- package/package.json +6 -2
- package/.github/workflows/publish-npm.yml +0 -59
- package/.github/workflows/publish-skill.yml +0 -72
- package/5e51cb7aa8b8e60d49d86f4689f5d4d1.png +0 -0
- package/CHANGELOG.md +0 -639
- package/DEVELOPMENT.md +0 -376
- package/SKILLMARKET-GUIDE.md +0 -288
- package/docs/WEEKLY-UPDATE-2026-04-23.md +0 -43
- package/docs/plans/2026-04-01-skillmarket-design.md +0 -267
- package/docs/plans/2026-04-01-skillmarket-implementation.md +0 -1031
- package/docs/plans/2026-04-15-cross-platform-adapter-design.md +0 -416
- package/docs/plans/2026-04-15-cross-platform-adapter-plan.md +0 -833
- package/docs/plans/2026-04-16-keyword-search-design.md +0 -143
- package/docs/plans/2026-04-29-weekly-update.md +0 -57
- package/skills/README.md +0 -54
- package/skills/test-skill/SKILL.md +0 -25
- package/skills/test-skill/index.js +0 -66
- package/skills/test-skill/metadata.json +0 -9
- package/skills/test-skill/package.json +0 -19
- package/skills/test-skill-1/SKILL.md +0 -24
- package/skills/test-skill-1/index.js +0 -13
- package/skills/test-skill-1/metadata.json +0 -9
- package/skills/test-skill-1/package.json +0 -16
- package/skills/test-skill-2/SKILL.md +0 -25
- package/skills/test-skill-2/index.js +0 -13
- package/skills/test-skill-2/metadata.json +0 -9
- package/skills/test-skill-2/package.json +0 -16
- package/src/adapters/base.ts +0 -87
- package/src/adapters/claude.ts +0 -31
- package/src/adapters/hermes.test.ts +0 -39
- package/src/adapters/hermes.ts +0 -77
- package/src/adapters/index.ts +0 -11
- package/src/adapters/openclaw.test.ts +0 -40
- package/src/adapters/openclaw.ts +0 -69
- package/src/adapters/opencode.ts +0 -40
- package/src/adapters/registry.test.ts +0 -29
- package/src/adapters/registry.ts +0 -85
- package/src/adapters/vscode.ts +0 -62
- package/src/cli.ts +0 -463
- package/src/commands/github-install.ts +0 -538
- package/src/commands/info.ts +0 -143
- package/src/commands/install.ts +0 -312
- package/src/commands/ls.ts +0 -307
- package/src/commands/npm.ts +0 -353
- package/src/commands/registry.ts +0 -159
- package/src/commands/search.ts +0 -103
- package/src/commands/sync.ts +0 -196
- package/src/commands/uninstall.ts +0 -400
- package/src/commands/update.ts +0 -113
- package/src/constants.test.ts +0 -18
- package/src/constants.ts +0 -128
- package/src/index.ts +0 -62
- package/src/types.ts +0 -172
- package/src/utils/dirs.ts +0 -166
- package/src/utils/platform.ts +0 -139
- package/tsconfig.json +0 -10
- package/tsup.config.ts +0 -22
- package/wanxuchen-skillmarket-1.0.1.tgz +0 -0
package/README.md
CHANGED
|
@@ -56,6 +56,9 @@ skm platforms
|
|
|
56
56
|
# Sync platform links
|
|
57
57
|
skm sync
|
|
58
58
|
|
|
59
|
+
# Sync skill to latest version (install to all platforms)
|
|
60
|
+
skm sync brainstorming
|
|
61
|
+
|
|
59
62
|
# Uninstall a skill (from all platforms)
|
|
60
63
|
skm uninstall brainstorming
|
|
61
64
|
|
|
@@ -101,11 +104,11 @@ $ skm platforms
|
|
|
101
104
|
|
|
102
105
|
📍 Available Platforms:
|
|
103
106
|
|
|
104
|
-
OpenCode
|
|
105
|
-
Claude Code
|
|
106
|
-
VSCode
|
|
107
|
-
OpenClaw
|
|
108
|
-
Hermes Agent
|
|
107
|
+
OpenCode ✅ Available (2 skills installed)
|
|
108
|
+
Claude Code ✅ Available (1 skills installed)
|
|
109
|
+
VSCode ✅ Available (0 skills installed)
|
|
110
|
+
OpenClaw ✅ Available (0 skills installed)
|
|
111
|
+
Hermes Agent ✅ Available (0 skills installed)
|
|
109
112
|
```
|
|
110
113
|
|
|
111
114
|
## Development
|
|
@@ -152,6 +155,8 @@ Skills are installed to `~/.skillmarket/` with the following structure:
|
|
|
152
155
|
- OpenCode
|
|
153
156
|
- Claude Code
|
|
154
157
|
- Antigravity
|
|
158
|
+
- OpenClaw
|
|
159
|
+
- Hermes Agent
|
|
155
160
|
|
|
156
161
|
## License
|
|
157
162
|
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { readFileSync } from "fs";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
import { dirname, resolve } from "path";
|
|
5
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
6
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7
|
+
import { dirname as dirname2, resolve } from "path";
|
|
8
8
|
|
|
9
9
|
// src/commands/registry.ts
|
|
10
10
|
import fs2 from "fs-extra";
|
|
@@ -102,7 +102,7 @@ async function isSkillInstalled(skillId) {
|
|
|
102
102
|
|
|
103
103
|
// src/commands/npm.ts
|
|
104
104
|
import https from "https";
|
|
105
|
-
import { URL } from "url";
|
|
105
|
+
import { URL as URL2 } from "url";
|
|
106
106
|
async function fetchNpmPackage(packageName) {
|
|
107
107
|
return new Promise((resolve2, reject) => {
|
|
108
108
|
const isScoped = packageName.startsWith("@");
|
|
@@ -120,7 +120,7 @@ async function fetchNpmPackage(packageName) {
|
|
|
120
120
|
} else {
|
|
121
121
|
encodedName = encodeURIComponent(packageName);
|
|
122
122
|
}
|
|
123
|
-
const url = new
|
|
123
|
+
const url = new URL2(`https://registry.npmjs.org/${encodedName}`);
|
|
124
124
|
const req = https.get(url.toString(), { timeout: 1e4 }, (res) => {
|
|
125
125
|
let data = "";
|
|
126
126
|
res.on("data", (chunk) => {
|
|
@@ -182,7 +182,7 @@ async function searchSkillmarketPackages(options = {}) {
|
|
|
182
182
|
const packages = [];
|
|
183
183
|
let total = 0;
|
|
184
184
|
return new Promise((resolve2, reject) => {
|
|
185
|
-
const url = new
|
|
185
|
+
const url = new URL2("https://registry.npmjs.org/-/v1/search");
|
|
186
186
|
url.searchParams.set("text", "keywords:skillmarket");
|
|
187
187
|
url.searchParams.set("size", String(Math.max(size, 100)));
|
|
188
188
|
url.searchParams.set("from", String(from));
|
|
@@ -1131,13 +1131,13 @@ function parseGitHubUrl(input) {
|
|
|
1131
1131
|
const repo = match[2].replace(/\.git$/, "");
|
|
1132
1132
|
const branch = match[3] || "main";
|
|
1133
1133
|
const commitOrPath = match[4] || match[3];
|
|
1134
|
-
const
|
|
1134
|
+
const path11 = match[5] || void 0;
|
|
1135
1135
|
return {
|
|
1136
1136
|
owner,
|
|
1137
1137
|
repo,
|
|
1138
1138
|
branch: commitOrPath && !commitOrPath.includes("/") ? commitOrPath : branch,
|
|
1139
1139
|
commit: commitOrPath?.match(/^[0-9a-f]{40}$/) ? commitOrPath : void 0,
|
|
1140
|
-
path:
|
|
1140
|
+
path: path11
|
|
1141
1141
|
};
|
|
1142
1142
|
}
|
|
1143
1143
|
}
|
|
@@ -1378,10 +1378,419 @@ Installing to platforms: ${targetPlatforms.join(", ")}`);
|
|
|
1378
1378
|
console.log(` Source: ${source.owner}/${source.repo}`);
|
|
1379
1379
|
}
|
|
1380
1380
|
|
|
1381
|
+
// src/commands/publish.ts
|
|
1382
|
+
import { execSync } from "child_process";
|
|
1383
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1384
|
+
import { join as join3 } from "path";
|
|
1385
|
+
import { fileURLToPath } from "url";
|
|
1386
|
+
async function publishSkill(skillName, options) {
|
|
1387
|
+
const __dirname4 = fileURLToPath(new URL(".", import.meta.url));
|
|
1388
|
+
const projectRoot = join3(__dirname4, "..", "..");
|
|
1389
|
+
const skillDir = join3(projectRoot, "skills", skillName);
|
|
1390
|
+
console.log(`Publishing ${skillName}...`);
|
|
1391
|
+
if (!existsSync3(skillDir)) {
|
|
1392
|
+
throw new Error(`Skill '${skillName}' not found in skills/ directory`);
|
|
1393
|
+
}
|
|
1394
|
+
if (!options?.skipInstall) {
|
|
1395
|
+
console.log("Running npm install...");
|
|
1396
|
+
try {
|
|
1397
|
+
execSync("npm install", {
|
|
1398
|
+
cwd: skillDir,
|
|
1399
|
+
stdio: "inherit"
|
|
1400
|
+
});
|
|
1401
|
+
} catch (err) {
|
|
1402
|
+
console.warn("Warning: npm install failed, continuing anyway...");
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
if (options?.version) {
|
|
1406
|
+
console.log(`Updating version to ${options.version}...`);
|
|
1407
|
+
try {
|
|
1408
|
+
execSync(`npm version ${options.version} --no-git-tag-version`, {
|
|
1409
|
+
cwd: skillDir,
|
|
1410
|
+
stdio: "inherit"
|
|
1411
|
+
});
|
|
1412
|
+
} catch (err) {
|
|
1413
|
+
throw new Error(`Failed to update version: ${err}`);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
console.log("Publishing to npm...");
|
|
1417
|
+
try {
|
|
1418
|
+
execSync("npm publish --access=public", {
|
|
1419
|
+
cwd: skillDir,
|
|
1420
|
+
stdio: "inherit"
|
|
1421
|
+
});
|
|
1422
|
+
} catch (err) {
|
|
1423
|
+
throw new Error(`Failed to publish: ${err}`);
|
|
1424
|
+
}
|
|
1425
|
+
console.log(`
|
|
1426
|
+
\u2705 ${skillName} published successfully!`);
|
|
1427
|
+
console.log(` View at: https://www.npmjs.com/package/@itismyskillmarket/${skillName}`);
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
// src/commands/verify.ts
|
|
1431
|
+
import fs11 from "fs-extra";
|
|
1432
|
+
import path10 from "path";
|
|
1433
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1434
|
+
var __filename = fileURLToPath2(import.meta.url);
|
|
1435
|
+
var __dirname = path10.dirname(__filename);
|
|
1436
|
+
async function verifySkill(skillName) {
|
|
1437
|
+
try {
|
|
1438
|
+
console.log(`
|
|
1439
|
+
\u{1F50D} Verifying skill: ${skillName}
|
|
1440
|
+
`);
|
|
1441
|
+
const skillDir = path10.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "skills", skillName);
|
|
1442
|
+
if (!await fs11.pathExists(skillDir)) {
|
|
1443
|
+
console.error(`\u274C Skill "${skillName}" not found locally.`);
|
|
1444
|
+
console.log(` Try: skm install ${skillName}`);
|
|
1445
|
+
process.exit(1);
|
|
1446
|
+
}
|
|
1447
|
+
let passed = 0;
|
|
1448
|
+
let failed = 0;
|
|
1449
|
+
const skillMdPath = path10.join(skillDir, "SKILL.md");
|
|
1450
|
+
if (await fs11.pathExists(skillMdPath)) {
|
|
1451
|
+
console.log(`\u2705 SKILL.md exists`);
|
|
1452
|
+
passed++;
|
|
1453
|
+
const content = await fs11.readFile(skillMdPath, "utf-8");
|
|
1454
|
+
if (content.trim().length > 0) {
|
|
1455
|
+
console.log(`\u2705 SKILL.md is not empty (${content.length} chars)`);
|
|
1456
|
+
passed++;
|
|
1457
|
+
} else {
|
|
1458
|
+
console.log(`\u26A0\uFE0F SKILL.md is empty`);
|
|
1459
|
+
failed++;
|
|
1460
|
+
}
|
|
1461
|
+
} else {
|
|
1462
|
+
console.log(`\u274C SKILL.md not found`);
|
|
1463
|
+
failed++;
|
|
1464
|
+
}
|
|
1465
|
+
const pkgPath = path10.join(skillDir, "package.json");
|
|
1466
|
+
if (await fs11.pathExists(pkgPath)) {
|
|
1467
|
+
console.log(`\u2705 package.json exists`);
|
|
1468
|
+
passed++;
|
|
1469
|
+
try {
|
|
1470
|
+
const pkg = await fs11.readJson(pkgPath);
|
|
1471
|
+
const requiredFields = ["name", "version", "description"];
|
|
1472
|
+
for (const field of requiredFields) {
|
|
1473
|
+
if (pkg[field]) {
|
|
1474
|
+
console.log(`\u2705 package.json has "${field}"`);
|
|
1475
|
+
passed++;
|
|
1476
|
+
} else {
|
|
1477
|
+
console.log(`\u26A0\uFE0F package.json missing "${field}"`);
|
|
1478
|
+
failed++;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
} catch (err) {
|
|
1482
|
+
console.log(`\u274C package.json is invalid JSON`);
|
|
1483
|
+
failed++;
|
|
1484
|
+
}
|
|
1485
|
+
} else {
|
|
1486
|
+
console.log(`\u26A0\uFE0F package.json not found (optional for basic skills)`);
|
|
1487
|
+
}
|
|
1488
|
+
const registryPath = path10.join(process.env.HOME || process.env.USERPROFILE || "", ".skillmarket", "registry.json");
|
|
1489
|
+
if (await fs11.pathExists(registryPath)) {
|
|
1490
|
+
try {
|
|
1491
|
+
const registry = await fs11.readJson(registryPath);
|
|
1492
|
+
if (registry[skillName]) {
|
|
1493
|
+
console.log(`\u2705 Skill registered in registry (v${registry[skillName].version})`);
|
|
1494
|
+
passed++;
|
|
1495
|
+
} else {
|
|
1496
|
+
console.log(`\u26A0\uFE0F Skill not found in registry`);
|
|
1497
|
+
failed++;
|
|
1498
|
+
}
|
|
1499
|
+
} catch {
|
|
1500
|
+
console.log(`\u26A0\uFE0F Registry is invalid JSON`);
|
|
1501
|
+
failed++;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
console.log(`
|
|
1505
|
+
\u{1F4CA} Verification Result:`);
|
|
1506
|
+
console.log(` \u2705 Passed: ${passed}`);
|
|
1507
|
+
console.log(` \u274C Failed: ${failed}`);
|
|
1508
|
+
if (failed === 0) {
|
|
1509
|
+
console.log(`
|
|
1510
|
+
\u2705 Skill "${skillName}" is valid!
|
|
1511
|
+
`);
|
|
1512
|
+
} else {
|
|
1513
|
+
console.log(`
|
|
1514
|
+
\u26A0\uFE0F Skill "${skillName}" has issues. Consider reinstalling.
|
|
1515
|
+
`);
|
|
1516
|
+
}
|
|
1517
|
+
} catch (err) {
|
|
1518
|
+
console.error("\u274C Verification failed:", err);
|
|
1519
|
+
process.exit(1);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// src/commands/ui.ts
|
|
1524
|
+
import { createServer } from "http";
|
|
1525
|
+
import { readFileSync, existsSync as existsSync4 } from "fs";
|
|
1526
|
+
import { join as join4, extname, dirname } from "path";
|
|
1527
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1528
|
+
var __filename2 = fileURLToPath3(import.meta.url);
|
|
1529
|
+
var __dirname2 = dirname(__filename2);
|
|
1530
|
+
var guiDir = join4(__dirname2, "..", "gui");
|
|
1531
|
+
var MIME_TYPES = {
|
|
1532
|
+
".html": "text/html; charset=utf-8",
|
|
1533
|
+
".js": "application/javascript; charset=utf-8",
|
|
1534
|
+
".css": "text/css; charset=utf-8",
|
|
1535
|
+
".json": "application/json; charset=utf-8",
|
|
1536
|
+
".png": "image/png",
|
|
1537
|
+
".svg": "image/svg+xml",
|
|
1538
|
+
".ico": "image/x-icon"
|
|
1539
|
+
};
|
|
1540
|
+
function jsonResponse(res, status, data) {
|
|
1541
|
+
res.writeHead(status, {
|
|
1542
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
1543
|
+
"Access-Control-Allow-Origin": "*"
|
|
1544
|
+
});
|
|
1545
|
+
res.end(JSON.stringify(data));
|
|
1546
|
+
}
|
|
1547
|
+
function parseBody(req) {
|
|
1548
|
+
return new Promise((resolve2, reject) => {
|
|
1549
|
+
let body = "";
|
|
1550
|
+
req.on("data", (chunk) => {
|
|
1551
|
+
body += chunk.toString();
|
|
1552
|
+
});
|
|
1553
|
+
req.on("end", () => {
|
|
1554
|
+
if (!body) return resolve2({});
|
|
1555
|
+
try {
|
|
1556
|
+
resolve2(JSON.parse(body));
|
|
1557
|
+
} catch {
|
|
1558
|
+
reject(new Error("Invalid JSON body"));
|
|
1559
|
+
}
|
|
1560
|
+
});
|
|
1561
|
+
req.on("error", reject);
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
var API_ROUTES = {
|
|
1565
|
+
GET: {},
|
|
1566
|
+
POST: {}
|
|
1567
|
+
};
|
|
1568
|
+
API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
|
|
1569
|
+
try {
|
|
1570
|
+
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1"));
|
|
1571
|
+
const limit = Math.min(100, Math.max(1, parseInt(url.searchParams.get("limit") || "20")));
|
|
1572
|
+
const search = url.searchParams.get("search") || "";
|
|
1573
|
+
const offset = (page - 1) * limit;
|
|
1574
|
+
const { packages, total } = await searchSkillmarketPackages({
|
|
1575
|
+
from: offset,
|
|
1576
|
+
size: limit,
|
|
1577
|
+
keyword: search || void 0
|
|
1578
|
+
});
|
|
1579
|
+
const skills = (await Promise.all(
|
|
1580
|
+
packages.map(async (pkgName) => {
|
|
1581
|
+
try {
|
|
1582
|
+
const info = await fetchNpmPackage(pkgName);
|
|
1583
|
+
if (!info) return null;
|
|
1584
|
+
const latestVersion = info["dist-tags"]?.latest || "unknown";
|
|
1585
|
+
const pkg = info.versions?.[latestVersion];
|
|
1586
|
+
const meta = pkg?.skillmarket;
|
|
1587
|
+
return {
|
|
1588
|
+
id: meta?.id || info.name.replace(/^@[^/]+\//, ""),
|
|
1589
|
+
name: info.name,
|
|
1590
|
+
displayName: meta?.displayName || info.name,
|
|
1591
|
+
version: latestVersion,
|
|
1592
|
+
description: pkg?.description || "",
|
|
1593
|
+
platforms: meta?.platforms || [],
|
|
1594
|
+
author: info.author?.name || pkg?.author?.name || "",
|
|
1595
|
+
homepage: pkg?.homepage || "",
|
|
1596
|
+
repository: pkg?.repository?.url || ""
|
|
1597
|
+
};
|
|
1598
|
+
} catch {
|
|
1599
|
+
return null;
|
|
1600
|
+
}
|
|
1601
|
+
})
|
|
1602
|
+
)).filter(Boolean);
|
|
1603
|
+
const totalPages = Math.ceil(total / limit) || 1;
|
|
1604
|
+
jsonResponse(res, 200, { skills, page, totalPages, total });
|
|
1605
|
+
} catch (err) {
|
|
1606
|
+
jsonResponse(res, 500, {
|
|
1607
|
+
error: String(err),
|
|
1608
|
+
skills: [],
|
|
1609
|
+
page: 1,
|
|
1610
|
+
totalPages: 1,
|
|
1611
|
+
total: 0
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
API_ROUTES.GET["/api/installed"] = async (_req, res, _url) => {
|
|
1616
|
+
try {
|
|
1617
|
+
const skills = await getInstalledSkills();
|
|
1618
|
+
jsonResponse(res, 200, skills.map((s) => ({
|
|
1619
|
+
id: s.id,
|
|
1620
|
+
displayName: s.id,
|
|
1621
|
+
version: s.version,
|
|
1622
|
+
installedAt: s.installedAt,
|
|
1623
|
+
platforms: s.platforms
|
|
1624
|
+
})));
|
|
1625
|
+
} catch (err) {
|
|
1626
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
API_ROUTES.GET["/api/platforms"] = async (_req, res, _url) => {
|
|
1630
|
+
try {
|
|
1631
|
+
const available = await detectPlatforms();
|
|
1632
|
+
const allAdapters = getAllAdapters();
|
|
1633
|
+
const platforms = await Promise.all(
|
|
1634
|
+
allAdapters.map(async (adapter) => {
|
|
1635
|
+
const isAvailable = available.find((a) => a.id === adapter.id);
|
|
1636
|
+
const installed = await adapter.listInstalled();
|
|
1637
|
+
return {
|
|
1638
|
+
id: adapter.id,
|
|
1639
|
+
name: adapter.name,
|
|
1640
|
+
available: !!isAvailable,
|
|
1641
|
+
installedCount: Array.isArray(installed) ? installed.length : 0
|
|
1642
|
+
};
|
|
1643
|
+
})
|
|
1644
|
+
);
|
|
1645
|
+
jsonResponse(res, 200, platforms);
|
|
1646
|
+
} catch (err) {
|
|
1647
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
|
|
1651
|
+
try {
|
|
1652
|
+
const skillName = url.searchParams.get("skill") || "";
|
|
1653
|
+
if (!skillName) {
|
|
1654
|
+
jsonResponse(res, 400, { error: 'Missing "skill" query parameter' });
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const info = await fetchNpmPackage(skillName);
|
|
1658
|
+
if (!info) {
|
|
1659
|
+
jsonResponse(res, 404, { error: `Skill "${skillName}" not found` });
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const latestVersion = info["dist-tags"]?.latest || "unknown";
|
|
1663
|
+
const pkg = latestVersion ? info.versions?.[latestVersion] : void 0;
|
|
1664
|
+
const meta = pkg?.skillmarket;
|
|
1665
|
+
const versionKeys = Object.keys(info.versions || {});
|
|
1666
|
+
const recentVersions = versionKeys.slice(-20);
|
|
1667
|
+
jsonResponse(res, 200, {
|
|
1668
|
+
id: meta?.id || info.name.replace(/^@[^/]+\//, ""),
|
|
1669
|
+
name: info.name,
|
|
1670
|
+
displayName: meta?.displayName || info.name,
|
|
1671
|
+
description: pkg?.description || "",
|
|
1672
|
+
version: latestVersion,
|
|
1673
|
+
platforms: meta?.platforms || [],
|
|
1674
|
+
versions: recentVersions,
|
|
1675
|
+
author: info.author?.name || pkg?.author?.name || "",
|
|
1676
|
+
license: info.license || "",
|
|
1677
|
+
homepage: pkg?.homepage || "",
|
|
1678
|
+
repository: pkg?.repository?.url || "",
|
|
1679
|
+
readme: info.readme || ""
|
|
1680
|
+
});
|
|
1681
|
+
} catch (err) {
|
|
1682
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1685
|
+
API_ROUTES.POST["/api/install"] = async (req, res, _url) => {
|
|
1686
|
+
try {
|
|
1687
|
+
const body = await parseBody(req);
|
|
1688
|
+
const skillId = String(body.skillId || "");
|
|
1689
|
+
const version = body.version ? String(body.version) : void 0;
|
|
1690
|
+
const platform = body.platform ? String(body.platform) : void 0;
|
|
1691
|
+
if (!skillId) {
|
|
1692
|
+
jsonResponse(res, 400, { error: "Missing skillId" });
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
await installSkill(skillId, version, {
|
|
1696
|
+
platforms: platform ? [platform] : void 0,
|
|
1697
|
+
force: true
|
|
1698
|
+
});
|
|
1699
|
+
jsonResponse(res, 200, { success: true, message: `${skillId} installed successfully` });
|
|
1700
|
+
} catch (err) {
|
|
1701
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
API_ROUTES.POST["/api/uninstall"] = async (req, res, _url) => {
|
|
1705
|
+
try {
|
|
1706
|
+
const body = await parseBody(req);
|
|
1707
|
+
const skillId = String(body.skillId || "");
|
|
1708
|
+
const platform = body.platform ? String(body.platform) : void 0;
|
|
1709
|
+
if (!skillId) {
|
|
1710
|
+
jsonResponse(res, 400, { error: "Missing skillId" });
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
await uninstallSkill(skillId, {
|
|
1714
|
+
platforms: platform ? [platform] : void 0,
|
|
1715
|
+
yes: true
|
|
1716
|
+
});
|
|
1717
|
+
jsonResponse(res, 200, { success: true, message: `${skillId} uninstalled successfully` });
|
|
1718
|
+
} catch (err) {
|
|
1719
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
API_ROUTES.POST["/api/update"] = async (req, res, _url) => {
|
|
1723
|
+
try {
|
|
1724
|
+
const body = await parseBody(req);
|
|
1725
|
+
const skillId = body.skillId ? String(body.skillId) : void 0;
|
|
1726
|
+
await updateSkill(skillId);
|
|
1727
|
+
const msg = skillId ? `${skillId} updated successfully` : "All skills updated successfully";
|
|
1728
|
+
jsonResponse(res, 200, { success: true, message: msg });
|
|
1729
|
+
} catch (err) {
|
|
1730
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
function serveStaticFile(res, filePath) {
|
|
1734
|
+
if (!existsSync4(filePath)) {
|
|
1735
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1736
|
+
res.end("Not Found");
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
const content = readFileSync(filePath);
|
|
1740
|
+
const ext = extname(filePath);
|
|
1741
|
+
const mime = MIME_TYPES[ext] || "application/octet-stream";
|
|
1742
|
+
res.writeHead(200, { "Content-Type": mime });
|
|
1743
|
+
res.end(content);
|
|
1744
|
+
}
|
|
1745
|
+
async function handleRequest(req, res) {
|
|
1746
|
+
const method = req.method || "GET";
|
|
1747
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
1748
|
+
const pathname = url.pathname;
|
|
1749
|
+
const routeHandler = API_ROUTES[method]?.[pathname];
|
|
1750
|
+
if (routeHandler) {
|
|
1751
|
+
try {
|
|
1752
|
+
await routeHandler(req, res, url);
|
|
1753
|
+
} catch (err) {
|
|
1754
|
+
jsonResponse(res, 500, { error: String(err) });
|
|
1755
|
+
}
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
if (pathname.startsWith("/api/")) {
|
|
1759
|
+
jsonResponse(res, 404, { error: `Unknown API endpoint: ${method} ${pathname}` });
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
const filePath = join4(guiDir, pathname === "/" ? "index.html" : pathname);
|
|
1763
|
+
if (filePath.startsWith(guiDir)) {
|
|
1764
|
+
serveStaticFile(res, filePath);
|
|
1765
|
+
} else {
|
|
1766
|
+
res.writeHead(403);
|
|
1767
|
+
res.end("Forbidden");
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
function startGuiServer(port = 18770) {
|
|
1771
|
+
const server = createServer(handleRequest);
|
|
1772
|
+
server.listen(port, () => {
|
|
1773
|
+
console.log(`
|
|
1774
|
+
\u{1F680} SkillMarket GUI started!`);
|
|
1775
|
+
console.log(` Local: http://localhost:${port}`);
|
|
1776
|
+
console.log(`
|
|
1777
|
+
Press Ctrl+C to stop
|
|
1778
|
+
`);
|
|
1779
|
+
});
|
|
1780
|
+
server.on("error", (err) => {
|
|
1781
|
+
if (err.code === "EADDRINUSE") {
|
|
1782
|
+
console.error(`\u274C Port ${port} is already in use. Try: skm gui ${port + 1}`);
|
|
1783
|
+
} else {
|
|
1784
|
+
console.error("\u274C Failed to start GUI server:", err.message);
|
|
1785
|
+
}
|
|
1786
|
+
process.exit(1);
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1381
1790
|
// src/cli.ts
|
|
1382
|
-
var
|
|
1383
|
-
var
|
|
1384
|
-
var packageJson = JSON.parse(
|
|
1791
|
+
var __filename3 = fileURLToPath4(import.meta.url);
|
|
1792
|
+
var __dirname3 = dirname2(__filename3);
|
|
1793
|
+
var packageJson = JSON.parse(readFileSync2(resolve(__dirname3, "../package.json"), "utf-8"));
|
|
1385
1794
|
var VERSION = packageJson.version || "1.3.1";
|
|
1386
1795
|
var program = new Command();
|
|
1387
1796
|
program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version(VERSION);
|
|
@@ -1550,4 +1959,24 @@ platformsCmd.action(async () => {
|
|
|
1550
1959
|
process.exit(1);
|
|
1551
1960
|
}
|
|
1552
1961
|
});
|
|
1962
|
+
program.command("gui [port]").description("Start SkillMarket GUI (web interface)").action(async (port) => {
|
|
1963
|
+
const portNum = port ? parseInt(port) : 18770;
|
|
1964
|
+
startGuiServer(portNum);
|
|
1965
|
+
});
|
|
1966
|
+
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) => {
|
|
1967
|
+
try {
|
|
1968
|
+
await publishSkill(skill, options.version ? { version: options.version } : void 0);
|
|
1969
|
+
} catch (err) {
|
|
1970
|
+
console.error("Publish failed:", err);
|
|
1971
|
+
process.exit(1);
|
|
1972
|
+
}
|
|
1973
|
+
});
|
|
1974
|
+
program.command("verify <skill>").description("Verify skill integrity and format").action(async (skill) => {
|
|
1975
|
+
try {
|
|
1976
|
+
await verifySkill(skill);
|
|
1977
|
+
} catch (err) {
|
|
1978
|
+
console.error("Verify failed:", err);
|
|
1979
|
+
process.exit(1);
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1553
1982
|
program.parse();
|