itismyskillmarket 1.3.6 → 1.3.8

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.
Files changed (63) hide show
  1. package/README.md +10 -5
  2. package/dist/index.js +480 -11
  3. package/gui/app.js +415 -0
  4. package/gui/index.html +84 -0
  5. package/gui/style.css +454 -0
  6. package/package.json +6 -2
  7. package/.github/workflows/publish-npm.yml +0 -59
  8. package/.github/workflows/publish-skill.yml +0 -72
  9. package/5e51cb7aa8b8e60d49d86f4689f5d4d1.png +0 -0
  10. package/CHANGELOG.md +0 -639
  11. package/DEVELOPMENT.md +0 -376
  12. package/SKILLMARKET-GUIDE.md +0 -288
  13. package/docs/WEEKLY-UPDATE-2026-04-23.md +0 -43
  14. package/docs/plans/2026-04-01-skillmarket-design.md +0 -267
  15. package/docs/plans/2026-04-01-skillmarket-implementation.md +0 -1031
  16. package/docs/plans/2026-04-15-cross-platform-adapter-design.md +0 -416
  17. package/docs/plans/2026-04-15-cross-platform-adapter-plan.md +0 -833
  18. package/docs/plans/2026-04-16-keyword-search-design.md +0 -143
  19. package/docs/plans/2026-04-29-weekly-update.md +0 -57
  20. package/skills/README.md +0 -54
  21. package/skills/test-skill/SKILL.md +0 -25
  22. package/skills/test-skill/index.js +0 -66
  23. package/skills/test-skill/metadata.json +0 -9
  24. package/skills/test-skill/package.json +0 -19
  25. package/skills/test-skill-1/SKILL.md +0 -24
  26. package/skills/test-skill-1/index.js +0 -13
  27. package/skills/test-skill-1/metadata.json +0 -9
  28. package/skills/test-skill-1/package.json +0 -16
  29. package/skills/test-skill-2/SKILL.md +0 -25
  30. package/skills/test-skill-2/index.js +0 -13
  31. package/skills/test-skill-2/metadata.json +0 -9
  32. package/skills/test-skill-2/package.json +0 -16
  33. package/src/adapters/base.ts +0 -87
  34. package/src/adapters/claude.ts +0 -31
  35. package/src/adapters/hermes.test.ts +0 -39
  36. package/src/adapters/hermes.ts +0 -77
  37. package/src/adapters/index.ts +0 -11
  38. package/src/adapters/openclaw.test.ts +0 -40
  39. package/src/adapters/openclaw.ts +0 -69
  40. package/src/adapters/opencode.ts +0 -40
  41. package/src/adapters/registry.test.ts +0 -29
  42. package/src/adapters/registry.ts +0 -85
  43. package/src/adapters/vscode.ts +0 -62
  44. package/src/cli.ts +0 -463
  45. package/src/commands/github-install.ts +0 -538
  46. package/src/commands/info.ts +0 -143
  47. package/src/commands/install.ts +0 -312
  48. package/src/commands/ls.ts +0 -307
  49. package/src/commands/npm.ts +0 -353
  50. package/src/commands/registry.ts +0 -159
  51. package/src/commands/search.ts +0 -103
  52. package/src/commands/sync.ts +0 -196
  53. package/src/commands/uninstall.ts +0 -400
  54. package/src/commands/update.ts +0 -113
  55. package/src/constants.test.ts +0 -18
  56. package/src/constants.ts +0 -128
  57. package/src/index.ts +0 -62
  58. package/src/types.ts +0 -172
  59. package/src/utils/dirs.ts +0 -166
  60. package/src/utils/platform.ts +0 -139
  61. package/tsconfig.json +0 -10
  62. package/tsup.config.ts +0 -22
  63. 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 ✅ Available (2 skills installed)
105
- Claude Code ✅ Available (1 skills installed)
106
- VSCode ✅ Available (0 skills installed)
107
- OpenClaw ✅ Available
108
- Hermes Agent ✅ Available
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 URL(`https://registry.npmjs.org/${encodedName}`);
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 URL("https://registry.npmjs.org/-/v1/search");
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 path10 = match[5] || void 0;
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: path10
1140
+ path: path11
1141
1141
  };
1142
1142
  }
1143
1143
  }
