skillverse 0.1.6 → 0.1.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.
- package/dist/bin.js +526 -158
- package/dist/bin.js.map +1 -1
- package/dist/index.js +514 -158
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/public/assets/index-C5PzeRR6.css +1 -0
- package/public/assets/index-CHREpWKn.js +23 -0
- package/public/index.html +2 -2
- package/public/assets/index-Dd6kW-3f.js +0 -20
- package/public/assets/index-li8hN2px.css +0 -1
package/dist/index.js
CHANGED
|
@@ -816,8 +816,8 @@ import express from "express";
|
|
|
816
816
|
import cors from "cors";
|
|
817
817
|
import dotenv2 from "dotenv";
|
|
818
818
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
819
|
-
import { dirname as dirname3, join as
|
|
820
|
-
import { mkdir as
|
|
819
|
+
import { dirname as dirname3, join as join9 } from "path";
|
|
820
|
+
import { mkdir as mkdir6 } from "fs/promises";
|
|
821
821
|
import { existsSync as existsSync9 } from "fs";
|
|
822
822
|
|
|
823
823
|
// src/routes/skills.ts
|
|
@@ -1118,7 +1118,7 @@ ${relativeSkillsPath}/
|
|
|
1118
1118
|
if (!existsSync3(skillsPath)) {
|
|
1119
1119
|
return [];
|
|
1120
1120
|
}
|
|
1121
|
-
const { readdir: readdir2, stat: stat2, readFile:
|
|
1121
|
+
const { readdir: readdir2, stat: stat2, readFile: readFile4 } = await import("fs/promises");
|
|
1122
1122
|
const items = await readdir2(skillsPath);
|
|
1123
1123
|
const existingSkills = [];
|
|
1124
1124
|
for (const item of items) {
|
|
@@ -1159,7 +1159,7 @@ ${relativeSkillsPath}/
|
|
|
1159
1159
|
if (!existsSync3(SKILLS_DIR)) {
|
|
1160
1160
|
await mkdir2(SKILLS_DIR, { recursive: true });
|
|
1161
1161
|
}
|
|
1162
|
-
const { rename, readFile:
|
|
1162
|
+
const { rename, readFile: readFile4, cp: cp2 } = await import("fs/promises");
|
|
1163
1163
|
const migrated = [];
|
|
1164
1164
|
const errors = [];
|
|
1165
1165
|
for (const skillName of skillNames) {
|
|
@@ -1192,7 +1192,7 @@ ${relativeSkillsPath}/
|
|
|
1192
1192
|
if (existsSync3(skillMdPath)) {
|
|
1193
1193
|
try {
|
|
1194
1194
|
const matter2 = await import("gray-matter");
|
|
1195
|
-
const fileContent = await
|
|
1195
|
+
const fileContent = await readFile4(skillMdPath, "utf-8");
|
|
1196
1196
|
const parsed = matter2.default(fileContent);
|
|
1197
1197
|
description = parsed.data.description || "";
|
|
1198
1198
|
metadata = parsed.data;
|
|
@@ -1462,7 +1462,7 @@ router.post("/:id/refresh-metadata", async (req, res, next) => {
|
|
|
1462
1462
|
});
|
|
1463
1463
|
router.get("/:id/skill-md", async (req, res, next) => {
|
|
1464
1464
|
try {
|
|
1465
|
-
const { readFile:
|
|
1465
|
+
const { readFile: readFile4 } = await import("fs/promises");
|
|
1466
1466
|
const skill = await skillService.getSkillById(req.params.id);
|
|
1467
1467
|
const skillMdPath = join4(skill.storagePath, "SKILL.md");
|
|
1468
1468
|
if (!existsSync4(skillMdPath)) {
|
|
@@ -1474,7 +1474,7 @@ router.get("/:id/skill-md", async (req, res, next) => {
|
|
|
1474
1474
|
}
|
|
1475
1475
|
});
|
|
1476
1476
|
}
|
|
1477
|
-
const content = await
|
|
1477
|
+
const content = await readFile4(skillMdPath, "utf-8");
|
|
1478
1478
|
res.json({
|
|
1479
1479
|
success: true,
|
|
1480
1480
|
data: {
|
|
@@ -1629,7 +1629,6 @@ router2.post("/:id/migrate-skills", async (req, res, next) => {
|
|
|
1629
1629
|
var workspaces_default = router2;
|
|
1630
1630
|
|
|
1631
1631
|
// src/routes/marketplace.ts
|
|
1632
|
-
init_db();
|
|
1633
1632
|
init_skillService();
|
|
1634
1633
|
import { Router as Router3 } from "express";
|
|
1635
1634
|
|
|
@@ -1716,41 +1715,278 @@ var bundleService = {
|
|
|
1716
1715
|
// src/routes/marketplace.ts
|
|
1717
1716
|
init_errorHandler();
|
|
1718
1717
|
init_dist();
|
|
1718
|
+
init_db();
|
|
1719
1719
|
import { existsSync as existsSync6 } from "fs";
|
|
1720
|
+
import { join as join6 } from "path";
|
|
1721
|
+
import { mkdir as mkdir5, rm as rm5, writeFile } from "fs/promises";
|
|
1722
|
+
|
|
1723
|
+
// src/services/githubMarketplaceRegistry.ts
|
|
1724
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
1725
|
+
import { createHash } from "crypto";
|
|
1726
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1727
|
+
function sha256Hex(buf) {
|
|
1728
|
+
return createHash("sha256").update(buf).digest("hex");
|
|
1729
|
+
}
|
|
1730
|
+
function nowIso() {
|
|
1731
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1732
|
+
}
|
|
1733
|
+
function normalizeIndex(index) {
|
|
1734
|
+
const base = {
|
|
1735
|
+
version: typeof index?.version === "number" ? index.version : 1,
|
|
1736
|
+
updatedAt: typeof index?.updatedAt === "string" ? index.updatedAt : nowIso(),
|
|
1737
|
+
skills: Array.isArray(index?.skills) ? index.skills : []
|
|
1738
|
+
};
|
|
1739
|
+
return base;
|
|
1740
|
+
}
|
|
1741
|
+
async function requireOctokit() {
|
|
1742
|
+
const mod = await import("octokit");
|
|
1743
|
+
return mod.Octokit;
|
|
1744
|
+
}
|
|
1745
|
+
var GitHubMarketplaceRegistry = class {
|
|
1746
|
+
constructor(cfg) {
|
|
1747
|
+
this.cfg = cfg;
|
|
1748
|
+
}
|
|
1749
|
+
getIndexPath() {
|
|
1750
|
+
return this.cfg.indexPath || "index.json";
|
|
1751
|
+
}
|
|
1752
|
+
async octokit() {
|
|
1753
|
+
const Octokit = await requireOctokit();
|
|
1754
|
+
return new Octokit({ auth: this.cfg.token });
|
|
1755
|
+
}
|
|
1756
|
+
async fetchIndexFromPages() {
|
|
1757
|
+
const resp = await fetch(this.cfg.indexUrl, { method: "GET" });
|
|
1758
|
+
if (!resp.ok) {
|
|
1759
|
+
throw new Error(`Failed to fetch marketplace index from Pages: ${resp.status} ${resp.statusText}`);
|
|
1760
|
+
}
|
|
1761
|
+
const json = await resp.json();
|
|
1762
|
+
return normalizeIndex(json);
|
|
1763
|
+
}
|
|
1764
|
+
async readIndexFromRepo() {
|
|
1765
|
+
const octokit = await this.octokit();
|
|
1766
|
+
const path = this.getIndexPath();
|
|
1767
|
+
const res = await octokit.rest.repos.getContent({
|
|
1768
|
+
owner: this.cfg.owner,
|
|
1769
|
+
repo: this.cfg.repo,
|
|
1770
|
+
path,
|
|
1771
|
+
ref: this.cfg.branch
|
|
1772
|
+
});
|
|
1773
|
+
if (Array.isArray(res.data) || res.data.type !== "file") {
|
|
1774
|
+
throw new Error(`Invalid index path in repo: ${path}`);
|
|
1775
|
+
}
|
|
1776
|
+
const content = Buffer2.from(res.data.content, res.data.encoding).toString("utf-8");
|
|
1777
|
+
const parsed = JSON.parse(content);
|
|
1778
|
+
return { index: normalizeIndex(parsed), sha: res.data.sha };
|
|
1779
|
+
}
|
|
1780
|
+
async upsertIndexToRepo(index, previousSha) {
|
|
1781
|
+
const octokit = await this.octokit();
|
|
1782
|
+
const path = this.getIndexPath();
|
|
1783
|
+
const body = JSON.stringify(
|
|
1784
|
+
{
|
|
1785
|
+
...index,
|
|
1786
|
+
updatedAt: nowIso()
|
|
1787
|
+
},
|
|
1788
|
+
null,
|
|
1789
|
+
2
|
|
1790
|
+
);
|
|
1791
|
+
const contentBase64 = Buffer2.from(body, "utf-8").toString("base64");
|
|
1792
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
1793
|
+
owner: this.cfg.owner,
|
|
1794
|
+
repo: this.cfg.repo,
|
|
1795
|
+
branch: this.cfg.branch,
|
|
1796
|
+
path,
|
|
1797
|
+
message: `chore(marketplace): update ${path}`,
|
|
1798
|
+
content: contentBase64,
|
|
1799
|
+
...previousSha ? { sha: previousSha } : {}
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
async createReleaseWithAsset(params) {
|
|
1803
|
+
const octokit = await this.octokit();
|
|
1804
|
+
const bundleBuf = await readFile3(params.bundlePath);
|
|
1805
|
+
const sha256 = sha256Hex(bundleBuf);
|
|
1806
|
+
const bundleSize = bundleBuf.byteLength;
|
|
1807
|
+
const safeName = params.skillName.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
1808
|
+
const safeVer = params.skillVersion.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
1809
|
+
const tag = `skillverse-marketplace/${safeName}/v${safeVer}/${Date.now()}`;
|
|
1810
|
+
const release = await octokit.rest.repos.createRelease({
|
|
1811
|
+
owner: this.cfg.owner,
|
|
1812
|
+
repo: this.cfg.repo,
|
|
1813
|
+
tag_name: tag,
|
|
1814
|
+
name: `SkillVerse Marketplace: ${params.skillName}@${params.skillVersion}`,
|
|
1815
|
+
body: params.description || "",
|
|
1816
|
+
draft: false,
|
|
1817
|
+
prerelease: false,
|
|
1818
|
+
target_commitish: this.cfg.branch
|
|
1819
|
+
});
|
|
1820
|
+
const assetName = `${safeName}-${safeVer}.tar.gz`;
|
|
1821
|
+
const uploadRes = await octokit.rest.repos.uploadReleaseAsset({
|
|
1822
|
+
owner: this.cfg.owner,
|
|
1823
|
+
repo: this.cfg.repo,
|
|
1824
|
+
release_id: release.data.id,
|
|
1825
|
+
name: assetName,
|
|
1826
|
+
data: bundleBuf,
|
|
1827
|
+
headers: {
|
|
1828
|
+
"content-type": "application/gzip",
|
|
1829
|
+
"content-length": bundleSize
|
|
1830
|
+
}
|
|
1831
|
+
});
|
|
1832
|
+
return {
|
|
1833
|
+
bundleUrl: uploadRes.data.browser_download_url,
|
|
1834
|
+
bundleSize,
|
|
1835
|
+
sha256,
|
|
1836
|
+
tag
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
upsertSkillEntry(index, entry) {
|
|
1840
|
+
const createdAt = nowIso();
|
|
1841
|
+
const existingIdx = index.skills.findIndex((s) => s?.name === entry.name && s?.type === entry.type);
|
|
1842
|
+
if (existingIdx >= 0) {
|
|
1843
|
+
const prev = index.skills[existingIdx];
|
|
1844
|
+
index.skills[existingIdx] = {
|
|
1845
|
+
...prev,
|
|
1846
|
+
...entry,
|
|
1847
|
+
updatedAt: nowIso(),
|
|
1848
|
+
createdAt: prev.createdAt || createdAt
|
|
1849
|
+
};
|
|
1850
|
+
} else {
|
|
1851
|
+
index.skills.push({
|
|
1852
|
+
...entry,
|
|
1853
|
+
createdAt,
|
|
1854
|
+
updatedAt: nowIso()
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
return index;
|
|
1858
|
+
}
|
|
1859
|
+
static stableIdForEntry(entry) {
|
|
1860
|
+
const key = entry.type === "git" ? `git:${entry.name}:${entry.gitUrl}` : `bundle:${entry.name}:${entry.skillVersion || ""}:${entry.bundleUrl}`;
|
|
1861
|
+
return createHash("sha256").update(key).digest("hex").slice(0, 24);
|
|
1862
|
+
}
|
|
1863
|
+
async deleteReleaseByTag(tag) {
|
|
1864
|
+
const octokit = await this.octokit();
|
|
1865
|
+
let releaseId;
|
|
1866
|
+
let page = 1;
|
|
1867
|
+
const perPage = 30;
|
|
1868
|
+
while (!releaseId) {
|
|
1869
|
+
const { data: releases } = await octokit.rest.repos.listReleases({
|
|
1870
|
+
owner: this.cfg.owner,
|
|
1871
|
+
repo: this.cfg.repo,
|
|
1872
|
+
page,
|
|
1873
|
+
per_page: perPage
|
|
1874
|
+
});
|
|
1875
|
+
if (releases.length === 0) break;
|
|
1876
|
+
const found = releases.find((r) => r.tag_name === tag);
|
|
1877
|
+
if (found) {
|
|
1878
|
+
releaseId = found.id;
|
|
1879
|
+
break;
|
|
1880
|
+
}
|
|
1881
|
+
page++;
|
|
1882
|
+
}
|
|
1883
|
+
if (!releaseId) {
|
|
1884
|
+
console.warn(`Release with tag "${tag}" not found, skipping deletion.`);
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
await octokit.rest.repos.deleteRelease({
|
|
1888
|
+
owner: this.cfg.owner,
|
|
1889
|
+
repo: this.cfg.repo,
|
|
1890
|
+
release_id: releaseId
|
|
1891
|
+
});
|
|
1892
|
+
try {
|
|
1893
|
+
await octokit.rest.git.deleteRef({
|
|
1894
|
+
owner: this.cfg.owner,
|
|
1895
|
+
repo: this.cfg.repo,
|
|
1896
|
+
ref: `tags/${tag}`
|
|
1897
|
+
});
|
|
1898
|
+
} catch (e) {
|
|
1899
|
+
console.warn(`Failed to delete git tag ref "tags/${tag}":`, e.message);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
|
|
1904
|
+
// src/marketplaceConfig.ts
|
|
1905
|
+
var marketplaceConfig = {
|
|
1906
|
+
indexUrl: "https://fdksd.github.io/skillverse-marketplace/index.json",
|
|
1907
|
+
owner: "fdksd",
|
|
1908
|
+
repo: "skillverse-marketplace",
|
|
1909
|
+
branch: "main",
|
|
1910
|
+
token: "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"
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1913
|
+
// src/routes/marketplace.ts
|
|
1720
1914
|
var router3 = Router3();
|
|
1915
|
+
function requireMarketplaceGitHubConfig() {
|
|
1916
|
+
const { indexUrl, owner, repo, branch, token } = marketplaceConfig;
|
|
1917
|
+
if (!indexUrl) {
|
|
1918
|
+
throw new AppError(
|
|
1919
|
+
ErrorCode.VALIDATION_ERROR,
|
|
1920
|
+
"Marketplace indexUrl is not configured.",
|
|
1921
|
+
400
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
return {
|
|
1925
|
+
indexUrl,
|
|
1926
|
+
owner,
|
|
1927
|
+
repo,
|
|
1928
|
+
branch,
|
|
1929
|
+
token,
|
|
1930
|
+
indexPath: "index.json"
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
function mapIndexToMarketplaceItems(index, search) {
|
|
1934
|
+
const query = (search || "").trim().toLowerCase();
|
|
1935
|
+
const skills = index.skills || [];
|
|
1936
|
+
const filtered = query ? skills.filter((s) => {
|
|
1937
|
+
const name = String(s?.name || "").toLowerCase();
|
|
1938
|
+
const desc = String(s?.description || "").toLowerCase();
|
|
1939
|
+
return name.includes(query) || desc.includes(query);
|
|
1940
|
+
}) : skills;
|
|
1941
|
+
return filtered.map((entry) => {
|
|
1942
|
+
const id = GitHubMarketplaceRegistry.stableIdForEntry(entry);
|
|
1943
|
+
const publishDate = entry.createdAt || entry.updatedAt || index.updatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
1944
|
+
return {
|
|
1945
|
+
id,
|
|
1946
|
+
skillId: id,
|
|
1947
|
+
publisherId: void 0,
|
|
1948
|
+
publisherName: entry.publisherName || "Anonymous",
|
|
1949
|
+
publishDate: new Date(publishDate),
|
|
1950
|
+
downloads: entry.downloads || 0,
|
|
1951
|
+
skill: {
|
|
1952
|
+
id,
|
|
1953
|
+
name: entry.name,
|
|
1954
|
+
source: entry.type === "git" ? "git" : "local",
|
|
1955
|
+
sourceUrl: entry.type === "git" ? entry.gitUrl : void 0,
|
|
1956
|
+
description: entry.description || "",
|
|
1957
|
+
commitHash: void 0,
|
|
1958
|
+
repoUrl: entry.type === "git" ? entry.gitUrl : void 0,
|
|
1959
|
+
updateAvailable: false,
|
|
1960
|
+
lastUpdateCheck: void 0,
|
|
1961
|
+
installDate: new Date(publishDate),
|
|
1962
|
+
metadata: {
|
|
1963
|
+
marketplace: entry
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
async function fetchIndex() {
|
|
1970
|
+
const ghCfg = requireMarketplaceGitHubConfig();
|
|
1971
|
+
const registry = new GitHubMarketplaceRegistry(ghCfg);
|
|
1972
|
+
return await registry.fetchIndexFromPages();
|
|
1973
|
+
}
|
|
1721
1974
|
router3.get("/skills", async (req, res, next) => {
|
|
1722
1975
|
try {
|
|
1723
1976
|
const { search, page = "1", pageSize = "20" } = req.query;
|
|
1724
|
-
const
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
]
|
|
1731
|
-
};
|
|
1732
|
-
}
|
|
1733
|
-
const [items, total] = await Promise.all([
|
|
1734
|
-
prisma.marketplaceSkill.findMany({
|
|
1735
|
-
where,
|
|
1736
|
-
include: {
|
|
1737
|
-
skill: true
|
|
1738
|
-
},
|
|
1739
|
-
orderBy: {
|
|
1740
|
-
downloads: "desc"
|
|
1741
|
-
},
|
|
1742
|
-
skip: (parseInt(page) - 1) * parseInt(pageSize),
|
|
1743
|
-
take: parseInt(pageSize)
|
|
1744
|
-
}),
|
|
1745
|
-
prisma.marketplaceSkill.count({ where })
|
|
1746
|
-
]);
|
|
1977
|
+
const index = await fetchIndex();
|
|
1978
|
+
const allItems = mapIndexToMarketplaceItems(index, search);
|
|
1979
|
+
const p = parseInt(page);
|
|
1980
|
+
const ps = parseInt(pageSize);
|
|
1981
|
+
const total = allItems.length;
|
|
1982
|
+
const items = allItems.slice((p - 1) * ps, (p - 1) * ps + ps);
|
|
1747
1983
|
res.json({
|
|
1748
1984
|
success: true,
|
|
1749
1985
|
data: {
|
|
1750
1986
|
items,
|
|
1751
1987
|
total,
|
|
1752
|
-
page:
|
|
1753
|
-
pageSize:
|
|
1988
|
+
page: p,
|
|
1989
|
+
pageSize: ps
|
|
1754
1990
|
}
|
|
1755
1991
|
});
|
|
1756
1992
|
} catch (error) {
|
|
@@ -1759,12 +1995,9 @@ router3.get("/skills", async (req, res, next) => {
|
|
|
1759
1995
|
});
|
|
1760
1996
|
router3.get("/skills/:id", async (req, res, next) => {
|
|
1761
1997
|
try {
|
|
1762
|
-
const
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
skill: true
|
|
1766
|
-
}
|
|
1767
|
-
});
|
|
1998
|
+
const index = await fetchIndex();
|
|
1999
|
+
const items = mapIndexToMarketplaceItems(index);
|
|
2000
|
+
const marketplaceSkill = items.find((i) => i.id === req.params.id);
|
|
1768
2001
|
if (!marketplaceSkill) {
|
|
1769
2002
|
throw new AppError(ErrorCode.NOT_FOUND, "Marketplace skill not found", 404);
|
|
1770
2003
|
}
|
|
@@ -1778,33 +2011,48 @@ router3.get("/skills/:id", async (req, res, next) => {
|
|
|
1778
2011
|
});
|
|
1779
2012
|
router3.get("/download/:id", async (req, res, next) => {
|
|
1780
2013
|
try {
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2014
|
+
const ghCfg = requireMarketplaceGitHubConfig();
|
|
2015
|
+
const registry = new GitHubMarketplaceRegistry(ghCfg);
|
|
2016
|
+
let index;
|
|
2017
|
+
let sha;
|
|
2018
|
+
try {
|
|
2019
|
+
const result = await registry.readIndexFromRepo();
|
|
2020
|
+
index = result.index;
|
|
2021
|
+
sha = result.sha;
|
|
2022
|
+
} catch (e) {
|
|
2023
|
+
console.warn("Failed to read index from repo, falling back to cached:", e);
|
|
2024
|
+
index = await fetchIndex();
|
|
2025
|
+
}
|
|
2026
|
+
const entryIndex = (index.skills || []).findIndex(
|
|
2027
|
+
(s) => GitHubMarketplaceRegistry.stableIdForEntry(s) === req.params.id
|
|
2028
|
+
);
|
|
2029
|
+
const entry = entryIndex >= 0 ? index.skills[entryIndex] : void 0;
|
|
2030
|
+
if (!entry) throw new AppError(ErrorCode.NOT_FOUND, "Marketplace skill not found", 404);
|
|
2031
|
+
if (sha) {
|
|
2032
|
+
try {
|
|
2033
|
+
entry.downloads = (entry.downloads || 0) + 1;
|
|
2034
|
+
index.skills[entryIndex] = entry;
|
|
2035
|
+
await registry.upsertIndexToRepo(index, sha);
|
|
2036
|
+
} catch (e) {
|
|
2037
|
+
console.warn("Failed to update download count:", e);
|
|
1785
2038
|
}
|
|
1786
|
-
});
|
|
1787
|
-
if (!marketplaceSkill) {
|
|
1788
|
-
throw new AppError(ErrorCode.NOT_FOUND, "Marketplace skill not found", 404);
|
|
1789
2039
|
}
|
|
1790
|
-
if (
|
|
2040
|
+
if (entry.type === "git") {
|
|
1791
2041
|
return res.json({
|
|
1792
2042
|
success: true,
|
|
1793
|
-
data: {
|
|
1794
|
-
type: "git",
|
|
1795
|
-
sourceUrl: marketplaceSkill.skill.sourceUrl
|
|
1796
|
-
}
|
|
2043
|
+
data: { type: "git", sourceUrl: entry.gitUrl }
|
|
1797
2044
|
});
|
|
1798
2045
|
}
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
"
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2046
|
+
return res.json({
|
|
2047
|
+
success: true,
|
|
2048
|
+
data: {
|
|
2049
|
+
type: "bundle",
|
|
2050
|
+
bundleUrl: entry.bundleUrl,
|
|
2051
|
+
bundleSize: entry.bundleSize,
|
|
2052
|
+
sha256: entry.sha256,
|
|
2053
|
+
skillVersion: entry.skillVersion
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
1808
2056
|
} catch (error) {
|
|
1809
2057
|
next(error);
|
|
1810
2058
|
}
|
|
@@ -1818,38 +2066,74 @@ router3.post("/publish", async (req, res, next) => {
|
|
|
1818
2066
|
error: "skillId is required"
|
|
1819
2067
|
});
|
|
1820
2068
|
}
|
|
1821
|
-
const skill = await
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
});
|
|
1830
|
-
if (existingEntry) {
|
|
1831
|
-
throw new AppError(ErrorCode.ALREADY_EXISTS, "Skill is already published to marketplace", 409);
|
|
1832
|
-
}
|
|
1833
|
-
let bundlePath = null;
|
|
1834
|
-
let bundleSize = null;
|
|
1835
|
-
if (skill.source === "local" && existsSync6(skill.storagePath)) {
|
|
1836
|
-
bundlePath = await bundleService.createBundle(skill.storagePath, skill.name);
|
|
1837
|
-
bundleSize = await bundleService.getBundleSize(bundlePath);
|
|
2069
|
+
const skill = await skillService.getSkillById(skillId);
|
|
2070
|
+
const ghCfg = requireMarketplaceGitHubConfig();
|
|
2071
|
+
if (!ghCfg.owner || !ghCfg.repo || !ghCfg.branch || !ghCfg.token) {
|
|
2072
|
+
throw new AppError(
|
|
2073
|
+
ErrorCode.VALIDATION_ERROR,
|
|
2074
|
+
"GitHub registry config is incomplete. Please set owner/repo/branch/token in Settings -> Marketplace.",
|
|
2075
|
+
400
|
|
2076
|
+
);
|
|
1838
2077
|
}
|
|
1839
|
-
const
|
|
1840
|
-
|
|
1841
|
-
|
|
2078
|
+
const registry = new GitHubMarketplaceRegistry(ghCfg);
|
|
2079
|
+
const { index, sha } = await registry.readIndexFromRepo();
|
|
2080
|
+
if (skill.source === "git") {
|
|
2081
|
+
if (!skill.sourceUrl) {
|
|
2082
|
+
throw new AppError(ErrorCode.VALIDATION_ERROR, "Git skill is missing sourceUrl", 400);
|
|
2083
|
+
}
|
|
2084
|
+
registry.upsertSkillEntry(index, {
|
|
2085
|
+
type: "git",
|
|
2086
|
+
name: skill.name,
|
|
2087
|
+
description: skill.description || "",
|
|
1842
2088
|
publisherName: publisherName || "Anonymous",
|
|
2089
|
+
gitUrl: skill.sourceUrl
|
|
2090
|
+
});
|
|
2091
|
+
} else {
|
|
2092
|
+
if (!existsSync6(skill.storagePath)) {
|
|
2093
|
+
throw new AppError(ErrorCode.FILE_SYSTEM_ERROR, "Skill files not found on disk", 400);
|
|
2094
|
+
}
|
|
2095
|
+
const bundlePath = await bundleService.createBundle(skill.storagePath, skill.name);
|
|
2096
|
+
const parsedMeta = (() => {
|
|
2097
|
+
try {
|
|
2098
|
+
return skill.metadata ? JSON.parse(skill.metadata) : {};
|
|
2099
|
+
} catch {
|
|
2100
|
+
return {};
|
|
2101
|
+
}
|
|
2102
|
+
})();
|
|
2103
|
+
const skillVersion = String(parsedMeta.version || parsedMeta.skillVersion || "1.0.0");
|
|
2104
|
+
const uploaded = await registry.createReleaseWithAsset({
|
|
2105
|
+
skillName: skill.name,
|
|
2106
|
+
skillVersion,
|
|
1843
2107
|
bundlePath,
|
|
1844
|
-
|
|
2108
|
+
description: skill.description || ""
|
|
2109
|
+
});
|
|
2110
|
+
registry.upsertSkillEntry(index, {
|
|
2111
|
+
type: "bundle",
|
|
2112
|
+
name: skill.name,
|
|
2113
|
+
description: skill.description || "",
|
|
2114
|
+
publisherName: publisherName || "Anonymous",
|
|
2115
|
+
bundleUrl: uploaded.bundleUrl,
|
|
2116
|
+
bundleSize: uploaded.bundleSize,
|
|
2117
|
+
sha256: uploaded.sha256,
|
|
2118
|
+
skillVersion
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
await registry.upsertIndexToRepo(index, sha);
|
|
2122
|
+
await prisma.marketplaceSkill.upsert({
|
|
2123
|
+
where: { skillId: skill.id },
|
|
2124
|
+
create: {
|
|
2125
|
+
skillId: skill.id,
|
|
2126
|
+
publisherName: publisherName || "Anonymous",
|
|
2127
|
+
downloads: 0
|
|
1845
2128
|
},
|
|
1846
|
-
|
|
1847
|
-
|
|
2129
|
+
update: {
|
|
2130
|
+
publisherName: publisherName || "Anonymous",
|
|
2131
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1848
2132
|
}
|
|
1849
2133
|
});
|
|
1850
2134
|
res.status(201).json({
|
|
1851
2135
|
success: true,
|
|
1852
|
-
data:
|
|
2136
|
+
data: { ok: true },
|
|
1853
2137
|
message: "Skill published to marketplace successfully"
|
|
1854
2138
|
});
|
|
1855
2139
|
} catch (error) {
|
|
@@ -1858,66 +2142,117 @@ router3.post("/publish", async (req, res, next) => {
|
|
|
1858
2142
|
});
|
|
1859
2143
|
router3.post("/install/:id", async (req, res, next) => {
|
|
1860
2144
|
try {
|
|
1861
|
-
const
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2145
|
+
const ghCfg = requireMarketplaceGitHubConfig();
|
|
2146
|
+
const registry = new GitHubMarketplaceRegistry(ghCfg);
|
|
2147
|
+
let index;
|
|
2148
|
+
let sha;
|
|
2149
|
+
try {
|
|
2150
|
+
const result = await registry.readIndexFromRepo();
|
|
2151
|
+
index = result.index;
|
|
2152
|
+
sha = result.sha;
|
|
2153
|
+
} catch (e) {
|
|
2154
|
+
console.warn("Failed to read index from repo for install count:", e);
|
|
2155
|
+
index = await fetchIndex();
|
|
2156
|
+
}
|
|
2157
|
+
const entryIndex = (index.skills || []).findIndex(
|
|
2158
|
+
(s) => GitHubMarketplaceRegistry.stableIdForEntry(s) === req.params.id
|
|
2159
|
+
);
|
|
2160
|
+
const entry = entryIndex >= 0 ? index.skills[entryIndex] : void 0;
|
|
2161
|
+
if (!entry) throw new AppError(ErrorCode.NOT_FOUND, "Marketplace skill not found", 404);
|
|
2162
|
+
if (sha) {
|
|
2163
|
+
try {
|
|
2164
|
+
entry.downloads = (entry.downloads || 0) + 1;
|
|
2165
|
+
index.skills[entryIndex] = entry;
|
|
2166
|
+
await registry.upsertIndexToRepo(index, sha);
|
|
2167
|
+
} catch (e) {
|
|
2168
|
+
console.warn("Failed to update download count:", e);
|
|
1865
2169
|
}
|
|
1866
|
-
});
|
|
1867
|
-
if (!marketplaceSkill) {
|
|
1868
|
-
throw new AppError(ErrorCode.NOT_FOUND, "Marketplace skill not found", 404);
|
|
1869
2170
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
const newSkill = await skillService.createSkillFromGit(
|
|
1873
|
-
sourceSkill.sourceUrl,
|
|
1874
|
-
sourceSkill.description || void 0
|
|
1875
|
-
);
|
|
1876
|
-
await prisma.marketplaceSkill.update({
|
|
1877
|
-
where: { id: req.params.id },
|
|
1878
|
-
data: { downloads: { increment: 1 } }
|
|
1879
|
-
});
|
|
2171
|
+
if (entry.type === "git") {
|
|
2172
|
+
const newSkill = await skillService.createSkillFromGit(entry.gitUrl, entry.description || void 0);
|
|
1880
2173
|
return res.status(201).json({
|
|
1881
2174
|
success: true,
|
|
1882
2175
|
data: newSkill,
|
|
1883
2176
|
message: "Skill installed from marketplace successfully"
|
|
1884
2177
|
});
|
|
1885
2178
|
}
|
|
1886
|
-
|
|
2179
|
+
const tempDir = process.env.TEMP_DIR || join6(process.env.HOME || "", ".skillverse", "temp");
|
|
2180
|
+
await mkdir5(tempDir, { recursive: true });
|
|
2181
|
+
const resp = await fetch(entry.bundleUrl);
|
|
2182
|
+
if (!resp.ok) {
|
|
2183
|
+
throw new AppError(
|
|
2184
|
+
ErrorCode.INTERNAL_ERROR,
|
|
2185
|
+
`Failed to download bundle: ${resp.status} ${resp.statusText}`,
|
|
2186
|
+
502
|
|
2187
|
+
);
|
|
2188
|
+
}
|
|
2189
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
2190
|
+
const tmpPath = join6(tempDir, `marketplace-${entry.name}-${Date.now()}.tar.gz`);
|
|
2191
|
+
await writeFile(tmpPath, buf);
|
|
2192
|
+
try {
|
|
1887
2193
|
const newSkill = await skillService.createSkillFromBundle(
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
2194
|
+
tmpPath,
|
|
2195
|
+
entry.name,
|
|
2196
|
+
entry.description || void 0
|
|
1891
2197
|
);
|
|
1892
|
-
await prisma.marketplaceSkill.update({
|
|
1893
|
-
where: { id: req.params.id },
|
|
1894
|
-
data: { downloads: { increment: 1 } }
|
|
1895
|
-
});
|
|
1896
2198
|
return res.status(201).json({
|
|
1897
2199
|
success: true,
|
|
1898
2200
|
data: newSkill,
|
|
1899
2201
|
message: "Skill installed from marketplace successfully"
|
|
1900
2202
|
});
|
|
2203
|
+
} finally {
|
|
2204
|
+
await rm5(tmpPath, { force: true }).catch(() => {
|
|
2205
|
+
});
|
|
1901
2206
|
}
|
|
1902
|
-
return res.status(400).json({
|
|
1903
|
-
success: false,
|
|
1904
|
-
error: "Cannot install this skill. Bundle not available."
|
|
1905
|
-
});
|
|
1906
2207
|
} catch (error) {
|
|
1907
2208
|
next(error);
|
|
1908
2209
|
}
|
|
1909
2210
|
});
|
|
1910
2211
|
router3.delete("/unpublish/:skillId", async (req, res, next) => {
|
|
1911
2212
|
try {
|
|
1912
|
-
const
|
|
1913
|
-
|
|
2213
|
+
const skill = await skillService.getSkillById(req.params.skillId);
|
|
2214
|
+
const ghCfg = requireMarketplaceGitHubConfig();
|
|
2215
|
+
if (!ghCfg.owner || !ghCfg.repo || !ghCfg.branch || !ghCfg.token) {
|
|
2216
|
+
throw new AppError(
|
|
2217
|
+
ErrorCode.VALIDATION_ERROR,
|
|
2218
|
+
"GitHub registry config is incomplete. Please set owner/repo/branch/token in Settings -> Marketplace.",
|
|
2219
|
+
400
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
const registry = new GitHubMarketplaceRegistry(ghCfg);
|
|
2223
|
+
const { index, sha } = await registry.readIndexFromRepo();
|
|
2224
|
+
const before = index.skills.length;
|
|
2225
|
+
const entryToRemove = index.skills.find((s) => {
|
|
2226
|
+
if (s?.name !== skill.name) return false;
|
|
2227
|
+
if (skill.source === "git") return s.type === "git";
|
|
2228
|
+
return s.type === "bundle";
|
|
1914
2229
|
});
|
|
1915
|
-
if (
|
|
2230
|
+
if (entryToRemove) {
|
|
2231
|
+
if (entryToRemove.type === "bundle" && entryToRemove.bundleUrl) {
|
|
2232
|
+
try {
|
|
2233
|
+
const match = entryToRemove.bundleUrl.match(/\/releases\/download\/(.+)\/[^/]+$/);
|
|
2234
|
+
if (match && match[1]) {
|
|
2235
|
+
const tag = decodeURIComponent(match[1]);
|
|
2236
|
+
console.log(`Deleting release tag: ${tag}`);
|
|
2237
|
+
await registry.deleteReleaseByTag(tag);
|
|
2238
|
+
}
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
console.warn("Failed to delete GitHub release:", e);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
index.skills = index.skills.filter((s) => s !== entryToRemove);
|
|
2244
|
+
}
|
|
2245
|
+
const after = index.skills.length;
|
|
2246
|
+
if (before === after) {
|
|
1916
2247
|
throw new AppError(ErrorCode.NOT_FOUND, "Skill is not published to marketplace", 404);
|
|
1917
2248
|
}
|
|
1918
|
-
await
|
|
1919
|
-
|
|
1920
|
-
|
|
2249
|
+
await registry.upsertIndexToRepo(index, sha);
|
|
2250
|
+
try {
|
|
2251
|
+
await prisma.marketplaceSkill.delete({
|
|
2252
|
+
where: { skillId: skill.id }
|
|
2253
|
+
});
|
|
2254
|
+
} catch (e) {
|
|
2255
|
+
}
|
|
1921
2256
|
res.json({
|
|
1922
2257
|
success: true,
|
|
1923
2258
|
message: "Skill unpublished from marketplace successfully"
|
|
@@ -2023,16 +2358,16 @@ var dashboard_default = router4;
|
|
|
2023
2358
|
|
|
2024
2359
|
// src/routes/config.ts
|
|
2025
2360
|
import { Router as Router5 } from "express";
|
|
2026
|
-
import { join as
|
|
2027
|
-
import { existsSync as existsSync7, readFileSync as
|
|
2361
|
+
import { join as join7 } from "path";
|
|
2362
|
+
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
2028
2363
|
var router5 = Router5();
|
|
2029
2364
|
var HOME = process.env.HOME || process.env.USERPROFILE || "";
|
|
2030
|
-
var BOOTSTRAP_HOME =
|
|
2031
|
-
var CONFIG_FILE =
|
|
2365
|
+
var BOOTSTRAP_HOME = join7(HOME, ".skillverse");
|
|
2366
|
+
var CONFIG_FILE = join7(BOOTSTRAP_HOME, "config.json");
|
|
2032
2367
|
function readConfig() {
|
|
2033
2368
|
if (existsSync7(CONFIG_FILE)) {
|
|
2034
2369
|
try {
|
|
2035
|
-
return JSON.parse(
|
|
2370
|
+
return JSON.parse(readFileSync3(CONFIG_FILE, "utf-8"));
|
|
2036
2371
|
} catch (e) {
|
|
2037
2372
|
console.error("Failed to read config.json:", e);
|
|
2038
2373
|
return {};
|
|
@@ -2047,8 +2382,17 @@ router5.get("/", (req, res, next) => {
|
|
|
2047
2382
|
// Show saved preference if available, otherwise current env/default
|
|
2048
2383
|
skillverseHome: fileConfig.skillverseHome || process.env.SKILLVERSE_HOME || BOOTSTRAP_HOME,
|
|
2049
2384
|
// registryUrl is potentially in config.json already
|
|
2050
|
-
registryUrl: fileConfig.registryUrl || process.env.SKILLVERSE_REGISTRY || "http://localhost:4000"
|
|
2051
|
-
//
|
|
2385
|
+
registryUrl: fileConfig.registryUrl || process.env.SKILLVERSE_REGISTRY || "http://localhost:4000",
|
|
2386
|
+
// Marketplace is now hardcoded
|
|
2387
|
+
marketplace: {
|
|
2388
|
+
indexUrl: "",
|
|
2389
|
+
github: {
|
|
2390
|
+
owner: "",
|
|
2391
|
+
repo: "",
|
|
2392
|
+
branch: "",
|
|
2393
|
+
tokenConfigured: false
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2052
2396
|
};
|
|
2053
2397
|
res.json({
|
|
2054
2398
|
success: true,
|
|
@@ -2060,19 +2404,19 @@ router5.get("/", (req, res, next) => {
|
|
|
2060
2404
|
});
|
|
2061
2405
|
router5.post("/", async (req, res, next) => {
|
|
2062
2406
|
try {
|
|
2063
|
-
const { skillverseHome, registryUrl, migrate } = req.body;
|
|
2407
|
+
const { skillverseHome, registryUrl, migrate, marketplace } = req.body;
|
|
2064
2408
|
const currentConfig = readConfig();
|
|
2065
2409
|
const oldHome = process.env.SKILLVERSE_HOME || BOOTSTRAP_HOME;
|
|
2066
2410
|
if (migrate && skillverseHome && skillverseHome !== oldHome) {
|
|
2067
2411
|
console.log(`Migrating data from ${oldHome} to ${skillverseHome}...`);
|
|
2068
2412
|
const { cp: cp2 } = await import("fs/promises");
|
|
2069
2413
|
if (!existsSync7(skillverseHome)) {
|
|
2070
|
-
const { mkdir:
|
|
2071
|
-
await
|
|
2414
|
+
const { mkdir: mkdir7 } = await import("fs/promises");
|
|
2415
|
+
await mkdir7(skillverseHome, { recursive: true });
|
|
2072
2416
|
}
|
|
2073
2417
|
const copyDir = async (srcName) => {
|
|
2074
|
-
const src =
|
|
2075
|
-
const dest =
|
|
2418
|
+
const src = join7(oldHome, srcName);
|
|
2419
|
+
const dest = join7(skillverseHome, srcName);
|
|
2076
2420
|
if (existsSync7(src)) {
|
|
2077
2421
|
console.log(`Copying ${srcName}...`);
|
|
2078
2422
|
await cp2(src, dest, { recursive: true, force: true });
|
|
@@ -2080,8 +2424,8 @@ router5.post("/", async (req, res, next) => {
|
|
|
2080
2424
|
};
|
|
2081
2425
|
await copyDir("skills");
|
|
2082
2426
|
await copyDir("marketplace");
|
|
2083
|
-
const dbSrc =
|
|
2084
|
-
const dbDest =
|
|
2427
|
+
const dbSrc = join7(oldHome, "skillverse.db");
|
|
2428
|
+
const dbDest = join7(skillverseHome, "skillverse.db");
|
|
2085
2429
|
if (existsSync7(dbSrc)) {
|
|
2086
2430
|
console.log("Copying database...");
|
|
2087
2431
|
await cp2(dbSrc, dbDest, { force: true });
|
|
@@ -2091,8 +2435,8 @@ router5.post("/", async (req, res, next) => {
|
|
|
2091
2435
|
if (existsSync7(shmSrc)) await cp2(shmSrc, dbDest + "-shm", { force: true });
|
|
2092
2436
|
console.log("Updating skill paths in new database...");
|
|
2093
2437
|
const { execSync } = await import("child_process");
|
|
2094
|
-
const oldSkillsPath =
|
|
2095
|
-
const newSkillsPath =
|
|
2438
|
+
const oldSkillsPath = join7(oldHome, "skills");
|
|
2439
|
+
const newSkillsPath = join7(skillverseHome, "skills");
|
|
2096
2440
|
const updateQuery = `UPDATE Skill SET storagePath = replace(storagePath, '${oldSkillsPath}', '${newSkillsPath}') WHERE storagePath LIKE '${oldSkillsPath}%';`;
|
|
2097
2441
|
try {
|
|
2098
2442
|
execSync(`sqlite3 "${dbDest}" "${updateQuery}"`, { encoding: "utf-8" });
|
|
@@ -2102,15 +2446,27 @@ router5.post("/", async (req, res, next) => {
|
|
|
2102
2446
|
}
|
|
2103
2447
|
}
|
|
2104
2448
|
}
|
|
2105
|
-
const
|
|
2449
|
+
const nextConfig = {
|
|
2106
2450
|
...currentConfig,
|
|
2107
2451
|
...skillverseHome && { skillverseHome },
|
|
2108
2452
|
...registryUrl && { registryUrl }
|
|
2109
2453
|
};
|
|
2110
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(
|
|
2454
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(nextConfig, null, 2));
|
|
2111
2455
|
res.json({
|
|
2112
2456
|
success: true,
|
|
2113
|
-
data:
|
|
2457
|
+
data: {
|
|
2458
|
+
...nextConfig,
|
|
2459
|
+
// Never return token
|
|
2460
|
+
marketplace: {
|
|
2461
|
+
indexUrl: nextConfig.marketplace?.indexUrl || "",
|
|
2462
|
+
github: {
|
|
2463
|
+
owner: nextConfig.marketplace?.github?.owner || "",
|
|
2464
|
+
repo: nextConfig.marketplace?.github?.repo || "",
|
|
2465
|
+
branch: nextConfig.marketplace?.github?.branch || "main",
|
|
2466
|
+
tokenConfigured: Boolean(nextConfig.marketplace?.github?.token)
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
},
|
|
2114
2470
|
message: "Configuration saved. Restart server for changes to take effect."
|
|
2115
2471
|
});
|
|
2116
2472
|
} catch (error) {
|
|
@@ -2126,7 +2482,7 @@ router5.get("/version", async (req, res, next) => {
|
|
|
2126
2482
|
const packageJsonPath = pathJoin(__dirname4, "..", "..", "package.json");
|
|
2127
2483
|
let currentVersion = "0.0.0";
|
|
2128
2484
|
if (existsSync7(packageJsonPath)) {
|
|
2129
|
-
const pkg = JSON.parse(
|
|
2485
|
+
const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
2130
2486
|
currentVersion = pkg.version || "0.0.0";
|
|
2131
2487
|
}
|
|
2132
2488
|
let latestVersion = currentVersion;
|
|
@@ -2181,7 +2537,7 @@ function requestLogger(req, res, next) {
|
|
|
2181
2537
|
// src/lib/initDb.ts
|
|
2182
2538
|
init_db();
|
|
2183
2539
|
import { existsSync as existsSync8 } from "fs";
|
|
2184
|
-
import { join as
|
|
2540
|
+
import { join as join8, dirname as dirname2 } from "path";
|
|
2185
2541
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2186
2542
|
import { spawnSync } from "child_process";
|
|
2187
2543
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
@@ -2189,13 +2545,13 @@ var __dirname2 = dirname2(__filename2);
|
|
|
2189
2545
|
function getSchemaPath() {
|
|
2190
2546
|
const possiblePaths = [
|
|
2191
2547
|
// Prod: dist/bin.js -> dist/../prisma/schema.prisma (i.e. ROOT/prisma/schema.prisma)
|
|
2192
|
-
|
|
2548
|
+
join8(__dirname2, "../prisma/schema.prisma"),
|
|
2193
2549
|
// Dev: src/lib/initDb.ts -> src/prisma/schema.prisma ? No, src/../prisma -> server/prisma
|
|
2194
2550
|
// If __dirname is src/lib: ../../prisma/schema.prisma
|
|
2195
|
-
|
|
2551
|
+
join8(__dirname2, "../../prisma/schema.prisma"),
|
|
2196
2552
|
// Fallbacks
|
|
2197
|
-
|
|
2198
|
-
|
|
2553
|
+
join8(process.cwd(), "prisma/schema.prisma"),
|
|
2554
|
+
join8(process.cwd(), "server/prisma/schema.prisma")
|
|
2199
2555
|
];
|
|
2200
2556
|
return possiblePaths.find((p) => existsSync8(p)) || null;
|
|
2201
2557
|
}
|
|
@@ -2222,10 +2578,10 @@ async function initializeDatabase() {
|
|
|
2222
2578
|
throw new Error("Could not find schema.prisma");
|
|
2223
2579
|
}
|
|
2224
2580
|
const possiblePrismaBins = [
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2581
|
+
join8(__dirname2, "../node_modules/.bin/prisma"),
|
|
2582
|
+
join8(__dirname2, "../../node_modules/.bin/prisma"),
|
|
2583
|
+
join8(__dirname2, "../../../node_modules/.bin/prisma"),
|
|
2584
|
+
join8(process.cwd(), "node_modules/.bin/prisma")
|
|
2229
2585
|
];
|
|
2230
2586
|
const prismaBin = possiblePrismaBins.find((p) => existsSync8(p)) || "prisma";
|
|
2231
2587
|
console.log(` Using schema: ${schemaPath}`);
|
|
@@ -2254,13 +2610,13 @@ app.use(express.json());
|
|
|
2254
2610
|
app.use(express.urlencoded({ extended: true }));
|
|
2255
2611
|
app.use(requestLogger);
|
|
2256
2612
|
var possiblePublicDirs = [
|
|
2257
|
-
|
|
2613
|
+
join9(__dirname3, "../public"),
|
|
2258
2614
|
// Production: dist/index.js -> public
|
|
2259
|
-
|
|
2615
|
+
join9(__dirname3, "../../public"),
|
|
2260
2616
|
// Dev tsx might resolve here
|
|
2261
|
-
|
|
2617
|
+
join9(process.cwd(), "public"),
|
|
2262
2618
|
// Fallback: relative to cwd
|
|
2263
|
-
|
|
2619
|
+
join9(process.cwd(), "server/public")
|
|
2264
2620
|
// Fallback: from root
|
|
2265
2621
|
];
|
|
2266
2622
|
var publicDir = possiblePublicDirs.find((dir) => existsSync9(dir));
|
|
@@ -2280,18 +2636,18 @@ app.get("/health", (req, res) => {
|
|
|
2280
2636
|
});
|
|
2281
2637
|
if (publicDir && existsSync9(publicDir)) {
|
|
2282
2638
|
app.get("*", (req, res) => {
|
|
2283
|
-
res.sendFile(
|
|
2639
|
+
res.sendFile(join9(publicDir, "index.html"));
|
|
2284
2640
|
});
|
|
2285
2641
|
}
|
|
2286
2642
|
app.use(errorHandler);
|
|
2287
2643
|
async function initializeStorage() {
|
|
2288
|
-
const skillverseHome = process.env.SKILLVERSE_HOME ||
|
|
2289
|
-
const skillsDir = process.env.SKILLS_DIR ||
|
|
2290
|
-
const marketplaceDir = process.env.MARKETPLACE_DIR ||
|
|
2644
|
+
const skillverseHome = process.env.SKILLVERSE_HOME || join9(process.env.HOME || "", ".skillverse");
|
|
2645
|
+
const skillsDir = process.env.SKILLS_DIR || join9(skillverseHome, "skills");
|
|
2646
|
+
const marketplaceDir = process.env.MARKETPLACE_DIR || join9(skillverseHome, "marketplace");
|
|
2291
2647
|
const dirs = [skillverseHome, skillsDir, marketplaceDir];
|
|
2292
2648
|
for (const dir of dirs) {
|
|
2293
2649
|
if (!existsSync9(dir)) {
|
|
2294
|
-
await
|
|
2650
|
+
await mkdir6(dir, { recursive: true });
|
|
2295
2651
|
console.log(`Created directory: ${dir}`);
|
|
2296
2652
|
}
|
|
2297
2653
|
}
|
|
@@ -2306,7 +2662,7 @@ async function startServer(port = 3001) {
|
|
|
2306
2662
|
return new Promise((resolve) => {
|
|
2307
2663
|
app.listen(port, () => {
|
|
2308
2664
|
console.log(`\u{1F680} SkillVerse server running on http://localhost:${port}`);
|
|
2309
|
-
console.log(`\u{1F4C1} Storage: ${process.env.SKILLVERSE_HOME ||
|
|
2665
|
+
console.log(`\u{1F4C1} Storage: ${process.env.SKILLVERSE_HOME || join9(process.env.HOME || "", ".skillverse")}`);
|
|
2310
2666
|
resolve();
|
|
2311
2667
|
});
|
|
2312
2668
|
});
|