@kwonye/mcpx 0.1.95 → 0.1.97

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.
@@ -1,8 +1,16 @@
1
+ import {
2
+ loadConfig,
3
+ loadProjectConfig,
4
+ saveConfig,
5
+ saveProjectConfig
6
+ } from "./cli-g4w6k655.js";
1
7
  import {
2
8
  ensureGatewayToken
3
- } from "./cli-tk8bggg5.js";
9
+ } from "./cli-remv48t3.js";
4
10
  import {
5
11
  ensureDir,
12
+ findProjectConfigPath,
13
+ getConfigPath,
6
14
  getManagedIndexPath,
7
15
  getSkillsDir,
8
16
  homeDir,
@@ -14,20 +22,128 @@ import {
14
22
  isServerEnabled
15
23
  } from "./cli-s4gspqdf.js";
16
24
 
17
- // src/core/skills.ts
25
+ // src/core/config-store.ts
18
26
  import fs from "node:fs";
19
27
  import path from "node:path";
28
+ var LOCK_STALE_MS = 5000;
29
+ var LOCK_RETRY_MS = 50;
30
+ var LOCK_MAX_RETRIES = 40;
31
+ var inProcessQueues = new Map;
32
+ function getLockPath(filePath) {
33
+ return `${filePath}.lock`;
34
+ }
35
+ function acquireLock(filePath) {
36
+ const lockPath = getLockPath(filePath);
37
+ try {
38
+ fs.mkdirSync(path.dirname(lockPath), { recursive: true });
39
+ const fd = fs.openSync(lockPath, "wx");
40
+ fs.writeSync(fd, String(process.pid));
41
+ fs.closeSync(fd);
42
+ return true;
43
+ } catch (err) {
44
+ if (err.code !== "EEXIST") {
45
+ return false;
46
+ }
47
+ try {
48
+ const stat = fs.statSync(lockPath);
49
+ if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {
50
+ fs.unlinkSync(lockPath);
51
+ return acquireLock(filePath);
52
+ }
53
+ } catch {
54
+ return acquireLock(filePath);
55
+ }
56
+ return false;
57
+ }
58
+ }
59
+ function releaseLock(filePath) {
60
+ try {
61
+ fs.unlinkSync(getLockPath(filePath));
62
+ } catch {}
63
+ }
64
+ function mutateFile(filePath, load, save, fn) {
65
+ const prevQueue = inProcessQueues.get(filePath) ?? Promise.resolve();
66
+ const nextQueue = prevQueue.then(() => executeWithLock(filePath, load, save, fn), () => executeWithLock(filePath, load, save, fn));
67
+ inProcessQueues.set(filePath, nextQueue.catch(() => {
68
+ return;
69
+ }));
70
+ return nextQueue;
71
+ }
72
+ async function executeWithLock(filePath, load, save, fn) {
73
+ let acquired = false;
74
+ for (let attempt = 0;attempt < LOCK_MAX_RETRIES; attempt++) {
75
+ acquired = acquireLock(filePath);
76
+ if (acquired)
77
+ break;
78
+ await new Promise((r) => setTimeout(r, LOCK_RETRY_MS));
79
+ }
80
+ if (!acquired) {
81
+ throw new Error(`Could not acquire lock for ${filePath}.`);
82
+ }
83
+ try {
84
+ const data = load(filePath);
85
+ const result = await fn(data);
86
+ save(data, filePath);
87
+ return result;
88
+ } finally {
89
+ releaseLock(filePath);
90
+ }
91
+ }
92
+ function mutateConfig(fn, configPath) {
93
+ return mutateFile(configPath ?? getConfigPath(), loadConfig, saveConfig, fn);
94
+ }
95
+ function mutateProjectConfig(projectConfigPath, fn) {
96
+ return mutateFile(projectConfigPath, (p) => loadProjectConfig(p), saveProjectConfig, fn);
97
+ }
98
+ async function mutateActiveConfig(options, mutator) {
99
+ const globalPath = getConfigPath();
100
+ if (!options.global) {
101
+ const projectConfigPath = findProjectConfigPath();
102
+ if (options.local) {
103
+ const projectPath = projectConfigPath ? path.dirname(projectConfigPath) : process.cwd();
104
+ const localPath = path.join(projectPath, ".mcpx.json");
105
+ const globalConfig = loadConfig(globalPath);
106
+ const result2 = await mutateProjectConfig(localPath, async (projectConfig) => {
107
+ const mergedConfig = {
108
+ ...globalConfig,
109
+ servers: { ...globalConfig.servers, ...projectConfig.servers }
110
+ };
111
+ const mutatorResult = await mutator(mergedConfig, { type: "project", projectPath });
112
+ const localServers = {};
113
+ for (const [name, spec] of Object.entries(mergedConfig.servers)) {
114
+ if (!(name in globalConfig.servers)) {
115
+ localServers[name] = spec;
116
+ }
117
+ }
118
+ projectConfig.servers = localServers;
119
+ return mutatorResult;
120
+ });
121
+ return { type: "project", configPath: localPath, projectPath, result: result2 };
122
+ }
123
+ if (projectConfigPath) {
124
+ const projectPath = path.dirname(projectConfigPath);
125
+ const result2 = await mutateConfig((config) => mutator(config, { type: "project", projectPath }), globalPath);
126
+ return { type: "project", configPath: globalPath, projectPath, result: result2 };
127
+ }
128
+ }
129
+ const result = await mutateConfig((config) => mutator(config, { type: "global" }), globalPath);
130
+ return { type: "global", configPath: globalPath, result };
131
+ }
132
+
133
+ // src/core/skills.ts
134
+ import fs2 from "node:fs";
135
+ import path2 from "node:path";
20
136
  function listSkills() {
21
137
  const skillsDir = getSkillsDir();
22
- if (!fs.existsSync(skillsDir)) {
138
+ if (!fs2.existsSync(skillsDir)) {
23
139
  return [];
24
140
  }
25
- const files = fs.readdirSync(skillsDir);
141
+ const files = fs2.readdirSync(skillsDir);
26
142
  const skills = [];
27
143
  for (const file of files) {
28
144
  if (file.endsWith(".md")) {
29
- const id = path.basename(file, ".md");
30
- const content = fs.readFileSync(path.join(skillsDir, file), "utf-8");
145
+ const id = path2.basename(file, ".md");
146
+ const content = fs2.readFileSync(path2.join(skillsDir, file), "utf-8");
31
147
  skills.push({ id, content });
32
148
  }
33
149
  }
@@ -35,38 +151,38 @@ function listSkills() {
35
151
  }
36
152
  function getSkill(id) {
37
153
  const skillsDir = getSkillsDir();
38
- const filePath = path.join(skillsDir, `${id}.md`);
39
- if (!fs.existsSync(filePath)) {
154
+ const filePath = path2.join(skillsDir, `${id}.md`);
155
+ if (!fs2.existsSync(filePath)) {
40
156
  return null;
41
157
  }
42
- const content = fs.readFileSync(filePath, "utf-8");
158
+ const content = fs2.readFileSync(filePath, "utf-8");
43
159
  return { id, content };
44
160
  }
45
161
  function saveSkill(id, content) {
46
162
  const skillsDir = getSkillsDir();
47
163
  ensureDir(skillsDir);
48
- const filePath = path.join(skillsDir, `${id}.md`);
49
- fs.writeFileSync(filePath, content, "utf-8");
164
+ const filePath = path2.join(skillsDir, `${id}.md`);
165
+ fs2.writeFileSync(filePath, content, "utf-8");
50
166
  }
51
167
  function deleteSkill(id) {
52
168
  const skillsDir = getSkillsDir();
53
- const filePath = path.join(skillsDir, `${id}.md`);
54
- if (fs.existsSync(filePath)) {
55
- fs.unlinkSync(filePath);
169
+ const filePath = path2.join(skillsDir, `${id}.md`);
170
+ if (fs2.existsSync(filePath)) {
171
+ fs2.unlinkSync(filePath);
56
172
  }
57
173
  }
58
174
 
59
175
  // src/core/plugin-projections.ts
60
- import fs2 from "node:fs";
61
- import path2 from "node:path";
176
+ import fs3 from "node:fs";
177
+ import path3 from "node:path";
62
178
  var OWNERSHIP_MANIFEST = "mcpx-plugins.json";
63
179
  function loadOwnership(targetDir) {
64
- const manifestPath = path2.join(targetDir, OWNERSHIP_MANIFEST);
65
- if (!fs2.existsSync(manifestPath)) {
180
+ const manifestPath = path3.join(targetDir, OWNERSHIP_MANIFEST);
181
+ if (!fs3.existsSync(manifestPath)) {
66
182
  return { version: 1, plugins: {} };
67
183
  }
68
184
  try {
69
- return JSON.parse(fs2.readFileSync(manifestPath, "utf8"));
185
+ return JSON.parse(fs3.readFileSync(manifestPath, "utf8"));
70
186
  } catch {
71
187
  console.error(`[mcpx] Warning: corrupt plugin ownership manifest at ${manifestPath}, resetting`);
72
188
  return { version: 1, plugins: {} };
@@ -74,7 +190,7 @@ function loadOwnership(targetDir) {
74
190
  }
75
191
  function saveOwnership(targetDir, manifest) {
76
192
  ensureDir(targetDir);
77
- fs2.writeFileSync(path2.join(targetDir, OWNERSHIP_MANIFEST), JSON.stringify(manifest, null, 2));
193
+ fs3.writeFileSync(path3.join(targetDir, OWNERSHIP_MANIFEST), JSON.stringify(manifest, null, 2));
78
194
  }
79
195
  function recordOwned(targetDir, pluginId, paths) {
80
196
  const manifest = loadOwnership(targetDir);
@@ -98,10 +214,10 @@ function removeOwned(targetDir, pluginId) {
98
214
  function prunePluginProjections(targetDir, pluginId) {
99
215
  const paths = removeOwned(targetDir, pluginId);
100
216
  for (const p of paths) {
101
- const fullPath = path2.join(targetDir, p);
217
+ const fullPath = path3.join(targetDir, p);
102
218
  try {
103
- if (fs2.existsSync(fullPath)) {
104
- fs2.rmSync(fullPath, { recursive: true, force: true });
219
+ if (fs3.existsSync(fullPath)) {
220
+ fs3.rmSync(fullPath, { recursive: true, force: true });
105
221
  }
106
222
  } catch {}
107
223
  }
@@ -125,9 +241,9 @@ function nsName(pluginName, id) {
125
241
  return `${pluginName}__${id}`;
126
242
  }
127
243
  function assertWithinBase(base, target) {
128
- const resolvedBase = path2.resolve(base);
129
- const resolvedTarget = path2.resolve(target);
130
- if (resolvedTarget !== resolvedBase && !resolvedTarget.startsWith(resolvedBase + path2.sep)) {
244
+ const resolvedBase = path3.resolve(base);
245
+ const resolvedTarget = path3.resolve(target);
246
+ if (resolvedTarget !== resolvedBase && !resolvedTarget.startsWith(resolvedBase + path3.sep)) {
131
247
  throw new Error(`Refusing to write outside projection base: ${target} (base: ${base})`);
132
248
  }
133
249
  }
@@ -144,7 +260,7 @@ function isComponentApproved(plugin, component) {
144
260
  return plugin.components[component] ?? false;
145
261
  }
146
262
  function syncClaude(plugins) {
147
- const targetBase = path2.join(homeDir(), ".claude", "skills");
263
+ const targetBase = path3.join(homeDir(), ".claude", "skills");
148
264
  const projectedDirs = [];
149
265
  const unsupported = [];
150
266
  const skippedUnapproved = [];
@@ -155,13 +271,13 @@ function syncClaude(plugins) {
155
271
  skippedUnapproved.push(`${plugin.pluginName}:skills`);
156
272
  continue;
157
273
  }
158
- const targetDir = path2.join(targetBase, plugin.pluginName);
274
+ const targetDir = path3.join(targetBase, plugin.pluginName);
159
275
  ensureDir(targetDir);
160
- const mcpJsonSrc = path2.join(plugin.pluginRoot, ".mcp.json");
161
- const mcpJsonDest = path2.join(targetDir, ".mcp.json");
276
+ const mcpJsonSrc = path3.join(plugin.pluginRoot, ".mcp.json");
277
+ const mcpJsonDest = path3.join(targetDir, ".mcp.json");
162
278
  copyPluginDir(plugin.pluginRoot, targetDir, [".mcp.json", ".git"]);
163
- if (fs2.existsSync(mcpJsonDest)) {
164
- fs2.rmSync(mcpJsonDest, { recursive: true, force: true });
279
+ if (fs3.existsSync(mcpJsonDest)) {
280
+ fs3.rmSync(mcpJsonDest, { recursive: true, force: true });
165
281
  }
166
282
  projectedDirs.push(targetDir);
167
283
  recordOwned(targetBase, plugin.pluginId, [plugin.pluginName]);
@@ -183,7 +299,7 @@ function syncClaudeDesktop(plugins) {
183
299
  };
184
300
  }
185
301
  function syncCodex(plugins) {
186
- const targetBase = path2.join(homeDir(), ".codex", "skills");
302
+ const targetBase = path3.join(homeDir(), ".codex", "skills");
187
303
  const projectedDirs = [];
188
304
  const unsupported = ["hooks", "agents"];
189
305
  const errors = [];
@@ -195,10 +311,10 @@ function syncCodex(plugins) {
195
311
  const owned = [];
196
312
  for (const skill of plugin.skills) {
197
313
  try {
198
- const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
314
+ const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
199
315
  assertWithinBase(targetBase, targetDir);
200
316
  ensureDir(targetDir);
201
- copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
317
+ copyFileOrDir(skill.path, path3.join(targetDir, "SKILL.md"));
202
318
  owned.push(nsName(plugin.pluginName, skill.id));
203
319
  projectedDirs.push(targetDir);
204
320
  } catch (error) {
@@ -217,8 +333,8 @@ function syncCodex(plugins) {
217
333
  };
218
334
  }
219
335
  function syncCursor(plugins) {
220
- const skillsBase = path2.join(homeDir(), ".cursor", "skills");
221
- const commandsBase = path2.join(homeDir(), ".cursor", "commands");
336
+ const skillsBase = path3.join(homeDir(), ".cursor", "skills");
337
+ const commandsBase = path3.join(homeDir(), ".cursor", "commands");
222
338
  const projectedDirs = [];
223
339
  const unsupported = ["hooks", "agents"];
224
340
  const errors = [];
@@ -231,10 +347,10 @@ function syncCursor(plugins) {
231
347
  ensureDir(skillsBase);
232
348
  for (const skill of plugin.skills) {
233
349
  try {
234
- const targetDir = path2.join(skillsBase, nsName(plugin.pluginName, skill.id));
350
+ const targetDir = path3.join(skillsBase, nsName(plugin.pluginName, skill.id));
235
351
  assertWithinBase(skillsBase, targetDir);
236
352
  ensureDir(targetDir);
237
- copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
353
+ copyFileOrDir(skill.path, path3.join(targetDir, "SKILL.md"));
238
354
  ownedSkills.push(nsName(plugin.pluginName, skill.id));
239
355
  projectedDirs.push(targetDir);
240
356
  } catch (error) {
@@ -246,7 +362,7 @@ function syncCursor(plugins) {
246
362
  ensureDir(commandsBase);
247
363
  for (const cmd of plugin.commands) {
248
364
  try {
249
- const targetPath = path2.join(commandsBase, `${nsName(plugin.pluginName, cmd.id)}.md`);
365
+ const targetPath = path3.join(commandsBase, `${nsName(plugin.pluginName, cmd.id)}.md`);
250
366
  assertWithinBase(commandsBase, targetPath);
251
367
  copyFileOrDir(cmd.path, targetPath);
252
368
  ownedCommands.push(`${nsName(plugin.pluginName, cmd.id)}.md`);
@@ -270,7 +386,7 @@ function syncCursor(plugins) {
270
386
  };
271
387
  }
272
388
  function syncVsCode(plugins) {
273
- const skillsBase = path2.join(homeDir(), ".copilot", "skills");
389
+ const skillsBase = path3.join(homeDir(), ".copilot", "skills");
274
390
  const projectedDirs = [];
275
391
  const unsupported = ["hooks", "agents"];
276
392
  const errors = [];
@@ -282,10 +398,10 @@ function syncVsCode(plugins) {
282
398
  const owned = [];
283
399
  for (const skill of plugin.skills) {
284
400
  try {
285
- const targetDir = path2.join(skillsBase, nsName(plugin.pluginName, skill.id));
401
+ const targetDir = path3.join(skillsBase, nsName(plugin.pluginName, skill.id));
286
402
  assertWithinBase(skillsBase, targetDir);
287
403
  ensureDir(targetDir);
288
- copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
404
+ copyFileOrDir(skill.path, path3.join(targetDir, "SKILL.md"));
289
405
  owned.push(nsName(plugin.pluginName, skill.id));
290
406
  projectedDirs.push(targetDir);
291
407
  } catch (error) {
@@ -304,7 +420,7 @@ function syncVsCode(plugins) {
304
420
  };
305
421
  }
306
422
  function syncQwen(plugins) {
307
- const targetBase = path2.join(homeDir(), ".qwen", "skills");
423
+ const targetBase = path3.join(homeDir(), ".qwen", "skills");
308
424
  const projectedDirs = [];
309
425
  const unsupported = ["hooks", "agents", "commands"];
310
426
  const errors = [];
@@ -316,10 +432,10 @@ function syncQwen(plugins) {
316
432
  const owned = [];
317
433
  for (const skill of plugin.skills) {
318
434
  try {
319
- const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
435
+ const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
320
436
  assertWithinBase(targetBase, targetDir);
321
437
  ensureDir(targetDir);
322
- copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
438
+ copyFileOrDir(skill.path, path3.join(targetDir, "SKILL.md"));
323
439
  owned.push(nsName(plugin.pluginName, skill.id));
324
440
  projectedDirs.push(targetDir);
325
441
  } catch (error) {
@@ -338,7 +454,7 @@ function syncQwen(plugins) {
338
454
  };
339
455
  }
340
456
  function syncCline(plugins) {
341
- const targetBase = path2.join(homeDir(), ".config", "cline", "skills");
457
+ const targetBase = path3.join(homeDir(), ".config", "cline", "skills");
342
458
  const projectedDirs = [];
343
459
  const unsupported = ["hooks", "agents", "commands"];
344
460
  const errors = [];
@@ -350,10 +466,10 @@ function syncCline(plugins) {
350
466
  const owned = [];
351
467
  for (const skill of plugin.skills) {
352
468
  try {
353
- const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
469
+ const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
354
470
  assertWithinBase(targetBase, targetDir);
355
471
  ensureDir(targetDir);
356
- copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
472
+ copyFileOrDir(skill.path, path3.join(targetDir, "SKILL.md"));
357
473
  owned.push(nsName(plugin.pluginName, skill.id));
358
474
  projectedDirs.push(targetDir);
359
475
  } catch (error) {
@@ -372,7 +488,7 @@ function syncCline(plugins) {
372
488
  };
373
489
  }
374
490
  function syncKiro(plugins) {
375
- const targetBase = path2.join(homeDir(), ".kiro", "skills");
491
+ const targetBase = path3.join(homeDir(), ".kiro", "skills");
376
492
  const projectedDirs = [];
377
493
  const unsupported = ["hooks", "agents", "commands"];
378
494
  const errors = [];
@@ -384,10 +500,10 @@ function syncKiro(plugins) {
384
500
  const owned = [];
385
501
  for (const skill of plugin.skills) {
386
502
  try {
387
- const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
503
+ const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
388
504
  assertWithinBase(targetBase, targetDir);
389
505
  ensureDir(targetDir);
390
- copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
506
+ copyFileOrDir(skill.path, path3.join(targetDir, "SKILL.md"));
391
507
  owned.push(nsName(plugin.pluginName, skill.id));
392
508
  projectedDirs.push(targetDir);
393
509
  } catch (error) {
@@ -431,14 +547,14 @@ function syncPluginsToClient(clientId, plugins) {
431
547
  return { clientId, status: "SKIPPED", projectedDirs: [], unsupported: [] };
432
548
  }
433
549
  const targetBaseMap = {
434
- claude: path2.join(homeDir(), ".claude", "skills"),
550
+ claude: path3.join(homeDir(), ".claude", "skills"),
435
551
  "claude-desktop": "",
436
- codex: path2.join(homeDir(), ".codex", "skills"),
437
- cursor: path2.join(homeDir(), ".cursor"),
438
- vscode: path2.join(homeDir(), ".copilot", "skills"),
439
- qwen: path2.join(homeDir(), ".qwen", "skills"),
440
- cline: path2.join(homeDir(), ".config", "cline", "skills"),
441
- kiro: path2.join(homeDir(), ".kiro", "skills"),
552
+ codex: path3.join(homeDir(), ".codex", "skills"),
553
+ cursor: path3.join(homeDir(), ".cursor"),
554
+ vscode: path3.join(homeDir(), ".copilot", "skills"),
555
+ qwen: path3.join(homeDir(), ".qwen", "skills"),
556
+ cline: path3.join(homeDir(), ".config", "cline", "skills"),
557
+ kiro: path3.join(homeDir(), ".kiro", "skills"),
442
558
  opencode: ""
443
559
  };
444
560
  const target = targetBaseMap[clientId];
@@ -451,17 +567,17 @@ function syncPluginsToClient(clientId, plugins) {
451
567
  function copyPluginDir(src, dest, exclude = [], errors) {
452
568
  const excludeSet = new Set(exclude);
453
569
  ensureDir(dest);
454
- const entries = fs2.readdirSync(src, { withFileTypes: true });
570
+ const entries = fs3.readdirSync(src, { withFileTypes: true });
455
571
  for (const entry of entries) {
456
572
  if (excludeSet.has(entry.name))
457
573
  continue;
458
- const srcPath = path2.join(src, entry.name);
459
- const destPath = path2.join(dest, entry.name);
574
+ const srcPath = path3.join(src, entry.name);
575
+ const destPath = path3.join(dest, entry.name);
460
576
  if (entry.isDirectory()) {
461
577
  copyPluginDir(srcPath, destPath, exclude, errors);
462
578
  } else if (entry.isFile()) {
463
579
  try {
464
- fs2.copyFileSync(srcPath, destPath);
580
+ fs3.copyFileSync(srcPath, destPath);
465
581
  } catch (e) {
466
582
  errors?.push(`Failed to copy ${srcPath}: ${e.message}`);
467
583
  }
@@ -470,11 +586,11 @@ function copyPluginDir(src, dest, exclude = [], errors) {
470
586
  }
471
587
  function copyFileOrDir(src, dest, errors) {
472
588
  try {
473
- ensureDir(path2.dirname(dest));
474
- if (fs2.statSync(src).isDirectory()) {
589
+ ensureDir(path3.dirname(dest));
590
+ if (fs3.statSync(src).isDirectory()) {
475
591
  copyPluginDir(src, dest, [], errors);
476
592
  } else {
477
- fs2.copyFileSync(src, dest);
593
+ fs3.copyFileSync(src, dest);
478
594
  }
479
595
  } catch (e) {
480
596
  errors?.push(`Failed to copy ${src} -> ${dest}: ${e.message}`);
@@ -485,21 +601,21 @@ function copyFileOrDir(src, dest, errors) {
485
601
  var APP_VERSION = "0.1.3";
486
602
 
487
603
  // src/adapters/claude.ts
488
- import fs4 from "node:fs";
489
- import path4 from "node:path";
604
+ import fs5 from "node:fs";
605
+ import path5 from "node:path";
490
606
  import { z } from "zod";
491
607
 
492
608
  // src/core/skill-projections.ts
493
- import fs3 from "node:fs";
494
- import path3 from "node:path";
609
+ import fs4 from "node:fs";
610
+ import path4 from "node:path";
495
611
  var OWNERSHIP_MANIFEST2 = "mcpx-skills.json";
496
612
  function loadOwnership2(targetDir) {
497
- const manifestPath = path3.join(targetDir, OWNERSHIP_MANIFEST2);
498
- if (!fs3.existsSync(manifestPath)) {
613
+ const manifestPath = path4.join(targetDir, OWNERSHIP_MANIFEST2);
614
+ if (!fs4.existsSync(manifestPath)) {
499
615
  return { version: 1, paths: [] };
500
616
  }
501
617
  try {
502
- return JSON.parse(fs3.readFileSync(manifestPath, "utf8"));
618
+ return JSON.parse(fs4.readFileSync(manifestPath, "utf8"));
503
619
  } catch {
504
620
  console.error(`[mcpx] Warning: corrupt ownership manifest at ${manifestPath}, resetting`);
505
621
  return { version: 1, paths: [] };
@@ -507,24 +623,24 @@ function loadOwnership2(targetDir) {
507
623
  }
508
624
  function saveOwnership2(targetDir, manifest) {
509
625
  ensureDir(targetDir);
510
- fs3.writeFileSync(path3.join(targetDir, OWNERSHIP_MANIFEST2), JSON.stringify(manifest, null, 2));
626
+ fs4.writeFileSync(path4.join(targetDir, OWNERSHIP_MANIFEST2), JSON.stringify(manifest, null, 2));
511
627
  }
512
628
  function projectSkillsToDir(targetDir, skills, layout) {
513
629
  const owned = loadOwnership2(targetDir);
514
630
  const newPaths = new Set(skills.map((s) => layout === "dir" ? `${s.id}/SKILL.md` : `${s.id}.md`));
515
631
  for (const ownedPath of owned.paths) {
516
632
  if (!newPaths.has(ownedPath)) {
517
- const fullPath = path3.join(targetDir, ownedPath);
633
+ const fullPath = path4.join(targetDir, ownedPath);
518
634
  try {
519
- if (fs3.existsSync(fullPath)) {
520
- fs3.rmSync(fullPath, { recursive: true, force: true });
635
+ if (fs4.existsSync(fullPath)) {
636
+ fs4.rmSync(fullPath, { recursive: true, force: true });
521
637
  }
522
638
  if (layout === "dir") {
523
- const dirPath = path3.join(targetDir, path3.dirname(ownedPath));
639
+ const dirPath = path4.join(targetDir, path4.dirname(ownedPath));
524
640
  try {
525
- const remaining = fs3.readdirSync(dirPath);
641
+ const remaining = fs4.readdirSync(dirPath);
526
642
  if (remaining.length === 0) {
527
- fs3.rmSync(dirPath, { recursive: true, force: true });
643
+ fs4.rmSync(dirPath, { recursive: true, force: true });
528
644
  }
529
645
  } catch {}
530
646
  }
@@ -534,9 +650,9 @@ function projectSkillsToDir(targetDir, skills, layout) {
534
650
  }
535
651
  }
536
652
  for (const skill of skills) {
537
- const filePath = layout === "dir" ? path3.join(targetDir, skill.id, "SKILL.md") : path3.join(targetDir, `${skill.id}.md`);
538
- ensureDir(path3.dirname(filePath));
539
- fs3.writeFileSync(filePath, skill.content, "utf-8");
653
+ const filePath = layout === "dir" ? path4.join(targetDir, skill.id, "SKILL.md") : path4.join(targetDir, `${skill.id}.md`);
654
+ ensureDir(path4.dirname(filePath));
655
+ fs4.writeFileSync(filePath, skill.content, "utf-8");
540
656
  }
541
657
  saveOwnership2(targetDir, { version: 1, paths: Array.from(newPaths) });
542
658
  }
@@ -703,9 +819,9 @@ function detectManagedEntryDrift(managedIndex, clientId, entryName, existingValu
703
819
  // src/adapters/claude.ts
704
820
  function normalizeProjectKey(p) {
705
821
  try {
706
- return fs4.realpathSync(path4.resolve(p));
822
+ return fs5.realpathSync(path5.resolve(p));
707
823
  } catch {
708
- return path4.resolve(p);
824
+ return path5.resolve(p);
709
825
  }
710
826
  }
711
827
  function syncProjectDisabledArray(project, managedNames, disabledForThisProject) {
@@ -732,7 +848,7 @@ var claudeEntrySchema = z.object({
732
848
  class ClaudeAdapter {
733
849
  id = "claude";
734
850
  detectConfigPath() {
735
- return path4.join(homeDir(), ".claude.json");
851
+ return path5.join(homeDir(), ".claude.json");
736
852
  }
737
853
  supportsHttp() {
738
854
  return true;
@@ -741,7 +857,7 @@ class ClaudeAdapter {
741
857
  return syncPluginsToClient(this.id, plugins);
742
858
  }
743
859
  syncSkills(skills) {
744
- projectSkillsToDir(path4.join(homeDir(), ".claude", "skills"), skills, "dir");
860
+ projectSkillsToDir(path5.join(homeDir(), ".claude", "skills"), skills, "dir");
745
861
  }
746
862
  scanForImports(_config, managedIndex) {
747
863
  const configPath = this.detectConfigPath();
@@ -868,7 +984,7 @@ class ClaudeAdapter {
868
984
 
869
985
  // src/adapters/claude-desktop.ts
870
986
  import { execFileSync } from "node:child_process";
871
- import path5 from "node:path";
987
+ import path6 from "node:path";
872
988
  import { z as z2 } from "zod";
873
989
  var stringMapSchema2 = z2.record(z2.string(), z2.string());
874
990
  var claudeDesktopEntrySchema = z2.object({
@@ -895,12 +1011,12 @@ class ClaudeDesktopAdapter {
895
1011
  id = "claude-desktop";
896
1012
  detectConfigPath() {
897
1013
  if (process.platform === "linux") {
898
- return path5.join(homeDir(), ".config", "Claude", "claude_desktop_config.json");
1014
+ return path6.join(homeDir(), ".config", "Claude", "claude_desktop_config.json");
899
1015
  }
900
1016
  if (process.platform === "win32") {
901
- return path5.join(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json");
1017
+ return path6.join(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json");
902
1018
  }
903
- return path5.join(homeDir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
1019
+ return path6.join(homeDir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
904
1020
  }
905
1021
  supportsHttp() {
906
1022
  return true;
@@ -908,6 +1024,13 @@ class ClaudeDesktopAdapter {
908
1024
  syncPlugins(plugins) {
909
1025
  return syncPluginsToClient(this.id, plugins);
910
1026
  }
1027
+ syncSkills(skills) {
1028
+ const configPath = this.detectConfigPath();
1029
+ if (!configPath) {
1030
+ return;
1031
+ }
1032
+ projectSkillsToDir(path6.join(path6.dirname(configPath), "skills"), skills, "dir");
1033
+ }
911
1034
  scanForImports(_config, managedIndex) {
912
1035
  const configPath = this.detectConfigPath();
913
1036
  const result = emptyImportScan(this.id, configPath ?? undefined);
@@ -1002,8 +1125,8 @@ class ClaudeDesktopAdapter {
1002
1125
  }
1003
1126
 
1004
1127
  // src/adapters/codex.ts
1005
- import path6 from "node:path";
1006
- import fs5 from "node:fs";
1128
+ import path7 from "node:path";
1129
+ import fs6 from "node:fs";
1007
1130
  import { parse, stringify } from "@iarna/toml";
1008
1131
  import { z as z3 } from "zod";
1009
1132
  var stringMapSchema3 = z3.preprocess((value) => {
@@ -1026,7 +1149,7 @@ var codexEntrySchema = z3.object({
1026
1149
  class CodexAdapter {
1027
1150
  id = "codex";
1028
1151
  detectConfigPath() {
1029
- return path6.join(homeDir(), ".codex", "config.toml");
1152
+ return path7.join(homeDir(), ".codex", "config.toml");
1030
1153
  }
1031
1154
  supportsHttp() {
1032
1155
  return true;
@@ -1035,15 +1158,15 @@ class CodexAdapter {
1035
1158
  return syncPluginsToClient(this.id, plugins);
1036
1159
  }
1037
1160
  syncSkills(skills) {
1038
- projectSkillsToDir(path6.join(homeDir(), ".codex", "skills"), skills, "dir");
1161
+ projectSkillsToDir(path7.join(homeDir(), ".codex", "skills"), skills, "dir");
1039
1162
  }
1040
1163
  scanForImports(_config, managedIndex) {
1041
1164
  const configPath = this.detectConfigPath();
1042
1165
  const result = emptyImportScan(this.id, configPath ?? undefined);
1043
- if (!configPath || !fs5.existsSync(configPath)) {
1166
+ if (!configPath || !fs6.existsSync(configPath)) {
1044
1167
  return result;
1045
1168
  }
1046
- const existing = fs5.readFileSync(configPath, "utf8");
1169
+ const existing = fs6.readFileSync(configPath, "utf8");
1047
1170
  const doc = existing.trim().length > 0 ? parse(existing) : {};
1048
1171
  const mcpServers = doc.mcp_servers ?? {};
1049
1172
  for (const [name, rawEntry] of Object.entries(mcpServers)) {
@@ -1098,7 +1221,7 @@ class CodexAdapter {
1098
1221
  return errorResult(this.id, undefined, "Unable to resolve Codex config.toml path.");
1099
1222
  }
1100
1223
  try {
1101
- const existing = fs5.existsSync(configPath) ? fs5.readFileSync(configPath, "utf8") : "";
1224
+ const existing = fs6.existsSync(configPath) ? fs6.readFileSync(configPath, "utf8") : "";
1102
1225
  const doc = existing.trim().length > 0 ? parse(existing) : {};
1103
1226
  const mcpServers = doc.mcp_servers ?? {};
1104
1227
  removeSourceEntries(mcpServers, options.sourceEntriesToRemove);
@@ -1121,10 +1244,10 @@ class CodexAdapter {
1121
1244
  mcpServers[name] = entry;
1122
1245
  }
1123
1246
  doc.mcp_servers = mcpServers;
1124
- fs5.mkdirSync(path6.dirname(configPath), { recursive: true });
1247
+ fs6.mkdirSync(path7.dirname(configPath), { recursive: true });
1125
1248
  const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
1126
- fs5.writeFileSync(tmpPath, stringify(doc), { mode: 384 });
1127
- fs5.renameSync(tmpPath, configPath);
1249
+ fs6.writeFileSync(tmpPath, stringify(doc), { mode: 384 });
1250
+ fs6.renameSync(tmpPath, configPath);
1128
1251
  setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
1129
1252
  return { ...okResult(this.id, configPath), driftedEntries: driftedNames.length > 0 ? driftedNames : undefined };
1130
1253
  } catch (error) {
@@ -1134,7 +1257,7 @@ class CodexAdapter {
1134
1257
  }
1135
1258
 
1136
1259
  // src/adapters/cursor.ts
1137
- import path7 from "node:path";
1260
+ import path8 from "node:path";
1138
1261
  import { z as z4 } from "zod";
1139
1262
  var stringMapSchema4 = z4.record(z4.string(), z4.string());
1140
1263
  var cursorEntrySchema = z4.object({
@@ -1151,7 +1274,7 @@ var cursorEntrySchema = z4.object({
1151
1274
  class CursorAdapter {
1152
1275
  id = "cursor";
1153
1276
  detectConfigPath() {
1154
- return path7.join(homeDir(), ".cursor", "mcp.json");
1277
+ return path8.join(homeDir(), ".cursor", "mcp.json");
1155
1278
  }
1156
1279
  supportsHttp() {
1157
1280
  return true;
@@ -1160,7 +1283,7 @@ class CursorAdapter {
1160
1283
  return syncPluginsToClient(this.id, plugins);
1161
1284
  }
1162
1285
  syncSkills(skills) {
1163
- projectSkillsToDir(path7.join(homeDir(), ".cursor", "skills"), skills, "dir");
1286
+ projectSkillsToDir(path8.join(homeDir(), ".cursor", "skills"), skills, "dir");
1164
1287
  }
1165
1288
  scanForImports(_config, managedIndex) {
1166
1289
  const configPath = this.detectConfigPath();
@@ -1264,8 +1387,8 @@ class CursorAdapter {
1264
1387
  }
1265
1388
 
1266
1389
  // src/adapters/cline.ts
1267
- import path8 from "node:path";
1268
- import fs6 from "node:fs";
1390
+ import path9 from "node:path";
1391
+ import fs7 from "node:fs";
1269
1392
  import { z as z5 } from "zod";
1270
1393
  var HTTP_TRANSPORT_TYPES = new Set(["http", "sse", "streamableHttp"]);
1271
1394
  var stringMapSchema5 = z5.record(z5.string(), z5.string());
@@ -1283,22 +1406,22 @@ var clineEntrySchema = z5.object({
1283
1406
  function getCandidatePaths() {
1284
1407
  if (process.platform === "linux") {
1285
1408
  return [
1286
- path8.join(homeDir(), ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1287
- path8.join(homeDir(), ".config", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1288
- path8.join(homeDir(), ".cline", "settings", "cline_mcp_settings.json")
1409
+ path9.join(homeDir(), ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1410
+ path9.join(homeDir(), ".config", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1411
+ path9.join(homeDir(), ".cline", "settings", "cline_mcp_settings.json")
1289
1412
  ];
1290
1413
  }
1291
1414
  if (process.platform === "win32") {
1292
1415
  return [
1293
- path8.join(process.env.APPDATA ?? "", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1294
- path8.join(process.env.APPDATA ?? "", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1295
- path8.join(homeDir(), ".cline", "settings", "cline_mcp_settings.json")
1416
+ path9.join(process.env.APPDATA ?? "", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1417
+ path9.join(process.env.APPDATA ?? "", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1418
+ path9.join(homeDir(), ".cline", "settings", "cline_mcp_settings.json")
1296
1419
  ];
1297
1420
  }
1298
1421
  return [
1299
- path8.join(homeDir(), "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1300
- path8.join(homeDir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1301
- path8.join(homeDir(), ".cline", "settings", "cline_mcp_settings.json")
1422
+ path9.join(homeDir(), "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1423
+ path9.join(homeDir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
1424
+ path9.join(homeDir(), ".cline", "settings", "cline_mcp_settings.json")
1302
1425
  ];
1303
1426
  }
1304
1427
 
@@ -1307,7 +1430,7 @@ class ClineAdapter {
1307
1430
  detectConfigPath() {
1308
1431
  const candidates = getCandidatePaths();
1309
1432
  for (const candidate of candidates) {
1310
- if (fs6.existsSync(candidate)) {
1433
+ if (fs7.existsSync(candidate)) {
1311
1434
  return candidate;
1312
1435
  }
1313
1436
  }
@@ -1320,12 +1443,12 @@ class ClineAdapter {
1320
1443
  return syncPluginsToClient(this.id, plugins);
1321
1444
  }
1322
1445
  syncSkills(skills) {
1323
- projectSkillsToDir(path8.join(homeDir(), ".config", "cline", "skills"), skills, "dir");
1446
+ projectSkillsToDir(path9.join(homeDir(), ".config", "cline", "skills"), skills, "dir");
1324
1447
  }
1325
1448
  scanForImports(_config, managedIndex) {
1326
1449
  const configPath = this.detectConfigPath();
1327
1450
  const result = emptyImportScan(this.id, configPath ?? undefined);
1328
- if (!configPath || !fs6.existsSync(configPath)) {
1451
+ if (!configPath || !fs7.existsSync(configPath)) {
1329
1452
  return result;
1330
1453
  }
1331
1454
  const raw = readJsonFile(configPath, {});
@@ -1384,7 +1507,7 @@ class ClineAdapter {
1384
1507
  if (!configPath) {
1385
1508
  return errorResult(this.id, undefined, "Unable to resolve Cline MCP config path.");
1386
1509
  }
1387
- if (!fs6.existsSync(configPath)) {
1510
+ if (!fs7.existsSync(configPath)) {
1388
1511
  return okResult(this.id, configPath, "Cline config not found; skipping sync.");
1389
1512
  }
1390
1513
  try {
@@ -1426,7 +1549,7 @@ class ClineAdapter {
1426
1549
  }
1427
1550
 
1428
1551
  // src/adapters/kiro.ts
1429
- import path9 from "node:path";
1552
+ import path10 from "node:path";
1430
1553
  import { z as z6 } from "zod";
1431
1554
  var stringMapSchema6 = z6.record(z6.string(), z6.string());
1432
1555
  var kiroEntrySchema = z6.object({
@@ -1443,7 +1566,7 @@ var kiroEntrySchema = z6.object({
1443
1566
  class KiroAdapter {
1444
1567
  id = "kiro";
1445
1568
  detectConfigPath() {
1446
- return path9.join(homeDir(), ".kiro", "settings", "mcp.json");
1569
+ return path10.join(homeDir(), ".kiro", "settings", "mcp.json");
1447
1570
  }
1448
1571
  supportsHttp() {
1449
1572
  return true;
@@ -1548,12 +1671,12 @@ class KiroAdapter {
1548
1671
  }
1549
1672
  }
1550
1673
  syncSkills(skills) {
1551
- projectSkillsToDir(path9.join(homeDir(), ".kiro", "skills"), skills, "flat");
1674
+ projectSkillsToDir(path10.join(homeDir(), ".kiro", "skills"), skills, "flat");
1552
1675
  }
1553
1676
  }
1554
1677
 
1555
1678
  // src/adapters/opencode.ts
1556
- import path10 from "node:path";
1679
+ import path11 from "node:path";
1557
1680
  import { z as z7 } from "zod";
1558
1681
  var stringMapSchema7 = z7.record(z7.string(), z7.string());
1559
1682
  var openCodeEntrySchema = z7.object({
@@ -1571,7 +1694,7 @@ var openCodeEntrySchema = z7.object({
1571
1694
  class OpenCodeAdapter {
1572
1695
  id = "opencode";
1573
1696
  detectConfigPath() {
1574
- return path10.join(homeDir(), ".config", "opencode", "opencode.json");
1697
+ return path11.join(homeDir(), ".config", "opencode", "opencode.json");
1575
1698
  }
1576
1699
  supportsHttp() {
1577
1700
  return true;
@@ -1579,6 +1702,13 @@ class OpenCodeAdapter {
1579
1702
  syncPlugins(plugins) {
1580
1703
  return syncPluginsToClient(this.id, plugins);
1581
1704
  }
1705
+ syncSkills(skills) {
1706
+ const configPath = this.detectConfigPath();
1707
+ if (!configPath) {
1708
+ return;
1709
+ }
1710
+ projectSkillsToDir(path11.join(path11.dirname(configPath), "skills"), skills, "dir");
1711
+ }
1582
1712
  scanForImports(_config, managedIndex) {
1583
1713
  const configPath = this.detectConfigPath();
1584
1714
  const result = emptyImportScan(this.id, configPath ?? undefined);
@@ -1684,7 +1814,7 @@ class OpenCodeAdapter {
1684
1814
  }
1685
1815
 
1686
1816
  // src/adapters/vscode.ts
1687
- import path11 from "node:path";
1817
+ import path12 from "node:path";
1688
1818
  import { z as z8 } from "zod";
1689
1819
  var stringMapSchema8 = z8.record(z8.string(), z8.string());
1690
1820
  var vscodeEntrySchema = z8.object({
@@ -1702,12 +1832,12 @@ class VsCodeAdapter {
1702
1832
  id = "vscode";
1703
1833
  detectConfigPath() {
1704
1834
  if (process.platform === "linux") {
1705
- return path11.join(homeDir(), ".config", "Code", "User", "mcp.json");
1835
+ return path12.join(homeDir(), ".config", "Code", "User", "mcp.json");
1706
1836
  }
1707
1837
  if (process.platform === "win32") {
1708
- return path11.join(process.env.APPDATA ?? "", "Code", "User", "mcp.json");
1838
+ return path12.join(process.env.APPDATA ?? "", "Code", "User", "mcp.json");
1709
1839
  }
1710
- return path11.join(homeDir(), "Library", "Application Support", "Code", "User", "mcp.json");
1840
+ return path12.join(homeDir(), "Library", "Application Support", "Code", "User", "mcp.json");
1711
1841
  }
1712
1842
  supportsHttp() {
1713
1843
  return true;
@@ -1716,7 +1846,7 @@ class VsCodeAdapter {
1716
1846
  return syncPluginsToClient(this.id, plugins);
1717
1847
  }
1718
1848
  syncSkills(skills) {
1719
- projectSkillsToDir(path11.join(homeDir(), ".copilot", "skills"), skills, "dir");
1849
+ projectSkillsToDir(path12.join(homeDir(), ".copilot", "skills"), skills, "dir");
1720
1850
  }
1721
1851
  scanForImports(_config, managedIndex) {
1722
1852
  const configPath = this.detectConfigPath();
@@ -1820,7 +1950,7 @@ class VsCodeAdapter {
1820
1950
  }
1821
1951
 
1822
1952
  // src/adapters/qwen.ts
1823
- import path12 from "node:path";
1953
+ import path13 from "node:path";
1824
1954
  import { z as z9 } from "zod";
1825
1955
  var stringMapSchema9 = z9.record(z9.string(), z9.string());
1826
1956
  var qwenEntrySchema = z9.object({
@@ -1837,7 +1967,7 @@ var qwenEntrySchema = z9.object({
1837
1967
  class QwenAdapter {
1838
1968
  id = "qwen";
1839
1969
  detectConfigPath() {
1840
- return path12.join(homeDir(), ".qwen", "settings.json");
1970
+ return path13.join(homeDir(), ".qwen", "settings.json");
1841
1971
  }
1842
1972
  supportsHttp() {
1843
1973
  return true;
@@ -1955,13 +2085,13 @@ class QwenAdapter {
1955
2085
  }
1956
2086
  }
1957
2087
  syncSkills(skills) {
1958
- projectSkillsToDir(path12.join(homeDir(), ".qwen", "skills"), skills, "flat");
2088
+ projectSkillsToDir(path13.join(homeDir(), ".qwen", "skills"), skills, "flat");
1959
2089
  }
1960
2090
  }
1961
2091
 
1962
2092
  // src/adapters/openclaw.ts
1963
- import fs7 from "node:fs";
1964
- import path13 from "node:path";
2093
+ import fs8 from "node:fs";
2094
+ import path14 from "node:path";
1965
2095
  import { z as z10 } from "zod";
1966
2096
  var stringMapSchema10 = z10.record(z10.string(), z10.string());
1967
2097
  var openclawEntrySchema = z10.object({
@@ -1979,7 +2109,7 @@ var openclawEntrySchema = z10.object({
1979
2109
  class OpenClawAdapter {
1980
2110
  id = "openclaw";
1981
2111
  detectConfigPath() {
1982
- return process.env.OPENCLAW_CONFIG_PATH ?? path13.join(homeDir(), ".openclaw", "openclaw.json");
2112
+ return process.env.OPENCLAW_CONFIG_PATH ?? path14.join(homeDir(), ".openclaw", "openclaw.json");
1983
2113
  }
1984
2114
  supportsHttp() {
1985
2115
  return true;
@@ -1988,7 +2118,7 @@ class OpenClawAdapter {
1988
2118
  return syncPluginsToClient(this.id, plugins);
1989
2119
  }
1990
2120
  syncSkills(skills) {
1991
- projectSkillsToDir(path13.join(homeDir(), ".openclaw", "skills"), skills, "dir");
2121
+ projectSkillsToDir(path14.join(homeDir(), ".openclaw", "skills"), skills, "dir");
1992
2122
  }
1993
2123
  scanForImports(_config, managedIndex) {
1994
2124
  const configPath = this.detectConfigPath();
@@ -1998,7 +2128,7 @@ class OpenClawAdapter {
1998
2128
  }
1999
2129
  let raw;
2000
2130
  try {
2001
- raw = JSON.parse(fs7.readFileSync(configPath, "utf8"));
2131
+ raw = JSON.parse(fs8.readFileSync(configPath, "utf8"));
2002
2132
  } catch {
2003
2133
  return result;
2004
2134
  }
@@ -2065,9 +2195,9 @@ class OpenClawAdapter {
2065
2195
  }
2066
2196
  try {
2067
2197
  let raw;
2068
- if (fs7.existsSync(configPath)) {
2198
+ if (fs8.existsSync(configPath)) {
2069
2199
  try {
2070
- raw = JSON.parse(fs7.readFileSync(configPath, "utf8"));
2200
+ raw = JSON.parse(fs8.readFileSync(configPath, "utf8"));
2071
2201
  } catch {
2072
2202
  return errorResult(this.id, configPath, "OpenClaw config contains invalid JSON (possibly JSON5). Cannot safely write.");
2073
2203
  }
@@ -2110,8 +2240,8 @@ class OpenClawAdapter {
2110
2240
  }
2111
2241
 
2112
2242
  // src/adapters/hermes.ts
2113
- import fs8 from "node:fs";
2114
- import path14 from "node:path";
2243
+ import fs9 from "node:fs";
2244
+ import path15 from "node:path";
2115
2245
  import YAML from "yaml";
2116
2246
  import { z as z11 } from "zod";
2117
2247
  var stringMapSchema11 = z11.record(z11.string(), z11.string());
@@ -2130,7 +2260,7 @@ var hermesEntrySchema = z11.object({
2130
2260
  class HermesAdapter {
2131
2261
  id = "hermes";
2132
2262
  detectConfigPath() {
2133
- return path14.join(homeDir(), ".hermes", "config.yaml");
2263
+ return path15.join(homeDir(), ".hermes", "config.yaml");
2134
2264
  }
2135
2265
  supportsHttp() {
2136
2266
  return true;
@@ -2139,15 +2269,15 @@ class HermesAdapter {
2139
2269
  return syncPluginsToClient(this.id, plugins);
2140
2270
  }
2141
2271
  syncSkills(skills) {
2142
- projectSkillsToDir(path14.join(homeDir(), ".hermes", "skills"), skills, "dir");
2272
+ projectSkillsToDir(path15.join(homeDir(), ".hermes", "skills"), skills, "dir");
2143
2273
  }
2144
2274
  scanForImports(_config, managedIndex) {
2145
2275
  const configPath = this.detectConfigPath();
2146
2276
  const result = emptyImportScan(this.id, configPath ?? undefined);
2147
- if (!configPath || !fs8.existsSync(configPath)) {
2277
+ if (!configPath || !fs9.existsSync(configPath)) {
2148
2278
  return result;
2149
2279
  }
2150
- const existing = fs8.readFileSync(configPath, "utf8");
2280
+ const existing = fs9.readFileSync(configPath, "utf8");
2151
2281
  const doc = YAML.parse(existing) ?? {};
2152
2282
  const mcpServers = doc.mcp_servers ?? {};
2153
2283
  for (const [name, rawEntry] of Object.entries(mcpServers)) {
@@ -2205,7 +2335,7 @@ class HermesAdapter {
2205
2335
  return errorResult(this.id, undefined, "Unable to resolve Hermes config.yaml path.");
2206
2336
  }
2207
2337
  try {
2208
- const existing = fs8.existsSync(configPath) ? fs8.readFileSync(configPath, "utf8") : "";
2338
+ const existing = fs9.existsSync(configPath) ? fs9.readFileSync(configPath, "utf8") : "";
2209
2339
  const doc = existing.trim().length > 0 ? YAML.parse(existing) ?? {} : {};
2210
2340
  const mcpServers = doc.mcp_servers ?? {};
2211
2341
  removeSourceEntries(mcpServers, options.sourceEntriesToRemove);
@@ -2226,10 +2356,10 @@ class HermesAdapter {
2226
2356
  mcpServers[name] = entry;
2227
2357
  }
2228
2358
  doc.mcp_servers = mcpServers;
2229
- fs8.mkdirSync(path14.dirname(configPath), { recursive: true });
2359
+ fs9.mkdirSync(path15.dirname(configPath), { recursive: true });
2230
2360
  const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
2231
- fs8.writeFileSync(tmpPath, YAML.stringify(doc), { mode: 384 });
2232
- fs8.renameSync(tmpPath, configPath);
2361
+ fs9.writeFileSync(tmpPath, YAML.stringify(doc), { mode: 384 });
2362
+ fs9.renameSync(tmpPath, configPath);
2233
2363
  setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
2234
2364
  return okResult(this.id, configPath);
2235
2365
  } catch (error) {
@@ -2277,28 +2407,28 @@ function saveManagedIndex(index, filePath = getManagedIndexPath()) {
2277
2407
  }
2278
2408
 
2279
2409
  // src/core/managed-index-lock.ts
2280
- import fs9 from "node:fs";
2281
- import path15 from "node:path";
2410
+ import fs10 from "node:fs";
2411
+ import path16 from "node:path";
2282
2412
  function isStale(lockPath, maxAgeMs = 5000) {
2283
2413
  try {
2284
- const stat = fs9.statSync(lockPath);
2414
+ const stat = fs10.statSync(lockPath);
2285
2415
  return Date.now() - stat.mtimeMs > maxAgeMs;
2286
2416
  } catch {
2287
2417
  return true;
2288
2418
  }
2289
2419
  }
2290
2420
  function withManagedIndexLock(lockPath, fn) {
2291
- fs9.mkdirSync(path15.dirname(lockPath), { recursive: true });
2421
+ fs10.mkdirSync(path16.dirname(lockPath), { recursive: true });
2292
2422
  const deadline = Date.now() + 5000;
2293
2423
  while (true) {
2294
2424
  try {
2295
- fs9.writeFileSync(lockPath, `${process.pid}
2425
+ fs10.writeFileSync(lockPath, `${process.pid}
2296
2426
  `, { flag: "wx" });
2297
2427
  break;
2298
2428
  } catch {
2299
2429
  if (isStale(lockPath)) {
2300
2430
  try {
2301
- fs9.unlinkSync(lockPath);
2431
+ fs10.unlinkSync(lockPath);
2302
2432
  } catch {}
2303
2433
  continue;
2304
2434
  }
@@ -2311,7 +2441,7 @@ function withManagedIndexLock(lockPath, fn) {
2311
2441
  return fn();
2312
2442
  } finally {
2313
2443
  try {
2314
- fs9.unlinkSync(lockPath);
2444
+ fs10.unlinkSync(lockPath);
2315
2445
  } catch {}
2316
2446
  }
2317
2447
  }
@@ -2583,4 +2713,4 @@ function persistSyncState(summary, config) {
2583
2713
  }
2584
2714
  }
2585
2715
 
2586
- export { listSkills, getSkill, saveSkill, deleteSkill, prunePluginProjections, pruneAllPluginProjections, syncPluginsToClient, APP_VERSION, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients, persistSyncState };
2716
+ export { mutateConfig, mutateProjectConfig, mutateActiveConfig, listSkills, getSkill, saveSkill, deleteSkill, prunePluginProjections, pruneAllPluginProjections, syncPluginsToClient, APP_VERSION, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients, persistSyncState };