@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,9 +1,10 @@
|
|
|
1
|
-
import type { ClientAdapter, ManagedIndex, McpxConfig, SyncClientOptions, SyncResult, PluginSyncInput, PluginSyncResult } from "../types.js";
|
|
1
|
+
import type { ClientAdapter, ManagedIndex, McpxConfig, Skill, SyncClientOptions, SyncResult, PluginSyncInput, PluginSyncResult } from "../types.js";
|
|
2
2
|
export declare class ClaudeDesktopAdapter implements ClientAdapter {
|
|
3
3
|
readonly id: "claude-desktop";
|
|
4
4
|
detectConfigPath(): string | null;
|
|
5
5
|
supportsHttp(): boolean;
|
|
6
6
|
syncPlugins(plugins: PluginSyncInput[]): PluginSyncResult;
|
|
7
|
+
syncSkills(skills: Skill[]): void;
|
|
7
8
|
scanForImports(_config: McpxConfig, managedIndex: ManagedIndex): import("../types.js").ClientImportScanResult;
|
|
8
9
|
syncGateway(_config: McpxConfig, options: SyncClientOptions): SyncResult;
|
|
9
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-desktop.d.ts","sourceRoot":"","sources":["../../src/adapters/claude-desktop.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAuB,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-desktop.d.ts","sourceRoot":"","sources":["../../src/adapters/claude-desktop.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAuB,UAAU,EAAE,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgDzK,qBAAa,oBAAqB,YAAW,aAAa;IACxD,QAAQ,CAAC,EAAE,EAAG,gBAAgB,CAAU;IAExC,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAUjC,YAAY,IAAI,OAAO;IAIvB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB;IAIzD,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAQjC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IA6D9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CA2DzE"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { ClientAdapter, ManagedIndex, McpxConfig, SyncClientOptions, SyncResult, PluginSyncInput, PluginSyncResult } from "../types.js";
|
|
1
|
+
import type { ClientAdapter, ManagedIndex, McpxConfig, Skill, SyncClientOptions, SyncResult, PluginSyncInput, PluginSyncResult } from "../types.js";
|
|
2
2
|
export declare class OpenCodeAdapter implements ClientAdapter {
|
|
3
3
|
readonly id: "opencode";
|
|
4
4
|
detectConfigPath(): string | null;
|
|
5
5
|
supportsHttp(): boolean;
|
|
6
6
|
syncPlugins(plugins: PluginSyncInput[]): PluginSyncResult;
|
|
7
|
+
syncSkills(skills: Skill[]): void;
|
|
7
8
|
scanForImports(_config: McpxConfig, managedIndex: ManagedIndex): import("../types.js").ClientImportScanResult;
|
|
8
9
|
syncGateway(_config: McpxConfig, options: SyncClientOptions): SyncResult;
|
|
9
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAkCpJ,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,EAAE,EAAG,UAAU,CAAU;IAElC,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB;IAIzD,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAQjC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAuE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CA6DzE"}
|
|
@@ -103,7 +103,7 @@ function parseCliAddCommand(command) {
|
|
|
103
103
|
if (parts[0] === "add") {
|
|
104
104
|
return parseStandardAdd(parts.slice(1));
|
|
105
105
|
}
|
|
106
|
-
|
|
106
|
+
throw new Error('Unrecognized command. Supported forms: "add <name> <url|command>", "claude mcp add ...", "codex mcp add ...", "qwen mcp add ...", "code --add-mcp ...", "openclaw mcp add ...", "hermes mcp add ...".');
|
|
107
107
|
}
|
|
108
108
|
function parseStandardAdd(args) {
|
|
109
109
|
const header = [];
|
|
@@ -3,25 +3,21 @@ import {
|
|
|
3
3
|
getGatewayUrl,
|
|
4
4
|
persistSyncState,
|
|
5
5
|
syncAllClients
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-vy81xjm0.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig,
|
|
9
9
|
loadMergedConfig,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
saveProjectConfig
|
|
13
|
-
} from "./cli-v27bt25d.js";
|
|
10
|
+
saveConfig
|
|
11
|
+
} from "./cli-g4w6k655.js";
|
|
14
12
|
import {
|
|
15
13
|
SecretsManager,
|
|
16
14
|
UpstreamError,
|
|
17
15
|
classifyUpstreamError,
|
|
18
16
|
ensureGatewayToken
|
|
19
|
-
} from "./cli-
|
|
17
|
+
} from "./cli-remv48t3.js";
|
|
20
18
|
import {
|
|
21
19
|
ensureDir,
|
|
22
20
|
ensureParentDir,
|
|
23
|
-
findProjectConfigPath,
|
|
24
|
-
getConfigPath,
|
|
25
21
|
getLogPath,
|
|
26
22
|
getPidPath,
|
|
27
23
|
getStagedVersionPath,
|
|
@@ -32,114 +28,6 @@ import {
|
|
|
32
28
|
isServerEnabled
|
|
33
29
|
} from "./cli-s4gspqdf.js";
|
|
34
30
|
|
|
35
|
-
// src/core/config-store.ts
|
|
36
|
-
import fs from "node:fs";
|
|
37
|
-
import path from "node:path";
|
|
38
|
-
var LOCK_STALE_MS = 5000;
|
|
39
|
-
var LOCK_RETRY_MS = 50;
|
|
40
|
-
var LOCK_MAX_RETRIES = 40;
|
|
41
|
-
var inProcessQueues = new Map;
|
|
42
|
-
function getLockPath(filePath) {
|
|
43
|
-
return `${filePath}.lock`;
|
|
44
|
-
}
|
|
45
|
-
function acquireLock(filePath) {
|
|
46
|
-
const lockPath = getLockPath(filePath);
|
|
47
|
-
try {
|
|
48
|
-
fs.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
49
|
-
const fd = fs.openSync(lockPath, "wx");
|
|
50
|
-
fs.writeSync(fd, String(process.pid));
|
|
51
|
-
fs.closeSync(fd);
|
|
52
|
-
return true;
|
|
53
|
-
} catch (err) {
|
|
54
|
-
if (err.code !== "EEXIST") {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
const stat = fs.statSync(lockPath);
|
|
59
|
-
if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {
|
|
60
|
-
fs.unlinkSync(lockPath);
|
|
61
|
-
return acquireLock(filePath);
|
|
62
|
-
}
|
|
63
|
-
} catch {
|
|
64
|
-
return acquireLock(filePath);
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function releaseLock(filePath) {
|
|
70
|
-
try {
|
|
71
|
-
fs.unlinkSync(getLockPath(filePath));
|
|
72
|
-
} catch {}
|
|
73
|
-
}
|
|
74
|
-
function mutateFile(filePath, load, save, fn) {
|
|
75
|
-
const prevQueue = inProcessQueues.get(filePath) ?? Promise.resolve();
|
|
76
|
-
const nextQueue = prevQueue.then(() => executeWithLock(filePath, load, save, fn), () => executeWithLock(filePath, load, save, fn));
|
|
77
|
-
inProcessQueues.set(filePath, nextQueue.catch(() => {
|
|
78
|
-
return;
|
|
79
|
-
}));
|
|
80
|
-
return nextQueue;
|
|
81
|
-
}
|
|
82
|
-
async function executeWithLock(filePath, load, save, fn) {
|
|
83
|
-
let acquired = false;
|
|
84
|
-
for (let attempt = 0;attempt < LOCK_MAX_RETRIES; attempt++) {
|
|
85
|
-
acquired = acquireLock(filePath);
|
|
86
|
-
if (acquired)
|
|
87
|
-
break;
|
|
88
|
-
await new Promise((r) => setTimeout(r, LOCK_RETRY_MS));
|
|
89
|
-
}
|
|
90
|
-
if (!acquired) {
|
|
91
|
-
throw new Error(`Could not acquire lock for ${filePath}.`);
|
|
92
|
-
}
|
|
93
|
-
try {
|
|
94
|
-
const data = load(filePath);
|
|
95
|
-
const result = await fn(data);
|
|
96
|
-
save(data, filePath);
|
|
97
|
-
return result;
|
|
98
|
-
} finally {
|
|
99
|
-
releaseLock(filePath);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
function mutateConfig(fn, configPath) {
|
|
103
|
-
return mutateFile(configPath ?? getConfigPath(), loadConfig, saveConfig, fn);
|
|
104
|
-
}
|
|
105
|
-
function mutateProjectConfig(projectConfigPath, fn) {
|
|
106
|
-
return mutateFile(projectConfigPath, (p) => loadProjectConfig(p), saveProjectConfig, fn);
|
|
107
|
-
}
|
|
108
|
-
async function mutateActiveConfig(options, mutator) {
|
|
109
|
-
const globalPath = getConfigPath();
|
|
110
|
-
if (!options.global) {
|
|
111
|
-
const projectConfigPath = findProjectConfigPath();
|
|
112
|
-
if (options.local) {
|
|
113
|
-
const projectPath = projectConfigPath ? path.dirname(projectConfigPath) : process.cwd();
|
|
114
|
-
const localPath = path.join(projectPath, ".mcpx.json");
|
|
115
|
-
const globalConfig = loadConfig(globalPath);
|
|
116
|
-
const result2 = await mutateProjectConfig(localPath, async (projectConfig) => {
|
|
117
|
-
const mergedConfig = {
|
|
118
|
-
...globalConfig,
|
|
119
|
-
servers: { ...globalConfig.servers, ...projectConfig.servers }
|
|
120
|
-
};
|
|
121
|
-
const mutatorResult = await mutator(mergedConfig, { type: "project", projectPath });
|
|
122
|
-
const localServers = {};
|
|
123
|
-
for (const [name, spec] of Object.entries(mergedConfig.servers)) {
|
|
124
|
-
if (!(name in globalConfig.servers)) {
|
|
125
|
-
localServers[name] = spec;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
projectConfig.servers = localServers;
|
|
129
|
-
return mutatorResult;
|
|
130
|
-
});
|
|
131
|
-
return { type: "project", configPath: localPath, projectPath, result: result2 };
|
|
132
|
-
}
|
|
133
|
-
if (projectConfigPath) {
|
|
134
|
-
const projectPath = path.dirname(projectConfigPath);
|
|
135
|
-
const result2 = await mutateConfig((config) => mutator(config, { type: "project", projectPath }), globalPath);
|
|
136
|
-
return { type: "project", configPath: globalPath, projectPath, result: result2 };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
const result = await mutateConfig((config) => mutator(config, { type: "global" }), globalPath);
|
|
140
|
-
return { type: "global", configPath: globalPath, result };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
31
|
// src/core/auth-probe.ts
|
|
144
32
|
var JSON_RPC_VERSION = "2.0";
|
|
145
33
|
var DEFAULT_AUTH_PROBE_TIMEOUT_MS = 8000;
|
|
@@ -476,20 +364,20 @@ function maybePrefixBearer(target, value, raw = false) {
|
|
|
476
364
|
|
|
477
365
|
// src/core/spawn-env.ts
|
|
478
366
|
import os from "node:os";
|
|
479
|
-
import
|
|
480
|
-
import
|
|
367
|
+
import path from "node:path";
|
|
368
|
+
import fs from "node:fs";
|
|
481
369
|
function existingNvmCurrentBin() {
|
|
482
|
-
const nvmDir = process.env.NVM_DIR ??
|
|
483
|
-
const current =
|
|
484
|
-
return
|
|
370
|
+
const nvmDir = process.env.NVM_DIR ?? path.join(os.homedir(), ".nvm");
|
|
371
|
+
const current = path.join(nvmDir, "current", "bin");
|
|
372
|
+
return fs.existsSync(current) ? current : null;
|
|
485
373
|
}
|
|
486
374
|
function buildEnrichedPath(current = process.env.PATH ?? "") {
|
|
487
375
|
const candidates = [
|
|
488
376
|
...current.split(":"),
|
|
489
377
|
"/opt/homebrew/bin",
|
|
490
378
|
"/usr/local/bin",
|
|
491
|
-
|
|
492
|
-
|
|
379
|
+
path.join(os.homedir(), ".bun", "bin"),
|
|
380
|
+
path.join(os.homedir(), ".local", "bin"),
|
|
493
381
|
existingNvmCurrentBin()
|
|
494
382
|
].filter((entry) => Boolean(entry));
|
|
495
383
|
const seen = new Set;
|
|
@@ -512,6 +400,7 @@ import {
|
|
|
512
400
|
discoverOAuthServerInfo,
|
|
513
401
|
refreshAuthorization
|
|
514
402
|
} from "@modelcontextprotocol/sdk/client/auth.js";
|
|
403
|
+
import { InvalidClientError, InvalidGrantError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
|
|
515
404
|
function oauthSecretName(serverName, suffix) {
|
|
516
405
|
return `oauth_${serverName.toLowerCase().replace(/[^a-z0-9._-]/g, "_")}_${suffix}`;
|
|
517
406
|
}
|
|
@@ -744,6 +633,7 @@ async function runOAuthLogin(serverName, spec, secrets, openUrl, configPath, cod
|
|
|
744
633
|
redirectUrl = `http://127.0.0.1:${port}/callback`;
|
|
745
634
|
codePromise = waitForAuthorizationCode(callbackServer, state);
|
|
746
635
|
}
|
|
636
|
+
codePromise.catch(() => {});
|
|
747
637
|
const provider = new InteractiveOAuthProvider(serverName, secrets, redirectUrl, state, openUrl);
|
|
748
638
|
try {
|
|
749
639
|
const initial = await auth(provider, {
|
|
@@ -820,7 +710,7 @@ async function getOAuthAccessToken(serverName, spec, secrets, options = {}) {
|
|
|
820
710
|
return refreshed.access_token;
|
|
821
711
|
} catch (err) {
|
|
822
712
|
const message = err instanceof Error ? err.message : String(err);
|
|
823
|
-
if (/invalid_grant|invalid_client|4\d{2}/i.test(message)) {
|
|
713
|
+
if (err instanceof InvalidGrantError || err instanceof InvalidClientError || /invalid_grant|invalid_client|4\d{2}/i.test(message)) {
|
|
824
714
|
throw new UpstreamError(serverName, "auth_expired", `OAuth refresh failed: ${message}`);
|
|
825
715
|
}
|
|
826
716
|
if (/ECONNREFUSED|ENOTFOUND|EAI_AGAIN|fetch failed/i.test(message)) {
|
|
@@ -833,8 +723,8 @@ async function getOAuthAccessToken(serverName, spec, secrets, options = {}) {
|
|
|
833
723
|
}
|
|
834
724
|
|
|
835
725
|
// src/core/update.ts
|
|
836
|
-
import
|
|
837
|
-
import
|
|
726
|
+
import fs2 from "node:fs";
|
|
727
|
+
import path2 from "node:path";
|
|
838
728
|
import { execFileSync } from "node:child_process";
|
|
839
729
|
function compareVersions(a, b) {
|
|
840
730
|
const partsA = a.split(".").map(Number);
|
|
@@ -873,17 +763,17 @@ async function checkForUpdates() {
|
|
|
873
763
|
}
|
|
874
764
|
function getStagedUpdate() {
|
|
875
765
|
const stagedPath = getStagedVersionPath();
|
|
876
|
-
if (!
|
|
766
|
+
if (!fs2.existsSync(stagedPath)) {
|
|
877
767
|
return null;
|
|
878
768
|
}
|
|
879
769
|
try {
|
|
880
|
-
const raw =
|
|
770
|
+
const raw = fs2.readFileSync(stagedPath, "utf8");
|
|
881
771
|
const info = JSON.parse(raw);
|
|
882
772
|
if (!info.version || !info.cliPath) {
|
|
883
773
|
return null;
|
|
884
774
|
}
|
|
885
|
-
const absoluteCliPath =
|
|
886
|
-
if (!
|
|
775
|
+
const absoluteCliPath = path2.isAbsolute(info.cliPath) ? info.cliPath : path2.join(getUpdatesDir(), info.cliPath);
|
|
776
|
+
if (!fs2.existsSync(absoluteCliPath)) {
|
|
887
777
|
return null;
|
|
888
778
|
}
|
|
889
779
|
return {
|
|
@@ -899,18 +789,18 @@ function stageUpdate(version, cliPath) {
|
|
|
899
789
|
ensureDir(updatesDir);
|
|
900
790
|
const stagedInfo = {
|
|
901
791
|
version,
|
|
902
|
-
cliPath:
|
|
792
|
+
cliPath: path2.isAbsolute(cliPath) ? path2.relative(updatesDir, cliPath) : cliPath,
|
|
903
793
|
stagedAt: new Date().toISOString()
|
|
904
794
|
};
|
|
905
|
-
|
|
795
|
+
fs2.writeFileSync(getStagedVersionPath(), JSON.stringify(stagedInfo, null, 2), "utf8");
|
|
906
796
|
}
|
|
907
797
|
function shouldUseStagedCli(stagedVersion, currentVersion) {
|
|
908
798
|
return compareVersions(stagedVersion, currentVersion) > 0;
|
|
909
799
|
}
|
|
910
800
|
function clearStagedUpdate() {
|
|
911
801
|
const stagedPath = getStagedVersionPath();
|
|
912
|
-
if (
|
|
913
|
-
|
|
802
|
+
if (fs2.existsSync(stagedPath)) {
|
|
803
|
+
fs2.unlinkSync(stagedPath);
|
|
914
804
|
}
|
|
915
805
|
}
|
|
916
806
|
function getStagedCliPath() {
|
|
@@ -919,59 +809,59 @@ function getStagedCliPath() {
|
|
|
919
809
|
}
|
|
920
810
|
function removeOldVersions(keepCount = 2) {
|
|
921
811
|
const updatesDir = getUpdatesDir();
|
|
922
|
-
if (!
|
|
812
|
+
if (!fs2.existsSync(updatesDir)) {
|
|
923
813
|
return;
|
|
924
814
|
}
|
|
925
|
-
const entries =
|
|
815
|
+
const entries = fs2.readdirSync(updatesDir, { withFileTypes: true });
|
|
926
816
|
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)));
|
|
927
817
|
if (versionDirs.length <= keepCount) {
|
|
928
818
|
return;
|
|
929
819
|
}
|
|
930
820
|
for (const oldVersion of versionDirs.slice(keepCount)) {
|
|
931
|
-
const oldPath =
|
|
821
|
+
const oldPath = path2.join(updatesDir, oldVersion);
|
|
932
822
|
try {
|
|
933
|
-
|
|
823
|
+
fs2.rmSync(oldPath, { recursive: true, force: true });
|
|
934
824
|
} catch {}
|
|
935
825
|
}
|
|
936
826
|
}
|
|
937
827
|
|
|
938
828
|
// src/core/update-manager.ts
|
|
939
|
-
import
|
|
940
|
-
import
|
|
829
|
+
import fs3 from "node:fs";
|
|
830
|
+
import path3 from "node:path";
|
|
941
831
|
import { execSync, spawn } from "node:child_process";
|
|
942
|
-
function
|
|
832
|
+
function acquireLock() {
|
|
943
833
|
const lockPath = getUpdateLockPath();
|
|
944
834
|
try {
|
|
945
|
-
ensureDir(
|
|
946
|
-
|
|
835
|
+
ensureDir(path3.dirname(lockPath));
|
|
836
|
+
fs3.writeFileSync(lockPath, `${process.pid}
|
|
947
837
|
`, { flag: "wx" });
|
|
948
838
|
return true;
|
|
949
839
|
} catch {
|
|
950
840
|
return false;
|
|
951
841
|
}
|
|
952
842
|
}
|
|
953
|
-
function
|
|
843
|
+
function releaseLock() {
|
|
954
844
|
const lockPath = getUpdateLockPath();
|
|
955
845
|
try {
|
|
956
|
-
|
|
846
|
+
fs3.unlinkSync(lockPath);
|
|
957
847
|
} catch {}
|
|
958
848
|
}
|
|
959
849
|
function isUpdateInProgress() {
|
|
960
850
|
const lockPath = getUpdateLockPath();
|
|
961
|
-
if (!
|
|
851
|
+
if (!fs3.existsSync(lockPath)) {
|
|
962
852
|
return false;
|
|
963
853
|
}
|
|
964
854
|
try {
|
|
965
|
-
const raw =
|
|
855
|
+
const raw = fs3.readFileSync(lockPath, "utf8").trim();
|
|
966
856
|
const pid = Number(raw);
|
|
967
857
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
968
|
-
|
|
858
|
+
fs3.unlinkSync(lockPath);
|
|
969
859
|
return false;
|
|
970
860
|
}
|
|
971
861
|
process.kill(pid, 0);
|
|
972
862
|
return true;
|
|
973
863
|
} catch {
|
|
974
|
-
|
|
864
|
+
fs3.unlinkSync(lockPath);
|
|
975
865
|
return false;
|
|
976
866
|
}
|
|
977
867
|
}
|
|
@@ -982,8 +872,8 @@ async function downloadAndStageUpdate() {
|
|
|
982
872
|
}
|
|
983
873
|
const targetVersion = updateStatus.latestVersion;
|
|
984
874
|
const updatesDir = getUpdatesDir();
|
|
985
|
-
const versionDir =
|
|
986
|
-
if (
|
|
875
|
+
const versionDir = path3.join(updatesDir, `v${targetVersion}`);
|
|
876
|
+
if (fs3.existsSync(versionDir)) {
|
|
987
877
|
const existingStaged = getStagedUpdate();
|
|
988
878
|
if (existingStaged?.version === targetVersion) {
|
|
989
879
|
return { success: false, error: `Version ${targetVersion} already staged` };
|
|
@@ -995,8 +885,8 @@ async function downloadAndStageUpdate() {
|
|
|
995
885
|
cwd: versionDir,
|
|
996
886
|
stdio: ["pipe", "pipe", "pipe"]
|
|
997
887
|
});
|
|
998
|
-
const tarballPath =
|
|
999
|
-
if (!
|
|
888
|
+
const tarballPath = path3.join(versionDir, `kwonye-mcpx-${targetVersion}.tgz`);
|
|
889
|
+
if (!fs3.existsSync(tarballPath)) {
|
|
1000
890
|
throw new Error("Downloaded tarball not found");
|
|
1001
891
|
}
|
|
1002
892
|
execSync(`tar -xzf ${tarballPath} --strip-components=1`, {
|
|
@@ -1007,8 +897,8 @@ async function downloadAndStageUpdate() {
|
|
|
1007
897
|
cwd: versionDir,
|
|
1008
898
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1009
899
|
});
|
|
1010
|
-
const cliPath =
|
|
1011
|
-
if (!
|
|
900
|
+
const cliPath = path3.join(versionDir, "dist", "cli.js");
|
|
901
|
+
if (!fs3.existsSync(cliPath)) {
|
|
1012
902
|
throw new Error("CLI entry point not found in downloaded package");
|
|
1013
903
|
}
|
|
1014
904
|
try {
|
|
@@ -1024,7 +914,7 @@ async function downloadAndStageUpdate() {
|
|
|
1024
914
|
return { success: true, version: targetVersion };
|
|
1025
915
|
} catch (error) {
|
|
1026
916
|
try {
|
|
1027
|
-
|
|
917
|
+
fs3.rmSync(versionDir, { recursive: true, force: true });
|
|
1028
918
|
} catch {}
|
|
1029
919
|
return {
|
|
1030
920
|
success: false,
|
|
@@ -1039,7 +929,7 @@ function startBackgroundUpdateCheck() {
|
|
|
1039
929
|
if (isUpdateInProgress()) {
|
|
1040
930
|
return;
|
|
1041
931
|
}
|
|
1042
|
-
if (!
|
|
932
|
+
if (!acquireLock()) {
|
|
1043
933
|
return;
|
|
1044
934
|
}
|
|
1045
935
|
const child = spawn(process.execPath, [
|
|
@@ -1056,7 +946,7 @@ function startBackgroundUpdateCheck() {
|
|
|
1056
946
|
});
|
|
1057
947
|
child.unref();
|
|
1058
948
|
setTimeout(() => {
|
|
1059
|
-
|
|
949
|
+
releaseLock();
|
|
1060
950
|
}, 60000);
|
|
1061
951
|
}
|
|
1062
952
|
async function runBackgroundUpdate() {
|
|
@@ -1070,14 +960,14 @@ async function runBackgroundUpdate() {
|
|
|
1070
960
|
} catch (error) {
|
|
1071
961
|
console.error(`[update-manager] Background update failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1072
962
|
} finally {
|
|
1073
|
-
|
|
963
|
+
releaseLock();
|
|
1074
964
|
}
|
|
1075
965
|
}
|
|
1076
966
|
async function performUpdate() {
|
|
1077
967
|
if (isUpdateInProgress()) {
|
|
1078
968
|
return { success: false, message: "Another update is already in progress." };
|
|
1079
969
|
}
|
|
1080
|
-
if (!
|
|
970
|
+
if (!acquireLock()) {
|
|
1081
971
|
return { success: false, message: "Another update is already in progress." };
|
|
1082
972
|
}
|
|
1083
973
|
try {
|
|
@@ -1096,7 +986,7 @@ async function performUpdate() {
|
|
|
1096
986
|
message: result.error ?? "Update failed"
|
|
1097
987
|
};
|
|
1098
988
|
} finally {
|
|
1099
|
-
|
|
989
|
+
releaseLock();
|
|
1100
990
|
}
|
|
1101
991
|
}
|
|
1102
992
|
function performRollback() {
|
|
@@ -1112,7 +1002,7 @@ function performRollback() {
|
|
|
1112
1002
|
}
|
|
1113
1003
|
|
|
1114
1004
|
// src/core/daemon.ts
|
|
1115
|
-
import
|
|
1005
|
+
import fs4 from "node:fs";
|
|
1116
1006
|
import net from "node:net";
|
|
1117
1007
|
import { spawn as spawn2, execFileSync as execFileSync2 } from "node:child_process";
|
|
1118
1008
|
|
|
@@ -2106,10 +1996,10 @@ function createGatewayServer(options) {
|
|
|
2106
1996
|
|
|
2107
1997
|
// src/core/daemon.ts
|
|
2108
1998
|
function readPidRecordFromFile(pidPath = getPidPath()) {
|
|
2109
|
-
if (!
|
|
1999
|
+
if (!fs4.existsSync(pidPath)) {
|
|
2110
2000
|
return null;
|
|
2111
2001
|
}
|
|
2112
|
-
const raw =
|
|
2002
|
+
const raw = fs4.readFileSync(pidPath, "utf8").trim();
|
|
2113
2003
|
if (!raw) {
|
|
2114
2004
|
return null;
|
|
2115
2005
|
}
|
|
@@ -2227,7 +2117,7 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
2227
2117
|
};
|
|
2228
2118
|
}
|
|
2229
2119
|
try {
|
|
2230
|
-
|
|
2120
|
+
fs4.unlinkSync(getPidPath());
|
|
2231
2121
|
} catch {}
|
|
2232
2122
|
}
|
|
2233
2123
|
const { port, fellBackFrom } = await resolveGatewayPort(config, secrets);
|
|
@@ -2240,24 +2130,24 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
2240
2130
|
const logPath = getLogPath();
|
|
2241
2131
|
ensureParentDir(pidPath);
|
|
2242
2132
|
ensureParentDir(logPath);
|
|
2243
|
-
let logFd =
|
|
2244
|
-
const logStat =
|
|
2133
|
+
let logFd = fs4.openSync(logPath, "a", 384);
|
|
2134
|
+
const logStat = fs4.fstatSync(logFd);
|
|
2245
2135
|
if (logStat.size > 10 * 1024 * 1024) {
|
|
2246
|
-
|
|
2136
|
+
fs4.closeSync(logFd);
|
|
2247
2137
|
const log1 = `${logPath}.1`;
|
|
2248
2138
|
const log2 = `${logPath}.2`;
|
|
2249
2139
|
try {
|
|
2250
|
-
if (
|
|
2251
|
-
|
|
2140
|
+
if (fs4.existsSync(log2))
|
|
2141
|
+
fs4.unlinkSync(log2);
|
|
2252
2142
|
} catch {}
|
|
2253
2143
|
try {
|
|
2254
|
-
if (
|
|
2255
|
-
|
|
2144
|
+
if (fs4.existsSync(log1))
|
|
2145
|
+
fs4.renameSync(log1, log2);
|
|
2256
2146
|
} catch {}
|
|
2257
2147
|
try {
|
|
2258
|
-
|
|
2148
|
+
fs4.renameSync(logPath, log1);
|
|
2259
2149
|
} catch {}
|
|
2260
|
-
logFd =
|
|
2150
|
+
logFd = fs4.openSync(logPath, "a", 384);
|
|
2261
2151
|
}
|
|
2262
2152
|
const child = spawn2(process.execPath, [cliPath, "daemon", "run", "--port", String(port)], {
|
|
2263
2153
|
detached: true,
|
|
@@ -2268,7 +2158,7 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
2268
2158
|
}
|
|
2269
2159
|
});
|
|
2270
2160
|
child.unref();
|
|
2271
|
-
|
|
2161
|
+
fs4.writeFileSync(pidPath, `${child.pid}:${port}
|
|
2272
2162
|
`, { mode: 384 });
|
|
2273
2163
|
startBackgroundUpdateCheck();
|
|
2274
2164
|
await waitForGatewayReady(port, token);
|
|
@@ -2292,7 +2182,7 @@ function stopDaemon() {
|
|
|
2292
2182
|
const cmd = execFileSync2("ps", ["-p", String(pid), "-o", "command="], { encoding: "utf8", timeout: 2000 }).trim();
|
|
2293
2183
|
const looksLikeMcpxDaemon = cmd.includes("daemon run") && (cmd.includes("mcpx") || cmd.includes("cli.js"));
|
|
2294
2184
|
if (!looksLikeMcpxDaemon) {
|
|
2295
|
-
|
|
2185
|
+
fs4.unlinkSync(pidPath);
|
|
2296
2186
|
return {
|
|
2297
2187
|
stopped: false,
|
|
2298
2188
|
message: `PID ${pid} is not a mcpx daemon (command: ${cmd.slice(0, 80)}). Pidfile cleaned up.`
|
|
@@ -2300,7 +2190,7 @@ function stopDaemon() {
|
|
|
2300
2190
|
}
|
|
2301
2191
|
} catch {
|
|
2302
2192
|
try {
|
|
2303
|
-
|
|
2193
|
+
fs4.unlinkSync(pidPath);
|
|
2304
2194
|
} catch {}
|
|
2305
2195
|
return {
|
|
2306
2196
|
stopped: false,
|
|
@@ -2311,7 +2201,7 @@ function stopDaemon() {
|
|
|
2311
2201
|
process.kill(pid, "SIGTERM");
|
|
2312
2202
|
} catch {}
|
|
2313
2203
|
try {
|
|
2314
|
-
|
|
2204
|
+
fs4.unlinkSync(pidPath);
|
|
2315
2205
|
} catch {}
|
|
2316
2206
|
return {
|
|
2317
2207
|
stopped: true,
|
|
@@ -2324,10 +2214,10 @@ async function restartDaemon(config, cliPath, secrets) {
|
|
|
2324
2214
|
}
|
|
2325
2215
|
function readDaemonLogs(maxLines = 200) {
|
|
2326
2216
|
const logPath = getLogPath();
|
|
2327
|
-
if (!
|
|
2217
|
+
if (!fs4.existsSync(logPath)) {
|
|
2328
2218
|
return "";
|
|
2329
2219
|
}
|
|
2330
|
-
const lines =
|
|
2220
|
+
const lines = fs4.readFileSync(logPath, "utf8").split(`
|
|
2331
2221
|
`);
|
|
2332
2222
|
return lines.slice(Math.max(lines.length - maxLines, 0)).join(`
|
|
2333
2223
|
`);
|
|
@@ -2470,4 +2360,4 @@ async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(
|
|
|
2470
2360
|
};
|
|
2471
2361
|
}
|
|
2472
2362
|
|
|
2473
|
-
export {
|
|
2363
|
+
export { probeHttpAuthRequirement, fetchRegistryServerDetail, selectBestPackage, extractRequiredInputs, mapRegistryToSpec, toSecretRef, secretRefName, defaultAuthSecretName, resolveAuthTarget, applyAuthReference, removeAuthReference, listAuthBindings, maybePrefixBearer, buildEnrichedPath, isOAuthReference, oauthReferenceServerName, runOAuthLogin, getOAuthAccessToken, compareVersions, checkForUpdates, getStagedUpdate, shouldUseStagedCli, clearStagedUpdate, getStagedCliPath, startBackgroundUpdateCheck, runBackgroundUpdate, performUpdate, performRollback, getDaemonStatus, startDaemon, stopDaemon, restartDaemon, readDaemonLogs, runDaemonForeground, STATUS_CLIENTS, buildStatusReport };
|
|
@@ -175,8 +175,10 @@ var UNREACHABLE_PATTERNS = [
|
|
|
175
175
|
/EAI_AGAIN/,
|
|
176
176
|
/socket hang up/,
|
|
177
177
|
/ENOENT/,
|
|
178
|
-
/connect econnrefused/i
|
|
178
|
+
/connect econnrefused/i,
|
|
179
|
+
/unable to connect/i
|
|
179
180
|
];
|
|
181
|
+
var UNREACHABLE_ERROR_CODES = new Set(["ConnectionRefused"]);
|
|
180
182
|
function classifyUpstreamError(upstream, error, wwwAuthenticate) {
|
|
181
183
|
if (error instanceof UpstreamError)
|
|
182
184
|
return error;
|
|
@@ -194,7 +196,7 @@ function classifyUpstreamError(upstream, error, wwwAuthenticate) {
|
|
|
194
196
|
if (TIMEOUT_RE.test(message)) {
|
|
195
197
|
return new UpstreamError(upstream, "timeout", message);
|
|
196
198
|
}
|
|
197
|
-
if (UNREACHABLE_PATTERNS.some((p) => p.test(message))) {
|
|
199
|
+
if (typeof maybeHttpError?.code === "string" && UNREACHABLE_ERROR_CODES.has(maybeHttpError.code) || UNREACHABLE_PATTERNS.some((p) => p.test(message))) {
|
|
198
200
|
return new UpstreamError(upstream, "unreachable", message);
|
|
199
201
|
}
|
|
200
202
|
return new UpstreamError(upstream, "upstream_error", message);
|