skillverse 0.1.3 → 0.1.5
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 +283 -64
- package/dist/bin.js.map +1 -1
- package/dist/index.js +842 -574
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/prisma/dev.db +0 -0
- package/public/assets/index-DVybgO9W.js +20 -0
- package/public/assets/index-li8hN2px.css +1 -0
- package/public/index.html +2 -2
- package/public/assets/index-BsYtpZSa.css +0 -1
- package/public/assets/index-Dfr_6UV8.js +0 -20
package/dist/bin.js
CHANGED
|
@@ -11,12 +11,26 @@ var __export = (target, all) => {
|
|
|
11
11
|
|
|
12
12
|
// src/config.ts
|
|
13
13
|
import { join, dirname } from "path";
|
|
14
|
-
import { existsSync, mkdirSync } from "fs";
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync } from "fs";
|
|
15
15
|
import { fileURLToPath } from "url";
|
|
16
16
|
import dotenv from "dotenv";
|
|
17
17
|
function setupEnvironment() {
|
|
18
18
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
19
|
-
const
|
|
19
|
+
const defaultHome = join(home, ".skillverse");
|
|
20
|
+
const bootstrapConfigPath = join(defaultHome, "config.json");
|
|
21
|
+
let skillverseHome = process.env.SKILLVERSE_HOME || defaultHome;
|
|
22
|
+
if (existsSync(bootstrapConfigPath)) {
|
|
23
|
+
try {
|
|
24
|
+
const config3 = JSON.parse(readFileSync(bootstrapConfigPath, "utf-8"));
|
|
25
|
+
if (config3.skillverseHome) {
|
|
26
|
+
skillverseHome = config3.skillverseHome;
|
|
27
|
+
process.env.SKILLVERSE_HOME = skillverseHome;
|
|
28
|
+
console.log(`Common config found. Using custom home: ${skillverseHome}`);
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.warn("Failed to read bootstrap config:", e);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
20
34
|
const dbUrl = process.env.DATABASE_URL;
|
|
21
35
|
if (!existsSync(skillverseHome)) {
|
|
22
36
|
try {
|
|
@@ -25,10 +39,14 @@ function setupEnvironment() {
|
|
|
25
39
|
console.error("Failed to create .skillverse directory:", error);
|
|
26
40
|
}
|
|
27
41
|
}
|
|
28
|
-
if (!dbUrl) {
|
|
42
|
+
if (!dbUrl || skillverseHome !== defaultHome) {
|
|
29
43
|
const dbPath = join(skillverseHome, "skillverse.db");
|
|
30
44
|
process.env.DATABASE_URL = `file:${dbPath}`;
|
|
45
|
+
console.log(`Using database at: ${dbPath}`);
|
|
31
46
|
}
|
|
47
|
+
process.env.SKILLS_DIR = join(skillverseHome, "skills");
|
|
48
|
+
process.env.MARKETPLACE_DIR = join(skillverseHome, "marketplace");
|
|
49
|
+
process.env.TEMP_DIR = join(skillverseHome, "temp");
|
|
32
50
|
return {
|
|
33
51
|
skillverseHome,
|
|
34
52
|
databaseUrl: process.env.DATABASE_URL
|
|
@@ -47,16 +65,25 @@ var init_config = __esm({
|
|
|
47
65
|
|
|
48
66
|
// src/lib/db.ts
|
|
49
67
|
import { PrismaClient } from "@prisma/client";
|
|
50
|
-
var globalForPrisma, prisma;
|
|
68
|
+
var config2, globalForPrisma, currentDbUrl, prisma;
|
|
51
69
|
var init_db = __esm({
|
|
52
70
|
"src/lib/db.ts"() {
|
|
53
71
|
"use strict";
|
|
54
72
|
init_config();
|
|
73
|
+
config2 = setupEnvironment();
|
|
55
74
|
globalForPrisma = globalThis;
|
|
75
|
+
currentDbUrl = process.env.DATABASE_URL;
|
|
76
|
+
console.log(`\u{1F4CA} DB connection target: ${currentDbUrl}`);
|
|
77
|
+
if (globalForPrisma.prisma && globalForPrisma.lastDbUrl !== currentDbUrl) {
|
|
78
|
+
console.log(`\u{1F504} DATABASE_URL changed from ${globalForPrisma.lastDbUrl} to ${currentDbUrl}, reconnecting...`);
|
|
79
|
+
globalForPrisma.prisma.$disconnect().catch(console.error);
|
|
80
|
+
globalForPrisma.prisma = void 0;
|
|
81
|
+
}
|
|
56
82
|
prisma = globalForPrisma.prisma ?? new PrismaClient({
|
|
57
83
|
log: process.env.NODE_ENV === "development" ? ["error", "warn"] : ["error"]
|
|
58
84
|
});
|
|
59
|
-
|
|
85
|
+
globalForPrisma.prisma = prisma;
|
|
86
|
+
globalForPrisma.lastDbUrl = currentDbUrl;
|
|
60
87
|
}
|
|
61
88
|
});
|
|
62
89
|
|
|
@@ -211,6 +238,11 @@ var init_errorHandler = __esm({
|
|
|
211
238
|
});
|
|
212
239
|
|
|
213
240
|
// src/services/skillService.ts
|
|
241
|
+
var skillService_exports = {};
|
|
242
|
+
__export(skillService_exports, {
|
|
243
|
+
SkillService: () => SkillService,
|
|
244
|
+
skillService: () => skillService
|
|
245
|
+
});
|
|
214
246
|
import { join as join3, basename } from "path";
|
|
215
247
|
import { existsSync as existsSync3 } from "fs";
|
|
216
248
|
import { mkdir, rm, cp, readFile, unlink } from "fs/promises";
|
|
@@ -231,16 +263,21 @@ function parseGitUrl(url) {
|
|
|
231
263
|
const skillName = pathParts[pathParts.length - 1];
|
|
232
264
|
return { repoUrl, subdir, skillName };
|
|
233
265
|
}
|
|
234
|
-
var
|
|
266
|
+
var getPaths, SkillService, skillService;
|
|
235
267
|
var init_skillService = __esm({
|
|
236
268
|
"src/services/skillService.ts"() {
|
|
237
269
|
"use strict";
|
|
238
270
|
init_db();
|
|
239
271
|
init_errorHandler();
|
|
240
272
|
init_dist();
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
273
|
+
getPaths = () => {
|
|
274
|
+
const home = process.env.SKILLVERSE_HOME || join3(process.env.HOME || "", ".skillverse");
|
|
275
|
+
return {
|
|
276
|
+
home,
|
|
277
|
+
skills: process.env.SKILLS_DIR || join3(home, "skills"),
|
|
278
|
+
temp: process.env.TEMP_DIR || join3(home, "temp")
|
|
279
|
+
};
|
|
280
|
+
};
|
|
244
281
|
SkillService = class {
|
|
245
282
|
async getAllSkills() {
|
|
246
283
|
const skills = await prisma.skill.findMany({
|
|
@@ -334,13 +371,14 @@ var init_skillService = __esm({
|
|
|
334
371
|
if (existingSkill) {
|
|
335
372
|
throw new AppError(ErrorCode.ALREADY_EXISTS, `Skill "${skillName}" already exists`, 409);
|
|
336
373
|
}
|
|
337
|
-
const
|
|
374
|
+
const { skills: skillsDir, temp: tempDir } = getPaths();
|
|
375
|
+
const skillPath = join3(skillsDir, skillName);
|
|
338
376
|
if (existsSync3(skillPath)) {
|
|
339
377
|
throw new AppError(ErrorCode.ALREADY_EXISTS, `Skill directory "${skillName}" already exists`, 409);
|
|
340
378
|
}
|
|
341
379
|
let commitHash = "";
|
|
342
380
|
if (subdir) {
|
|
343
|
-
tempPath = join3(
|
|
381
|
+
tempPath = join3(tempDir, `git-clone-${Date.now()}`);
|
|
344
382
|
await mkdir(tempPath, { recursive: true });
|
|
345
383
|
console.log(`Cloning ${repoUrl} to temp path for extraction...`);
|
|
346
384
|
const git = simpleGit();
|
|
@@ -411,8 +449,9 @@ var init_skillService = __esm({
|
|
|
411
449
|
if (!existsSync3(path)) {
|
|
412
450
|
throw new AppError(ErrorCode.FILE_SYSTEM_ERROR, `Source path not found: ${path}`, 400);
|
|
413
451
|
}
|
|
452
|
+
const { skills: skillsDir } = getPaths();
|
|
414
453
|
const skillName = name || basename(path);
|
|
415
|
-
const skillPath = join3(
|
|
454
|
+
const skillPath = join3(skillsDir, skillName);
|
|
416
455
|
const existingSkill = await prisma.skill.findUnique({
|
|
417
456
|
where: { name: skillName }
|
|
418
457
|
});
|
|
@@ -467,7 +506,8 @@ var init_skillService = __esm({
|
|
|
467
506
|
}
|
|
468
507
|
}
|
|
469
508
|
async createSkillFromLocal(name, zipPath, description) {
|
|
470
|
-
const
|
|
509
|
+
const { skills: skillsDir, temp: tempDir } = getPaths();
|
|
510
|
+
const skillPath = join3(skillsDir, name);
|
|
471
511
|
const existingSkill = await prisma.skill.findUnique({
|
|
472
512
|
where: { name }
|
|
473
513
|
});
|
|
@@ -477,7 +517,7 @@ var init_skillService = __esm({
|
|
|
477
517
|
if (existsSync3(skillPath)) {
|
|
478
518
|
throw new AppError(ErrorCode.ALREADY_EXISTS, `Skill directory "${name}" already exists`, 409);
|
|
479
519
|
}
|
|
480
|
-
const extractPath = join3(
|
|
520
|
+
const extractPath = join3(tempDir, `extract-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
|
|
481
521
|
await mkdir(extractPath, { recursive: true });
|
|
482
522
|
try {
|
|
483
523
|
const zip = new AdmZip(zipPath);
|
|
@@ -523,8 +563,9 @@ var init_skillService = __esm({
|
|
|
523
563
|
name = `${originalName}-${counter}`;
|
|
524
564
|
counter++;
|
|
525
565
|
}
|
|
526
|
-
const
|
|
527
|
-
const
|
|
566
|
+
const { skills: skillsDir, temp: tempDir } = getPaths();
|
|
567
|
+
const skillPath = join3(skillsDir, name);
|
|
568
|
+
const extractPath = join3(tempDir, `extract-bundle-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
|
|
528
569
|
await mkdir(extractPath, { recursive: true });
|
|
529
570
|
try {
|
|
530
571
|
const { createReadStream: createReadStream2 } = await import("fs");
|
|
@@ -617,7 +658,8 @@ var init_skillService = __esm({
|
|
|
617
658
|
message: "Not a git skill or missing repo URL"
|
|
618
659
|
};
|
|
619
660
|
}
|
|
620
|
-
const
|
|
661
|
+
const { temp: tempDir } = getPaths();
|
|
662
|
+
const tempPath = join3(tempDir, `check-update-${Date.now()}`);
|
|
621
663
|
await mkdir(tempPath, { recursive: true });
|
|
622
664
|
try {
|
|
623
665
|
const git = simpleGit();
|
|
@@ -690,7 +732,8 @@ var init_skillService = __esm({
|
|
|
690
732
|
let tempSkillPath = null;
|
|
691
733
|
try {
|
|
692
734
|
const { repoUrl, subdir } = parseGitUrl(skill.sourceUrl);
|
|
693
|
-
|
|
735
|
+
const { temp: tempDir } = getPaths();
|
|
736
|
+
tempPath = join3(tempDir, `upgrade-${Date.now()}`);
|
|
694
737
|
await mkdir(tempPath, { recursive: true });
|
|
695
738
|
const git = simpleGit();
|
|
696
739
|
console.log(`Cloning ${repoUrl} to temp for upgrade...`);
|
|
@@ -742,6 +785,73 @@ var init_skillService = __esm({
|
|
|
742
785
|
});
|
|
743
786
|
}
|
|
744
787
|
}
|
|
788
|
+
async scanForSkills() {
|
|
789
|
+
const { skills: skillsDir } = getPaths();
|
|
790
|
+
console.log(`Scanning for skills in ${skillsDir}...`);
|
|
791
|
+
if (!existsSync3(skillsDir)) {
|
|
792
|
+
console.log("Skills directory does not exist, skipping scan.");
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
const entries = await import("fs/promises").then((fs) => fs.readdir(skillsDir, { withFileTypes: true }));
|
|
796
|
+
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
797
|
+
console.log(`Found ${directories.length} directories in skills folder.`);
|
|
798
|
+
let importedCount = 0;
|
|
799
|
+
for (const dirName of directories) {
|
|
800
|
+
const skillPath = join3(skillsDir, dirName);
|
|
801
|
+
const existingSkill = await prisma.skill.findUnique({
|
|
802
|
+
where: { name: dirName }
|
|
803
|
+
});
|
|
804
|
+
if (existingSkill) {
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
const hasSkillMd = existsSync3(join3(skillPath, "SKILL.md"));
|
|
808
|
+
const hasPackageJson = existsSync3(join3(skillPath, "package.json"));
|
|
809
|
+
const hasSkillJson = existsSync3(join3(skillPath, "skill.json"));
|
|
810
|
+
if (!hasSkillMd && !hasPackageJson && !hasSkillJson) {
|
|
811
|
+
console.log(`Skipping ${dirName}: No skill metadata found.`);
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
console.log(`Importing skill: ${dirName}`);
|
|
816
|
+
const parsed = await this.parseSkillMetadata(skillPath);
|
|
817
|
+
let source = "local";
|
|
818
|
+
let sourceUrl = void 0;
|
|
819
|
+
let repoUrl = void 0;
|
|
820
|
+
let commitHash = void 0;
|
|
821
|
+
if (existsSync3(join3(skillPath, ".git"))) {
|
|
822
|
+
source = "git";
|
|
823
|
+
try {
|
|
824
|
+
const git = simpleGit(skillPath);
|
|
825
|
+
const remotes = await git.getRemotes(true);
|
|
826
|
+
if (remotes.length > 0) {
|
|
827
|
+
sourceUrl = remotes[0].refs.fetch;
|
|
828
|
+
repoUrl = sourceUrl;
|
|
829
|
+
}
|
|
830
|
+
commitHash = await git.revparse(["HEAD"]);
|
|
831
|
+
} catch (e) {
|
|
832
|
+
console.warn(`Failed to read git info for ${dirName}:`, e);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
await prisma.skill.create({
|
|
836
|
+
data: {
|
|
837
|
+
name: dirName,
|
|
838
|
+
source,
|
|
839
|
+
sourceUrl,
|
|
840
|
+
repoUrl,
|
|
841
|
+
commitHash,
|
|
842
|
+
description: parsed.description,
|
|
843
|
+
storagePath: skillPath,
|
|
844
|
+
metadata: JSON.stringify(parsed.metadata)
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
importedCount++;
|
|
848
|
+
} catch (error) {
|
|
849
|
+
console.error(`Failed to import skill ${dirName}:`, error);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
console.log(`Scan complete. Imported ${importedCount} new skills.`);
|
|
853
|
+
return importedCount;
|
|
854
|
+
}
|
|
745
855
|
};
|
|
746
856
|
skillService = new SkillService();
|
|
747
857
|
}
|
|
@@ -1077,17 +1187,17 @@ ${relativeSkillsPath}/
|
|
|
1077
1187
|
*/
|
|
1078
1188
|
async migrateExistingSkills(workspaceId, skillNames) {
|
|
1079
1189
|
const workspace = await this.getWorkspaceById(workspaceId);
|
|
1080
|
-
const
|
|
1081
|
-
const
|
|
1082
|
-
if (!existsSync4(
|
|
1083
|
-
await mkdir2(
|
|
1190
|
+
const SKILLVERSE_HOME2 = process.env.SKILLVERSE_HOME || join4(homedir(), ".skillverse");
|
|
1191
|
+
const SKILLS_DIR = process.env.SKILLS_DIR || join4(SKILLVERSE_HOME2, "skills");
|
|
1192
|
+
if (!existsSync4(SKILLS_DIR)) {
|
|
1193
|
+
await mkdir2(SKILLS_DIR, { recursive: true });
|
|
1084
1194
|
}
|
|
1085
1195
|
const { rename, readFile: readFile3, cp: cp2 } = await import("fs/promises");
|
|
1086
1196
|
const migrated = [];
|
|
1087
1197
|
const errors = [];
|
|
1088
1198
|
for (const skillName of skillNames) {
|
|
1089
1199
|
const sourcePath = join4(workspace.path, skillName);
|
|
1090
|
-
const targetPath = join4(
|
|
1200
|
+
const targetPath = join4(SKILLS_DIR, skillName);
|
|
1091
1201
|
try {
|
|
1092
1202
|
if (!existsSync4(sourcePath)) {
|
|
1093
1203
|
errors.push(`${skillName}: Source path not found`);
|
|
@@ -1165,20 +1275,20 @@ import multer from "multer";
|
|
|
1165
1275
|
import { join as join5 } from "path";
|
|
1166
1276
|
import { existsSync as existsSync5 } from "fs";
|
|
1167
1277
|
import { mkdir as mkdir3, rm as rm3 } from "fs/promises";
|
|
1168
|
-
var router,
|
|
1278
|
+
var router, TEMP_DIR, storage, upload, skills_default;
|
|
1169
1279
|
var init_skills = __esm({
|
|
1170
1280
|
"src/routes/skills.ts"() {
|
|
1171
1281
|
"use strict";
|
|
1172
1282
|
init_skillService();
|
|
1173
1283
|
init_workspaceService();
|
|
1174
1284
|
router = Router();
|
|
1175
|
-
|
|
1176
|
-
if (!existsSync5(
|
|
1177
|
-
mkdir3(
|
|
1285
|
+
TEMP_DIR = process.env.TEMP_DIR || join5(process.env.HOME || "", ".skillverse", "temp");
|
|
1286
|
+
if (!existsSync5(TEMP_DIR)) {
|
|
1287
|
+
mkdir3(TEMP_DIR, { recursive: true });
|
|
1178
1288
|
}
|
|
1179
1289
|
storage = multer.diskStorage({
|
|
1180
1290
|
destination: (req, file, cb) => {
|
|
1181
|
-
cb(null,
|
|
1291
|
+
cb(null, TEMP_DIR);
|
|
1182
1292
|
},
|
|
1183
1293
|
filename: (req, file, cb) => {
|
|
1184
1294
|
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
|
|
@@ -1980,6 +2090,110 @@ var init_dashboard = __esm({
|
|
|
1980
2090
|
}
|
|
1981
2091
|
});
|
|
1982
2092
|
|
|
2093
|
+
// src/routes/config.ts
|
|
2094
|
+
import { Router as Router5 } from "express";
|
|
2095
|
+
import { join as join7 } from "path";
|
|
2096
|
+
import { existsSync as existsSync8, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
2097
|
+
function readConfig() {
|
|
2098
|
+
if (existsSync8(CONFIG_FILE)) {
|
|
2099
|
+
try {
|
|
2100
|
+
return JSON.parse(readFileSync2(CONFIG_FILE, "utf-8"));
|
|
2101
|
+
} catch (e) {
|
|
2102
|
+
console.error("Failed to read config.json:", e);
|
|
2103
|
+
return {};
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
return {};
|
|
2107
|
+
}
|
|
2108
|
+
var router5, HOME, BOOTSTRAP_HOME, CONFIG_FILE, config_default;
|
|
2109
|
+
var init_config2 = __esm({
|
|
2110
|
+
"src/routes/config.ts"() {
|
|
2111
|
+
"use strict";
|
|
2112
|
+
router5 = Router5();
|
|
2113
|
+
HOME = process.env.HOME || process.env.USERPROFILE || "";
|
|
2114
|
+
BOOTSTRAP_HOME = join7(HOME, ".skillverse");
|
|
2115
|
+
CONFIG_FILE = join7(BOOTSTRAP_HOME, "config.json");
|
|
2116
|
+
router5.get("/", (req, res, next) => {
|
|
2117
|
+
try {
|
|
2118
|
+
const fileConfig = readConfig();
|
|
2119
|
+
const config3 = {
|
|
2120
|
+
// Show saved preference if available, otherwise current env/default
|
|
2121
|
+
skillverseHome: fileConfig.skillverseHome || process.env.SKILLVERSE_HOME || BOOTSTRAP_HOME,
|
|
2122
|
+
// registryUrl is potentially in config.json already
|
|
2123
|
+
registryUrl: fileConfig.registryUrl || process.env.SKILLVERSE_REGISTRY || "http://localhost:4000"
|
|
2124
|
+
// ... add other configurable items
|
|
2125
|
+
};
|
|
2126
|
+
res.json({
|
|
2127
|
+
success: true,
|
|
2128
|
+
data: config3
|
|
2129
|
+
});
|
|
2130
|
+
} catch (error) {
|
|
2131
|
+
next(error);
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
router5.post("/", async (req, res, next) => {
|
|
2135
|
+
try {
|
|
2136
|
+
const { skillverseHome, registryUrl, migrate } = req.body;
|
|
2137
|
+
const currentConfig = readConfig();
|
|
2138
|
+
const oldHome = process.env.SKILLVERSE_HOME || BOOTSTRAP_HOME;
|
|
2139
|
+
if (migrate && skillverseHome && skillverseHome !== oldHome) {
|
|
2140
|
+
console.log(`Migrating data from ${oldHome} to ${skillverseHome}...`);
|
|
2141
|
+
const { cp: cp2 } = await import("fs/promises");
|
|
2142
|
+
if (!existsSync8(skillverseHome)) {
|
|
2143
|
+
const { mkdir: mkdir6 } = await import("fs/promises");
|
|
2144
|
+
await mkdir6(skillverseHome, { recursive: true });
|
|
2145
|
+
}
|
|
2146
|
+
const copyDir = async (srcName) => {
|
|
2147
|
+
const src = join7(oldHome, srcName);
|
|
2148
|
+
const dest = join7(skillverseHome, srcName);
|
|
2149
|
+
if (existsSync8(src)) {
|
|
2150
|
+
console.log(`Copying ${srcName}...`);
|
|
2151
|
+
await cp2(src, dest, { recursive: true, force: true });
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
await copyDir("skills");
|
|
2155
|
+
await copyDir("marketplace");
|
|
2156
|
+
const dbSrc = join7(oldHome, "skillverse.db");
|
|
2157
|
+
const dbDest = join7(skillverseHome, "skillverse.db");
|
|
2158
|
+
if (existsSync8(dbSrc)) {
|
|
2159
|
+
console.log("Copying database...");
|
|
2160
|
+
await cp2(dbSrc, dbDest, { force: true });
|
|
2161
|
+
const walSrc = dbSrc + "-wal";
|
|
2162
|
+
if (existsSync8(walSrc)) await cp2(walSrc, dbDest + "-wal", { force: true });
|
|
2163
|
+
const shmSrc = dbSrc + "-shm";
|
|
2164
|
+
if (existsSync8(shmSrc)) await cp2(shmSrc, dbDest + "-shm", { force: true });
|
|
2165
|
+
console.log("Updating skill paths in new database...");
|
|
2166
|
+
const { execSync } = await import("child_process");
|
|
2167
|
+
const oldSkillsPath = join7(oldHome, "skills");
|
|
2168
|
+
const newSkillsPath = join7(skillverseHome, "skills");
|
|
2169
|
+
const updateQuery = `UPDATE Skill SET storagePath = replace(storagePath, '${oldSkillsPath}', '${newSkillsPath}') WHERE storagePath LIKE '${oldSkillsPath}%';`;
|
|
2170
|
+
try {
|
|
2171
|
+
execSync(`sqlite3 "${dbDest}" "${updateQuery}"`, { encoding: "utf-8" });
|
|
2172
|
+
console.log("\u2705 Updated skill paths in new database");
|
|
2173
|
+
} catch (sqlErr) {
|
|
2174
|
+
console.error("Failed to update skill paths:", sqlErr);
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
const newConfig = {
|
|
2179
|
+
...currentConfig,
|
|
2180
|
+
...skillverseHome && { skillverseHome },
|
|
2181
|
+
...registryUrl && { registryUrl }
|
|
2182
|
+
};
|
|
2183
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2));
|
|
2184
|
+
res.json({
|
|
2185
|
+
success: true,
|
|
2186
|
+
data: newConfig,
|
|
2187
|
+
message: "Configuration saved. Restart server for changes to take effect."
|
|
2188
|
+
});
|
|
2189
|
+
} catch (error) {
|
|
2190
|
+
next(error);
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
config_default = router5;
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
|
|
1983
2197
|
// src/middleware/logger.ts
|
|
1984
2198
|
function requestLogger(req, res, next) {
|
|
1985
2199
|
const start = Date.now();
|
|
@@ -2004,29 +2218,32 @@ import express from "express";
|
|
|
2004
2218
|
import cors from "cors";
|
|
2005
2219
|
import dotenv2 from "dotenv";
|
|
2006
2220
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2007
|
-
import { dirname as dirname3, join as
|
|
2221
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
2008
2222
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
2009
|
-
import { existsSync as
|
|
2223
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2010
2224
|
async function initializeStorage() {
|
|
2011
|
-
const skillverseHome = process.env.SKILLVERSE_HOME ||
|
|
2012
|
-
const skillsDir = process.env.SKILLS_DIR ||
|
|
2013
|
-
const marketplaceDir = process.env.MARKETPLACE_DIR ||
|
|
2225
|
+
const skillverseHome = process.env.SKILLVERSE_HOME || join8(process.env.HOME || "", ".skillverse");
|
|
2226
|
+
const skillsDir = process.env.SKILLS_DIR || join8(skillverseHome, "skills");
|
|
2227
|
+
const marketplaceDir = process.env.MARKETPLACE_DIR || join8(skillverseHome, "marketplace");
|
|
2014
2228
|
const dirs = [skillverseHome, skillsDir, marketplaceDir];
|
|
2015
2229
|
for (const dir of dirs) {
|
|
2016
|
-
if (!
|
|
2230
|
+
if (!existsSync9(dir)) {
|
|
2017
2231
|
await mkdir5(dir, { recursive: true });
|
|
2018
2232
|
console.log(`Created directory: ${dir}`);
|
|
2019
2233
|
}
|
|
2020
2234
|
}
|
|
2021
2235
|
}
|
|
2022
|
-
async function startServer(port =
|
|
2236
|
+
async function startServer(port = 3001) {
|
|
2023
2237
|
try {
|
|
2024
2238
|
await initializeStorage();
|
|
2025
2239
|
await ensureDatabaseInitialized();
|
|
2240
|
+
console.log("\u{1F50D} Scanning for existing skills...");
|
|
2241
|
+
const { skillService: skillService2 } = await Promise.resolve().then(() => (init_skillService(), skillService_exports));
|
|
2242
|
+
await skillService2.scanForSkills();
|
|
2026
2243
|
return new Promise((resolve) => {
|
|
2027
2244
|
app.listen(port, () => {
|
|
2028
2245
|
console.log(`\u{1F680} SkillVerse server running on http://localhost:${port}`);
|
|
2029
|
-
console.log(`\u{1F4C1} Storage: ${process.env.SKILLVERSE_HOME ||
|
|
2246
|
+
console.log(`\u{1F4C1} Storage: ${process.env.SKILLVERSE_HOME || join8(process.env.HOME || "", ".skillverse")}`);
|
|
2030
2247
|
resolve();
|
|
2031
2248
|
});
|
|
2032
2249
|
});
|
|
@@ -2043,6 +2260,7 @@ var init_index = __esm({
|
|
|
2043
2260
|
init_workspaces();
|
|
2044
2261
|
init_marketplace();
|
|
2045
2262
|
init_dashboard();
|
|
2263
|
+
init_config2();
|
|
2046
2264
|
init_errorHandler();
|
|
2047
2265
|
init_logger();
|
|
2048
2266
|
init_initDb();
|
|
@@ -2056,16 +2274,16 @@ var init_index = __esm({
|
|
|
2056
2274
|
app.use(express.urlencoded({ extended: true }));
|
|
2057
2275
|
app.use(requestLogger);
|
|
2058
2276
|
possiblePublicDirs = [
|
|
2059
|
-
|
|
2277
|
+
join8(__dirname3, "../public"),
|
|
2060
2278
|
// Production: dist/index.js -> public
|
|
2061
|
-
|
|
2279
|
+
join8(__dirname3, "../../public"),
|
|
2062
2280
|
// Dev tsx might resolve here
|
|
2063
|
-
|
|
2281
|
+
join8(process.cwd(), "public"),
|
|
2064
2282
|
// Fallback: relative to cwd
|
|
2065
|
-
|
|
2283
|
+
join8(process.cwd(), "server/public")
|
|
2066
2284
|
// Fallback: from root
|
|
2067
2285
|
];
|
|
2068
|
-
publicDir = possiblePublicDirs.find((dir) =>
|
|
2286
|
+
publicDir = possiblePublicDirs.find((dir) => existsSync9(dir));
|
|
2069
2287
|
if (publicDir) {
|
|
2070
2288
|
app.use(express.static(publicDir));
|
|
2071
2289
|
console.log(`\u{1F4C2} Serving static files from: ${publicDir}`);
|
|
@@ -2076,12 +2294,13 @@ var init_index = __esm({
|
|
|
2076
2294
|
app.use("/api/workspaces", workspaces_default);
|
|
2077
2295
|
app.use("/api/marketplace", marketplace_default);
|
|
2078
2296
|
app.use("/api/dashboard", dashboard_default);
|
|
2297
|
+
app.use("/api/config", config_default);
|
|
2079
2298
|
app.get("/health", (req, res) => {
|
|
2080
2299
|
res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2081
2300
|
});
|
|
2082
|
-
if (publicDir &&
|
|
2301
|
+
if (publicDir && existsSync9(publicDir)) {
|
|
2083
2302
|
app.get("*", (req, res) => {
|
|
2084
|
-
res.sendFile(
|
|
2303
|
+
res.sendFile(join8(publicDir, "index.html"));
|
|
2085
2304
|
});
|
|
2086
2305
|
}
|
|
2087
2306
|
app.use(errorHandler);
|
|
@@ -2098,33 +2317,33 @@ init_skillService();
|
|
|
2098
2317
|
init_workspaceService();
|
|
2099
2318
|
import { program } from "commander";
|
|
2100
2319
|
import open from "open";
|
|
2101
|
-
import { existsSync as
|
|
2102
|
-
import { join as
|
|
2320
|
+
import { existsSync as existsSync10, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
2321
|
+
import { join as join9 } from "path";
|
|
2103
2322
|
import readline from "readline";
|
|
2104
|
-
var { skillverseHome:
|
|
2105
|
-
var AUTH_FILE =
|
|
2106
|
-
var
|
|
2323
|
+
var { skillverseHome: SKILLVERSE_HOME } = config;
|
|
2324
|
+
var AUTH_FILE = join9(SKILLVERSE_HOME, "auth.json");
|
|
2325
|
+
var CONFIG_FILE2 = join9(SKILLVERSE_HOME, "config.json");
|
|
2107
2326
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
2108
2327
|
if (["list", "start", "install", "add", "remove", "import", "search"].includes(actionCommand.name())) {
|
|
2109
2328
|
await ensureDatabaseInitialized();
|
|
2110
2329
|
}
|
|
2111
2330
|
});
|
|
2112
2331
|
function getRegistryUrl() {
|
|
2113
|
-
if (
|
|
2114
|
-
const
|
|
2115
|
-
return
|
|
2332
|
+
if (existsSync10(CONFIG_FILE2)) {
|
|
2333
|
+
const config3 = JSON.parse(readFileSync3(CONFIG_FILE2, "utf-8"));
|
|
2334
|
+
return config3.registryUrl || "http://localhost:4000";
|
|
2116
2335
|
}
|
|
2117
2336
|
return process.env.SKILLVERSE_REGISTRY || "http://localhost:4000";
|
|
2118
2337
|
}
|
|
2119
2338
|
function getAuthToken() {
|
|
2120
|
-
if (
|
|
2121
|
-
const auth = JSON.parse(
|
|
2339
|
+
if (existsSync10(AUTH_FILE)) {
|
|
2340
|
+
const auth = JSON.parse(readFileSync3(AUTH_FILE, "utf-8"));
|
|
2122
2341
|
return auth.token || null;
|
|
2123
2342
|
}
|
|
2124
2343
|
return null;
|
|
2125
2344
|
}
|
|
2126
2345
|
function saveAuth(token, user) {
|
|
2127
|
-
|
|
2346
|
+
writeFileSync2(AUTH_FILE, JSON.stringify({ token, user }, null, 2));
|
|
2128
2347
|
}
|
|
2129
2348
|
async function prompt(question, hidden = false) {
|
|
2130
2349
|
const rl = readline.createInterface({
|
|
@@ -2162,8 +2381,8 @@ async function prompt(question, hidden = false) {
|
|
|
2162
2381
|
});
|
|
2163
2382
|
}
|
|
2164
2383
|
program.name("skillverse").description("SkillVerse - Local-first skill management platform for AI coding assistants").version("0.1.0");
|
|
2165
|
-
program.command("start").description("Start the SkillVerse local server").option("
|
|
2166
|
-
const port =
|
|
2384
|
+
program.command("start").description("Start the SkillVerse local server").option("--no-open", "Do not open browser on start").action(async (options) => {
|
|
2385
|
+
const port = 3001;
|
|
2167
2386
|
console.log("");
|
|
2168
2387
|
console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
2169
2388
|
console.log(" \u2551 \u{1F680} SkillVerse CLI \u2551");
|
|
@@ -2215,7 +2434,7 @@ program.command("publish [path]").description("Publish a skill to the Registry")
|
|
|
2215
2434
|
}
|
|
2216
2435
|
const targetPath = skillPath || process.cwd();
|
|
2217
2436
|
const registryUrl = options.registry || getRegistryUrl();
|
|
2218
|
-
if (!
|
|
2437
|
+
if (!existsSync10(targetPath)) {
|
|
2219
2438
|
console.error(`
|
|
2220
2439
|
\u274C Path not found: ${targetPath}`);
|
|
2221
2440
|
process.exit(1);
|
|
@@ -2230,7 +2449,7 @@ program.command("publish [path]").description("Publish a skill to the Registry")
|
|
|
2230
2449
|
const form = new FormData();
|
|
2231
2450
|
form.append("name", skillName);
|
|
2232
2451
|
if (options.description) form.append("description", options.description);
|
|
2233
|
-
form.append("bundle",
|
|
2452
|
+
form.append("bundle", readFileSync3(bundlePath), {
|
|
2234
2453
|
filename: `${skillName}.tar.gz`,
|
|
2235
2454
|
contentType: "application/gzip"
|
|
2236
2455
|
});
|
|
@@ -2289,14 +2508,14 @@ program.command("search <query>").description("Search for skills in the Registry
|
|
|
2289
2508
|
}
|
|
2290
2509
|
});
|
|
2291
2510
|
program.command("config").description("Configure SkillVerse settings").option("-r, --registry <url>", "Set default registry URL").action((options) => {
|
|
2292
|
-
const
|
|
2511
|
+
const config3 = existsSync10(CONFIG_FILE2) ? JSON.parse(readFileSync3(CONFIG_FILE2, "utf-8")) : {};
|
|
2293
2512
|
if (options.registry) {
|
|
2294
|
-
|
|
2295
|
-
|
|
2513
|
+
config3.registryUrl = options.registry;
|
|
2514
|
+
writeFileSync2(CONFIG_FILE2, JSON.stringify(config3, null, 2));
|
|
2296
2515
|
console.log(`\u2705 Registry URL set to: ${options.registry}`);
|
|
2297
2516
|
} else {
|
|
2298
2517
|
console.log("\nCurrent Configuration:");
|
|
2299
|
-
console.log(` Registry: ${
|
|
2518
|
+
console.log(` Registry: ${config3.registryUrl || getRegistryUrl()}`);
|
|
2300
2519
|
}
|
|
2301
2520
|
});
|
|
2302
2521
|
program.command("install [gitUrl]").description("Install a skill from Git URL").option("-a, --agent <agent>", "Link to agent workspace (vscode, cursor, etc.)").action(async (gitUrl, options) => {
|
|
@@ -2342,8 +2561,8 @@ program.command("install [gitUrl]").description("Install a skill from Git URL").
|
|
|
2342
2561
|
}
|
|
2343
2562
|
});
|
|
2344
2563
|
program.command("add").description("Add a local skill").requiredOption("-p, --path <path>", "Path to skill directory").option("-a, --agent <agent>", "Link to agent workspace").action(async (options) => {
|
|
2345
|
-
const sourcePath = options.path.startsWith("/") ? options.path :
|
|
2346
|
-
if (!
|
|
2564
|
+
const sourcePath = options.path.startsWith("/") ? options.path : join9(process.cwd(), options.path);
|
|
2565
|
+
if (!existsSync10(sourcePath)) {
|
|
2347
2566
|
console.error(`\u274C Source path not found: ${sourcePath}`);
|
|
2348
2567
|
process.exit(1);
|
|
2349
2568
|
}
|