@mcpcloud/cli 0.18.0 → 0.19.0-next-20260901020935
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/README.md +193 -42
- package/dist/index.js +535 -181
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,12 +20,14 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
20
20
|
}
|
|
21
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(mod))
|
|
25
|
+
if (!__hasOwnProp.call(to, key))
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
28
|
+
enumerable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
29
31
|
if (canCache)
|
|
30
32
|
cache.set(mod, to);
|
|
31
33
|
return to;
|
|
@@ -48,7 +50,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
48
50
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
49
51
|
|
|
50
52
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
|
|
51
|
-
var require_error = __commonJS((exports)
|
|
53
|
+
var require_error = __commonJS(function(exports) {
|
|
52
54
|
class CommanderError extends Error {
|
|
53
55
|
constructor(exitCode, code, message) {
|
|
54
56
|
super(message);
|
|
@@ -72,7 +74,7 @@ var require_error = __commonJS((exports) => {
|
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
|
|
75
|
-
var require_argument = __commonJS((exports)
|
|
77
|
+
var require_argument = __commonJS(function(exports) {
|
|
76
78
|
var { InvalidArgumentError } = require_error();
|
|
77
79
|
|
|
78
80
|
class Argument {
|
|
@@ -151,7 +153,7 @@ var require_argument = __commonJS((exports) => {
|
|
|
151
153
|
});
|
|
152
154
|
|
|
153
155
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
|
|
154
|
-
var require_help = __commonJS((exports)
|
|
156
|
+
var require_help = __commonJS(function(exports) {
|
|
155
157
|
var { humanReadableArgName } = require_argument();
|
|
156
158
|
|
|
157
159
|
class Help {
|
|
@@ -400,7 +402,7 @@ var require_help = __commonJS((exports) => {
|
|
|
400
402
|
});
|
|
401
403
|
|
|
402
404
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
|
|
403
|
-
var require_option = __commonJS((exports)
|
|
405
|
+
var require_option = __commonJS(function(exports) {
|
|
404
406
|
var { InvalidArgumentError } = require_error();
|
|
405
407
|
|
|
406
408
|
class Option {
|
|
@@ -551,7 +553,7 @@ var require_option = __commonJS((exports) => {
|
|
|
551
553
|
});
|
|
552
554
|
|
|
553
555
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
|
|
554
|
-
var require_suggestSimilar = __commonJS((exports)
|
|
556
|
+
var require_suggestSimilar = __commonJS(function(exports) {
|
|
555
557
|
var maxDistance = 3;
|
|
556
558
|
function editDistance(a, b) {
|
|
557
559
|
if (Math.abs(a.length - b.length) > maxDistance)
|
|
@@ -624,7 +626,7 @@ var require_suggestSimilar = __commonJS((exports) => {
|
|
|
624
626
|
});
|
|
625
627
|
|
|
626
628
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
|
|
627
|
-
var require_command = __commonJS((exports)
|
|
629
|
+
var require_command = __commonJS(function(exports) {
|
|
628
630
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
629
631
|
var childProcess = __require("node:child_process");
|
|
630
632
|
var path = __require("node:path");
|
|
@@ -1867,7 +1869,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1867
1869
|
});
|
|
1868
1870
|
|
|
1869
1871
|
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
|
|
1870
|
-
var require_commander = __commonJS((exports)
|
|
1872
|
+
var require_commander = __commonJS(function(exports) {
|
|
1871
1873
|
var { Argument } = require_argument();
|
|
1872
1874
|
var { Command } = require_command();
|
|
1873
1875
|
var { CommanderError, InvalidArgumentError } = require_error();
|
|
@@ -2226,7 +2228,7 @@ var init_main = __esm(() => {
|
|
|
2226
2228
|
});
|
|
2227
2229
|
|
|
2228
2230
|
// ../../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
|
|
2229
|
-
var require_src = __commonJS((exports, module)
|
|
2231
|
+
var require_src = __commonJS(function(exports, module) {
|
|
2230
2232
|
var ESC2 = "\x1B";
|
|
2231
2233
|
var CSI2 = `${ESC2}[`;
|
|
2232
2234
|
var beep = "\x07";
|
|
@@ -3073,65 +3075,65 @@ ${i}` : `${s}${v("inverse", e)}${i}`;
|
|
|
3073
3075
|
// ../../node_modules/.bun/@clack+prompts@1.4.0/node_modules/@clack/prompts/dist/index.mjs
|
|
3074
3076
|
var exports_dist = {};
|
|
3075
3077
|
__export(exports_dist, {
|
|
3076
|
-
|
|
3077
|
-
unicodeOr: () => w2,
|
|
3078
|
-
unicode: () => tt2,
|
|
3079
|
-
text: () => Pe,
|
|
3080
|
-
tasks: () => Ge,
|
|
3081
|
-
taskLog: () => Oe,
|
|
3082
|
-
symbolBar: () => yt,
|
|
3083
|
-
symbol: () => P2,
|
|
3084
|
-
stream: () => q2,
|
|
3085
|
-
spinner: () => ft,
|
|
3086
|
-
settings: () => h,
|
|
3087
|
-
selectKey: () => Ee,
|
|
3088
|
-
select: () => xe,
|
|
3089
|
-
progress: () => _e,
|
|
3090
|
-
path: () => Ie,
|
|
3091
|
-
password: () => Ce,
|
|
3092
|
-
outro: () => ye,
|
|
3093
|
-
note: () => Se,
|
|
3094
|
-
multiselect: () => ve,
|
|
3095
|
-
multiline: () => fe,
|
|
3096
|
-
log: () => R2,
|
|
3097
|
-
limitOptions: () => F2,
|
|
3098
|
-
isTTY: () => It,
|
|
3099
|
-
isCancel: () => q,
|
|
3100
|
-
isCI: () => ot2,
|
|
3101
|
-
intro: () => ge,
|
|
3102
|
-
groupMultiselect: () => pe,
|
|
3103
|
-
group: () => he,
|
|
3104
|
-
date: () => le,
|
|
3105
|
-
confirm: () => ue,
|
|
3106
|
-
cancel: () => me,
|
|
3107
|
-
box: () => ae,
|
|
3108
|
-
autocompleteMultiselect: () => ie,
|
|
3109
|
-
autocomplete: () => At,
|
|
3110
|
-
S_WARN: () => mt,
|
|
3111
|
-
S_SUCCESS: () => pt,
|
|
3112
|
-
S_STEP_SUBMIT: () => H2,
|
|
3113
|
-
S_STEP_ERROR: () => ut2,
|
|
3114
|
-
S_STEP_CANCEL: () => at2,
|
|
3115
|
-
S_STEP_ACTIVE: () => Tt,
|
|
3116
|
-
S_RADIO_INACTIVE: () => U2,
|
|
3117
|
-
S_RADIO_ACTIVE: () => z2,
|
|
3118
|
-
S_PASSWORD_MASK: () => Et,
|
|
3119
|
-
S_INFO: () => ht2,
|
|
3120
|
-
S_ERROR: () => gt,
|
|
3121
|
-
S_CORNER_TOP_RIGHT: () => ct,
|
|
3122
|
-
S_CORNER_TOP_LEFT: () => Mt,
|
|
3123
|
-
S_CORNER_BOTTOM_RIGHT: () => $t,
|
|
3124
|
-
S_CORNER_BOTTOM_LEFT: () => dt,
|
|
3125
|
-
S_CONNECT_LEFT: () => Gt,
|
|
3126
|
-
S_CHECKBOX_SELECTED: () => K2,
|
|
3127
|
-
S_CHECKBOX_INACTIVE: () => Y2,
|
|
3128
|
-
S_CHECKBOX_ACTIVE: () => et2,
|
|
3129
|
-
S_BAR_START_RIGHT: () => _t,
|
|
3130
|
-
S_BAR_START: () => lt,
|
|
3131
|
-
S_BAR_H: () => st2,
|
|
3132
|
-
S_BAR_END_RIGHT: () => xt,
|
|
3078
|
+
S_BAR: () => $2,
|
|
3133
3079
|
S_BAR_END: () => x2,
|
|
3134
|
-
|
|
3080
|
+
S_BAR_END_RIGHT: () => xt,
|
|
3081
|
+
S_BAR_H: () => st2,
|
|
3082
|
+
S_BAR_START: () => lt,
|
|
3083
|
+
S_BAR_START_RIGHT: () => _t,
|
|
3084
|
+
S_CHECKBOX_ACTIVE: () => et2,
|
|
3085
|
+
S_CHECKBOX_INACTIVE: () => Y2,
|
|
3086
|
+
S_CHECKBOX_SELECTED: () => K2,
|
|
3087
|
+
S_CONNECT_LEFT: () => Gt,
|
|
3088
|
+
S_CORNER_BOTTOM_LEFT: () => dt,
|
|
3089
|
+
S_CORNER_BOTTOM_RIGHT: () => $t,
|
|
3090
|
+
S_CORNER_TOP_LEFT: () => Mt,
|
|
3091
|
+
S_CORNER_TOP_RIGHT: () => ct,
|
|
3092
|
+
S_ERROR: () => gt,
|
|
3093
|
+
S_INFO: () => ht2,
|
|
3094
|
+
S_PASSWORD_MASK: () => Et,
|
|
3095
|
+
S_RADIO_ACTIVE: () => z2,
|
|
3096
|
+
S_RADIO_INACTIVE: () => U2,
|
|
3097
|
+
S_STEP_ACTIVE: () => Tt,
|
|
3098
|
+
S_STEP_CANCEL: () => at2,
|
|
3099
|
+
S_STEP_ERROR: () => ut2,
|
|
3100
|
+
S_STEP_SUBMIT: () => H2,
|
|
3101
|
+
S_SUCCESS: () => pt,
|
|
3102
|
+
S_WARN: () => mt,
|
|
3103
|
+
autocomplete: () => At,
|
|
3104
|
+
autocompleteMultiselect: () => ie,
|
|
3105
|
+
box: () => ae,
|
|
3106
|
+
cancel: () => me,
|
|
3107
|
+
confirm: () => ue,
|
|
3108
|
+
date: () => le,
|
|
3109
|
+
group: () => he,
|
|
3110
|
+
groupMultiselect: () => pe,
|
|
3111
|
+
intro: () => ge,
|
|
3112
|
+
isCI: () => ot2,
|
|
3113
|
+
isCancel: () => q,
|
|
3114
|
+
isTTY: () => It,
|
|
3115
|
+
limitOptions: () => F2,
|
|
3116
|
+
log: () => R2,
|
|
3117
|
+
multiline: () => fe,
|
|
3118
|
+
multiselect: () => ve,
|
|
3119
|
+
note: () => Se,
|
|
3120
|
+
outro: () => ye,
|
|
3121
|
+
password: () => Ce,
|
|
3122
|
+
path: () => Ie,
|
|
3123
|
+
progress: () => _e,
|
|
3124
|
+
select: () => xe,
|
|
3125
|
+
selectKey: () => Ee,
|
|
3126
|
+
settings: () => h,
|
|
3127
|
+
spinner: () => ft,
|
|
3128
|
+
stream: () => q2,
|
|
3129
|
+
symbol: () => P2,
|
|
3130
|
+
symbolBar: () => yt,
|
|
3131
|
+
taskLog: () => Oe,
|
|
3132
|
+
tasks: () => Ge,
|
|
3133
|
+
text: () => Pe,
|
|
3134
|
+
unicode: () => tt2,
|
|
3135
|
+
unicodeOr: () => w2,
|
|
3136
|
+
updateSettings: () => j
|
|
3135
3137
|
});
|
|
3136
3138
|
import { styleText as e, stripVTControlCharacters as nt2 } from "node:util";
|
|
3137
3139
|
import V2 from "node:process";
|
|
@@ -4070,7 +4072,8 @@ var PROFILE_FIELD_KEYS = [
|
|
|
4070
4072
|
"editorOpenTarget",
|
|
4071
4073
|
"editorCommand",
|
|
4072
4074
|
"defaultAgent",
|
|
4073
|
-
"aliases"
|
|
4075
|
+
"aliases",
|
|
4076
|
+
"gitRepoDirs"
|
|
4074
4077
|
];
|
|
4075
4078
|
function pickProfileFields(source) {
|
|
4076
4079
|
const out = {};
|
|
@@ -5621,7 +5624,7 @@ function registerAliasCommands(program2) {
|
|
|
5621
5624
|
"",
|
|
5622
5625
|
"Examples:",
|
|
5623
5626
|
" $ mcp alias set forge server:forge-code-issues-api",
|
|
5624
|
-
' $ mcp alias set
|
|
5627
|
+
' $ mcp alias set payments project:"Payments"',
|
|
5625
5628
|
" $ mcp servers deploy forge --wait",
|
|
5626
5629
|
" $ mcp alias list",
|
|
5627
5630
|
" $ mcp alias rm forge"
|
|
@@ -6080,7 +6083,7 @@ function registerAuthCommands(program2) {
|
|
|
6080
6083
|
"Examples:",
|
|
6081
6084
|
" $ mcp login # default: browser flow",
|
|
6082
6085
|
" $ mcp login --paste # SSH/headless: paste the key",
|
|
6083
|
-
" $ mcp login --key
|
|
6086
|
+
" $ mcp login --key mcf_abc… # save a key directly",
|
|
6084
6087
|
"",
|
|
6085
6088
|
"See `mcp help auth` for the full identity model."
|
|
6086
6089
|
].join(`
|
|
@@ -6794,6 +6797,225 @@ function requireServer(server) {
|
|
|
6794
6797
|
throw new CliExitError(1);
|
|
6795
6798
|
}
|
|
6796
6799
|
|
|
6800
|
+
// src/commands/servers-git.ts
|
|
6801
|
+
var GIT_LINK_PATH = "/api/v1/server/git-link";
|
|
6802
|
+
var GIT_SYNC_PATH = "/api/v1/server/git-sync";
|
|
6803
|
+
var GIT_SYNC_STATUS_PATH = "/api/v1/server/git-sync-status";
|
|
6804
|
+
var COMMIT_PATH = "/api/v1/server/commit";
|
|
6805
|
+
function reportApiError2(err, action) {
|
|
6806
|
+
if (err instanceof McpCloudApiError) {
|
|
6807
|
+
printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
|
|
6808
|
+
} else {
|
|
6809
|
+
printError(`${action} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
6810
|
+
}
|
|
6811
|
+
throw new CliExitError(1);
|
|
6812
|
+
}
|
|
6813
|
+
function shortSha(sha) {
|
|
6814
|
+
return sha ? sha.slice(0, 7) : "—";
|
|
6815
|
+
}
|
|
6816
|
+
function parseRepoRef(ref) {
|
|
6817
|
+
const match = /^([^/\s]+)\/([^/\s]+)$/.exec(ref.trim());
|
|
6818
|
+
if (!match || !match[1] || !match[2])
|
|
6819
|
+
return null;
|
|
6820
|
+
return { owner: match[1], name: match[2] };
|
|
6821
|
+
}
|
|
6822
|
+
function describeDeployed(deployed) {
|
|
6823
|
+
if (!deployed)
|
|
6824
|
+
return "—";
|
|
6825
|
+
if (!deployed.stamped)
|
|
6826
|
+
return "untracked (predates fingerprinting — redeploy to stamp)";
|
|
6827
|
+
if (deployed.behindHead === 0)
|
|
6828
|
+
return "up to date with HEAD";
|
|
6829
|
+
if (deployed.behindHead === null)
|
|
6830
|
+
return "behind HEAD (deployed from an uncommitted tree)";
|
|
6831
|
+
return `${deployed.behindHead} commit${deployed.behindHead === 1 ? "" : "s"} behind HEAD`;
|
|
6832
|
+
}
|
|
6833
|
+
function describeWorkingTree(tree) {
|
|
6834
|
+
const parts = [];
|
|
6835
|
+
if (tree.added > 0)
|
|
6836
|
+
parts.push(`${tree.added} added`);
|
|
6837
|
+
if (tree.modified > 0)
|
|
6838
|
+
parts.push(`${tree.modified} modified`);
|
|
6839
|
+
if (tree.deleted > 0)
|
|
6840
|
+
parts.push(`${tree.deleted} deleted`);
|
|
6841
|
+
if (parts.length === 0)
|
|
6842
|
+
return "clean";
|
|
6843
|
+
return `${parts.join(", ")} (uncommitted)`;
|
|
6844
|
+
}
|
|
6845
|
+
async function linkRepoAtCreation(args) {
|
|
6846
|
+
const repo = parseRepoRef(args.repoRef);
|
|
6847
|
+
if (!repo) {
|
|
6848
|
+
printError(`Invalid --git-repo "${args.repoRef}". Expected owner/name — the server was created without a linked repo.`);
|
|
6849
|
+
return;
|
|
6850
|
+
}
|
|
6851
|
+
try {
|
|
6852
|
+
await api.post(GIT_LINK_PATH, {
|
|
6853
|
+
organizationId: args.orgId,
|
|
6854
|
+
serverId: args.serverId,
|
|
6855
|
+
owner: repo.owner,
|
|
6856
|
+
name: repo.name,
|
|
6857
|
+
pathPrefix: args.pathPrefix,
|
|
6858
|
+
autoSync: args.autoSync,
|
|
6859
|
+
deferInitialSync: true
|
|
6860
|
+
});
|
|
6861
|
+
printSuccess(`Linked ${repo.owner}/${repo.name}${args.pathPrefix ? ` (prefix ${args.pathPrefix})` : ""} — the repo fills itself after the first generation${args.autoSync ? "" : " once you run `mcp servers git sync`"}.`);
|
|
6862
|
+
} catch (err) {
|
|
6863
|
+
printError(`Server created, but linking ${repo.owner}/${repo.name} failed: ${err instanceof McpCloudApiError ? err.error.message : String(err)}`);
|
|
6864
|
+
printInfo(` ${c.dim("Link it later with")} ${c.bold("mcp servers git link <server> --repo " + args.repoRef)}`);
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
function registerServerGitCommands(servers) {
|
|
6868
|
+
const git = servers.command("git").description("Link a server to a GitHub repo and drive the sync loop from the terminal");
|
|
6869
|
+
git.command("status <server>").description("Show the server's git link, mirror + reconcile state, and working-tree changes").option("--org <organizationId>", "Organization ID").action(runAction(async (serverRef, opts) => {
|
|
6870
|
+
const orgId = await resolveOrgId(opts.org);
|
|
6871
|
+
const serverId = await resolveServerId(serverRef, orgId);
|
|
6872
|
+
const data = await api.get(GIT_SYNC_STATUS_PATH, {
|
|
6873
|
+
organizationId: orgId,
|
|
6874
|
+
serverId
|
|
6875
|
+
});
|
|
6876
|
+
if (isJsonMode()) {
|
|
6877
|
+
printJson(data);
|
|
6878
|
+
return;
|
|
6879
|
+
}
|
|
6880
|
+
if (!data.repo) {
|
|
6881
|
+
printInfo("Not linked to a Git repository.");
|
|
6882
|
+
printInfo(` ${c.dim("Link one with")} ${c.bold("mcp servers git link <server> --repo <owner/name>")}`);
|
|
6883
|
+
return;
|
|
6884
|
+
}
|
|
6885
|
+
printKeyValue({
|
|
6886
|
+
repo: `${data.repo.owner}/${data.repo.name}@${data.repo.branch}`,
|
|
6887
|
+
...data.repo.pathPrefix ? { "path prefix": data.repo.pathPrefix } : {},
|
|
6888
|
+
"auto-sync": data.repo.autoSync ? "on (5-minute sweep)" : "off",
|
|
6889
|
+
"mirror push": data.sync ? `${data.sync.status} · ${shortSha(data.sync.lastPushedGitSha)}${data.sync.lastSyncedAt ? ` · ${formatDate(data.sync.lastSyncedAt)}` : ""}${data.sync.mirrorBehindHead ? " · behind HEAD" : ""}` : "—",
|
|
6890
|
+
"last pull": data.pull ? `${data.pull.status} · ${shortSha(data.pull.lastPulledGitSha)}${data.pull.lastPulledAt ? ` · ${formatDate(data.pull.lastPulledAt)}` : ""}` : "—",
|
|
6891
|
+
"working tree": data.workingTree ? describeWorkingTree(data.workingTree) : "—",
|
|
6892
|
+
deployed: describeDeployed(data.deployed)
|
|
6893
|
+
});
|
|
6894
|
+
if (data.sync?.error)
|
|
6895
|
+
printError(`mirror error: ${data.sync.error}`);
|
|
6896
|
+
if (data.pull?.error)
|
|
6897
|
+
printError(`pull error: ${data.pull.error}`);
|
|
6898
|
+
if ((data.pull?.conflictedFileCount ?? 0) > 0) {
|
|
6899
|
+
printInfo(` ${c.dim("Resolve by committing or discarding the local edits, then push again from git.")}`);
|
|
6900
|
+
}
|
|
6901
|
+
const tree = data.workingTree;
|
|
6902
|
+
if (tree && tree.added + tree.modified + tree.deleted > 0) {
|
|
6903
|
+
printInfo(` ${c.dim("Commit with")} ${c.bold('mcp servers commit <server> -m "…"')} ${c.dim("to make these mirrorable + deployable.")}`);
|
|
6904
|
+
} else if (data.sync?.mirrorBehindHead) {
|
|
6905
|
+
printInfo(` ${c.dim("Committed HEAD is not mirrored yet — push it with")} ${c.bold("mcp servers git sync <server>")}${c.dim(data.repo.autoSync ? " (or wait for auto-sync)" : "")}`);
|
|
6906
|
+
}
|
|
6907
|
+
}));
|
|
6908
|
+
git.command("link <server>").description("Link an existing GitHub repo (App installation must have access) and run the initial sync").requiredOption("--repo <owner/name>", "Repository, as owner/name").option("--branch <branch>", "Branch to sync (default: the repo default branch)").option("--path-prefix <prefix>", "Sync into this path inside the repo").option("--auto-sync", "Mirror each committed change automatically").option("--org <organizationId>", "Organization ID").addHelpText("after", [
|
|
6909
|
+
"",
|
|
6910
|
+
"Notes:",
|
|
6911
|
+
" The initial sync mirrors COMMITTED code. On a server with no commit",
|
|
6912
|
+
' yet, run `mcp servers commit <server> -m "…"` first — the link is',
|
|
6913
|
+
" saved either way; only the first push waits.",
|
|
6914
|
+
" An empty repository is fine: the push bootstraps its first commit."
|
|
6915
|
+
].join(`
|
|
6916
|
+
`)).action(runAction(async (serverRef, opts) => {
|
|
6917
|
+
const repo = parseRepoRef(opts.repo);
|
|
6918
|
+
if (!repo) {
|
|
6919
|
+
printError(`Invalid --repo "${opts.repo}". Expected owner/name, e.g. my-org/my-mcp-server.`);
|
|
6920
|
+
throw new CliExitError(1);
|
|
6921
|
+
}
|
|
6922
|
+
const orgId = await resolveOrgId(opts.org);
|
|
6923
|
+
const serverId = await resolveServerId(serverRef, orgId);
|
|
6924
|
+
try {
|
|
6925
|
+
const data = await api.post(GIT_LINK_PATH, {
|
|
6926
|
+
organizationId: orgId,
|
|
6927
|
+
serverId,
|
|
6928
|
+
owner: repo.owner,
|
|
6929
|
+
name: repo.name,
|
|
6930
|
+
branch: opts.branch,
|
|
6931
|
+
pathPrefix: opts.pathPrefix,
|
|
6932
|
+
autoSync: opts.autoSync === true
|
|
6933
|
+
});
|
|
6934
|
+
if (isJsonMode()) {
|
|
6935
|
+
printJson({ linked: true, ...data });
|
|
6936
|
+
return;
|
|
6937
|
+
}
|
|
6938
|
+
printSuccess(`Linked to ${data.owner}/${data.name} and synced. \`mcp dev\` now runs git-native for this server.`);
|
|
6939
|
+
} catch (err) {
|
|
6940
|
+
if (err instanceof McpCloudApiError && (err.error.code === "uncommitted_changes" || err.error.code === "no_commit_to_sync")) {
|
|
6941
|
+
printSuccess(`Linked to ${repo.owner}/${repo.name}.`);
|
|
6942
|
+
printError(`Initial sync skipped: ${err.error.message}`);
|
|
6943
|
+
printInfo(` ${c.dim("Then push with")} ${c.bold("mcp servers git sync <server>")}`);
|
|
6944
|
+
throw new CliExitError(1);
|
|
6945
|
+
}
|
|
6946
|
+
reportApiError2(err, "Link");
|
|
6947
|
+
}
|
|
6948
|
+
}));
|
|
6949
|
+
git.command("sync <server>").description("Push committed HEAD to the linked repo now (no cron wait)").option("--org <organizationId>", "Organization ID").action(runAction(async (serverRef, opts) => {
|
|
6950
|
+
const orgId = await resolveOrgId(opts.org);
|
|
6951
|
+
const serverId = await resolveServerId(serverRef, orgId);
|
|
6952
|
+
try {
|
|
6953
|
+
const data = await api.post(GIT_SYNC_PATH, {
|
|
6954
|
+
organizationId: orgId,
|
|
6955
|
+
serverId
|
|
6956
|
+
});
|
|
6957
|
+
if (isJsonMode()) {
|
|
6958
|
+
printJson(data);
|
|
6959
|
+
return;
|
|
6960
|
+
}
|
|
6961
|
+
printSuccess(`Mirror push landed as ${shortSha(data.commitSha)}.`);
|
|
6962
|
+
} catch (err) {
|
|
6963
|
+
reportApiError2(err, "Sync");
|
|
6964
|
+
}
|
|
6965
|
+
}));
|
|
6966
|
+
git.command("unlink <server>").description("Unlink the GitHub repo — the repo is untouched, mirroring and reconciliation stop").option("--org <organizationId>", "Organization ID").action(runAction(async (serverRef, opts) => {
|
|
6967
|
+
const orgId = await resolveOrgId(opts.org);
|
|
6968
|
+
const serverId = await resolveServerId(serverRef, orgId);
|
|
6969
|
+
try {
|
|
6970
|
+
const data = await api.delete(`${GIT_LINK_PATH}?organizationId=${encodeURIComponent(orgId)}&serverId=${encodeURIComponent(serverId)}`);
|
|
6971
|
+
if (isJsonMode()) {
|
|
6972
|
+
printJson(data);
|
|
6973
|
+
return;
|
|
6974
|
+
}
|
|
6975
|
+
if (data.cleared) {
|
|
6976
|
+
printSuccess("Unlinked. The repository itself is untouched.");
|
|
6977
|
+
} else {
|
|
6978
|
+
printInfo("Nothing to do — this server was not linked.");
|
|
6979
|
+
}
|
|
6980
|
+
} catch (err) {
|
|
6981
|
+
reportApiError2(err, "Unlink");
|
|
6982
|
+
}
|
|
6983
|
+
}));
|
|
6984
|
+
}
|
|
6985
|
+
function registerServerCommitCommand(servers) {
|
|
6986
|
+
servers.command("commit <server>").description("Commit the working tree as a new internal version (advances the branch — mirror + deploy see it)").requiredOption("-m, --message <message>", "Commit message").option("--branch <branch>", "Branch to commit on (default: main)").option("--org <organizationId>", "Organization ID").addHelpText("after", [
|
|
6987
|
+
"",
|
|
6988
|
+
"Notes:",
|
|
6989
|
+
" Headless semantics: commits whatever the working tree holds right",
|
|
6990
|
+
" now — including edits reconciled from a `git push`. A clean tree is",
|
|
6991
|
+
" a no-op success, not an error. Check what would land with",
|
|
6992
|
+
" `mcp servers git status <server>`."
|
|
6993
|
+
].join(`
|
|
6994
|
+
`)).action(runAction(async (serverRef, opts) => {
|
|
6995
|
+
const orgId = await resolveOrgId(opts.org);
|
|
6996
|
+
const serverId = await resolveServerId(serverRef, orgId);
|
|
6997
|
+
try {
|
|
6998
|
+
const data = await api.post(COMMIT_PATH, {
|
|
6999
|
+
organizationId: orgId,
|
|
7000
|
+
serverId,
|
|
7001
|
+
message: opts.message,
|
|
7002
|
+
branch: opts.branch
|
|
7003
|
+
});
|
|
7004
|
+
if (isJsonMode()) {
|
|
7005
|
+
printJson(data);
|
|
7006
|
+
return;
|
|
7007
|
+
}
|
|
7008
|
+
if (data.noop) {
|
|
7009
|
+
printInfo("Nothing to commit — the working tree is clean.");
|
|
7010
|
+
return;
|
|
7011
|
+
}
|
|
7012
|
+
printSuccess(`Committed ${data.changedFileCount} file${data.changedFileCount === 1 ? "" : "s"} (${data.commitId}).`);
|
|
7013
|
+
} catch (err) {
|
|
7014
|
+
reportApiError2(err, "Commit");
|
|
7015
|
+
}
|
|
7016
|
+
}));
|
|
7017
|
+
}
|
|
7018
|
+
|
|
6797
7019
|
// src/commands/servers-prompts.ts
|
|
6798
7020
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
6799
7021
|
|
|
@@ -6815,7 +7037,7 @@ async function resolveServerScope(serverRef, org) {
|
|
|
6815
7037
|
|
|
6816
7038
|
// src/commands/servers-prompts.ts
|
|
6817
7039
|
var PROMPT_PATH = "/api/v1/server/prompt";
|
|
6818
|
-
function
|
|
7040
|
+
function reportApiError3(err, action) {
|
|
6819
7041
|
if (err instanceof McpCloudApiError) {
|
|
6820
7042
|
printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
|
|
6821
7043
|
const details = err.error.details;
|
|
@@ -6871,7 +7093,7 @@ function registerServerPromptCommands(servers) {
|
|
|
6871
7093
|
{ key: "description", label: "DESCRIPTION", width: 48 }
|
|
6872
7094
|
]);
|
|
6873
7095
|
} catch (err) {
|
|
6874
|
-
|
|
7096
|
+
reportApiError3(err, "Listing prompts");
|
|
6875
7097
|
}
|
|
6876
7098
|
}));
|
|
6877
7099
|
prompts.command("set <server> <name>").description("Create or replace a prompt by name. Re-running with the same name updates it.").option("--org <organizationId>", "Organization ID").option("--template <markdown>", "Prompt body, inline").option("--template-file <path>", "Prompt body, read from a file").option("--arguments <json>", "JSON array of {name, description, required}; defaults to []").option("--description <text>", "What the prompt is for").addHelpText("after", [
|
|
@@ -6909,7 +7131,7 @@ function registerServerPromptCommands(servers) {
|
|
|
6909
7131
|
}
|
|
6910
7132
|
printInfo(c.dim(" Not live yet: run `mcp servers generate <server> --store`, then deploy."));
|
|
6911
7133
|
} catch (err) {
|
|
6912
|
-
|
|
7134
|
+
reportApiError3(err, "Saving the prompt");
|
|
6913
7135
|
}
|
|
6914
7136
|
}));
|
|
6915
7137
|
prompts.command("rm <server> <name>").description("Remove a prompt by name.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, name, opts) => {
|
|
@@ -6922,7 +7144,7 @@ function registerServerPromptCommands(servers) {
|
|
|
6922
7144
|
}
|
|
6923
7145
|
printSuccess(`Removed prompt ${c.bold(name)}.`);
|
|
6924
7146
|
} catch (err) {
|
|
6925
|
-
|
|
7147
|
+
reportApiError3(err, "Removing the prompt");
|
|
6926
7148
|
}
|
|
6927
7149
|
}));
|
|
6928
7150
|
}
|
|
@@ -6930,7 +7152,7 @@ function registerServerPromptCommands(servers) {
|
|
|
6930
7152
|
// src/commands/servers-resources.ts
|
|
6931
7153
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
6932
7154
|
var RESOURCE_PATH = "/api/v1/server/resource";
|
|
6933
|
-
function
|
|
7155
|
+
function reportApiError4(err, action) {
|
|
6934
7156
|
if (err instanceof McpCloudApiError) {
|
|
6935
7157
|
printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
|
|
6936
7158
|
} else {
|
|
@@ -6968,7 +7190,7 @@ function registerServerResourceCommands(servers) {
|
|
|
6968
7190
|
{ key: "mime", label: "MIME", width: 20 }
|
|
6969
7191
|
]);
|
|
6970
7192
|
} catch (err) {
|
|
6971
|
-
|
|
7193
|
+
reportApiError4(err, "Listing resources");
|
|
6972
7194
|
}
|
|
6973
7195
|
}));
|
|
6974
7196
|
resources.command("set <server> <uri>").description("Create or replace a resource by URI. Re-running with the same URI updates it.").option("--org <organizationId>", "Organization ID").option("--name <name>", "Human-readable name (defaults to the URI)").option("--description <text>", "What the resource holds").option("--mime <type>", "MIME type", "text/markdown").option("--content <text>", "Body of a static resource, inline").option("--content-file <path>", "Body of a static resource, from a file").option("--upstream <template>", "Upstream path template — makes this a DYNAMIC resource fetched per read").addHelpText("after", [
|
|
@@ -7010,7 +7232,7 @@ function registerServerResourceCommands(servers) {
|
|
|
7010
7232
|
printSuccess(`${data.resource.replaced ? "Updated" : "Created"} ${resourceType} resource ${c.bold(uri)} on ${scope.serverName}.`);
|
|
7011
7233
|
printInfo(c.dim(" Not live yet: run `mcp servers generate <server> --store`, then deploy."));
|
|
7012
7234
|
} catch (err) {
|
|
7013
|
-
|
|
7235
|
+
reportApiError4(err, "Saving the resource");
|
|
7014
7236
|
}
|
|
7015
7237
|
}));
|
|
7016
7238
|
resources.command("rm <server> <uri>").description("Remove a resource by URI.").option("--org <organizationId>", "Organization ID").action(runAction(async (server, uri, opts) => {
|
|
@@ -7023,7 +7245,7 @@ function registerServerResourceCommands(servers) {
|
|
|
7023
7245
|
}
|
|
7024
7246
|
printSuccess(`Removed resource ${c.bold(uri)}.`);
|
|
7025
7247
|
} catch (err) {
|
|
7026
|
-
|
|
7248
|
+
reportApiError4(err, "Removing the resource");
|
|
7027
7249
|
}
|
|
7028
7250
|
}));
|
|
7029
7251
|
}
|
|
@@ -7031,7 +7253,7 @@ function registerServerResourceCommands(servers) {
|
|
|
7031
7253
|
// src/commands/servers-shape.ts
|
|
7032
7254
|
var SCORE_PATH = "/api/v1/server/usability-score";
|
|
7033
7255
|
var SHAPE_PATH = "/api/v1/server/shape";
|
|
7034
|
-
function
|
|
7256
|
+
function reportApiError5(err, action) {
|
|
7035
7257
|
if (err instanceof McpCloudApiError) {
|
|
7036
7258
|
printError(`${action} failed (HTTP ${err.status}): ${err.error.message}`);
|
|
7037
7259
|
} else {
|
|
@@ -7075,7 +7297,7 @@ function registerServerShapingCommands(servers) {
|
|
|
7075
7297
|
printSuccess(`Scoring started for ${scope.serverName}.`);
|
|
7076
7298
|
printInfo(c.dim(` ${data.message}`));
|
|
7077
7299
|
} catch (err) {
|
|
7078
|
-
|
|
7300
|
+
reportApiError5(err, "Starting the scoring run");
|
|
7079
7301
|
}
|
|
7080
7302
|
return;
|
|
7081
7303
|
}
|
|
@@ -7096,7 +7318,7 @@ function registerServerShapingCommands(servers) {
|
|
|
7096
7318
|
printSuccess(`${formatPercent(mean)} ±${formatPercent(max - min)} across ${data.batch.length} runs`);
|
|
7097
7319
|
printInfo(c.dim(` ${data.batch[0]?.scored ?? 0} scenarios · ${data.catalogSize ?? "—"} tools · judged by ${data.modelKey ?? "—"}`));
|
|
7098
7320
|
} catch (err) {
|
|
7099
|
-
|
|
7321
|
+
reportApiError5(err, "Reading the score");
|
|
7100
7322
|
}
|
|
7101
7323
|
}));
|
|
7102
7324
|
servers.command("shape <server>").description("Propose task-shaped tools over this server’s endpoints (starts a run, or reads the last one)").option("--org <organizationId>", "Organization ID").option("--start", "Start a new shaping run instead of reading the last").addHelpText("after", [
|
|
@@ -7126,7 +7348,7 @@ function registerServerShapingCommands(servers) {
|
|
|
7126
7348
|
printSuccess(`Shaping started for ${scope.serverName}.`);
|
|
7127
7349
|
printInfo(c.dim(` ${data.message}`));
|
|
7128
7350
|
} catch (err) {
|
|
7129
|
-
|
|
7351
|
+
reportApiError5(err, "Starting the shaping run");
|
|
7130
7352
|
}
|
|
7131
7353
|
return;
|
|
7132
7354
|
}
|
|
@@ -7159,7 +7381,7 @@ function registerServerShapingCommands(servers) {
|
|
|
7159
7381
|
}
|
|
7160
7382
|
printInfo(c.dim(" Accept a proposal in the dashboard; nothing is created here."));
|
|
7161
7383
|
} catch (err) {
|
|
7162
|
-
|
|
7384
|
+
reportApiError5(err, "Reading shaping proposals");
|
|
7163
7385
|
}
|
|
7164
7386
|
}));
|
|
7165
7387
|
}
|
|
@@ -8084,13 +8306,14 @@ function registerServerGetCommand(servers) {
|
|
|
8084
8306
|
organizationId: orgId,
|
|
8085
8307
|
serverId
|
|
8086
8308
|
});
|
|
8309
|
+
const gitLink = await api.get("/api/v1/server/git-link", { organizationId: orgId, serverId }).then((r) => r.gitLink).catch(() => null);
|
|
8087
8310
|
const probe = opts.probe ? await probeServerSurface({
|
|
8088
8311
|
configured: data.server,
|
|
8089
8312
|
organizationId: orgId,
|
|
8090
8313
|
serverId
|
|
8091
8314
|
}) : null;
|
|
8092
8315
|
if (isJsonMode()) {
|
|
8093
|
-
printJson(
|
|
8316
|
+
printJson({ ...data, gitLink, ...probe ? { probe } : {} });
|
|
8094
8317
|
if (probe?.drift.length)
|
|
8095
8318
|
throw new CliExitError(1);
|
|
8096
8319
|
return;
|
|
@@ -8105,6 +8328,7 @@ function registerServerGetCommand(servers) {
|
|
|
8105
8328
|
url: s.deploymentUrl ?? "—",
|
|
8106
8329
|
"tool surface": describeToolSurface(s),
|
|
8107
8330
|
"upstream keys": s.upstreamApiKeyMode ?? "shared",
|
|
8331
|
+
git: gitLink ? `${gitLink.owner}/${gitLink.name}@${gitLink.branch} (mcp servers git status)` : "—",
|
|
8108
8332
|
"latest deployment": s.latestDeploymentId ?? "—",
|
|
8109
8333
|
"last deployed": s.lastDeployedAt ? formatDate(s.lastDeployedAt) : "—",
|
|
8110
8334
|
created: formatDate(s.createdAt),
|
|
@@ -8720,7 +8944,7 @@ function registerServerLifecycleCommands(servers) {
|
|
|
8720
8944
|
|
|
8721
8945
|
// src/commands/servers-mutations.ts
|
|
8722
8946
|
function registerServerMutationCommands(servers) {
|
|
8723
|
-
servers.command("create").description("Create an empty server skeleton in a project").requiredOption("--project <project>", "Project (id or name)").requiredOption("--name <name>", "Display name (1–100 chars)").option("--org <organizationId>", "Organization ID").option("--description <text>", "Optional description").addHelpText("after", [
|
|
8947
|
+
servers.command("create").description("Create an empty server skeleton in a project").requiredOption("--project <project>", "Project (id or name)").requiredOption("--name <name>", "Display name (1–100 chars)").option("--org <organizationId>", "Organization ID").option("--description <text>", "Optional description").option("--git-repo <owner/name>", "Host the generated code on this GitHub repo (links now, mirrors after first generation)").option("--git-path-prefix <prefix>", "Sync into this path inside the repo").option("--no-git-auto-sync", "Do not mirror commits automatically").addHelpText("after", [
|
|
8724
8948
|
"",
|
|
8725
8949
|
"Notes:",
|
|
8726
8950
|
" Empty-skeleton create. Source-material import (OpenAPI/GraphQL spec)",
|
|
@@ -8743,6 +8967,15 @@ function registerServerMutationCommands(servers) {
|
|
|
8743
8967
|
if (opts.description !== undefined)
|
|
8744
8968
|
body["description"] = opts.description;
|
|
8745
8969
|
const data = await api.post("/api/v1/servers", body);
|
|
8970
|
+
if (opts.gitRepo) {
|
|
8971
|
+
await linkRepoAtCreation({
|
|
8972
|
+
orgId,
|
|
8973
|
+
serverId: data.server.id,
|
|
8974
|
+
repoRef: opts.gitRepo,
|
|
8975
|
+
pathPrefix: opts.gitPathPrefix,
|
|
8976
|
+
autoSync: opts.gitAutoSync
|
|
8977
|
+
});
|
|
8978
|
+
}
|
|
8746
8979
|
if (isJsonMode()) {
|
|
8747
8980
|
printJson(data);
|
|
8748
8981
|
return;
|
|
@@ -9038,7 +9271,7 @@ function validateSourceType(value) {
|
|
|
9038
9271
|
return v2;
|
|
9039
9272
|
}
|
|
9040
9273
|
function registerServerSpecCommands(servers) {
|
|
9041
|
-
servers.command("ingest").description("Create a server from an OpenAPI spec (file, URL, or @- stdin) or a GraphQL endpoint. Wraps POST /api/v1/server/ingest.").requiredOption("--project <project>", "Project (id or name) to create the server in").requiredOption("--spec <file|url>", "OpenAPI spec (local file, http(s) URL, or @- for stdin), or — with --source-type graphql — the GraphQL endpoint URL to introspect").option("--org <organizationId>", "Organization ID").option("--source-type <type>", `Override spec classification: ${SOURCE_TYPES.join(" | ")} (OpenAPI auto-detected; graphql requires an endpoint URL)`).addHelpText("after", [
|
|
9274
|
+
servers.command("ingest").description("Create a server from an OpenAPI spec (file, URL, or @- stdin) or a GraphQL endpoint. Wraps POST /api/v1/server/ingest.").requiredOption("--project <project>", "Project (id or name) to create the server in").requiredOption("--spec <file|url>", "OpenAPI spec (local file, http(s) URL, or @- for stdin), or — with --source-type graphql — the GraphQL endpoint URL to introspect").option("--org <organizationId>", "Organization ID").option("--source-type <type>", `Override spec classification: ${SOURCE_TYPES.join(" | ")} (OpenAPI auto-detected; graphql requires an endpoint URL)`).option("--git-repo <owner/name>", "Host the generated code on this GitHub repo (links now, mirrors after first generation)").option("--git-path-prefix <prefix>", "Sync into this path inside the repo").option("--no-git-auto-sync", "Do not mirror commits automatically").addHelpText("after", [
|
|
9042
9275
|
"",
|
|
9043
9276
|
"Examples:",
|
|
9044
9277
|
" $ mcp servers ingest --project proj_123 --spec ./openapi.yaml",
|
|
@@ -9059,6 +9292,15 @@ function registerServerSpecCommands(servers) {
|
|
|
9059
9292
|
projectId,
|
|
9060
9293
|
payload
|
|
9061
9294
|
}));
|
|
9295
|
+
if (opts.gitRepo) {
|
|
9296
|
+
await linkRepoAtCreation({
|
|
9297
|
+
orgId,
|
|
9298
|
+
serverId: data.server.id,
|
|
9299
|
+
repoRef: opts.gitRepo,
|
|
9300
|
+
pathPrefix: opts.gitPathPrefix,
|
|
9301
|
+
autoSync: opts.gitAutoSync
|
|
9302
|
+
});
|
|
9303
|
+
}
|
|
9062
9304
|
if (isJsonMode()) {
|
|
9063
9305
|
printJson(data);
|
|
9064
9306
|
return;
|
|
@@ -9527,6 +9769,8 @@ function registerServerTestCommands(servers) {
|
|
|
9527
9769
|
function registerServerCommands(program2) {
|
|
9528
9770
|
const servers = program2.command("servers").description("Manage MCP servers");
|
|
9529
9771
|
registerServerDepsCommands(servers);
|
|
9772
|
+
registerServerGitCommands(servers);
|
|
9773
|
+
registerServerCommitCommand(servers);
|
|
9530
9774
|
registerServerPromptCommands(servers);
|
|
9531
9775
|
registerServerResourceCommands(servers);
|
|
9532
9776
|
registerServerShapingCommands(servers);
|
|
@@ -13231,8 +13475,8 @@ function registerSkillCommands(program2) {
|
|
|
13231
13475
|
}
|
|
13232
13476
|
|
|
13233
13477
|
// src/lib/dev/prepare.ts
|
|
13234
|
-
import { existsSync as existsSync20, writeFileSync as writeFileSync12 } from "node:fs";
|
|
13235
|
-
import { join as join18, relative as relative6 } from "node:path";
|
|
13478
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20, writeFileSync as writeFileSync12 } from "node:fs";
|
|
13479
|
+
import { join as join18, relative as relative6, resolve as resolve8 } from "node:path";
|
|
13236
13480
|
|
|
13237
13481
|
// src/lib/dev/bundle-sync.ts
|
|
13238
13482
|
import {
|
|
@@ -13443,6 +13687,24 @@ function runGit(args, cwd) {
|
|
|
13443
13687
|
stderr: res.stderr ?? ""
|
|
13444
13688
|
};
|
|
13445
13689
|
}
|
|
13690
|
+
function getOriginUrl(repoDir) {
|
|
13691
|
+
try {
|
|
13692
|
+
const res = runGit(["remote", "get-url", "origin"], repoDir);
|
|
13693
|
+
const url = res.stdout.trim();
|
|
13694
|
+
return res.status === 0 && url ? url : null;
|
|
13695
|
+
} catch {
|
|
13696
|
+
return null;
|
|
13697
|
+
}
|
|
13698
|
+
}
|
|
13699
|
+
function originMatchesRepo(originUrl, owner, name) {
|
|
13700
|
+
const normalized = originUrl.trim().toLowerCase();
|
|
13701
|
+
const target = `${owner}/${name}`.toLowerCase();
|
|
13702
|
+
const patterns = [
|
|
13703
|
+
`github.com/${target}`,
|
|
13704
|
+
`github.com:${target}`
|
|
13705
|
+
];
|
|
13706
|
+
return patterns.some((p2) => normalized.endsWith(p2) || normalized.endsWith(`${p2}.git`));
|
|
13707
|
+
}
|
|
13446
13708
|
function isGitAvailable() {
|
|
13447
13709
|
try {
|
|
13448
13710
|
return runGit(["--version"]).status === 0;
|
|
@@ -28543,6 +28805,18 @@ function buildInspectorModule() {
|
|
|
28543
28805
|
` if (response.body && !isStream) {`,
|
|
28544
28806
|
` const buf = new Uint8Array(await response.clone().arrayBuffer())`,
|
|
28545
28807
|
` responseBodyText = decodeBody(buf)`,
|
|
28808
|
+
` // Rebuild the response from the captured bytes. Under Bun, streaming`,
|
|
28809
|
+
` // the original body after the clone-read yields ZERO bytes inside a`,
|
|
28810
|
+
` // node:http server callback (the recorder saw the full body while the`,
|
|
28811
|
+
` // client got Content-Length: 0) — a buffer-backed Response cannot`,
|
|
28812
|
+
` // drain. content-length is dropped so node:http recomputes it.`,
|
|
28813
|
+
` const rebuiltHeaders = new Headers(response.headers)`,
|
|
28814
|
+
` rebuiltHeaders.delete('content-length')`,
|
|
28815
|
+
` response = new Response(buf.byteLength > 0 ? buf : null, {`,
|
|
28816
|
+
` status: response.status,`,
|
|
28817
|
+
` statusText: response.statusText,`,
|
|
28818
|
+
` headers: rebuiltHeaders,`,
|
|
28819
|
+
` })`,
|
|
28546
28820
|
` } else if (response.body && isStream) {`,
|
|
28547
28821
|
` const [forUser, forCapture] = response.body.tee()`,
|
|
28548
28822
|
` const reader = forCapture.getReader()`,
|
|
@@ -29000,6 +29274,47 @@ async function installDependencies(options) {
|
|
|
29000
29274
|
}
|
|
29001
29275
|
|
|
29002
29276
|
// src/lib/dev/prepare.ts
|
|
29277
|
+
function missingEnvBindingNames(envExample, envJson) {
|
|
29278
|
+
let present = {};
|
|
29279
|
+
try {
|
|
29280
|
+
const parsed = JSON.parse(envJson);
|
|
29281
|
+
if (parsed && typeof parsed === "object") {
|
|
29282
|
+
present = parsed;
|
|
29283
|
+
}
|
|
29284
|
+
} catch {}
|
|
29285
|
+
const names = [];
|
|
29286
|
+
for (const line of envExample.split(`
|
|
29287
|
+
`)) {
|
|
29288
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)=/.exec(line.trim());
|
|
29289
|
+
const name = match?.[1];
|
|
29290
|
+
if (!name)
|
|
29291
|
+
continue;
|
|
29292
|
+
const value = present[name];
|
|
29293
|
+
if (typeof value === "string" && value.length > 0)
|
|
29294
|
+
continue;
|
|
29295
|
+
if (!names.includes(name))
|
|
29296
|
+
names.push(name);
|
|
29297
|
+
}
|
|
29298
|
+
return names;
|
|
29299
|
+
}
|
|
29300
|
+
function printEnvBindingHint(dest, envPath, cwd) {
|
|
29301
|
+
const examplePath = join18(dest, ".env.example");
|
|
29302
|
+
if (!existsSync20(examplePath))
|
|
29303
|
+
return;
|
|
29304
|
+
let example = "";
|
|
29305
|
+
let envJson = "{}";
|
|
29306
|
+
try {
|
|
29307
|
+
example = readFileSync20(examplePath, "utf-8");
|
|
29308
|
+
if (existsSync20(envPath))
|
|
29309
|
+
envJson = readFileSync20(envPath, "utf-8");
|
|
29310
|
+
} catch {
|
|
29311
|
+
return;
|
|
29312
|
+
}
|
|
29313
|
+
const missing = missingEnvBindingNames(example, envJson);
|
|
29314
|
+
if (missing.length === 0)
|
|
29315
|
+
return;
|
|
29316
|
+
printInfo(` → this server expects ${missing.map((n) => c.bold(n)).join(", ")} — add value${missing.length === 1 ? "" : "s"} to ${relative6(cwd, envPath)} (upstream calls 401 until then)`);
|
|
29317
|
+
}
|
|
29003
29318
|
var ENTRY_CANDIDATES = ["src/worker.ts", "src/server.ts", "src/index.ts"];
|
|
29004
29319
|
async function prepareDev(opts) {
|
|
29005
29320
|
const cwd = opts.cwd;
|
|
@@ -29024,7 +29339,19 @@ async function prepareDev(opts) {
|
|
|
29024
29339
|
gitNative = true;
|
|
29025
29340
|
projectId = projectId ?? gitLink.projectId;
|
|
29026
29341
|
serverName = `${gitLink.owner}/${gitLink.name}`;
|
|
29027
|
-
|
|
29342
|
+
const registered = readConfig().gitRepoDirs?.[opts.serverId];
|
|
29343
|
+
const chosen = opts.repoDirOverride ? resolve8(cwd, opts.repoDirOverride) : registered;
|
|
29344
|
+
repoDir = chosen ?? gitCloneDir(cwd, gitLink.owner, gitLink.name);
|
|
29345
|
+
if (chosen && existsSync20(join18(repoDir, ".git"))) {
|
|
29346
|
+
const origin = getOriginUrl(repoDir);
|
|
29347
|
+
if (!origin || !originMatchesRepo(origin, gitLink.owner, gitLink.name)) {
|
|
29348
|
+
printError(`${repoDir} is a checkout of ${origin ?? "an unknown remote"}, not ${gitLink.owner}/${gitLink.name}. Pass a checkout of the linked repo, or drop --repo to use the default clone.`);
|
|
29349
|
+
process.exit(1);
|
|
29350
|
+
}
|
|
29351
|
+
}
|
|
29352
|
+
if (registered && !opts.repoDirOverride) {
|
|
29353
|
+
printInfo(` → using registered checkout ${repoDir}`);
|
|
29354
|
+
}
|
|
29028
29355
|
dest = gitLink.pathPrefix ? join18(repoDir, gitLink.pathPrefix) : repoDir;
|
|
29029
29356
|
printStep(`Git-linked server — cloning ${gitLink.owner}/${gitLink.name}@${gitLink.branch}…`);
|
|
29030
29357
|
try {
|
|
@@ -29035,6 +29362,11 @@ async function prepareDev(opts) {
|
|
|
29035
29362
|
onStep: (m2) => printStep(m2)
|
|
29036
29363
|
});
|
|
29037
29364
|
printSuccess(result.cloned ? `Cloned to ${relative6(cwd, repoDir)}` : `Using existing clone at ${relative6(cwd, repoDir)}`);
|
|
29365
|
+
const cfg = readConfig();
|
|
29366
|
+
if (cfg.gitRepoDirs?.[opts.serverId] !== repoDir) {
|
|
29367
|
+
cfg.gitRepoDirs = { ...cfg.gitRepoDirs, [opts.serverId]: repoDir };
|
|
29368
|
+
writeConfig(cfg);
|
|
29369
|
+
}
|
|
29038
29370
|
} catch (err) {
|
|
29039
29371
|
if (err instanceof GitNotAvailableError) {
|
|
29040
29372
|
printError(err.message);
|
|
@@ -29050,6 +29382,7 @@ async function prepareDev(opts) {
|
|
|
29050
29382
|
`, "utf-8");
|
|
29051
29383
|
printInfo(` → seeded ${relative6(cwd, env)} (empty; fill secrets here)`);
|
|
29052
29384
|
}
|
|
29385
|
+
printEnvBindingHint(dest, env, cwd);
|
|
29053
29386
|
printInfo(` ${"Open the clone in your editor; commit + push to sync (config under mcpcloud/ is read-only)."}`);
|
|
29054
29387
|
} else if (!opts.offline) {
|
|
29055
29388
|
if (!projectId) {
|
|
@@ -29075,6 +29408,7 @@ async function prepareDev(opts) {
|
|
|
29075
29408
|
`, "utf-8");
|
|
29076
29409
|
printInfo(` → seeded ${relative6(cwd, env)} (empty; fill secrets here)`);
|
|
29077
29410
|
}
|
|
29411
|
+
printEnvBindingHint(dest, env, cwd);
|
|
29078
29412
|
printStep("Fetching tool metadata…");
|
|
29079
29413
|
const tools = await fetchToolsForServer({
|
|
29080
29414
|
organizationId: opts.organizationId,
|
|
@@ -29145,7 +29479,7 @@ async function prepareDev(opts) {
|
|
|
29145
29479
|
|
|
29146
29480
|
// src/lib/dev/tree-sync.ts
|
|
29147
29481
|
import { createHash as createHash4 } from "node:crypto";
|
|
29148
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync14, readdirSync as readdirSync3, readFileSync as
|
|
29482
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync14, readdirSync as readdirSync3, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "node:fs";
|
|
29149
29483
|
import { join as join19 } from "node:path";
|
|
29150
29484
|
var AUTHORING_GUIDE_FILE = "AGENTS.md";
|
|
29151
29485
|
var STRUCTURAL_FRONTMATTER_KEYS = [
|
|
@@ -29167,7 +29501,7 @@ function listToolFiles(devRootDir, serverId) {
|
|
|
29167
29501
|
}
|
|
29168
29502
|
function readToolFile(devRootDir, serverId, toolName) {
|
|
29169
29503
|
const file = join19(serverToolsDir(devRootDir, serverId), `${toolName}.md`);
|
|
29170
|
-
const raw =
|
|
29504
|
+
const raw = readFileSync21(file, "utf-8");
|
|
29171
29505
|
try {
|
|
29172
29506
|
return { raw, view: parseToolMarkdown(raw) };
|
|
29173
29507
|
} catch (err) {
|
|
@@ -29287,7 +29621,7 @@ function listHandlerFiles(devRootDir) {
|
|
|
29287
29621
|
return [];
|
|
29288
29622
|
return readdirSync3(dir).filter((entry) => entry.endsWith(".ts") && !entry.endsWith(".definition.ts")).sort().map((entry) => ({
|
|
29289
29623
|
slug: entry.slice(0, -3),
|
|
29290
|
-
source:
|
|
29624
|
+
source: readFileSync21(join19(dir, entry), "utf-8")
|
|
29291
29625
|
}));
|
|
29292
29626
|
}
|
|
29293
29627
|
function writeHandlerManifest(args) {
|
|
@@ -29315,7 +29649,7 @@ function recordHandlerPushed(args) {
|
|
|
29315
29649
|
serverId: args.serverId,
|
|
29316
29650
|
version: 1
|
|
29317
29651
|
};
|
|
29318
|
-
manifest.handlers[args.slug] = hashSource2(
|
|
29652
|
+
manifest.handlers[args.slug] = hashSource2(readFileSync21(file, "utf-8"));
|
|
29319
29653
|
writeFileSync13(handlerManifestPath(args.devRootDir, args.serverId), JSON.stringify(manifest, null, 2), "utf-8");
|
|
29320
29654
|
}
|
|
29321
29655
|
function readHandlerManifest(devRootDir, serverId) {
|
|
@@ -29323,7 +29657,7 @@ function readHandlerManifest(devRootDir, serverId) {
|
|
|
29323
29657
|
if (!existsSync21(file))
|
|
29324
29658
|
return null;
|
|
29325
29659
|
try {
|
|
29326
|
-
const parsed = JSON.parse(
|
|
29660
|
+
const parsed = JSON.parse(readFileSync21(file, "utf-8"));
|
|
29327
29661
|
return parsed.version === 1 && parsed.handlers ? parsed : null;
|
|
29328
29662
|
} catch {
|
|
29329
29663
|
return null;
|
|
@@ -30213,7 +30547,7 @@ function registerConfigCommands(program2) {
|
|
|
30213
30547
|
}
|
|
30214
30548
|
printSuccess(`Saved editor command: ${cfg.editorCommand}`);
|
|
30215
30549
|
}));
|
|
30216
|
-
config.command("use <name>").description("Switch the active profile (e.g.
|
|
30550
|
+
config.command("use <name>").description("Switch the active profile (e.g. selfhost, prod)").action(runAction((name) => {
|
|
30217
30551
|
setCurrentProfile(name);
|
|
30218
30552
|
if (isJsonMode()) {
|
|
30219
30553
|
printJson({ currentProfile: name });
|
|
@@ -30293,13 +30627,13 @@ function registerConfigCommands(program2) {
|
|
|
30293
30627
|
|
|
30294
30628
|
// src/commands/dev.ts
|
|
30295
30629
|
import { existsSync as existsSync34 } from "node:fs";
|
|
30296
|
-
import { isAbsolute as isAbsolute4, relative as relative7, resolve as
|
|
30630
|
+
import { isAbsolute as isAbsolute4, relative as relative7, resolve as resolve10 } from "node:path";
|
|
30297
30631
|
|
|
30298
30632
|
// src/lib/dev/sessions.ts
|
|
30299
30633
|
import {
|
|
30300
30634
|
existsSync as existsSync22,
|
|
30301
30635
|
mkdirSync as mkdirSync15,
|
|
30302
|
-
readFileSync as
|
|
30636
|
+
readFileSync as readFileSync22,
|
|
30303
30637
|
readdirSync as readdirSync4,
|
|
30304
30638
|
unlinkSync,
|
|
30305
30639
|
writeFileSync as writeFileSync14
|
|
@@ -30343,7 +30677,7 @@ function listSessions() {
|
|
|
30343
30677
|
continue;
|
|
30344
30678
|
const path = join21(dir, entry);
|
|
30345
30679
|
try {
|
|
30346
|
-
const parsed = JSON.parse(
|
|
30680
|
+
const parsed = JSON.parse(readFileSync22(path, "utf-8"));
|
|
30347
30681
|
if (typeof parsed.pid !== "number") {
|
|
30348
30682
|
unlinkSync(path);
|
|
30349
30683
|
continue;
|
|
@@ -30803,7 +31137,7 @@ function emitLines(text, filter) {
|
|
|
30803
31137
|
}
|
|
30804
31138
|
}
|
|
30805
31139
|
function sleep2(ms) {
|
|
30806
|
-
return new Promise((
|
|
31140
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
30807
31141
|
}
|
|
30808
31142
|
|
|
30809
31143
|
// src/lib/dev/bootstrap.ts
|
|
@@ -31097,6 +31431,17 @@ async function maybeOpenEditor(args) {
|
|
|
31097
31431
|
printSavedNeverHint();
|
|
31098
31432
|
return { opened: false, reason: "saved-never" };
|
|
31099
31433
|
}
|
|
31434
|
+
if (args.override === "no" || args.override === "never") {
|
|
31435
|
+
if (args.override === "never") {
|
|
31436
|
+
const cfg = readConfig();
|
|
31437
|
+
cfg.editorOpenPreference = "never";
|
|
31438
|
+
writeConfig(cfg);
|
|
31439
|
+
}
|
|
31440
|
+
return {
|
|
31441
|
+
opened: false,
|
|
31442
|
+
reason: args.override === "never" ? "saved-never" : "declined"
|
|
31443
|
+
};
|
|
31444
|
+
}
|
|
31100
31445
|
if (detection.kind === "none") {
|
|
31101
31446
|
if (args.override === "yes" || args.override === "always") {
|
|
31102
31447
|
printError("Cannot open editor: no supported editor found on PATH.");
|
|
@@ -31112,6 +31457,9 @@ async function maybeOpenEditor(args) {
|
|
|
31112
31457
|
let workingCommand;
|
|
31113
31458
|
let workingDisplay;
|
|
31114
31459
|
let savedFromPicker = false;
|
|
31460
|
+
if (detection.kind === "multiple" && isNonInteractive()) {
|
|
31461
|
+
return { opened: false, reason: "non-interactive" };
|
|
31462
|
+
}
|
|
31115
31463
|
if (detection.kind === "multiple") {
|
|
31116
31464
|
const picked = await promptForEditor(detection.candidates, args);
|
|
31117
31465
|
if (picked === null) {
|
|
@@ -31144,21 +31492,16 @@ async function maybeOpenEditor(args) {
|
|
|
31144
31492
|
cfg.editorOpenPreference = "always";
|
|
31145
31493
|
writeConfig(cfg);
|
|
31146
31494
|
willOpen = true;
|
|
31147
|
-
} else if (args.override === "never") {
|
|
31148
|
-
const cfg = readConfig();
|
|
31149
|
-
cfg.editorOpenPreference = "never";
|
|
31150
|
-
writeConfig(cfg);
|
|
31151
|
-
willOpen = false;
|
|
31152
|
-
savedNeverThisRun = true;
|
|
31153
31495
|
} else if (args.override === "yes") {
|
|
31154
31496
|
willOpen = true;
|
|
31155
|
-
} else if (args.override === "no") {
|
|
31156
|
-
willOpen = false;
|
|
31157
31497
|
} else if (args.override !== "ask" && savedPref === "always") {
|
|
31158
31498
|
willOpen = true;
|
|
31159
31499
|
} else if (savedFromPicker) {
|
|
31160
31500
|
willOpen = true;
|
|
31161
31501
|
}
|
|
31502
|
+
if (willOpen === null && isNonInteractive()) {
|
|
31503
|
+
return { opened: false, reason: "non-interactive" };
|
|
31504
|
+
}
|
|
31162
31505
|
if (willOpen === null) {
|
|
31163
31506
|
const promptResult = await promptOpenChoice(workingCommand, args.dir, args.target);
|
|
31164
31507
|
willOpen = promptResult.open;
|
|
@@ -31702,19 +32045,19 @@ import { homedir as homedir4 } from "node:os";
|
|
|
31702
32045
|
import { join as join26 } from "node:path";
|
|
31703
32046
|
|
|
31704
32047
|
// src/lib/dev/agent-connectors/json-config-utils.ts
|
|
31705
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as
|
|
32048
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
|
|
31706
32049
|
import { dirname as dirname10, join as join25, basename } from "node:path";
|
|
31707
32050
|
function readJsonFile(path) {
|
|
31708
32051
|
if (!existsSync28(path))
|
|
31709
32052
|
return { ok: true, value: {} };
|
|
31710
32053
|
try {
|
|
31711
|
-
const raw =
|
|
32054
|
+
const raw = readFileSync23(path, "utf-8");
|
|
31712
32055
|
if (!raw.trim())
|
|
31713
32056
|
return { ok: true, value: {} };
|
|
31714
32057
|
return { ok: true, value: JSON.parse(raw) };
|
|
31715
32058
|
} catch {
|
|
31716
32059
|
try {
|
|
31717
|
-
return { ok: false, raw:
|
|
32060
|
+
return { ok: false, raw: readFileSync23(path, "utf-8") };
|
|
31718
32061
|
} catch {
|
|
31719
32062
|
return { ok: false };
|
|
31720
32063
|
}
|
|
@@ -31736,7 +32079,7 @@ function backupConfig(args) {
|
|
|
31736
32079
|
const filename = `${args.agentId}__${basename(args.configPath)}.bak`;
|
|
31737
32080
|
const backupPath = join25(args.backupsDir, filename);
|
|
31738
32081
|
if (!existsSync28(backupPath)) {
|
|
31739
|
-
const raw =
|
|
32082
|
+
const raw = readFileSync23(args.configPath, "utf-8");
|
|
31740
32083
|
writeFileSync15(backupPath, raw, "utf-8");
|
|
31741
32084
|
}
|
|
31742
32085
|
return { backupPath, existed: true };
|
|
@@ -31747,7 +32090,7 @@ function restoreFromBackup(args) {
|
|
|
31747
32090
|
if (!existsSync28(backupPath)) {
|
|
31748
32091
|
return { restored: false };
|
|
31749
32092
|
}
|
|
31750
|
-
const raw =
|
|
32093
|
+
const raw = readFileSync23(backupPath, "utf-8");
|
|
31751
32094
|
mkdirSync16(dirname10(args.configPath), { recursive: true });
|
|
31752
32095
|
writeFileSync15(args.configPath, raw, "utf-8");
|
|
31753
32096
|
return { restored: true };
|
|
@@ -31836,7 +32179,7 @@ var claudeCodeConnector = {
|
|
|
31836
32179
|
import {
|
|
31837
32180
|
existsSync as existsSync30,
|
|
31838
32181
|
mkdirSync as mkdirSync17,
|
|
31839
|
-
readFileSync as
|
|
32182
|
+
readFileSync as readFileSync24,
|
|
31840
32183
|
unlinkSync as unlinkSync3,
|
|
31841
32184
|
writeFileSync as writeFileSync17
|
|
31842
32185
|
} from "node:fs";
|
|
@@ -31895,7 +32238,7 @@ var codexConnector = {
|
|
|
31895
32238
|
});
|
|
31896
32239
|
let existing = "";
|
|
31897
32240
|
if (existsSync30(path)) {
|
|
31898
|
-
existing =
|
|
32241
|
+
existing = readFileSync24(path, "utf-8");
|
|
31899
32242
|
}
|
|
31900
32243
|
const conflict = findSectionRange(existing, args.name) !== null;
|
|
31901
32244
|
let next = existing;
|
|
@@ -31917,7 +32260,7 @@ var codexConnector = {
|
|
|
31917
32260
|
async remove(args) {
|
|
31918
32261
|
const path = configPath2();
|
|
31919
32262
|
if (existsSync30(path)) {
|
|
31920
|
-
const existing =
|
|
32263
|
+
const existing = readFileSync24(path, "utf-8");
|
|
31921
32264
|
const range = findSectionRange(existing, args.name);
|
|
31922
32265
|
if (range) {
|
|
31923
32266
|
const next = existing.slice(0, range.start) + existing.slice(range.end);
|
|
@@ -31930,7 +32273,7 @@ var codexConnector = {
|
|
|
31930
32273
|
agentId: this.id
|
|
31931
32274
|
});
|
|
31932
32275
|
if (!restored.restored && existsSync30(path)) {
|
|
31933
|
-
const after =
|
|
32276
|
+
const after = readFileSync24(path, "utf-8");
|
|
31934
32277
|
if (!after.trim()) {
|
|
31935
32278
|
try {
|
|
31936
32279
|
unlinkSync3(path);
|
|
@@ -32092,7 +32435,7 @@ var cursorConnector = {
|
|
|
32092
32435
|
// src/lib/dev/agent-connectors/vscode-copilot.ts
|
|
32093
32436
|
import { existsSync as existsSync33, unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "node:fs";
|
|
32094
32437
|
import { homedir as homedir8, platform as platform4 } from "node:os";
|
|
32095
|
-
import { join as join30, resolve as
|
|
32438
|
+
import { join as join30, resolve as resolve9 } from "node:path";
|
|
32096
32439
|
function userLevelConfigPath() {
|
|
32097
32440
|
const home = homedir8();
|
|
32098
32441
|
const p2 = platform4();
|
|
@@ -32106,7 +32449,7 @@ function userLevelConfigPath() {
|
|
|
32106
32449
|
return join30(xdg, "Code", "User", "mcp.json");
|
|
32107
32450
|
}
|
|
32108
32451
|
function isHomeDir(cwd) {
|
|
32109
|
-
return
|
|
32452
|
+
return resolve9(cwd) === resolve9(homedir8());
|
|
32110
32453
|
}
|
|
32111
32454
|
function hasWorkspaceVscode(cwd) {
|
|
32112
32455
|
return existsSync33(join30(cwd, ".vscode"));
|
|
@@ -32319,14 +32662,14 @@ function parseGraceMs(value, fallbackMs) {
|
|
|
32319
32662
|
return Math.round(n * 1000);
|
|
32320
32663
|
}
|
|
32321
32664
|
function resolveSpecPath(cwd, raw) {
|
|
32322
|
-
return isAbsolute4(raw) ? raw :
|
|
32665
|
+
return isAbsolute4(raw) ? raw : resolve10(cwd, raw);
|
|
32323
32666
|
}
|
|
32324
32667
|
function buildConnectionName(serverId) {
|
|
32325
32668
|
const slug = serverId.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24) || "mcp-server";
|
|
32326
32669
|
return `mcpsh-dev-${slug}`;
|
|
32327
32670
|
}
|
|
32328
32671
|
function registerDevCommand(program2) {
|
|
32329
|
-
const dev = program2.command("dev").description("Run a deployed MCP server locally with hot reload + agent auto-wire").option("--server <server>", "Server (id, name, or slug; default: from .mcpcloud/state.json)").option("--org <organizationId>", "Organization ID (overrides default)").option("--port <number>", "Local port (default 8787)").option("--transport <list>", "Comma-separated: http,sse,stdio (default http,sse)").option("--stdio", "Shorthand for --transport stdio").option("--offline", "Use cached bundle, skip Convex sync").option("--no-watch", "Disable file watcher").option("--no-connect", "Disable agent auto-wire prompts").option("--auto-connect <agent>", "Auto-wire the named agent (claude-code, cursor, codex, vscode-copilot, continue)").option("--no-inspector", "Disable the inspector UI (default: enabled at /__inspect)").option("--spec <path>", "Watch this OpenAPI spec file and regenerate the bundle on change").option("--no-auto-regen", "Show spec drift but do not auto-apply (manual file edit still works)").option("--regen-grace <seconds>", "Grace period before auto-applying spec changes (default 5)").option("--enrich-on-change", "Preserve per-tool enrichment when the spec changes").option("--open <choice>", "Open an editor on startup: yes | always | no | never | ask").option("--open-target <choice>", "What to open: tools (.mcpcloud/tools/<server>/) | bundle (read-only .mcpcloud/server/) | all (both). When omitted on first run, mcp dev prompts.").option("--editor <command>", "Editor binary for this invocation (e.g. cursor, code, windsurf). Overrides saved editorCommand and the multi-editor picker.").option("--verbose", "Verbose logs").action(runAction(runDev));
|
|
32672
|
+
const dev = program2.command("dev").description("Run a deployed MCP server locally with hot reload + agent auto-wire").option("--server <server>", "Server (id, name, or slug; default: from .mcpcloud/state.json)").option("--org <organizationId>", "Organization ID (overrides default)").option("--port <number>", "Local port (default 8787)").option("--transport <list>", "Comma-separated: http,sse,stdio (default http,sse)").option("--stdio", "Shorthand for --transport stdio").option("--offline", "Use cached bundle, skip Convex sync").option("--repo <path>", "Git-native only: serve from this checkout of the linked repo (remembered per server, so later runs anywhere reuse it)").option("--no-watch", "Disable file watcher").option("--no-connect", "Disable agent auto-wire prompts").option("--auto-connect <agent>", "Auto-wire the named agent (claude-code, cursor, codex, vscode-copilot, continue)").option("--no-inspector", "Disable the inspector UI (default: enabled at /__inspect)").option("--spec <path>", "Watch this OpenAPI spec file and regenerate the bundle on change").option("--no-auto-regen", "Show spec drift but do not auto-apply (manual file edit still works)").option("--regen-grace <seconds>", "Grace period before auto-applying spec changes (default 5)").option("--enrich-on-change", "Preserve per-tool enrichment when the spec changes").option("--open <choice>", "Open an editor on startup: yes | always | no | never | ask").option("--open-target <choice>", "What to open: tools (.mcpcloud/tools/<server>/) | bundle (read-only .mcpcloud/server/) | all (both). When omitted on first run, mcp dev prompts.").option("--editor <command>", "Editor binary for this invocation (e.g. cursor, code, windsurf). Overrides saved editorCommand and the multi-editor picker.").option("--verbose", "Verbose logs").action(runAction(runDev));
|
|
32330
32673
|
dev.addHelpText("after", `
|
|
32331
32674
|
Git-native mode (automatic):
|
|
32332
32675
|
If the chosen server is linked to a GitHub repo, mcp dev clones it under
|
|
@@ -32334,7 +32677,7 @@ Git-native mode (automatic):
|
|
|
32334
32677
|
your own editor, then commit + push: the webhook reconciles src/** back into
|
|
32335
32678
|
MCPCloud. The CLI's tool/handler PATCH watchers are off in this mode (native
|
|
32336
32679
|
git is the version control). Config under mcpcloud/ is a read-only mirror —
|
|
32337
|
-
change it in the dashboard. Deploy when ready with \`mcp deploy\` or the UI.
|
|
32680
|
+
change it in the dashboard. Deploy when ready with \`mcp servers deploy\` or the UI.
|
|
32338
32681
|
An unlinked server uses the default flow (download bundle, edit via dashboard).
|
|
32339
32682
|
`);
|
|
32340
32683
|
dev.command("list").description("List running mcp dev sessions on this machine").action(runAction(runDevList));
|
|
@@ -32477,7 +32820,8 @@ async function runDev(opts) {
|
|
|
32477
32820
|
port,
|
|
32478
32821
|
transports,
|
|
32479
32822
|
offline: Boolean(opts.offline),
|
|
32480
|
-
inspector: inspectorEnabled
|
|
32823
|
+
inspector: inspectorEnabled,
|
|
32824
|
+
repoDirOverride: typeof opts.repo === "string" ? opts.repo : undefined
|
|
32481
32825
|
});
|
|
32482
32826
|
let specPath = null;
|
|
32483
32827
|
if (opts.spec) {
|
|
@@ -32762,7 +33106,7 @@ async function runWithRuntime(args) {
|
|
|
32762
33106
|
printInfo(` ${c.dim(`Edit files in ${relative7(args.cwd, args.prepared.destDir)}/ to hot-reload.`)}`);
|
|
32763
33107
|
if (args.gitNative && args.prepared.repoDir) {
|
|
32764
33108
|
printInfo(` ${c.dim(`Git-native: edit + commit + push in ${relative7(args.cwd, args.prepared.repoDir)}/ — the webhook reconciles src/**.`)}`);
|
|
32765
|
-
printInfo(` ${c.dim("Config under mcpcloud/ is read-only; change it in the dashboard. Deploy when ready (mcp deploy).")}`);
|
|
33109
|
+
printInfo(` ${c.dim("Config under mcpcloud/ is read-only; change it in the dashboard. Deploy when ready (mcp servers deploy).")}`);
|
|
32766
33110
|
}
|
|
32767
33111
|
if (toolsWatcher) {
|
|
32768
33112
|
printInfo(` ${c.dim(`Edit tool metadata in .mcpcloud/tools/${args.serverId}/ (changes push to cloud on save).`)}`);
|
|
@@ -32803,7 +33147,7 @@ async function runWithRuntime(args) {
|
|
|
32803
33147
|
parts.push(`${status.deletedFileCount} deleted`);
|
|
32804
33148
|
}
|
|
32805
33149
|
printSuccess(`Push ${sha} reconciled (${parts.join(", ")}) — changes ready for deployment.`);
|
|
32806
|
-
printInfo(` ${c.dim("Deploy with")} ${c.bold("mcp deploy")} ${c.dim("or the dashboard — no preview needed, this session is your local server.")}`);
|
|
33150
|
+
printInfo(` ${c.dim("Deploy with")} ${c.bold("mcp servers deploy")} ${c.dim("or the dashboard — no preview needed, this session is your local server.")}`);
|
|
32807
33151
|
},
|
|
32808
33152
|
onError: () => {}
|
|
32809
33153
|
}) : null;
|
|
@@ -33408,12 +33752,12 @@ async function confirmRollback(deploymentId) {
|
|
|
33408
33752
|
}
|
|
33409
33753
|
|
|
33410
33754
|
// src/commands/doctor.ts
|
|
33411
|
-
import { existsSync as existsSync36, statSync as statSync6, readFileSync as
|
|
33755
|
+
import { existsSync as existsSync36, statSync as statSync6, readFileSync as readFileSync26 } from "node:fs";
|
|
33412
33756
|
import { homedir as homedir9, platform as platform6 } from "node:os";
|
|
33413
33757
|
import { join as join32, delimiter as delimiter3 } from "node:path";
|
|
33414
33758
|
|
|
33415
33759
|
// src/lib/version-check.ts
|
|
33416
|
-
import { existsSync as existsSync35, mkdirSync as mkdirSync18, readFileSync as
|
|
33760
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync18, readFileSync as readFileSync25, writeFileSync as writeFileSync21 } from "node:fs";
|
|
33417
33761
|
import { join as join31 } from "node:path";
|
|
33418
33762
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
33419
33763
|
var FETCH_TIMEOUT_MS2 = 2000;
|
|
@@ -33428,7 +33772,7 @@ function readCache() {
|
|
|
33428
33772
|
if (!existsSync35(cacheFile()))
|
|
33429
33773
|
return null;
|
|
33430
33774
|
try {
|
|
33431
|
-
const raw = JSON.parse(
|
|
33775
|
+
const raw = JSON.parse(readFileSync25(cacheFile(), "utf-8"));
|
|
33432
33776
|
if (typeof raw.latest !== "string" || typeof raw.fetchedAt !== "number")
|
|
33433
33777
|
return null;
|
|
33434
33778
|
return { latest: raw.latest, fetchedAt: raw.fetchedAt };
|
|
@@ -33574,7 +33918,7 @@ function checkConfigFile() {
|
|
|
33574
33918
|
} catch {}
|
|
33575
33919
|
}
|
|
33576
33920
|
try {
|
|
33577
|
-
JSON.parse(
|
|
33921
|
+
JSON.parse(readFileSync26(path, "utf-8"));
|
|
33578
33922
|
} catch (err) {
|
|
33579
33923
|
return {
|
|
33580
33924
|
name: "Config file",
|
|
@@ -33929,7 +34273,7 @@ var TOPICS = {
|
|
|
33929
34273
|
" 2. Paste flow (SSH/headless): mcp login --paste",
|
|
33930
34274
|
" Prompts for an API key generated in the dashboard.",
|
|
33931
34275
|
"",
|
|
33932
|
-
" 3. Environment variable: export MCPCLOUD_API_KEY=
|
|
34276
|
+
" 3. Environment variable: export MCPCLOUD_API_KEY=mcf_…",
|
|
33933
34277
|
" Highest precedence. Overrides any saved key for the current process.",
|
|
33934
34278
|
"",
|
|
33935
34279
|
"Show the active identity:",
|
|
@@ -33945,12 +34289,12 @@ var TOPICS = {
|
|
|
33945
34289
|
title: "Profiles",
|
|
33946
34290
|
body: [
|
|
33947
34291
|
"A profile is a named bundle of API key + base URL + default org. Use profiles to switch between",
|
|
33948
|
-
"
|
|
34292
|
+
"production and self-hosted deployments without editing JSON by hand.",
|
|
33949
34293
|
"",
|
|
33950
|
-
" $ mcp config profile add
|
|
33951
|
-
" $ mcp config use
|
|
34294
|
+
" $ mcp config profile add selfhost --url https://selfhost.example.com --key mcf_…",
|
|
34295
|
+
" $ mcp config use selfhost",
|
|
33952
34296
|
" $ mcp config profile list",
|
|
33953
|
-
" $ mcp --profile
|
|
34297
|
+
" $ mcp --profile selfhost servers list # one-off override",
|
|
33954
34298
|
"",
|
|
33955
34299
|
"Resolution order for the active profile:",
|
|
33956
34300
|
" 1. --profile <name> flag",
|
|
@@ -34045,10 +34389,10 @@ function prompt2(question) {
|
|
|
34045
34389
|
throw new Error("Interactive prompts are disabled in CI mode. Pass --org / --project / --name explicitly or run `mcp init` outside CI.");
|
|
34046
34390
|
}
|
|
34047
34391
|
const rl = createInterface3({ input: process.stdin, output: process.stderr });
|
|
34048
|
-
return new Promise((
|
|
34392
|
+
return new Promise((resolve11) => {
|
|
34049
34393
|
rl.question(question, (answer) => {
|
|
34050
34394
|
rl.close();
|
|
34051
|
-
|
|
34395
|
+
resolve11(answer.trim());
|
|
34052
34396
|
});
|
|
34053
34397
|
});
|
|
34054
34398
|
}
|
|
@@ -34188,6 +34532,15 @@ async function runSpecInit(args) {
|
|
|
34188
34532
|
}
|
|
34189
34533
|
const ingest = await api.post("/api/v1/server/ingest", buildIngestBody({ organizationId: orgId, projectId: project.id, payload }));
|
|
34190
34534
|
const server = ingest.server;
|
|
34535
|
+
if (opts.gitRepo) {
|
|
34536
|
+
await linkRepoAtCreation({
|
|
34537
|
+
orgId,
|
|
34538
|
+
serverId: server.id,
|
|
34539
|
+
repoRef: opts.gitRepo,
|
|
34540
|
+
pathPrefix: opts.gitPathPrefix,
|
|
34541
|
+
autoSync: opts.gitAutoSync
|
|
34542
|
+
});
|
|
34543
|
+
}
|
|
34191
34544
|
if (!isJsonMode()) {
|
|
34192
34545
|
printSuccess(`Server ${c.bold(server.id)} created from spec.`);
|
|
34193
34546
|
}
|
|
@@ -34297,7 +34650,7 @@ function reportDeploySuccess(args) {
|
|
|
34297
34650
|
|
|
34298
34651
|
// src/commands/init.ts
|
|
34299
34652
|
function registerInitCommand(program2) {
|
|
34300
|
-
program2.command("init").description("Guided onboarding: pick org → pick/create project → create a server (empty skeleton, or generated from an OpenAPI/GraphQL spec via --from-spec)").option("--org <organizationId>", "Organization ID").option("--project <project>", "Reuse an existing project (id or name) instead of creating one").option("--name <serverName>", "Name for the new server (skeleton path only)").option("--from-spec <file|url>", "Build from an OpenAPI spec (local file, http(s) URL, or @- for stdin), or — with --source-type graphql — a GraphQL endpoint URL to introspect").option("--source-type <type>", `Override spec classification: ${SOURCE_TYPES.join(" | ")} (OpenAPI auto-detected; graphql requires an endpoint URL)`).option("--deploy", "After importing the spec, deploy the server").option("--wait", "With --deploy, follow events until the deploy is terminal").option("--wait-timeout <seconds>", "Max seconds to wait for a terminal deploy state (default 300)", "300").addHelpText("after", [
|
|
34653
|
+
program2.command("init").description("Guided onboarding: pick org → pick/create project → create a server (empty skeleton, or generated from an OpenAPI/GraphQL spec via --from-spec)").option("--org <organizationId>", "Organization ID").option("--project <project>", "Reuse an existing project (id or name) instead of creating one").option("--name <serverName>", "Name for the new server (skeleton path only)").option("--from-spec <file|url>", "Build from an OpenAPI spec (local file, http(s) URL, or @- for stdin), or — with --source-type graphql — a GraphQL endpoint URL to introspect").option("--source-type <type>", `Override spec classification: ${SOURCE_TYPES.join(" | ")} (OpenAPI auto-detected; graphql requires an endpoint URL)`).option("--deploy", "After importing the spec, deploy the server").option("--wait", "With --deploy, follow events until the deploy is terminal").option("--wait-timeout <seconds>", "Max seconds to wait for a terminal deploy state (default 300)", "300").option("--git-repo <owner/name>", "Host the generated code on this GitHub repo (spec path only; links now, mirrors after first generation)").option("--git-path-prefix <prefix>", "Sync into this path inside the repo").option("--no-git-auto-sync", "Do not mirror commits automatically").addHelpText("after", [
|
|
34301
34654
|
"",
|
|
34302
34655
|
"Two modes:",
|
|
34303
34656
|
" Skeleton (default): resolve org → pick/create project → create an empty server.",
|
|
@@ -34420,7 +34773,7 @@ function registerInstallationCommands(program2) {
|
|
|
34420
34773
|
}
|
|
34421
34774
|
|
|
34422
34775
|
// src/commands/invoke.ts
|
|
34423
|
-
import { existsSync as existsSync37, readFileSync as
|
|
34776
|
+
import { existsSync as existsSync37, readFileSync as readFileSync27 } from "node:fs";
|
|
34424
34777
|
import { join as join33 } from "node:path";
|
|
34425
34778
|
|
|
34426
34779
|
// src/lib/dev/local-invoke.ts
|
|
@@ -34431,7 +34784,7 @@ function isReadyMessage(value) {
|
|
|
34431
34784
|
async function bootLocalRuntime(args) {
|
|
34432
34785
|
const startupErrors = [];
|
|
34433
34786
|
let handle;
|
|
34434
|
-
const ready = new Promise((
|
|
34787
|
+
const ready = new Promise((resolve11, reject) => {
|
|
34435
34788
|
const timer = setTimeout(() => {
|
|
34436
34789
|
reject(new Error(`The local runtime did not become ready within ${READY_TIMEOUT_MS / 1000}s.${startupErrors.length > 0 ? `
|
|
34437
34790
|
${startupErrors.join("").trim()}` : ""}`));
|
|
@@ -34452,7 +34805,7 @@ ${startupErrors.join("").trim()}` : ""}`));
|
|
|
34452
34805
|
if (!isReadyMessage(message))
|
|
34453
34806
|
return;
|
|
34454
34807
|
clearTimeout(timer);
|
|
34455
|
-
|
|
34808
|
+
resolve11(typeof message.baseUrl === "string" ? message.baseUrl : `http://127.0.0.1:${args.port}`);
|
|
34456
34809
|
});
|
|
34457
34810
|
});
|
|
34458
34811
|
try {
|
|
@@ -34513,9 +34866,9 @@ function selectCodeModeInvocation(args) {
|
|
|
34513
34866
|
}
|
|
34514
34867
|
function readCodeOption(raw) {
|
|
34515
34868
|
if (raw === "@-")
|
|
34516
|
-
return
|
|
34869
|
+
return readFileSync27(0, "utf-8");
|
|
34517
34870
|
if (raw.startsWith("@"))
|
|
34518
|
-
return
|
|
34871
|
+
return readFileSync27(raw.slice(1), "utf-8");
|
|
34519
34872
|
return raw;
|
|
34520
34873
|
}
|
|
34521
34874
|
function parseTimeoutMs4(value, fallbackMs) {
|
|
@@ -34797,7 +35150,7 @@ async function runLocalInvoke(args) {
|
|
|
34797
35150
|
throw new CliExitError(1);
|
|
34798
35151
|
}
|
|
34799
35152
|
const env = {
|
|
34800
|
-
...args.envFile ? parseEnvFile(
|
|
35153
|
+
...args.envFile ? parseEnvFile(readFileSync27(args.envFile, "utf-8")) : {},
|
|
34801
35154
|
...parseEnvPairs(args.envPairs)
|
|
34802
35155
|
};
|
|
34803
35156
|
const port = await findAvailablePort({ range: 40, start: 43117 });
|
|
@@ -35789,7 +36142,7 @@ import {
|
|
|
35789
36142
|
existsSync as existsSync38,
|
|
35790
36143
|
mkdirSync as mkdirSync19,
|
|
35791
36144
|
readdirSync as readdirSync5,
|
|
35792
|
-
readFileSync as
|
|
36145
|
+
readFileSync as readFileSync28,
|
|
35793
36146
|
rmSync as rmSync3,
|
|
35794
36147
|
statSync as statSync7
|
|
35795
36148
|
} from "node:fs";
|
|
@@ -35809,7 +36162,7 @@ function readManifestFromPackageDir(packageDir) {
|
|
|
35809
36162
|
return null;
|
|
35810
36163
|
let pkg;
|
|
35811
36164
|
try {
|
|
35812
|
-
pkg = JSON.parse(
|
|
36165
|
+
pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
|
|
35813
36166
|
} catch {
|
|
35814
36167
|
return null;
|
|
35815
36168
|
}
|
|
@@ -35878,15 +36231,15 @@ async function loadPlugins(program2) {
|
|
|
35878
36231
|
}
|
|
35879
36232
|
var PACKAGE_SPEC_PATTERN = /^(@[a-z0-9~-][\w.~-]*\/)?[a-z0-9~-][\w.~-]*(@[-\w.^~><=*+|]+)?$/i;
|
|
35880
36233
|
function runNpm(args, cwd) {
|
|
35881
|
-
return new Promise((
|
|
36234
|
+
return new Promise((resolve11) => {
|
|
35882
36235
|
const isWindows = process.platform === "win32";
|
|
35883
36236
|
const child = spawn7(isWindows ? "npm.cmd" : "npm", args, {
|
|
35884
36237
|
shell: isWindows,
|
|
35885
36238
|
cwd,
|
|
35886
36239
|
stdio: "inherit"
|
|
35887
36240
|
});
|
|
35888
|
-
child.on("close", (code) =>
|
|
35889
|
-
child.on("error", () =>
|
|
36241
|
+
child.on("close", (code) => resolve11(code ?? 1));
|
|
36242
|
+
child.on("error", () => resolve11(1));
|
|
35890
36243
|
});
|
|
35891
36244
|
}
|
|
35892
36245
|
async function installPlugin(packageSpec) {
|
|
@@ -36410,7 +36763,7 @@ function clipboardCandidatesFor(platform7, waylandDisplay) {
|
|
|
36410
36763
|
return linux;
|
|
36411
36764
|
}
|
|
36412
36765
|
async function defaultIsExecutable(binary) {
|
|
36413
|
-
return await new Promise((
|
|
36766
|
+
return await new Promise((resolve11) => {
|
|
36414
36767
|
const isWin = process.platform === "win32";
|
|
36415
36768
|
const cmd = isWin ? "where" : "command";
|
|
36416
36769
|
const args = isWin ? [binary] : ["-v", binary];
|
|
@@ -36418,8 +36771,8 @@ async function defaultIsExecutable(binary) {
|
|
|
36418
36771
|
shell: !isWin,
|
|
36419
36772
|
stdio: "ignore"
|
|
36420
36773
|
});
|
|
36421
|
-
child.on("error", () =>
|
|
36422
|
-
child.on("exit", (code) =>
|
|
36774
|
+
child.on("error", () => resolve11(false));
|
|
36775
|
+
child.on("exit", (code) => resolve11(code === 0));
|
|
36423
36776
|
});
|
|
36424
36777
|
}
|
|
36425
36778
|
async function detectClipboard(probe) {
|
|
@@ -36441,7 +36794,7 @@ async function copyToClipboard(text, probe) {
|
|
|
36441
36794
|
};
|
|
36442
36795
|
}
|
|
36443
36796
|
const spawnImpl = probe?.spawnImpl ?? spawn8;
|
|
36444
|
-
return await new Promise((
|
|
36797
|
+
return await new Promise((resolve11) => {
|
|
36445
36798
|
const child = spawnImpl(candidate.binary, candidate.args, {
|
|
36446
36799
|
stdio: ["pipe", "ignore", "pipe"]
|
|
36447
36800
|
});
|
|
@@ -36450,7 +36803,7 @@ async function copyToClipboard(text, probe) {
|
|
|
36450
36803
|
stderr += chunk.toString("utf-8");
|
|
36451
36804
|
});
|
|
36452
36805
|
child.on("error", (err) => {
|
|
36453
|
-
|
|
36806
|
+
resolve11({
|
|
36454
36807
|
kind: "failed",
|
|
36455
36808
|
binary: candidate.binary,
|
|
36456
36809
|
message: err instanceof Error ? err.message : String(err)
|
|
@@ -36458,9 +36811,9 @@ async function copyToClipboard(text, probe) {
|
|
|
36458
36811
|
});
|
|
36459
36812
|
child.on("exit", (code) => {
|
|
36460
36813
|
if (code === 0) {
|
|
36461
|
-
|
|
36814
|
+
resolve11({ kind: "ok", binary: candidate.binary });
|
|
36462
36815
|
} else {
|
|
36463
|
-
|
|
36816
|
+
resolve11({
|
|
36464
36817
|
kind: "failed",
|
|
36465
36818
|
binary: candidate.binary,
|
|
36466
36819
|
message: stderr.trim() || `${candidate.binary} exited with status ${code ?? "?"}`
|
|
@@ -36470,7 +36823,7 @@ async function copyToClipboard(text, probe) {
|
|
|
36470
36823
|
try {
|
|
36471
36824
|
child.stdin?.end(text);
|
|
36472
36825
|
} catch (err) {
|
|
36473
|
-
|
|
36826
|
+
resolve11({
|
|
36474
36827
|
kind: "failed",
|
|
36475
36828
|
binary: candidate.binary,
|
|
36476
36829
|
message: err instanceof Error ? err.message : String(err)
|
|
@@ -36532,7 +36885,7 @@ var CLI_EXAMPLES = {
|
|
|
36532
36885
|
"config show": ["mcp config show"],
|
|
36533
36886
|
"config set-url": ["mcp config set-url https://your-deployment.example.com"],
|
|
36534
36887
|
"config set-org": ["mcp config set-org org_abc"],
|
|
36535
|
-
"config use": ["mcp config use
|
|
36888
|
+
"config use": ["mcp config use selfhost"],
|
|
36536
36889
|
"servers list": [
|
|
36537
36890
|
"mcp servers list",
|
|
36538
36891
|
"mcp servers list --filter status=active",
|
|
@@ -37273,13 +37626,14 @@ function liveBadge(frame, label = "LIVE") {
|
|
|
37273
37626
|
return palette.semGreen + dot + " " + ansi.reset + ansi.bold + palette.ink100 + label + ansi.reset;
|
|
37274
37627
|
}
|
|
37275
37628
|
var SPLASH_LINES = [
|
|
37276
|
-
"███╗ ███╗ ██████╗██████╗
|
|
37277
|
-
"████╗
|
|
37278
|
-
"██╔████╔██║██║
|
|
37279
|
-
"██║╚██╔╝██║██║ ██╔═══╝
|
|
37280
|
-
"██║ ╚═╝ ██║╚██████╗██║
|
|
37281
|
-
"╚═╝ ╚═╝ ╚═════╝╚═╝
|
|
37629
|
+
"███╗ ███╗ ██████╗██████╗ ██████╗██╗ ██╗",
|
|
37630
|
+
"████╗ ████║██╔════╝██╔══██╗ ██╔════╝██║ ██║",
|
|
37631
|
+
"██╔████╔██║██║ ██████╔╝ ██║ ██║ ██║",
|
|
37632
|
+
"██║╚██╔╝██║██║ ██╔═══╝ ██║ ██║ ██║",
|
|
37633
|
+
"██║ ╚═╝ ██║╚██████╗██║ ╚██████╗███████╗██║",
|
|
37634
|
+
"╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═════╝╚══════╝╚═╝"
|
|
37282
37635
|
];
|
|
37636
|
+
var SPLASH_ATTRIBUTION = "by MCPCloud.sh".padStart(49);
|
|
37283
37637
|
function centerLine(text, width) {
|
|
37284
37638
|
const len = visibleLength(text);
|
|
37285
37639
|
if (len >= width)
|
|
@@ -37543,7 +37897,7 @@ function displayValueFor(field, value) {
|
|
|
37543
37897
|
import {
|
|
37544
37898
|
existsSync as existsSync39,
|
|
37545
37899
|
mkdirSync as mkdirSync20,
|
|
37546
|
-
readFileSync as
|
|
37900
|
+
readFileSync as readFileSync29,
|
|
37547
37901
|
writeFileSync as writeFileSync22
|
|
37548
37902
|
} from "node:fs";
|
|
37549
37903
|
import { join as join35 } from "node:path";
|
|
@@ -37625,7 +37979,7 @@ function readTuiState() {
|
|
|
37625
37979
|
return {};
|
|
37626
37980
|
let parsed;
|
|
37627
37981
|
try {
|
|
37628
|
-
parsed = JSON.parse(
|
|
37982
|
+
parsed = JSON.parse(readFileSync29(path, "utf-8"));
|
|
37629
37983
|
} catch {
|
|
37630
37984
|
return {};
|
|
37631
37985
|
}
|
|
@@ -38094,8 +38448,8 @@ function renderSplash(state) {
|
|
|
38094
38448
|
const colored = ansi.bold + palette.ink100 + (SPLASH_LINES[i] ?? "") + ansi.reset;
|
|
38095
38449
|
out.push(moveTo(splashTop + i, 1) + palette.voidBg + centerLine(colored, cols) + ansi.reset);
|
|
38096
38450
|
}
|
|
38097
|
-
const
|
|
38098
|
-
out.push(moveTo(splashTop + SPLASH_LINES.length
|
|
38451
|
+
const attribution = palette.ink35 + SPLASH_ATTRIBUTION + ansi.reset;
|
|
38452
|
+
out.push(moveTo(splashTop + SPLASH_LINES.length, 1) + palette.voidBg + centerLine(attribution, cols) + ansi.reset);
|
|
38099
38453
|
const spinner = SPINNER_FRAMES[state.spinnerFrame % SPINNER_FRAMES.length] ?? "⠋";
|
|
38100
38454
|
const loading = palette.ink60 + spinner + ansi.reset + palette.ink35 + " fetching " + state.tab + " from " + state.orgId + "…" + ansi.reset;
|
|
38101
38455
|
out.push(moveTo(splashTop + SPLASH_LINES.length + 3, 1) + palette.voidBg + centerLine(loading, cols) + ansi.reset);
|
|
@@ -38910,7 +39264,7 @@ async function startInspector(state, handles, redraw) {
|
|
|
38910
39264
|
redraw();
|
|
38911
39265
|
}
|
|
38912
39266
|
function registerUiCommand(program2) {
|
|
38913
|
-
program2.command("ui").description("Interactive terminal UI: browse orgs/servers/skills, tail deployment logs, and watch the live `mcp dev` inspector").option("--org <organizationId>", "Organization ID (overrides default)").option("--no-splash", "Skip the splash screen and jump straight to the list view").addHelpText("after", [
|
|
39267
|
+
program2.command("ui").description("Interactive terminal UI: browse orgs/servers/skills, tail deployment logs, and watch the live `mcp dev` inspector").option("--org <organizationId>", "Organization ID (overrides default)").option("--splash", "Always show the splash screen, even after the first run").option("--no-splash", "Skip the splash screen and jump straight to the list view").addHelpText("after", [
|
|
38914
39268
|
"",
|
|
38915
39269
|
"Tabs (1-6):",
|
|
38916
39270
|
" 1 Servers",
|
|
@@ -38968,7 +39322,8 @@ function registerUiCommand(program2) {
|
|
|
38968
39322
|
" Last tab, org, sort, filter, and selected row are persisted to",
|
|
38969
39323
|
" ~/.mcpcloud/tui-state.json so the next launch resumes where you",
|
|
38970
39324
|
" left off. The splash is shown once per install; pass --no-splash",
|
|
38971
|
-
" to suppress it sooner, or
|
|
39325
|
+
" to suppress it sooner, or --splash to bring it back (demos,",
|
|
39326
|
+
" screenshots)."
|
|
38972
39327
|
].join(`
|
|
38973
39328
|
`)).action(runAction(async (opts) => {
|
|
38974
39329
|
if (!process.stdout.isTTY) {
|
|
@@ -38986,8 +39341,7 @@ function registerUiCommand(program2) {
|
|
|
38986
39341
|
} else {
|
|
38987
39342
|
orgId = await resolveOrgId(undefined);
|
|
38988
39343
|
}
|
|
38989
|
-
const
|
|
38990
|
-
const showSplash = !splashFlagDisabled && persisted.splashSeen !== true;
|
|
39344
|
+
const showSplash = opts.splash === true || opts.splash !== false && persisted.splashSeen !== true;
|
|
38991
39345
|
const sortByTab = {
|
|
38992
39346
|
servers: persisted.sortByTab?.servers ?? null,
|
|
38993
39347
|
projects: persisted.sortByTab?.projects ?? null,
|
|
@@ -39641,7 +39995,7 @@ function registerUiCommand(program2) {
|
|
|
39641
39995
|
}
|
|
39642
39996
|
return false;
|
|
39643
39997
|
};
|
|
39644
|
-
await new Promise((
|
|
39998
|
+
await new Promise((resolve11) => {
|
|
39645
39999
|
const flushAndExit = () => {
|
|
39646
40000
|
try {
|
|
39647
40001
|
if (persistTimer) {
|
|
@@ -39651,7 +40005,7 @@ function registerUiCommand(program2) {
|
|
|
39651
40005
|
writeTuiState(snapshotForPersist());
|
|
39652
40006
|
} catch {}
|
|
39653
40007
|
shutdown(handles);
|
|
39654
|
-
|
|
40008
|
+
resolve11();
|
|
39655
40009
|
};
|
|
39656
40010
|
const executePaletteCommand = (id) => {
|
|
39657
40011
|
if (id.startsWith("tab:")) {
|
|
@@ -40321,10 +40675,10 @@ function buildCommand(manager) {
|
|
|
40321
40675
|
}
|
|
40322
40676
|
}
|
|
40323
40677
|
function runShell(command) {
|
|
40324
|
-
return new Promise((
|
|
40678
|
+
return new Promise((resolve11) => {
|
|
40325
40679
|
const child = spawn9(command, { shell: true, stdio: "inherit" });
|
|
40326
|
-
child.on("close", (code) =>
|
|
40327
|
-
child.on("error", () =>
|
|
40680
|
+
child.on("close", (code) => resolve11(code ?? 1));
|
|
40681
|
+
child.on("error", () => resolve11(1));
|
|
40328
40682
|
});
|
|
40329
40683
|
}
|
|
40330
40684
|
function registerUpdateCommand(program2) {
|
|
@@ -40424,7 +40778,7 @@ function createProgram() {
|
|
|
40424
40778
|
" $ mcp servers list --field id,name --format jsonl",
|
|
40425
40779
|
" $ mcp servers list --filter status=active --no-table",
|
|
40426
40780
|
"",
|
|
40427
|
-
"Self-
|
|
40781
|
+
"Self-hosted deployment: point the CLI elsewhere with MCPCLOUD_BASE_URL,",
|
|
40428
40782
|
"`mcp config set-url <url>`, or --base-url <url> (each overrides the default)."
|
|
40429
40783
|
].join(`
|
|
40430
40784
|
`));
|