@mcp-use/cli 3.0.2-canary.0 → 3.0.2-canary.2

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/index.js CHANGED
@@ -1202,6 +1202,13 @@ var GitHubAuthRequiredError = class extends Error {
1202
1202
  this.authorizeUrl = authorizeUrl;
1203
1203
  }
1204
1204
  };
1205
+ var ApiUnauthorizedError = class extends Error {
1206
+ status = 401;
1207
+ constructor(message = "Your session has expired or your API key is invalid.") {
1208
+ super(message);
1209
+ this.name = "ApiUnauthorizedError";
1210
+ }
1211
+ };
1205
1212
  var McpUseAPI = class _McpUseAPI {
1206
1213
  baseUrl;
1207
1214
  apiKey;
@@ -1243,11 +1250,7 @@ var McpUseAPI = class _McpUseAPI {
1243
1250
  });
1244
1251
  clearTimeout(timeoutId);
1245
1252
  if (response.status === 401) {
1246
- const err = new Error(
1247
- "Your session has expired or your API key is invalid."
1248
- );
1249
- err.status = 401;
1250
- throw err;
1253
+ throw new ApiUnauthorizedError();
1251
1254
  }
1252
1255
  if (!response.ok) {
1253
1256
  const errorText = await response.text();
@@ -2803,12 +2806,12 @@ import { promises as fs9 } from "fs";
2803
2806
  import path5 from "path";
2804
2807
 
2805
2808
  // src/utils/git.ts
2806
- import { exec } from "child_process";
2809
+ import { execFile as execFile7 } from "child_process";
2807
2810
  import { promisify as promisify7 } from "util";
2808
- var execAsync = promisify7(exec);
2809
- async function gitCommand(command, cwd = process.cwd()) {
2811
+ var execFileAsync5 = promisify7(execFile7);
2812
+ async function gitCommand(args, cwd = process.cwd()) {
2810
2813
  try {
2811
- const { stdout } = await execAsync(command, { cwd });
2814
+ const { stdout } = await execFileAsync5("git", args, { cwd });
2812
2815
  return stdout.trim();
2813
2816
  } catch (error) {
2814
2817
  return null;
@@ -2830,9 +2833,10 @@ ${trimmed}`);
2830
2833
  this.exitCode = opts.exitCode;
2831
2834
  }
2832
2835
  };
2833
- async function gitCommandOrThrow(command, cwd = process.cwd()) {
2836
+ async function gitCommandOrThrow(args, cwd = process.cwd()) {
2837
+ const command = `git ${args.join(" ")}`;
2834
2838
  try {
2835
- const { stdout } = await execAsync(command, { cwd });
2839
+ const { stdout } = await execFileAsync5("git", args, { cwd });
2836
2840
  return stdout.trim();
2837
2841
  } catch (error) {
2838
2842
  const e = error;
@@ -2845,11 +2849,11 @@ async function gitCommandOrThrow(command, cwd = process.cwd()) {
2845
2849
  }
2846
2850
  }
2847
2851
  async function isGitRepo(cwd = process.cwd()) {
2848
- const result = await gitCommand("git rev-parse --is-inside-work-tree", cwd);
2852
+ const result = await gitCommand(["rev-parse", "--is-inside-work-tree"], cwd);
2849
2853
  return result === "true";
2850
2854
  }
2851
2855
  async function getRemoteUrl(cwd = process.cwd()) {
2852
- return gitCommand("git config --get remote.origin.url", cwd);
2856
+ return gitCommand(["config", "--get", "remote.origin.url"], cwd);
2853
2857
  }
2854
2858
  function parseGitHubUrl(url) {
2855
2859
  const sshMatch = url.match(/git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
@@ -2864,16 +2868,16 @@ function parseGitHubUrl(url) {
2864
2868
  };
2865
2869
  }
2866
2870
  async function getCurrentBranch(cwd = process.cwd()) {
2867
- return gitCommand("git rev-parse --abbrev-ref HEAD", cwd);
2871
+ return gitCommand(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
2868
2872
  }
2869
2873
  async function getCommitSha(cwd = process.cwd()) {
2870
- return gitCommand("git rev-parse HEAD", cwd);
2874
+ return gitCommand(["rev-parse", "HEAD"], cwd);
2871
2875
  }
2872
2876
  async function getCommitMessage(cwd = process.cwd()) {
2873
- return gitCommand("git log -1 --pretty=%B", cwd);
2877
+ return gitCommand(["log", "-1", "--pretty=%B"], cwd);
2874
2878
  }
2875
2879
  async function hasUncommittedChanges(cwd = process.cwd()) {
2876
- const result = await gitCommand("git status --porcelain", cwd);
2880
+ const result = await gitCommand(["status", "--porcelain"], cwd);
2877
2881
  return result !== null && result.length > 0;
2878
2882
  }
2879
2883
  async function getGitInfo(cwd = process.cwd()) {
@@ -2906,24 +2910,21 @@ async function getGitInfo(cwd = process.cwd()) {
2906
2910
  hasUncommittedChanges: uncommittedChanges
2907
2911
  };
2908
2912
  }
2909
- function shellQuote(message) {
2910
- return `"${message.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
2911
- }
2912
2913
  async function gitInit(cwd, message = "Initial commit") {
2913
- await gitCommandOrThrow("git init", cwd);
2914
- await gitCommandOrThrow("git add .", cwd);
2915
- await gitCommandOrThrow(`git commit -m ${shellQuote(message)}`, cwd);
2916
- await gitCommandOrThrow("git branch -M main", cwd);
2917
- await gitCommandOrThrow("git rev-parse HEAD", cwd);
2914
+ await gitCommandOrThrow(["init"], cwd);
2915
+ await gitCommandOrThrow(["add", "."], cwd);
2916
+ await gitCommandOrThrow(["commit", "-m", message], cwd);
2917
+ await gitCommandOrThrow(["branch", "-M", "main"], cwd);
2918
+ await gitCommandOrThrow(["rev-parse", "HEAD"], cwd);
2918
2919
  }
2919
2920
  async function gitAddRemoteAndPush(cwd, cloneUrl, branch = "main") {
2920
- await gitCommandOrThrow(`git remote add origin ${cloneUrl}`, cwd);
2921
- await gitCommandOrThrow(`git push -u origin ${branch}`, cwd);
2921
+ await gitCommandOrThrow(["remote", "add", "origin", cloneUrl], cwd);
2922
+ await gitCommandOrThrow(["push", "-u", "origin", branch], cwd);
2922
2923
  }
2923
2924
  async function gitCommitAndPush(cwd, message, branch = "main") {
2924
- await gitCommandOrThrow("git add .", cwd);
2925
- await gitCommandOrThrow(`git commit -m ${shellQuote(message)}`, cwd);
2926
- await gitCommandOrThrow(`git push origin ${branch}`, cwd);
2925
+ await gitCommandOrThrow(["add", "."], cwd);
2926
+ await gitCommandOrThrow(["commit", "-m", message], cwd);
2927
+ await gitCommandOrThrow(["push", "origin", branch], cwd);
2927
2928
  }
2928
2929
  function isGitHubUrl(url) {
2929
2930
  try {
@@ -3324,6 +3325,58 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3324
3325
  source_default.gray("Check status with: ") + source_default.white(`mcp-use deployments get ${deploymentId}`)
3325
3326
  );
3326
3327
  }
3328
+ async function promptReauthenticateOn401(options, orgIdToRestore) {
3329
+ console.log(source_default.red("\n\u2717 Session expired or API key invalid."));
3330
+ if (options.yes) {
3331
+ console.log(
3332
+ source_default.gray(" Run mcp-use login to re-authenticate, then retry.")
3333
+ );
3334
+ process.exit(1);
3335
+ }
3336
+ const should = await prompt(source_default.white("Log in again? (Y/n): "), "y");
3337
+ if (!should) {
3338
+ process.exit(1);
3339
+ }
3340
+ await loginCommand({ silent: false });
3341
+ if (!await isLoggedIn()) {
3342
+ console.log(source_default.red("\u2717 Login failed. Please try again."));
3343
+ process.exit(1);
3344
+ }
3345
+ const fresh = await McpUseAPI.create();
3346
+ if (orgIdToRestore) {
3347
+ fresh.setOrgId(orgIdToRestore);
3348
+ }
3349
+ return fresh;
3350
+ }
3351
+ async function ensureApiSessionForDeploy(api, options, orgIdToRestore) {
3352
+ let client = api;
3353
+ for (; ; ) {
3354
+ try {
3355
+ await client.testAuth();
3356
+ return client;
3357
+ } catch (e) {
3358
+ if (!(e instanceof ApiUnauthorizedError)) throw e;
3359
+ client = await promptReauthenticateOn401(options, orgIdToRestore);
3360
+ }
3361
+ }
3362
+ }
3363
+ async function getGitHubConnectionStatusWith401Retry(api, options, orgIdToRestore) {
3364
+ let client = api;
3365
+ for (let attempt = 0; attempt < 2; attempt++) {
3366
+ try {
3367
+ const status = await client.getGitHubConnectionStatus();
3368
+ return { api: client, status };
3369
+ } catch (e) {
3370
+ if (e instanceof ApiUnauthorizedError && attempt === 0) {
3371
+ client = await promptReauthenticateOn401(options, orgIdToRestore);
3372
+ await client.testAuth();
3373
+ continue;
3374
+ }
3375
+ throw e;
3376
+ }
3377
+ }
3378
+ throw new Error("Unreachable");
3379
+ }
3327
3380
  async function checkRepoAccess(api, owner, repo) {
3328
3381
  try {
3329
3382
  const resp = await api.getGitHubRepos(true);
@@ -3334,6 +3387,7 @@ async function checkRepoAccess(api, owner, repo) {
3334
3387
  }
3335
3388
  async function promptGitHubInstallation(api, reason, repoName, opts) {
3336
3389
  const yes = !!opts?.yes;
3390
+ const reauth = opts?.reauth;
3337
3391
  console.log();
3338
3392
  if (reason === "not_connected") {
3339
3393
  console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
@@ -3357,9 +3411,23 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
3357
3411
  ),
3358
3412
  "y"
3359
3413
  );
3360
- if (!shouldInstall) return false;
3414
+ if (!shouldInstall) return { ok: false, api };
3415
+ let client = api;
3361
3416
  try {
3362
- const appName = await api.getGitHubAppName();
3417
+ let appName;
3418
+ for (; ; ) {
3419
+ try {
3420
+ appName = await client.getGitHubAppName();
3421
+ break;
3422
+ } catch (e) {
3423
+ if (e instanceof ApiUnauthorizedError && reauth) {
3424
+ client = await reauth();
3425
+ await client.testAuth();
3426
+ continue;
3427
+ }
3428
+ throw e;
3429
+ }
3430
+ }
3363
3431
  const installUrl = `https://github.com/apps/${appName}/installations/new`;
3364
3432
  console.log(source_default.cyan(`
3365
3433
  Opening browser...`));
@@ -3383,23 +3451,34 @@ Opening browser...`));
3383
3451
  while (Date.now() < deadline) {
3384
3452
  await new Promise((r) => setTimeout(r, 2e3));
3385
3453
  try {
3386
- const status = await api.getGitHubConnectionStatus();
3454
+ const status = await client.getGitHubConnectionStatus();
3387
3455
  if (status.is_connected) {
3388
- if (!repoName) return true;
3456
+ if (!repoName) return { ok: true, api: client };
3389
3457
  const [o, r] = repoName.split("/");
3390
- if (o && r && await checkRepoAccess(api, o, r)) return true;
3458
+ if (o && r && await checkRepoAccess(client, o, r)) {
3459
+ return { ok: true, api: client };
3460
+ }
3461
+ }
3462
+ } catch (e) {
3463
+ if (e instanceof ApiUnauthorizedError && reauth) {
3464
+ client = await reauth();
3465
+ await client.testAuth();
3466
+ continue;
3391
3467
  }
3392
- } catch {
3393
3468
  }
3394
3469
  }
3395
3470
  }
3396
- return true;
3397
- } catch {
3471
+ return { ok: true, api: client };
3472
+ } catch (e) {
3473
+ if (e instanceof ApiUnauthorizedError) {
3474
+ console.log(source_default.red("\n\u2717 Session expired or API key invalid."));
3475
+ process.exit(1);
3476
+ }
3398
3477
  console.log(source_default.yellow("\n\u26A0\uFE0F Unable to open browser automatically"));
3399
3478
  console.log(
3400
3479
  source_default.white("Please visit: ") + source_default.cyan("https://manufact.com/cloud/settings")
3401
3480
  );
3402
- return false;
3481
+ return { ok: false, api: client };
3403
3482
  }
3404
3483
  }
3405
3484
  async function deployCommand(options) {
@@ -3442,7 +3521,8 @@ async function deployCommand(options) {
3442
3521
  process.exit(1);
3443
3522
  }
3444
3523
  }
3445
- const api = await McpUseAPI.create();
3524
+ let api = await McpUseAPI.create();
3525
+ let resolvedOrgId;
3446
3526
  if (options.org) {
3447
3527
  const authInfo = await api.testAuth();
3448
3528
  const match = (authInfo.orgs ?? []).find(
@@ -3450,6 +3530,7 @@ async function deployCommand(options) {
3450
3530
  );
3451
3531
  if (match) {
3452
3532
  api.setOrgId(match.id);
3533
+ resolvedOrgId = match.id;
3453
3534
  const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3454
3535
  console.log(
3455
3536
  source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
@@ -3488,6 +3569,7 @@ async function deployCommand(options) {
3488
3569
  process.exit(1);
3489
3570
  }
3490
3571
  api.setOrgId(selectedOrg.id);
3572
+ resolvedOrgId = selectedOrg.id;
3491
3573
  await writeConfig({
3492
3574
  ...config,
3493
3575
  orgId: selectedOrg.id,
@@ -3498,6 +3580,8 @@ async function deployCommand(options) {
3498
3580
  source_default.gray("Organization: ") + source_default.cyan(selectedOrg.name)
3499
3581
  );
3500
3582
  } else {
3583
+ resolvedOrgId = config.orgId;
3584
+ api.setOrgId(config.orgId);
3501
3585
  if (config.orgName) {
3502
3586
  const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
3503
3587
  console.log(
@@ -3506,21 +3590,39 @@ async function deployCommand(options) {
3506
3590
  }
3507
3591
  }
3508
3592
  }
3593
+ api = await ensureApiSessionForDeploy(api, options, resolvedOrgId);
3509
3594
  console.log(source_default.cyan.bold("\n\u{1F680} Deploying to Manufact cloud...\n"));
3510
- let connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3511
- if (!connectionStatus?.is_connected) {
3595
+ const reauth = () => promptReauthenticateOn401(options, resolvedOrgId);
3596
+ let ghConn = await getGitHubConnectionStatusWith401Retry(
3597
+ api,
3598
+ options,
3599
+ resolvedOrgId
3600
+ );
3601
+ api = ghConn.api;
3602
+ let connectionStatus = ghConn.status;
3603
+ if (!connectionStatus.is_connected) {
3512
3604
  const installed = await promptGitHubInstallation(
3513
3605
  api,
3514
3606
  "not_connected",
3515
3607
  void 0,
3516
- { yes: options.yes }
3608
+ {
3609
+ yes: options.yes,
3610
+ reauth
3611
+ }
3517
3612
  );
3518
- if (!installed) {
3613
+ if (!installed.ok) {
3519
3614
  console.log(source_default.gray("Deployment cancelled."));
3520
3615
  process.exit(0);
3521
3616
  }
3522
- connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3523
- if (!connectionStatus?.is_connected) {
3617
+ api = installed.api;
3618
+ ghConn = await getGitHubConnectionStatusWith401Retry(
3619
+ api,
3620
+ options,
3621
+ resolvedOrgId
3622
+ );
3623
+ api = ghConn.api;
3624
+ connectionStatus = ghConn.status;
3625
+ if (!connectionStatus.is_connected) {
3524
3626
  console.log(source_default.red("\n\u2717 GitHub connection could not be verified."));
3525
3627
  console.log(
3526
3628
  source_default.cyan(
@@ -3799,11 +3901,16 @@ async function deployCommand(options) {
3799
3901
  api,
3800
3902
  "no_access",
3801
3903
  repoFullName,
3802
- { yes: options.yes, installationId: githubInstallationId }
3904
+ {
3905
+ yes: options.yes,
3906
+ installationId: githubInstallationId,
3907
+ reauth: () => promptReauthenticateOn401(options, resolvedOrgId)
3908
+ }
3803
3909
  );
3804
- if (!configured) {
3910
+ if (!configured.ok) {
3805
3911
  process.exit(0);
3806
3912
  }
3913
+ api = configured.api;
3807
3914
  const retry = await checkRepoAccess(api, gitInfo.owner, gitInfo.repo);
3808
3915
  if (!retry) {
3809
3916
  const appName = await api.getGitHubAppName();