@@ -1378,10 +1378,459 @@ 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 cache = /* @__PURE__ */ new Map();
1532
+ function getCached(key) {
1533
+ const entry = cache.get(key);
1534
+ if (!entry) return null;
1535
+ if (Date.now() > entry.expiry) {
1536
+ cache.delete(key);
1537
+ return null;
1538
+ }
1539
+ return entry.data;
1540
+ }
1541
+ function setCache(key, data, ttlMs = 6e4) {
1542
+ cache.set(key, { data, expiry: Date.now() + ttlMs });
1543
+ }
1544
+ async function throttledMap(items, fn, concurrency = 3) {
1545
+ const results = [];
1546
+ for (let i = 0; i < items.length; i += concurrency) {
1547
+ const batch = items.slice(i, i + concurrency);
1548
+ const batchResults = await Promise.all(batch.map((item, idx) => fn(item, i + idx)));
1549
+ results.push(...batchResults);
1550
+ if (i + concurrency < items.length) {
1551
+ await new Promise((r) => setTimeout(r, 200));
1552
+ }
1553
+ }
1554
+ return results;
1555
+ }
1556
+ var MIME_TYPES = {
1557
+ ".html": "text/html; charset=utf-8",
1558
+ ".js": "application/javascript; charset=utf-8",
1559
+ ".css": "text/css; charset=utf-8",
1560
+ ".json": "application/json; charset=utf-8",
1561
+ ".png": "image/png",
1562
+ ".svg": "image/svg+xml",
1563
+ ".ico": "image/x-icon"
1564
+ };
1565
+ function jsonResponse(res, status, data) {
1566
+ res.writeHead(status, {
1567
+ "Content-Type": "application/json; charset=utf-8",
1568
+ "Access-Control-Allow-Origin": "*"
1569
+ });
1570
+ res.end(JSON.stringify(data));
1571
+ }
1572
+ function parseBody(req) {
1573
+ return new Promise((resolve2, reject) => {
1574
+ let body = "";
1575
+ req.on("data", (chunk) => {
1576
+ body += chunk.toString();
1577
+ });
1578
+ req.on("end", () => {
1579
+ if (!body) return resolve2({});
1580
+ try {
1581
+ resolve2(JSON.parse(body));
1582
+ } catch {
1583
+ reject(new Error("Invalid JSON body"));
1584
+ }
1585
+ });
1586
+ req.on("error", reject);
1587
+ });
1588
+ }
1589
+ var API_ROUTES = {
1590
+ GET: {},
1591
+ POST: {}
1592
+ };
1593
+ API_ROUTES.GET["/api/skills"] = async (_req, res, url) => {
1594
+ try {
1595
+ const page = Math.max(1, parseInt(url.searchParams.get("page") || "1"));
1596
+ const limit = Math.min(100, Math.max(1, parseInt(url.searchParams.get("limit") || "20")));
1597
+ const search = url.searchParams.get("search") || "";
1598
+ const cacheKey = `search:${search}:limit:${limit}`;
1599
+ let searchResult = getCached(cacheKey);
1600
+ if (!searchResult) {
1601
+ searchResult = await searchSkillmarketPackages({
1602
+ from: 0,
1603
+ size: 100,
1604
+ // 一次拉取更多,避免分页
1605
+ keyword: search || void 0
1606
+ });
1607
+ setCache(cacheKey, searchResult, 3e4);
1608
+ }
1609
+ const { packages, total } = searchResult;
1610
+ const skillDetails = await throttledMap(packages, async (pkgName) => {
1611
+ try {
1612
+ const pkgCacheKey = `pkg:${pkgName}`;
1613
+ let info = getCached(pkgCacheKey);
1614
+ if (!info) {
1615
+ info = await fetchNpmPackage(pkgName);
1616
+ if (info) setCache(pkgCacheKey, info, 3e4);
1617
+ }
1618
+ if (!info) return null;
1619
+ const latestVersion = info["dist-tags"]?.latest || "unknown";
1620
+ const pkg = info.versions?.[latestVersion];
1621
+ const meta = pkg?.skillmarket;
1622
+ return {
1623
+ id: meta?.id || info.name.replace(/^@[^/]+\//, ""),
1624
+ name: info.name,
1625
+ displayName: meta?.displayName || info.name,
1626
+ version: latestVersion,
1627
+ description: pkg?.description || "",
1628
+ platforms: meta?.platforms || [],
1629
+ author: info.author?.name || pkg?.author?.name || "",
1630
+ homepage: pkg?.homepage || "",
1631
+ repository: pkg?.repository?.url || ""
1632
+ };
1633
+ } catch {
1634
+ return null;
1635
+ }
1636
+ }, 3);
1637
+ const skills = skillDetails.filter(Boolean);
1638
+ const totalPages = Math.ceil(total / limit) || 1;
1639
+ jsonResponse(res, 200, { skills, page, totalPages, total });
1640
+ } catch (err) {
1641
+ jsonResponse(res, 500, {
1642
+ error: String(err),
1643
+ skills: [],
1644
+ page: 1,
1645
+ totalPages: 1,
1646
+ total: 0
1647
+ });
1648
+ }
1649
+ };
1650
+ API_ROUTES.GET["/api/installed"] = async (_req, res, _url) => {
1651
+ try {
1652
+ const skills = await getInstalledSkills();
1653
+ jsonResponse(res, 200, skills.map((s) => ({
1654
+ id: s.id,
1655
+ displayName: s.id,
1656
+ version: s.version,
1657
+ installedAt: s.installedAt,
1658
+ platforms: s.platforms
1659
+ })));
1660
+ } catch (err) {
1661
+ jsonResponse(res, 500, { error: String(err) });
1662
+ }
1663
+ };
1664
+ API_ROUTES.GET["/api/platforms"] = async (_req, res, _url) => {
1665
+ try {
1666
+ const available = await detectPlatforms();
1667
+ const allAdapters = getAllAdapters();
1668
+ const platforms = await Promise.all(
1669
+ allAdapters.map(async (adapter) => {
1670
+ const isAvailable = available.find((a) => a.id === adapter.id);
1671
+ const installed = await adapter.listInstalled();
1672
+ return {
1673
+ id: adapter.id,
1674
+ name: adapter.name,
1675
+ available: !!isAvailable,
1676
+ installedCount: Array.isArray(installed) ? installed.length : 0
1677
+ };
1678
+ })
1679
+ );
1680
+ jsonResponse(res, 200, platforms);
1681
+ } catch (err) {
1682
+ jsonResponse(res, 500, { error: String(err) });
1683
+ }
1684
+ };
1685
+ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
1686
+ try {
1687
+ const skillName = url.searchParams.get("skill") || "";
1688
+ if (!skillName) {
1689
+ jsonResponse(res, 400, { error: 'Missing "skill" query parameter' });
1690
+ return;
1691
+ }
1692
+ const cacheKey = `skill-info:${skillName}`;
1693
+ let info = getCached(cacheKey);
1694
+ if (!info) {
1695
+ info = await fetchNpmPackage(skillName);
1696
+ if (info) setCache(cacheKey, info, 3e4);
1697
+ }
1698
+ if (!info) {
1699
+ jsonResponse(res, 404, { error: `Skill "${skillName}" not found` });
1700
+ return;
1701
+ }
1702
+ const latestVersion = info["dist-tags"]?.latest || "unknown";
1703
+ const pkg = latestVersion ? info.versions?.[latestVersion] : void 0;
1704
+ const meta = pkg?.skillmarket;
1705
+ const versionKeys = Object.keys(info.versions || {});
1706
+ const recentVersions = versionKeys.slice(-20);
1707
+ jsonResponse(res, 200, {
1708
+ id: meta?.id || info.name.replace(/^@[^/]+\//, ""),
1709
+ name: info.name,
1710
+ displayName: meta?.displayName || info.name,
1711
+ description: pkg?.description || "",
1712
+ version: latestVersion,
1713
+ platforms: meta?.platforms || [],
1714
+ versions: recentVersions,
1715
+ author: info.author?.name || pkg?.author?.name || "",
1716
+ license: info.license || "",
1717
+ homepage: pkg?.homepage || "",
1718
+ repository: pkg?.repository?.url || "",
1719
+ readme: info.readme || ""
1720
+ });
1721
+ } catch (err) {
1722
+ jsonResponse(res, 500, { error: String(err) });
1723
+ }
1724
+ };
1725
+ API_ROUTES.POST["/api/install"] = async (req, res, _url) => {
1726
+ try {
1727
+ const body = await parseBody(req);
1728
+ const skillId = String(body.skillId || "");
1729
+ const version = body.version ? String(body.version) : void 0;
1730
+ const platform = body.platform ? String(body.platform) : void 0;
1731
+ if (!skillId) {
1732
+ jsonResponse(res, 400, { error: "Missing skillId" });
1733
+ return;
1734
+ }
1735
+ await installSkill(skillId, version, {
1736
+ platforms: platform ? [platform] : void 0,
1737
+ force: true
1738
+ });
1739
+ jsonResponse(res, 200, { success: true, message: `${skillId} installed successfully` });
1740
+ } catch (err) {
1741
+ jsonResponse(res, 500, { error: String(err) });
1742
+ }
1743
+ };
1744
+ API_ROUTES.POST["/api/uninstall"] = async (req, res, _url) => {
1745
+ try {
1746
+ const body = await parseBody(req);
1747
+ const skillId = String(body.skillId || "");
1748
+ const platform = body.platform ? String(body.platform) : void 0;
1749
+ if (!skillId) {
1750
+ jsonResponse(res, 400, { error: "Missing skillId" });
1751
+ return;
1752
+ }
1753
+ await uninstallSkill(skillId, {
1754
+ platforms: platform ? [platform] : void 0,
1755
+ yes: true
1756
+ });
1757
+ jsonResponse(res, 200, { success: true, message: `${skillId} uninstalled successfully` });
1758
+ } catch (err) {
1759
+ jsonResponse(res, 500, { error: String(err) });
1760
+ }
1761
+ };
1762
+ API_ROUTES.POST["/api/update"] = async (req, res, _url) => {
1763
+ try {
1764
+ const body = await parseBody(req);
1765
+ const skillId = body.skillId ? String(body.skillId) : void 0;
1766
+ await updateSkill(skillId);
1767
+ const msg = skillId ? `${skillId} updated successfully` : "All skills updated successfully";
1768
+ jsonResponse(res, 200, { success: true, message: msg });
1769
+ } catch (err) {
1770
+ jsonResponse(res, 500, { error: String(err) });
1771
+ }
1772
+ };
1773
+ function serveStaticFile(res, filePath) {
1774
+ if (!existsSync4(filePath)) {
1775
+ res.writeHead(404, { "Content-Type": "text/plain" });
1776
+ res.end("Not Found");
1777
+ return;
1778
+ }
1779
+ const content = readFileSync(filePath);
1780
+ const ext = extname(filePath);
1781
+ const mime = MIME_TYPES[ext] || "application/octet-stream";
1782
+ res.writeHead(200, { "Content-Type": mime });
1783
+ res.end(content);
1784
+ }
1785
+ async function handleRequest(req, res) {
1786
+ const method = req.method || "GET";
1787
+ const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
1788
+ const pathname = url.pathname;
1789
+ const routeHandler = API_ROUTES[method]?.[pathname];
1790
+ if (routeHandler) {
1791
+ try {
1792
+ await routeHandler(req, res, url);
1793
+ } catch (err) {
1794
+ jsonResponse(res, 500, { error: String(err) });
1795
+ }
1796
+ return;
1797
+ }
1798
+ if (pathname.startsWith("/api/")) {
1799
+ jsonResponse(res, 404, { error: `Unknown API endpoint: ${method} ${pathname}` });
1800
+ return;
1801
+ }
1802
+ const filePath = join4(guiDir, pathname === "/" ? "index.html" : pathname);
1803
+ if (filePath.startsWith(guiDir)) {
1804
+ serveStaticFile(res, filePath);
1805
+ } else {
1806
+ res.writeHead(403);
1807
+ res.end("Forbidden");
1808
+ }
1809
+ }
1810
+ function startGuiServer(port = 18770) {
1811
+ const server = createServer(handleRequest);
1812
+ server.listen(port, () => {
1813
+ console.log(`
1814
+ \u{1F680} SkillMarket GUI started!`);
1815
+ console.log(` Local: http://localhost:${port}`);
1816
+ console.log(`
1817
+ Press Ctrl+C to stop
1818
+ `);
1819
+ });
1820
+ server.on("error", (err) => {
1821
+ if (err.code === "EADDRINUSE") {
1822
+ console.error(`\u274C Port ${port} is already in use. Try: skm gui ${port + 1}`);
1823
+ } else {
1824
+ console.error("\u274C Failed to start GUI server:", err.message);
1825
+ }
1826
+ process.exit(1);
1827
+ });
1828
+ }
1829
+
1381
1830
  // src/cli.ts
1382
- var __filename = fileURLToPath(import.meta.url);
1383
- var __dirname = dirname(__filename);
1384
- var packageJson = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf-8"));
1831
+ var __filename3 = fileURLToPath4(import.meta.url);
1832
+ var __dirname3 = dirname2(__filename3);
1833
+ var packageJson = JSON.parse(readFileSync2(resolve(__dirname3, "../package.json"), "utf-8"));
1385
1834
  var VERSION = packageJson.version || "1.3.1";
1386
1835
  var program = new Command();
1387
1836
  program.name("skm").description("SkillMarket - Cross-platform skill manager for AI coding tools").version(VERSION);
@@ -1550,4 +1999,24 @@ platformsCmd.action(async () => {
1550
1999
  process.exit(1);
1551
2000
  }
1552
2001
  });
2002
+ program.command("gui [port]").description("Start SkillMarket GUI (web interface)").action(async (port) => {
2003
+ const portNum = port ? parseInt(port) : 18770;
2004
+ startGuiServer(portNum);
2005
+ });
2006
+ 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) => {
2007
+ try {
2008
+ await publishSkill(skill, options.version ? { version: options.version } : void 0);
2009
+ } catch (err) {
2010
+ console.error("Publish failed:", err);
2011
+ process.exit(1);
2012
+ }
2013
+ });
2014
+ program.command("verify <skill>").description("Verify skill integrity and format").action(async (skill) => {
2015
+ try {
2016
+ await verifySkill(skill);
2017
+ } catch (err) {
2018
+ console.error("Verify failed:", err);
2019
+ process.exit(1);
2020
+ }
2021
+ });
1553
2022
  program.parse();