@kwonye/mcpx 0.1.94 → 0.1.96
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/claude.d.ts +2 -1
- package/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/cline.d.ts +3 -1
- package/dist/adapters/cline.d.ts.map +1 -1
- package/dist/adapters/codex.d.ts +2 -1
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/cursor.d.ts +2 -1
- package/dist/adapters/cursor.d.ts.map +1 -1
- package/dist/adapters/hermes.d.ts +11 -0
- package/dist/adapters/hermes.d.ts.map +1 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/kiro.d.ts.map +1 -1
- package/dist/adapters/openclaw.d.ts +11 -0
- package/dist/adapters/openclaw.d.ts.map +1 -0
- package/dist/adapters/opencode.d.ts +2 -1
- package/dist/adapters/opencode.d.ts.map +1 -1
- package/dist/adapters/qwen.d.ts.map +1 -1
- package/dist/adapters/utils/index.d.ts +7 -1
- package/dist/adapters/utils/index.d.ts.map +1 -1
- package/dist/adapters/vscode.d.ts +2 -1
- package/dist/adapters/vscode.d.ts.map +1 -1
- package/dist/{cli-n8vt375e.js → cli-2vg0te30.js} +715 -211
- package/dist/{cli-154shqmt.js → cli-ap2jhwnz.js} +311 -95
- package/dist/{cli-tk8bggg5.js → cli-remv48t3.js} +4 -2
- package/dist/{cli-csfsg1yf.js → cli-v27bt25d.js} +79 -7
- package/dist/{cli-9fmn9y72.js → cli-z1fv3ra8.js} +105 -29
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +362 -75
- package/dist/compat/hermes.d.ts +7 -0
- package/dist/compat/hermes.d.ts.map +1 -0
- package/dist/compat/index.d.ts.map +1 -1
- package/dist/compat/openclaw.d.ts +7 -0
- package/dist/compat/openclaw.d.ts.map +1 -0
- package/dist/{config-dtc3c79c.js → config-5p08cb0c.js} +1 -1
- package/dist/core/add-command.d.ts.map +1 -1
- package/dist/core/config-store.d.ts +30 -0
- package/dist/core/config-store.d.ts.map +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/daemon.d.ts +5 -1
- package/dist/core/daemon.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 +16 -67
- package/dist/core/managed-index-lock.d.ts +2 -0
- package/dist/core/managed-index-lock.d.ts.map +1 -0
- package/dist/core/oauth.d.ts.map +1 -1
- package/dist/core/plugin-host.d.ts +2 -0
- package/dist/core/plugin-host.d.ts.map +1 -0
- package/dist/core/plugin-manager.d.ts +19 -6
- package/dist/core/plugin-manager.d.ts.map +1 -1
- package/dist/core/plugin-parse.d.ts.map +1 -1
- package/dist/core/plugin-projections.d.ts.map +1 -1
- package/dist/core/skill-projections.d.ts +3 -0
- package/dist/core/skill-projections.d.ts.map +1 -0
- package/dist/core/status.d.ts.map +1 -1
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/update-manager.d.ts.map +1 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/plugin-host-73dvcen6.js +129 -0
- package/dist/{plugin-manager-1sjwfnah.js → plugin-manager-y5txkse1.js} +12 -4
- package/dist/{registry-n12thgf2.js → registry-bnjb2345.js} +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +3 -2
- package/dist/cli-mxmgxdm2.js +0 -2257
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
|
+
APP_VERSION,
|
|
2
3
|
getGatewayUrl,
|
|
3
4
|
persistSyncState,
|
|
4
5
|
syncAllClients
|
|
5
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-2vg0te30.js";
|
|
6
7
|
import {
|
|
7
8
|
loadConfig,
|
|
8
9
|
loadMergedConfig,
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
loadProjectConfig,
|
|
11
|
+
saveConfig,
|
|
12
|
+
saveProjectConfig
|
|
13
|
+
} from "./cli-v27bt25d.js";
|
|
11
14
|
import {
|
|
12
15
|
SecretsManager,
|
|
13
16
|
UpstreamError,
|
|
14
17
|
classifyUpstreamError,
|
|
15
18
|
ensureGatewayToken
|
|
16
|
-
} from "./cli-
|
|
19
|
+
} from "./cli-remv48t3.js";
|
|
17
20
|
import {
|
|
18
21
|
ensureDir,
|
|
19
22
|
ensureParentDir,
|
|
23
|
+
findProjectConfigPath,
|
|
24
|
+
getConfigPath,
|
|
20
25
|
getLogPath,
|
|
21
26
|
getPidPath,
|
|
22
27
|
getStagedVersionPath,
|
|
@@ -27,6 +32,114 @@ import {
|
|
|
27
32
|
isServerEnabled
|
|
28
33
|
} from "./cli-s4gspqdf.js";
|
|
29
34
|
|
|
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
|
+
|
|
30
143
|
// src/core/auth-probe.ts
|
|
31
144
|
var JSON_RPC_VERSION = "2.0";
|
|
32
145
|
var DEFAULT_AUTH_PROBE_TIMEOUT_MS = 8000;
|
|
@@ -363,20 +476,20 @@ function maybePrefixBearer(target, value, raw = false) {
|
|
|
363
476
|
|
|
364
477
|
// src/core/spawn-env.ts
|
|
365
478
|
import os from "node:os";
|
|
366
|
-
import
|
|
367
|
-
import
|
|
479
|
+
import path2 from "node:path";
|
|
480
|
+
import fs2 from "node:fs";
|
|
368
481
|
function existingNvmCurrentBin() {
|
|
369
|
-
const nvmDir = process.env.NVM_DIR ??
|
|
370
|
-
const current =
|
|
371
|
-
return
|
|
482
|
+
const nvmDir = process.env.NVM_DIR ?? path2.join(os.homedir(), ".nvm");
|
|
483
|
+
const current = path2.join(nvmDir, "current", "bin");
|
|
484
|
+
return fs2.existsSync(current) ? current : null;
|
|
372
485
|
}
|
|
373
486
|
function buildEnrichedPath(current = process.env.PATH ?? "") {
|
|
374
487
|
const candidates = [
|
|
375
488
|
...current.split(":"),
|
|
376
489
|
"/opt/homebrew/bin",
|
|
377
490
|
"/usr/local/bin",
|
|
378
|
-
|
|
379
|
-
|
|
491
|
+
path2.join(os.homedir(), ".bun", "bin"),
|
|
492
|
+
path2.join(os.homedir(), ".local", "bin"),
|
|
380
493
|
existingNvmCurrentBin()
|
|
381
494
|
].filter((entry) => Boolean(entry));
|
|
382
495
|
const seen = new Set;
|
|
@@ -653,12 +766,14 @@ async function runOAuthLogin(serverName, spec, secrets, openUrl, configPath, cod
|
|
|
653
766
|
const summary = syncAllClients(config, secrets);
|
|
654
767
|
persistSyncState(summary, config);
|
|
655
768
|
saveConfig(config, configPath);
|
|
769
|
+
new McpxOAuthProvider(serverName, secrets).invalidateCredentials("verifier");
|
|
656
770
|
return { serverName, authorized: true };
|
|
657
771
|
} catch (error) {
|
|
658
772
|
if (backupTokens)
|
|
659
773
|
secrets.setSecret(oauthName, backupTokens);
|
|
660
774
|
if (backupClient)
|
|
661
775
|
secrets.setSecret(clientName, backupClient);
|
|
776
|
+
new McpxOAuthProvider(serverName, secrets).invalidateCredentials("verifier");
|
|
662
777
|
throw error;
|
|
663
778
|
} finally {
|
|
664
779
|
if (callbackServer) {
|
|
@@ -717,12 +832,9 @@ async function getOAuthAccessToken(serverName, spec, secrets, options = {}) {
|
|
|
717
832
|
return stored.tokens.access_token;
|
|
718
833
|
}
|
|
719
834
|
|
|
720
|
-
// src/version.ts
|
|
721
|
-
var APP_VERSION = "0.1.3";
|
|
722
|
-
|
|
723
835
|
// src/core/update.ts
|
|
724
|
-
import
|
|
725
|
-
import
|
|
836
|
+
import fs3 from "node:fs";
|
|
837
|
+
import path3 from "node:path";
|
|
726
838
|
import { execFileSync } from "node:child_process";
|
|
727
839
|
function compareVersions(a, b) {
|
|
728
840
|
const partsA = a.split(".").map(Number);
|
|
@@ -761,17 +873,17 @@ async function checkForUpdates() {
|
|
|
761
873
|
}
|
|
762
874
|
function getStagedUpdate() {
|
|
763
875
|
const stagedPath = getStagedVersionPath();
|
|
764
|
-
if (!
|
|
876
|
+
if (!fs3.existsSync(stagedPath)) {
|
|
765
877
|
return null;
|
|
766
878
|
}
|
|
767
879
|
try {
|
|
768
|
-
const raw =
|
|
880
|
+
const raw = fs3.readFileSync(stagedPath, "utf8");
|
|
769
881
|
const info = JSON.parse(raw);
|
|
770
882
|
if (!info.version || !info.cliPath) {
|
|
771
883
|
return null;
|
|
772
884
|
}
|
|
773
|
-
const absoluteCliPath =
|
|
774
|
-
if (!
|
|
885
|
+
const absoluteCliPath = path3.isAbsolute(info.cliPath) ? info.cliPath : path3.join(getUpdatesDir(), info.cliPath);
|
|
886
|
+
if (!fs3.existsSync(absoluteCliPath)) {
|
|
775
887
|
return null;
|
|
776
888
|
}
|
|
777
889
|
return {
|
|
@@ -787,18 +899,18 @@ function stageUpdate(version, cliPath) {
|
|
|
787
899
|
ensureDir(updatesDir);
|
|
788
900
|
const stagedInfo = {
|
|
789
901
|
version,
|
|
790
|
-
cliPath:
|
|
902
|
+
cliPath: path3.isAbsolute(cliPath) ? path3.relative(updatesDir, cliPath) : cliPath,
|
|
791
903
|
stagedAt: new Date().toISOString()
|
|
792
904
|
};
|
|
793
|
-
|
|
905
|
+
fs3.writeFileSync(getStagedVersionPath(), JSON.stringify(stagedInfo, null, 2), "utf8");
|
|
794
906
|
}
|
|
795
907
|
function shouldUseStagedCli(stagedVersion, currentVersion) {
|
|
796
908
|
return compareVersions(stagedVersion, currentVersion) > 0;
|
|
797
909
|
}
|
|
798
910
|
function clearStagedUpdate() {
|
|
799
911
|
const stagedPath = getStagedVersionPath();
|
|
800
|
-
if (
|
|
801
|
-
|
|
912
|
+
if (fs3.existsSync(stagedPath)) {
|
|
913
|
+
fs3.unlinkSync(stagedPath);
|
|
802
914
|
}
|
|
803
915
|
}
|
|
804
916
|
function getStagedCliPath() {
|
|
@@ -807,59 +919,59 @@ function getStagedCliPath() {
|
|
|
807
919
|
}
|
|
808
920
|
function removeOldVersions(keepCount = 2) {
|
|
809
921
|
const updatesDir = getUpdatesDir();
|
|
810
|
-
if (!
|
|
922
|
+
if (!fs3.existsSync(updatesDir)) {
|
|
811
923
|
return;
|
|
812
924
|
}
|
|
813
|
-
const entries =
|
|
925
|
+
const entries = fs3.readdirSync(updatesDir, { withFileTypes: true });
|
|
814
926
|
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)));
|
|
815
927
|
if (versionDirs.length <= keepCount) {
|
|
816
928
|
return;
|
|
817
929
|
}
|
|
818
930
|
for (const oldVersion of versionDirs.slice(keepCount)) {
|
|
819
|
-
const oldPath =
|
|
931
|
+
const oldPath = path3.join(updatesDir, oldVersion);
|
|
820
932
|
try {
|
|
821
|
-
|
|
933
|
+
fs3.rmSync(oldPath, { recursive: true, force: true });
|
|
822
934
|
} catch {}
|
|
823
935
|
}
|
|
824
936
|
}
|
|
825
937
|
|
|
826
938
|
// src/core/update-manager.ts
|
|
827
|
-
import
|
|
828
|
-
import
|
|
939
|
+
import fs4 from "node:fs";
|
|
940
|
+
import path4 from "node:path";
|
|
829
941
|
import { execSync, spawn } from "node:child_process";
|
|
830
|
-
function
|
|
942
|
+
function acquireLock2() {
|
|
831
943
|
const lockPath = getUpdateLockPath();
|
|
832
944
|
try {
|
|
833
|
-
ensureDir(
|
|
834
|
-
|
|
945
|
+
ensureDir(path4.dirname(lockPath));
|
|
946
|
+
fs4.writeFileSync(lockPath, `${process.pid}
|
|
835
947
|
`, { flag: "wx" });
|
|
836
948
|
return true;
|
|
837
949
|
} catch {
|
|
838
950
|
return false;
|
|
839
951
|
}
|
|
840
952
|
}
|
|
841
|
-
function
|
|
953
|
+
function releaseLock2() {
|
|
842
954
|
const lockPath = getUpdateLockPath();
|
|
843
955
|
try {
|
|
844
|
-
|
|
956
|
+
fs4.unlinkSync(lockPath);
|
|
845
957
|
} catch {}
|
|
846
958
|
}
|
|
847
959
|
function isUpdateInProgress() {
|
|
848
960
|
const lockPath = getUpdateLockPath();
|
|
849
|
-
if (!
|
|
961
|
+
if (!fs4.existsSync(lockPath)) {
|
|
850
962
|
return false;
|
|
851
963
|
}
|
|
852
964
|
try {
|
|
853
|
-
const raw =
|
|
965
|
+
const raw = fs4.readFileSync(lockPath, "utf8").trim();
|
|
854
966
|
const pid = Number(raw);
|
|
855
967
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
856
|
-
|
|
968
|
+
fs4.unlinkSync(lockPath);
|
|
857
969
|
return false;
|
|
858
970
|
}
|
|
859
971
|
process.kill(pid, 0);
|
|
860
972
|
return true;
|
|
861
973
|
} catch {
|
|
862
|
-
|
|
974
|
+
fs4.unlinkSync(lockPath);
|
|
863
975
|
return false;
|
|
864
976
|
}
|
|
865
977
|
}
|
|
@@ -870,8 +982,8 @@ async function downloadAndStageUpdate() {
|
|
|
870
982
|
}
|
|
871
983
|
const targetVersion = updateStatus.latestVersion;
|
|
872
984
|
const updatesDir = getUpdatesDir();
|
|
873
|
-
const versionDir =
|
|
874
|
-
if (
|
|
985
|
+
const versionDir = path4.join(updatesDir, `v${targetVersion}`);
|
|
986
|
+
if (fs4.existsSync(versionDir)) {
|
|
875
987
|
const existingStaged = getStagedUpdate();
|
|
876
988
|
if (existingStaged?.version === targetVersion) {
|
|
877
989
|
return { success: false, error: `Version ${targetVersion} already staged` };
|
|
@@ -883,8 +995,8 @@ async function downloadAndStageUpdate() {
|
|
|
883
995
|
cwd: versionDir,
|
|
884
996
|
stdio: ["pipe", "pipe", "pipe"]
|
|
885
997
|
});
|
|
886
|
-
const tarballPath =
|
|
887
|
-
if (!
|
|
998
|
+
const tarballPath = path4.join(versionDir, `kwonye-mcpx-${targetVersion}.tgz`);
|
|
999
|
+
if (!fs4.existsSync(tarballPath)) {
|
|
888
1000
|
throw new Error("Downloaded tarball not found");
|
|
889
1001
|
}
|
|
890
1002
|
execSync(`tar -xzf ${tarballPath} --strip-components=1`, {
|
|
@@ -895,16 +1007,24 @@ async function downloadAndStageUpdate() {
|
|
|
895
1007
|
cwd: versionDir,
|
|
896
1008
|
stdio: ["pipe", "pipe", "pipe"]
|
|
897
1009
|
});
|
|
898
|
-
const cliPath =
|
|
899
|
-
if (!
|
|
1010
|
+
const cliPath = path4.join(versionDir, "dist", "cli.js");
|
|
1011
|
+
if (!fs4.existsSync(cliPath)) {
|
|
900
1012
|
throw new Error("CLI entry point not found in downloaded package");
|
|
901
1013
|
}
|
|
1014
|
+
try {
|
|
1015
|
+
execSync(`${process.execPath} ${JSON.stringify(cliPath)} --version`, {
|
|
1016
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1017
|
+
timeout: 1e4
|
|
1018
|
+
});
|
|
1019
|
+
} catch (smokeTestError) {
|
|
1020
|
+
throw new Error(`Downloaded CLI failed smoke test (--version): ${smokeTestError instanceof Error ? smokeTestError.message : String(smokeTestError)}`);
|
|
1021
|
+
}
|
|
902
1022
|
stageUpdate(targetVersion, cliPath);
|
|
903
1023
|
removeOldVersions(2);
|
|
904
1024
|
return { success: true, version: targetVersion };
|
|
905
1025
|
} catch (error) {
|
|
906
1026
|
try {
|
|
907
|
-
|
|
1027
|
+
fs4.rmSync(versionDir, { recursive: true, force: true });
|
|
908
1028
|
} catch {}
|
|
909
1029
|
return {
|
|
910
1030
|
success: false,
|
|
@@ -913,10 +1033,13 @@ async function downloadAndStageUpdate() {
|
|
|
913
1033
|
}
|
|
914
1034
|
}
|
|
915
1035
|
function startBackgroundUpdateCheck() {
|
|
1036
|
+
if (process.env.MCPX_NO_UPDATE === "1") {
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
916
1039
|
if (isUpdateInProgress()) {
|
|
917
1040
|
return;
|
|
918
1041
|
}
|
|
919
|
-
if (!
|
|
1042
|
+
if (!acquireLock2()) {
|
|
920
1043
|
return;
|
|
921
1044
|
}
|
|
922
1045
|
const child = spawn(process.execPath, [
|
|
@@ -933,7 +1056,7 @@ function startBackgroundUpdateCheck() {
|
|
|
933
1056
|
});
|
|
934
1057
|
child.unref();
|
|
935
1058
|
setTimeout(() => {
|
|
936
|
-
|
|
1059
|
+
releaseLock2();
|
|
937
1060
|
}, 60000);
|
|
938
1061
|
}
|
|
939
1062
|
async function runBackgroundUpdate() {
|
|
@@ -947,27 +1070,34 @@ async function runBackgroundUpdate() {
|
|
|
947
1070
|
} catch (error) {
|
|
948
1071
|
console.error(`[update-manager] Background update failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
949
1072
|
} finally {
|
|
950
|
-
|
|
1073
|
+
releaseLock2();
|
|
951
1074
|
}
|
|
952
1075
|
}
|
|
953
1076
|
async function performUpdate() {
|
|
954
1077
|
if (isUpdateInProgress()) {
|
|
955
1078
|
return { success: false, message: "Another update is already in progress." };
|
|
956
1079
|
}
|
|
957
|
-
|
|
958
|
-
|
|
1080
|
+
if (!acquireLock2()) {
|
|
1081
|
+
return { success: false, message: "Another update is already in progress." };
|
|
1082
|
+
}
|
|
1083
|
+
try {
|
|
1084
|
+
const result = await downloadAndStageUpdate();
|
|
1085
|
+
if (result.success && result.version) {
|
|
1086
|
+
return {
|
|
1087
|
+
success: true,
|
|
1088
|
+
message: `Update to v${result.version} ready! Will activate on next run.`
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
if (result.error === "No update available") {
|
|
1092
|
+
return { success: true, message: "Already on latest version." };
|
|
1093
|
+
}
|
|
959
1094
|
return {
|
|
960
|
-
success:
|
|
961
|
-
message:
|
|
1095
|
+
success: false,
|
|
1096
|
+
message: result.error ?? "Update failed"
|
|
962
1097
|
};
|
|
1098
|
+
} finally {
|
|
1099
|
+
releaseLock2();
|
|
963
1100
|
}
|
|
964
|
-
if (result.error === "No update available") {
|
|
965
|
-
return { success: true, message: "Already on latest version." };
|
|
966
|
-
}
|
|
967
|
-
return {
|
|
968
|
-
success: false,
|
|
969
|
-
message: result.error ?? "Update failed"
|
|
970
|
-
};
|
|
971
1101
|
}
|
|
972
1102
|
function performRollback() {
|
|
973
1103
|
const currentStaged = getStagedUpdate();
|
|
@@ -982,7 +1112,7 @@ function performRollback() {
|
|
|
982
1112
|
}
|
|
983
1113
|
|
|
984
1114
|
// src/core/daemon.ts
|
|
985
|
-
import
|
|
1115
|
+
import fs5 from "node:fs";
|
|
986
1116
|
import net from "node:net";
|
|
987
1117
|
import { spawn as spawn2, execFileSync as execFileSync2 } from "node:child_process";
|
|
988
1118
|
|
|
@@ -1226,11 +1356,41 @@ function withTimeout(work, timeoutMs, timeoutMessage) {
|
|
|
1226
1356
|
});
|
|
1227
1357
|
});
|
|
1228
1358
|
}
|
|
1229
|
-
function specFingerprint(spec) {
|
|
1230
|
-
|
|
1359
|
+
function specFingerprint(spec, secrets) {
|
|
1360
|
+
if (!secrets)
|
|
1361
|
+
return JSON.stringify(spec);
|
|
1362
|
+
const resolvedMarkers = {};
|
|
1363
|
+
const collect = (obj) => {
|
|
1364
|
+
if (!obj)
|
|
1365
|
+
return;
|
|
1366
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1367
|
+
if (value.startsWith("secret://") || value.startsWith("oauth://")) {
|
|
1368
|
+
try {
|
|
1369
|
+
resolvedMarkers[key] = secrets.resolveMaybeSecret(value);
|
|
1370
|
+
} catch {
|
|
1371
|
+
resolvedMarkers[key] = value;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
if (spec.transport === "stdio")
|
|
1377
|
+
collect(spec.env);
|
|
1378
|
+
if (spec.transport === "http")
|
|
1379
|
+
collect(spec.headers);
|
|
1380
|
+
return JSON.stringify({ spec, resolvedMarkers });
|
|
1231
1381
|
}
|
|
1382
|
+
var EXTRA_INHERITED_ENV = ["TMPDIR", "LANG"];
|
|
1232
1383
|
function resolveStdioEnv(spec, secrets) {
|
|
1233
1384
|
const env = getDefaultEnvironment();
|
|
1385
|
+
for (const key of EXTRA_INHERITED_ENV) {
|
|
1386
|
+
const value = process.env[key];
|
|
1387
|
+
if (value)
|
|
1388
|
+
env[key] = value;
|
|
1389
|
+
}
|
|
1390
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
1391
|
+
if (key.startsWith("LC_") && value)
|
|
1392
|
+
env[key] = value;
|
|
1393
|
+
}
|
|
1234
1394
|
env.PATH = buildEnrichedPath(env.PATH);
|
|
1235
1395
|
for (const [key, value] of Object.entries(spec.env ?? {})) {
|
|
1236
1396
|
env[key] = secrets.resolveMaybeSecret(value);
|
|
@@ -1440,7 +1600,11 @@ async function handleListTools(config, secrets, runtime, upstreamFilter, clientA
|
|
|
1440
1600
|
runtime.upstreamErrors?.set(upstream.name, { code, message: error instanceof Error ? error.message : String(error) });
|
|
1441
1601
|
}
|
|
1442
1602
|
}
|
|
1443
|
-
|
|
1603
|
+
const failedUpstreams = upstreams.filter((u) => runtime.upstreamErrors?.has(u.name)).map((u) => ({ name: u.name, ...runtime.upstreamErrors.get(u.name) }));
|
|
1604
|
+
return {
|
|
1605
|
+
tools,
|
|
1606
|
+
...failedUpstreams.length > 0 ? { _meta: { mcpxUpstreamErrors: failedUpstreams } } : {}
|
|
1607
|
+
};
|
|
1444
1608
|
}
|
|
1445
1609
|
async function handleListResources(config, secrets, runtime, upstreamFilter, clientAuthorizationHeader) {
|
|
1446
1610
|
const resources = [];
|
|
@@ -1476,7 +1640,11 @@ async function handleListResources(config, secrets, runtime, upstreamFilter, cli
|
|
|
1476
1640
|
runtime.upstreamErrors?.set(upstream.name, { code, message: error instanceof Error ? error.message : String(error) });
|
|
1477
1641
|
}
|
|
1478
1642
|
}
|
|
1479
|
-
|
|
1643
|
+
const failedUpstreams = upstreams.filter((u) => runtime.upstreamErrors?.has(u.name)).map((u) => ({ name: u.name, ...runtime.upstreamErrors.get(u.name) }));
|
|
1644
|
+
return {
|
|
1645
|
+
resources,
|
|
1646
|
+
...failedUpstreams.length > 0 ? { _meta: { mcpxUpstreamErrors: failedUpstreams } } : {}
|
|
1647
|
+
};
|
|
1480
1648
|
}
|
|
1481
1649
|
async function handleListPrompts(config, secrets, runtime, upstreamFilter, clientAuthorizationHeader) {
|
|
1482
1650
|
const prompts = [];
|
|
@@ -1510,7 +1678,11 @@ async function handleListPrompts(config, secrets, runtime, upstreamFilter, clien
|
|
|
1510
1678
|
runtime.upstreamErrors?.set(upstream.name, { code, message: error instanceof Error ? error.message : String(error) });
|
|
1511
1679
|
}
|
|
1512
1680
|
}
|
|
1513
|
-
|
|
1681
|
+
const failedUpstreams = upstreams.filter((u) => runtime.upstreamErrors?.has(u.name)).map((u) => ({ name: u.name, ...runtime.upstreamErrors.get(u.name) }));
|
|
1682
|
+
return {
|
|
1683
|
+
prompts,
|
|
1684
|
+
...failedUpstreams.length > 0 ? { _meta: { mcpxUpstreamErrors: failedUpstreams } } : {}
|
|
1685
|
+
};
|
|
1514
1686
|
}
|
|
1515
1687
|
async function routeNamespacedCall(config, method, params, id, secrets, runtime, upstreamFilter, clientAuthorizationHeader) {
|
|
1516
1688
|
if (!params || typeof params !== "object") {
|
|
@@ -1784,6 +1956,16 @@ function createGatewayServer(options) {
|
|
|
1784
1956
|
}
|
|
1785
1957
|
return;
|
|
1786
1958
|
}
|
|
1959
|
+
const wantsStream = (request.headers.accept ?? "").includes("text/event-stream");
|
|
1960
|
+
if (wantsStream && request.headers["mcp-session-id"]) {
|
|
1961
|
+
response.statusCode = 405;
|
|
1962
|
+
response.setHeader("content-type", "application/json");
|
|
1963
|
+
response.end(JSON.stringify({ error: "get_stream_not_supported", message: "mcpx does not support server-initiated SSE streams over GET; use POST for all requests." }));
|
|
1964
|
+
if (debug) {
|
|
1965
|
+
console.error(`[mcpx gateway] -> 405 (GET stream not supported)`);
|
|
1966
|
+
}
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1787
1969
|
response.statusCode = 200;
|
|
1788
1970
|
response.setHeader("content-type", "application/json");
|
|
1789
1971
|
response.end(JSON.stringify({ ok: true, server: "mcpx" }));
|
|
@@ -1923,19 +2105,24 @@ function createGatewayServer(options) {
|
|
|
1923
2105
|
}
|
|
1924
2106
|
|
|
1925
2107
|
// src/core/daemon.ts
|
|
1926
|
-
function
|
|
1927
|
-
if (!
|
|
2108
|
+
function readPidRecordFromFile(pidPath = getPidPath()) {
|
|
2109
|
+
if (!fs5.existsSync(pidPath)) {
|
|
1928
2110
|
return null;
|
|
1929
2111
|
}
|
|
1930
|
-
const raw =
|
|
2112
|
+
const raw = fs5.readFileSync(pidPath, "utf8").trim();
|
|
1931
2113
|
if (!raw) {
|
|
1932
2114
|
return null;
|
|
1933
2115
|
}
|
|
1934
|
-
const
|
|
2116
|
+
const [pidRaw, portRaw] = raw.split(":");
|
|
2117
|
+
const pid = Number(pidRaw);
|
|
1935
2118
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
1936
2119
|
return null;
|
|
1937
2120
|
}
|
|
1938
|
-
|
|
2121
|
+
const port = portRaw ? Number(portRaw) : null;
|
|
2122
|
+
return { pid, port: Number.isFinite(port) && port > 0 ? port : null };
|
|
2123
|
+
}
|
|
2124
|
+
function readPidFromFile(pidPath = getPidPath()) {
|
|
2125
|
+
return readPidRecordFromFile(pidPath)?.pid ?? null;
|
|
1939
2126
|
}
|
|
1940
2127
|
function processExists(pid) {
|
|
1941
2128
|
try {
|
|
@@ -1959,7 +2146,7 @@ async function isPortAvailable(port) {
|
|
|
1959
2146
|
}
|
|
1960
2147
|
async function resolveGatewayPort(config, secrets) {
|
|
1961
2148
|
if (await isPortAvailable(config.gateway.port)) {
|
|
1962
|
-
return config.gateway.port;
|
|
2149
|
+
return { port: config.gateway.port };
|
|
1963
2150
|
}
|
|
1964
2151
|
for (let offset = 1;offset <= 20; offset += 1) {
|
|
1965
2152
|
const candidate = config.gateway.port + offset;
|
|
@@ -1977,7 +2164,7 @@ async function resolveGatewayPort(config, secrets) {
|
|
|
1977
2164
|
saveConfig(config);
|
|
1978
2165
|
} catch {}
|
|
1979
2166
|
}
|
|
1980
|
-
return candidate;
|
|
2167
|
+
return { port: candidate, fellBackFrom: oldPort };
|
|
1981
2168
|
}
|
|
1982
2169
|
}
|
|
1983
2170
|
throw new Error(`No available local port found near ${config.gateway.port}.`);
|
|
@@ -2007,8 +2194,8 @@ async function waitForGatewayReady(port, token, timeoutMs = 5000) {
|
|
|
2007
2194
|
}
|
|
2008
2195
|
function getDaemonStatus(config) {
|
|
2009
2196
|
const pidPath = getPidPath();
|
|
2010
|
-
const
|
|
2011
|
-
if (!
|
|
2197
|
+
const record = readPidRecordFromFile(pidPath);
|
|
2198
|
+
if (!record) {
|
|
2012
2199
|
return {
|
|
2013
2200
|
running: false,
|
|
2014
2201
|
pidFile: pidPath,
|
|
@@ -2016,12 +2203,15 @@ function getDaemonStatus(config) {
|
|
|
2016
2203
|
port: config.gateway.port
|
|
2017
2204
|
};
|
|
2018
2205
|
}
|
|
2206
|
+
const running = processExists(record.pid);
|
|
2207
|
+
const port = record.port ?? config.gateway.port;
|
|
2019
2208
|
return {
|
|
2020
|
-
running
|
|
2021
|
-
pid,
|
|
2209
|
+
running,
|
|
2210
|
+
pid: record.pid,
|
|
2022
2211
|
pidFile: pidPath,
|
|
2023
2212
|
logFile: getLogPath(),
|
|
2024
|
-
port
|
|
2213
|
+
port,
|
|
2214
|
+
portMismatch: running && record.port !== null && record.port !== config.gateway.port
|
|
2025
2215
|
};
|
|
2026
2216
|
}
|
|
2027
2217
|
async function startDaemon(config, cliPath, secrets) {
|
|
@@ -2037,16 +2227,38 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
2037
2227
|
};
|
|
2038
2228
|
}
|
|
2039
2229
|
try {
|
|
2040
|
-
|
|
2230
|
+
fs5.unlinkSync(getPidPath());
|
|
2041
2231
|
} catch {}
|
|
2042
2232
|
}
|
|
2043
|
-
const port = await resolveGatewayPort(config, secrets);
|
|
2233
|
+
const { port, fellBackFrom } = await resolveGatewayPort(config, secrets);
|
|
2234
|
+
if (fellBackFrom) {
|
|
2235
|
+
process.stderr.write(`mcpx: port ${fellBackFrom} was unavailable; gateway started on ${port} instead. All client configs were re-synced to the new port.
|
|
2236
|
+
`);
|
|
2237
|
+
}
|
|
2044
2238
|
const token = ensureGatewayToken(config, secrets);
|
|
2045
2239
|
const pidPath = getPidPath();
|
|
2046
2240
|
const logPath = getLogPath();
|
|
2047
2241
|
ensureParentDir(pidPath);
|
|
2048
2242
|
ensureParentDir(logPath);
|
|
2049
|
-
|
|
2243
|
+
let logFd = fs5.openSync(logPath, "a", 384);
|
|
2244
|
+
const logStat = fs5.fstatSync(logFd);
|
|
2245
|
+
if (logStat.size > 10 * 1024 * 1024) {
|
|
2246
|
+
fs5.closeSync(logFd);
|
|
2247
|
+
const log1 = `${logPath}.1`;
|
|
2248
|
+
const log2 = `${logPath}.2`;
|
|
2249
|
+
try {
|
|
2250
|
+
if (fs5.existsSync(log2))
|
|
2251
|
+
fs5.unlinkSync(log2);
|
|
2252
|
+
} catch {}
|
|
2253
|
+
try {
|
|
2254
|
+
if (fs5.existsSync(log1))
|
|
2255
|
+
fs5.renameSync(log1, log2);
|
|
2256
|
+
} catch {}
|
|
2257
|
+
try {
|
|
2258
|
+
fs5.renameSync(logPath, log1);
|
|
2259
|
+
} catch {}
|
|
2260
|
+
logFd = fs5.openSync(logPath, "a", 384);
|
|
2261
|
+
}
|
|
2050
2262
|
const child = spawn2(process.execPath, [cliPath, "daemon", "run", "--port", String(port)], {
|
|
2051
2263
|
detached: true,
|
|
2052
2264
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -2056,7 +2268,7 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
2056
2268
|
}
|
|
2057
2269
|
});
|
|
2058
2270
|
child.unref();
|
|
2059
|
-
|
|
2271
|
+
fs5.writeFileSync(pidPath, `${child.pid}:${port}
|
|
2060
2272
|
`, { mode: 384 });
|
|
2061
2273
|
startBackgroundUpdateCheck();
|
|
2062
2274
|
await waitForGatewayReady(port, token);
|
|
@@ -2078,8 +2290,9 @@ function stopDaemon() {
|
|
|
2078
2290
|
}
|
|
2079
2291
|
try {
|
|
2080
2292
|
const cmd = execFileSync2("ps", ["-p", String(pid), "-o", "command="], { encoding: "utf8", timeout: 2000 }).trim();
|
|
2081
|
-
|
|
2082
|
-
|
|
2293
|
+
const looksLikeMcpxDaemon = cmd.includes("daemon run") && (cmd.includes("mcpx") || cmd.includes("cli.js"));
|
|
2294
|
+
if (!looksLikeMcpxDaemon) {
|
|
2295
|
+
fs5.unlinkSync(pidPath);
|
|
2083
2296
|
return {
|
|
2084
2297
|
stopped: false,
|
|
2085
2298
|
message: `PID ${pid} is not a mcpx daemon (command: ${cmd.slice(0, 80)}). Pidfile cleaned up.`
|
|
@@ -2087,7 +2300,7 @@ function stopDaemon() {
|
|
|
2087
2300
|
}
|
|
2088
2301
|
} catch {
|
|
2089
2302
|
try {
|
|
2090
|
-
|
|
2303
|
+
fs5.unlinkSync(pidPath);
|
|
2091
2304
|
} catch {}
|
|
2092
2305
|
return {
|
|
2093
2306
|
stopped: false,
|
|
@@ -2098,7 +2311,7 @@ function stopDaemon() {
|
|
|
2098
2311
|
process.kill(pid, "SIGTERM");
|
|
2099
2312
|
} catch {}
|
|
2100
2313
|
try {
|
|
2101
|
-
|
|
2314
|
+
fs5.unlinkSync(pidPath);
|
|
2102
2315
|
} catch {}
|
|
2103
2316
|
return {
|
|
2104
2317
|
stopped: true,
|
|
@@ -2111,10 +2324,10 @@ async function restartDaemon(config, cliPath, secrets) {
|
|
|
2111
2324
|
}
|
|
2112
2325
|
function readDaemonLogs(maxLines = 200) {
|
|
2113
2326
|
const logPath = getLogPath();
|
|
2114
|
-
if (!
|
|
2327
|
+
if (!fs5.existsSync(logPath)) {
|
|
2115
2328
|
return "";
|
|
2116
2329
|
}
|
|
2117
|
-
const lines =
|
|
2330
|
+
const lines = fs5.readFileSync(logPath, "utf8").split(`
|
|
2118
2331
|
`);
|
|
2119
2332
|
return lines.slice(Math.max(lines.length - maxLines, 0)).join(`
|
|
2120
2333
|
`);
|
|
@@ -2139,7 +2352,7 @@ function runDaemonForeground(config, port, secrets) {
|
|
|
2139
2352
|
}
|
|
2140
2353
|
|
|
2141
2354
|
// src/core/status.ts
|
|
2142
|
-
var STATUS_CLIENTS = ["claude", "claude-desktop", "codex", "cursor", "cline", "opencode", "kiro", "vscode", "qwen"];
|
|
2355
|
+
var STATUS_CLIENTS = ["claude", "claude-desktop", "codex", "cursor", "cline", "opencode", "kiro", "vscode", "qwen", "openclaw", "hermes"];
|
|
2143
2356
|
function describeServerTarget(spec) {
|
|
2144
2357
|
if (spec.transport === "http") {
|
|
2145
2358
|
return spec.url;
|
|
@@ -2192,15 +2405,15 @@ async function fetchTokenCounts(gatewayUrl, token) {
|
|
|
2192
2405
|
method: "custom/tokenCounts",
|
|
2193
2406
|
params: {}
|
|
2194
2407
|
}),
|
|
2195
|
-
signal: AbortSignal.timeout(
|
|
2408
|
+
signal: AbortSignal.timeout(65000)
|
|
2196
2409
|
});
|
|
2197
2410
|
if (!res.ok) {
|
|
2198
|
-
return {};
|
|
2411
|
+
return { counts: {}, fetchError: `HTTP ${res.status}` };
|
|
2199
2412
|
}
|
|
2200
2413
|
const data = await res.json();
|
|
2201
|
-
return data?.result ?? {};
|
|
2414
|
+
return { counts: data?.result ?? {} };
|
|
2202
2415
|
} catch (error) {
|
|
2203
|
-
return {};
|
|
2416
|
+
return { counts: {}, fetchError: error instanceof Error ? error.message : String(error) };
|
|
2204
2417
|
}
|
|
2205
2418
|
}
|
|
2206
2419
|
async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(config)) {
|
|
@@ -2208,8 +2421,11 @@ async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(
|
|
|
2208
2421
|
const token = ensureGatewayToken(config, secrets);
|
|
2209
2422
|
const gatewayUrl = getGatewayUrl(config);
|
|
2210
2423
|
let tokenCounts = {};
|
|
2424
|
+
let tokenCountFetchError;
|
|
2211
2425
|
if (daemon.running) {
|
|
2212
|
-
|
|
2426
|
+
const result = await fetchTokenCounts(gatewayUrl, token);
|
|
2427
|
+
tokenCounts = result.counts;
|
|
2428
|
+
tokenCountFetchError = result.fetchError;
|
|
2213
2429
|
}
|
|
2214
2430
|
const projectEntries = Object.values(config.projects ?? {});
|
|
2215
2431
|
let totalGlobalTokens = 0;
|
|
@@ -2254,4 +2470,4 @@ async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(
|
|
|
2254
2470
|
};
|
|
2255
2471
|
}
|
|
2256
2472
|
|
|
2257
|
-
export { probeHttpAuthRequirement, fetchRegistryServerDetail, selectBestPackage, extractRequiredInputs, mapRegistryToSpec, toSecretRef, secretRefName, defaultAuthSecretName, resolveAuthTarget, applyAuthReference, removeAuthReference, listAuthBindings, maybePrefixBearer, buildEnrichedPath, isOAuthReference, oauthReferenceServerName, runOAuthLogin, getOAuthAccessToken,
|
|
2473
|
+
export { mutateConfig, mutateProjectConfig, mutateActiveConfig, 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 };
|