@mcp-use/cli 3.0.0-canary.3 → 3.0.0-canary.5
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/commands/auth.d.ts +2 -8
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/deploy.d.ts +3 -4
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deployments.d.ts +0 -3
- package/dist/commands/deployments.d.ts.map +1 -1
- package/dist/commands/org.d.ts.map +1 -1
- package/dist/commands/servers.d.ts +3 -0
- package/dist/commands/servers.d.ts.map +1 -0
- package/dist/index.cjs +1229 -1185
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1228 -1184
- package/dist/index.js.map +1 -1
- package/dist/utils/api.d.ts +130 -144
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/cloud-urls.d.ts +14 -0
- package/dist/utils/cloud-urls.d.ts.map +1 -0
- package/dist/utils/config.d.ts +10 -4
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/git.d.ts +12 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -503,7 +503,7 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
503
503
|
var source_default = chalk;
|
|
504
504
|
|
|
505
505
|
// src/index.ts
|
|
506
|
-
import { Command as
|
|
506
|
+
import { Command as Command5 } from "commander";
|
|
507
507
|
import "dotenv/config";
|
|
508
508
|
import { spawn } from "child_process";
|
|
509
509
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -1147,14 +1147,21 @@ async function ensureConfigDir() {
|
|
|
1147
1147
|
async function readConfig() {
|
|
1148
1148
|
try {
|
|
1149
1149
|
const content = await fs7.readFile(CONFIG_FILE, "utf-8");
|
|
1150
|
-
|
|
1150
|
+
const raw = JSON.parse(content);
|
|
1151
|
+
return {
|
|
1152
|
+
...raw,
|
|
1153
|
+
orgId: raw.orgId ?? raw.profileId,
|
|
1154
|
+
orgName: raw.orgName ?? raw.profileName,
|
|
1155
|
+
orgSlug: raw.orgSlug ?? raw.profileSlug
|
|
1156
|
+
};
|
|
1151
1157
|
} catch (error) {
|
|
1152
1158
|
return {};
|
|
1153
1159
|
}
|
|
1154
1160
|
}
|
|
1155
1161
|
async function writeConfig(config) {
|
|
1156
1162
|
await ensureConfigDir();
|
|
1157
|
-
|
|
1163
|
+
const { profileId: _a, profileName: _b, profileSlug: _c, ...clean } = config;
|
|
1164
|
+
await fs7.writeFile(CONFIG_FILE, JSON.stringify(clean, null, 2), "utf-8");
|
|
1158
1165
|
}
|
|
1159
1166
|
async function deleteConfig() {
|
|
1160
1167
|
try {
|
|
@@ -1174,9 +1181,9 @@ async function isLoggedIn() {
|
|
|
1174
1181
|
const apiKey = await getApiKey();
|
|
1175
1182
|
return !!apiKey;
|
|
1176
1183
|
}
|
|
1177
|
-
async function
|
|
1184
|
+
async function getOrgId() {
|
|
1178
1185
|
const config = await readConfig();
|
|
1179
|
-
return config.
|
|
1186
|
+
return config.orgId || null;
|
|
1180
1187
|
}
|
|
1181
1188
|
async function getWebUrl() {
|
|
1182
1189
|
return DEFAULT_WEB_URL;
|
|
@@ -1190,30 +1197,21 @@ async function getAuthBaseUrl() {
|
|
|
1190
1197
|
var McpUseAPI = class _McpUseAPI {
|
|
1191
1198
|
baseUrl;
|
|
1192
1199
|
apiKey;
|
|
1193
|
-
|
|
1194
|
-
constructor(baseUrl, apiKey,
|
|
1200
|
+
orgId;
|
|
1201
|
+
constructor(baseUrl, apiKey, orgId) {
|
|
1195
1202
|
this.baseUrl = baseUrl || "";
|
|
1196
1203
|
this.apiKey = apiKey;
|
|
1197
|
-
this.
|
|
1204
|
+
this.orgId = orgId;
|
|
1198
1205
|
}
|
|
1199
|
-
/**
|
|
1200
|
-
* Initialize API client with config
|
|
1201
|
-
*/
|
|
1202
1206
|
static async create() {
|
|
1203
1207
|
const baseUrl = await getApiUrl();
|
|
1204
1208
|
const apiKey = await getApiKey();
|
|
1205
|
-
const
|
|
1206
|
-
return new _McpUseAPI(baseUrl, apiKey ?? void 0,
|
|
1209
|
+
const orgId = await getOrgId();
|
|
1210
|
+
return new _McpUseAPI(baseUrl, apiKey ?? void 0, orgId ?? void 0);
|
|
1207
1211
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
*/
|
|
1211
|
-
setProfileId(profileId) {
|
|
1212
|
-
this.profileId = profileId;
|
|
1212
|
+
setOrgId(orgId) {
|
|
1213
|
+
this.orgId = orgId;
|
|
1213
1214
|
}
|
|
1214
|
-
/**
|
|
1215
|
-
* Make authenticated request
|
|
1216
|
-
*/
|
|
1217
1215
|
async request(endpoint, options = {}) {
|
|
1218
1216
|
const url = `${this.baseUrl}${endpoint}`;
|
|
1219
1217
|
const headers = {
|
|
@@ -1223,8 +1221,8 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1223
1221
|
if (this.apiKey) {
|
|
1224
1222
|
headers["x-api-key"] = this.apiKey;
|
|
1225
1223
|
}
|
|
1226
|
-
if (this.
|
|
1227
|
-
headers["x-profile-id"] = this.
|
|
1224
|
+
if (this.orgId) {
|
|
1225
|
+
headers["x-profile-id"] = this.orgId;
|
|
1228
1226
|
}
|
|
1229
1227
|
const timeout = options.timeout || 3e4;
|
|
1230
1228
|
const controller = new AbortController();
|
|
@@ -1251,16 +1249,13 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1251
1249
|
} catch (error) {
|
|
1252
1250
|
clearTimeout(timeoutId);
|
|
1253
1251
|
if (error.name === "AbortError") {
|
|
1254
|
-
throw new Error(
|
|
1255
|
-
`Request timeout after ${timeout / 1e3}s. Try using --follow flag to stream logs instead.`
|
|
1256
|
-
);
|
|
1252
|
+
throw new Error(`Request timeout after ${timeout / 1e3}s.`);
|
|
1257
1253
|
}
|
|
1258
1254
|
throw error;
|
|
1259
1255
|
}
|
|
1260
1256
|
}
|
|
1261
1257
|
/**
|
|
1262
1258
|
* Create a persistent API key using a Better Auth access token.
|
|
1263
|
-
* Calls Better Auth's built-in POST /api/auth/api-key/create endpoint.
|
|
1264
1259
|
*/
|
|
1265
1260
|
async createApiKeyWithAccessToken(accessToken, name = "CLI") {
|
|
1266
1261
|
const authBase = await getAuthBaseUrl();
|
|
@@ -1279,255 +1274,171 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1279
1274
|
}
|
|
1280
1275
|
return response.json();
|
|
1281
1276
|
}
|
|
1282
|
-
|
|
1283
|
-
* Test authentication
|
|
1284
|
-
*/
|
|
1277
|
+
// ── Auth ────────────────────────────────────────────────────────
|
|
1285
1278
|
async testAuth() {
|
|
1286
|
-
|
|
1279
|
+
const wire = await this.request("/test-auth");
|
|
1280
|
+
return {
|
|
1281
|
+
message: wire.message,
|
|
1282
|
+
user_id: wire.user_id,
|
|
1283
|
+
email: wire.email,
|
|
1284
|
+
default_org_id: wire.default_profile_id,
|
|
1285
|
+
orgs: (wire.profiles ?? []).map((p) => ({
|
|
1286
|
+
id: p.id,
|
|
1287
|
+
name: p.profile_name,
|
|
1288
|
+
slug: p.slug,
|
|
1289
|
+
role: p.role
|
|
1290
|
+
}))
|
|
1291
|
+
};
|
|
1287
1292
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
*/
|
|
1291
|
-
async setDefaultProfile(profileId) {
|
|
1292
|
-
await this.request(`/profiles/${profileId}/set-default`, {
|
|
1293
|
+
async setDefaultOrg(orgId) {
|
|
1294
|
+
await this.request(`/organizations/${orgId}/set-default`, {
|
|
1293
1295
|
method: "POST"
|
|
1294
1296
|
});
|
|
1295
1297
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1298
|
+
// ── Organization ID resolution ──────────────────────────────────
|
|
1299
|
+
async resolveOrganizationId() {
|
|
1300
|
+
if (this.orgId) return this.orgId;
|
|
1301
|
+
const auth = await this.testAuth();
|
|
1302
|
+
const id = auth.default_org_id;
|
|
1303
|
+
if (!id) {
|
|
1304
|
+
throw new Error(
|
|
1305
|
+
"No organization set. Run `mcp-use org switch` or use --org to specify one."
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
return id;
|
|
1309
|
+
}
|
|
1310
|
+
// ── Servers ─────────────────────────────────────────────────────
|
|
1311
|
+
async createServer(body) {
|
|
1312
|
+
return this.request("/servers", {
|
|
1301
1313
|
method: "POST",
|
|
1302
|
-
body: JSON.stringify(
|
|
1314
|
+
body: JSON.stringify(body)
|
|
1303
1315
|
});
|
|
1304
1316
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
return this.request(`/deployments/${deploymentId}`);
|
|
1310
|
-
}
|
|
1311
|
-
/**
|
|
1312
|
-
* Stream deployment logs
|
|
1313
|
-
*/
|
|
1314
|
-
async *streamDeploymentLogs(deploymentId) {
|
|
1315
|
-
const url = `${this.baseUrl}/deployments/${deploymentId}/logs/stream`;
|
|
1316
|
-
const headers = {};
|
|
1317
|
-
if (this.apiKey) {
|
|
1318
|
-
headers["x-api-key"] = this.apiKey;
|
|
1319
|
-
}
|
|
1320
|
-
if (this.profileId) {
|
|
1321
|
-
headers["x-profile-id"] = this.profileId;
|
|
1317
|
+
async listServers(params) {
|
|
1318
|
+
const search = new URLSearchParams();
|
|
1319
|
+
if (params?.organizationId) {
|
|
1320
|
+
search.set("organizationId", params.organizationId);
|
|
1322
1321
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
throw new Error(`Failed to stream logs: ${response.status}`);
|
|
1322
|
+
if (params?.limit != null) {
|
|
1323
|
+
search.set("limit", String(params.limit));
|
|
1326
1324
|
}
|
|
1327
|
-
if (
|
|
1328
|
-
|
|
1325
|
+
if (params?.skip != null) {
|
|
1326
|
+
search.set("skip", String(params.skip));
|
|
1329
1327
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
let buffer = "";
|
|
1333
|
-
try {
|
|
1334
|
-
while (true) {
|
|
1335
|
-
const { done, value } = await reader.read();
|
|
1336
|
-
if (done) break;
|
|
1337
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1338
|
-
const lines = buffer.split("\n");
|
|
1339
|
-
buffer = lines.pop() || "";
|
|
1340
|
-
for (const line of lines) {
|
|
1341
|
-
if (line.startsWith("data: ")) {
|
|
1342
|
-
const data = line.slice(6);
|
|
1343
|
-
try {
|
|
1344
|
-
const parsed = JSON.parse(data);
|
|
1345
|
-
if (parsed.log) {
|
|
1346
|
-
yield parsed.log;
|
|
1347
|
-
} else if (parsed.error) {
|
|
1348
|
-
throw new Error(parsed.error);
|
|
1349
|
-
}
|
|
1350
|
-
} catch (e) {
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
} finally {
|
|
1356
|
-
reader.releaseLock();
|
|
1328
|
+
if (params?.sort) {
|
|
1329
|
+
search.set("sort", params.sort);
|
|
1357
1330
|
}
|
|
1331
|
+
const q = search.toString();
|
|
1332
|
+
return this.request(`/servers${q ? `?${q}` : ""}`);
|
|
1358
1333
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
if (stats.size > maxSize) {
|
|
1369
|
-
throw new Error(
|
|
1370
|
-
`File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
|
|
1371
|
-
);
|
|
1372
|
-
}
|
|
1373
|
-
const fileBuffer = await readFile4(filePath);
|
|
1374
|
-
const filename = basename(filePath);
|
|
1375
|
-
const formData = new FormData();
|
|
1376
|
-
const blob = new Blob([fileBuffer], { type: "application/gzip" });
|
|
1377
|
-
formData.append("source_file", blob, filename);
|
|
1378
|
-
formData.append("name", request.name);
|
|
1379
|
-
formData.append("source_type", "upload");
|
|
1380
|
-
if (request.source.type === "upload") {
|
|
1381
|
-
formData.append("runtime", request.source.runtime || "node");
|
|
1382
|
-
formData.append("port", String(request.source.port || 3e3));
|
|
1383
|
-
if (request.source.startCommand) {
|
|
1384
|
-
formData.append("startCommand", request.source.startCommand);
|
|
1385
|
-
}
|
|
1386
|
-
if (request.source.buildCommand) {
|
|
1387
|
-
formData.append("buildCommand", request.source.buildCommand);
|
|
1388
|
-
}
|
|
1389
|
-
if (request.source.env && Object.keys(request.source.env).length > 0) {
|
|
1390
|
-
formData.append("env", JSON.stringify(request.source.env));
|
|
1334
|
+
async getServer(idOrSlug) {
|
|
1335
|
+
const path8 = encodeURIComponent(idOrSlug);
|
|
1336
|
+
return this.request(`/servers/${path8}`);
|
|
1337
|
+
}
|
|
1338
|
+
async deleteServer(id) {
|
|
1339
|
+
await this.request(
|
|
1340
|
+
`/servers/${encodeURIComponent(id)}`,
|
|
1341
|
+
{
|
|
1342
|
+
method: "DELETE"
|
|
1391
1343
|
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
formData.append("healthCheckPath", request.healthCheckPath);
|
|
1398
|
-
}
|
|
1399
|
-
const url = `${this.baseUrl}/deployments`;
|
|
1400
|
-
const headers = {};
|
|
1401
|
-
if (this.apiKey) {
|
|
1402
|
-
headers["x-api-key"] = this.apiKey;
|
|
1403
|
-
}
|
|
1404
|
-
if (this.profileId) {
|
|
1405
|
-
headers["x-profile-id"] = this.profileId;
|
|
1406
|
-
}
|
|
1407
|
-
const response = await fetch(url, {
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
// ── Deployments ─────────────────────────────────────────────────
|
|
1347
|
+
async createDeployment(input) {
|
|
1348
|
+
return this.request("/deployments", {
|
|
1408
1349
|
method: "POST",
|
|
1409
|
-
|
|
1410
|
-
body: formData
|
|
1350
|
+
body: JSON.stringify(input)
|
|
1411
1351
|
});
|
|
1412
|
-
if (!response.ok) {
|
|
1413
|
-
const error = await response.text();
|
|
1414
|
-
throw new Error(`Deployment failed: ${error}`);
|
|
1415
|
-
}
|
|
1416
|
-
return response.json();
|
|
1417
1352
|
}
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1353
|
+
async getDeployment(deploymentId) {
|
|
1354
|
+
return this.request(`/deployments/${deploymentId}`);
|
|
1355
|
+
}
|
|
1421
1356
|
async listDeployments() {
|
|
1422
|
-
|
|
1423
|
-
return response.deployments;
|
|
1357
|
+
return this.request("/deployments");
|
|
1424
1358
|
}
|
|
1425
|
-
/**
|
|
1426
|
-
* Delete deployment
|
|
1427
|
-
*/
|
|
1428
1359
|
async deleteDeployment(deploymentId) {
|
|
1429
1360
|
await this.request(`/deployments/${deploymentId}`, {
|
|
1430
1361
|
method: "DELETE"
|
|
1431
1362
|
});
|
|
1432
1363
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
async updateDeployment(deploymentId, updates) {
|
|
1437
|
-
return this.request(`/deployments/${deploymentId}`, {
|
|
1438
|
-
method: "PATCH",
|
|
1439
|
-
body: JSON.stringify(updates)
|
|
1440
|
-
});
|
|
1441
|
-
}
|
|
1442
|
-
/**
|
|
1443
|
-
* Redeploy deployment
|
|
1444
|
-
*
|
|
1445
|
-
* @param deploymentId - The deployment ID to redeploy
|
|
1446
|
-
* @param configOrFilePath - Either a RedeploymentConfig object with updated settings,
|
|
1447
|
-
* or a file path string for source code upload
|
|
1448
|
-
*/
|
|
1449
|
-
async redeployDeployment(deploymentId, configOrFilePath) {
|
|
1450
|
-
if (typeof configOrFilePath === "string") {
|
|
1451
|
-
const filePath = configOrFilePath;
|
|
1452
|
-
const { readFile: readFile4 } = await import("fs/promises");
|
|
1453
|
-
const { basename } = await import("path");
|
|
1454
|
-
const { stat } = await import("fs/promises");
|
|
1455
|
-
const stats = await stat(filePath);
|
|
1456
|
-
const maxSize = 2 * 1024 * 1024;
|
|
1457
|
-
if (stats.size > maxSize) {
|
|
1458
|
-
throw new Error(
|
|
1459
|
-
`File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
|
|
1460
|
-
);
|
|
1461
|
-
}
|
|
1462
|
-
const fileBuffer = await readFile4(filePath);
|
|
1463
|
-
const formData = new FormData();
|
|
1464
|
-
const blob = new Blob([fileBuffer], { type: "application/gzip" });
|
|
1465
|
-
formData.append("source_file", blob, basename(filePath));
|
|
1466
|
-
const headers = {};
|
|
1467
|
-
if (this.apiKey) headers["x-api-key"] = this.apiKey;
|
|
1468
|
-
if (this.profileId) headers["x-profile-id"] = this.profileId;
|
|
1469
|
-
const response = await fetch(
|
|
1470
|
-
`${this.baseUrl}/deployments/${deploymentId}/redeploy`,
|
|
1471
|
-
{
|
|
1472
|
-
method: "POST",
|
|
1473
|
-
headers,
|
|
1474
|
-
body: formData
|
|
1475
|
-
}
|
|
1476
|
-
);
|
|
1477
|
-
if (!response.ok) {
|
|
1478
|
-
const error = await response.text();
|
|
1479
|
-
throw new Error(`Redeploy failed: ${error}`);
|
|
1480
|
-
}
|
|
1481
|
-
return response.json();
|
|
1482
|
-
}
|
|
1483
|
-
const config = configOrFilePath;
|
|
1484
|
-
return this.request(`/deployments/${deploymentId}/redeploy`, {
|
|
1485
|
-
method: "POST",
|
|
1486
|
-
body: config ? JSON.stringify(config) : void 0
|
|
1364
|
+
async stopDeployment(deploymentId) {
|
|
1365
|
+
await this.request(`/deployments/${deploymentId}/stop`, {
|
|
1366
|
+
method: "POST"
|
|
1487
1367
|
});
|
|
1488
1368
|
}
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
async getDeploymentLogs(deploymentId) {
|
|
1493
|
-
const response = await this.request(
|
|
1494
|
-
`/deployments/${deploymentId}/logs`,
|
|
1369
|
+
async getDeploymentLogs(deploymentId, lines = 500) {
|
|
1370
|
+
const resp = await this.request(
|
|
1371
|
+
`/deployments/${deploymentId}/logs?lines=${lines}`,
|
|
1495
1372
|
{ timeout: 6e4 }
|
|
1496
|
-
// 60 second timeout for logs
|
|
1497
1373
|
);
|
|
1498
|
-
return
|
|
1374
|
+
return resp.logs;
|
|
1499
1375
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
async getDeploymentBuildLogs(deploymentId) {
|
|
1504
|
-
const response = await this.request(
|
|
1505
|
-
`/deployments/${deploymentId}/logs/build`,
|
|
1376
|
+
async getDeploymentBuildLogs(deploymentId, offset = 0) {
|
|
1377
|
+
return this.request(
|
|
1378
|
+
`/deployments/${deploymentId}/build-logs?offset=${offset}`,
|
|
1506
1379
|
{ timeout: 6e4 }
|
|
1507
|
-
// 60 second timeout for logs
|
|
1508
1380
|
);
|
|
1509
|
-
return response.data.logs;
|
|
1510
1381
|
}
|
|
1511
|
-
|
|
1512
|
-
* Get GitHub connection status
|
|
1513
|
-
*/
|
|
1382
|
+
// ── GitHub ──────────────────────────────────────────────────────
|
|
1514
1383
|
async getGitHubConnectionStatus() {
|
|
1515
|
-
|
|
1384
|
+
const orgId = await this.resolveOrganizationId();
|
|
1385
|
+
const resp = await this.request(`/github/installations?organizationId=${orgId}`);
|
|
1386
|
+
return {
|
|
1387
|
+
is_connected: resp.installations.length > 0,
|
|
1388
|
+
installations: resp.installations.map((i) => ({
|
|
1389
|
+
id: i.id,
|
|
1390
|
+
installation_id: i.installationId,
|
|
1391
|
+
account_login: i.account?.login ?? "",
|
|
1392
|
+
account_type: i.account?.type ?? "User"
|
|
1393
|
+
}))
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
async getGitHubRepos(_refresh) {
|
|
1397
|
+
const orgId = await this.resolveOrganizationId();
|
|
1398
|
+
const installResp = await this.request(`/github/installations?organizationId=${orgId}`);
|
|
1399
|
+
if (installResp.installations.length === 0) {
|
|
1400
|
+
return { user: { login: "", id: 0, avatar_url: "" }, repos: [] };
|
|
1401
|
+
}
|
|
1402
|
+
const inst = installResp.installations[0];
|
|
1403
|
+
const reposResp = await this.request(`/github/installations/${inst.installationId}/repos`);
|
|
1404
|
+
return {
|
|
1405
|
+
user: {
|
|
1406
|
+
login: inst.account?.login ?? "",
|
|
1407
|
+
id: 0,
|
|
1408
|
+
avatar_url: inst.account?.avatar_url ?? ""
|
|
1409
|
+
},
|
|
1410
|
+
repos: reposResp.repos.map((r) => ({
|
|
1411
|
+
id: r.id,
|
|
1412
|
+
name: r.name,
|
|
1413
|
+
full_name: r.fullName,
|
|
1414
|
+
private: r.private,
|
|
1415
|
+
owner: { login: r.fullName.split("/")[0] ?? "" }
|
|
1416
|
+
}))
|
|
1417
|
+
};
|
|
1516
1418
|
}
|
|
1517
|
-
/**
|
|
1518
|
-
* Get GitHub app name
|
|
1519
|
-
*/
|
|
1520
1419
|
async getGitHubAppName() {
|
|
1521
|
-
|
|
1522
|
-
return
|
|
1420
|
+
if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
|
|
1421
|
+
if (this.baseUrl.includes("localhost")) return "mcp-use-local";
|
|
1422
|
+
if (this.baseUrl.includes(".dev.")) return "mcp-use-dev";
|
|
1423
|
+
return "mcp-use";
|
|
1523
1424
|
}
|
|
1524
1425
|
/**
|
|
1525
|
-
*
|
|
1426
|
+
* Returns the GitHub numeric installation ID (not the DB UUID) for the org.
|
|
1427
|
+
* Used for building direct installation settings URLs.
|
|
1526
1428
|
*/
|
|
1527
|
-
async
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1429
|
+
async getGitHubInstallationId() {
|
|
1430
|
+
const status = await this.getGitHubConnectionStatus();
|
|
1431
|
+
return status.installations?.[0]?.installation_id ?? null;
|
|
1432
|
+
}
|
|
1433
|
+
async createGitHubRepo(opts) {
|
|
1434
|
+
return this.request(`/github/installations/${opts.installationId}/repos`, {
|
|
1435
|
+
method: "POST",
|
|
1436
|
+
body: JSON.stringify({
|
|
1437
|
+
name: opts.name,
|
|
1438
|
+
private: opts.private ?? true,
|
|
1439
|
+
org: opts.org
|
|
1440
|
+
})
|
|
1441
|
+
});
|
|
1531
1442
|
}
|
|
1532
1443
|
};
|
|
1533
1444
|
|
|
@@ -1592,19 +1503,17 @@ async function pollForDeviceToken(authBaseUrl, deviceCode, intervalSeconds) {
|
|
|
1592
1503
|
}
|
|
1593
1504
|
throw new Error("Login timed out. Please try again.");
|
|
1594
1505
|
}
|
|
1595
|
-
async function promptOrgSelection(
|
|
1596
|
-
if (
|
|
1597
|
-
if (
|
|
1598
|
-
return
|
|
1506
|
+
async function promptOrgSelection(orgs, defaultOrgId) {
|
|
1507
|
+
if (orgs.length === 0) return null;
|
|
1508
|
+
if (orgs.length === 1) {
|
|
1509
|
+
return orgs[0];
|
|
1599
1510
|
}
|
|
1600
1511
|
console.log(source_default.cyan.bold("\n\u{1F3E2} Select an organization:\n"));
|
|
1601
|
-
for (let i = 0; i <
|
|
1602
|
-
const
|
|
1603
|
-
const marker =
|
|
1604
|
-
const slug =
|
|
1605
|
-
console.log(
|
|
1606
|
-
` ${source_default.white(`${i + 1}.`)} ${p.profile_name}${slug}${marker}`
|
|
1607
|
-
);
|
|
1512
|
+
for (let i = 0; i < orgs.length; i++) {
|
|
1513
|
+
const o = orgs[i];
|
|
1514
|
+
const marker = o.id === defaultOrgId ? source_default.green(" (current)") : "";
|
|
1515
|
+
const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
|
|
1516
|
+
console.log(` ${source_default.white(`${i + 1}.`)} ${o.name}${slug}${marker}`);
|
|
1608
1517
|
}
|
|
1609
1518
|
const readline = await import("readline");
|
|
1610
1519
|
const rl = readline.createInterface({
|
|
@@ -1612,7 +1521,7 @@ async function promptOrgSelection(profiles, defaultProfileId) {
|
|
|
1612
1521
|
output: process.stdout
|
|
1613
1522
|
});
|
|
1614
1523
|
return new Promise((resolve2) => {
|
|
1615
|
-
const defaultIdx =
|
|
1524
|
+
const defaultIdx = defaultOrgId ? orgs.findIndex((o) => o.id === defaultOrgId) : 0;
|
|
1616
1525
|
const defaultDisplay = defaultIdx >= 0 ? defaultIdx + 1 : 1;
|
|
1617
1526
|
rl.question(
|
|
1618
1527
|
source_default.gray(`
|
|
@@ -1621,11 +1530,11 @@ Enter number [${defaultDisplay}]: `),
|
|
|
1621
1530
|
rl.close();
|
|
1622
1531
|
const trimmed = answer.trim();
|
|
1623
1532
|
const idx = trimmed === "" ? defaultIdx : parseInt(trimmed, 10) - 1;
|
|
1624
|
-
if (idx >= 0 && idx <
|
|
1625
|
-
resolve2(
|
|
1533
|
+
if (idx >= 0 && idx < orgs.length) {
|
|
1534
|
+
resolve2(orgs[idx]);
|
|
1626
1535
|
} else {
|
|
1627
1536
|
console.log(source_default.yellow("Invalid selection, using default."));
|
|
1628
|
-
resolve2(
|
|
1537
|
+
resolve2(orgs[defaultIdx >= 0 ? defaultIdx : 0]);
|
|
1629
1538
|
}
|
|
1630
1539
|
}
|
|
1631
1540
|
);
|
|
@@ -1704,28 +1613,25 @@ async function loginCommand(options) {
|
|
|
1704
1613
|
const masked = storedKey.substring(0, 8) + "...";
|
|
1705
1614
|
console.log(source_default.white(" API Key: ") + source_default.gray(masked));
|
|
1706
1615
|
}
|
|
1707
|
-
const
|
|
1708
|
-
if (
|
|
1709
|
-
let
|
|
1710
|
-
if (
|
|
1711
|
-
|
|
1616
|
+
const orgs = authInfo.orgs ?? [];
|
|
1617
|
+
if (orgs.length > 0) {
|
|
1618
|
+
let selectedOrg = null;
|
|
1619
|
+
if (orgs.length === 1) {
|
|
1620
|
+
selectedOrg = orgs[0];
|
|
1712
1621
|
} else {
|
|
1713
|
-
|
|
1714
|
-
profiles,
|
|
1715
|
-
authInfo.default_profile_id
|
|
1716
|
-
);
|
|
1622
|
+
selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
|
|
1717
1623
|
}
|
|
1718
|
-
if (
|
|
1624
|
+
if (selectedOrg) {
|
|
1719
1625
|
const config = await readConfig();
|
|
1720
1626
|
await writeConfig({
|
|
1721
1627
|
...config,
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1628
|
+
orgId: selectedOrg.id,
|
|
1629
|
+
orgName: selectedOrg.name,
|
|
1630
|
+
orgSlug: selectedOrg.slug ?? void 0
|
|
1725
1631
|
});
|
|
1726
|
-
const slug =
|
|
1632
|
+
const slug = selectedOrg.slug ? source_default.gray(` (${selectedOrg.slug})`) : "";
|
|
1727
1633
|
console.log(
|
|
1728
|
-
source_default.white(" Org: ") + source_default.cyan(
|
|
1634
|
+
source_default.white(" Org: ") + source_default.cyan(selectedOrg.name) + slug
|
|
1729
1635
|
);
|
|
1730
1636
|
}
|
|
1731
1637
|
}
|
|
@@ -1795,22 +1701,22 @@ async function whoamiCommand() {
|
|
|
1795
1701
|
console.log(source_default.white("API Key: ") + source_default.gray(masked));
|
|
1796
1702
|
}
|
|
1797
1703
|
const config = await readConfig();
|
|
1798
|
-
const
|
|
1799
|
-
if (
|
|
1800
|
-
const
|
|
1801
|
-
(
|
|
1704
|
+
const orgs = authInfo.orgs ?? [];
|
|
1705
|
+
if (orgs.length > 0) {
|
|
1706
|
+
const activeOrg = orgs.find(
|
|
1707
|
+
(o) => o.id === (config.orgId || authInfo.default_org_id)
|
|
1802
1708
|
);
|
|
1803
|
-
if (
|
|
1804
|
-
const slug =
|
|
1709
|
+
if (activeOrg) {
|
|
1710
|
+
const slug = activeOrg.slug ? source_default.gray(` (${activeOrg.slug})`) : "";
|
|
1805
1711
|
console.log(
|
|
1806
|
-
source_default.white("Org: ") + source_default.cyan(
|
|
1712
|
+
source_default.white("Org: ") + source_default.cyan(activeOrg.name) + slug
|
|
1807
1713
|
);
|
|
1808
1714
|
}
|
|
1809
|
-
if (
|
|
1715
|
+
if (orgs.length > 1) {
|
|
1810
1716
|
console.log(
|
|
1811
1717
|
source_default.gray(
|
|
1812
1718
|
`
|
|
1813
|
-
${
|
|
1719
|
+
${orgs.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
|
|
1814
1720
|
)
|
|
1815
1721
|
);
|
|
1816
1722
|
}
|
|
@@ -2587,9 +2493,9 @@ async function listPromptsCommand(options) {
|
|
|
2587
2493
|
}
|
|
2588
2494
|
console.log(formatHeader(`Available Prompts (${prompts.length}):`));
|
|
2589
2495
|
console.log("");
|
|
2590
|
-
const tableData = prompts.map((
|
|
2591
|
-
name: source_default.bold(
|
|
2592
|
-
description:
|
|
2496
|
+
const tableData = prompts.map((prompt4) => ({
|
|
2497
|
+
name: source_default.bold(prompt4.name),
|
|
2498
|
+
description: prompt4.description || source_default.gray("No description")
|
|
2593
2499
|
}));
|
|
2594
2500
|
console.log(
|
|
2595
2501
|
formatTable(tableData, [
|
|
@@ -2617,20 +2523,20 @@ async function getPromptCommand(promptName, argsJson, options) {
|
|
|
2617
2523
|
}
|
|
2618
2524
|
}
|
|
2619
2525
|
console.error(formatInfo(`Getting prompt '${promptName}'...`));
|
|
2620
|
-
const
|
|
2526
|
+
const prompt4 = await session.getPrompt(promptName, args);
|
|
2621
2527
|
if (options?.json) {
|
|
2622
|
-
console.log(formatJson(
|
|
2528
|
+
console.log(formatJson(prompt4));
|
|
2623
2529
|
} else {
|
|
2624
2530
|
console.log(formatHeader(`Prompt: ${promptName}`));
|
|
2625
2531
|
console.log("");
|
|
2626
|
-
if (
|
|
2627
|
-
console.log(
|
|
2532
|
+
if (prompt4.description) {
|
|
2533
|
+
console.log(prompt4.description);
|
|
2628
2534
|
console.log("");
|
|
2629
2535
|
}
|
|
2630
|
-
if (
|
|
2536
|
+
if (prompt4.messages) {
|
|
2631
2537
|
console.log(formatHeader("Messages:"));
|
|
2632
2538
|
console.log("");
|
|
2633
|
-
console.log(formatPromptMessages(
|
|
2539
|
+
console.log(formatPromptMessages(prompt4.messages));
|
|
2634
2540
|
}
|
|
2635
2541
|
}
|
|
2636
2542
|
} catch (error) {
|
|
@@ -2770,8 +2676,8 @@ async function interactiveCommand(options) {
|
|
|
2770
2676
|
async (argsInput) => {
|
|
2771
2677
|
try {
|
|
2772
2678
|
const args = argsInput.trim() ? JSON.parse(argsInput) : {};
|
|
2773
|
-
const
|
|
2774
|
-
console.log(formatPromptMessages(
|
|
2679
|
+
const prompt4 = await session.getPrompt(arg, args);
|
|
2680
|
+
console.log(formatPromptMessages(prompt4.messages));
|
|
2775
2681
|
} catch (error) {
|
|
2776
2682
|
console.error(formatError(error.message));
|
|
2777
2683
|
}
|
|
@@ -2937,6 +2843,20 @@ async function getGitInfo(cwd = process.cwd()) {
|
|
|
2937
2843
|
hasUncommittedChanges: uncommittedChanges
|
|
2938
2844
|
};
|
|
2939
2845
|
}
|
|
2846
|
+
async function gitInit(cwd, message = "Initial commit") {
|
|
2847
|
+
await gitCommand("git init", cwd);
|
|
2848
|
+
await gitCommand("git add .", cwd);
|
|
2849
|
+
await gitCommand(`git commit -m "${message}"`, cwd);
|
|
2850
|
+
}
|
|
2851
|
+
async function gitAddRemoteAndPush(cwd, cloneUrl, branch = "main") {
|
|
2852
|
+
await gitCommand(`git remote add origin ${cloneUrl}`, cwd);
|
|
2853
|
+
await gitCommand(`git push -u origin ${branch}`, cwd);
|
|
2854
|
+
}
|
|
2855
|
+
async function gitCommitAndPush(cwd, message, branch = "main") {
|
|
2856
|
+
await gitCommand("git add .", cwd);
|
|
2857
|
+
await gitCommand(`git commit -m "${message}"`, cwd);
|
|
2858
|
+
await gitCommand(`git push origin ${branch}`, cwd);
|
|
2859
|
+
}
|
|
2940
2860
|
function isGitHubUrl(url) {
|
|
2941
2861
|
try {
|
|
2942
2862
|
const parsedUrl = new URL(url);
|
|
@@ -2951,6 +2871,22 @@ function isGitHubUrl(url) {
|
|
|
2951
2871
|
return false;
|
|
2952
2872
|
}
|
|
2953
2873
|
|
|
2874
|
+
// src/utils/cloud-urls.ts
|
|
2875
|
+
var GATEWAY_DOMAIN = "run.mcp-use.com";
|
|
2876
|
+
function buildGatewayUrl(slugOrId) {
|
|
2877
|
+
return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
|
|
2878
|
+
}
|
|
2879
|
+
function getMcpServerUrl(deployment) {
|
|
2880
|
+
if (deployment.mcpUrl) return deployment.mcpUrl;
|
|
2881
|
+
if (deployment.serverId) return buildGatewayUrl(deployment.serverId);
|
|
2882
|
+
return "";
|
|
2883
|
+
}
|
|
2884
|
+
function getMcpServerUrlForCloudServer(server) {
|
|
2885
|
+
if (server.mcpUrl) return server.mcpUrl;
|
|
2886
|
+
const hostKey = server.slug && server.slug.trim() || server.id;
|
|
2887
|
+
return buildGatewayUrl(hostKey);
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2954
2890
|
// src/utils/project-link.ts
|
|
2955
2891
|
import { promises as fs8 } from "fs";
|
|
2956
2892
|
import path4 from "path";
|
|
@@ -2997,10 +2933,6 @@ ${MCP_USE_DIR}
|
|
|
2997
2933
|
}
|
|
2998
2934
|
|
|
2999
2935
|
// src/commands/deploy.ts
|
|
3000
|
-
var GATEWAY_DOMAIN = "run.mcp-use.com";
|
|
3001
|
-
function buildGatewayUrl(slugOrId) {
|
|
3002
|
-
return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
|
|
3003
|
-
}
|
|
3004
2936
|
async function parseEnvFile(filePath) {
|
|
3005
2937
|
try {
|
|
3006
2938
|
const content = await fs9.readFile(filePath, "utf-8");
|
|
@@ -3010,9 +2942,7 @@ async function parseEnvFile(filePath) {
|
|
|
3010
2942
|
let currentValue = "";
|
|
3011
2943
|
for (let line of lines) {
|
|
3012
2944
|
line = line.trim();
|
|
3013
|
-
if (!line || line.startsWith("#"))
|
|
3014
|
-
continue;
|
|
3015
|
-
}
|
|
2945
|
+
if (!line || line.startsWith("#")) continue;
|
|
3016
2946
|
if (currentKey && !line.includes("=")) {
|
|
3017
2947
|
currentValue += "\n" + line;
|
|
3018
2948
|
continue;
|
|
@@ -3023,20 +2953,15 @@ async function parseEnvFile(filePath) {
|
|
|
3023
2953
|
currentValue = "";
|
|
3024
2954
|
}
|
|
3025
2955
|
const equalIndex = line.indexOf("=");
|
|
3026
|
-
if (equalIndex === -1)
|
|
3027
|
-
continue;
|
|
3028
|
-
}
|
|
2956
|
+
if (equalIndex === -1) continue;
|
|
3029
2957
|
const key = line.substring(0, equalIndex).trim();
|
|
3030
|
-
|
|
2958
|
+
const value = line.substring(equalIndex + 1).trim();
|
|
3031
2959
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
3032
|
-
console.log(
|
|
3033
|
-
source_default.yellow(`\u26A0\uFE0F Skipping invalid environment variable key: ${key}`)
|
|
3034
|
-
);
|
|
2960
|
+
console.log(source_default.yellow(`\u26A0\uFE0F Skipping invalid env key: ${key}`));
|
|
3035
2961
|
continue;
|
|
3036
2962
|
}
|
|
3037
2963
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
3038
|
-
|
|
3039
|
-
envVars[key] = value;
|
|
2964
|
+
envVars[key] = value.slice(1, -1);
|
|
3040
2965
|
} else if (value.startsWith('"') || value.startsWith("'")) {
|
|
3041
2966
|
currentKey = key;
|
|
3042
2967
|
currentValue = value.slice(1);
|
|
@@ -3060,16 +2985,12 @@ async function parseEnvFile(filePath) {
|
|
|
3060
2985
|
function parseEnvVar(envStr) {
|
|
3061
2986
|
const equalIndex = envStr.indexOf("=");
|
|
3062
2987
|
if (equalIndex === -1) {
|
|
3063
|
-
throw new Error(
|
|
3064
|
-
`Invalid environment variable format: "${envStr}". Expected KEY=VALUE`
|
|
3065
|
-
);
|
|
2988
|
+
throw new Error(`Invalid env format: "${envStr}". Expected KEY=VALUE`);
|
|
3066
2989
|
}
|
|
3067
2990
|
const key = envStr.substring(0, equalIndex).trim();
|
|
3068
2991
|
const value = envStr.substring(equalIndex + 1);
|
|
3069
2992
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
3070
|
-
throw new Error(
|
|
3071
|
-
`Invalid environment variable key: "${key}". Keys must start with a letter or underscore and contain only letters, numbers, and underscores.`
|
|
3072
|
-
);
|
|
2993
|
+
throw new Error(`Invalid env key: "${key}".`);
|
|
3073
2994
|
}
|
|
3074
2995
|
return { key, value };
|
|
3075
2996
|
}
|
|
@@ -3112,72 +3033,48 @@ async function buildEnvVars(options) {
|
|
|
3112
3033
|
}
|
|
3113
3034
|
async function isMcpProject(cwd = process.cwd()) {
|
|
3114
3035
|
try {
|
|
3115
|
-
const
|
|
3116
|
-
const
|
|
3117
|
-
|
|
3118
|
-
const hasMcpDeps = packageJson2.dependencies?.["mcp-use"] || packageJson2.dependencies?.["@modelcontextprotocol/sdk"] || packageJson2.devDependencies?.["mcp-use"] || packageJson2.devDependencies?.["@modelcontextprotocol/sdk"];
|
|
3119
|
-
const hasMcpScripts = packageJson2.scripts?.mcp || packageJson2.scripts?.["mcp:dev"];
|
|
3120
|
-
return !!(hasMcpDeps || hasMcpScripts);
|
|
3036
|
+
const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
|
|
3037
|
+
const pkg = JSON.parse(content);
|
|
3038
|
+
return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
|
|
3121
3039
|
} catch {
|
|
3122
3040
|
return false;
|
|
3123
3041
|
}
|
|
3124
3042
|
}
|
|
3125
3043
|
async function getProjectName(cwd = process.cwd()) {
|
|
3126
3044
|
try {
|
|
3127
|
-
const
|
|
3128
|
-
const
|
|
3129
|
-
|
|
3130
|
-
if (packageJson2.name) {
|
|
3131
|
-
return packageJson2.name;
|
|
3132
|
-
}
|
|
3045
|
+
const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
|
|
3046
|
+
const pkg = JSON.parse(content);
|
|
3047
|
+
if (pkg.name) return pkg.name;
|
|
3133
3048
|
} catch {
|
|
3134
3049
|
}
|
|
3135
3050
|
return path5.basename(cwd);
|
|
3136
3051
|
}
|
|
3137
|
-
async function detectBuildCommand(cwd
|
|
3052
|
+
async function detectBuildCommand(cwd) {
|
|
3138
3053
|
try {
|
|
3139
|
-
const
|
|
3140
|
-
|
|
3141
|
-
const packageJson2 = JSON.parse(content);
|
|
3142
|
-
if (packageJson2.scripts?.build) {
|
|
3143
|
-
return "npm run build";
|
|
3144
|
-
}
|
|
3054
|
+
const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
|
|
3055
|
+
if (JSON.parse(content).scripts?.build) return "npm run build";
|
|
3145
3056
|
} catch {
|
|
3146
3057
|
}
|
|
3147
3058
|
return void 0;
|
|
3148
3059
|
}
|
|
3149
|
-
async function detectStartCommand(cwd
|
|
3060
|
+
async function detectStartCommand(cwd) {
|
|
3150
3061
|
try {
|
|
3151
|
-
const
|
|
3152
|
-
const
|
|
3153
|
-
|
|
3154
|
-
if (
|
|
3155
|
-
return "npm start";
|
|
3156
|
-
}
|
|
3157
|
-
if (packageJson2.main) {
|
|
3158
|
-
return `node ${packageJson2.main}`;
|
|
3159
|
-
}
|
|
3062
|
+
const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
|
|
3063
|
+
const pkg = JSON.parse(content);
|
|
3064
|
+
if (pkg.scripts?.start) return "npm start";
|
|
3065
|
+
if (pkg.main) return `node ${pkg.main}`;
|
|
3160
3066
|
} catch {
|
|
3161
3067
|
}
|
|
3162
3068
|
return void 0;
|
|
3163
3069
|
}
|
|
3164
|
-
async function detectRuntime(cwd
|
|
3165
|
-
|
|
3166
|
-
const pythonFiles = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
3167
|
-
for (const file of pythonFiles) {
|
|
3168
|
-
try {
|
|
3169
|
-
await fs9.access(path5.join(cwd, file));
|
|
3170
|
-
return "python";
|
|
3171
|
-
} catch {
|
|
3172
|
-
continue;
|
|
3173
|
-
}
|
|
3174
|
-
}
|
|
3070
|
+
async function detectRuntime(cwd) {
|
|
3071
|
+
for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
|
|
3175
3072
|
try {
|
|
3176
|
-
await fs9.access(path5.join(cwd,
|
|
3177
|
-
return "
|
|
3073
|
+
await fs9.access(path5.join(cwd, f));
|
|
3074
|
+
return "python";
|
|
3178
3075
|
} catch {
|
|
3076
|
+
continue;
|
|
3179
3077
|
}
|
|
3180
|
-
} catch {
|
|
3181
3078
|
}
|
|
3182
3079
|
return "node";
|
|
3183
3080
|
}
|
|
@@ -3187,50 +3084,64 @@ async function prompt(question, defaultValue = "n") {
|
|
|
3187
3084
|
input: process.stdin,
|
|
3188
3085
|
output: process.stdout
|
|
3189
3086
|
});
|
|
3190
|
-
const
|
|
3191
|
-
const
|
|
3192
|
-
/(\(y\/n\):)/,
|
|
3193
|
-
`(${defaultIndicator}):`
|
|
3194
|
-
);
|
|
3087
|
+
const indicator = defaultValue === "y" ? "Y/n" : "y/N";
|
|
3088
|
+
const q = question.replace(/(\(y\/n\):)/, `(${indicator}):`);
|
|
3195
3089
|
return new Promise((resolve2) => {
|
|
3196
|
-
rl.question(
|
|
3090
|
+
rl.question(q, (answer) => {
|
|
3197
3091
|
rl.close();
|
|
3198
|
-
const
|
|
3199
|
-
if (
|
|
3200
|
-
|
|
3201
|
-
} else {
|
|
3202
|
-
resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
|
|
3203
|
-
}
|
|
3092
|
+
const a = answer.trim().toLowerCase();
|
|
3093
|
+
if (a === "") resolve2(defaultValue === "y");
|
|
3094
|
+
else resolve2(a === "y" || a === "yes");
|
|
3204
3095
|
});
|
|
3205
3096
|
});
|
|
3206
3097
|
}
|
|
3207
|
-
function
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
}
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3098
|
+
async function promptText(question, defaultValue) {
|
|
3099
|
+
const readline = await import("readline");
|
|
3100
|
+
const rl = readline.createInterface({
|
|
3101
|
+
input: process.stdin,
|
|
3102
|
+
output: process.stdout
|
|
3103
|
+
});
|
|
3104
|
+
const suffix = defaultValue ? source_default.gray(` [${defaultValue}]`) : "";
|
|
3105
|
+
return new Promise((resolve2) => {
|
|
3106
|
+
rl.question(question + suffix + " ", (answer) => {
|
|
3107
|
+
rl.close();
|
|
3108
|
+
resolve2(answer.trim() || defaultValue || "");
|
|
3109
|
+
});
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
var REQUIRED_IGNORES = [
|
|
3113
|
+
"node_modules",
|
|
3114
|
+
"dist",
|
|
3115
|
+
".env",
|
|
3116
|
+
".env.local",
|
|
3117
|
+
".mcp-use"
|
|
3118
|
+
];
|
|
3119
|
+
async function ensureGitignore(cwd) {
|
|
3120
|
+
const gitignorePath = path5.join(cwd, ".gitignore");
|
|
3121
|
+
let content = "";
|
|
3122
|
+
try {
|
|
3123
|
+
content = await fs9.readFile(gitignorePath, "utf-8");
|
|
3124
|
+
} catch {
|
|
3125
|
+
}
|
|
3126
|
+
const missing = REQUIRED_IGNORES.filter((entry) => !content.includes(entry));
|
|
3127
|
+
if (missing.length > 0) {
|
|
3128
|
+
const additions = missing.join("\n");
|
|
3129
|
+
const newContent = content + (content.endsWith("\n") ? "" : "\n") + additions + "\n";
|
|
3130
|
+
await fs9.writeFile(gitignorePath, newContent, "utf-8");
|
|
3216
3131
|
}
|
|
3217
3132
|
}
|
|
3218
|
-
async function displayDeploymentProgress(api,
|
|
3133
|
+
async function displayDeploymentProgress(api, deploymentId, progressOptions) {
|
|
3219
3134
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3220
3135
|
let frameIndex = 0;
|
|
3221
3136
|
let spinnerInterval = null;
|
|
3222
|
-
let lastStep = "";
|
|
3223
3137
|
const startSpinner = (message) => {
|
|
3224
|
-
if (spinnerInterval)
|
|
3225
|
-
clearInterval(spinnerInterval);
|
|
3226
|
-
}
|
|
3138
|
+
if (spinnerInterval) clearInterval(spinnerInterval);
|
|
3227
3139
|
process.stdout.write("\r\x1B[K");
|
|
3228
3140
|
spinnerInterval = setInterval(() => {
|
|
3229
|
-
const frame = frames[frameIndex];
|
|
3230
|
-
frameIndex = (frameIndex + 1) % frames.length;
|
|
3231
3141
|
process.stdout.write(
|
|
3232
|
-
"\r" + source_default.cyan(
|
|
3142
|
+
"\r" + source_default.cyan(frames[frameIndex]) + " " + source_default.gray(message)
|
|
3233
3143
|
);
|
|
3144
|
+
frameIndex = (frameIndex + 1) % frames.length;
|
|
3234
3145
|
}, 80);
|
|
3235
3146
|
};
|
|
3236
3147
|
const stopSpinner = () => {
|
|
@@ -3242,82 +3153,56 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
|
|
|
3242
3153
|
};
|
|
3243
3154
|
console.log();
|
|
3244
3155
|
startSpinner("Deploying...");
|
|
3245
|
-
try {
|
|
3246
|
-
for await (const log of api.streamDeploymentLogs(deployment.id)) {
|
|
3247
|
-
try {
|
|
3248
|
-
const logData = JSON.parse(log);
|
|
3249
|
-
if (logData.step && logData.step !== lastStep) {
|
|
3250
|
-
lastStep = logData.step;
|
|
3251
|
-
const stepMessages = {
|
|
3252
|
-
clone: "Preparing source code...",
|
|
3253
|
-
analyze: "Analyzing project...",
|
|
3254
|
-
build: "Building container image...",
|
|
3255
|
-
deploy: "Deploying to cloud..."
|
|
3256
|
-
};
|
|
3257
|
-
const message = stepMessages[logData.step] || "Deploying...";
|
|
3258
|
-
startSpinner(message);
|
|
3259
|
-
}
|
|
3260
|
-
if (logData.line) {
|
|
3261
|
-
stopSpinner();
|
|
3262
|
-
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
3263
|
-
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
3264
|
-
console.log(stepPrefix + levelColor(logData.line));
|
|
3265
|
-
}
|
|
3266
|
-
} catch {
|
|
3267
|
-
}
|
|
3268
|
-
}
|
|
3269
|
-
} catch (error) {
|
|
3270
|
-
stopSpinner();
|
|
3271
|
-
}
|
|
3272
3156
|
let checkCount = 0;
|
|
3273
|
-
const maxChecks =
|
|
3274
|
-
let delay =
|
|
3157
|
+
const maxChecks = 120;
|
|
3158
|
+
let delay = 2e3;
|
|
3275
3159
|
const maxDelay = 1e4;
|
|
3276
|
-
let
|
|
3160
|
+
let buildLogOffset = 0;
|
|
3277
3161
|
while (checkCount < maxChecks) {
|
|
3278
|
-
const
|
|
3279
|
-
await new Promise((
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
const
|
|
3283
|
-
|
|
3162
|
+
const waitMs = delay;
|
|
3163
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
3164
|
+
checkCount++;
|
|
3165
|
+
try {
|
|
3166
|
+
const resp = await api.getDeploymentBuildLogs(
|
|
3167
|
+
deploymentId,
|
|
3168
|
+
buildLogOffset
|
|
3284
3169
|
);
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3170
|
+
if (resp.logs.length > 0) {
|
|
3171
|
+
for (const line of resp.logs.split("\n").filter((l) => l.trim())) {
|
|
3172
|
+
try {
|
|
3173
|
+
const d = JSON.parse(line);
|
|
3174
|
+
if (d.line) {
|
|
3175
|
+
stopSpinner();
|
|
3176
|
+
const color = d.level === "error" ? source_default.red : d.level === "warn" ? source_default.yellow : source_default.gray;
|
|
3177
|
+
const prefix = d.step ? source_default.cyan(`[${d.step}]`) + " " : "";
|
|
3178
|
+
console.log(prefix + color(d.line));
|
|
3179
|
+
}
|
|
3180
|
+
} catch {
|
|
3290
3181
|
stopSpinner();
|
|
3291
|
-
|
|
3292
|
-
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
3293
|
-
console.log(stepPrefix + levelColor(logData.line));
|
|
3182
|
+
console.log(source_default.gray(line));
|
|
3294
3183
|
}
|
|
3295
|
-
} catch {
|
|
3296
3184
|
}
|
|
3185
|
+
buildLogOffset = resp.offset;
|
|
3297
3186
|
}
|
|
3298
|
-
|
|
3187
|
+
} catch {
|
|
3299
3188
|
}
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3189
|
+
const dep = await api.getDeployment(deploymentId);
|
|
3190
|
+
if (dep.status === "running") {
|
|
3191
|
+
stopSpinner();
|
|
3192
|
+
const mcpUrl = getMcpServerUrl(dep);
|
|
3303
3193
|
const webUrl = (await getWebUrl()).replace(/\/$/, "");
|
|
3304
3194
|
const config = await readConfig();
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
if (orgSlug) {
|
|
3309
|
-
dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${serverRef}`;
|
|
3310
|
-
} else {
|
|
3311
|
-
dashboardUrl = `${webUrl}/cloud/servers/${serverRef}`;
|
|
3312
|
-
}
|
|
3195
|
+
let dashboardUrl = null;
|
|
3196
|
+
if (dep.serverId) {
|
|
3197
|
+
dashboardUrl = config.orgSlug ? `${webUrl}/cloud/${config.orgSlug}/servers/${dep.serverId}` : `${webUrl}/cloud/servers/${dep.serverId}`;
|
|
3313
3198
|
}
|
|
3314
|
-
const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
|
|
3315
|
-
mcpServerUrl
|
|
3316
|
-
)}`;
|
|
3199
|
+
const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(mcpUrl)}`;
|
|
3317
3200
|
console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
|
|
3318
|
-
|
|
3319
|
-
|
|
3201
|
+
if (mcpUrl) {
|
|
3202
|
+
console.log(source_default.white("\u{1F310} MCP Server URL:"));
|
|
3203
|
+
console.log(source_default.cyan.bold(` ${mcpUrl}
|
|
3320
3204
|
`));
|
|
3205
|
+
}
|
|
3321
3206
|
if (dashboardUrl) {
|
|
3322
3207
|
console.log(source_default.white("\u{1F4CA} Dashboard:"));
|
|
3323
3208
|
console.log(source_default.cyan.bold(` ${dashboardUrl}
|
|
@@ -3326,169 +3211,76 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
|
|
|
3326
3211
|
console.log(source_default.white("\u{1F50D} Inspector URL:"));
|
|
3327
3212
|
console.log(source_default.cyan.bold(` ${inspectorUrl}
|
|
3328
3213
|
`));
|
|
3329
|
-
console.log(
|
|
3330
|
-
source_default.gray("Deployment ID: ") + source_default.white(finalDeployment.id)
|
|
3331
|
-
);
|
|
3214
|
+
console.log(source_default.gray("Deployment ID: ") + source_default.white(dep.id));
|
|
3332
3215
|
return;
|
|
3333
|
-
} else if (
|
|
3216
|
+
} else if (dep.status === "failed") {
|
|
3334
3217
|
stopSpinner();
|
|
3335
3218
|
console.log(source_default.red.bold("\u2717 Deployment failed\n"));
|
|
3336
|
-
if (
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
)
|
|
3354
|
-
return;
|
|
3355
|
-
}
|
|
3356
|
-
} else if (finalDeployment.error.includes("Authenticated git clone failed")) {
|
|
3357
|
-
let repoName;
|
|
3358
|
-
const repoMatch = finalDeployment.error.match(
|
|
3359
|
-
/github\.com\/([^/]+\/[^/\s]+)/
|
|
3360
|
-
);
|
|
3361
|
-
if (repoMatch) {
|
|
3362
|
-
repoName = repoMatch[1].replace(/\.git$/, "");
|
|
3363
|
-
} else if (finalDeployment.source.type === "github") {
|
|
3364
|
-
repoName = finalDeployment.source.repo;
|
|
3365
|
-
}
|
|
3366
|
-
console.log();
|
|
3367
|
-
const retry = await promptGitHubInstallation(
|
|
3368
|
-
api,
|
|
3369
|
-
"no_access",
|
|
3370
|
-
repoName,
|
|
3371
|
-
{ yes: progressOptions?.yes }
|
|
3219
|
+
if (dep.error) {
|
|
3220
|
+
const internalPatterns = [
|
|
3221
|
+
"GraphQL",
|
|
3222
|
+
"authenticated",
|
|
3223
|
+
"INTERNAL",
|
|
3224
|
+
"Fly API",
|
|
3225
|
+
"token validation",
|
|
3226
|
+
"context deadline",
|
|
3227
|
+
"Bad gateway",
|
|
3228
|
+
"502",
|
|
3229
|
+
"503"
|
|
3230
|
+
];
|
|
3231
|
+
const isInternalError = internalPatterns.some(
|
|
3232
|
+
(p) => dep.error.includes(p)
|
|
3233
|
+
);
|
|
3234
|
+
if (isInternalError) {
|
|
3235
|
+
console.log(
|
|
3236
|
+
source_default.red("Error: ") + "An internal infrastructure error occurred. Please try again."
|
|
3372
3237
|
);
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
await displayDeploymentProgress(
|
|
3377
|
-
api,
|
|
3378
|
-
newDeployment,
|
|
3379
|
-
progressOptions
|
|
3380
|
-
);
|
|
3381
|
-
return;
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
3384
|
-
}
|
|
3385
|
-
if (finalDeployment.buildLogs) {
|
|
3386
|
-
console.log(source_default.gray("\nBuild logs:"));
|
|
3387
|
-
try {
|
|
3388
|
-
const logs = finalDeployment.buildLogs.split("\n").filter((l) => l.trim());
|
|
3389
|
-
for (const log of logs) {
|
|
3390
|
-
try {
|
|
3391
|
-
const logData = JSON.parse(log);
|
|
3392
|
-
if (logData.line) {
|
|
3393
|
-
console.log(source_default.gray(` ${logData.line}`));
|
|
3394
|
-
}
|
|
3395
|
-
} catch {
|
|
3396
|
-
console.log(source_default.gray(` ${log}`));
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
} catch {
|
|
3400
|
-
console.log(source_default.gray(finalDeployment.buildLogs));
|
|
3238
|
+
console.log(source_default.gray(" Details: " + dep.error));
|
|
3239
|
+
} else {
|
|
3240
|
+
console.log(source_default.red("Error: ") + dep.error);
|
|
3401
3241
|
}
|
|
3402
3242
|
}
|
|
3403
3243
|
process.exit(1);
|
|
3404
|
-
} else if (
|
|
3244
|
+
} else if (dep.status === "building" || dep.status === "pending") {
|
|
3405
3245
|
startSpinner("Building and deploying...");
|
|
3406
|
-
checkCount++;
|
|
3407
3246
|
delay = Math.min(delay * 1.2, maxDelay);
|
|
3408
3247
|
} else {
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
);
|
|
3248
|
+
stopSpinner();
|
|
3249
|
+
console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + dep.status);
|
|
3412
3250
|
return;
|
|
3413
3251
|
}
|
|
3414
3252
|
}
|
|
3415
3253
|
stopSpinner();
|
|
3416
3254
|
console.log(source_default.yellow("\u26A0\uFE0F Deployment is taking longer than expected."));
|
|
3417
3255
|
console.log(
|
|
3418
|
-
source_default.gray("Check status with: ") + source_default.white(`mcp-use
|
|
3256
|
+
source_default.gray("Check status with: ") + source_default.white(`mcp-use deployments get ${deploymentId}`)
|
|
3419
3257
|
);
|
|
3420
3258
|
}
|
|
3421
3259
|
async function checkRepoAccess(api, owner, repo) {
|
|
3422
3260
|
try {
|
|
3423
|
-
const
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
} catch (error) {
|
|
3427
|
-
console.log(source_default.gray("Could not verify repository access"));
|
|
3261
|
+
const resp = await api.getGitHubRepos(true);
|
|
3262
|
+
return resp.repos.some((r) => r.full_name === `${owner}/${repo}`);
|
|
3263
|
+
} catch {
|
|
3428
3264
|
return false;
|
|
3429
3265
|
}
|
|
3430
3266
|
}
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
if (
|
|
3435
|
-
console.log(source_default.
|
|
3436
|
-
|
|
3437
|
-
source_default.white("
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
while (Date.now() < deadline) {
|
|
3449
|
-
try {
|
|
3450
|
-
const status = await api.getGitHubConnectionStatus();
|
|
3451
|
-
if (!status.is_connected) {
|
|
3452
|
-
await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
|
|
3453
|
-
continue;
|
|
3454
|
-
}
|
|
3455
|
-
if (repoName) {
|
|
3456
|
-
const parts = repoName.split("/");
|
|
3457
|
-
const owner = parts[0];
|
|
3458
|
-
const repo = parts[1];
|
|
3459
|
-
if (owner && repo && await checkRepoAccess(api, owner, repo)) {
|
|
3460
|
-
return;
|
|
3461
|
-
}
|
|
3462
|
-
} else {
|
|
3463
|
-
return;
|
|
3464
|
-
}
|
|
3465
|
-
} catch {
|
|
3466
|
-
}
|
|
3467
|
-
await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
|
|
3468
|
-
}
|
|
3469
|
-
console.log(
|
|
3470
|
-
source_default.yellow(
|
|
3471
|
-
"\u26A0\uFE0F Timed out waiting for GitHub setup. Continuing with verification..."
|
|
3472
|
-
)
|
|
3473
|
-
);
|
|
3474
|
-
}
|
|
3475
|
-
async function promptGitHubInstallation(api, reason, repoName, opts) {
|
|
3476
|
-
const yes = !!opts?.yes;
|
|
3477
|
-
console.log();
|
|
3478
|
-
if (reason === "not_connected") {
|
|
3479
|
-
console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
|
|
3480
|
-
console.log(
|
|
3481
|
-
source_default.white("Deployments require a connected GitHub account.\n")
|
|
3482
|
-
);
|
|
3483
|
-
} else {
|
|
3484
|
-
console.log(
|
|
3485
|
-
source_default.yellow("\u26A0\uFE0F GitHub App doesn't have access to this repository")
|
|
3486
|
-
);
|
|
3487
|
-
console.log(
|
|
3488
|
-
source_default.white(
|
|
3489
|
-
`The GitHub App needs permission to access ${source_default.cyan(repoName || "this repository")}.
|
|
3490
|
-
`
|
|
3491
|
-
)
|
|
3267
|
+
async function promptGitHubInstallation(api, reason, repoName, opts) {
|
|
3268
|
+
const yes = !!opts?.yes;
|
|
3269
|
+
console.log();
|
|
3270
|
+
if (reason === "not_connected") {
|
|
3271
|
+
console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
|
|
3272
|
+
console.log(
|
|
3273
|
+
source_default.white("Deployments require a connected GitHub account.\n")
|
|
3274
|
+
);
|
|
3275
|
+
} else {
|
|
3276
|
+
console.log(
|
|
3277
|
+
source_default.yellow("\u26A0\uFE0F GitHub App doesn't have access to this repository")
|
|
3278
|
+
);
|
|
3279
|
+
console.log(
|
|
3280
|
+
source_default.white(
|
|
3281
|
+
`The GitHub App needs permission to access ${source_default.cyan(repoName || "this repository")}.
|
|
3282
|
+
`
|
|
3283
|
+
)
|
|
3492
3284
|
);
|
|
3493
3285
|
}
|
|
3494
3286
|
const shouldInstall = yes ? true : await prompt(
|
|
@@ -3497,96 +3289,48 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
|
|
|
3497
3289
|
),
|
|
3498
3290
|
"y"
|
|
3499
3291
|
);
|
|
3500
|
-
if (!shouldInstall)
|
|
3501
|
-
return false;
|
|
3502
|
-
}
|
|
3292
|
+
if (!shouldInstall) return false;
|
|
3503
3293
|
try {
|
|
3504
|
-
const appName =
|
|
3505
|
-
const installUrl =
|
|
3506
|
-
console.log(
|
|
3507
|
-
|
|
3508
|
-
`
|
|
3509
|
-
Opening browser to ${reason === "not_connected" ? "install" : "configure"} GitHub App...`
|
|
3510
|
-
)
|
|
3511
|
-
);
|
|
3294
|
+
const appName = await api.getGitHubAppName();
|
|
3295
|
+
const installUrl = `https://github.com/apps/${appName}/installations/new`;
|
|
3296
|
+
console.log(source_default.cyan(`
|
|
3297
|
+
Opening browser...`));
|
|
3512
3298
|
console.log(source_default.gray(`URL: ${installUrl}
|
|
3513
3299
|
`));
|
|
3514
3300
|
if (reason === "no_access") {
|
|
3515
|
-
console.log(source_default.white("Please:"));
|
|
3516
3301
|
console.log(
|
|
3517
|
-
source_default.cyan("
|
|
3302
|
+
source_default.white("Please add ") + source_default.cyan.bold(repoName || "your repository") + source_default.white(" to the app's repository access, then return here.\n")
|
|
3518
3303
|
);
|
|
3519
|
-
|
|
3304
|
+
} else {
|
|
3520
3305
|
console.log(
|
|
3521
|
-
source_default.
|
|
3522
|
-
` 3. Grant access to ${source_default.bold(repoName || "your repository")}`
|
|
3523
|
-
)
|
|
3306
|
+
source_default.white("Complete the GitHub App installation, then return here.\n")
|
|
3524
3307
|
);
|
|
3525
|
-
console.log(source_default.cyan(" 4. Save your changes"));
|
|
3526
|
-
console.log(source_default.cyan(" 5. Return here when done\n"));
|
|
3527
|
-
} else {
|
|
3528
|
-
console.log(source_default.white("Please:"));
|
|
3529
|
-
console.log(source_default.cyan(" 1. Select the repositories to grant access"));
|
|
3530
|
-
if (repoName) {
|
|
3531
|
-
console.log(
|
|
3532
|
-
source_default.cyan(` 2. Make sure to include ${source_default.bold(repoName)}`)
|
|
3533
|
-
);
|
|
3534
|
-
console.log(source_default.cyan(" 3. Complete the installation"));
|
|
3535
|
-
} else {
|
|
3536
|
-
console.log(source_default.cyan(" 2. Complete the installation"));
|
|
3537
|
-
}
|
|
3538
|
-
console.log();
|
|
3539
3308
|
}
|
|
3540
3309
|
await open_default(installUrl);
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
)
|
|
3557
|
-
);
|
|
3558
|
-
} else {
|
|
3559
|
-
console.log(source_default.green(`\u2713 Repository ${repoName} is accessible!
|
|
3560
|
-
`));
|
|
3561
|
-
verified = true;
|
|
3310
|
+
if (!yes) {
|
|
3311
|
+
await prompt(source_default.white("Press Enter when done..."), "y");
|
|
3312
|
+
} else {
|
|
3313
|
+
console.log(source_default.gray("Waiting for GitHub configuration (polling)..."));
|
|
3314
|
+
const deadline = Date.now() + 12e4;
|
|
3315
|
+
while (Date.now() < deadline) {
|
|
3316
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
3317
|
+
try {
|
|
3318
|
+
const status = await api.getGitHubConnectionStatus();
|
|
3319
|
+
if (status.is_connected) {
|
|
3320
|
+
if (!repoName) return true;
|
|
3321
|
+
const [o, r] = repoName.split("/");
|
|
3322
|
+
if (o && r && await checkRepoAccess(api, o, r)) return true;
|
|
3323
|
+
}
|
|
3324
|
+
} catch {
|
|
3562
3325
|
}
|
|
3563
|
-
} else {
|
|
3564
|
-
console.log(source_default.green("\u2713 GitHub connected successfully!\n"));
|
|
3565
|
-
verified = true;
|
|
3566
3326
|
}
|
|
3567
|
-
} catch (error) {
|
|
3568
|
-
console.log(
|
|
3569
|
-
source_default.yellow("\u26A0\uFE0F Could not verify GitHub connection (API issue)")
|
|
3570
|
-
);
|
|
3571
|
-
}
|
|
3572
|
-
if (!verified) {
|
|
3573
|
-
console.log(
|
|
3574
|
-
source_default.gray(
|
|
3575
|
-
"\nNote: If you completed the GitHub setup, the deployment may work now.\n"
|
|
3576
|
-
)
|
|
3577
|
-
);
|
|
3578
3327
|
}
|
|
3579
3328
|
return true;
|
|
3580
|
-
} catch
|
|
3581
|
-
console.log(
|
|
3582
|
-
source_default.yellow("\n\u26A0\uFE0F Unable to open GitHub installation automatically")
|
|
3583
|
-
);
|
|
3329
|
+
} catch {
|
|
3330
|
+
console.log(source_default.yellow("\n\u26A0\uFE0F Unable to open browser automatically"));
|
|
3584
3331
|
console.log(
|
|
3585
3332
|
source_default.white("Please visit: ") + source_default.cyan("https://manufact.com/cloud/settings")
|
|
3586
3333
|
);
|
|
3587
|
-
console.log(
|
|
3588
|
-
source_default.gray("Then connect your GitHub account and try again.\n")
|
|
3589
|
-
);
|
|
3590
3334
|
return false;
|
|
3591
3335
|
}
|
|
3592
3336
|
}
|
|
@@ -3594,47 +3338,139 @@ async function deployCommand(options) {
|
|
|
3594
3338
|
try {
|
|
3595
3339
|
const cwd = process.cwd();
|
|
3596
3340
|
if (!await isLoggedIn()) {
|
|
3597
|
-
console.log(source_default.
|
|
3341
|
+
console.log(source_default.cyan.bold("Welcome to Manufact Cloud!\n"));
|
|
3598
3342
|
if (options.yes) {
|
|
3599
3343
|
console.log(
|
|
3600
|
-
source_default.
|
|
3601
|
-
"Run " + source_default.white("npx mcp-use login") + " first.
|
|
3344
|
+
source_default.red(
|
|
3345
|
+
"\u2717 Not logged in. Run " + source_default.white("npx mcp-use login") + " first."
|
|
3602
3346
|
)
|
|
3603
3347
|
);
|
|
3604
3348
|
process.exit(1);
|
|
3605
3349
|
}
|
|
3606
3350
|
const shouldLogin = await prompt(
|
|
3607
|
-
source_default.white("
|
|
3351
|
+
source_default.white("You need to log in to deploy. Log in now? (Y/n): "),
|
|
3608
3352
|
"y"
|
|
3609
3353
|
);
|
|
3610
|
-
if (shouldLogin) {
|
|
3611
|
-
try {
|
|
3612
|
-
await loginCommand({ silent: false });
|
|
3613
|
-
if (!await isLoggedIn()) {
|
|
3614
|
-
console.log(
|
|
3615
|
-
source_default.red("\u2717 Login verification failed. Please try again.")
|
|
3616
|
-
);
|
|
3617
|
-
process.exit(1);
|
|
3618
|
-
}
|
|
3619
|
-
console.log(source_default.gray("\nContinuing with deployment...\n"));
|
|
3620
|
-
} catch (error) {
|
|
3621
|
-
console.error(
|
|
3622
|
-
source_default.red.bold("\u2717 Login failed:"),
|
|
3623
|
-
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
3624
|
-
);
|
|
3625
|
-
process.exit(1);
|
|
3626
|
-
}
|
|
3627
|
-
} else {
|
|
3354
|
+
if (!shouldLogin) {
|
|
3628
3355
|
console.log(
|
|
3629
3356
|
source_default.gray(
|
|
3630
3357
|
"Run " + source_default.white("npx mcp-use login") + " to get started."
|
|
3631
3358
|
)
|
|
3632
3359
|
);
|
|
3360
|
+
process.exit(0);
|
|
3361
|
+
}
|
|
3362
|
+
try {
|
|
3363
|
+
await loginCommand({ silent: false });
|
|
3364
|
+
if (!await isLoggedIn()) {
|
|
3365
|
+
console.log(source_default.red("\u2717 Login failed. Please try again."));
|
|
3366
|
+
process.exit(1);
|
|
3367
|
+
}
|
|
3368
|
+
console.log(source_default.gray("\nContinuing with deployment...\n"));
|
|
3369
|
+
} catch (error) {
|
|
3370
|
+
console.error(
|
|
3371
|
+
source_default.red.bold("\u2717 Login failed:"),
|
|
3372
|
+
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
3373
|
+
);
|
|
3374
|
+
process.exit(1);
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
const api = await McpUseAPI.create();
|
|
3378
|
+
if (options.org) {
|
|
3379
|
+
const authInfo = await api.testAuth();
|
|
3380
|
+
const match = (authInfo.orgs ?? []).find(
|
|
3381
|
+
(o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
|
|
3382
|
+
);
|
|
3383
|
+
if (match) {
|
|
3384
|
+
api.setOrgId(match.id);
|
|
3385
|
+
const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
|
|
3386
|
+
console.log(
|
|
3387
|
+
source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
|
|
3388
|
+
);
|
|
3389
|
+
} else {
|
|
3390
|
+
console.error(
|
|
3391
|
+
source_default.red(
|
|
3392
|
+
`\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
|
|
3393
|
+
)
|
|
3394
|
+
);
|
|
3395
|
+
process.exit(1);
|
|
3396
|
+
}
|
|
3397
|
+
} else {
|
|
3398
|
+
const config = await readConfig();
|
|
3399
|
+
if (!config.orgId) {
|
|
3400
|
+
const authInfo = await api.testAuth();
|
|
3401
|
+
if (authInfo.orgs.length === 0) {
|
|
3402
|
+
console.log(
|
|
3403
|
+
source_default.red(
|
|
3404
|
+
"\u2717 No organizations found. Please create one at manufact.com/cloud."
|
|
3405
|
+
)
|
|
3406
|
+
);
|
|
3407
|
+
process.exit(1);
|
|
3408
|
+
}
|
|
3409
|
+
let selectedOrg;
|
|
3410
|
+
if (authInfo.orgs.length === 1) {
|
|
3411
|
+
selectedOrg = authInfo.orgs[0];
|
|
3412
|
+
} else {
|
|
3413
|
+
selectedOrg = await promptOrgSelection(
|
|
3414
|
+
authInfo.orgs,
|
|
3415
|
+
authInfo.default_org_id
|
|
3416
|
+
);
|
|
3417
|
+
}
|
|
3418
|
+
if (!selectedOrg) {
|
|
3419
|
+
console.log(source_default.red("\u2717 No organization selected."));
|
|
3420
|
+
process.exit(1);
|
|
3421
|
+
}
|
|
3422
|
+
api.setOrgId(selectedOrg.id);
|
|
3423
|
+
await writeConfig({
|
|
3424
|
+
...config,
|
|
3425
|
+
orgId: selectedOrg.id,
|
|
3426
|
+
orgName: selectedOrg.name,
|
|
3427
|
+
orgSlug: selectedOrg.slug ?? void 0
|
|
3428
|
+
});
|
|
3429
|
+
console.log(
|
|
3430
|
+
source_default.gray("Organization: ") + source_default.cyan(selectedOrg.name)
|
|
3431
|
+
);
|
|
3432
|
+
} else {
|
|
3433
|
+
if (config.orgName) {
|
|
3434
|
+
const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
|
|
3435
|
+
console.log(
|
|
3436
|
+
source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
|
|
3437
|
+
);
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
console.log(source_default.cyan.bold("\n\u{1F680} Deploying to Manufact cloud...\n"));
|
|
3442
|
+
let connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
|
|
3443
|
+
if (!connectionStatus?.is_connected) {
|
|
3444
|
+
const installed = await promptGitHubInstallation(
|
|
3445
|
+
api,
|
|
3446
|
+
"not_connected",
|
|
3447
|
+
void 0,
|
|
3448
|
+
{ yes: options.yes }
|
|
3449
|
+
);
|
|
3450
|
+
if (!installed) {
|
|
3633
3451
|
console.log(source_default.gray("Deployment cancelled."));
|
|
3634
3452
|
process.exit(0);
|
|
3635
3453
|
}
|
|
3454
|
+
connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
|
|
3455
|
+
if (!connectionStatus?.is_connected) {
|
|
3456
|
+
console.log(source_default.red("\n\u2717 GitHub connection could not be verified."));
|
|
3457
|
+
console.log(
|
|
3458
|
+
source_default.cyan(
|
|
3459
|
+
" Visit https://manufact.com/cloud/settings to connect GitHub.\n"
|
|
3460
|
+
)
|
|
3461
|
+
);
|
|
3462
|
+
process.exit(1);
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
const installations = connectionStatus.installations ?? [];
|
|
3466
|
+
if (installations.length === 0) {
|
|
3467
|
+
console.log(source_default.red("\u2717 No GitHub installations found."));
|
|
3468
|
+
process.exit(1);
|
|
3636
3469
|
}
|
|
3637
|
-
|
|
3470
|
+
const defaultInstallation = installations.find((i) => i.account_type === "Organization") ?? installations[0];
|
|
3471
|
+
const installationDbId = defaultInstallation.id;
|
|
3472
|
+
const githubInstallationId = defaultInstallation.installation_id;
|
|
3473
|
+
console.log(source_default.green("\u2713 GitHub connected\n"));
|
|
3638
3474
|
const projectDir = options.rootDir ? path5.resolve(cwd, options.rootDir) : cwd;
|
|
3639
3475
|
if (options.rootDir) {
|
|
3640
3476
|
try {
|
|
@@ -3645,381 +3481,383 @@ async function deployCommand(options) {
|
|
|
3645
3481
|
);
|
|
3646
3482
|
process.exit(1);
|
|
3647
3483
|
}
|
|
3648
|
-
console.log(source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir));
|
|
3649
3484
|
}
|
|
3650
3485
|
const isMcp = await isMcpProject(projectDir);
|
|
3651
|
-
if (!isMcp) {
|
|
3486
|
+
if (!isMcp && !options.yes) {
|
|
3652
3487
|
console.log(
|
|
3653
|
-
source_default.yellow(
|
|
3654
|
-
|
|
3655
|
-
|
|
3488
|
+
source_default.yellow("\u26A0\uFE0F This doesn't look like an MCP server project.")
|
|
3489
|
+
);
|
|
3490
|
+
const shouldContinue = await prompt(
|
|
3491
|
+
source_default.white("Continue anyway? (y/n): ")
|
|
3656
3492
|
);
|
|
3657
|
-
if (!
|
|
3658
|
-
|
|
3659
|
-
|
|
3493
|
+
if (!shouldContinue) {
|
|
3494
|
+
process.exit(0);
|
|
3495
|
+
}
|
|
3496
|
+
console.log();
|
|
3497
|
+
}
|
|
3498
|
+
let gitInfo = await getGitInfo(cwd);
|
|
3499
|
+
let repoFullName;
|
|
3500
|
+
let branch = "main";
|
|
3501
|
+
if (!gitInfo.isGitRepo || !gitInfo.remoteUrl) {
|
|
3502
|
+
const projectName2 = options.name || await getProjectName(projectDir);
|
|
3503
|
+
console.log(source_default.yellow("\u26A0\uFE0F No GitHub remote found.\n"));
|
|
3504
|
+
if (options.yes) {
|
|
3505
|
+
console.log(source_default.gray("Creating GitHub repository automatically..."));
|
|
3506
|
+
} else {
|
|
3507
|
+
const shouldCreate = await prompt(
|
|
3508
|
+
source_default.white("Create a GitHub repository and push your code? (Y/n): "),
|
|
3509
|
+
"y"
|
|
3660
3510
|
);
|
|
3661
|
-
if (!
|
|
3662
|
-
console.log(
|
|
3511
|
+
if (!shouldCreate) {
|
|
3512
|
+
console.log(
|
|
3513
|
+
source_default.gray(
|
|
3514
|
+
"Deployment cancelled. Set up a GitHub remote and try again."
|
|
3515
|
+
)
|
|
3516
|
+
);
|
|
3663
3517
|
process.exit(0);
|
|
3664
3518
|
}
|
|
3665
3519
|
}
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3520
|
+
const defaultIdx = installations.findIndex(
|
|
3521
|
+
(i) => i.account_type === "Organization"
|
|
3522
|
+
);
|
|
3523
|
+
let selectedIdx = defaultIdx >= 0 ? defaultIdx : 0;
|
|
3524
|
+
if (installations.length > 1 && !options.yes) {
|
|
3525
|
+
console.log(
|
|
3526
|
+
source_default.cyan.bold("\u{1F419} Select a GitHub account for the repository:\n")
|
|
3527
|
+
);
|
|
3528
|
+
for (let i = 0; i < installations.length; i++) {
|
|
3529
|
+
const inst = installations[i];
|
|
3530
|
+
const typeLabel = inst.account_type === "Organization" ? source_default.gray(" (org)") : source_default.gray(" (personal)");
|
|
3531
|
+
const marker = i === selectedIdx ? source_default.green(" \u2190 default") : "";
|
|
3532
|
+
console.log(
|
|
3533
|
+
` ${source_default.white(`${i + 1}.`)} ${inst.account_login}${typeLabel}${marker}`
|
|
3534
|
+
);
|
|
3535
|
+
}
|
|
3536
|
+
console.log();
|
|
3537
|
+
const readline = await import("readline");
|
|
3538
|
+
const rl = readline.createInterface({
|
|
3539
|
+
input: process.stdin,
|
|
3540
|
+
output: process.stdout
|
|
3541
|
+
});
|
|
3542
|
+
const answer = await new Promise((resolve2) => {
|
|
3543
|
+
rl.question(
|
|
3544
|
+
source_default.gray(`Enter number [${selectedIdx + 1}]: `),
|
|
3545
|
+
(a) => {
|
|
3546
|
+
rl.close();
|
|
3547
|
+
resolve2(a.trim());
|
|
3548
|
+
}
|
|
3549
|
+
);
|
|
3550
|
+
});
|
|
3551
|
+
const parsed = answer === "" ? selectedIdx : parseInt(answer, 10) - 1;
|
|
3552
|
+
if (parsed >= 0 && parsed < installations.length) {
|
|
3553
|
+
selectedIdx = parsed;
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
const repoInstallation = installations[selectedIdx];
|
|
3557
|
+
if (repoInstallation.account_type !== "Organization") {
|
|
3558
|
+
console.log(
|
|
3559
|
+
source_default.yellow(
|
|
3560
|
+
"\n\u26A0\uFE0F GitHub Apps cannot create repos on personal accounts.\n"
|
|
3561
|
+
)
|
|
3562
|
+
);
|
|
3563
|
+
console.log(
|
|
3564
|
+
source_default.white("To deploy from ") + source_default.cyan(repoInstallation.account_login) + source_default.white(", create a repository manually:\n")
|
|
3565
|
+
);
|
|
3566
|
+
console.log(
|
|
3567
|
+
source_default.cyan(" 1. ") + source_default.white("Go to ") + source_default.cyan("https://github.com/new")
|
|
3568
|
+
);
|
|
3569
|
+
console.log(
|
|
3570
|
+
source_default.cyan(" 2. ") + source_default.white("Create a repository (any name, can be private)")
|
|
3571
|
+
);
|
|
3572
|
+
console.log(source_default.cyan(" 3. ") + source_default.white("Add it as a remote:"));
|
|
3573
|
+
console.log(source_default.gray(" git init && git remote add origin <url>"));
|
|
3574
|
+
console.log(source_default.cyan(" 4. ") + source_default.white("Push your code:"));
|
|
3575
|
+
console.log(
|
|
3576
|
+
source_default.gray(
|
|
3577
|
+
" git add . && git commit -m 'Initial commit' && git push -u origin main"
|
|
3578
|
+
)
|
|
3579
|
+
);
|
|
3580
|
+
console.log(
|
|
3581
|
+
source_default.cyan(" 5. ") + source_default.white("Grant the GitHub App access to the repo:")
|
|
3582
|
+
);
|
|
3583
|
+
const appName = await api.getGitHubAppName();
|
|
3584
|
+
console.log(
|
|
3585
|
+
source_default.gray(
|
|
3586
|
+
` https://github.com/apps/${appName}/installations/new`
|
|
3587
|
+
)
|
|
3588
|
+
);
|
|
3589
|
+
console.log(
|
|
3590
|
+
source_default.cyan(" 6. ") + source_default.white("Run ") + source_default.cyan("mcp-use deploy") + source_default.white(" again\n")
|
|
3591
|
+
);
|
|
3592
|
+
process.exit(0);
|
|
3593
|
+
}
|
|
3594
|
+
const repoName = options.yes ? projectName2 : await promptText(source_default.gray("Repository name:"), projectName2);
|
|
3595
|
+
await ensureGitignore(cwd);
|
|
3596
|
+
console.log(
|
|
3597
|
+
source_default.gray(
|
|
3598
|
+
`Creating repository on ${repoInstallation.account_login}...`
|
|
3599
|
+
)
|
|
3600
|
+
);
|
|
3601
|
+
const repoResult = await api.createGitHubRepo({
|
|
3602
|
+
installationId: repoInstallation.installation_id,
|
|
3603
|
+
name: repoName,
|
|
3604
|
+
private: true,
|
|
3605
|
+
org: repoInstallation.account_login
|
|
3606
|
+
});
|
|
3607
|
+
console.log(source_default.green(`\u2713 Created ${source_default.cyan(repoResult.fullName)}`));
|
|
3608
|
+
if (!gitInfo.isGitRepo) {
|
|
3609
|
+
console.log(source_default.gray("Initializing git..."));
|
|
3610
|
+
await gitInit(cwd, "Initial commit");
|
|
3611
|
+
console.log(source_default.gray("Pushing to GitHub..."));
|
|
3612
|
+
await gitAddRemoteAndPush(cwd, repoResult.cloneUrl, "main");
|
|
3613
|
+
} else {
|
|
3614
|
+
console.log(source_default.gray("Adding remote and pushing..."));
|
|
3615
|
+
await gitAddRemoteAndPush(
|
|
3616
|
+
cwd,
|
|
3617
|
+
repoResult.cloneUrl,
|
|
3618
|
+
gitInfo.branch || "main"
|
|
3619
|
+
);
|
|
3620
|
+
}
|
|
3621
|
+
console.log(source_default.green("\u2713 Code pushed to GitHub\n"));
|
|
3622
|
+
gitInfo = await getGitInfo(cwd);
|
|
3623
|
+
repoFullName = repoResult.fullName;
|
|
3624
|
+
branch = gitInfo.branch || "main";
|
|
3625
|
+
} else if (!isGitHubUrl(gitInfo.remoteUrl)) {
|
|
3690
3626
|
console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
|
|
3691
3627
|
console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
|
|
3692
3628
|
`));
|
|
3693
|
-
console.log(source_default.white("Please add a GitHub remote to deploy."));
|
|
3694
3629
|
process.exit(1);
|
|
3695
|
-
}
|
|
3696
|
-
if (!gitInfo.owner || !gitInfo.repo) {
|
|
3630
|
+
} else if (!gitInfo.owner || !gitInfo.repo) {
|
|
3697
3631
|
console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
|
|
3698
3632
|
process.exit(1);
|
|
3699
|
-
}
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3633
|
+
} else {
|
|
3634
|
+
repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
|
|
3635
|
+
branch = gitInfo.branch || "main";
|
|
3636
|
+
if (gitInfo.hasUncommittedChanges) {
|
|
3637
|
+
console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes.\n"));
|
|
3638
|
+
if (!options.yes) {
|
|
3639
|
+
const shouldCommit = await prompt(
|
|
3640
|
+
source_default.white("Commit and push changes before deploying? (Y/n): "),
|
|
3641
|
+
"y"
|
|
3642
|
+
);
|
|
3643
|
+
if (shouldCommit) {
|
|
3644
|
+
await ensureGitignore(cwd);
|
|
3645
|
+
console.log(source_default.gray("Committing and pushing..."));
|
|
3646
|
+
await gitCommitAndPush(cwd, "Deploy changes", branch);
|
|
3647
|
+
gitInfo = await getGitInfo(cwd);
|
|
3648
|
+
console.log(source_default.green("\u2713 Changes pushed\n"));
|
|
3649
|
+
} else {
|
|
3650
|
+
console.log(source_default.gray("Deploying from last pushed commit.\n"));
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
console.log(source_default.gray("Checking repository access..."));
|
|
3655
|
+
const hasAccess = await checkRepoAccess(
|
|
3656
|
+
api,
|
|
3657
|
+
gitInfo.owner,
|
|
3658
|
+
gitInfo.repo
|
|
3707
3659
|
);
|
|
3708
|
-
if (!
|
|
3709
|
-
|
|
3710
|
-
source_default.
|
|
3660
|
+
if (!hasAccess) {
|
|
3661
|
+
console.log(
|
|
3662
|
+
source_default.yellow(
|
|
3663
|
+
`\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
|
|
3664
|
+
)
|
|
3665
|
+
);
|
|
3666
|
+
const configured = await promptGitHubInstallation(
|
|
3667
|
+
api,
|
|
3668
|
+
"no_access",
|
|
3669
|
+
repoFullName,
|
|
3670
|
+
{ yes: options.yes, installationId: githubInstallationId }
|
|
3711
3671
|
);
|
|
3712
|
-
if (!
|
|
3713
|
-
console.log(source_default.gray("Deployment cancelled."));
|
|
3672
|
+
if (!configured) {
|
|
3714
3673
|
process.exit(0);
|
|
3715
3674
|
}
|
|
3675
|
+
const retry = await checkRepoAccess(api, gitInfo.owner, gitInfo.repo);
|
|
3676
|
+
if (!retry) {
|
|
3677
|
+
const appName = await api.getGitHubAppName();
|
|
3678
|
+
console.log(
|
|
3679
|
+
source_default.red(
|
|
3680
|
+
`
|
|
3681
|
+
\u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
|
|
3682
|
+
)
|
|
3683
|
+
);
|
|
3684
|
+
console.log(
|
|
3685
|
+
source_default.cyan(
|
|
3686
|
+
` https://github.com/apps/${appName}/installations/new
|
|
3687
|
+
`
|
|
3688
|
+
)
|
|
3689
|
+
);
|
|
3690
|
+
process.exit(1);
|
|
3691
|
+
}
|
|
3716
3692
|
}
|
|
3717
|
-
console.log();
|
|
3718
|
-
}
|
|
3719
|
-
console.log(source_default.white("GitHub repository detected:"));
|
|
3720
|
-
console.log(
|
|
3721
|
-
source_default.gray(` Repository: `) + source_default.cyan(`${gitInfo.owner}/${gitInfo.repo}`)
|
|
3722
|
-
);
|
|
3723
|
-
console.log(
|
|
3724
|
-
source_default.gray(` Branch: `) + source_default.cyan(gitInfo.branch || "main")
|
|
3725
|
-
);
|
|
3726
|
-
if (gitInfo.commitSha) {
|
|
3727
|
-
console.log(
|
|
3728
|
-
source_default.gray(` Commit: `) + source_default.gray(gitInfo.commitSha.substring(0, 7))
|
|
3729
|
-
);
|
|
3730
|
-
}
|
|
3731
|
-
if (gitInfo.commitMessage) {
|
|
3732
|
-
console.log(
|
|
3733
|
-
source_default.gray(` Message: `) + source_default.gray(gitInfo.commitMessage.split("\n")[0])
|
|
3734
|
-
);
|
|
3735
|
-
}
|
|
3736
|
-
console.log();
|
|
3737
|
-
if (!options.yes) {
|
|
3738
|
-
const shouldDeploy = await prompt(
|
|
3739
|
-
source_default.white(
|
|
3740
|
-
`Deploy from GitHub repository ${gitInfo.owner}/${gitInfo.repo}? (Y/n): `
|
|
3741
|
-
),
|
|
3742
|
-
"y"
|
|
3743
|
-
);
|
|
3744
|
-
if (!shouldDeploy) {
|
|
3745
|
-
console.log(source_default.gray("Deployment cancelled."));
|
|
3746
|
-
process.exit(0);
|
|
3747
|
-
}
|
|
3693
|
+
console.log(source_default.green("\u2713 Repository access confirmed"));
|
|
3748
3694
|
}
|
|
3749
3695
|
const projectName = options.name || await getProjectName(projectDir);
|
|
3750
|
-
const runtime = options.runtime || await detectRuntime(projectDir);
|
|
3751
3696
|
const port = options.port || 3e3;
|
|
3752
3697
|
const buildCommand = await detectBuildCommand(projectDir);
|
|
3753
3698
|
const startCommand = await detectStartCommand(projectDir);
|
|
3699
|
+
const runtime = options.runtime || await detectRuntime(projectDir);
|
|
3754
3700
|
const envVars = await buildEnvVars(options);
|
|
3755
3701
|
console.log();
|
|
3756
3702
|
console.log(source_default.white("Deployment configuration:"));
|
|
3703
|
+
console.log(source_default.gray(` Repository: `) + source_default.cyan(repoFullName));
|
|
3704
|
+
console.log(source_default.gray(` Branch: `) + source_default.cyan(branch));
|
|
3757
3705
|
console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
|
|
3758
3706
|
console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
|
|
3759
3707
|
console.log(source_default.gray(` Port: `) + source_default.cyan(port));
|
|
3760
|
-
if (options.
|
|
3708
|
+
if (options.region)
|
|
3709
|
+
console.log(source_default.gray(` Region: `) + source_default.cyan(options.region));
|
|
3710
|
+
if (options.buildCommand)
|
|
3761
3711
|
console.log(
|
|
3762
|
-
source_default.gray(`
|
|
3712
|
+
source_default.gray(` Build command: `) + source_default.cyan(options.buildCommand)
|
|
3763
3713
|
);
|
|
3764
|
-
|
|
3765
|
-
if (buildCommand) {
|
|
3766
|
-
console.log(source_default.gray(` Build command: `) + source_default.cyan(buildCommand));
|
|
3767
|
-
}
|
|
3768
|
-
if (startCommand) {
|
|
3769
|
-
console.log(source_default.gray(` Start command: `) + source_default.cyan(startCommand));
|
|
3770
|
-
}
|
|
3771
|
-
if (envVars && Object.keys(envVars).length > 0) {
|
|
3714
|
+
else if (buildCommand)
|
|
3772
3715
|
console.log(
|
|
3773
|
-
source_default.gray(`
|
|
3716
|
+
source_default.gray(` Build command: `) + source_default.gray(buildCommand + " (auto-detected)")
|
|
3774
3717
|
);
|
|
3718
|
+
if (options.startCommand)
|
|
3775
3719
|
console.log(
|
|
3776
|
-
source_default.gray(`
|
|
3720
|
+
source_default.gray(` Start command: `) + source_default.cyan(options.startCommand)
|
|
3777
3721
|
);
|
|
3778
|
-
|
|
3779
|
-
console.log();
|
|
3780
|
-
const api = await McpUseAPI.create();
|
|
3781
|
-
if (options.org) {
|
|
3782
|
-
try {
|
|
3783
|
-
const authInfo = await api.testAuth();
|
|
3784
|
-
const match = (authInfo.profiles ?? []).find(
|
|
3785
|
-
(p) => p.slug === options.org || p.id === options.org || p.profile_name.toLowerCase() === options.org.toLowerCase()
|
|
3786
|
-
);
|
|
3787
|
-
if (match) {
|
|
3788
|
-
api.setProfileId(match.id);
|
|
3789
|
-
const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
|
|
3790
|
-
console.log(
|
|
3791
|
-
source_default.gray("Organization: ") + source_default.cyan(match.profile_name) + slug
|
|
3792
|
-
);
|
|
3793
|
-
} else {
|
|
3794
|
-
console.error(
|
|
3795
|
-
source_default.red(
|
|
3796
|
-
`\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
|
|
3797
|
-
)
|
|
3798
|
-
);
|
|
3799
|
-
process.exit(1);
|
|
3800
|
-
}
|
|
3801
|
-
} catch (error) {
|
|
3802
|
-
console.error(
|
|
3803
|
-
source_default.red("\u2717 Failed to resolve organization:"),
|
|
3804
|
-
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
3805
|
-
);
|
|
3806
|
-
process.exit(1);
|
|
3807
|
-
}
|
|
3808
|
-
}
|
|
3809
|
-
let githubVerified = false;
|
|
3810
|
-
try {
|
|
3811
|
-
console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
|
|
3812
|
-
const connectionStatus = await api.getGitHubConnectionStatus();
|
|
3813
|
-
if (!connectionStatus.is_connected) {
|
|
3814
|
-
const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
|
|
3815
|
-
const installed = await promptGitHubInstallation(
|
|
3816
|
-
api,
|
|
3817
|
-
"not_connected",
|
|
3818
|
-
repoFullName,
|
|
3819
|
-
{ yes: options.yes }
|
|
3820
|
-
);
|
|
3821
|
-
if (!installed) {
|
|
3822
|
-
console.log(source_default.gray("Deployment cancelled."));
|
|
3823
|
-
process.exit(0);
|
|
3824
|
-
}
|
|
3825
|
-
const retryStatus = await api.getGitHubConnectionStatus();
|
|
3826
|
-
if (!retryStatus.is_connected) {
|
|
3827
|
-
console.log(
|
|
3828
|
-
source_default.red("\n\u2717 GitHub connection could not be verified.")
|
|
3829
|
-
);
|
|
3830
|
-
console.log(
|
|
3831
|
-
source_default.gray("Please try connecting GitHub from the web UI:")
|
|
3832
|
-
);
|
|
3833
|
-
console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
|
|
3834
|
-
process.exit(1);
|
|
3835
|
-
}
|
|
3836
|
-
githubVerified = true;
|
|
3837
|
-
} else if (gitInfo.owner && gitInfo.repo) {
|
|
3838
|
-
console.log(source_default.gray("Checking repository access..."));
|
|
3839
|
-
const hasAccess = await checkRepoAccess(
|
|
3840
|
-
api,
|
|
3841
|
-
gitInfo.owner,
|
|
3842
|
-
gitInfo.repo
|
|
3843
|
-
);
|
|
3844
|
-
if (!hasAccess) {
|
|
3845
|
-
const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
|
|
3846
|
-
console.log(
|
|
3847
|
-
source_default.yellow(
|
|
3848
|
-
`\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
|
|
3849
|
-
)
|
|
3850
|
-
);
|
|
3851
|
-
const configured = await promptGitHubInstallation(
|
|
3852
|
-
api,
|
|
3853
|
-
"no_access",
|
|
3854
|
-
repoFullName,
|
|
3855
|
-
{ yes: options.yes }
|
|
3856
|
-
);
|
|
3857
|
-
if (!configured) {
|
|
3858
|
-
console.log(source_default.gray("Deployment cancelled."));
|
|
3859
|
-
process.exit(0);
|
|
3860
|
-
}
|
|
3861
|
-
const hasAccessRetry = await checkRepoAccess(
|
|
3862
|
-
api,
|
|
3863
|
-
gitInfo.owner,
|
|
3864
|
-
gitInfo.repo
|
|
3865
|
-
);
|
|
3866
|
-
if (!hasAccessRetry) {
|
|
3867
|
-
console.log(
|
|
3868
|
-
source_default.red(
|
|
3869
|
-
`
|
|
3870
|
-
\u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
|
|
3871
|
-
)
|
|
3872
|
-
);
|
|
3873
|
-
console.log(
|
|
3874
|
-
source_default.gray(
|
|
3875
|
-
"Please make sure the GitHub App has access to this repository."
|
|
3876
|
-
)
|
|
3877
|
-
);
|
|
3878
|
-
console.log(
|
|
3879
|
-
source_default.cyan(" https://github.com/settings/installations\n")
|
|
3880
|
-
);
|
|
3881
|
-
process.exit(1);
|
|
3882
|
-
}
|
|
3883
|
-
githubVerified = true;
|
|
3884
|
-
} else {
|
|
3885
|
-
console.log(source_default.green("\u2713 Repository access confirmed"));
|
|
3886
|
-
githubVerified = true;
|
|
3887
|
-
}
|
|
3888
|
-
}
|
|
3889
|
-
} catch (error) {
|
|
3890
|
-
console.log(source_default.red("\u2717 Could not verify GitHub connection"));
|
|
3891
|
-
console.log(
|
|
3892
|
-
source_default.gray(
|
|
3893
|
-
"Error: " + (error instanceof Error ? error.message : "Unknown error")
|
|
3894
|
-
)
|
|
3895
|
-
);
|
|
3896
|
-
console.log(source_default.gray("\nPlease ensure:"));
|
|
3722
|
+
else if (startCommand)
|
|
3897
3723
|
console.log(
|
|
3898
|
-
source_default.
|
|
3899
|
-
" 1. You have connected GitHub at https://manufact.com/cloud/settings"
|
|
3900
|
-
)
|
|
3724
|
+
source_default.gray(` Start command: `) + source_default.gray(startCommand + " (auto-detected)")
|
|
3901
3725
|
);
|
|
3726
|
+
if (Object.keys(envVars).length > 0) {
|
|
3902
3727
|
console.log(
|
|
3903
|
-
source_default.
|
|
3728
|
+
source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
|
|
3904
3729
|
);
|
|
3905
|
-
console.log(source_default.cyan(" 3. Your internet connection is stable\n"));
|
|
3906
|
-
process.exit(1);
|
|
3907
3730
|
}
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
)
|
|
3912
|
-
|
|
3731
|
+
console.log();
|
|
3732
|
+
if (!options.yes) {
|
|
3733
|
+
const shouldDeploy = await prompt(source_default.white(`Deploy? (Y/n): `), "y");
|
|
3734
|
+
if (!shouldDeploy) {
|
|
3735
|
+
console.log(source_default.gray("Deployment cancelled."));
|
|
3736
|
+
process.exit(0);
|
|
3737
|
+
}
|
|
3913
3738
|
}
|
|
3914
3739
|
const existingLink = !options.new ? await getProjectLink(cwd) : null;
|
|
3915
|
-
|
|
3916
|
-
if (existingLink) {
|
|
3740
|
+
let serverId = existingLink?.serverId;
|
|
3741
|
+
if (existingLink && serverId) {
|
|
3917
3742
|
try {
|
|
3918
|
-
const
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
if (existingDeployment && existingDeployment.status !== "failed") {
|
|
3922
|
-
console.log(source_default.green(`\u2713 Found linked deployment`));
|
|
3743
|
+
const existingDep = await api.getDeployment(existingLink.deploymentId);
|
|
3744
|
+
if (existingDep && existingDep.status !== "failed") {
|
|
3745
|
+
console.log(source_default.green(`\u2713 Found linked server`));
|
|
3923
3746
|
console.log(source_default.gray(` Redeploying to maintain the same URL...`));
|
|
3924
|
-
console.log(
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
...options.port !== void 0 ? { port: options.port } : {},
|
|
3932
|
-
env: Object.keys(envVars).length > 0 ? envVars : void 0,
|
|
3933
|
-
rootDir: options.rootDir || void 0
|
|
3934
|
-
};
|
|
3935
|
-
const deployment2 = await api.redeployDeployment(
|
|
3936
|
-
existingLink.deploymentId,
|
|
3937
|
-
redeploymentConfig
|
|
3938
|
-
);
|
|
3747
|
+
console.log(source_default.cyan(` URL: ${getMcpServerUrl(existingDep)}
|
|
3748
|
+
`));
|
|
3749
|
+
const newDep = await api.createDeployment({
|
|
3750
|
+
serverId,
|
|
3751
|
+
branch,
|
|
3752
|
+
trigger: "redeploy"
|
|
3753
|
+
});
|
|
3939
3754
|
await saveProjectLink(cwd, {
|
|
3940
3755
|
...existingLink,
|
|
3941
|
-
linkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3942
|
-
|
|
3943
|
-
await displayDeploymentProgress(api, deployment2, {
|
|
3944
|
-
yes: options.yes
|
|
3756
|
+
linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3757
|
+
deploymentId: newDep.id
|
|
3945
3758
|
});
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
}
|
|
3759
|
+
console.log(
|
|
3760
|
+
source_default.green("\u2713 Deployment created: ") + source_default.gray(newDep.id)
|
|
3761
|
+
);
|
|
3762
|
+
await displayDeploymentProgress(api, newDep.id, { yes: options.yes });
|
|
3951
3763
|
return;
|
|
3952
|
-
}
|
|
3764
|
+
}
|
|
3765
|
+
} catch (err) {
|
|
3766
|
+
const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
|
|
3767
|
+
if (is404) {
|
|
3953
3768
|
console.log(
|
|
3954
|
-
source_default.yellow(
|
|
3955
|
-
`\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
|
|
3956
|
-
)
|
|
3769
|
+
source_default.yellow("\u26A0\uFE0F Previously linked server no longer exists.\n")
|
|
3957
3770
|
);
|
|
3958
|
-
if (
|
|
3959
|
-
|
|
3960
|
-
source_default.
|
|
3771
|
+
if (!options.yes) {
|
|
3772
|
+
const shouldRecreate = await prompt(
|
|
3773
|
+
source_default.white("Create a new server and deploy? (Y/n): "),
|
|
3774
|
+
"y"
|
|
3961
3775
|
);
|
|
3776
|
+
if (!shouldRecreate) {
|
|
3777
|
+
console.log(source_default.gray("Deployment cancelled."));
|
|
3778
|
+
process.exit(0);
|
|
3779
|
+
}
|
|
3962
3780
|
}
|
|
3781
|
+
serverId = void 0;
|
|
3963
3782
|
}
|
|
3964
|
-
}
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
let deploymentId;
|
|
3786
|
+
if (serverId) {
|
|
3787
|
+
console.log(source_default.gray("Creating deployment..."));
|
|
3788
|
+
try {
|
|
3789
|
+
const result = await api.createDeployment({
|
|
3790
|
+
serverId,
|
|
3791
|
+
branch,
|
|
3792
|
+
trigger: "manual"
|
|
3793
|
+
});
|
|
3794
|
+
deploymentId = result.id;
|
|
3795
|
+
} catch (err) {
|
|
3796
|
+
const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
|
|
3797
|
+
if (is404) {
|
|
3798
|
+
console.log(
|
|
3799
|
+
source_default.yellow(
|
|
3800
|
+
"\u26A0\uFE0F Linked server no longer exists. Creating a new one...\n"
|
|
3801
|
+
)
|
|
3802
|
+
);
|
|
3803
|
+
serverId = void 0;
|
|
3804
|
+
} else {
|
|
3805
|
+
throw err;
|
|
3970
3806
|
}
|
|
3971
3807
|
}
|
|
3972
3808
|
}
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3809
|
+
if (!serverId) {
|
|
3810
|
+
const orgId = await api.resolveOrganizationId();
|
|
3811
|
+
console.log(source_default.gray("Creating server and deployment..."));
|
|
3812
|
+
const serverResult = await api.createServer({
|
|
3976
3813
|
type: "github",
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3814
|
+
organizationId: orgId,
|
|
3815
|
+
installationId: installationDbId,
|
|
3816
|
+
name: projectName,
|
|
3817
|
+
repoFullName,
|
|
3818
|
+
branch,
|
|
3819
|
+
rootDir: options.rootDir,
|
|
3981
3820
|
port,
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
console.log(
|
|
3995
|
-
source_default.gray("Organization: ") + source_default.cyan(config.profileName) + slug
|
|
3996
|
-
);
|
|
3997
|
-
}
|
|
3998
|
-
} catch {
|
|
3821
|
+
env: Object.keys(envVars).length > 0 ? envVars : void 0,
|
|
3822
|
+
region: options.region,
|
|
3823
|
+
buildCommand: options.buildCommand,
|
|
3824
|
+
startCommand: options.startCommand
|
|
3825
|
+
});
|
|
3826
|
+
deploymentId = serverResult.deploymentId ?? "";
|
|
3827
|
+
if (!deploymentId) {
|
|
3828
|
+
console.log(
|
|
3829
|
+
source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
|
|
3830
|
+
);
|
|
3831
|
+
console.log(source_default.yellow("\u26A0\uFE0F No deployment was triggered."));
|
|
3832
|
+
return;
|
|
3999
3833
|
}
|
|
3834
|
+
await saveProjectLink(cwd, {
|
|
3835
|
+
deploymentId,
|
|
3836
|
+
deploymentName: projectName,
|
|
3837
|
+
linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3838
|
+
serverId: serverResult.server.id
|
|
3839
|
+
});
|
|
3840
|
+
console.log(
|
|
3841
|
+
source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
|
|
3842
|
+
);
|
|
3843
|
+
console.log(source_default.gray(` Future deploys will reuse the same URL
|
|
3844
|
+
`));
|
|
3845
|
+
}
|
|
3846
|
+
if (!deploymentId) {
|
|
3847
|
+
console.log(source_default.red("\u2717 No deployment was created."));
|
|
3848
|
+
process.exit(1);
|
|
4000
3849
|
}
|
|
4001
|
-
console.log(source_default.gray("Creating deployment..."));
|
|
4002
|
-
const deployment = await api.createDeployment(deploymentRequest);
|
|
4003
|
-
console.log(
|
|
4004
|
-
source_default.green("\u2713 Deployment created: ") + source_default.gray(deployment.id)
|
|
4005
|
-
);
|
|
4006
|
-
await saveProjectLink(cwd, {
|
|
4007
|
-
deploymentId: deployment.id,
|
|
4008
|
-
deploymentName: projectName,
|
|
4009
|
-
deploymentUrl: deployment.domain,
|
|
4010
|
-
linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4011
|
-
serverId: deployment.serverId
|
|
4012
|
-
});
|
|
4013
3850
|
console.log(
|
|
4014
|
-
source_default.
|
|
3851
|
+
source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
|
|
4015
3852
|
);
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
3853
|
+
await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
|
|
3854
|
+
if (options.open) {
|
|
3855
|
+
const dep = await api.getDeployment(deploymentId);
|
|
3856
|
+
const url = getMcpServerUrl(dep);
|
|
3857
|
+
if (url) {
|
|
3858
|
+
console.log(source_default.gray("\nOpening in browser..."));
|
|
3859
|
+
await open_default(url);
|
|
3860
|
+
}
|
|
4023
3861
|
}
|
|
4024
3862
|
} catch (error) {
|
|
4025
3863
|
console.error(
|
|
@@ -4095,19 +3933,19 @@ async function listDeploymentsCommand() {
|
|
|
4095
3933
|
);
|
|
4096
3934
|
console.log(
|
|
4097
3935
|
source_default.white.bold(
|
|
4098
|
-
`${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"
|
|
3936
|
+
`${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"MCP URL".padEnd(45)} ${"CREATED"}`
|
|
4099
3937
|
)
|
|
4100
3938
|
);
|
|
4101
|
-
console.log(source_default.gray("\u2500".repeat(
|
|
3939
|
+
console.log(source_default.gray("\u2500".repeat(140)));
|
|
4102
3940
|
for (const deployment of sortedDeployments) {
|
|
4103
3941
|
const id = formatId(deployment.id).padEnd(40);
|
|
4104
3942
|
const name = deployment.name.substring(0, 24).padEnd(25);
|
|
4105
3943
|
const statusColor = getStatusColor(deployment.status);
|
|
4106
3944
|
const status = statusColor(deployment.status.padEnd(12));
|
|
4107
|
-
const
|
|
3945
|
+
const mcpUrl = (deployment.mcpUrl || "-").substring(0, 44).padEnd(45);
|
|
4108
3946
|
const created = formatRelativeTime(deployment.createdAt);
|
|
4109
3947
|
console.log(
|
|
4110
|
-
`${source_default.gray(id)} ${name} ${status} ${source_default.cyan(
|
|
3948
|
+
`${source_default.gray(id)} ${name} ${status} ${source_default.cyan(mcpUrl)} ${source_default.gray(created)}`
|
|
4111
3949
|
);
|
|
4112
3950
|
}
|
|
4113
3951
|
console.log();
|
|
@@ -4139,31 +3977,28 @@ async function getDeploymentCommand(deploymentId) {
|
|
|
4139
3977
|
console.log(
|
|
4140
3978
|
source_default.white("Status: ") + statusColor(deployment.status)
|
|
4141
3979
|
);
|
|
4142
|
-
if (deployment.
|
|
3980
|
+
if (deployment.serverId) {
|
|
4143
3981
|
console.log(
|
|
4144
|
-
source_default.white("
|
|
3982
|
+
source_default.white("Server ID: ") + source_default.gray(deployment.serverId)
|
|
4145
3983
|
);
|
|
4146
3984
|
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
);
|
|
3985
|
+
const mcpUrl = getMcpServerUrl(deployment);
|
|
3986
|
+
if (mcpUrl) {
|
|
3987
|
+
console.log(source_default.white("MCP URL: ") + source_default.cyan(mcpUrl));
|
|
4151
3988
|
}
|
|
4152
|
-
|
|
4153
|
-
source_default.white("Source: ") + source_default.gray(deployment.source.type)
|
|
4154
|
-
);
|
|
4155
|
-
if (deployment.source.type === "github") {
|
|
3989
|
+
if (deployment.gitBranch) {
|
|
4156
3990
|
console.log(
|
|
4157
|
-
source_default.white("
|
|
3991
|
+
source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
|
|
4158
3992
|
);
|
|
3993
|
+
}
|
|
3994
|
+
if (deployment.gitCommitSha) {
|
|
4159
3995
|
console.log(
|
|
4160
|
-
source_default.white("
|
|
3996
|
+
source_default.white("Commit: ") + source_default.gray(deployment.gitCommitSha.substring(0, 7))
|
|
4161
3997
|
);
|
|
4162
3998
|
}
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
);
|
|
3999
|
+
if (deployment.port) {
|
|
4000
|
+
console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
|
|
4001
|
+
}
|
|
4167
4002
|
if (deployment.provider) {
|
|
4168
4003
|
console.log(
|
|
4169
4004
|
source_default.white("Provider: ") + source_default.gray(deployment.provider)
|
|
@@ -4175,13 +4010,6 @@ async function getDeploymentCommand(deploymentId) {
|
|
|
4175
4010
|
console.log(
|
|
4176
4011
|
source_default.white("Updated: ") + source_default.gray(formatRelativeTime(deployment.updatedAt))
|
|
4177
4012
|
);
|
|
4178
|
-
if (deployment.source.env && Object.keys(deployment.source.env).length > 0) {
|
|
4179
|
-
console.log(source_default.white("\nEnvironment Variables:"));
|
|
4180
|
-
for (const [key, value] of Object.entries(deployment.source.env)) {
|
|
4181
|
-
const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
|
|
4182
|
-
console.log(source_default.gray(` ${key}=`) + source_default.white(displayValue));
|
|
4183
|
-
}
|
|
4184
|
-
}
|
|
4185
4013
|
if (deployment.status === "failed" && deployment.error) {
|
|
4186
4014
|
console.log(source_default.red("\nError:"));
|
|
4187
4015
|
console.log(source_default.red(` ${deployment.error}`));
|
|
@@ -4208,43 +4036,56 @@ async function restartDeploymentCommand(deploymentId, options) {
|
|
|
4208
4036
|
}
|
|
4209
4037
|
const api = await McpUseAPI.create();
|
|
4210
4038
|
const deployment = await api.getDeployment(deploymentId);
|
|
4039
|
+
if (!deployment.serverId) {
|
|
4040
|
+
console.log(
|
|
4041
|
+
source_default.red("\u2717 Cannot restart: deployment has no linked server.")
|
|
4042
|
+
);
|
|
4043
|
+
process.exit(1);
|
|
4044
|
+
}
|
|
4211
4045
|
console.log(
|
|
4212
4046
|
source_default.cyan.bold(`
|
|
4213
4047
|
\u{1F504} Restarting deployment: ${deployment.name}
|
|
4214
4048
|
`)
|
|
4215
4049
|
);
|
|
4216
|
-
const
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
);
|
|
4050
|
+
const newDep = await api.createDeployment({
|
|
4051
|
+
serverId: deployment.serverId,
|
|
4052
|
+
trigger: "redeploy"
|
|
4053
|
+
});
|
|
4054
|
+
console.log(source_default.green("\u2713 Restart initiated: ") + source_default.gray(newDep.id));
|
|
4220
4055
|
if (options.follow) {
|
|
4221
|
-
console.log(source_default.gray("\nFollowing
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
))
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4056
|
+
console.log(source_default.gray("\nFollowing build logs...\n"));
|
|
4057
|
+
let offset = 0;
|
|
4058
|
+
let terminal = false;
|
|
4059
|
+
while (!terminal) {
|
|
4060
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
4061
|
+
try {
|
|
4062
|
+
const resp = await api.getDeploymentBuildLogs(newDep.id, offset);
|
|
4063
|
+
if (resp.logs.length > 0) {
|
|
4064
|
+
const lines = resp.logs.split("\n").filter((l) => l.trim());
|
|
4065
|
+
for (const line of lines) {
|
|
4066
|
+
try {
|
|
4067
|
+
const logData = JSON.parse(line);
|
|
4068
|
+
if (logData.line) {
|
|
4069
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
4070
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
4071
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
4072
|
+
}
|
|
4073
|
+
} catch {
|
|
4074
|
+
console.log(source_default.gray(line));
|
|
4075
|
+
}
|
|
4232
4076
|
}
|
|
4233
|
-
|
|
4234
|
-
|
|
4077
|
+
offset = resp.offset;
|
|
4078
|
+
}
|
|
4079
|
+
if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
|
|
4080
|
+
terminal = true;
|
|
4235
4081
|
}
|
|
4082
|
+
} catch {
|
|
4236
4083
|
}
|
|
4237
|
-
} catch (error) {
|
|
4238
|
-
console.log(
|
|
4239
|
-
source_default.gray(
|
|
4240
|
-
"\nLog stream ended. Use " + source_default.white(`mcp-use deployments get ${deploymentId}`) + " to check status."
|
|
4241
|
-
)
|
|
4242
|
-
);
|
|
4243
4084
|
}
|
|
4244
4085
|
} else {
|
|
4245
4086
|
console.log(
|
|
4246
4087
|
source_default.gray(
|
|
4247
|
-
"\nCheck status with: " + source_default.white(`mcp-use deployments get ${
|
|
4088
|
+
"\nCheck status with: " + source_default.white(`mcp-use deployments get ${newDep.id}`)
|
|
4248
4089
|
)
|
|
4249
4090
|
);
|
|
4250
4091
|
}
|
|
@@ -4278,8 +4119,10 @@ async function deleteDeploymentCommand(deploymentId, options) {
|
|
|
4278
4119
|
)
|
|
4279
4120
|
);
|
|
4280
4121
|
console.log(source_default.gray(` ID: ${deployment.id}`));
|
|
4281
|
-
|
|
4122
|
+
if (deployment.mcpUrl) {
|
|
4123
|
+
console.log(source_default.gray(` URL: ${deployment.mcpUrl}
|
|
4282
4124
|
`));
|
|
4125
|
+
}
|
|
4283
4126
|
const confirmed = await prompt2(
|
|
4284
4127
|
source_default.white("Are you sure you want to delete this deployment? (y/N): ")
|
|
4285
4128
|
);
|
|
@@ -4315,30 +4158,41 @@ async function logsCommand(deploymentId, options) {
|
|
|
4315
4158
|
}
|
|
4316
4159
|
const api = await McpUseAPI.create();
|
|
4317
4160
|
if (options.follow) {
|
|
4318
|
-
console.log(source_default.gray("
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4161
|
+
console.log(source_default.gray("Following build logs...\n"));
|
|
4162
|
+
let offset = 0;
|
|
4163
|
+
let terminal = false;
|
|
4164
|
+
while (!terminal) {
|
|
4165
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
4166
|
+
try {
|
|
4167
|
+
const resp = await api.getDeploymentBuildLogs(deploymentId, offset);
|
|
4168
|
+
if (resp.logs.length > 0) {
|
|
4169
|
+
const lines = resp.logs.split("\n").filter((l) => l.trim());
|
|
4170
|
+
for (const line of lines) {
|
|
4171
|
+
try {
|
|
4172
|
+
const logData = JSON.parse(line);
|
|
4173
|
+
if (logData.line) {
|
|
4174
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
4175
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
4176
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
4177
|
+
}
|
|
4178
|
+
} catch {
|
|
4179
|
+
console.log(source_default.gray(line));
|
|
4180
|
+
}
|
|
4327
4181
|
}
|
|
4328
|
-
|
|
4329
|
-
|
|
4182
|
+
offset = resp.offset;
|
|
4183
|
+
}
|
|
4184
|
+
if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
|
|
4185
|
+
terminal = true;
|
|
4330
4186
|
}
|
|
4187
|
+
} catch {
|
|
4331
4188
|
}
|
|
4332
|
-
} catch (error) {
|
|
4333
|
-
console.log(source_default.gray("\nLog stream ended."));
|
|
4334
4189
|
}
|
|
4335
|
-
} else {
|
|
4336
|
-
const
|
|
4190
|
+
} else if (options.build) {
|
|
4191
|
+
const resp = await api.getDeploymentBuildLogs(deploymentId);
|
|
4192
|
+
const logs = resp.logs;
|
|
4337
4193
|
if (!logs || logs.trim() === "") {
|
|
4338
4194
|
console.log(
|
|
4339
|
-
source_default.yellow(
|
|
4340
|
-
`No ${options.build ? "build " : ""}logs available for this deployment.`
|
|
4341
|
-
)
|
|
4195
|
+
source_default.yellow("No build logs available for this deployment.")
|
|
4342
4196
|
);
|
|
4343
4197
|
return;
|
|
4344
4198
|
}
|
|
@@ -4355,6 +4209,25 @@ async function logsCommand(deploymentId, options) {
|
|
|
4355
4209
|
console.log(source_default.gray(line));
|
|
4356
4210
|
}
|
|
4357
4211
|
}
|
|
4212
|
+
} else {
|
|
4213
|
+
const logs = await api.getDeploymentLogs(deploymentId);
|
|
4214
|
+
if (!logs || logs.trim() === "") {
|
|
4215
|
+
console.log(source_default.yellow("No logs available for this deployment."));
|
|
4216
|
+
return;
|
|
4217
|
+
}
|
|
4218
|
+
const logLines = logs.split("\n").filter((l) => l.trim());
|
|
4219
|
+
for (const line of logLines) {
|
|
4220
|
+
try {
|
|
4221
|
+
const logData = JSON.parse(line);
|
|
4222
|
+
if (logData.line) {
|
|
4223
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
4224
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
4225
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
4226
|
+
}
|
|
4227
|
+
} catch {
|
|
4228
|
+
console.log(source_default.gray(line));
|
|
4229
|
+
}
|
|
4230
|
+
}
|
|
4358
4231
|
}
|
|
4359
4232
|
console.log();
|
|
4360
4233
|
} catch (error) {
|
|
@@ -4365,7 +4238,7 @@ async function logsCommand(deploymentId, options) {
|
|
|
4365
4238
|
process.exit(1);
|
|
4366
4239
|
}
|
|
4367
4240
|
}
|
|
4368
|
-
async function
|
|
4241
|
+
async function stopDeploymentCommand(deploymentId) {
|
|
4369
4242
|
try {
|
|
4370
4243
|
if (!await isLoggedIn()) {
|
|
4371
4244
|
console.log(source_default.red("\u2717 You are not logged in."));
|
|
@@ -4377,33 +4250,19 @@ async function listEnvCommand(deploymentId) {
|
|
|
4377
4250
|
process.exit(1);
|
|
4378
4251
|
}
|
|
4379
4252
|
const api = await McpUseAPI.create();
|
|
4380
|
-
|
|
4381
|
-
console.log(
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
`)
|
|
4385
|
-
);
|
|
4386
|
-
if (!deployment.source.env || Object.keys(deployment.source.env).length === 0) {
|
|
4387
|
-
console.log(source_default.yellow("No environment variables set."));
|
|
4388
|
-
console.log();
|
|
4389
|
-
return;
|
|
4390
|
-
}
|
|
4391
|
-
for (const [key, value] of Object.entries(deployment.source.env)) {
|
|
4392
|
-
const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
|
|
4393
|
-
console.log(
|
|
4394
|
-
source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
|
|
4395
|
-
);
|
|
4396
|
-
}
|
|
4397
|
-
console.log();
|
|
4253
|
+
await api.stopDeployment(deploymentId);
|
|
4254
|
+
console.log(source_default.green.bold(`
|
|
4255
|
+
\u2713 Deployment stopped
|
|
4256
|
+
`));
|
|
4398
4257
|
} catch (error) {
|
|
4399
4258
|
console.error(
|
|
4400
|
-
source_default.red.bold("\n\u2717 Failed to
|
|
4259
|
+
source_default.red.bold("\n\u2717 Failed to stop deployment:"),
|
|
4401
4260
|
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4402
4261
|
);
|
|
4403
4262
|
process.exit(1);
|
|
4404
4263
|
}
|
|
4405
4264
|
}
|
|
4406
|
-
async function
|
|
4265
|
+
async function startDeploymentCommand(deploymentId) {
|
|
4407
4266
|
try {
|
|
4408
4267
|
if (!await isLoggedIn()) {
|
|
4409
4268
|
console.log(source_default.red("\u2717 You are not logged in."));
|
|
@@ -4414,43 +4273,87 @@ async function setEnvCommand(deploymentId, envPairs) {
|
|
|
4414
4273
|
);
|
|
4415
4274
|
process.exit(1);
|
|
4416
4275
|
}
|
|
4417
|
-
const env2 = {};
|
|
4418
|
-
for (const pair of envPairs) {
|
|
4419
|
-
const [key, ...valueParts] = pair.split("=");
|
|
4420
|
-
if (!key || valueParts.length === 0) {
|
|
4421
|
-
console.log(source_default.red(`\u2717 Invalid format: ${pair}. Expected KEY=VALUE`));
|
|
4422
|
-
process.exit(1);
|
|
4423
|
-
}
|
|
4424
|
-
env2[key.trim()] = valueParts.join("=").trim();
|
|
4425
|
-
}
|
|
4426
|
-
const api = await McpUseAPI.create();
|
|
4427
|
-
const deployment = await api.getDeployment(deploymentId);
|
|
4428
|
-
const currentEnv = deployment.source.env || {};
|
|
4429
|
-
const mergedEnv = { ...currentEnv, ...env2 };
|
|
4430
|
-
const updated = await api.updateDeployment(deploymentId, {
|
|
4431
|
-
env: mergedEnv
|
|
4432
|
-
});
|
|
4433
4276
|
console.log(
|
|
4434
|
-
source_default.
|
|
4435
|
-
\
|
|
4436
|
-
|
|
4277
|
+
source_default.yellow(
|
|
4278
|
+
"\u26A0\uFE0F Start is not supported in this version. Use `mcp-use deployments restart` to redeploy."
|
|
4279
|
+
)
|
|
4437
4280
|
);
|
|
4438
|
-
for (const key of Object.keys(env2)) {
|
|
4439
|
-
const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : env2[key];
|
|
4440
|
-
console.log(
|
|
4441
|
-
source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
|
|
4442
|
-
);
|
|
4443
|
-
}
|
|
4444
|
-
console.log();
|
|
4445
4281
|
} catch (error) {
|
|
4446
4282
|
console.error(
|
|
4447
|
-
source_default.red.bold("\n\u2717 Failed to
|
|
4283
|
+
source_default.red.bold("\n\u2717 Failed to start deployment:"),
|
|
4448
4284
|
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4449
4285
|
);
|
|
4450
4286
|
process.exit(1);
|
|
4451
4287
|
}
|
|
4452
4288
|
}
|
|
4453
|
-
|
|
4289
|
+
function createDeploymentsCommand() {
|
|
4290
|
+
const deploymentsCommand = new Command2("deployments").description(
|
|
4291
|
+
"Manage cloud deployments"
|
|
4292
|
+
);
|
|
4293
|
+
deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
|
|
4294
|
+
deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
|
|
4295
|
+
deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow build logs").description(
|
|
4296
|
+
"Restart a deployment (triggers a new deployment on the same server)"
|
|
4297
|
+
).action(restartDeploymentCommand);
|
|
4298
|
+
deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
|
|
4299
|
+
deploymentsCommand.command("logs").argument("<deployment-id>", "Deployment ID").option("-b, --build", "Show build logs instead of runtime logs").option("-f, --follow", "Follow build logs in real-time").description("View deployment logs").action(logsCommand);
|
|
4300
|
+
deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
|
|
4301
|
+
deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
|
|
4302
|
+
return deploymentsCommand;
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
// src/commands/servers.ts
|
|
4306
|
+
import { Command as Command3 } from "commander";
|
|
4307
|
+
async function prompt3(question) {
|
|
4308
|
+
const readline = await import("readline");
|
|
4309
|
+
const rl = readline.createInterface({
|
|
4310
|
+
input: process.stdin,
|
|
4311
|
+
output: process.stdout
|
|
4312
|
+
});
|
|
4313
|
+
return new Promise((resolve2) => {
|
|
4314
|
+
rl.question(question, (answer) => {
|
|
4315
|
+
rl.close();
|
|
4316
|
+
const trimmedAnswer = answer.trim().toLowerCase();
|
|
4317
|
+
resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
|
|
4318
|
+
});
|
|
4319
|
+
});
|
|
4320
|
+
}
|
|
4321
|
+
function isRecord(v) {
|
|
4322
|
+
return typeof v === "object" && v !== null;
|
|
4323
|
+
}
|
|
4324
|
+
function pickStr(obj, key) {
|
|
4325
|
+
if (!isRecord(obj)) return "-";
|
|
4326
|
+
const v = obj[key];
|
|
4327
|
+
if (typeof v === "string") return v;
|
|
4328
|
+
if (v != null && typeof v !== "object") return String(v);
|
|
4329
|
+
return "-";
|
|
4330
|
+
}
|
|
4331
|
+
async function applyOrgOption(api, org) {
|
|
4332
|
+
if (!org) return;
|
|
4333
|
+
const authInfo = await api.testAuth();
|
|
4334
|
+
const match = (authInfo.orgs ?? []).find(
|
|
4335
|
+
(o) => o.slug === org || o.id === org || o.name.toLowerCase() === org.toLowerCase()
|
|
4336
|
+
);
|
|
4337
|
+
if (!match) {
|
|
4338
|
+
console.error(
|
|
4339
|
+
source_default.red(
|
|
4340
|
+
`\u2717 Organization "${org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
|
|
4341
|
+
)
|
|
4342
|
+
);
|
|
4343
|
+
process.exit(1);
|
|
4344
|
+
}
|
|
4345
|
+
api.setOrgId(match.id);
|
|
4346
|
+
const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
|
|
4347
|
+
console.log(source_default.gray("Organization: ") + source_default.cyan(match.name) + slug);
|
|
4348
|
+
}
|
|
4349
|
+
function getStatusColor2(status) {
|
|
4350
|
+
const s = status.toLowerCase();
|
|
4351
|
+
if (s.includes("run") || s === "active") return source_default.green;
|
|
4352
|
+
if (s.includes("fail") || s.includes("error")) return source_default.red;
|
|
4353
|
+
if (s.includes("build") || s.includes("pend")) return source_default.yellow;
|
|
4354
|
+
return source_default.gray;
|
|
4355
|
+
}
|
|
4356
|
+
async function listServersCommand(options) {
|
|
4454
4357
|
try {
|
|
4455
4358
|
if (!await isLoggedIn()) {
|
|
4456
4359
|
console.log(source_default.red("\u2717 You are not logged in."));
|
|
@@ -4462,32 +4365,62 @@ async function unsetEnvCommand(deploymentId, keys) {
|
|
|
4462
4365
|
process.exit(1);
|
|
4463
4366
|
}
|
|
4464
4367
|
const api = await McpUseAPI.create();
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4368
|
+
await applyOrgOption(api, options.org);
|
|
4369
|
+
if (options.org) console.log();
|
|
4370
|
+
const limit = options.limit ? parseInt(options.limit, 10) : void 0;
|
|
4371
|
+
const skip = options.skip ? parseInt(options.skip, 10) : void 0;
|
|
4372
|
+
if (limit !== void 0 && (Number.isNaN(limit) || limit < 1)) {
|
|
4373
|
+
console.log(source_default.red("\u2717 Invalid --limit"));
|
|
4374
|
+
process.exit(1);
|
|
4469
4375
|
}
|
|
4470
|
-
|
|
4471
|
-
|
|
4376
|
+
if (skip !== void 0 && (Number.isNaN(skip) || skip < 0)) {
|
|
4377
|
+
console.log(source_default.red("\u2717 Invalid --skip"));
|
|
4378
|
+
process.exit(1);
|
|
4379
|
+
}
|
|
4380
|
+
const servers = await api.listServers({
|
|
4381
|
+
limit,
|
|
4382
|
+
skip,
|
|
4383
|
+
sort: options.sort
|
|
4472
4384
|
});
|
|
4385
|
+
if (servers.length === 0) {
|
|
4386
|
+
console.log(source_default.yellow("No servers found."));
|
|
4387
|
+
console.log(
|
|
4388
|
+
source_default.gray(
|
|
4389
|
+
"\nCreate one by deploying with " + source_default.white("mcp-use deploy")
|
|
4390
|
+
)
|
|
4391
|
+
);
|
|
4392
|
+
return;
|
|
4393
|
+
}
|
|
4394
|
+
console.log(source_default.cyan.bold(`
|
|
4395
|
+
\u{1F5A5} Servers (${servers.length})
|
|
4396
|
+
`));
|
|
4473
4397
|
console.log(
|
|
4474
|
-
source_default.
|
|
4475
|
-
|
|
4476
|
-
|
|
4398
|
+
source_default.white.bold(
|
|
4399
|
+
`${"ID".padEnd(38)} ${"NAME".padEnd(22)} ${"STATUS".padEnd(14)} ${"REPO".padEnd(32)} ${"MCP URL".padEnd(52)}`
|
|
4400
|
+
)
|
|
4477
4401
|
);
|
|
4478
|
-
|
|
4479
|
-
|
|
4402
|
+
console.log(source_default.gray("\u2500".repeat(165)));
|
|
4403
|
+
for (const s of servers) {
|
|
4404
|
+
const id = s.id.substring(0, 37).padEnd(38);
|
|
4405
|
+
const name = (s.name || s.slug || "-").substring(0, 21).padEnd(22);
|
|
4406
|
+
const statusColor = getStatusColor2(s.status);
|
|
4407
|
+
const status = statusColor(s.status.substring(0, 13).padEnd(14));
|
|
4408
|
+
const repo = (s.connectedRepository?.repoFullName ?? "-").substring(0, 31).padEnd(32);
|
|
4409
|
+
const mcp = getMcpServerUrlForCloudServer(s).substring(0, 51).padEnd(52);
|
|
4410
|
+
console.log(
|
|
4411
|
+
`${source_default.gray(id)} ${name} ${status} ${source_default.gray(repo)} ${source_default.cyan(mcp)}`
|
|
4412
|
+
);
|
|
4480
4413
|
}
|
|
4481
4414
|
console.log();
|
|
4482
4415
|
} catch (error) {
|
|
4483
4416
|
console.error(
|
|
4484
|
-
source_default.red.bold("\n\u2717 Failed to
|
|
4417
|
+
source_default.red.bold("\n\u2717 Failed to list servers:"),
|
|
4485
4418
|
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4486
4419
|
);
|
|
4487
4420
|
process.exit(1);
|
|
4488
4421
|
}
|
|
4489
4422
|
}
|
|
4490
|
-
async function
|
|
4423
|
+
async function getServerCommand(idOrSlug, options) {
|
|
4491
4424
|
try {
|
|
4492
4425
|
if (!await isLoggedIn()) {
|
|
4493
4426
|
console.log(source_default.red("\u2717 You are not logged in."));
|
|
@@ -4499,21 +4432,99 @@ async function stopDeploymentCommand(deploymentId) {
|
|
|
4499
4432
|
process.exit(1);
|
|
4500
4433
|
}
|
|
4501
4434
|
const api = await McpUseAPI.create();
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
console.log(source_default.
|
|
4506
|
-
|
|
4507
|
-
|
|
4435
|
+
await applyOrgOption(api, options.org);
|
|
4436
|
+
if (options.org) console.log();
|
|
4437
|
+
const server = await api.getServer(idOrSlug);
|
|
4438
|
+
console.log(source_default.cyan.bold("\n\u{1F5A5} Server Details\n"));
|
|
4439
|
+
console.log(source_default.white("ID: ") + source_default.gray(server.id));
|
|
4440
|
+
if (server.slug) {
|
|
4441
|
+
console.log(source_default.white("Slug: ") + source_default.cyan(server.slug));
|
|
4442
|
+
}
|
|
4443
|
+
console.log(
|
|
4444
|
+
source_default.white("Name: ") + source_default.cyan(server.name ?? "-")
|
|
4445
|
+
);
|
|
4446
|
+
const statusColor = getStatusColor2(server.status);
|
|
4447
|
+
console.log(source_default.white("Status: ") + statusColor(server.status));
|
|
4448
|
+
if (server.latestDeploymentStatus) {
|
|
4449
|
+
console.log(
|
|
4450
|
+
source_default.white("Last deploy: ") + source_default.gray(server.latestDeploymentStatus)
|
|
4451
|
+
);
|
|
4452
|
+
}
|
|
4453
|
+
console.log(source_default.white("Region: ") + source_default.gray(server.region));
|
|
4454
|
+
console.log(
|
|
4455
|
+
source_default.white("MCP URL: ") + source_default.cyan(getMcpServerUrlForCloudServer(server))
|
|
4456
|
+
);
|
|
4457
|
+
if (server.connectedRepository) {
|
|
4458
|
+
const cr = server.connectedRepository;
|
|
4459
|
+
console.log(source_default.white("\nRepository"));
|
|
4460
|
+
console.log(source_default.white(" Full name: ") + source_default.gray(cr.repoFullName));
|
|
4461
|
+
console.log(
|
|
4462
|
+
source_default.white(" Prod branch: ") + source_default.gray(cr.productionBranch)
|
|
4463
|
+
);
|
|
4464
|
+
}
|
|
4465
|
+
if (server.activeDeploymentId) {
|
|
4466
|
+
console.log(
|
|
4467
|
+
source_default.white("\nActive deployment: ") + source_default.cyan(server.activeDeploymentId)
|
|
4468
|
+
);
|
|
4469
|
+
}
|
|
4470
|
+
if (server.previousDeploymentId) {
|
|
4471
|
+
console.log(
|
|
4472
|
+
source_default.white("Previous deployment: ") + source_default.gray(server.previousDeploymentId)
|
|
4473
|
+
);
|
|
4474
|
+
}
|
|
4475
|
+
const depCount = server._count?.deployments;
|
|
4476
|
+
if (depCount != null) {
|
|
4477
|
+
console.log(
|
|
4478
|
+
source_default.white("Deployment count: ") + source_default.gray(String(depCount))
|
|
4479
|
+
);
|
|
4480
|
+
}
|
|
4481
|
+
console.log(
|
|
4482
|
+
source_default.white("Created: ") + source_default.gray(formatRelativeTime(server.createdAt))
|
|
4483
|
+
);
|
|
4484
|
+
console.log(
|
|
4485
|
+
source_default.white("Updated: ") + source_default.gray(formatRelativeTime(server.updatedAt))
|
|
4486
|
+
);
|
|
4487
|
+
const config = await readConfig();
|
|
4488
|
+
const base = (await getWebUrl()).replace(/\/$/, "");
|
|
4489
|
+
if (config.orgSlug) {
|
|
4490
|
+
console.log(
|
|
4491
|
+
source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/${config.orgSlug}/servers/${server.id}`)
|
|
4492
|
+
);
|
|
4493
|
+
} else {
|
|
4494
|
+
console.log(
|
|
4495
|
+
source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/servers/${server.id}`)
|
|
4496
|
+
);
|
|
4497
|
+
}
|
|
4498
|
+
if (Array.isArray(server.deployments) && server.deployments.length > 0) {
|
|
4499
|
+
console.log(source_default.cyan.bold("\nRecent deployments\n"));
|
|
4500
|
+
console.log(
|
|
4501
|
+
source_default.white.bold(
|
|
4502
|
+
`${"ID".padEnd(40)} ${"NAME".padEnd(24)} ${"STATUS".padEnd(12)} ${"UPDATED"}`
|
|
4503
|
+
)
|
|
4504
|
+
);
|
|
4505
|
+
console.log(source_default.gray("\u2500".repeat(100)));
|
|
4506
|
+
for (const d of server.deployments) {
|
|
4507
|
+
const did = pickStr(d, "id").padEnd(40);
|
|
4508
|
+
const dname = pickStr(d, "name").substring(0, 23).padEnd(24);
|
|
4509
|
+
const dst = pickStr(d, "status").padEnd(12);
|
|
4510
|
+
const du = pickStr(d, "updatedAt");
|
|
4511
|
+
const updated = du !== "-" ? formatRelativeTime(du) : source_default.gray("-");
|
|
4512
|
+
const sc = getStatusColor2(dst.trim());
|
|
4513
|
+
console.log(
|
|
4514
|
+
`${source_default.gray(did)} ${dname} ${sc(dst)} ${source_default.gray(updated)}`
|
|
4515
|
+
);
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
console.log();
|
|
4508
4519
|
} catch (error) {
|
|
4509
4520
|
console.error(
|
|
4510
|
-
source_default.red.bold("\n\u2717 Failed to
|
|
4521
|
+
source_default.red.bold("\n\u2717 Failed to get server:"),
|
|
4511
4522
|
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4512
4523
|
);
|
|
4513
4524
|
process.exit(1);
|
|
4514
4525
|
}
|
|
4515
4526
|
}
|
|
4516
|
-
async function
|
|
4527
|
+
async function deleteServerCommand(serverId, options) {
|
|
4517
4528
|
try {
|
|
4518
4529
|
if (!await isLoggedIn()) {
|
|
4519
4530
|
console.log(source_default.red("\u2717 You are not logged in."));
|
|
@@ -4525,36 +4536,59 @@ async function startDeploymentCommand(deploymentId) {
|
|
|
4525
4536
|
process.exit(1);
|
|
4526
4537
|
}
|
|
4527
4538
|
const api = await McpUseAPI.create();
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4539
|
+
await applyOrgOption(api, options.org);
|
|
4540
|
+
if (options.org) console.log();
|
|
4541
|
+
const server = await api.getServer(serverId);
|
|
4542
|
+
if (!options.yes) {
|
|
4543
|
+
console.log(
|
|
4544
|
+
source_default.yellow(
|
|
4545
|
+
`
|
|
4546
|
+
\u26A0\uFE0F You are about to delete server: ${source_default.white(server.name || server.slug || server.id)}`
|
|
4547
|
+
)
|
|
4548
|
+
);
|
|
4549
|
+
console.log(source_default.gray(` ID: ${server.id}`));
|
|
4550
|
+
if (server.connectedRepository?.repoFullName) {
|
|
4551
|
+
console.log(
|
|
4552
|
+
source_default.gray(` Repo: ${server.connectedRepository.repoFullName}
|
|
4553
|
+
`)
|
|
4554
|
+
);
|
|
4555
|
+
} else {
|
|
4556
|
+
console.log();
|
|
4557
|
+
}
|
|
4558
|
+
const confirmed = await prompt3(
|
|
4559
|
+
source_default.white(
|
|
4560
|
+
"This deletes the server and all its deployments. Continue? (y/N): "
|
|
4561
|
+
)
|
|
4562
|
+
);
|
|
4563
|
+
if (!confirmed) {
|
|
4564
|
+
console.log(source_default.gray("Deletion cancelled."));
|
|
4565
|
+
return;
|
|
4566
|
+
}
|
|
4567
|
+
}
|
|
4568
|
+
await api.deleteServer(server.id);
|
|
4569
|
+
console.log(
|
|
4570
|
+
source_default.green.bold(
|
|
4571
|
+
`
|
|
4572
|
+
\u2713 Server deleted: ${server.name || server.slug || server.id}
|
|
4573
|
+
`
|
|
4574
|
+
)
|
|
4575
|
+
);
|
|
4534
4576
|
} catch (error) {
|
|
4535
4577
|
console.error(
|
|
4536
|
-
source_default.red.bold("\n\u2717 Failed to
|
|
4578
|
+
source_default.red.bold("\n\u2717 Failed to delete server:"),
|
|
4537
4579
|
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4538
4580
|
);
|
|
4539
4581
|
process.exit(1);
|
|
4540
4582
|
}
|
|
4541
4583
|
}
|
|
4542
|
-
function
|
|
4543
|
-
const
|
|
4544
|
-
"Manage cloud
|
|
4584
|
+
function createServersCommand() {
|
|
4585
|
+
const serversCommand = new Command3("servers").description(
|
|
4586
|
+
"Manage cloud servers (Git-backed deploy targets)"
|
|
4545
4587
|
);
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
deploymentsCommand.command("logs").argument("<deployment-id>", "Deployment ID").option("-b, --build", "Show build logs instead of runtime logs").option("-f, --follow", "Stream logs in real-time").description("View deployment logs").action(logsCommand);
|
|
4551
|
-
const envCommand = deploymentsCommand.command("env").description("Manage environment variables");
|
|
4552
|
-
envCommand.command("list").argument("<deployment-id>", "Deployment ID").description("List environment variables").action(listEnvCommand);
|
|
4553
|
-
envCommand.command("set").argument("<deployment-id>", "Deployment ID").argument("<pairs...>", "Environment variables in KEY=VALUE format").description("Set environment variables").action(setEnvCommand);
|
|
4554
|
-
envCommand.command("unset").argument("<deployment-id>", "Deployment ID").argument("<keys...>", "Environment variable keys to remove").description("Unset environment variables").action(unsetEnvCommand);
|
|
4555
|
-
deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
|
|
4556
|
-
deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
|
|
4557
|
-
return deploymentsCommand;
|
|
4588
|
+
serversCommand.command("list").alias("ls").description("List servers for the current organization").option("--org <slug-or-id>", "Target organization (slug, id, or name)").option("--limit <n>", "Page size (1\u2013100, default 50)").option("--skip <n>", "Offset for pagination").option("--sort <field:asc|desc>", "Sort (e.g. updatedAt:desc)").action(listServersCommand);
|
|
4589
|
+
serversCommand.command("get").argument("<id-or-slug>", "Server UUID or slug").option("--org <slug-or-id>", "Resolve org context before fetch").description("Show server details and recent deployments").action(getServerCommand);
|
|
4590
|
+
serversCommand.command("delete").alias("rm").argument("<server-id>", "Server UUID (or slug if API accepts it)").option("-y, --yes", "Skip confirmation prompt").option("--org <slug-or-id>", "Target organization").description("Delete a server and all its deployments").action(deleteServerCommand);
|
|
4591
|
+
return serversCommand;
|
|
4558
4592
|
}
|
|
4559
4593
|
|
|
4560
4594
|
// src/commands/org.ts
|
|
@@ -4574,22 +4608,22 @@ async function orgListCommand() {
|
|
|
4574
4608
|
const api = await McpUseAPI.create();
|
|
4575
4609
|
const authInfo = await api.testAuth();
|
|
4576
4610
|
const config = await readConfig();
|
|
4577
|
-
const
|
|
4578
|
-
const activeId = config.
|
|
4579
|
-
if (
|
|
4611
|
+
const orgs = authInfo.orgs ?? [];
|
|
4612
|
+
const activeId = config.orgId || authInfo.default_org_id;
|
|
4613
|
+
if (orgs.length === 0) {
|
|
4580
4614
|
console.log(source_default.yellow("No organizations found."));
|
|
4581
4615
|
return;
|
|
4582
4616
|
}
|
|
4583
4617
|
console.log(source_default.cyan.bold("\u{1F3E2} Your organizations:\n"));
|
|
4584
|
-
for (const
|
|
4585
|
-
const isActive =
|
|
4618
|
+
for (const o of orgs) {
|
|
4619
|
+
const isActive = o.id === activeId;
|
|
4586
4620
|
const marker = isActive ? source_default.green(" \u2190 active") : "";
|
|
4587
|
-
const slug =
|
|
4588
|
-
const role = source_default.gray(` [${
|
|
4589
|
-
const name = isActive ? source_default.cyan.bold(
|
|
4621
|
+
const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
|
|
4622
|
+
const role = source_default.gray(` [${o.role}]`);
|
|
4623
|
+
const name = isActive ? source_default.cyan.bold(o.name) : source_default.white(o.name);
|
|
4590
4624
|
console.log(` ${name}${slug}${role}${marker}`);
|
|
4591
4625
|
}
|
|
4592
|
-
if (
|
|
4626
|
+
if (orgs.length > 1) {
|
|
4593
4627
|
console.log(
|
|
4594
4628
|
source_default.gray("\nSwitch with " + source_default.white("npx mcp-use org switch"))
|
|
4595
4629
|
);
|
|
@@ -4608,40 +4642,40 @@ async function orgSwitchCommand() {
|
|
|
4608
4642
|
const api = await McpUseAPI.create();
|
|
4609
4643
|
const authInfo = await api.testAuth();
|
|
4610
4644
|
const config = await readConfig();
|
|
4611
|
-
const
|
|
4612
|
-
if (
|
|
4645
|
+
const orgs = authInfo.orgs ?? [];
|
|
4646
|
+
if (orgs.length === 0) {
|
|
4613
4647
|
console.log(source_default.yellow("No organizations found."));
|
|
4614
4648
|
return;
|
|
4615
4649
|
}
|
|
4616
|
-
if (
|
|
4617
|
-
const
|
|
4618
|
-
const slug2 =
|
|
4650
|
+
if (orgs.length === 1) {
|
|
4651
|
+
const o = orgs[0];
|
|
4652
|
+
const slug2 = o.slug ? source_default.gray(` (${o.slug})`) : "";
|
|
4619
4653
|
console.log(
|
|
4620
4654
|
source_default.yellow(
|
|
4621
|
-
`You only have one organization: ${source_default.cyan(
|
|
4655
|
+
`You only have one organization: ${source_default.cyan(o.name)}${slug2}`
|
|
4622
4656
|
)
|
|
4623
4657
|
);
|
|
4624
4658
|
return;
|
|
4625
4659
|
}
|
|
4626
|
-
const activeId = config.
|
|
4627
|
-
const selected = await promptOrgSelection(
|
|
4660
|
+
const activeId = config.orgId || authInfo.default_org_id;
|
|
4661
|
+
const selected = await promptOrgSelection(orgs, activeId);
|
|
4628
4662
|
if (!selected) {
|
|
4629
4663
|
console.log(source_default.yellow("No organization selected."));
|
|
4630
4664
|
return;
|
|
4631
4665
|
}
|
|
4632
4666
|
await writeConfig({
|
|
4633
4667
|
...config,
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4668
|
+
orgId: selected.id,
|
|
4669
|
+
orgName: selected.name,
|
|
4670
|
+
orgSlug: selected.slug ?? void 0
|
|
4637
4671
|
});
|
|
4638
4672
|
try {
|
|
4639
|
-
await api.
|
|
4673
|
+
await api.setDefaultOrg(selected.id);
|
|
4640
4674
|
} catch {
|
|
4641
4675
|
}
|
|
4642
4676
|
const slug = selected.slug ? source_default.gray(` (${selected.slug})`) : "";
|
|
4643
4677
|
console.log(
|
|
4644
|
-
source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.
|
|
4678
|
+
source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.name) + slug
|
|
4645
4679
|
);
|
|
4646
4680
|
} catch (error) {
|
|
4647
4681
|
console.error(
|
|
@@ -4655,7 +4689,7 @@ async function orgCurrentCommand() {
|
|
|
4655
4689
|
try {
|
|
4656
4690
|
if (!await ensureLoggedIn()) return;
|
|
4657
4691
|
const config = await readConfig();
|
|
4658
|
-
if (!config.
|
|
4692
|
+
if (!config.orgId) {
|
|
4659
4693
|
console.log(
|
|
4660
4694
|
source_default.yellow(
|
|
4661
4695
|
"No organization selected. Run " + source_default.white("npx mcp-use org switch") + " to pick one."
|
|
@@ -4663,9 +4697,9 @@ async function orgCurrentCommand() {
|
|
|
4663
4697
|
);
|
|
4664
4698
|
return;
|
|
4665
4699
|
}
|
|
4666
|
-
const slug = config.
|
|
4700
|
+
const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
|
|
4667
4701
|
console.log(
|
|
4668
|
-
source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.
|
|
4702
|
+
source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.orgName || config.orgId) + slug
|
|
4669
4703
|
);
|
|
4670
4704
|
} catch (error) {
|
|
4671
4705
|
console.error(
|
|
@@ -4677,7 +4711,7 @@ async function orgCurrentCommand() {
|
|
|
4677
4711
|
}
|
|
4678
4712
|
|
|
4679
4713
|
// src/commands/skills.ts
|
|
4680
|
-
import { Command as
|
|
4714
|
+
import { Command as Command4 } from "commander";
|
|
4681
4715
|
import { cpSync, existsSync as existsSync2, mkdtempSync, readdirSync, rmSync } from "fs";
|
|
4682
4716
|
import { tmpdir } from "os";
|
|
4683
4717
|
import { join as join2, resolve } from "path";
|
|
@@ -4747,7 +4781,7 @@ async function addSkillsToProject(projectPath) {
|
|
|
4747
4781
|
}
|
|
4748
4782
|
}
|
|
4749
4783
|
function createSkillsCommand() {
|
|
4750
|
-
const skills = new
|
|
4784
|
+
const skills = new Command4("skills").description(
|
|
4751
4785
|
"Manage mcp-use AI agent skills"
|
|
4752
4786
|
);
|
|
4753
4787
|
const installAction = async (options) => {
|
|
@@ -4923,7 +4957,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
4923
4957
|
}
|
|
4924
4958
|
|
|
4925
4959
|
// src/index.ts
|
|
4926
|
-
var program = new
|
|
4960
|
+
var program = new Command5();
|
|
4927
4961
|
var packageContent = readFileSync2(
|
|
4928
4962
|
path7.join(__dirname, "../package.json"),
|
|
4929
4963
|
"utf-8"
|
|
@@ -6751,7 +6785,13 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
|
|
|
6751
6785
|
).option(
|
|
6752
6786
|
"--org <slug-or-id>",
|
|
6753
6787
|
"Deploy to a specific organization (by slug or ID)"
|
|
6754
|
-
).option("-y, --yes", "Skip confirmation prompts").
|
|
6788
|
+
).option("-y, --yes", "Skip confirmation prompts").option("--region <region>", "Deploy region: US, EU, or APAC (default: US)").option(
|
|
6789
|
+
"--build-command <cmd>",
|
|
6790
|
+
"Custom build command (overrides auto-detection)"
|
|
6791
|
+
).option(
|
|
6792
|
+
"--start-command <cmd>",
|
|
6793
|
+
"Custom start command (overrides auto-detection)"
|
|
6794
|
+
).action(async (options) => {
|
|
6755
6795
|
await deployCommand({
|
|
6756
6796
|
open: options.open,
|
|
6757
6797
|
name: options.name,
|
|
@@ -6762,11 +6802,15 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
|
|
|
6762
6802
|
envFile: options.envFile,
|
|
6763
6803
|
rootDir: options.rootDir,
|
|
6764
6804
|
org: options.org,
|
|
6765
|
-
yes: options.yes
|
|
6805
|
+
yes: options.yes,
|
|
6806
|
+
region: options.region,
|
|
6807
|
+
buildCommand: options.buildCommand,
|
|
6808
|
+
startCommand: options.startCommand
|
|
6766
6809
|
});
|
|
6767
6810
|
});
|
|
6768
6811
|
program.addCommand(createClientCommand());
|
|
6769
6812
|
program.addCommand(createDeploymentsCommand());
|
|
6813
|
+
program.addCommand(createServersCommand());
|
|
6770
6814
|
program.addCommand(createSkillsCommand());
|
|
6771
6815
|
program.command("generate-types").description(
|
|
6772
6816
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|