@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.
- package/dist/adapters/claude-desktop.d.ts +2 -1
- package/dist/adapters/claude-desktop.d.ts.map +1 -1
- package/dist/adapters/opencode.d.ts +2 -1
- package/dist/adapters/opencode.d.ts.map +1 -1
- package/dist/{cli-v27bt25d.js → cli-g4w6k655.js} +1 -1
- package/dist/{cli-28fsxhe3.js → cli-gf70a85c.js} +71 -181
- package/dist/{cli-tk8bggg5.js → cli-remv48t3.js} +4 -2
- package/dist/{cli-njtbb11m.js → cli-tdsve98z.js} +182 -152
- package/dist/{cli-wxw1t3rr.js → cli-vy81xjm0.js} +287 -157
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +69 -54
- package/dist/{config-5p08cb0c.js → config-2s2aqkqp.js} +1 -1
- package/dist/core/add-command.d.ts.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +10 -8
- package/dist/core/oauth.d.ts.map +1 -1
- package/dist/core/plugin-manager.d.ts.map +1 -1
- package/dist/{plugin-host-954a7tf7.js → plugin-host-d9wkemnr.js} +4 -4
- package/dist/{plugin-manager-m8ar2271.js → plugin-manager-0ygz96m9.js} +4 -4
- package/dist/{registry-n12thgf2.js → registry-bnjb2345.js} +1 -1
- package/package.json +1 -1
|
@@ -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-
|
|
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/
|
|
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 (!
|
|
138
|
+
if (!fs2.existsSync(skillsDir)) {
|
|
23
139
|
return [];
|
|
24
140
|
}
|
|
25
|
-
const files =
|
|
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 =
|
|
30
|
-
const content =
|
|
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 =
|
|
39
|
-
if (!
|
|
154
|
+
const filePath = path2.join(skillsDir, `${id}.md`);
|
|
155
|
+
if (!fs2.existsSync(filePath)) {
|
|
40
156
|
return null;
|
|
41
157
|
}
|
|
42
|
-
const content =
|
|
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 =
|
|
49
|
-
|
|
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 =
|
|
54
|
-
if (
|
|
55
|
-
|
|
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
|
|
61
|
-
import
|
|
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 =
|
|
65
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
217
|
+
const fullPath = path3.join(targetDir, p);
|
|
102
218
|
try {
|
|
103
|
-
if (
|
|
104
|
-
|
|
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 =
|
|
129
|
-
const resolvedTarget =
|
|
130
|
-
if (resolvedTarget !== resolvedBase && !resolvedTarget.startsWith(resolvedBase +
|
|
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 =
|
|
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 =
|
|
274
|
+
const targetDir = path3.join(targetBase, plugin.pluginName);
|
|
159
275
|
ensureDir(targetDir);
|
|
160
|
-
const mcpJsonSrc =
|
|
161
|
-
const mcpJsonDest =
|
|
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 (
|
|
164
|
-
|
|
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 =
|
|
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 =
|
|
314
|
+
const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
199
315
|
assertWithinBase(targetBase, targetDir);
|
|
200
316
|
ensureDir(targetDir);
|
|
201
|
-
copyFileOrDir(skill.path,
|
|
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 =
|
|
221
|
-
const commandsBase =
|
|
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 =
|
|
350
|
+
const targetDir = path3.join(skillsBase, nsName(plugin.pluginName, skill.id));
|
|
235
351
|
assertWithinBase(skillsBase, targetDir);
|
|
236
352
|
ensureDir(targetDir);
|
|
237
|
-
copyFileOrDir(skill.path,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
401
|
+
const targetDir = path3.join(skillsBase, nsName(plugin.pluginName, skill.id));
|
|
286
402
|
assertWithinBase(skillsBase, targetDir);
|
|
287
403
|
ensureDir(targetDir);
|
|
288
|
-
copyFileOrDir(skill.path,
|
|
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 =
|
|
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 =
|
|
435
|
+
const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
320
436
|
assertWithinBase(targetBase, targetDir);
|
|
321
437
|
ensureDir(targetDir);
|
|
322
|
-
copyFileOrDir(skill.path,
|
|
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 =
|
|
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 =
|
|
469
|
+
const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
354
470
|
assertWithinBase(targetBase, targetDir);
|
|
355
471
|
ensureDir(targetDir);
|
|
356
|
-
copyFileOrDir(skill.path,
|
|
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 =
|
|
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 =
|
|
503
|
+
const targetDir = path3.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
388
504
|
assertWithinBase(targetBase, targetDir);
|
|
389
505
|
ensureDir(targetDir);
|
|
390
|
-
copyFileOrDir(skill.path,
|
|
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:
|
|
550
|
+
claude: path3.join(homeDir(), ".claude", "skills"),
|
|
435
551
|
"claude-desktop": "",
|
|
436
|
-
codex:
|
|
437
|
-
cursor:
|
|
438
|
-
vscode:
|
|
439
|
-
qwen:
|
|
440
|
-
cline:
|
|
441
|
-
kiro:
|
|
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 =
|
|
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 =
|
|
459
|
-
const destPath =
|
|
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
|
-
|
|
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(
|
|
474
|
-
if (
|
|
589
|
+
ensureDir(path3.dirname(dest));
|
|
590
|
+
if (fs3.statSync(src).isDirectory()) {
|
|
475
591
|
copyPluginDir(src, dest, [], errors);
|
|
476
592
|
} else {
|
|
477
|
-
|
|
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
|
|
489
|
-
import
|
|
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
|
|
494
|
-
import
|
|
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 =
|
|
498
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
633
|
+
const fullPath = path4.join(targetDir, ownedPath);
|
|
518
634
|
try {
|
|
519
|
-
if (
|
|
520
|
-
|
|
635
|
+
if (fs4.existsSync(fullPath)) {
|
|
636
|
+
fs4.rmSync(fullPath, { recursive: true, force: true });
|
|
521
637
|
}
|
|
522
638
|
if (layout === "dir") {
|
|
523
|
-
const dirPath =
|
|
639
|
+
const dirPath = path4.join(targetDir, path4.dirname(ownedPath));
|
|
524
640
|
try {
|
|
525
|
-
const remaining =
|
|
641
|
+
const remaining = fs4.readdirSync(dirPath);
|
|
526
642
|
if (remaining.length === 0) {
|
|
527
|
-
|
|
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" ?
|
|
538
|
-
ensureDir(
|
|
539
|
-
|
|
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
|
|
822
|
+
return fs5.realpathSync(path5.resolve(p));
|
|
707
823
|
} catch {
|
|
708
|
-
return
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
1014
|
+
return path6.join(homeDir(), ".config", "Claude", "claude_desktop_config.json");
|
|
899
1015
|
}
|
|
900
1016
|
if (process.platform === "win32") {
|
|
901
|
-
return
|
|
1017
|
+
return path6.join(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json");
|
|
902
1018
|
}
|
|
903
|
-
return
|
|
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
|
|
1006
|
-
import
|
|
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
|
|
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(
|
|
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 || !
|
|
1166
|
+
if (!configPath || !fs6.existsSync(configPath)) {
|
|
1044
1167
|
return result;
|
|
1045
1168
|
}
|
|
1046
|
-
const existing =
|
|
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 =
|
|
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
|
-
|
|
1247
|
+
fs6.mkdirSync(path7.dirname(configPath), { recursive: true });
|
|
1125
1248
|
const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
|
|
1126
|
-
|
|
1127
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
1268
|
-
import
|
|
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
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
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
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
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
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
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 (
|
|
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(
|
|
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 || !
|
|
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 (!
|
|
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
|
|
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
|
|
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(
|
|
1674
|
+
projectSkillsToDir(path10.join(homeDir(), ".kiro", "skills"), skills, "flat");
|
|
1552
1675
|
}
|
|
1553
1676
|
}
|
|
1554
1677
|
|
|
1555
1678
|
// src/adapters/opencode.ts
|
|
1556
|
-
import
|
|
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
|
|
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
|
|
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
|
|
1835
|
+
return path12.join(homeDir(), ".config", "Code", "User", "mcp.json");
|
|
1706
1836
|
}
|
|
1707
1837
|
if (process.platform === "win32") {
|
|
1708
|
-
return
|
|
1838
|
+
return path12.join(process.env.APPDATA ?? "", "Code", "User", "mcp.json");
|
|
1709
1839
|
}
|
|
1710
|
-
return
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
2088
|
+
projectSkillsToDir(path13.join(homeDir(), ".qwen", "skills"), skills, "flat");
|
|
1959
2089
|
}
|
|
1960
2090
|
}
|
|
1961
2091
|
|
|
1962
2092
|
// src/adapters/openclaw.ts
|
|
1963
|
-
import
|
|
1964
|
-
import
|
|
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 ??
|
|
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(
|
|
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(
|
|
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 (
|
|
2198
|
+
if (fs8.existsSync(configPath)) {
|
|
2069
2199
|
try {
|
|
2070
|
-
raw = JSON.parse(
|
|
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
|
|
2114
|
-
import
|
|
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
|
|
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(
|
|
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 || !
|
|
2277
|
+
if (!configPath || !fs9.existsSync(configPath)) {
|
|
2148
2278
|
return result;
|
|
2149
2279
|
}
|
|
2150
|
-
const existing =
|
|
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 =
|
|
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
|
-
|
|
2359
|
+
fs9.mkdirSync(path15.dirname(configPath), { recursive: true });
|
|
2230
2360
|
const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
|
|
2231
|
-
|
|
2232
|
-
|
|
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
|
|
2281
|
-
import
|
|
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 =
|
|
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
|
-
|
|
2421
|
+
fs10.mkdirSync(path16.dirname(lockPath), { recursive: true });
|
|
2292
2422
|
const deadline = Date.now() + 5000;
|
|
2293
2423
|
while (true) {
|
|
2294
2424
|
try {
|
|
2295
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|