@kwonye/mcpx 0.1.104 → 0.1.106
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/codex.d.ts +2 -0
- package/dist/adapters/index.d.ts +2 -1
- package/dist/adapters/json.d.ts +26 -0
- package/dist/adapters/pi.d.ts +9 -0
- package/dist/chunk-0xt563m1.js +126 -0
- package/dist/{chunk-s9v1epnk.js → chunk-1mrkz29t.js} +71 -56
- package/dist/{chunk-31brdz5s.js → chunk-1v66g9d6.js} +4 -3
- package/dist/chunk-1yq3yb66.js +126 -0
- package/dist/chunk-27mq4agf.js +33 -0
- package/dist/{chunk-941dqsx2.js → chunk-4aafp444.js} +8175 -8066
- package/dist/chunk-4xym942z.js +36 -0
- package/dist/{chunk-tnhekcpv.js → chunk-56z18csx.js} +1 -1
- package/dist/{chunk-bnbz55g6.js → chunk-65kshh9w.js} +1 -1
- package/dist/{chunk-xydajvzg.js → chunk-7ky3rsw9.js} +1 -1
- package/dist/chunk-7rq88hb3.js +563 -0
- package/dist/chunk-8v13hqrp.js +825 -0
- package/dist/chunk-a2gen8bn.js +730 -0
- package/dist/{chunk-wq4zd3t7.js → chunk-brxwa30j.js} +130 -111
- package/dist/chunk-chaj8a8b.js +45 -0
- package/dist/chunk-e96643mj.js +26 -0
- package/dist/{chunk-02r7k4ax.js → chunk-ew06e41w.js} +12 -6
- package/dist/chunk-ezk8txcy.js +23 -0
- package/dist/{chunk-cqenqnxk.js → chunk-grkz21sq.js} +35 -3
- package/dist/{chunk-12vgqm89.js → chunk-gvjxpk98.js} +1 -1
- package/dist/chunk-h9kp47rp.js +18 -0
- package/dist/chunk-hahs24dv.js +127 -0
- package/dist/{chunk-z34m83m4.js → chunk-jv0s0cp6.js} +5 -3
- package/dist/{chunk-enzmq965.js → chunk-n0462d52.js} +1 -1
- package/dist/chunk-nh6hhv29.js +138 -0
- package/dist/chunk-p7yzyt87.js +19426 -0
- package/dist/chunk-q86c5s6r.js +7 -0
- package/dist/chunk-qf8bj9y7.js +254 -0
- package/dist/chunk-t20f49g3.js +30 -0
- package/dist/{chunk-b58zsdp4.js → chunk-v041118a.js} +17 -5
- package/dist/{chunk-91vcwk5m.js → chunk-v14bg5yp.js} +1 -1
- package/dist/chunk-wvzap0na.js +18166 -0
- package/dist/chunk-wztmp5b4.js +30479 -0
- package/dist/chunk-xvqr1q9b.js +14 -0
- package/dist/{chunk-0xhdyt4z.js → chunk-yj7mpczw.js} +17 -5
- package/dist/chunk-yr0txkw0.js +31 -0
- package/dist/cli.js +3977 -1045
- package/dist/core/adoption.d.ts +62 -0
- package/dist/core/analytics.d.ts +17 -0
- package/dist/core/consumers.d.ts +8 -0
- package/dist/core/control.d.ts +12 -0
- package/dist/core/daemon.d.ts +2 -2
- package/dist/core/file-state.d.ts +5 -0
- package/dist/core/harnesses.d.ts +25 -0
- package/dist/core/index.d.ts +17 -7
- package/dist/core/index.js +128 -62
- package/dist/core/managed-index-lock.d.ts +1 -1
- package/dist/core/management.d.ts +32 -0
- package/dist/core/native-document.d.ts +4 -0
- package/dist/core/operations.d.ts +52 -0
- package/dist/core/paths.d.ts +2 -0
- package/dist/core/plugin-manager.d.ts +4 -1
- package/dist/core/plugin-projections.d.ts +1 -0
- package/dist/core/runtime-entry.d.ts +6 -0
- package/dist/core/runtime-snapshot.d.ts +6 -0
- package/dist/core/secret-keychain.d.ts +31 -0
- package/dist/core/secrets.d.ts +12 -2
- package/dist/core/served-skills.d.ts +62 -0
- package/dist/core/share.d.ts +71 -0
- package/dist/core/skills.d.ts +7 -0
- package/dist/core/status.d.ts +1 -0
- package/dist/core/sync-plan.d.ts +14 -0
- package/dist/core/sync.d.ts +3 -0
- package/dist/core/telemetry.d.ts +2 -2
- package/dist/core/tui.d.ts +20 -0
- package/dist/core/verify-upstreams.d.ts +4 -0
- package/dist/core/work-limiter.d.ts +10 -0
- package/dist/gateway/server.d.ts +2 -0
- package/dist/types.d.ts +72 -1
- package/dist/util/fs.d.ts +2 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/adapters/opencode.d.ts +0 -11
- package/dist/chunk-cz8cdmw1.js +0 -344
- package/dist/chunk-z1k63fa3.js +0 -3760
package/dist/chunk-cz8cdmw1.js
DELETED
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ensureParentDir,
|
|
3
|
-
getGatewayTokenPath,
|
|
4
|
-
getSecretsKeyPath,
|
|
5
|
-
getSecretsStorePath,
|
|
6
|
-
readJsonFile,
|
|
7
|
-
writeJsonAtomic
|
|
8
|
-
} from "./chunk-cqenqnxk.js";
|
|
9
|
-
import {
|
|
10
|
-
isServerEnabled,
|
|
11
|
-
normalizeServerSpecEnabled
|
|
12
|
-
} from "./chunk-bjw71y54.js";
|
|
13
|
-
|
|
14
|
-
// src/core/registry.ts
|
|
15
|
-
import crypto from "node:crypto";
|
|
16
|
-
import fs from "node:fs";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
function validateServerName(name) {
|
|
19
|
-
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,62}$/.test(name)) {
|
|
20
|
-
throw new Error("Invalid server name. Use 1-63 chars: letters, numbers, '.', '-', '_' and start with alphanumeric.");
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function addServer(config, name, spec, force = false) {
|
|
24
|
-
validateServerName(name);
|
|
25
|
-
if (config.servers[name] && !force) {
|
|
26
|
-
throw new Error(`Server "${name}" already exists. Use --force to overwrite.`);
|
|
27
|
-
}
|
|
28
|
-
config.servers[name] = normalizeServerSpecEnabled(spec);
|
|
29
|
-
}
|
|
30
|
-
function removeServer(config, name, force = false) {
|
|
31
|
-
if (!config.servers[name] && !force) {
|
|
32
|
-
throw new Error(`Server "${name}" does not exist.`);
|
|
33
|
-
}
|
|
34
|
-
delete config.servers[name];
|
|
35
|
-
if (config.projects) {
|
|
36
|
-
for (const project of Object.values(config.projects)) {
|
|
37
|
-
if (project.disabledServers) {
|
|
38
|
-
project.disabledServers = project.disabledServers.filter((s) => s !== name);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function updateServer(config, name, spec) {
|
|
44
|
-
validateServerName(name);
|
|
45
|
-
if (!config.servers[name]) {
|
|
46
|
-
throw new Error(`Server "${name}" does not exist.`);
|
|
47
|
-
}
|
|
48
|
-
config.servers[name] = normalizeServerSpecEnabled(spec);
|
|
49
|
-
}
|
|
50
|
-
function setServerEnabled(config, name, enabled) {
|
|
51
|
-
const existing = config.servers[name];
|
|
52
|
-
if (!existing) {
|
|
53
|
-
throw new Error(`Server "${name}" does not exist.`);
|
|
54
|
-
}
|
|
55
|
-
config.servers[name] = {
|
|
56
|
-
...existing,
|
|
57
|
-
enabled
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function getGatewayTokenSecretName(config) {
|
|
61
|
-
if (!config.gateway.tokenRef.startsWith("secret://")) {
|
|
62
|
-
return "local_gateway_token";
|
|
63
|
-
}
|
|
64
|
-
return config.gateway.tokenRef.slice("secret://".length) || "local_gateway_token";
|
|
65
|
-
}
|
|
66
|
-
function ensureGatewayToken(config, secrets) {
|
|
67
|
-
const secretName = getGatewayTokenSecretName(config);
|
|
68
|
-
const tokenPath = getGatewayTokenPath(secretName);
|
|
69
|
-
const envValue = process.env[`MCPX_SECRET_${secretName}`];
|
|
70
|
-
if (envValue && envValue.length > 0) {
|
|
71
|
-
return envValue;
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
const fileValue = fs.readFileSync(tokenPath, "utf8").trim();
|
|
75
|
-
if (fileValue) {
|
|
76
|
-
return fileValue;
|
|
77
|
-
}
|
|
78
|
-
} catch {}
|
|
79
|
-
const storeValue = secrets.getSecret(secretName);
|
|
80
|
-
if (storeValue) {
|
|
81
|
-
ensureParentDir(tokenPath);
|
|
82
|
-
fs.writeFileSync(tokenPath, storeValue, { mode: 384 });
|
|
83
|
-
return storeValue;
|
|
84
|
-
}
|
|
85
|
-
const token = crypto.randomBytes(32).toString("base64url");
|
|
86
|
-
ensureParentDir(tokenPath);
|
|
87
|
-
fs.writeFileSync(tokenPath, token, { mode: 384 });
|
|
88
|
-
return token;
|
|
89
|
-
}
|
|
90
|
-
function rotateGatewayToken(config, secrets) {
|
|
91
|
-
const secretName = getGatewayTokenSecretName(config);
|
|
92
|
-
const token = crypto.randomBytes(32).toString("base64url");
|
|
93
|
-
const tokenPath = getGatewayTokenPath(secretName);
|
|
94
|
-
ensureParentDir(tokenPath);
|
|
95
|
-
fs.writeFileSync(tokenPath, token, { mode: 384 });
|
|
96
|
-
secrets.removeSecret(secretName);
|
|
97
|
-
return token;
|
|
98
|
-
}
|
|
99
|
-
function registerProject(globalConfig, projectPath, name) {
|
|
100
|
-
if (!globalConfig.projects) {
|
|
101
|
-
globalConfig.projects = {};
|
|
102
|
-
}
|
|
103
|
-
const resolvedPath = path.resolve(projectPath);
|
|
104
|
-
const projectName = name?.trim() || path.basename(resolvedPath);
|
|
105
|
-
const existing = globalConfig.projects[resolvedPath];
|
|
106
|
-
globalConfig.projects[resolvedPath] = {
|
|
107
|
-
name: projectName,
|
|
108
|
-
path: resolvedPath,
|
|
109
|
-
disabledServers: existing?.disabledServers ?? []
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
function unregisterProject(globalConfig, projectPath) {
|
|
113
|
-
if (globalConfig.projects) {
|
|
114
|
-
delete globalConfig.projects[path.resolve(projectPath)];
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
function setProjectServerEnabled(globalConfig, projectPath, serverName, enabled) {
|
|
118
|
-
if (!globalConfig.projects)
|
|
119
|
-
globalConfig.projects = {};
|
|
120
|
-
const resolvedPath = path.resolve(projectPath);
|
|
121
|
-
const project = globalConfig.projects[resolvedPath];
|
|
122
|
-
if (!project) {
|
|
123
|
-
throw new Error(`Project "${resolvedPath}" is not registered.`);
|
|
124
|
-
}
|
|
125
|
-
const serverSpec = globalConfig.servers[serverName];
|
|
126
|
-
if (!serverSpec) {
|
|
127
|
-
throw new Error(`Server "${serverName}" does not exist.`);
|
|
128
|
-
}
|
|
129
|
-
if (!project.disabledServers) {
|
|
130
|
-
project.disabledServers = [];
|
|
131
|
-
}
|
|
132
|
-
if (enabled) {
|
|
133
|
-
project.disabledServers = project.disabledServers.filter((s) => s !== serverName);
|
|
134
|
-
if (!isServerEnabled(serverSpec)) {
|
|
135
|
-
return { effective: false, reason: "globally_disabled" };
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
if (!project.disabledServers.includes(serverName)) {
|
|
139
|
-
project.disabledServers.push(serverName);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return { effective: true };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// src/core/errors.ts
|
|
146
|
-
class UpstreamError extends Error {
|
|
147
|
-
code;
|
|
148
|
-
upstream;
|
|
149
|
-
status;
|
|
150
|
-
wwwAuthenticate;
|
|
151
|
-
constructor(upstream, code, message, options) {
|
|
152
|
-
super(message);
|
|
153
|
-
this.name = "UpstreamError";
|
|
154
|
-
this.code = code;
|
|
155
|
-
this.upstream = upstream;
|
|
156
|
-
this.status = options?.status;
|
|
157
|
-
this.wwwAuthenticate = options?.wwwAuthenticate;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
class SecretNotFoundError extends Error {
|
|
162
|
-
code = "secret_missing";
|
|
163
|
-
secretName;
|
|
164
|
-
constructor(secretName) {
|
|
165
|
-
super(`Secret not found: ${secretName}. Run: mcpx secret set ${secretName}`);
|
|
166
|
-
this.name = "SecretNotFoundError";
|
|
167
|
-
this.secretName = secretName;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
var TIMEOUT_RE = /timed out after \d+ms/;
|
|
171
|
-
var UNREACHABLE_PATTERNS = [
|
|
172
|
-
/fetch failed/i,
|
|
173
|
-
/ECONNREFUSED/,
|
|
174
|
-
/ENOTFOUND/,
|
|
175
|
-
/EAI_AGAIN/,
|
|
176
|
-
/socket hang up/,
|
|
177
|
-
/ENOENT/,
|
|
178
|
-
/connect econnrefused/i,
|
|
179
|
-
/unable to connect/i
|
|
180
|
-
];
|
|
181
|
-
var UNREACHABLE_ERROR_CODES = new Set(["ConnectionRefused"]);
|
|
182
|
-
function classifyUpstreamError(upstream, error, wwwAuthenticate) {
|
|
183
|
-
if (error instanceof UpstreamError)
|
|
184
|
-
return error;
|
|
185
|
-
if (error instanceof SecretNotFoundError) {
|
|
186
|
-
return new UpstreamError(upstream, "secret_missing", error.message);
|
|
187
|
-
}
|
|
188
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
189
|
-
const maybeHttpError = error;
|
|
190
|
-
const httpStatus = maybeHttpError?.status ?? (typeof maybeHttpError?.code === "number" ? maybeHttpError.code : undefined);
|
|
191
|
-
if (httpStatus === 401 || httpStatus === 403) {
|
|
192
|
-
return new UpstreamError(upstream, "auth_required", message, {
|
|
193
|
-
status: httpStatus,
|
|
194
|
-
wwwAuthenticate
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
if (TIMEOUT_RE.test(message)) {
|
|
198
|
-
return new UpstreamError(upstream, "timeout", message);
|
|
199
|
-
}
|
|
200
|
-
if (typeof maybeHttpError?.code === "string" && UNREACHABLE_ERROR_CODES.has(maybeHttpError.code) || UNREACHABLE_PATTERNS.some((p) => p.test(message))) {
|
|
201
|
-
return new UpstreamError(upstream, "unreachable", message);
|
|
202
|
-
}
|
|
203
|
-
return new UpstreamError(upstream, "upstream_error", message);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// src/core/secrets.ts
|
|
207
|
-
import crypto2 from "node:crypto";
|
|
208
|
-
import fs2 from "node:fs";
|
|
209
|
-
var ALGORITHM = "aes-256-gcm";
|
|
210
|
-
function loadKey(keyPath) {
|
|
211
|
-
try {
|
|
212
|
-
const stored = fs2.readFileSync(keyPath, "utf8").trim();
|
|
213
|
-
return Buffer.from(stored, "base64");
|
|
214
|
-
} catch (err) {
|
|
215
|
-
if (err.code !== "ENOENT")
|
|
216
|
-
throw err;
|
|
217
|
-
}
|
|
218
|
-
ensureParentDir(keyPath);
|
|
219
|
-
const key = crypto2.randomBytes(32);
|
|
220
|
-
try {
|
|
221
|
-
fs2.writeFileSync(keyPath, key.toString("base64") + `
|
|
222
|
-
`, { flag: "wx", mode: 384 });
|
|
223
|
-
} catch (err) {
|
|
224
|
-
if (err.code === "EEXIST") {
|
|
225
|
-
const stored = fs2.readFileSync(keyPath, "utf8").trim();
|
|
226
|
-
return Buffer.from(stored, "base64");
|
|
227
|
-
}
|
|
228
|
-
throw err;
|
|
229
|
-
}
|
|
230
|
-
return key;
|
|
231
|
-
}
|
|
232
|
-
function readSecretsData(storePath, keyPath) {
|
|
233
|
-
const envelope = readJsonFile(storePath, null);
|
|
234
|
-
if (!envelope || envelope.version !== 1 || envelope.algorithm !== ALGORITHM)
|
|
235
|
-
return null;
|
|
236
|
-
try {
|
|
237
|
-
const key = loadKey(keyPath);
|
|
238
|
-
const iv = Buffer.from(envelope.iv, "base64");
|
|
239
|
-
const authTag = Buffer.from(envelope.authTag, "base64");
|
|
240
|
-
const ciphertext = Buffer.from(envelope.ciphertext, "base64");
|
|
241
|
-
const decipher = crypto2.createDecipheriv(ALGORITHM, key, iv);
|
|
242
|
-
decipher.setAuthTag(authTag);
|
|
243
|
-
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
244
|
-
return JSON.parse(decrypted.toString("utf8"));
|
|
245
|
-
} catch {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
function buildEnvelope(keyPath, data) {
|
|
250
|
-
const key = loadKey(keyPath);
|
|
251
|
-
const iv = crypto2.randomBytes(12);
|
|
252
|
-
const cipher = crypto2.createCipheriv(ALGORITHM, key, iv);
|
|
253
|
-
const plaintext = JSON.stringify(data);
|
|
254
|
-
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
255
|
-
return {
|
|
256
|
-
version: 1,
|
|
257
|
-
algorithm: ALGORITHM,
|
|
258
|
-
iv: iv.toString("base64"),
|
|
259
|
-
authTag: cipher.getAuthTag().toString("base64"),
|
|
260
|
-
ciphertext: encrypted.toString("base64")
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
function parseSecretRef(ref) {
|
|
264
|
-
if (!ref.startsWith("secret://"))
|
|
265
|
-
return null;
|
|
266
|
-
const name = ref.slice("secret://".length);
|
|
267
|
-
return name.length > 0 ? name : null;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
class SecretsManager {
|
|
271
|
-
storePath;
|
|
272
|
-
keyPath;
|
|
273
|
-
constructor(storePath = getSecretsStorePath(), keyPath = getSecretsKeyPath()) {
|
|
274
|
-
this.storePath = storePath;
|
|
275
|
-
this.keyPath = keyPath;
|
|
276
|
-
}
|
|
277
|
-
readStore() {
|
|
278
|
-
const data = readSecretsData(this.storePath, this.keyPath);
|
|
279
|
-
return data?.secrets ?? null;
|
|
280
|
-
}
|
|
281
|
-
recoverCorruptStore() {
|
|
282
|
-
try {
|
|
283
|
-
if (fs2.existsSync(this.storePath)) {
|
|
284
|
-
fs2.renameSync(this.storePath, `${this.storePath}.corrupt-${Date.now()}`);
|
|
285
|
-
}
|
|
286
|
-
} catch {}
|
|
287
|
-
}
|
|
288
|
-
listSecretNames() {
|
|
289
|
-
return Object.keys(this.readStore() ?? {}).sort();
|
|
290
|
-
}
|
|
291
|
-
setSecret(name, value) {
|
|
292
|
-
let map = this.readStore();
|
|
293
|
-
if (map === null) {
|
|
294
|
-
if (fs2.existsSync(this.storePath)) {
|
|
295
|
-
console.error(`[mcpx] Warning: the secrets store at ${this.storePath} could not be read (corrupt, or its encryption key changed) and is being reset. All previously stored secrets will need to be re-entered.`);
|
|
296
|
-
}
|
|
297
|
-
this.recoverCorruptStore();
|
|
298
|
-
map = {};
|
|
299
|
-
}
|
|
300
|
-
map[name] = value;
|
|
301
|
-
const envelope = buildEnvelope(this.keyPath, { secrets: map });
|
|
302
|
-
writeJsonAtomic(this.storePath, envelope);
|
|
303
|
-
}
|
|
304
|
-
removeSecret(name) {
|
|
305
|
-
const map = this.readStore() ?? {};
|
|
306
|
-
delete map[name];
|
|
307
|
-
const envelope = buildEnvelope(this.keyPath, { secrets: map });
|
|
308
|
-
writeJsonAtomic(this.storePath, envelope);
|
|
309
|
-
}
|
|
310
|
-
getSecret(name) {
|
|
311
|
-
const envOverride = process.env[`MCPX_SECRET_${name}`];
|
|
312
|
-
if (envOverride && envOverride.length > 0)
|
|
313
|
-
return envOverride;
|
|
314
|
-
return (this.readStore() ?? {})[name] ?? null;
|
|
315
|
-
}
|
|
316
|
-
resolveMaybeSecret(value) {
|
|
317
|
-
const secretName = parseSecretRef(value);
|
|
318
|
-
if (!secretName)
|
|
319
|
-
return value;
|
|
320
|
-
const secret = this.getSecret(secretName);
|
|
321
|
-
if (!secret)
|
|
322
|
-
throw new SecretNotFoundError(secretName);
|
|
323
|
-
return secret;
|
|
324
|
-
}
|
|
325
|
-
rotateLocalToken(secretName = "local_gateway_token") {
|
|
326
|
-
const token = crypto2.randomBytes(32).toString("base64url");
|
|
327
|
-
this.setSecret(secretName, token);
|
|
328
|
-
return token;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
function readSecretValueFromStdin() {
|
|
332
|
-
if (process.stdin.isTTY) {
|
|
333
|
-
throw new Error("No value provided. Use --value or pipe a value via stdin.");
|
|
334
|
-
}
|
|
335
|
-
const content = fs2.readFileSync(process.stdin.fd, "utf8").trim();
|
|
336
|
-
if (content.length === 0) {
|
|
337
|
-
throw new Error("Empty secret value provided.");
|
|
338
|
-
}
|
|
339
|
-
return content;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export { UpstreamError, SecretNotFoundError, classifyUpstreamError, SecretsManager, readSecretValueFromStdin, validateServerName, addServer, removeServer, updateServer, setServerEnabled, getGatewayTokenSecretName, ensureGatewayToken, rotateGatewayToken, registerProject, unregisterProject, setProjectServerEnabled };
|
|
343
|
-
|
|
344
|
-
//# debugId=C03A0B51CA07FB8164756E2164756E21
|