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 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 skillverseHome = process.env.SKILLVERSE_HOME || join(home, ".skillverse");
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
- if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
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 SKILLVERSE_HOME, SKILLS_DIR, TEMP_DIR, SkillService, skillService;
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
- SKILLVERSE_HOME = process.env.SKILLVERSE_HOME || join3(process.env.HOME || "", ".skillverse");
242
- SKILLS_DIR = process.env.SKILLS_DIR || join3(SKILLVERSE_HOME, "skills");
243
- TEMP_DIR = process.env.TEMP_DIR || join3(SKILLVERSE_HOME, "temp");
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 skillPath = join3(SKILLS_DIR, skillName);
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(TEMP_DIR, `git-clone-${Date.now()}`);
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(SKILLS_DIR, skillName);
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 skillPath = join3(SKILLS_DIR, name);
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(TEMP_DIR, `extract-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
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 skillPath = join3(SKILLS_DIR, name);
527
- const extractPath = join3(TEMP_DIR, `extract-bundle-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
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 tempPath = join3(TEMP_DIR, `check-update-${Date.now()}`);
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
- tempPath = join3(TEMP_DIR, `upgrade-${Date.now()}`);
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 SKILLVERSE_HOME3 = process.env.SKILLVERSE_HOME || join4(homedir(), ".skillverse");
1081
- const SKILLS_DIR2 = process.env.SKILLS_DIR || join4(SKILLVERSE_HOME3, "skills");
1082
- if (!existsSync4(SKILLS_DIR2)) {
1083
- await mkdir2(SKILLS_DIR2, { recursive: true });
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(SKILLS_DIR2, skillName);
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, TEMP_DIR2, storage, upload, skills_default;
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
- TEMP_DIR2 = process.env.TEMP_DIR || join5(process.env.HOME || "", ".skillverse", "temp");
1176
- if (!existsSync5(TEMP_DIR2)) {
1177
- mkdir3(TEMP_DIR2, { recursive: true });
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, TEMP_DIR2);
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 join7 } from "path";
2221
+ import { dirname as dirname3, join as join8 } from "path";
2008
2222
  import { mkdir as mkdir5 } from "fs/promises";
2009
- import { existsSync as existsSync8 } from "fs";
2223
+ import { existsSync as existsSync9 } from "fs";
2010
2224
  async function initializeStorage() {
2011
- const skillverseHome = process.env.SKILLVERSE_HOME || join7(process.env.HOME || "", ".skillverse");
2012
- const skillsDir = process.env.SKILLS_DIR || join7(skillverseHome, "skills");
2013
- const marketplaceDir = process.env.MARKETPLACE_DIR || join7(skillverseHome, "marketplace");
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 (!existsSync8(dir)) {
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 = parseInt(process.env.PORT || "3001")) {
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 || join7(process.env.HOME || "", ".skillverse")}`);
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
- join7(__dirname3, "../public"),
2277
+ join8(__dirname3, "../public"),
2060
2278
  // Production: dist/index.js -> public
2061
- join7(__dirname3, "../../public"),
2279
+ join8(__dirname3, "../../public"),
2062
2280
  // Dev tsx might resolve here
2063
- join7(process.cwd(), "public"),
2281
+ join8(process.cwd(), "public"),
2064
2282
  // Fallback: relative to cwd
2065
- join7(process.cwd(), "server/public")
2283
+ join8(process.cwd(), "server/public")
2066
2284
  // Fallback: from root
2067
2285
  ];
2068
- publicDir = possiblePublicDirs.find((dir) => existsSync8(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 && existsSync8(publicDir)) {
2301
+ if (publicDir && existsSync9(publicDir)) {
2083
2302
  app.get("*", (req, res) => {
2084
- res.sendFile(join7(publicDir, "index.html"));
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 existsSync9, readFileSync, writeFileSync } from "fs";
2102
- import { join as join8 } from "path";
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: SKILLVERSE_HOME2 } = config;
2105
- var AUTH_FILE = join8(SKILLVERSE_HOME2, "auth.json");
2106
- var CONFIG_FILE = join8(SKILLVERSE_HOME2, "config.json");
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 (existsSync9(CONFIG_FILE)) {
2114
- const config2 = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
2115
- return config2.registryUrl || "http://localhost:4000";
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 (existsSync9(AUTH_FILE)) {
2121
- const auth = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
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
- writeFileSync(AUTH_FILE, JSON.stringify({ token, user }, null, 2));
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("-p, --port <number>", "Port to run server on", "3001").option("--no-open", "Do not open browser on start").action(async (options) => {
2166
- const port = parseInt(options.port, 10);
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 (!existsSync9(targetPath)) {
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", readFileSync(bundlePath), {
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 config2 = existsSync9(CONFIG_FILE) ? JSON.parse(readFileSync(CONFIG_FILE, "utf-8")) : {};
2511
+ const config3 = existsSync10(CONFIG_FILE2) ? JSON.parse(readFileSync3(CONFIG_FILE2, "utf-8")) : {};
2293
2512
  if (options.registry) {
2294
- config2.registryUrl = options.registry;
2295
- writeFileSync(CONFIG_FILE, JSON.stringify(config2, null, 2));
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: ${config2.registryUrl || getRegistryUrl()}`);
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 : join8(process.cwd(), options.path);
2346
- if (!existsSync9(sourcePath)) {
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
  }