@kwonye/mcpx 0.1.93 → 0.1.94
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/cline.d.ts.map +1 -1
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/kiro.d.ts.map +1 -1
- package/dist/adapters/opencode.d.ts.map +1 -1
- package/dist/adapters/utils/index.d.ts +11 -3
- package/dist/adapters/utils/index.d.ts.map +1 -1
- package/dist/{cli-y7ba5qvr.js → cli-154shqmt.js} +126 -68
- package/dist/{cli-qvkpwy9w.js → cli-9fmn9y72.js} +36 -17
- package/dist/{cli-np0wwh6m.js → cli-csfsg1yf.js} +78 -4
- package/dist/{cli-m2645syd.js → cli-mxmgxdm2.js} +127 -69
- package/dist/{cli-kwyp9ywh.js → cli-n8vt375e.js} +306 -172
- package/dist/{cli-8vxva0cb.js → cli-tk8bggg5.js} +81 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +45 -21
- package/dist/{config-2s5nsm2g.js → config-dtc3c79c.js} +6 -2
- package/dist/core/config-repair.d.ts.map +1 -1
- package/dist/core/config-store.d.ts +3 -0
- package/dist/core/config-store.d.ts.map +1 -0
- package/dist/core/config.d.ts +13 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/daemon.d.ts +1 -1
- package/dist/core/daemon.d.ts.map +1 -1
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +81 -6
- package/dist/core/oauth.d.ts.map +1 -1
- package/dist/core/plugin-manager.d.ts.map +1 -1
- package/dist/core/plugin-projections.d.ts +6 -2
- package/dist/core/plugin-projections.d.ts.map +1 -1
- package/dist/core/registry.d.ts +4 -1
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/secrets.d.ts.map +1 -1
- package/dist/core/server-auth.d.ts.map +1 -1
- package/dist/core/status.d.ts +1 -0
- package/dist/core/status.d.ts.map +1 -1
- package/dist/core/sync.d.ts +19 -2
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/gateway/server.d.ts +4 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/{plugin-manager-1sc4b6am.js → plugin-manager-1sjwfnah.js} +4 -4
- package/dist/{registry-mztfy0cz.js → registry-n12thgf2.js} +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cline.d.ts","sourceRoot":"","sources":["../../src/adapters/cline.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA2D1G,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAE/B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAWjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAmE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;
|
|
1
|
+
{"version":3,"file":"cline.d.ts","sourceRoot":"","sources":["../../src/adapters/cline.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA2D1G,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAE/B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAWjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAmE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CA2DzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoC7I,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAE/B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB;IAIzD,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IA+D9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoC7I,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAE/B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB;IAIzD,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IA+D9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CAyDzE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kiro.d.ts","sourceRoot":"","sources":["../../src/adapters/kiro.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqCpJ,qBAAa,WAAY,YAAW,aAAa;IAC/C,QAAQ,CAAC,EAAE,EAAG,MAAM,CAAU;IAE9B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB;IAIzD,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAgE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;
|
|
1
|
+
{"version":3,"file":"kiro.d.ts","sourceRoot":"","sources":["../../src/adapters/kiro.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqCpJ,qBAAa,WAAY,YAAW,aAAa;IAC/C,QAAQ,CAAC,EAAE,EAAG,MAAM,CAAU;IAE9B,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB;IAIzD,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAgE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;IAyDxE,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;CAyBlC"}
|
|
@@ -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,MAAM,aAAa,CAAC;AA+B1G,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,EAAE,EAAG,UAAU,CAAU;IAElC,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAuE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;
|
|
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,MAAM,aAAa,CAAC;AA+B1G,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,EAAE,EAAG,UAAU,CAAU;IAElC,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,YAAY,IAAI,OAAO;IAIvB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAuE9D,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;CAyDzE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientId, ClientImportScanResult, ClientImportSkippedEntry,
|
|
1
|
+
import type { ClientId, ClientImportScanResult, ClientImportSkippedEntry, ManagedIndex, SyncResult, UpstreamServerSpec } from "../../types.js";
|
|
2
2
|
export declare function getManagedEntryNames(managedIndex: ManagedIndex, clientId: ClientId): string[];
|
|
3
3
|
export declare function isManagedEntry(managedIndex: ManagedIndex, clientId: ClientId, entryName: string): boolean;
|
|
4
4
|
export declare function pruneStaleManagedEntries(managedIndex: ManagedIndex, clientId: ClientId, servers: Record<string, unknown>, keepEntryNames: string[]): void;
|
|
@@ -16,6 +16,14 @@ export declare function serverSpecsEqual(left: UpstreamServerSpec, right: Upstre
|
|
|
16
16
|
export declare function emptyImportScan(clientId: ClientId, configPath?: string): ClientImportScanResult;
|
|
17
17
|
export declare function buildImportSkip(clientId: ClientId, sourceEntryName: string, reason: string, configPath?: string, serverName?: string): ClientImportSkippedEntry;
|
|
18
18
|
export declare function removeSourceEntries(entries: Record<string, unknown>, names: string[] | undefined): void;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Purge managed entry names from the native disabledMcpServers array.
|
|
21
|
+
* Disabled managed servers are simply absent from the client config (no entry written).
|
|
22
|
+
*/
|
|
23
|
+
export declare function purgeManagedFromDisabledArray(raw: Record<string, unknown>, managedNames: string[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Purge managed entry names from the mcp.excluded array.
|
|
26
|
+
* Disabled managed servers are simply absent from the client config (no entry written).
|
|
27
|
+
*/
|
|
28
|
+
export declare function purgeManagedFromExcludedArray(raw: Record<string, unknown>, managedNames: string[]): void;
|
|
21
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,sBAAsB,EACtB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,sBAAsB,EACtB,wBAAwB,EAExB,YAAY,EACZ,UAAU,EACV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAGxB,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAE7F;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEzG;AAED,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,cAAc,EAAE,MAAM,EAAE,GACvB,IAAI,CAcN;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,OAAO,GACrB,MAAM,GAAG,IAAI,CAUf;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,IAAI,CAeN;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CAO7F;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAMjF;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAO3G;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAM7E;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErE;AAaD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,CAgBhF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAEpE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAE7F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,sBAAsB,CAO/F;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,SAAkB,GAC3B,wBAAwB,CAQ1B;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAIvG;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,YAAY,EAAE,MAAM,EAAE,GACrB,IAAI,CAMN;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,YAAY,EAAE,MAAM,EAAE,GACrB,IAAI,CAQN"}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getGatewayUrl,
|
|
3
|
+
persistSyncState,
|
|
3
4
|
syncAllClients
|
|
4
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-n8vt375e.js";
|
|
5
6
|
import {
|
|
6
7
|
loadConfig,
|
|
7
8
|
loadMergedConfig,
|
|
8
9
|
saveConfig
|
|
9
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-csfsg1yf.js";
|
|
10
11
|
import {
|
|
11
12
|
SecretsManager,
|
|
13
|
+
UpstreamError,
|
|
14
|
+
classifyUpstreamError,
|
|
12
15
|
ensureGatewayToken
|
|
13
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-tk8bggg5.js";
|
|
14
17
|
import {
|
|
15
18
|
ensureDir,
|
|
16
19
|
ensureParentDir,
|
|
@@ -344,6 +347,7 @@ function listAuthBindings(spec) {
|
|
|
344
347
|
value
|
|
345
348
|
}));
|
|
346
349
|
}
|
|
350
|
+
var TOKEN68 = /^[A-Za-z0-9\-._~+/]+=*$/;
|
|
347
351
|
function maybePrefixBearer(target, value, raw = false) {
|
|
348
352
|
if (raw || target.kind !== "header" || target.key.toLowerCase() !== "authorization") {
|
|
349
353
|
return value;
|
|
@@ -351,7 +355,10 @@ function maybePrefixBearer(target, value, raw = false) {
|
|
|
351
355
|
if (/^\S+\s+\S+/.test(value)) {
|
|
352
356
|
return value;
|
|
353
357
|
}
|
|
354
|
-
|
|
358
|
+
if (TOKEN68.test(value)) {
|
|
359
|
+
return `Bearer ${value}`;
|
|
360
|
+
}
|
|
361
|
+
return value;
|
|
355
362
|
}
|
|
356
363
|
|
|
357
364
|
// src/core/spawn-env.ts
|
|
@@ -605,7 +612,12 @@ function bindOAuthReference(config, serverName) {
|
|
|
605
612
|
};
|
|
606
613
|
}
|
|
607
614
|
async function runOAuthLogin(serverName, spec, secrets, openUrl, configPath, codeReceiver) {
|
|
608
|
-
|
|
615
|
+
const oauthName = oauthSecretName(serverName, "tokens");
|
|
616
|
+
const clientName = oauthSecretName(serverName, "client");
|
|
617
|
+
const backupTokens = secrets.getSecret(oauthName);
|
|
618
|
+
const backupClient = secrets.getSecret(clientName);
|
|
619
|
+
new McpxOAuthProvider(serverName, secrets).invalidateCredentials("verifier");
|
|
620
|
+
new McpxOAuthProvider(serverName, secrets).invalidateCredentials("discovery");
|
|
609
621
|
const state = crypto.randomUUID();
|
|
610
622
|
let callbackServer;
|
|
611
623
|
let redirectUrl;
|
|
@@ -638,8 +650,16 @@ async function runOAuthLogin(serverName, spec, secrets, openUrl, configPath, cod
|
|
|
638
650
|
const config = loadConfig(configPath);
|
|
639
651
|
bindOAuthReference(config, serverName);
|
|
640
652
|
saveConfig(config, configPath);
|
|
641
|
-
syncAllClients(config, secrets);
|
|
653
|
+
const summary = syncAllClients(config, secrets);
|
|
654
|
+
persistSyncState(summary, config);
|
|
655
|
+
saveConfig(config, configPath);
|
|
642
656
|
return { serverName, authorized: true };
|
|
657
|
+
} catch (error) {
|
|
658
|
+
if (backupTokens)
|
|
659
|
+
secrets.setSecret(oauthName, backupTokens);
|
|
660
|
+
if (backupClient)
|
|
661
|
+
secrets.setSecret(clientName, backupClient);
|
|
662
|
+
throw error;
|
|
643
663
|
} finally {
|
|
644
664
|
if (callbackServer) {
|
|
645
665
|
await closeServer(callbackServer);
|
|
@@ -649,32 +669,52 @@ async function runOAuthLogin(serverName, spec, secrets, openUrl, configPath, cod
|
|
|
649
669
|
async function getOAuthAccessToken(serverName, spec, secrets, options = {}) {
|
|
650
670
|
const stored = readJsonSecret(secrets, oauthSecretName(serverName, "tokens"));
|
|
651
671
|
if (!stored) {
|
|
652
|
-
throw new
|
|
653
|
-
}
|
|
654
|
-
if (!options.forceRefresh && !tokensAreExpiring(stored)) {
|
|
655
|
-
return stored.tokens.access_token;
|
|
672
|
+
throw new UpstreamError(serverName, "auth_required", `No OAuth tokens stored for "${serverName}".`);
|
|
656
673
|
}
|
|
657
|
-
if (
|
|
658
|
-
if (!
|
|
659
|
-
|
|
674
|
+
if (options.forceRefresh || tokensAreExpiring(stored)) {
|
|
675
|
+
if (!stored.tokens.refresh_token) {
|
|
676
|
+
if (!options.forceRefresh) {
|
|
677
|
+
return stored.tokens.access_token;
|
|
678
|
+
}
|
|
679
|
+
throw new UpstreamError(serverName, "auth_expired", `No refresh token for "${serverName}". Re-authentication required.`);
|
|
680
|
+
}
|
|
681
|
+
const provider = new McpxOAuthProvider(serverName, secrets);
|
|
682
|
+
const clientInformation = provider.clientInformation();
|
|
683
|
+
if (!clientInformation) {
|
|
684
|
+
throw new UpstreamError(serverName, "auth_expired", `No OAuth client info for "${serverName}". Re-authentication required.`);
|
|
685
|
+
}
|
|
686
|
+
let serverInfo;
|
|
687
|
+
try {
|
|
688
|
+
const cachedDiscovery = provider.discoveryState();
|
|
689
|
+
serverInfo = cachedDiscovery ?? await discoverOAuthServerInfo(spec.url);
|
|
690
|
+
} catch (err) {
|
|
691
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
692
|
+
if (/ECONNREFUSED|ENOTFOUND|EAI_AGAIN|fetch failed/i.test(message)) {
|
|
693
|
+
throw new UpstreamError(serverName, "unreachable", `OAuth discovery failed: ${message}`);
|
|
694
|
+
}
|
|
695
|
+
throw new UpstreamError(serverName, "upstream_error", `OAuth discovery failed: ${message}`);
|
|
696
|
+
}
|
|
697
|
+
try {
|
|
698
|
+
const refreshed = await refreshAuthorization(serverInfo.authorizationServerUrl, {
|
|
699
|
+
metadata: serverInfo.authorizationServerMetadata,
|
|
700
|
+
clientInformation,
|
|
701
|
+
refreshToken: stored.tokens.refresh_token,
|
|
702
|
+
resource: serverInfo.resourceMetadata?.resource ? new URL(serverInfo.resourceMetadata.resource) : undefined
|
|
703
|
+
});
|
|
704
|
+
provider.saveTokens(refreshed);
|
|
705
|
+
return refreshed.access_token;
|
|
706
|
+
} catch (err) {
|
|
707
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
708
|
+
if (/invalid_grant|invalid_client|4\d{2}/i.test(message)) {
|
|
709
|
+
throw new UpstreamError(serverName, "auth_expired", `OAuth refresh failed: ${message}`);
|
|
710
|
+
}
|
|
711
|
+
if (/ECONNREFUSED|ENOTFOUND|EAI_AGAIN|fetch failed/i.test(message)) {
|
|
712
|
+
throw new UpstreamError(serverName, "unreachable", `OAuth refresh failed: ${message}`);
|
|
713
|
+
}
|
|
714
|
+
throw new UpstreamError(serverName, "upstream_error", `OAuth refresh failed: ${message}`);
|
|
660
715
|
}
|
|
661
|
-
throw new Error(`No OAuth refresh token stored for "${serverName}". Re-authentication required.`);
|
|
662
|
-
}
|
|
663
|
-
const provider = new McpxOAuthProvider(serverName, secrets);
|
|
664
|
-
const clientInformation = provider.clientInformation();
|
|
665
|
-
if (!clientInformation) {
|
|
666
|
-
throw new Error(`No OAuth client information stored for "${serverName}". Re-authentication required.`);
|
|
667
716
|
}
|
|
668
|
-
|
|
669
|
-
const serverInfo = cachedDiscovery ?? await discoverOAuthServerInfo(spec.url);
|
|
670
|
-
const refreshed = await refreshAuthorization(serverInfo.authorizationServerUrl, {
|
|
671
|
-
metadata: serverInfo.authorizationServerMetadata,
|
|
672
|
-
clientInformation,
|
|
673
|
-
refreshToken: stored.tokens.refresh_token,
|
|
674
|
-
resource: serverInfo.resourceMetadata?.resource ? new URL(serverInfo.resourceMetadata.resource) : undefined
|
|
675
|
-
});
|
|
676
|
-
provider.saveTokens(refreshed);
|
|
677
|
-
return refreshed.access_token;
|
|
717
|
+
return stored.tokens.access_token;
|
|
678
718
|
}
|
|
679
719
|
|
|
680
720
|
// src/version.ts
|
|
@@ -944,7 +984,7 @@ function performRollback() {
|
|
|
944
984
|
// src/core/daemon.ts
|
|
945
985
|
import fs4 from "node:fs";
|
|
946
986
|
import net from "node:net";
|
|
947
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
987
|
+
import { spawn as spawn2, execFileSync as execFileSync2 } from "node:child_process";
|
|
948
988
|
|
|
949
989
|
// src/gateway/server.ts
|
|
950
990
|
import http2 from "node:http";
|
|
@@ -964,19 +1004,6 @@ var OAUTH_WELL_KNOWN_PREFIXES = [
|
|
|
964
1004
|
"/.well-known/oauth-authorization-server",
|
|
965
1005
|
"/.well-known/openid-configuration"
|
|
966
1006
|
];
|
|
967
|
-
|
|
968
|
-
class UpstreamHttpError extends Error {
|
|
969
|
-
status;
|
|
970
|
-
wwwAuthenticate;
|
|
971
|
-
bodyText;
|
|
972
|
-
constructor(upstreamName, status, bodyText, wwwAuthenticate) {
|
|
973
|
-
super(`Upstream ${upstreamName} returned HTTP ${status}: ${bodyText.slice(0, 400)}`);
|
|
974
|
-
this.name = "UpstreamHttpError";
|
|
975
|
-
this.status = status;
|
|
976
|
-
this.bodyText = bodyText;
|
|
977
|
-
this.wwwAuthenticate = wwwAuthenticate;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
1007
|
function makeError(id, code, message, data) {
|
|
981
1008
|
return {
|
|
982
1009
|
jsonrpc: "2.0",
|
|
@@ -1135,8 +1162,8 @@ async function getUpstreamTokenCounts(config, secrets, runtime) {
|
|
|
1135
1162
|
const fingerprint = specFingerprint(upstream.spec);
|
|
1136
1163
|
const cached = runtime.tokenCache.get(upstream.name);
|
|
1137
1164
|
if (cached?.fingerprint === fingerprint) {
|
|
1138
|
-
const
|
|
1139
|
-
results[upstream.name] =
|
|
1165
|
+
const runtimeErr2 = runtime.upstreamErrors?.get(upstream.name);
|
|
1166
|
+
results[upstream.name] = runtimeErr2 ? { ...cached.count, runtimeError: runtimeErr2.message, runtimeErrorCode: runtimeErr2.code } : cached.count;
|
|
1140
1167
|
continue;
|
|
1141
1168
|
}
|
|
1142
1169
|
let toolsCount = 0;
|
|
@@ -1178,8 +1205,8 @@ async function getUpstreamTokenCounts(config, secrets, runtime) {
|
|
|
1178
1205
|
if (errors.length === 0) {
|
|
1179
1206
|
runtime.tokenCache.set(upstream.name, { fingerprint, count: countObj });
|
|
1180
1207
|
}
|
|
1181
|
-
const
|
|
1182
|
-
results[upstream.name] =
|
|
1208
|
+
const runtimeErr = runtime.upstreamErrors?.get(upstream.name);
|
|
1209
|
+
results[upstream.name] = runtimeErr ? { ...countObj, runtimeError: runtimeErr.message, runtimeErrorCode: runtimeErr.code } : countObj;
|
|
1183
1210
|
}
|
|
1184
1211
|
return results;
|
|
1185
1212
|
}
|
|
@@ -1348,11 +1375,8 @@ async function callUpstreamOnce(upstream, method, params, secrets, runtime, pass
|
|
|
1348
1375
|
if (!forceOAuthRefresh && hasOAuth && error instanceof StreamableHTTPError && (error.code === 401 || error.code === 403)) {
|
|
1349
1376
|
return callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, true);
|
|
1350
1377
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
throw new UpstreamHttpError(upstream.name, error.code, error.message ?? "", wwwAuthenticate);
|
|
1354
|
-
}
|
|
1355
|
-
throw error;
|
|
1378
|
+
const wwwAuthenticate = runtime.lastWwwAuthenticate?.get(upstream.name);
|
|
1379
|
+
throw classifyUpstreamError(upstream.name, error, wwwAuthenticate);
|
|
1356
1380
|
}
|
|
1357
1381
|
}
|
|
1358
1382
|
function authHeaderIsValid(request, expectedToken) {
|
|
@@ -1371,7 +1395,7 @@ function authHeaderIsValid(request, expectedToken) {
|
|
|
1371
1395
|
return scheme === "Bearer" && token === expectedToken;
|
|
1372
1396
|
}
|
|
1373
1397
|
function isAuthChallenge(error) {
|
|
1374
|
-
return error instanceof
|
|
1398
|
+
return error instanceof UpstreamError && (error.code === "auth_required" || error.code === "auth_expired");
|
|
1375
1399
|
}
|
|
1376
1400
|
function getClientAuthorizationForUpstream(request, expectedToken) {
|
|
1377
1401
|
const authHeader = request.headers.authorization;
|
|
@@ -1412,7 +1436,8 @@ async function handleListTools(config, secrets, runtime, upstreamFilter, clientA
|
|
|
1412
1436
|
if (upstreams.length === 1) {
|
|
1413
1437
|
throw error;
|
|
1414
1438
|
}
|
|
1415
|
-
|
|
1439
|
+
const code = error instanceof UpstreamError ? error.code : "upstream_error";
|
|
1440
|
+
runtime.upstreamErrors?.set(upstream.name, { code, message: error instanceof Error ? error.message : String(error) });
|
|
1416
1441
|
}
|
|
1417
1442
|
}
|
|
1418
1443
|
return { tools };
|
|
@@ -1447,7 +1472,8 @@ async function handleListResources(config, secrets, runtime, upstreamFilter, cli
|
|
|
1447
1472
|
if (upstreams.length === 1) {
|
|
1448
1473
|
throw error;
|
|
1449
1474
|
}
|
|
1450
|
-
|
|
1475
|
+
const code = error instanceof UpstreamError ? error.code : "upstream_error";
|
|
1476
|
+
runtime.upstreamErrors?.set(upstream.name, { code, message: error instanceof Error ? error.message : String(error) });
|
|
1451
1477
|
}
|
|
1452
1478
|
}
|
|
1453
1479
|
return { resources };
|
|
@@ -1480,7 +1506,8 @@ async function handleListPrompts(config, secrets, runtime, upstreamFilter, clien
|
|
|
1480
1506
|
if (upstreams.length === 1) {
|
|
1481
1507
|
throw error;
|
|
1482
1508
|
}
|
|
1483
|
-
|
|
1509
|
+
const code = error instanceof UpstreamError ? error.code : "upstream_error";
|
|
1510
|
+
runtime.upstreamErrors?.set(upstream.name, { code, message: error instanceof Error ? error.message : String(error) });
|
|
1484
1511
|
}
|
|
1485
1512
|
}
|
|
1486
1513
|
return { prompts };
|
|
@@ -1521,8 +1548,9 @@ async function routeNamespacedCall(config, method, params, id, secrets, runtime,
|
|
|
1521
1548
|
if (isAuthChallenge(error)) {
|
|
1522
1549
|
throw error;
|
|
1523
1550
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1551
|
+
const errCode = error instanceof UpstreamError ? error.code : "upstream_error";
|
|
1552
|
+
runtime.upstreamErrors?.set(upstream2.name, { code: errCode, message: error.message });
|
|
1553
|
+
return makeError(id, -32000, error.message, { mcpxCode: errCode, upstream: upstream2.name });
|
|
1526
1554
|
}
|
|
1527
1555
|
}
|
|
1528
1556
|
if (method === "prompts/get") {
|
|
@@ -1554,8 +1582,9 @@ async function routeNamespacedCall(config, method, params, id, secrets, runtime,
|
|
|
1554
1582
|
if (isAuthChallenge(error)) {
|
|
1555
1583
|
throw error;
|
|
1556
1584
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1585
|
+
const errCode = error instanceof UpstreamError ? error.code : "upstream_error";
|
|
1586
|
+
runtime.upstreamErrors?.set(upstream2.name, { code: errCode, message: error.message });
|
|
1587
|
+
return makeError(id, -32000, error.message, { mcpxCode: errCode, upstream: upstream2.name });
|
|
1559
1588
|
}
|
|
1560
1589
|
}
|
|
1561
1590
|
const uri = typeof params.uri === "string" ? params.uri : "";
|
|
@@ -1586,8 +1615,9 @@ async function routeNamespacedCall(config, method, params, id, secrets, runtime,
|
|
|
1586
1615
|
if (isAuthChallenge(error)) {
|
|
1587
1616
|
throw error;
|
|
1588
1617
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1618
|
+
const errCode = error instanceof UpstreamError ? error.code : "upstream_error";
|
|
1619
|
+
runtime.upstreamErrors?.set(upstream.name, { code: errCode, message: error.message });
|
|
1620
|
+
return makeError(id, -32000, error.message, { mcpxCode: errCode, upstream: upstream.name });
|
|
1591
1621
|
}
|
|
1592
1622
|
}
|
|
1593
1623
|
async function handleRequestObject(request, secrets, runtime, upstreamFilter, clientAuthorizationHeader) {
|
|
@@ -1858,16 +1888,16 @@ function createGatewayServer(options) {
|
|
|
1858
1888
|
}
|
|
1859
1889
|
} catch (error) {
|
|
1860
1890
|
if (isAuthChallenge(error)) {
|
|
1861
|
-
response.statusCode = error.status;
|
|
1891
|
+
response.statusCode = error.status ?? 401;
|
|
1862
1892
|
response.setHeader("content-type", "application/json");
|
|
1863
1893
|
if (error.wwwAuthenticate) {
|
|
1864
1894
|
const localResourceMetadataUrl = appendUpstreamQuery(`${getLocalOriginFromRequest(request)}/.well-known/oauth-protected-resource`, getRequestedUpstream(requestUrl));
|
|
1865
1895
|
response.setHeader("www-authenticate", rewriteWwwAuthenticateResourceMetadata(error.wwwAuthenticate, localResourceMetadataUrl));
|
|
1866
1896
|
}
|
|
1867
1897
|
response.end(JSON.stringify(makeError(null, -32001, "Upstream authentication required.", {
|
|
1898
|
+
mcpxCode: error.code,
|
|
1868
1899
|
status: error.status,
|
|
1869
|
-
|
|
1870
|
-
wwwAuthenticate: error.wwwAuthenticate
|
|
1900
|
+
upstream: error.upstream
|
|
1871
1901
|
})));
|
|
1872
1902
|
if (debug) {
|
|
1873
1903
|
console.error(`[mcpx gateway] -> ${error.status} upstream auth challenge`);
|
|
@@ -1927,7 +1957,7 @@ async function isPortAvailable(port) {
|
|
|
1927
1957
|
tester.listen(port, "127.0.0.1");
|
|
1928
1958
|
});
|
|
1929
1959
|
}
|
|
1930
|
-
async function resolveGatewayPort(config) {
|
|
1960
|
+
async function resolveGatewayPort(config, secrets) {
|
|
1931
1961
|
if (await isPortAvailable(config.gateway.port)) {
|
|
1932
1962
|
return config.gateway.port;
|
|
1933
1963
|
}
|
|
@@ -1937,8 +1967,16 @@ async function resolveGatewayPort(config) {
|
|
|
1937
1967
|
break;
|
|
1938
1968
|
}
|
|
1939
1969
|
if (await isPortAvailable(candidate)) {
|
|
1970
|
+
const oldPort = config.gateway.port;
|
|
1940
1971
|
config.gateway.port = candidate;
|
|
1941
1972
|
saveConfig(config);
|
|
1973
|
+
if (secrets) {
|
|
1974
|
+
try {
|
|
1975
|
+
const summary = syncAllClients(config, secrets);
|
|
1976
|
+
persistSyncState(summary, config);
|
|
1977
|
+
saveConfig(config);
|
|
1978
|
+
} catch {}
|
|
1979
|
+
}
|
|
1942
1980
|
return candidate;
|
|
1943
1981
|
}
|
|
1944
1982
|
}
|
|
@@ -2002,7 +2040,7 @@ async function startDaemon(config, cliPath, secrets) {
|
|
|
2002
2040
|
fs4.unlinkSync(getPidPath());
|
|
2003
2041
|
} catch {}
|
|
2004
2042
|
}
|
|
2005
|
-
const port = await resolveGatewayPort(config);
|
|
2043
|
+
const port = await resolveGatewayPort(config, secrets);
|
|
2006
2044
|
const token = ensureGatewayToken(config, secrets);
|
|
2007
2045
|
const pidPath = getPidPath();
|
|
2008
2046
|
const logPath = getLogPath();
|
|
@@ -2038,6 +2076,24 @@ function stopDaemon() {
|
|
|
2038
2076
|
message: "mcpx daemon is not running."
|
|
2039
2077
|
};
|
|
2040
2078
|
}
|
|
2079
|
+
try {
|
|
2080
|
+
const cmd = execFileSync2("ps", ["-p", String(pid), "-o", "command="], { encoding: "utf8", timeout: 2000 }).trim();
|
|
2081
|
+
if (!cmd.includes("mcpx") && !cmd.includes("daemon") && !cmd.includes("cli.js")) {
|
|
2082
|
+
fs4.unlinkSync(pidPath);
|
|
2083
|
+
return {
|
|
2084
|
+
stopped: false,
|
|
2085
|
+
message: `PID ${pid} is not a mcpx daemon (command: ${cmd.slice(0, 80)}). Pidfile cleaned up.`
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
} catch {
|
|
2089
|
+
try {
|
|
2090
|
+
fs4.unlinkSync(pidPath);
|
|
2091
|
+
} catch {}
|
|
2092
|
+
return {
|
|
2093
|
+
stopped: false,
|
|
2094
|
+
message: `PID ${pid} not found. Pidfile cleaned up.`
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2041
2097
|
try {
|
|
2042
2098
|
process.kill(pid, "SIGTERM");
|
|
2043
2099
|
} catch {}
|
|
@@ -2165,6 +2221,7 @@ async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(
|
|
|
2165
2221
|
if (tokenCount?.error && buildAuthBindings(spec).length > 0 && tokenCount.total > 0) {
|
|
2166
2222
|
tokenCount = { ...tokenCount, error: undefined };
|
|
2167
2223
|
}
|
|
2224
|
+
const health = tokenCount ? tokenCount.error || tokenCount.runtimeError ? "error" : "ok" : "unknown";
|
|
2168
2225
|
const serverEntry = {
|
|
2169
2226
|
name,
|
|
2170
2227
|
enabled: isServerEnabled(spec),
|
|
@@ -2172,7 +2229,8 @@ async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(
|
|
|
2172
2229
|
target: describeServerTarget(spec),
|
|
2173
2230
|
authBindings: buildAuthBindings(spec),
|
|
2174
2231
|
clients: buildClientMappings(config, managedIndex, name),
|
|
2175
|
-
tokenCount
|
|
2232
|
+
tokenCount,
|
|
2233
|
+
health
|
|
2176
2234
|
};
|
|
2177
2235
|
if (serverEntry.enabled && tokenCount) {
|
|
2178
2236
|
totalGlobalTokens += tokenCount.total;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
persistSyncState,
|
|
2
3
|
syncAllClients
|
|
3
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-n8vt375e.js";
|
|
4
5
|
import {
|
|
5
6
|
loadConfig,
|
|
6
|
-
loadMergedConfig,
|
|
7
7
|
saveConfig
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-csfsg1yf.js";
|
|
9
9
|
import {
|
|
10
10
|
SecretsManager
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-tk8bggg5.js";
|
|
12
12
|
import {
|
|
13
13
|
ensureDir,
|
|
14
14
|
getConfigPath,
|
|
@@ -691,11 +691,18 @@ class PluginManager {
|
|
|
691
691
|
if (config.plugins[pluginId]) {
|
|
692
692
|
throw new Error(`Plugin ${pluginId} is already installed`);
|
|
693
693
|
}
|
|
694
|
+
const serverNames = info.components.mcpServers.map((s) => `${pluginName}__${s.id}`);
|
|
695
|
+
for (const existing of Object.values(config.plugins)) {
|
|
696
|
+
for (const sn of serverNames) {
|
|
697
|
+
if (existing.serverNames.includes(sn)) {
|
|
698
|
+
throw new Error(`Server name collision: "${sn}" is already claimed by plugin "${existing.name}". Use --name to specify a different plugin name.`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
694
702
|
const dataDir = path5.join(getPluginDataRoot(), pluginId);
|
|
695
703
|
ensureDir(dataDir);
|
|
696
704
|
const enabled = options?.enabled ?? true;
|
|
697
705
|
const discovered = info.components;
|
|
698
|
-
const serverNames = discovered.mcpServers.map((s) => `${pluginName}__${s.id}`);
|
|
699
706
|
const plugin = {
|
|
700
707
|
id: pluginId,
|
|
701
708
|
name: pluginName,
|
|
@@ -736,8 +743,10 @@ class PluginManager {
|
|
|
736
743
|
}
|
|
737
744
|
saveConfig(config, this.configPath);
|
|
738
745
|
this.lifecycle.initData(pluginId);
|
|
739
|
-
const
|
|
740
|
-
syncAllClients(
|
|
746
|
+
const syncConfig = loadConfig(this.configPath);
|
|
747
|
+
const summary = syncAllClients(syncConfig, this.secrets);
|
|
748
|
+
persistSyncState(summary, syncConfig);
|
|
749
|
+
saveConfig(syncConfig, this.configPath);
|
|
741
750
|
return plugin;
|
|
742
751
|
}
|
|
743
752
|
async updatePlugin(pluginId) {
|
|
@@ -772,8 +781,10 @@ class PluginManager {
|
|
|
772
781
|
current.approvals = {};
|
|
773
782
|
config.plugins[pluginId] = current;
|
|
774
783
|
saveConfig(config, this.configPath);
|
|
775
|
-
const
|
|
776
|
-
syncAllClients(
|
|
784
|
+
const syncConfig = loadConfig(this.configPath);
|
|
785
|
+
const summary = syncAllClients(syncConfig, this.secrets);
|
|
786
|
+
persistSyncState(summary, syncConfig);
|
|
787
|
+
saveConfig(syncConfig, this.configPath);
|
|
777
788
|
return current;
|
|
778
789
|
}
|
|
779
790
|
async uninstallPlugin(pluginId, keepData = false) {
|
|
@@ -791,8 +802,10 @@ class PluginManager {
|
|
|
791
802
|
if (!keepData) {
|
|
792
803
|
await this.lifecycle.removeData(pluginId);
|
|
793
804
|
}
|
|
794
|
-
const
|
|
795
|
-
syncAllClients(
|
|
805
|
+
const syncConfig = loadConfig(this.configPath);
|
|
806
|
+
const summary = syncAllClients(syncConfig, this.secrets);
|
|
807
|
+
persistSyncState(summary, syncConfig);
|
|
808
|
+
saveConfig(syncConfig, this.configPath);
|
|
796
809
|
}
|
|
797
810
|
async enablePlugin(pluginId) {
|
|
798
811
|
const config = loadConfig(this.configPath);
|
|
@@ -803,8 +816,10 @@ class PluginManager {
|
|
|
803
816
|
throw new Error(`Plugin ${pluginId} not found`);
|
|
804
817
|
plugin.enabled = true;
|
|
805
818
|
saveConfig(config, this.configPath);
|
|
806
|
-
const
|
|
807
|
-
syncAllClients(
|
|
819
|
+
const syncConfig = loadConfig(this.configPath);
|
|
820
|
+
const summary = syncAllClients(syncConfig, this.secrets);
|
|
821
|
+
persistSyncState(summary, syncConfig);
|
|
822
|
+
saveConfig(syncConfig, this.configPath);
|
|
808
823
|
}
|
|
809
824
|
async disablePlugin(pluginId) {
|
|
810
825
|
const config = loadConfig(this.configPath);
|
|
@@ -815,8 +830,10 @@ class PluginManager {
|
|
|
815
830
|
throw new Error(`Plugin ${pluginId} not found`);
|
|
816
831
|
plugin.enabled = false;
|
|
817
832
|
saveConfig(config, this.configPath);
|
|
818
|
-
const
|
|
819
|
-
syncAllClients(
|
|
833
|
+
const syncConfig = loadConfig(this.configPath);
|
|
834
|
+
const summary = syncAllClients(syncConfig, this.secrets);
|
|
835
|
+
persistSyncState(summary, syncConfig);
|
|
836
|
+
saveConfig(syncConfig, this.configPath);
|
|
820
837
|
}
|
|
821
838
|
async approveComponent(pluginId, component) {
|
|
822
839
|
const config = loadConfig(this.configPath);
|
|
@@ -836,8 +853,10 @@ class PluginManager {
|
|
|
836
853
|
}
|
|
837
854
|
}
|
|
838
855
|
saveConfig(config, this.configPath);
|
|
839
|
-
const
|
|
840
|
-
syncAllClients(
|
|
856
|
+
const syncConfig = loadConfig(this.configPath);
|
|
857
|
+
const summary = syncAllClients(syncConfig, this.secrets);
|
|
858
|
+
persistSyncState(summary, syncConfig);
|
|
859
|
+
saveConfig(syncConfig, this.configPath);
|
|
841
860
|
}
|
|
842
861
|
async getPluginStatus(pluginId) {
|
|
843
862
|
const config = loadConfig(this.configPath);
|