@kwonye/mcpx 0.1.73 → 0.1.75
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.map +1 -1
- package/dist/adapters/kiro.d.ts +2 -1
- package/dist/adapters/kiro.d.ts.map +1 -1
- package/dist/adapters/qwen.d.ts +2 -1
- package/dist/adapters/qwen.d.ts.map +1 -1
- package/dist/adapters/utils/index.d.ts.map +1 -1
- package/dist/{cli-ezvj44tr.js → cli-e9hdd44n.js} +201 -88
- package/dist/{cli-7rggq938.js → cli-fh6jh7fs.js} +202 -89
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +153 -35
- package/dist/core/daemon.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/proxy.d.ts +2 -0
- package/dist/core/proxy.d.ts.map +1 -0
- package/dist/core/skills.d.ts +6 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -28,6 +28,9 @@ function getStateRoot() {
|
|
|
28
28
|
function getConfigPath() {
|
|
29
29
|
return path.join(getConfigRoot(), "mcpx", "config.json");
|
|
30
30
|
}
|
|
31
|
+
function getSkillsDir() {
|
|
32
|
+
return path.join(getConfigRoot(), "mcpx", "skills");
|
|
33
|
+
}
|
|
31
34
|
function getManagedIndexPath() {
|
|
32
35
|
return path.join(getDataRoot(), "mcpx", "managed-index.json");
|
|
33
36
|
}
|
|
@@ -216,10 +219,52 @@ function ensureGatewayToken(config, secrets) {
|
|
|
216
219
|
return secrets.rotateLocalToken(secretName);
|
|
217
220
|
}
|
|
218
221
|
|
|
222
|
+
// src/core/skills.ts
|
|
223
|
+
import fs3 from "node:fs";
|
|
224
|
+
import path3 from "node:path";
|
|
225
|
+
function listSkills() {
|
|
226
|
+
const skillsDir = getSkillsDir();
|
|
227
|
+
if (!fs3.existsSync(skillsDir)) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const files = fs3.readdirSync(skillsDir);
|
|
231
|
+
const skills = [];
|
|
232
|
+
for (const file of files) {
|
|
233
|
+
if (file.endsWith(".md")) {
|
|
234
|
+
const id = path3.basename(file, ".md");
|
|
235
|
+
const content = fs3.readFileSync(path3.join(skillsDir, file), "utf-8");
|
|
236
|
+
skills.push({ id, content });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return skills;
|
|
240
|
+
}
|
|
241
|
+
function getSkill(id) {
|
|
242
|
+
const skillsDir = getSkillsDir();
|
|
243
|
+
const filePath = path3.join(skillsDir, `${id}.md`);
|
|
244
|
+
if (!fs3.existsSync(filePath)) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
248
|
+
return { id, content };
|
|
249
|
+
}
|
|
250
|
+
function saveSkill(id, content) {
|
|
251
|
+
const skillsDir = getSkillsDir();
|
|
252
|
+
ensureDir(skillsDir);
|
|
253
|
+
const filePath = path3.join(skillsDir, `${id}.md`);
|
|
254
|
+
fs3.writeFileSync(filePath, content, "utf-8");
|
|
255
|
+
}
|
|
256
|
+
function deleteSkill(id) {
|
|
257
|
+
const skillsDir = getSkillsDir();
|
|
258
|
+
const filePath = path3.join(skillsDir, `${id}.md`);
|
|
259
|
+
if (fs3.existsSync(filePath)) {
|
|
260
|
+
fs3.unlinkSync(filePath);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
219
264
|
// src/core/secrets.ts
|
|
220
265
|
import { execFileSync } from "node:child_process";
|
|
221
266
|
import crypto2 from "node:crypto";
|
|
222
|
-
import
|
|
267
|
+
import fs4 from "node:fs";
|
|
223
268
|
function parseSecretRef(ref) {
|
|
224
269
|
if (!ref.startsWith("secret://")) {
|
|
225
270
|
return null;
|
|
@@ -313,7 +358,7 @@ function readSecretValueFromStdin() {
|
|
|
313
358
|
if (process.stdin.isTTY) {
|
|
314
359
|
throw new Error("No value provided. Use --value or pipe a value via stdin.");
|
|
315
360
|
}
|
|
316
|
-
const content =
|
|
361
|
+
const content = fs4.readFileSync(process.stdin.fd, "utf8").trim();
|
|
317
362
|
if (content.length === 0) {
|
|
318
363
|
throw new Error("Empty secret value provided.");
|
|
319
364
|
}
|
|
@@ -372,7 +417,7 @@ async function probeHttpAuthRequirement(spec, secrets, timeoutMs = DEFAULT_AUTH_
|
|
|
372
417
|
}
|
|
373
418
|
|
|
374
419
|
// src/adapters/claude.ts
|
|
375
|
-
import
|
|
420
|
+
import path4 from "node:path";
|
|
376
421
|
import { z as z2 } from "zod";
|
|
377
422
|
|
|
378
423
|
// src/adapters/utils/index.ts
|
|
@@ -390,6 +435,11 @@ function pruneStaleManagedEntries(managedIndex, clientId, servers, keepEntryName
|
|
|
390
435
|
delete servers[name];
|
|
391
436
|
}
|
|
392
437
|
}
|
|
438
|
+
for (const name of Object.keys(servers)) {
|
|
439
|
+
if (!keep.has(name) && name.endsWith(" (mcpx)")) {
|
|
440
|
+
delete servers[name];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
393
443
|
}
|
|
394
444
|
function ensureManagedEntryWritable(managedIndex, clientId, entryName, existingValue) {
|
|
395
445
|
if (existingValue === undefined || existingValue === null) {
|
|
@@ -511,7 +561,7 @@ var claudeEntrySchema = z2.object({
|
|
|
511
561
|
class ClaudeAdapter {
|
|
512
562
|
id = "claude";
|
|
513
563
|
detectConfigPath() {
|
|
514
|
-
return
|
|
564
|
+
return path4.join(homeDir(), ".claude.json");
|
|
515
565
|
}
|
|
516
566
|
supportsHttp() {
|
|
517
567
|
return true;
|
|
@@ -623,7 +673,8 @@ class ClaudeAdapter {
|
|
|
623
673
|
}
|
|
624
674
|
|
|
625
675
|
// src/adapters/claude-desktop.ts
|
|
626
|
-
import
|
|
676
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
677
|
+
import path5 from "node:path";
|
|
627
678
|
import { z as z3 } from "zod";
|
|
628
679
|
var stringMapSchema2 = z3.record(z3.string(), z3.string());
|
|
629
680
|
var claudeDesktopEntrySchema = z3.object({
|
|
@@ -636,11 +687,20 @@ var claudeDesktopEntrySchema = z3.object({
|
|
|
636
687
|
cwd: z3.string().min(1).optional(),
|
|
637
688
|
disabled: z3.boolean().optional()
|
|
638
689
|
}).passthrough();
|
|
690
|
+
function buildProxyEntry(entry) {
|
|
691
|
+
const upstreamName = entry.name.replace(/ \(mcpx\)$/, "");
|
|
692
|
+
try {
|
|
693
|
+
const mcpxPath = execFileSync2("which", ["mcpx"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
694
|
+
if (mcpxPath)
|
|
695
|
+
return { command: mcpxPath, args: ["proxy", upstreamName] };
|
|
696
|
+
} catch {}
|
|
697
|
+
return { command: "npx", args: ["-y", "@kwonye/mcpx@latest", "proxy", upstreamName] };
|
|
698
|
+
}
|
|
639
699
|
|
|
640
700
|
class ClaudeDesktopAdapter {
|
|
641
701
|
id = "claude-desktop";
|
|
642
702
|
detectConfigPath() {
|
|
643
|
-
return
|
|
703
|
+
return path5.join(homeDir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
644
704
|
}
|
|
645
705
|
supportsHttp() {
|
|
646
706
|
return true;
|
|
@@ -663,7 +723,7 @@ class ClaudeDesktopAdapter {
|
|
|
663
723
|
continue;
|
|
664
724
|
}
|
|
665
725
|
const entry = parsed.data;
|
|
666
|
-
if ((entry.type === undefined || entry.type === "http") && entry.url && !entry.command) {
|
|
726
|
+
if ((entry.type === undefined || entry.type === "http" || entry.type === "streamable_http") && entry.url && !entry.command) {
|
|
667
727
|
result.candidates.push({
|
|
668
728
|
clientId: this.id,
|
|
669
729
|
configPath,
|
|
@@ -707,11 +767,10 @@ class ClaudeDesktopAdapter {
|
|
|
707
767
|
try {
|
|
708
768
|
const raw = readJsonFile(configPath, {});
|
|
709
769
|
const enabledEntries = options.managedEntries.filter((entry) => entry.enabled);
|
|
710
|
-
const serverEntries = Object.fromEntries(enabledEntries.map((entry) =>
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
}]));
|
|
770
|
+
const serverEntries = Object.fromEntries(enabledEntries.map((entry) => {
|
|
771
|
+
const { command, args } = buildProxyEntry(entry);
|
|
772
|
+
return [entry.name, { command, args }];
|
|
773
|
+
}));
|
|
715
774
|
const enabledManagedNames = enabledEntries.map((entry) => entry.name);
|
|
716
775
|
const topLevelServers = raw.mcpServers ?? {};
|
|
717
776
|
removeSourceEntries(topLevelServers, options.sourceEntriesToRemove);
|
|
@@ -727,10 +786,10 @@ class ClaudeDesktopAdapter {
|
|
|
727
786
|
}
|
|
728
787
|
raw.mcpServers = topLevelServers;
|
|
729
788
|
writeJsonAtomic(configPath, raw);
|
|
730
|
-
setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(options.managedEntries.map((entry) =>
|
|
731
|
-
entry
|
|
732
|
-
JSON.stringify({
|
|
733
|
-
|
|
789
|
+
setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(options.managedEntries.map((entry) => {
|
|
790
|
+
const { command, args } = buildProxyEntry(entry);
|
|
791
|
+
return [entry.name, JSON.stringify({ command, args, enabled: entry.enabled })];
|
|
792
|
+
})));
|
|
734
793
|
return okResult(this.id, configPath);
|
|
735
794
|
} catch (error) {
|
|
736
795
|
return errorResult(this.id, configPath, error.message);
|
|
@@ -739,8 +798,8 @@ class ClaudeDesktopAdapter {
|
|
|
739
798
|
}
|
|
740
799
|
|
|
741
800
|
// src/adapters/codex.ts
|
|
742
|
-
import
|
|
743
|
-
import
|
|
801
|
+
import path6 from "node:path";
|
|
802
|
+
import fs5 from "node:fs";
|
|
744
803
|
import { parse, stringify } from "@iarna/toml";
|
|
745
804
|
import { z as z4 } from "zod";
|
|
746
805
|
var stringMapSchema3 = z4.preprocess((value) => {
|
|
@@ -763,7 +822,7 @@ var codexEntrySchema = z4.object({
|
|
|
763
822
|
class CodexAdapter {
|
|
764
823
|
id = "codex";
|
|
765
824
|
detectConfigPath() {
|
|
766
|
-
return
|
|
825
|
+
return path6.join(homeDir(), ".codex", "config.toml");
|
|
767
826
|
}
|
|
768
827
|
supportsHttp() {
|
|
769
828
|
return true;
|
|
@@ -771,10 +830,10 @@ class CodexAdapter {
|
|
|
771
830
|
scanForImports(_config, managedIndex) {
|
|
772
831
|
const configPath = this.detectConfigPath();
|
|
773
832
|
const result = emptyImportScan(this.id, configPath ?? undefined);
|
|
774
|
-
if (!configPath || !
|
|
833
|
+
if (!configPath || !fs5.existsSync(configPath)) {
|
|
775
834
|
return result;
|
|
776
835
|
}
|
|
777
|
-
const existing =
|
|
836
|
+
const existing = fs5.readFileSync(configPath, "utf8");
|
|
778
837
|
const doc = existing.trim().length > 0 ? parse(existing) : {};
|
|
779
838
|
const mcpServers = doc.mcp_servers ?? {};
|
|
780
839
|
for (const [name, rawEntry] of Object.entries(mcpServers)) {
|
|
@@ -829,7 +888,7 @@ class CodexAdapter {
|
|
|
829
888
|
return errorResult(this.id, undefined, "Unable to resolve Codex config.toml path.");
|
|
830
889
|
}
|
|
831
890
|
try {
|
|
832
|
-
const existing =
|
|
891
|
+
const existing = fs5.existsSync(configPath) ? fs5.readFileSync(configPath, "utf8") : "";
|
|
833
892
|
const doc = existing.trim().length > 0 ? parse(existing) : {};
|
|
834
893
|
const mcpServers = doc.mcp_servers ?? {};
|
|
835
894
|
removeSourceEntries(mcpServers, options.sourceEntriesToRemove);
|
|
@@ -850,10 +909,10 @@ class CodexAdapter {
|
|
|
850
909
|
mcpServers[name] = entry;
|
|
851
910
|
}
|
|
852
911
|
doc.mcp_servers = mcpServers;
|
|
853
|
-
|
|
912
|
+
fs5.mkdirSync(path6.dirname(configPath), { recursive: true });
|
|
854
913
|
const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
|
|
855
|
-
|
|
856
|
-
|
|
914
|
+
fs5.writeFileSync(tmpPath, stringify(doc), { mode: 384 });
|
|
915
|
+
fs5.renameSync(tmpPath, configPath);
|
|
857
916
|
setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
|
|
858
917
|
return okResult(this.id, configPath);
|
|
859
918
|
} catch (error) {
|
|
@@ -863,7 +922,7 @@ class CodexAdapter {
|
|
|
863
922
|
}
|
|
864
923
|
|
|
865
924
|
// src/adapters/cursor.ts
|
|
866
|
-
import
|
|
925
|
+
import path7 from "node:path";
|
|
867
926
|
import { z as z5 } from "zod";
|
|
868
927
|
var stringMapSchema4 = z5.record(z5.string(), z5.string());
|
|
869
928
|
var cursorEntrySchema = z5.object({
|
|
@@ -880,7 +939,7 @@ var cursorEntrySchema = z5.object({
|
|
|
880
939
|
class CursorAdapter {
|
|
881
940
|
id = "cursor";
|
|
882
941
|
detectConfigPath() {
|
|
883
|
-
return
|
|
942
|
+
return path7.join(homeDir(), "Library", "Application Support", "Cursor", "User", "mcp.json");
|
|
884
943
|
}
|
|
885
944
|
supportsHttp() {
|
|
886
945
|
return true;
|
|
@@ -986,8 +1045,8 @@ class CursorAdapter {
|
|
|
986
1045
|
}
|
|
987
1046
|
|
|
988
1047
|
// src/adapters/cline.ts
|
|
989
|
-
import
|
|
990
|
-
import
|
|
1048
|
+
import path8 from "node:path";
|
|
1049
|
+
import fs6 from "node:fs";
|
|
991
1050
|
import { z as z6 } from "zod";
|
|
992
1051
|
var stringMapSchema5 = z6.record(z6.string(), z6.string());
|
|
993
1052
|
var clineEntrySchema = z6.object({
|
|
@@ -1002,8 +1061,8 @@ var clineEntrySchema = z6.object({
|
|
|
1002
1061
|
}).passthrough();
|
|
1003
1062
|
function getCandidatePaths() {
|
|
1004
1063
|
return [
|
|
1005
|
-
|
|
1006
|
-
|
|
1064
|
+
path8.join(homeDir(), "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
|
1065
|
+
path8.join(homeDir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
|
|
1007
1066
|
];
|
|
1008
1067
|
}
|
|
1009
1068
|
|
|
@@ -1012,7 +1071,7 @@ class ClineAdapter {
|
|
|
1012
1071
|
detectConfigPath() {
|
|
1013
1072
|
const candidates = getCandidatePaths();
|
|
1014
1073
|
for (const candidate of candidates) {
|
|
1015
|
-
if (
|
|
1074
|
+
if (fs6.existsSync(candidate)) {
|
|
1016
1075
|
return candidate;
|
|
1017
1076
|
}
|
|
1018
1077
|
}
|
|
@@ -1024,7 +1083,7 @@ class ClineAdapter {
|
|
|
1024
1083
|
scanForImports(_config, managedIndex) {
|
|
1025
1084
|
const configPath = this.detectConfigPath();
|
|
1026
1085
|
const result = emptyImportScan(this.id, configPath ?? undefined);
|
|
1027
|
-
if (!configPath || !
|
|
1086
|
+
if (!configPath || !fs6.existsSync(configPath)) {
|
|
1028
1087
|
return result;
|
|
1029
1088
|
}
|
|
1030
1089
|
const raw = readJsonFile(configPath, {});
|
|
@@ -1119,7 +1178,8 @@ class ClineAdapter {
|
|
|
1119
1178
|
}
|
|
1120
1179
|
|
|
1121
1180
|
// src/adapters/kiro.ts
|
|
1122
|
-
import
|
|
1181
|
+
import fs7 from "node:fs";
|
|
1182
|
+
import path9 from "node:path";
|
|
1123
1183
|
import { z as z7 } from "zod";
|
|
1124
1184
|
var stringMapSchema6 = z7.record(z7.string(), z7.string());
|
|
1125
1185
|
var kiroEntrySchema = z7.object({
|
|
@@ -1135,7 +1195,7 @@ var kiroEntrySchema = z7.object({
|
|
|
1135
1195
|
class KiroAdapter {
|
|
1136
1196
|
id = "kiro";
|
|
1137
1197
|
detectConfigPath() {
|
|
1138
|
-
return
|
|
1198
|
+
return path9.join(homeDir(), ".kiro", "settings", "mcp.json");
|
|
1139
1199
|
}
|
|
1140
1200
|
supportsHttp() {
|
|
1141
1201
|
return true;
|
|
@@ -1234,10 +1294,30 @@ class KiroAdapter {
|
|
|
1234
1294
|
return errorResult(this.id, configPath, error.message);
|
|
1235
1295
|
}
|
|
1236
1296
|
}
|
|
1297
|
+
syncSkills(skills) {
|
|
1298
|
+
const skillsDir = path9.join(homeDir(), ".kiro", "skills");
|
|
1299
|
+
if (!fs7.existsSync(skillsDir)) {
|
|
1300
|
+
fs7.mkdirSync(skillsDir, { recursive: true });
|
|
1301
|
+
}
|
|
1302
|
+
const existingFiles = fs7.readdirSync(skillsDir);
|
|
1303
|
+
const managedIds = new Set(skills.map((s) => s.id));
|
|
1304
|
+
for (const file of existingFiles) {
|
|
1305
|
+
if (file.endsWith(".md")) {
|
|
1306
|
+
const id = path9.basename(file, ".md");
|
|
1307
|
+
if (!managedIds.has(id)) {
|
|
1308
|
+
fs7.unlinkSync(path9.join(skillsDir, file));
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
for (const skill of skills) {
|
|
1313
|
+
const targetPath = path9.join(skillsDir, `${skill.id}.md`);
|
|
1314
|
+
fs7.writeFileSync(targetPath, skill.content, "utf-8");
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1237
1317
|
}
|
|
1238
1318
|
|
|
1239
1319
|
// src/adapters/opencode.ts
|
|
1240
|
-
import
|
|
1320
|
+
import path10 from "node:path";
|
|
1241
1321
|
import { z as z8 } from "zod";
|
|
1242
1322
|
var stringMapSchema7 = z8.record(z8.string(), z8.string());
|
|
1243
1323
|
var openCodeEntrySchema = z8.object({
|
|
@@ -1254,7 +1334,7 @@ var openCodeEntrySchema = z8.object({
|
|
|
1254
1334
|
class OpenCodeAdapter {
|
|
1255
1335
|
id = "opencode";
|
|
1256
1336
|
detectConfigPath() {
|
|
1257
|
-
return
|
|
1337
|
+
return path10.join(homeDir(), ".config", "opencode", "opencode.json");
|
|
1258
1338
|
}
|
|
1259
1339
|
supportsHttp() {
|
|
1260
1340
|
return true;
|
|
@@ -1357,7 +1437,7 @@ class OpenCodeAdapter {
|
|
|
1357
1437
|
}
|
|
1358
1438
|
|
|
1359
1439
|
// src/adapters/vscode.ts
|
|
1360
|
-
import
|
|
1440
|
+
import path11 from "node:path";
|
|
1361
1441
|
import { z as z9 } from "zod";
|
|
1362
1442
|
var stringMapSchema8 = z9.record(z9.string(), z9.string());
|
|
1363
1443
|
var vscodeEntrySchema = z9.object({
|
|
@@ -1374,7 +1454,7 @@ var vscodeEntrySchema = z9.object({
|
|
|
1374
1454
|
class VsCodeAdapter {
|
|
1375
1455
|
id = "vscode";
|
|
1376
1456
|
detectConfigPath() {
|
|
1377
|
-
return
|
|
1457
|
+
return path11.join(homeDir(), "Library", "Application Support", "Code", "User", "mcp.json");
|
|
1378
1458
|
}
|
|
1379
1459
|
supportsHttp() {
|
|
1380
1460
|
return true;
|
|
@@ -1480,7 +1560,8 @@ class VsCodeAdapter {
|
|
|
1480
1560
|
}
|
|
1481
1561
|
|
|
1482
1562
|
// src/adapters/qwen.ts
|
|
1483
|
-
import
|
|
1563
|
+
import fs8 from "node:fs";
|
|
1564
|
+
import path12 from "node:path";
|
|
1484
1565
|
import { z as z10 } from "zod";
|
|
1485
1566
|
var stringMapSchema9 = z10.record(z10.string(), z10.string());
|
|
1486
1567
|
var qwenEntrySchema = z10.object({
|
|
@@ -1496,7 +1577,7 @@ var qwenEntrySchema = z10.object({
|
|
|
1496
1577
|
class QwenAdapter {
|
|
1497
1578
|
id = "qwen";
|
|
1498
1579
|
detectConfigPath() {
|
|
1499
|
-
return
|
|
1580
|
+
return path12.join(homeDir(), ".qwen", "settings.json");
|
|
1500
1581
|
}
|
|
1501
1582
|
supportsHttp() {
|
|
1502
1583
|
return true;
|
|
@@ -1592,6 +1673,26 @@ class QwenAdapter {
|
|
|
1592
1673
|
return errorResult(this.id, configPath, error.message);
|
|
1593
1674
|
}
|
|
1594
1675
|
}
|
|
1676
|
+
syncSkills(skills) {
|
|
1677
|
+
const skillsDir = path12.join(homeDir(), ".qwen", "skills");
|
|
1678
|
+
if (!fs8.existsSync(skillsDir)) {
|
|
1679
|
+
fs8.mkdirSync(skillsDir, { recursive: true });
|
|
1680
|
+
}
|
|
1681
|
+
const existingFiles = fs8.readdirSync(skillsDir);
|
|
1682
|
+
const managedIds = new Set(skills.map((s) => s.id));
|
|
1683
|
+
for (const file of existingFiles) {
|
|
1684
|
+
if (file.endsWith(".md")) {
|
|
1685
|
+
const id = path12.basename(file, ".md");
|
|
1686
|
+
if (!managedIds.has(id)) {
|
|
1687
|
+
fs8.unlinkSync(path12.join(skillsDir, file));
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
for (const skill of skills) {
|
|
1692
|
+
const targetPath = path12.join(skillsDir, `${skill.id}.md`);
|
|
1693
|
+
fs8.writeFileSync(targetPath, skill.content, "utf-8");
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1595
1696
|
}
|
|
1596
1697
|
|
|
1597
1698
|
// src/adapters/index.ts
|
|
@@ -1710,8 +1811,14 @@ function syncAllClients(config, secrets, targetClients) {
|
|
|
1710
1811
|
const localToken = ensureGatewayToken(config, secrets);
|
|
1711
1812
|
const gatewayUrl = getGatewayUrl(config);
|
|
1712
1813
|
const managedEntries = buildManagedEntries(config, gatewayUrl, localToken);
|
|
1814
|
+
const skills = listSkills();
|
|
1713
1815
|
const results = [];
|
|
1714
1816
|
for (const adapter of filteredAdapters) {
|
|
1817
|
+
if (adapter.syncSkills) {
|
|
1818
|
+
try {
|
|
1819
|
+
adapter.syncSkills(skills);
|
|
1820
|
+
} catch (error) {}
|
|
1821
|
+
}
|
|
1715
1822
|
if (!adapter.supportsHttp()) {
|
|
1716
1823
|
results.push({
|
|
1717
1824
|
clientId: adapter.id,
|
|
@@ -1857,12 +1964,12 @@ function maybePrefixBearer(target, value, raw = false) {
|
|
|
1857
1964
|
}
|
|
1858
1965
|
|
|
1859
1966
|
// src/version.ts
|
|
1860
|
-
var APP_VERSION = "0.1.
|
|
1967
|
+
var APP_VERSION = "0.1.75";
|
|
1861
1968
|
|
|
1862
1969
|
// src/core/update.ts
|
|
1863
|
-
import
|
|
1864
|
-
import
|
|
1865
|
-
import { execFileSync as
|
|
1970
|
+
import fs9 from "node:fs";
|
|
1971
|
+
import path13 from "node:path";
|
|
1972
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1866
1973
|
function compareVersions(a, b) {
|
|
1867
1974
|
const partsA = a.split(".").map(Number);
|
|
1868
1975
|
const partsB = b.split(".").map(Number);
|
|
@@ -1878,7 +1985,7 @@ function compareVersions(a, b) {
|
|
|
1878
1985
|
}
|
|
1879
1986
|
async function checkForUpdates() {
|
|
1880
1987
|
try {
|
|
1881
|
-
const output =
|
|
1988
|
+
const output = execFileSync3("npm", ["view", "@kwonye/mcpx", "version"], {
|
|
1882
1989
|
encoding: "utf8",
|
|
1883
1990
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1884
1991
|
}).trim();
|
|
@@ -1900,17 +2007,17 @@ async function checkForUpdates() {
|
|
|
1900
2007
|
}
|
|
1901
2008
|
function getStagedUpdate() {
|
|
1902
2009
|
const stagedPath = getStagedVersionPath();
|
|
1903
|
-
if (!
|
|
2010
|
+
if (!fs9.existsSync(stagedPath)) {
|
|
1904
2011
|
return null;
|
|
1905
2012
|
}
|
|
1906
2013
|
try {
|
|
1907
|
-
const raw =
|
|
2014
|
+
const raw = fs9.readFileSync(stagedPath, "utf8");
|
|
1908
2015
|
const info = JSON.parse(raw);
|
|
1909
2016
|
if (!info.version || !info.cliPath) {
|
|
1910
2017
|
return null;
|
|
1911
2018
|
}
|
|
1912
|
-
const absoluteCliPath =
|
|
1913
|
-
if (!
|
|
2019
|
+
const absoluteCliPath = path13.isAbsolute(info.cliPath) ? info.cliPath : path13.join(getUpdatesDir(), info.cliPath);
|
|
2020
|
+
if (!fs9.existsSync(absoluteCliPath)) {
|
|
1914
2021
|
return null;
|
|
1915
2022
|
}
|
|
1916
2023
|
return {
|
|
@@ -1926,15 +2033,15 @@ function stageUpdate(version, cliPath) {
|
|
|
1926
2033
|
ensureDir(updatesDir);
|
|
1927
2034
|
const stagedInfo = {
|
|
1928
2035
|
version,
|
|
1929
|
-
cliPath:
|
|
2036
|
+
cliPath: path13.isAbsolute(cliPath) ? path13.relative(updatesDir, cliPath) : cliPath,
|
|
1930
2037
|
stagedAt: new Date().toISOString()
|
|
1931
2038
|
};
|
|
1932
|
-
|
|
2039
|
+
fs9.writeFileSync(getStagedVersionPath(), JSON.stringify(stagedInfo, null, 2), "utf8");
|
|
1933
2040
|
}
|
|
1934
2041
|
function clearStagedUpdate() {
|
|
1935
2042
|
const stagedPath = getStagedVersionPath();
|
|
1936
|
-
if (
|
|
1937
|
-
|
|
2043
|
+
if (fs9.existsSync(stagedPath)) {
|
|
2044
|
+
fs9.unlinkSync(stagedPath);
|
|
1938
2045
|
}
|
|
1939
2046
|
}
|
|
1940
2047
|
function getStagedCliPath() {
|
|
@@ -1943,31 +2050,31 @@ function getStagedCliPath() {
|
|
|
1943
2050
|
}
|
|
1944
2051
|
function removeOldVersions(keepCount = 2) {
|
|
1945
2052
|
const updatesDir = getUpdatesDir();
|
|
1946
|
-
if (!
|
|
2053
|
+
if (!fs9.existsSync(updatesDir)) {
|
|
1947
2054
|
return;
|
|
1948
2055
|
}
|
|
1949
|
-
const entries =
|
|
2056
|
+
const entries = fs9.readdirSync(updatesDir, { withFileTypes: true });
|
|
1950
2057
|
const versionDirs = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith("v")).map((entry) => entry.name).sort((a, b) => compareVersions(b.slice(1), a.slice(1)));
|
|
1951
2058
|
if (versionDirs.length <= keepCount) {
|
|
1952
2059
|
return;
|
|
1953
2060
|
}
|
|
1954
2061
|
for (const oldVersion of versionDirs.slice(keepCount)) {
|
|
1955
|
-
const oldPath =
|
|
2062
|
+
const oldPath = path13.join(updatesDir, oldVersion);
|
|
1956
2063
|
try {
|
|
1957
|
-
|
|
2064
|
+
fs9.rmSync(oldPath, { recursive: true, force: true });
|
|
1958
2065
|
} catch {}
|
|
1959
2066
|
}
|
|
1960
2067
|
}
|
|
1961
2068
|
|
|
1962
2069
|
// src/core/update-manager.ts
|
|
1963
|
-
import
|
|
1964
|
-
import
|
|
2070
|
+
import fs10 from "node:fs";
|
|
2071
|
+
import path14 from "node:path";
|
|
1965
2072
|
import { execSync, spawn } from "node:child_process";
|
|
1966
2073
|
function acquireLock() {
|
|
1967
2074
|
const lockPath = getUpdateLockPath();
|
|
1968
2075
|
try {
|
|
1969
|
-
ensureDir(
|
|
1970
|
-
|
|
2076
|
+
ensureDir(path14.dirname(lockPath));
|
|
2077
|
+
fs10.writeFileSync(lockPath, `${process.pid}
|
|
1971
2078
|
`, { flag: "wx" });
|
|
1972
2079
|
return true;
|
|
1973
2080
|
} catch {
|
|
@@ -1977,25 +2084,25 @@ function acquireLock() {
|
|
|
1977
2084
|
function releaseLock() {
|
|
1978
2085
|
const lockPath = getUpdateLockPath();
|
|
1979
2086
|
try {
|
|
1980
|
-
|
|
2087
|
+
fs10.unlinkSync(lockPath);
|
|
1981
2088
|
} catch {}
|
|
1982
2089
|
}
|
|
1983
2090
|
function isUpdateInProgress() {
|
|
1984
2091
|
const lockPath = getUpdateLockPath();
|
|
1985
|
-
if (!
|
|
2092
|
+
if (!fs10.existsSync(lockPath)) {
|
|
1986
2093
|
return false;
|
|
1987
2094
|
}
|
|
1988
2095
|
try {
|
|
1989
|
-
const raw =
|
|
2096
|
+
const raw = fs10.readFileSync(lockPath, "utf8").trim();
|
|
1990
2097
|
const pid = Number(raw);
|
|
1991
2098
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
1992
|
-
|
|
2099
|
+
fs10.unlinkSync(lockPath);
|
|
1993
2100
|
return false;
|
|
1994
2101
|
}
|
|
1995
2102
|
process.kill(pid, 0);
|
|
1996
2103
|
return true;
|
|
1997
2104
|
} catch {
|
|
1998
|
-
|
|
2105
|
+
fs10.unlinkSync(lockPath);
|
|
1999
2106
|
return false;
|
|
2000
2107
|
}
|
|
2001
2108
|
}
|
|
@@ -2006,8 +2113,8 @@ async function downloadAndStageUpdate() {
|
|
|
2006
2113
|
}
|
|
2007
2114
|
const targetVersion = updateStatus.latestVersion;
|
|
2008
2115
|
const updatesDir = getUpdatesDir();
|
|
2009
|
-
const versionDir =
|
|
2010
|
-
if (
|
|
2116
|
+
const versionDir = path14.join(updatesDir, `v${targetVersion}`);
|
|
2117
|
+
if (fs10.existsSync(versionDir)) {
|
|
2011
2118
|
const existingStaged = getStagedUpdate();
|
|
2012
2119
|
if (existingStaged?.version === targetVersion) {
|
|
2013
2120
|
return { success: false, error: `Version ${targetVersion} already staged` };
|
|
@@ -2019,8 +2126,8 @@ async function downloadAndStageUpdate() {
|
|
|
2019
2126
|
cwd: versionDir,
|
|
2020
2127
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2021
2128
|
});
|
|
2022
|
-
const tarballPath =
|
|
2023
|
-
if (!
|
|
2129
|
+
const tarballPath = path14.join(versionDir, `kwonye-mcpx-${targetVersion}.tgz`);
|
|
2130
|
+
if (!fs10.existsSync(tarballPath)) {
|
|
2024
2131
|
throw new Error("Downloaded tarball not found");
|
|
2025
2132
|
}
|
|
2026
2133
|
execSync(`tar -xzf ${tarballPath} --strip-components=1`, {
|
|
@@ -2031,8 +2138,8 @@ async function downloadAndStageUpdate() {
|
|
|
2031
2138
|
cwd: versionDir,
|
|
2032
2139
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2033
2140
|
});
|
|
2034
|
-
const cliPath =
|
|
2035
|
-
if (!
|
|
2141
|
+
const cliPath = path14.join(versionDir, "dist", "cli.js");
|
|
2142
|
+
if (!fs10.existsSync(cliPath)) {
|
|
2036
2143
|
throw new Error("CLI entry point not found in downloaded package");
|
|
2037
2144
|
}
|
|
2038
2145
|
stageUpdate(targetVersion, cliPath);
|
|
@@ -2040,7 +2147,7 @@ async function downloadAndStageUpdate() {
|
|
|
2040
2147
|
return { success: true, version: targetVersion };
|
|
2041
2148
|
} catch (error) {
|
|
2042
2149
|
try {
|
|
2043
|
-
|
|
2150
|
+
fs10.rmSync(versionDir, { recursive: true, force: true });
|
|
2044
2151
|
} catch {}
|
|
2045
2152
|
return {
|
|
2046
2153
|
success: false,
|
|
@@ -2118,7 +2225,7 @@ function performRollback() {
|
|
|
2118
2225
|
}
|
|
2119
2226
|
|
|
2120
2227
|
// src/core/daemon.ts
|
|
2121
|
-
import
|
|
2228
|
+
import fs11 from "node:fs";
|
|
2122
2229
|
import net from "node:net";
|
|
2123
2230
|
import { spawn as spawn2 } from "node:child_process";
|
|
2124
2231
|
|
|
@@ -3064,10 +3171,10 @@ function createGatewayServer(options) {
|
|
|
3064
3171
|
|
|
3065
3172
|
// src/core/daemon.ts
|
|
3066
3173
|
function readPidFromFile(pidPath = getPidPath()) {
|
|
3067
|
-
if (!
|
|
3174
|
+
if (!fs11.existsSync(pidPath)) {
|
|
3068
3175
|
return null;
|
|
3069
3176
|
}
|
|
3070
|
-
const raw =
|
|
3177
|
+
const raw = fs11.readFileSync(pidPath, "utf8").trim();
|
|
3071
3178
|
if (!raw) {
|
|
3072
3179
|
return null;
|
|
3073
3180
|
}
|
|
@@ -3136,12 +3243,18 @@ function getDaemonStatus(config) {
|
|
|
3136
3243
|
async function startDaemon(config, cliPath, secrets) {
|
|
3137
3244
|
const existingStatus = getDaemonStatus(config);
|
|
3138
3245
|
if (existingStatus.running && existingStatus.pid) {
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3246
|
+
const portAvailable = await isPortAvailable(config.gateway.port);
|
|
3247
|
+
if (!portAvailable) {
|
|
3248
|
+
return {
|
|
3249
|
+
started: false,
|
|
3250
|
+
pid: existingStatus.pid,
|
|
3251
|
+
port: config.gateway.port,
|
|
3252
|
+
message: "mcpx daemon already running."
|
|
3253
|
+
};
|
|
3254
|
+
}
|
|
3255
|
+
try {
|
|
3256
|
+
fs11.unlinkSync(getPidPath());
|
|
3257
|
+
} catch {}
|
|
3145
3258
|
}
|
|
3146
3259
|
const port = await resolveGatewayPort(config);
|
|
3147
3260
|
ensureGatewayToken(config, secrets);
|
|
@@ -3149,7 +3262,7 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
3149
3262
|
const logPath = getLogPath();
|
|
3150
3263
|
ensureParentDir(pidPath);
|
|
3151
3264
|
ensureParentDir(logPath);
|
|
3152
|
-
const logFd =
|
|
3265
|
+
const logFd = fs11.openSync(logPath, "a", 384);
|
|
3153
3266
|
const child = spawn2(process.execPath, [cliPath, "daemon", "run", "--port", String(port)], {
|
|
3154
3267
|
detached: true,
|
|
3155
3268
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -3159,7 +3272,7 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
3159
3272
|
}
|
|
3160
3273
|
});
|
|
3161
3274
|
child.unref();
|
|
3162
|
-
|
|
3275
|
+
fs11.writeFileSync(pidPath, `${child.pid}
|
|
3163
3276
|
`, { mode: 384 });
|
|
3164
3277
|
startBackgroundUpdateCheck();
|
|
3165
3278
|
return {
|
|
@@ -3182,7 +3295,7 @@ function stopDaemon() {
|
|
|
3182
3295
|
process.kill(pid, "SIGTERM");
|
|
3183
3296
|
} catch {}
|
|
3184
3297
|
try {
|
|
3185
|
-
|
|
3298
|
+
fs11.unlinkSync(pidPath);
|
|
3186
3299
|
} catch {}
|
|
3187
3300
|
return {
|
|
3188
3301
|
stopped: true,
|
|
@@ -3195,10 +3308,10 @@ async function restartDaemon(config, cliPath, secrets) {
|
|
|
3195
3308
|
}
|
|
3196
3309
|
function readDaemonLogs(maxLines = 200) {
|
|
3197
3310
|
const logPath = getLogPath();
|
|
3198
|
-
if (!
|
|
3311
|
+
if (!fs11.existsSync(logPath)) {
|
|
3199
3312
|
return "";
|
|
3200
3313
|
}
|
|
3201
|
-
const lines =
|
|
3314
|
+
const lines = fs11.readFileSync(logPath, "utf8").split(`
|
|
3202
3315
|
`);
|
|
3203
3316
|
return lines.slice(Math.max(lines.length - maxLines, 0)).join(`
|
|
3204
3317
|
`);
|
|
@@ -3289,4 +3402,4 @@ function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(config
|
|
|
3289
3402
|
};
|
|
3290
3403
|
}
|
|
3291
3404
|
|
|
3292
|
-
export { getConfigPath, getManagedIndexPath, defaultConfig, loadConfig, saveConfig, addServer, removeServer, updateServer, setServerEnabled, SecretsManager, readSecretValueFromStdin, probeHttpAuthRequirement, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients, toSecretRef, secretRefName, defaultAuthSecretName, resolveAuthTarget, applyAuthReference, removeAuthReference, listAuthBindings, maybePrefixBearer, APP_VERSION, compareVersions, checkForUpdates, getStagedUpdate, clearStagedUpdate, getStagedCliPath, startBackgroundUpdateCheck, runBackgroundUpdate, performUpdate, performRollback, getDaemonStatus, startDaemon, stopDaemon, restartDaemon, readDaemonLogs, runDaemonForeground, STATUS_CLIENTS, buildStatusReport };
|
|
3405
|
+
export { getConfigPath, getManagedIndexPath, defaultConfig, loadConfig, saveConfig, addServer, removeServer, updateServer, setServerEnabled, ensureGatewayToken, listSkills, getSkill, saveSkill, deleteSkill, SecretsManager, readSecretValueFromStdin, probeHttpAuthRequirement, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients, toSecretRef, secretRefName, defaultAuthSecretName, resolveAuthTarget, applyAuthReference, removeAuthReference, listAuthBindings, maybePrefixBearer, APP_VERSION, compareVersions, checkForUpdates, getStagedUpdate, clearStagedUpdate, getStagedCliPath, startBackgroundUpdateCheck, runBackgroundUpdate, performUpdate, performRollback, getDaemonStatus, startDaemon, stopDaemon, restartDaemon, readDaemonLogs, runDaemonForeground, STATUS_CLIENTS, buildStatusReport };
|