@mcpcloud/cli 0.3.0 → 0.4.0-next-20260611161108
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 +562 -176
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5113,6 +5113,10 @@ function stateFile(cwd) {
|
|
|
5113
5113
|
function serverDir(cwd) {
|
|
5114
5114
|
return join4(devRoot(cwd), "server");
|
|
5115
5115
|
}
|
|
5116
|
+
function gitCloneDir(cwd, owner, name) {
|
|
5117
|
+
const safe = `${owner}__${name}`.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
5118
|
+
return join4(devRoot(cwd), "git", safe);
|
|
5119
|
+
}
|
|
5116
5120
|
function envFile(cwd) {
|
|
5117
5121
|
return join4(devRoot(cwd), "env.json");
|
|
5118
5122
|
}
|
|
@@ -5152,6 +5156,7 @@ function ensureGitignore(cwd) {
|
|
|
5152
5156
|
writeFileSync2(ignoreFile, [
|
|
5153
5157
|
"# generated by `mcp dev`",
|
|
5154
5158
|
"server/",
|
|
5159
|
+
"git/",
|
|
5155
5160
|
"env.json",
|
|
5156
5161
|
"agent-backups/",
|
|
5157
5162
|
"inspector/",
|
|
@@ -8097,7 +8102,7 @@ function registerConfigCommands(program2) {
|
|
|
8097
8102
|
}
|
|
8098
8103
|
|
|
8099
8104
|
// src/commands/dev.ts
|
|
8100
|
-
import { existsSync as
|
|
8105
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
8101
8106
|
import { isAbsolute as isAbsolute2, relative as relative7, resolve as resolve6 } from "node:path";
|
|
8102
8107
|
|
|
8103
8108
|
// src/lib/mcp-invoke.ts
|
|
@@ -9556,6 +9561,24 @@ var Q = class extends m {
|
|
|
9556
9561
|
}
|
|
9557
9562
|
}
|
|
9558
9563
|
};
|
|
9564
|
+
|
|
9565
|
+
class X extends m {
|
|
9566
|
+
get cursor() {
|
|
9567
|
+
return this.value ? 0 : 1;
|
|
9568
|
+
}
|
|
9569
|
+
get _value() {
|
|
9570
|
+
return this.cursor === 0;
|
|
9571
|
+
}
|
|
9572
|
+
constructor(t) {
|
|
9573
|
+
super(t, false), this.value = !!t.initialValue, this.on("userInput", () => {
|
|
9574
|
+
this.value = this._value;
|
|
9575
|
+
}), this.on("confirm", (s) => {
|
|
9576
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
9577
|
+
}), this.on("cursor", () => {
|
|
9578
|
+
this.value = !this.value;
|
|
9579
|
+
});
|
|
9580
|
+
}
|
|
9581
|
+
}
|
|
9559
9582
|
var Z = { Y: { type: "year", len: 4 }, M: { type: "month", len: 2 }, D: { type: "day", len: 2 } };
|
|
9560
9583
|
function P(r) {
|
|
9561
9584
|
return [...r].map((t) => Z[t]);
|
|
@@ -9992,6 +10015,33 @@ var F2 = ({ cursor: t, options: i, style: s, output: r = process.stdout, maxItem
|
|
|
9992
10015
|
S2.push(G2);
|
|
9993
10016
|
return h2 && S2.push(l), S2;
|
|
9994
10017
|
};
|
|
10018
|
+
var ue = (t) => {
|
|
10019
|
+
const i = t.active ?? "Yes", s = t.inactive ?? "No";
|
|
10020
|
+
return new X({ active: i, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
|
|
10021
|
+
const r = t.withGuide ?? h.withGuide, u = `${P2(this.state)} `, n = r ? `${e("gray", $2)} ` : "", a = W(t.output, t.message, n, u), c2 = `${r ? `${e("gray", $2)}
|
|
10022
|
+
` : ""}${a}
|
|
10023
|
+
`, o = this.value ? i : s;
|
|
10024
|
+
switch (this.state) {
|
|
10025
|
+
case "submit": {
|
|
10026
|
+
const l = r ? `${e("gray", $2)} ` : "";
|
|
10027
|
+
return `${c2}${l}${e("dim", o)}`;
|
|
10028
|
+
}
|
|
10029
|
+
case "cancel": {
|
|
10030
|
+
const l = r ? `${e("gray", $2)} ` : "";
|
|
10031
|
+
return `${c2}${l}${e(["strikethrough", "dim"], o)}${r ? `
|
|
10032
|
+
${e("gray", $2)}` : ""}`;
|
|
10033
|
+
}
|
|
10034
|
+
default: {
|
|
10035
|
+
const l = r ? `${e("cyan", $2)} ` : "", d = r ? e("cyan", x2) : "";
|
|
10036
|
+
return `${c2}${l}${this.value ? `${e("green", z2)} ${i}` : `${e("dim", U2)} ${e("dim", i)}`}${t.vertical ? r ? `
|
|
10037
|
+
${e("cyan", $2)} ` : `
|
|
10038
|
+
` : ` ${e("dim", "/")} `}${this.value ? `${e("dim", U2)} ${e("dim", s)}` : `${e("green", z2)} ${s}`}
|
|
10039
|
+
${d}
|
|
10040
|
+
`;
|
|
10041
|
+
}
|
|
10042
|
+
}
|
|
10043
|
+
} }).prompt();
|
|
10044
|
+
};
|
|
9995
10045
|
var me = (t = "", i) => {
|
|
9996
10046
|
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", x2)} ` : "";
|
|
9997
10047
|
s.write(`${r}${e("red", t)}
|
|
@@ -10092,6 +10142,18 @@ async function resolveDevTarget(deps) {
|
|
|
10092
10142
|
}
|
|
10093
10143
|
};
|
|
10094
10144
|
}
|
|
10145
|
+
async function promptResumeOrSwitch(args) {
|
|
10146
|
+
const label = args.serverName ? `${args.serverName} ${c.dim(`(${args.serverId})`)}` : args.serverId;
|
|
10147
|
+
const resume = await ue({
|
|
10148
|
+
message: `Resume ${label}?`,
|
|
10149
|
+
active: "Resume",
|
|
10150
|
+
inactive: "Pick a different server",
|
|
10151
|
+
initialValue: true
|
|
10152
|
+
});
|
|
10153
|
+
if (q(resume))
|
|
10154
|
+
return "cancel";
|
|
10155
|
+
return resume ? "resume" : "switch";
|
|
10156
|
+
}
|
|
10095
10157
|
function canRunInteractive() {
|
|
10096
10158
|
if (isCiMode())
|
|
10097
10159
|
return false;
|
|
@@ -10177,6 +10239,20 @@ async function resolveServerProject(args) {
|
|
|
10177
10239
|
version: data.server.version
|
|
10178
10240
|
};
|
|
10179
10241
|
}
|
|
10242
|
+
async function resolveServerGitLink(args) {
|
|
10243
|
+
const data = await api.get("/api/v1/server/git-link", {
|
|
10244
|
+
organizationId: args.organizationId,
|
|
10245
|
+
serverId: args.serverId
|
|
10246
|
+
});
|
|
10247
|
+
return data.gitLink ?? null;
|
|
10248
|
+
}
|
|
10249
|
+
async function resolveServerGitPullStatus(args) {
|
|
10250
|
+
const data = await api.get("/api/v1/server/git-sync-status", {
|
|
10251
|
+
organizationId: args.organizationId,
|
|
10252
|
+
serverId: args.serverId
|
|
10253
|
+
});
|
|
10254
|
+
return data.pull ?? null;
|
|
10255
|
+
}
|
|
10180
10256
|
async function fetchBundle(args) {
|
|
10181
10257
|
requireApiKey();
|
|
10182
10258
|
const url = new URL("/api/v1/artifacts/download", getBaseUrl());
|
|
@@ -10274,6 +10350,49 @@ function pruneStaleFiles(rootDir, currentDir, kept) {
|
|
|
10274
10350
|
return removed;
|
|
10275
10351
|
}
|
|
10276
10352
|
|
|
10353
|
+
// src/lib/dev/git-pull-poll.ts
|
|
10354
|
+
var DEFAULT_INTERVAL_MS2 = 6000;
|
|
10355
|
+
function reducePollState(baseline, status) {
|
|
10356
|
+
if (!status)
|
|
10357
|
+
return { baseline, nudge: false };
|
|
10358
|
+
const sha = status.lastPulledGitSha;
|
|
10359
|
+
if (baseline === undefined)
|
|
10360
|
+
return { baseline: sha, nudge: false };
|
|
10361
|
+
if (sha && sha !== baseline)
|
|
10362
|
+
return { baseline: sha, nudge: true };
|
|
10363
|
+
return { baseline, nudge: false };
|
|
10364
|
+
}
|
|
10365
|
+
function startGitPullPoll(args) {
|
|
10366
|
+
const intervalMs = args.intervalMs ?? DEFAULT_INTERVAL_MS2;
|
|
10367
|
+
let baseline;
|
|
10368
|
+
let stopped = false;
|
|
10369
|
+
let timer = null;
|
|
10370
|
+
const tick = async () => {
|
|
10371
|
+
if (stopped)
|
|
10372
|
+
return;
|
|
10373
|
+
try {
|
|
10374
|
+
const status = await args.fetchStatus();
|
|
10375
|
+
const next = reducePollState(baseline, status);
|
|
10376
|
+
baseline = next.baseline;
|
|
10377
|
+
if (next.nudge && status)
|
|
10378
|
+
args.onChange(status);
|
|
10379
|
+
} catch (err) {
|
|
10380
|
+
args.onError?.(err);
|
|
10381
|
+
} finally {
|
|
10382
|
+
if (!stopped)
|
|
10383
|
+
timer = setTimeout(() => void tick(), intervalMs);
|
|
10384
|
+
}
|
|
10385
|
+
};
|
|
10386
|
+
tick();
|
|
10387
|
+
return {
|
|
10388
|
+
close() {
|
|
10389
|
+
stopped = true;
|
|
10390
|
+
if (timer)
|
|
10391
|
+
clearTimeout(timer);
|
|
10392
|
+
}
|
|
10393
|
+
};
|
|
10394
|
+
}
|
|
10395
|
+
|
|
10277
10396
|
// src/lib/dev/editor.ts
|
|
10278
10397
|
import { spawn as spawn4 } from "node:child_process";
|
|
10279
10398
|
import { existsSync as existsSync17, statSync as statSync4 } from "node:fs";
|
|
@@ -10972,16 +11091,126 @@ async function installDependencies(options) {
|
|
|
10972
11091
|
}
|
|
10973
11092
|
|
|
10974
11093
|
// src/lib/dev/prepare.ts
|
|
10975
|
-
import { existsSync as
|
|
10976
|
-
import { join as
|
|
11094
|
+
import { existsSync as existsSync25, writeFileSync as writeFileSync10 } from "node:fs";
|
|
11095
|
+
import { join as join20, relative as relative6 } from "node:path";
|
|
11096
|
+
|
|
11097
|
+
// src/lib/dev/git-clone.ts
|
|
11098
|
+
import { spawnSync } from "node:child_process";
|
|
11099
|
+
import {
|
|
11100
|
+
existsSync as existsSync22,
|
|
11101
|
+
mkdirSync as mkdirSync9,
|
|
11102
|
+
readFileSync as readFileSync14,
|
|
11103
|
+
writeFileSync as writeFileSync7
|
|
11104
|
+
} from "node:fs";
|
|
11105
|
+
import { dirname as dirname5, join as join17 } from "node:path";
|
|
11106
|
+
|
|
11107
|
+
class GitNotAvailableError extends Error {
|
|
11108
|
+
constructor() {
|
|
11109
|
+
super("git is not installed or not on your PATH. Install Git to use Git-native dev mode.");
|
|
11110
|
+
this.name = "GitNotAvailableError";
|
|
11111
|
+
}
|
|
11112
|
+
}
|
|
11113
|
+
|
|
11114
|
+
class GitCloneError extends Error {
|
|
11115
|
+
constructor(message) {
|
|
11116
|
+
super(message);
|
|
11117
|
+
this.name = "GitCloneError";
|
|
11118
|
+
}
|
|
11119
|
+
}
|
|
11120
|
+
var GIT_LOCAL_EXCLUDES = [
|
|
11121
|
+
"_mcpsh_*",
|
|
11122
|
+
"node_modules/",
|
|
11123
|
+
"bun.lock"
|
|
11124
|
+
];
|
|
11125
|
+
var EXCLUDE_HEADER = "# added by `mcp dev` (Git-native mode)";
|
|
11126
|
+
function gitCloneArgs(httpsCloneUrl, branch, repoDir) {
|
|
11127
|
+
return [
|
|
11128
|
+
"clone",
|
|
11129
|
+
"--branch",
|
|
11130
|
+
branch,
|
|
11131
|
+
"--single-branch",
|
|
11132
|
+
httpsCloneUrl,
|
|
11133
|
+
repoDir
|
|
11134
|
+
];
|
|
11135
|
+
}
|
|
11136
|
+
function gitFetchArgs(branch) {
|
|
11137
|
+
return ["fetch", "--quiet", "origin", branch];
|
|
11138
|
+
}
|
|
11139
|
+
function mergeLocalExcludes(existing) {
|
|
11140
|
+
const lines = existing.split(`
|
|
11141
|
+
`);
|
|
11142
|
+
const present = new Set(lines.map((l) => l.trim()));
|
|
11143
|
+
const missing = GIT_LOCAL_EXCLUDES.filter((pattern) => !present.has(pattern));
|
|
11144
|
+
if (missing.length === 0)
|
|
11145
|
+
return null;
|
|
11146
|
+
const prefix = existing.length > 0 && !existing.endsWith(`
|
|
11147
|
+
`) ? `
|
|
11148
|
+
` : "";
|
|
11149
|
+
const block = present.has(EXCLUDE_HEADER) ? missing.join(`
|
|
11150
|
+
`) : [EXCLUDE_HEADER, ...missing].join(`
|
|
11151
|
+
`);
|
|
11152
|
+
return `${existing}${prefix}${block}
|
|
11153
|
+
`;
|
|
11154
|
+
}
|
|
11155
|
+
function runGit(args, cwd) {
|
|
11156
|
+
const res = spawnSync("git", args, {
|
|
11157
|
+
cwd,
|
|
11158
|
+
encoding: "utf-8",
|
|
11159
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
11160
|
+
});
|
|
11161
|
+
if (res.error && res.error.code === "ENOENT") {
|
|
11162
|
+
throw new GitNotAvailableError;
|
|
11163
|
+
}
|
|
11164
|
+
return {
|
|
11165
|
+
status: res.status ?? 1,
|
|
11166
|
+
stdout: res.stdout ?? "",
|
|
11167
|
+
stderr: res.stderr ?? ""
|
|
11168
|
+
};
|
|
11169
|
+
}
|
|
11170
|
+
function isGitAvailable() {
|
|
11171
|
+
try {
|
|
11172
|
+
return runGit(["--version"]).status === 0;
|
|
11173
|
+
} catch {
|
|
11174
|
+
return false;
|
|
11175
|
+
}
|
|
11176
|
+
}
|
|
11177
|
+
function applyLocalExcludes(repoDir) {
|
|
11178
|
+
const excludePath = join17(repoDir, ".git", "info", "exclude");
|
|
11179
|
+
const existing = existsSync22(excludePath) ? readFileSync14(excludePath, "utf-8") : "";
|
|
11180
|
+
const next = mergeLocalExcludes(existing);
|
|
11181
|
+
if (next === null)
|
|
11182
|
+
return;
|
|
11183
|
+
if (!existsSync22(dirname5(excludePath))) {
|
|
11184
|
+
mkdirSync9(dirname5(excludePath), { recursive: true });
|
|
11185
|
+
}
|
|
11186
|
+
writeFileSync7(excludePath, next, "utf-8");
|
|
11187
|
+
}
|
|
11188
|
+
function ensureClone(opts) {
|
|
11189
|
+
if (!isGitAvailable()) {
|
|
11190
|
+
throw new GitNotAvailableError;
|
|
11191
|
+
}
|
|
11192
|
+
if (existsSync22(join17(opts.repoDir, ".git"))) {
|
|
11193
|
+
opts.onStep?.("Refreshing existing clone (git fetch)…");
|
|
11194
|
+
runGit(gitFetchArgs(opts.branch), opts.repoDir);
|
|
11195
|
+
applyLocalExcludes(opts.repoDir);
|
|
11196
|
+
return { cloned: false };
|
|
11197
|
+
}
|
|
11198
|
+
opts.onStep?.(`Cloning ${opts.httpsCloneUrl} (branch ${opts.branch})…`);
|
|
11199
|
+
const res = runGit(gitCloneArgs(opts.httpsCloneUrl, opts.branch, opts.repoDir));
|
|
11200
|
+
if (res.status !== 0) {
|
|
11201
|
+
throw new GitCloneError(`git clone failed (exit ${res.status}). ${res.stderr.trim() || "Check that you have access to the repository with your local git credentials."}`);
|
|
11202
|
+
}
|
|
11203
|
+
applyLocalExcludes(opts.repoDir);
|
|
11204
|
+
return { cloned: true };
|
|
11205
|
+
}
|
|
10977
11206
|
|
|
10978
11207
|
// src/lib/dev/host-runtime.ts
|
|
10979
|
-
import { existsSync as
|
|
10980
|
-
import { dirname as
|
|
11208
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync11, writeFileSync as writeFileSync9 } from "node:fs";
|
|
11209
|
+
import { dirname as dirname6, join as join19 } from "node:path";
|
|
10981
11210
|
|
|
10982
11211
|
// src/lib/dev/inspector-module.ts
|
|
10983
|
-
import { existsSync as
|
|
10984
|
-
import { join as
|
|
11212
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8 } from "node:fs";
|
|
11213
|
+
import { join as join18 } from "node:path";
|
|
10985
11214
|
|
|
10986
11215
|
// src/lib/dev/inspector-assets.ts
|
|
10987
11216
|
var INSPECTOR_HTML = `<!doctype html>
|
|
@@ -11482,7 +11711,7 @@ function requireReact_production() {
|
|
|
11482
11711
|
react_production.useTransition = function() {
|
|
11483
11712
|
return ReactSharedInternals.H.useTransition();
|
|
11484
11713
|
};
|
|
11485
|
-
react_production.version = "19.2.
|
|
11714
|
+
react_production.version = "19.2.7";
|
|
11486
11715
|
return react_production;
|
|
11487
11716
|
}
|
|
11488
11717
|
var hasRequiredReact;
|
|
@@ -11909,7 +12138,7 @@ function requireReactDom_production() {
|
|
|
11909
12138
|
reactDom_production.useFormStatus = function() {
|
|
11910
12139
|
return ReactSharedInternals.H.useHostTransitionStatus();
|
|
11911
12140
|
};
|
|
11912
|
-
reactDom_production.version = "19.2.
|
|
12141
|
+
reactDom_production.version = "19.2.7";
|
|
11913
12142
|
return reactDom_production;
|
|
11914
12143
|
}
|
|
11915
12144
|
var hasRequiredReactDom;
|
|
@@ -23353,12 +23582,12 @@ function requireReactDomClient_production() {
|
|
|
23353
23582
|
}
|
|
23354
23583
|
};
|
|
23355
23584
|
var isomorphicReactPackageVersion$jscomp$inline_1840 = React.version;
|
|
23356
|
-
if ("19.2.
|
|
23585
|
+
if ("19.2.7" !== isomorphicReactPackageVersion$jscomp$inline_1840)
|
|
23357
23586
|
throw Error(
|
|
23358
23587
|
formatProdErrorMessage(
|
|
23359
23588
|
527,
|
|
23360
23589
|
isomorphicReactPackageVersion$jscomp$inline_1840,
|
|
23361
|
-
"19.2.
|
|
23590
|
+
"19.2.7"
|
|
23362
23591
|
)
|
|
23363
23592
|
);
|
|
23364
23593
|
ReactDOMSharedInternals.findDOMNode = function(componentOrElement) {
|
|
@@ -23376,10 +23605,10 @@ function requireReactDomClient_production() {
|
|
|
23376
23605
|
};
|
|
23377
23606
|
var internals$jscomp$inline_2347 = {
|
|
23378
23607
|
bundleType: 0,
|
|
23379
|
-
version: "19.2.
|
|
23608
|
+
version: "19.2.7",
|
|
23380
23609
|
rendererPackageName: "react-dom",
|
|
23381
23610
|
currentDispatcherRef: ReactSharedInternals,
|
|
23382
|
-
reconcilerVersion: "19.2.
|
|
23611
|
+
reconcilerVersion: "19.2.7"
|
|
23383
23612
|
};
|
|
23384
23613
|
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
|
23385
23614
|
var hook$jscomp$inline_2348 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
@@ -23446,7 +23675,7 @@ function requireReactDomClient_production() {
|
|
|
23446
23675
|
listenToAllSupportedEvents(container);
|
|
23447
23676
|
return new ReactDOMHydrationRoot(initialChildren);
|
|
23448
23677
|
};
|
|
23449
|
-
reactDomClient_production.version = "19.2.
|
|
23678
|
+
reactDomClient_production.version = "19.2.7";
|
|
23450
23679
|
return reactDomClient_production;
|
|
23451
23680
|
}
|
|
23452
23681
|
var hasRequiredClient;
|
|
@@ -26116,10 +26345,10 @@ function buildInspectorModule() {
|
|
|
26116
26345
|
`);
|
|
26117
26346
|
}
|
|
26118
26347
|
function writeInspectorModule(serverDir2) {
|
|
26119
|
-
if (!
|
|
26120
|
-
|
|
26121
|
-
const target =
|
|
26122
|
-
|
|
26348
|
+
if (!existsSync23(serverDir2))
|
|
26349
|
+
mkdirSync10(serverDir2, { recursive: true });
|
|
26350
|
+
const target = join18(serverDir2, INSPECTOR_FILE_NAME);
|
|
26351
|
+
writeFileSync8(target, buildInspectorModule(), "utf-8");
|
|
26123
26352
|
return target;
|
|
26124
26353
|
}
|
|
26125
26354
|
|
|
@@ -26298,11 +26527,11 @@ function buildHostScript(options) {
|
|
|
26298
26527
|
`);
|
|
26299
26528
|
}
|
|
26300
26529
|
function writeHostScript(serverDir2, options) {
|
|
26301
|
-
if (!
|
|
26302
|
-
|
|
26303
|
-
const target =
|
|
26304
|
-
|
|
26305
|
-
|
|
26530
|
+
if (!existsSync24(serverDir2))
|
|
26531
|
+
mkdirSync11(serverDir2, { recursive: true });
|
|
26532
|
+
const target = join19(serverDir2, HOST_FILE_NAME);
|
|
26533
|
+
mkdirSync11(dirname6(target), { recursive: true });
|
|
26534
|
+
writeFileSync9(target, buildHostScript(options), "utf-8");
|
|
26306
26535
|
if (options.inspector) {
|
|
26307
26536
|
writeInspectorModule(serverDir2);
|
|
26308
26537
|
}
|
|
@@ -26314,12 +26543,50 @@ var ENTRY_CANDIDATES = ["src/worker.ts", "src/server.ts", "src/index.ts"];
|
|
|
26314
26543
|
async function prepareDev(opts) {
|
|
26315
26544
|
const cwd = opts.cwd;
|
|
26316
26545
|
ensureGitignore(cwd);
|
|
26317
|
-
|
|
26546
|
+
let dest = serverDir(cwd);
|
|
26318
26547
|
const env = envFile(cwd);
|
|
26319
26548
|
const backups = backupsDir(cwd);
|
|
26320
26549
|
const cached2 = readState(cwd);
|
|
26321
26550
|
let projectId = cached2?.projectId;
|
|
26322
|
-
|
|
26551
|
+
let serverName = cached2?.serverName;
|
|
26552
|
+
let gitNative = false;
|
|
26553
|
+
let repoDir;
|
|
26554
|
+
const gitLink = opts.offline ? null : await resolveServerGitLink({
|
|
26555
|
+
serverId: opts.serverId,
|
|
26556
|
+
organizationId: opts.organizationId
|
|
26557
|
+
}).catch(() => null);
|
|
26558
|
+
if (gitLink) {
|
|
26559
|
+
gitNative = true;
|
|
26560
|
+
projectId = projectId ?? gitLink.projectId;
|
|
26561
|
+
serverName = `${gitLink.owner}/${gitLink.name}`;
|
|
26562
|
+
repoDir = gitCloneDir(cwd, gitLink.owner, gitLink.name);
|
|
26563
|
+
dest = gitLink.pathPrefix ? join20(repoDir, gitLink.pathPrefix) : repoDir;
|
|
26564
|
+
printStep(`Git-linked server — cloning ${gitLink.owner}/${gitLink.name}@${gitLink.branch}…`);
|
|
26565
|
+
try {
|
|
26566
|
+
const result = ensureClone({
|
|
26567
|
+
repoDir,
|
|
26568
|
+
httpsCloneUrl: gitLink.httpsCloneUrl,
|
|
26569
|
+
branch: gitLink.branch,
|
|
26570
|
+
onStep: (m2) => printStep(m2)
|
|
26571
|
+
});
|
|
26572
|
+
printSuccess(result.cloned ? `Cloned to ${relative6(cwd, repoDir)}` : `Using existing clone at ${relative6(cwd, repoDir)}`);
|
|
26573
|
+
} catch (err) {
|
|
26574
|
+
if (err instanceof GitNotAvailableError) {
|
|
26575
|
+
printError(err.message);
|
|
26576
|
+
} else if (err instanceof GitCloneError) {
|
|
26577
|
+
printError(err.message);
|
|
26578
|
+
} else {
|
|
26579
|
+
printError(`Git clone failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
26580
|
+
}
|
|
26581
|
+
process.exit(1);
|
|
26582
|
+
}
|
|
26583
|
+
if (!existsSync25(env)) {
|
|
26584
|
+
writeFileSync10(env, `{}
|
|
26585
|
+
`, "utf-8");
|
|
26586
|
+
printInfo(` → seeded ${relative6(cwd, env)} (empty; fill secrets here)`);
|
|
26587
|
+
}
|
|
26588
|
+
printInfo(` ${"Open the clone in your editor; commit + push to sync (config under mcpcloud/ is read-only)."}`);
|
|
26589
|
+
} else if (!opts.offline) {
|
|
26323
26590
|
if (!projectId) {
|
|
26324
26591
|
printStep(`Looking up server ${opts.serverId}…`);
|
|
26325
26592
|
const lookup = await resolveServerProject({
|
|
@@ -26327,6 +26594,7 @@ async function prepareDev(opts) {
|
|
|
26327
26594
|
organizationId: opts.organizationId
|
|
26328
26595
|
});
|
|
26329
26596
|
projectId = lookup.projectId;
|
|
26597
|
+
serverName = lookup.serverName;
|
|
26330
26598
|
printInfo(` → ${lookup.serverName} (project ${projectId})`);
|
|
26331
26599
|
}
|
|
26332
26600
|
printStep("Fetching bundle…");
|
|
@@ -26337,8 +26605,8 @@ async function prepareDev(opts) {
|
|
|
26337
26605
|
});
|
|
26338
26606
|
const result = materializeBundle(dest, bundle, { prune: true });
|
|
26339
26607
|
printInfo(` → wrote ${result.filesWritten} files (pruned ${result.filesRemoved})`);
|
|
26340
|
-
if (!
|
|
26341
|
-
|
|
26608
|
+
if (!existsSync25(env)) {
|
|
26609
|
+
writeFileSync10(env, `{}
|
|
26342
26610
|
`, "utf-8");
|
|
26343
26611
|
printInfo(` → seeded ${relative6(cwd, env)} (empty; fill secrets here)`);
|
|
26344
26612
|
}
|
|
@@ -26355,7 +26623,7 @@ async function prepareDev(opts) {
|
|
|
26355
26623
|
});
|
|
26356
26624
|
printInfo(` → wrote ${toolsResult.filesWritten} editable tool file${toolsResult.filesWritten === 1 ? "" : "s"}${toolsResult.filesRemoved > 0 ? ` (pruned ${toolsResult.filesRemoved})` : ""}`);
|
|
26357
26625
|
} else {
|
|
26358
|
-
if (!
|
|
26626
|
+
if (!existsSync25(dest)) {
|
|
26359
26627
|
printError("No cached bundle found. Run once without --offline first.");
|
|
26360
26628
|
process.exit(1);
|
|
26361
26629
|
}
|
|
@@ -26364,7 +26632,7 @@ async function prepareDev(opts) {
|
|
|
26364
26632
|
process.exit(1);
|
|
26365
26633
|
}
|
|
26366
26634
|
}
|
|
26367
|
-
const entryRel = ENTRY_CANDIDATES.find((c2) =>
|
|
26635
|
+
const entryRel = ENTRY_CANDIDATES.find((c2) => existsSync25(join20(dest, c2)));
|
|
26368
26636
|
if (!entryRel) {
|
|
26369
26637
|
printError("Could not locate an entry file (expected src/worker.ts).");
|
|
26370
26638
|
process.exit(1);
|
|
@@ -26385,7 +26653,8 @@ async function prepareDev(opts) {
|
|
|
26385
26653
|
bundleVersion: 0,
|
|
26386
26654
|
lastSyncedAt: Date.now(),
|
|
26387
26655
|
transports: opts.transports,
|
|
26388
|
-
port: opts.port
|
|
26656
|
+
port: opts.port,
|
|
26657
|
+
...serverName !== undefined ? { serverName } : {}
|
|
26389
26658
|
};
|
|
26390
26659
|
writeState(cwd, state);
|
|
26391
26660
|
const storePath = inspectorDir(cwd);
|
|
@@ -26403,7 +26672,9 @@ async function prepareDev(opts) {
|
|
|
26403
26672
|
destDir: dest,
|
|
26404
26673
|
envPath: env,
|
|
26405
26674
|
backupsPath: backups,
|
|
26406
|
-
state
|
|
26675
|
+
state,
|
|
26676
|
+
gitNative,
|
|
26677
|
+
...repoDir !== undefined ? { repoDir } : {}
|
|
26407
26678
|
};
|
|
26408
26679
|
}
|
|
26409
26680
|
|
|
@@ -26519,73 +26790,73 @@ function createBurstGuard() {
|
|
|
26519
26790
|
}
|
|
26520
26791
|
|
|
26521
26792
|
// src/lib/dev/agent-connectors/claude-code.ts
|
|
26522
|
-
import { existsSync as
|
|
26793
|
+
import { existsSync as existsSync27, unlinkSync as unlinkSync2, writeFileSync as writeFileSync12 } from "node:fs";
|
|
26523
26794
|
import { homedir as homedir4 } from "node:os";
|
|
26524
|
-
import { join as
|
|
26795
|
+
import { join as join22 } from "node:path";
|
|
26525
26796
|
|
|
26526
26797
|
// src/lib/dev/agent-connectors/json-config-utils.ts
|
|
26527
|
-
import { existsSync as
|
|
26528
|
-
import { dirname as
|
|
26798
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
|
|
26799
|
+
import { dirname as dirname7, join as join21, basename } from "node:path";
|
|
26529
26800
|
function readJsonFile(path) {
|
|
26530
|
-
if (!
|
|
26801
|
+
if (!existsSync26(path))
|
|
26531
26802
|
return { ok: true, value: {} };
|
|
26532
26803
|
try {
|
|
26533
|
-
const raw =
|
|
26804
|
+
const raw = readFileSync15(path, "utf-8");
|
|
26534
26805
|
if (!raw.trim())
|
|
26535
26806
|
return { ok: true, value: {} };
|
|
26536
26807
|
return { ok: true, value: JSON.parse(raw) };
|
|
26537
26808
|
} catch {
|
|
26538
26809
|
try {
|
|
26539
|
-
return { ok: false, raw:
|
|
26810
|
+
return { ok: false, raw: readFileSync15(path, "utf-8") };
|
|
26540
26811
|
} catch {
|
|
26541
26812
|
return { ok: false };
|
|
26542
26813
|
}
|
|
26543
26814
|
}
|
|
26544
26815
|
}
|
|
26545
26816
|
function atomicWriteJson(path, value) {
|
|
26546
|
-
|
|
26817
|
+
mkdirSync12(dirname7(path), { recursive: true });
|
|
26547
26818
|
const tmp = `${path}.mcpsh-${process.pid}-${Date.now()}.tmp`;
|
|
26548
|
-
|
|
26819
|
+
writeFileSync11(tmp, JSON.stringify(value, null, 2) + `
|
|
26549
26820
|
`, "utf-8");
|
|
26550
26821
|
const { renameSync: renameSync2 } = __require("node:fs");
|
|
26551
26822
|
renameSync2(tmp, path);
|
|
26552
26823
|
}
|
|
26553
26824
|
function backupConfig(args) {
|
|
26554
|
-
if (!
|
|
26825
|
+
if (!existsSync26(args.configPath)) {
|
|
26555
26826
|
return { backupPath: null, existed: false };
|
|
26556
26827
|
}
|
|
26557
|
-
|
|
26828
|
+
mkdirSync12(args.backupsDir, { recursive: true });
|
|
26558
26829
|
const filename = `${args.agentId}__${basename(args.configPath)}.bak`;
|
|
26559
|
-
const backupPath =
|
|
26560
|
-
if (!
|
|
26561
|
-
const raw =
|
|
26562
|
-
|
|
26830
|
+
const backupPath = join21(args.backupsDir, filename);
|
|
26831
|
+
if (!existsSync26(backupPath)) {
|
|
26832
|
+
const raw = readFileSync15(args.configPath, "utf-8");
|
|
26833
|
+
writeFileSync11(backupPath, raw, "utf-8");
|
|
26563
26834
|
}
|
|
26564
26835
|
return { backupPath, existed: true };
|
|
26565
26836
|
}
|
|
26566
26837
|
function restoreFromBackup(args) {
|
|
26567
26838
|
const filename = `${args.agentId}__${basename(args.configPath)}.bak`;
|
|
26568
|
-
const backupPath =
|
|
26569
|
-
if (!
|
|
26839
|
+
const backupPath = join21(args.backupsDir, filename);
|
|
26840
|
+
if (!existsSync26(backupPath)) {
|
|
26570
26841
|
return { restored: false };
|
|
26571
26842
|
}
|
|
26572
|
-
const raw =
|
|
26573
|
-
|
|
26574
|
-
|
|
26843
|
+
const raw = readFileSync15(backupPath, "utf-8");
|
|
26844
|
+
mkdirSync12(dirname7(args.configPath), { recursive: true });
|
|
26845
|
+
writeFileSync11(args.configPath, raw, "utf-8");
|
|
26575
26846
|
return { restored: true };
|
|
26576
26847
|
}
|
|
26577
26848
|
|
|
26578
26849
|
// src/lib/dev/agent-connectors/claude-code.ts
|
|
26579
26850
|
function configPath() {
|
|
26580
|
-
return
|
|
26851
|
+
return join22(homedir4(), ".claude.json");
|
|
26581
26852
|
}
|
|
26582
26853
|
function legacyConfigPath() {
|
|
26583
|
-
return
|
|
26854
|
+
return join22(homedir4(), ".claude", "mcp.json");
|
|
26584
26855
|
}
|
|
26585
26856
|
function resolveConfigPath() {
|
|
26586
|
-
if (
|
|
26857
|
+
if (existsSync27(configPath()))
|
|
26587
26858
|
return configPath();
|
|
26588
|
-
if (
|
|
26859
|
+
if (existsSync27(legacyConfigPath()))
|
|
26589
26860
|
return legacyConfigPath();
|
|
26590
26861
|
return configPath();
|
|
26591
26862
|
}
|
|
@@ -26595,8 +26866,8 @@ var claudeCodeConnector = {
|
|
|
26595
26866
|
hotkey: "c",
|
|
26596
26867
|
describeLocation: () => resolveConfigPath(),
|
|
26597
26868
|
async detect() {
|
|
26598
|
-
const claudeDir =
|
|
26599
|
-
if (
|
|
26869
|
+
const claudeDir = join22(homedir4(), ".claude");
|
|
26870
|
+
if (existsSync27(configPath()) || existsSync27(legacyConfigPath()) || existsSync27(claudeDir)) {
|
|
26600
26871
|
return { installed: true, note: "Found Claude Code config" };
|
|
26601
26872
|
}
|
|
26602
26873
|
return { installed: false };
|
|
@@ -26634,7 +26905,7 @@ var claudeCodeConnector = {
|
|
|
26634
26905
|
backupsDir: args.backupsDir,
|
|
26635
26906
|
agentId: this.id
|
|
26636
26907
|
});
|
|
26637
|
-
if (!restored.restored &&
|
|
26908
|
+
if (!restored.restored && existsSync27(path)) {
|
|
26638
26909
|
const after = readJsonFile(path);
|
|
26639
26910
|
if (after.ok && after.value && typeof after.value === "object") {
|
|
26640
26911
|
const root = after.value;
|
|
@@ -26644,7 +26915,7 @@ var claudeCodeConnector = {
|
|
|
26644
26915
|
try {
|
|
26645
26916
|
unlinkSync2(path);
|
|
26646
26917
|
} catch {
|
|
26647
|
-
|
|
26918
|
+
writeFileSync12(path, `{}
|
|
26648
26919
|
`, "utf-8");
|
|
26649
26920
|
}
|
|
26650
26921
|
}
|
|
@@ -26656,16 +26927,16 @@ var claudeCodeConnector = {
|
|
|
26656
26927
|
|
|
26657
26928
|
// src/lib/dev/agent-connectors/codex.ts
|
|
26658
26929
|
import {
|
|
26659
|
-
existsSync as
|
|
26660
|
-
mkdirSync as
|
|
26661
|
-
readFileSync as
|
|
26930
|
+
existsSync as existsSync28,
|
|
26931
|
+
mkdirSync as mkdirSync13,
|
|
26932
|
+
readFileSync as readFileSync16,
|
|
26662
26933
|
unlinkSync as unlinkSync3,
|
|
26663
|
-
writeFileSync as
|
|
26934
|
+
writeFileSync as writeFileSync13
|
|
26664
26935
|
} from "node:fs";
|
|
26665
26936
|
import { homedir as homedir5 } from "node:os";
|
|
26666
|
-
import { dirname as
|
|
26937
|
+
import { dirname as dirname8, join as join23 } from "node:path";
|
|
26667
26938
|
function configPath2() {
|
|
26668
|
-
return
|
|
26939
|
+
return join23(homedir5(), ".codex", "config.toml");
|
|
26669
26940
|
}
|
|
26670
26941
|
var SECTION_PREFIX = "mcp_servers.";
|
|
26671
26942
|
function buildSection(name, url) {
|
|
@@ -26703,7 +26974,7 @@ var codexConnector = {
|
|
|
26703
26974
|
hotkey: "x",
|
|
26704
26975
|
describeLocation: () => configPath2(),
|
|
26705
26976
|
async detect() {
|
|
26706
|
-
if (
|
|
26977
|
+
if (existsSync28(join23(homedir5(), ".codex")) || existsSync28(configPath2())) {
|
|
26707
26978
|
return { installed: true, note: "Found ~/.codex/" };
|
|
26708
26979
|
}
|
|
26709
26980
|
return { installed: false };
|
|
@@ -26716,8 +26987,8 @@ var codexConnector = {
|
|
|
26716
26987
|
agentId: this.id
|
|
26717
26988
|
});
|
|
26718
26989
|
let existing = "";
|
|
26719
|
-
if (
|
|
26720
|
-
existing =
|
|
26990
|
+
if (existsSync28(path)) {
|
|
26991
|
+
existing = readFileSync16(path, "utf-8");
|
|
26721
26992
|
}
|
|
26722
26993
|
const conflict = findSectionRange(existing, args.name) !== null;
|
|
26723
26994
|
let next = existing;
|
|
@@ -26732,18 +27003,18 @@ var codexConnector = {
|
|
|
26732
27003
|
next += `
|
|
26733
27004
|
`;
|
|
26734
27005
|
next += buildSection(args.name, args.url);
|
|
26735
|
-
|
|
26736
|
-
|
|
27006
|
+
mkdirSync13(dirname8(path), { recursive: true });
|
|
27007
|
+
writeFileSync13(path, next, "utf-8");
|
|
26737
27008
|
return { added: !conflict, conflict };
|
|
26738
27009
|
},
|
|
26739
27010
|
async remove(args) {
|
|
26740
27011
|
const path = configPath2();
|
|
26741
|
-
if (
|
|
26742
|
-
const existing =
|
|
27012
|
+
if (existsSync28(path)) {
|
|
27013
|
+
const existing = readFileSync16(path, "utf-8");
|
|
26743
27014
|
const range = findSectionRange(existing, args.name);
|
|
26744
27015
|
if (range) {
|
|
26745
27016
|
const next = existing.slice(0, range.start) + existing.slice(range.end);
|
|
26746
|
-
|
|
27017
|
+
writeFileSync13(path, next, "utf-8");
|
|
26747
27018
|
}
|
|
26748
27019
|
}
|
|
26749
27020
|
const restored = restoreFromBackup({
|
|
@@ -26751,8 +27022,8 @@ var codexConnector = {
|
|
|
26751
27022
|
backupsDir: args.backupsDir,
|
|
26752
27023
|
agentId: this.id
|
|
26753
27024
|
});
|
|
26754
|
-
if (!restored.restored &&
|
|
26755
|
-
const after =
|
|
27025
|
+
if (!restored.restored && existsSync28(path)) {
|
|
27026
|
+
const after = readFileSync16(path, "utf-8");
|
|
26756
27027
|
if (!after.trim()) {
|
|
26757
27028
|
try {
|
|
26758
27029
|
unlinkSync3(path);
|
|
@@ -26764,11 +27035,11 @@ var codexConnector = {
|
|
|
26764
27035
|
};
|
|
26765
27036
|
|
|
26766
27037
|
// src/lib/dev/agent-connectors/continue.ts
|
|
26767
|
-
import { existsSync as
|
|
27038
|
+
import { existsSync as existsSync29, unlinkSync as unlinkSync4, writeFileSync as writeFileSync14 } from "node:fs";
|
|
26768
27039
|
import { homedir as homedir6 } from "node:os";
|
|
26769
|
-
import { join as
|
|
27040
|
+
import { join as join24 } from "node:path";
|
|
26770
27041
|
function configPath3() {
|
|
26771
|
-
return
|
|
27042
|
+
return join24(homedir6(), ".continue", "config.json");
|
|
26772
27043
|
}
|
|
26773
27044
|
function isContinueServerEntry(value) {
|
|
26774
27045
|
return Boolean(value && typeof value === "object" && typeof value.name === "string");
|
|
@@ -26779,8 +27050,8 @@ var continueConnector = {
|
|
|
26779
27050
|
hotkey: "n",
|
|
26780
27051
|
describeLocation: () => configPath3(),
|
|
26781
27052
|
async detect() {
|
|
26782
|
-
const dir =
|
|
26783
|
-
if (
|
|
27053
|
+
const dir = join24(homedir6(), ".continue");
|
|
27054
|
+
if (existsSync29(dir) || existsSync29(configPath3())) {
|
|
26784
27055
|
return { installed: true, note: "Found ~/.continue/" };
|
|
26785
27056
|
}
|
|
26786
27057
|
return { installed: false };
|
|
@@ -26818,7 +27089,7 @@ var continueConnector = {
|
|
|
26818
27089
|
backupsDir: args.backupsDir,
|
|
26819
27090
|
agentId: this.id
|
|
26820
27091
|
});
|
|
26821
|
-
if (!restored.restored &&
|
|
27092
|
+
if (!restored.restored && existsSync29(path)) {
|
|
26822
27093
|
const after = readJsonFile(path);
|
|
26823
27094
|
if (after.ok && after.value && typeof after.value === "object") {
|
|
26824
27095
|
const root = after.value;
|
|
@@ -26828,7 +27099,7 @@ var continueConnector = {
|
|
|
26828
27099
|
try {
|
|
26829
27100
|
unlinkSync4(path);
|
|
26830
27101
|
} catch {
|
|
26831
|
-
|
|
27102
|
+
writeFileSync14(path, `{}
|
|
26832
27103
|
`, "utf-8");
|
|
26833
27104
|
}
|
|
26834
27105
|
}
|
|
@@ -26839,11 +27110,11 @@ var continueConnector = {
|
|
|
26839
27110
|
};
|
|
26840
27111
|
|
|
26841
27112
|
// src/lib/dev/agent-connectors/cursor.ts
|
|
26842
|
-
import { existsSync as
|
|
27113
|
+
import { existsSync as existsSync30, unlinkSync as unlinkSync5, writeFileSync as writeFileSync15 } from "node:fs";
|
|
26843
27114
|
import { homedir as homedir7 } from "node:os";
|
|
26844
|
-
import { join as
|
|
27115
|
+
import { join as join25 } from "node:path";
|
|
26845
27116
|
function globalConfigPath() {
|
|
26846
|
-
return
|
|
27117
|
+
return join25(homedir7(), ".cursor", "mcp.json");
|
|
26847
27118
|
}
|
|
26848
27119
|
var cursorConnector = {
|
|
26849
27120
|
id: "cursor",
|
|
@@ -26851,9 +27122,9 @@ var cursorConnector = {
|
|
|
26851
27122
|
hotkey: "u",
|
|
26852
27123
|
describeLocation: () => globalConfigPath(),
|
|
26853
27124
|
async detect() {
|
|
26854
|
-
const cursorDir =
|
|
26855
|
-
const macAppSupport =
|
|
26856
|
-
if (
|
|
27125
|
+
const cursorDir = join25(homedir7(), ".cursor");
|
|
27126
|
+
const macAppSupport = join25(homedir7(), "Library", "Application Support", "Cursor");
|
|
27127
|
+
if (existsSync30(cursorDir) || existsSync30(macAppSupport)) {
|
|
26857
27128
|
return { installed: true, note: "Found Cursor config dir" };
|
|
26858
27129
|
}
|
|
26859
27130
|
return { installed: false };
|
|
@@ -26891,7 +27162,7 @@ var cursorConnector = {
|
|
|
26891
27162
|
backupsDir: args.backupsDir,
|
|
26892
27163
|
agentId: this.id
|
|
26893
27164
|
});
|
|
26894
|
-
if (!restored.restored &&
|
|
27165
|
+
if (!restored.restored && existsSync30(path)) {
|
|
26895
27166
|
const after = readJsonFile(path);
|
|
26896
27167
|
if (after.ok && after.value && typeof after.value === "object") {
|
|
26897
27168
|
const root = after.value;
|
|
@@ -26901,7 +27172,7 @@ var cursorConnector = {
|
|
|
26901
27172
|
try {
|
|
26902
27173
|
unlinkSync5(path);
|
|
26903
27174
|
} catch {
|
|
26904
|
-
|
|
27175
|
+
writeFileSync15(path, `{}
|
|
26905
27176
|
`, "utf-8");
|
|
26906
27177
|
}
|
|
26907
27178
|
}
|
|
@@ -26912,30 +27183,30 @@ var cursorConnector = {
|
|
|
26912
27183
|
};
|
|
26913
27184
|
|
|
26914
27185
|
// src/lib/dev/agent-connectors/vscode-copilot.ts
|
|
26915
|
-
import { existsSync as
|
|
27186
|
+
import { existsSync as existsSync31, unlinkSync as unlinkSync6, writeFileSync as writeFileSync16 } from "node:fs";
|
|
26916
27187
|
import { homedir as homedir8, platform as platform4 } from "node:os";
|
|
26917
|
-
import { join as
|
|
27188
|
+
import { join as join26, resolve as resolve5 } from "node:path";
|
|
26918
27189
|
function userLevelConfigPath() {
|
|
26919
27190
|
const home = homedir8();
|
|
26920
27191
|
const p2 = platform4();
|
|
26921
27192
|
if (p2 === "darwin")
|
|
26922
|
-
return
|
|
27193
|
+
return join26(home, "Library", "Application Support", "Code", "User", "mcp.json");
|
|
26923
27194
|
if (p2 === "win32") {
|
|
26924
|
-
const appData = process.env["APPDATA"] ??
|
|
26925
|
-
return
|
|
27195
|
+
const appData = process.env["APPDATA"] ?? join26(home, "AppData", "Roaming");
|
|
27196
|
+
return join26(appData, "Code", "User", "mcp.json");
|
|
26926
27197
|
}
|
|
26927
|
-
const xdg = process.env["XDG_CONFIG_HOME"] ??
|
|
26928
|
-
return
|
|
27198
|
+
const xdg = process.env["XDG_CONFIG_HOME"] ?? join26(home, ".config");
|
|
27199
|
+
return join26(xdg, "Code", "User", "mcp.json");
|
|
26929
27200
|
}
|
|
26930
27201
|
function isHomeDir(cwd) {
|
|
26931
27202
|
return resolve5(cwd) === resolve5(homedir8());
|
|
26932
27203
|
}
|
|
26933
27204
|
function hasWorkspaceVscode(cwd) {
|
|
26934
|
-
return
|
|
27205
|
+
return existsSync31(join26(cwd, ".vscode"));
|
|
26935
27206
|
}
|
|
26936
27207
|
function configPath4(cwd) {
|
|
26937
27208
|
if (!isHomeDir(cwd) && hasWorkspaceVscode(cwd)) {
|
|
26938
|
-
return
|
|
27209
|
+
return join26(cwd, ".vscode", "mcp.json");
|
|
26939
27210
|
}
|
|
26940
27211
|
return userLevelConfigPath();
|
|
26941
27212
|
}
|
|
@@ -26949,7 +27220,7 @@ var vscodeCopilotConnector = {
|
|
|
26949
27220
|
if (!isHomeDir(here) && hasWorkspaceVscode(here)) {
|
|
26950
27221
|
return { installed: true, note: "Found .vscode/ in current dir" };
|
|
26951
27222
|
}
|
|
26952
|
-
if (
|
|
27223
|
+
if (existsSync31(userLevelConfigPath().replace(/mcp\.json$/, ""))) {
|
|
26953
27224
|
return { installed: true, note: "Found VS Code user profile" };
|
|
26954
27225
|
}
|
|
26955
27226
|
return { installed: false };
|
|
@@ -26987,7 +27258,7 @@ var vscodeCopilotConnector = {
|
|
|
26987
27258
|
backupsDir: args.backupsDir,
|
|
26988
27259
|
agentId: this.id
|
|
26989
27260
|
});
|
|
26990
|
-
if (!restored.restored &&
|
|
27261
|
+
if (!restored.restored && existsSync31(path)) {
|
|
26991
27262
|
const after = readJsonFile(path);
|
|
26992
27263
|
if (after.ok && after.value && typeof after.value === "object") {
|
|
26993
27264
|
const root = after.value;
|
|
@@ -26997,7 +27268,7 @@ var vscodeCopilotConnector = {
|
|
|
26997
27268
|
try {
|
|
26998
27269
|
unlinkSync6(path);
|
|
26999
27270
|
} catch {
|
|
27000
|
-
|
|
27271
|
+
writeFileSync16(path, `{}
|
|
27001
27272
|
`, "utf-8");
|
|
27002
27273
|
}
|
|
27003
27274
|
}
|
|
@@ -27149,6 +27420,16 @@ function buildConnectionName(serverId) {
|
|
|
27149
27420
|
}
|
|
27150
27421
|
function registerDevCommand(program2) {
|
|
27151
27422
|
const dev = program2.command("dev").description("Run a deployed MCP server locally with hot reload + agent auto-wire").option("--server <serverId>", "Server ID (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));
|
|
27423
|
+
dev.addHelpText("after", `
|
|
27424
|
+
Git-native mode (automatic):
|
|
27425
|
+
If the chosen server is linked to a GitHub repo, mcp dev clones it under
|
|
27426
|
+
.mcpcloud/git/ and runs against the working copy — no flag needed. Edit in
|
|
27427
|
+
your own editor, then commit + push: the webhook reconciles src/** back into
|
|
27428
|
+
MCPCloud. The CLI's tool/handler PATCH watchers are off in this mode (native
|
|
27429
|
+
git is the version control). Config under mcpcloud/ is a read-only mirror —
|
|
27430
|
+
change it in the dashboard. Deploy when ready with \`mcp deploy\` or the UI.
|
|
27431
|
+
An unlinked server uses the default flow (download bundle, edit via dashboard).
|
|
27432
|
+
`);
|
|
27152
27433
|
dev.command("list").description("List running mcp dev sessions on this machine").action(runAction(runDevList));
|
|
27153
27434
|
dev.command("kill <pid>").description('Stop a running mcp dev session by PID (or "all" to stop every session)').action(runAction(runDevKill));
|
|
27154
27435
|
dev.command("init").description("Interactively pick an organization + server and write .mcpcloud/state.json (forces the picker even if state already exists)").action(runAction(runDevInit));
|
|
@@ -27178,7 +27459,8 @@ async function runDevInit() {
|
|
|
27178
27459
|
bundleVersion: 0,
|
|
27179
27460
|
lastSyncedAt: 0,
|
|
27180
27461
|
transports: ["http", "sse"],
|
|
27181
|
-
port: 8787
|
|
27462
|
+
port: 8787,
|
|
27463
|
+
serverName: result.target.serverName
|
|
27182
27464
|
});
|
|
27183
27465
|
printSuccess(`Saved .mcpcloud/state.json — run ${c.bold("mcp dev")} to start.`);
|
|
27184
27466
|
}
|
|
@@ -27234,6 +27516,21 @@ async function runDev(opts) {
|
|
|
27234
27516
|
const cached2 = readState(cwd);
|
|
27235
27517
|
let serverId = opts.server ?? cached2?.serverId;
|
|
27236
27518
|
let organizationId = opts.org ?? cached2?.organizationId ?? undefined;
|
|
27519
|
+
if (!opts.server && cached2?.serverId && canRunInteractive()) {
|
|
27520
|
+
const choice = await promptResumeOrSwitch({
|
|
27521
|
+
serverId: cached2.serverId,
|
|
27522
|
+
...cached2.serverName !== undefined ? { serverName: cached2.serverName } : {}
|
|
27523
|
+
});
|
|
27524
|
+
if (choice === "cancel")
|
|
27525
|
+
process.exit(1);
|
|
27526
|
+
if (choice === "switch") {
|
|
27527
|
+
const result = await runInteractiveBootstrap();
|
|
27528
|
+
if (result.kind !== "resolved")
|
|
27529
|
+
process.exit(1);
|
|
27530
|
+
serverId = result.target.serverId;
|
|
27531
|
+
organizationId = result.target.organizationId;
|
|
27532
|
+
}
|
|
27533
|
+
}
|
|
27237
27534
|
if (!serverId) {
|
|
27238
27535
|
if (!canRunInteractive()) {
|
|
27239
27536
|
printError("No server selected. Pass --server <serverId>, run `mcp dev init` to pick one interactively, or run from a directory with .mcpcloud/state.json.");
|
|
@@ -27274,7 +27571,7 @@ async function runDev(opts) {
|
|
|
27274
27571
|
let specPath = null;
|
|
27275
27572
|
if (opts.spec) {
|
|
27276
27573
|
const resolved = resolveSpecPath(cwd, opts.spec);
|
|
27277
|
-
if (!
|
|
27574
|
+
if (!existsSync32(resolved)) {
|
|
27278
27575
|
printError(`Spec file not found: ${resolved}`);
|
|
27279
27576
|
process.exit(1);
|
|
27280
27577
|
}
|
|
@@ -27303,7 +27600,8 @@ async function runDev(opts) {
|
|
|
27303
27600
|
enrichOnChange,
|
|
27304
27601
|
openChoice,
|
|
27305
27602
|
openTargetOverride,
|
|
27306
|
-
editorOverride
|
|
27603
|
+
editorOverride,
|
|
27604
|
+
gitNative: prepared.gitNative
|
|
27307
27605
|
});
|
|
27308
27606
|
}
|
|
27309
27607
|
async function emitStaleHandlerOverrideWarning(args) {
|
|
@@ -27338,6 +27636,21 @@ async function runWithRuntime(args) {
|
|
|
27338
27636
|
}
|
|
27339
27637
|
});
|
|
27340
27638
|
runtime = launch();
|
|
27639
|
+
let fullShutdownReady = false;
|
|
27640
|
+
const killRuntimeNow = () => {
|
|
27641
|
+
try {
|
|
27642
|
+
runtime?.child.kill("SIGKILL");
|
|
27643
|
+
} catch {}
|
|
27644
|
+
};
|
|
27645
|
+
process.once("exit", killRuntimeNow);
|
|
27646
|
+
const earlySignal = (signal) => {
|
|
27647
|
+
if (fullShutdownReady)
|
|
27648
|
+
return;
|
|
27649
|
+
killRuntimeNow();
|
|
27650
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
27651
|
+
};
|
|
27652
|
+
process.on("SIGINT", () => earlySignal("SIGINT"));
|
|
27653
|
+
process.on("SIGTERM", () => earlySignal("SIGTERM"));
|
|
27341
27654
|
const baseUrl = `http://127.0.0.1:${args.port}`;
|
|
27342
27655
|
const mcpUrl = `${baseUrl}/mcp`;
|
|
27343
27656
|
const connectionName = buildConnectionName(args.serverId);
|
|
@@ -27354,7 +27667,14 @@ async function runWithRuntime(args) {
|
|
|
27354
27667
|
});
|
|
27355
27668
|
wired.push(...selected);
|
|
27356
27669
|
}
|
|
27357
|
-
if (args.transports[0] !== "stdio") {
|
|
27670
|
+
if (args.transports[0] !== "stdio" && args.gitNative) {
|
|
27671
|
+
await maybeOpenEditor({
|
|
27672
|
+
dir: args.prepared.repoDir ?? args.prepared.destDir,
|
|
27673
|
+
target: "bundle",
|
|
27674
|
+
override: args.openChoice,
|
|
27675
|
+
editorOverride: args.editorOverride
|
|
27676
|
+
});
|
|
27677
|
+
} else if (args.transports[0] !== "stdio") {
|
|
27358
27678
|
const savedTarget = readConfig().editorOpenTarget;
|
|
27359
27679
|
let target = resolveOpenTarget({
|
|
27360
27680
|
override: args.openTargetOverride,
|
|
@@ -27405,11 +27725,16 @@ async function runWithRuntime(args) {
|
|
|
27405
27725
|
const watcher = args.watch ? watchDir({
|
|
27406
27726
|
rootDir: args.prepared.destDir,
|
|
27407
27727
|
debounceMs: 250,
|
|
27408
|
-
ignore: [
|
|
27728
|
+
ignore: [
|
|
27729
|
+
"node_modules",
|
|
27730
|
+
"_mcpsh_host.mjs",
|
|
27731
|
+
"_mcpsh_inspector.mjs",
|
|
27732
|
+
".git"
|
|
27733
|
+
],
|
|
27409
27734
|
onChange: async (path) => {
|
|
27410
27735
|
if (shuttingDown)
|
|
27411
27736
|
return;
|
|
27412
|
-
if (shouldWarnAboutBundleEdit({
|
|
27737
|
+
if (!args.gitNative && shouldWarnAboutBundleEdit({
|
|
27413
27738
|
changedPath: path,
|
|
27414
27739
|
alreadyWarned: bundleEditWarned,
|
|
27415
27740
|
suppressed: suppressBundleWarn,
|
|
@@ -27427,14 +27752,14 @@ async function runWithRuntime(args) {
|
|
|
27427
27752
|
runtime = launch();
|
|
27428
27753
|
}
|
|
27429
27754
|
}) : null;
|
|
27430
|
-
const toolsWatcher = args.watch ? startToolsWatcher({
|
|
27755
|
+
const toolsWatcher = args.watch && !args.gitNative ? startToolsWatcher({
|
|
27431
27756
|
cwd: args.cwd,
|
|
27432
27757
|
serverId: args.serverId,
|
|
27433
27758
|
organizationId: args.organizationId,
|
|
27434
27759
|
projectId: args.prepared.state.projectId,
|
|
27435
27760
|
devBaseUrl: args.inspector ? baseUrl : undefined
|
|
27436
27761
|
}) : null;
|
|
27437
|
-
const handlersWatcher = args.watch ? startHandlersWatcher({
|
|
27762
|
+
const handlersWatcher = args.watch && !args.gitNative ? startHandlersWatcher({
|
|
27438
27763
|
cwd: args.cwd,
|
|
27439
27764
|
serverId: args.serverId,
|
|
27440
27765
|
organizationId: args.organizationId,
|
|
@@ -27443,7 +27768,7 @@ async function runWithRuntime(args) {
|
|
|
27443
27768
|
let specWatcher = null;
|
|
27444
27769
|
let pendingApply = null;
|
|
27445
27770
|
let regenInFlight = false;
|
|
27446
|
-
if (args.specPath) {
|
|
27771
|
+
if (args.specPath && !args.gitNative) {
|
|
27447
27772
|
const initial = readSpecFile(args.specPath);
|
|
27448
27773
|
let lastAppliedHash = initial.hash;
|
|
27449
27774
|
specWatcher = watchSpecFile({
|
|
@@ -27524,20 +27849,60 @@ async function runWithRuntime(args) {
|
|
|
27524
27849
|
printInfo(` ${c.dim("Inspector: ")} ${c.cyan(`${baseUrl}/__inspect`)}`);
|
|
27525
27850
|
}
|
|
27526
27851
|
printInfo(` ${c.dim(`Edit files in ${relative7(args.cwd, args.prepared.destDir)}/ to hot-reload.`)}`);
|
|
27852
|
+
if (args.gitNative && args.prepared.repoDir) {
|
|
27853
|
+
printInfo(` ${c.dim(`Git-native: edit + commit + push in ${relative7(args.cwd, args.prepared.repoDir)}/ — the webhook reconciles src/**.`)}`);
|
|
27854
|
+
printInfo(` ${c.dim("Config under mcpcloud/ is read-only; change it in the dashboard. Deploy when ready (mcp deploy).")}`);
|
|
27855
|
+
}
|
|
27527
27856
|
if (toolsWatcher) {
|
|
27528
27857
|
printInfo(` ${c.dim(`Edit tool metadata in .mcpcloud/tools/${args.serverId}/ (changes push to cloud on save).`)}`);
|
|
27529
27858
|
}
|
|
27530
27859
|
if (handlersWatcher) {
|
|
27531
27860
|
printInfo(` ${c.dim(`Edit tool handlers in .mcpcloud/server/src/tools/<slug>.ts (changes push to cloud on save).`)}`);
|
|
27532
27861
|
}
|
|
27533
|
-
if (
|
|
27862
|
+
if (specWatcher) {
|
|
27534
27863
|
printInfo(` ${c.dim(`Spec watch: ${relative7(args.cwd, args.specPath)}`)}`);
|
|
27535
27864
|
}
|
|
27536
|
-
|
|
27537
|
-
|
|
27538
|
-
|
|
27539
|
-
|
|
27540
|
-
|
|
27865
|
+
const gitPullPoller = args.gitNative ? startGitPullPoll({
|
|
27866
|
+
fetchStatus: () => resolveServerGitPullStatus({
|
|
27867
|
+
serverId: args.serverId,
|
|
27868
|
+
organizationId: args.organizationId
|
|
27869
|
+
}),
|
|
27870
|
+
onChange: (status) => {
|
|
27871
|
+
if (shuttingDown)
|
|
27872
|
+
return;
|
|
27873
|
+
const sha = status.lastPulledGitSha ? status.lastPulledGitSha.slice(0, 7) : "HEAD";
|
|
27874
|
+
if (status.rejectedFileCount > 0) {
|
|
27875
|
+
printWarn(`Push ${sha}: MCPCloud rejected ${status.rejectedFileCount} file${status.rejectedFileCount === 1 ? "" : "s"} (unsafe handler code).`);
|
|
27876
|
+
if (status.error)
|
|
27877
|
+
printInfo(` ${c.dim(status.error)}`);
|
|
27878
|
+
printInfo(` ${c.dim("Fix the flagged file(s) and push again.")}`);
|
|
27879
|
+
return;
|
|
27880
|
+
}
|
|
27881
|
+
if (status.status === "error") {
|
|
27882
|
+
printWarn(`Push ${sha}: MCPCloud could not reconcile — ${status.error ?? "unknown error"}.`);
|
|
27883
|
+
return;
|
|
27884
|
+
}
|
|
27885
|
+
if (status.status !== "pulled") {
|
|
27886
|
+
printInfo(`Push ${sha}: ${status.hadConfigDrift ? "touched the read-only mcpcloud/ config — ignored." : "touched only generated files outside src/** — nothing synced."}`);
|
|
27887
|
+
printInfo(` ${c.dim("Only src/ round-trips; edit there to sync. README / mcpcloud/ are generated.")}`);
|
|
27888
|
+
return;
|
|
27889
|
+
}
|
|
27890
|
+
const parts = [`${status.pulledFileCount} updated`];
|
|
27891
|
+
if (status.deletedFileCount > 0) {
|
|
27892
|
+
parts.push(`${status.deletedFileCount} deleted`);
|
|
27893
|
+
}
|
|
27894
|
+
printSuccess(`Push ${sha} reconciled (${parts.join(", ")}) — changes ready for deployment.`);
|
|
27895
|
+
printInfo(` ${c.dim("Deploy with")} ${c.bold("mcp deploy")} ${c.dim("or the dashboard — no preview needed, this session is your local server.")}`);
|
|
27896
|
+
},
|
|
27897
|
+
onError: () => {}
|
|
27898
|
+
}) : null;
|
|
27899
|
+
if (!args.gitNative) {
|
|
27900
|
+
await emitStaleHandlerOverrideWarning({
|
|
27901
|
+
organizationId: args.organizationId,
|
|
27902
|
+
projectId: args.prepared.state.projectId,
|
|
27903
|
+
serverId: args.serverId
|
|
27904
|
+
});
|
|
27905
|
+
}
|
|
27541
27906
|
printInfo(` ${c.dim("Ctrl+C to stop.")}`);
|
|
27542
27907
|
if (isJsonMode()) {
|
|
27543
27908
|
printJson({
|
|
@@ -27576,6 +27941,9 @@ async function runWithRuntime(args) {
|
|
|
27576
27941
|
try {
|
|
27577
27942
|
specWatcher?.close();
|
|
27578
27943
|
} catch {}
|
|
27944
|
+
try {
|
|
27945
|
+
gitPullPoller?.close();
|
|
27946
|
+
} catch {}
|
|
27579
27947
|
if (pendingApply) {
|
|
27580
27948
|
clearTimeout(pendingApply);
|
|
27581
27949
|
pendingApply = null;
|
|
@@ -27595,6 +27963,7 @@ async function runWithRuntime(args) {
|
|
|
27595
27963
|
printSuccess("Bye.");
|
|
27596
27964
|
process.exit(0);
|
|
27597
27965
|
};
|
|
27966
|
+
fullShutdownReady = true;
|
|
27598
27967
|
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
27599
27968
|
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
27600
27969
|
shortcuts = startShortcuts({
|
|
@@ -28018,13 +28387,13 @@ async function confirmRollback(deploymentId) {
|
|
|
28018
28387
|
}
|
|
28019
28388
|
|
|
28020
28389
|
// src/commands/doctor.ts
|
|
28021
|
-
import { existsSync as
|
|
28390
|
+
import { existsSync as existsSync34, statSync as statSync6, readFileSync as readFileSync18 } from "node:fs";
|
|
28022
28391
|
import { homedir as homedir9, platform as platform6 } from "node:os";
|
|
28023
|
-
import { join as
|
|
28392
|
+
import { join as join28, delimiter as delimiter3 } from "node:path";
|
|
28024
28393
|
|
|
28025
28394
|
// src/lib/version-check.ts
|
|
28026
|
-
import { existsSync as
|
|
28027
|
-
import { join as
|
|
28395
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync14, readFileSync as readFileSync17, writeFileSync as writeFileSync17 } from "node:fs";
|
|
28396
|
+
import { join as join27 } from "node:path";
|
|
28028
28397
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
28029
28398
|
var FETCH_TIMEOUT_MS2 = 2000;
|
|
28030
28399
|
var REGISTRY_URL = "https://registry.npmjs.org/@mcpcloud/cli/latest";
|
|
@@ -28032,13 +28401,13 @@ function cacheDir() {
|
|
|
28032
28401
|
return configDir();
|
|
28033
28402
|
}
|
|
28034
28403
|
function cacheFile() {
|
|
28035
|
-
return
|
|
28404
|
+
return join27(cacheDir(), "version-check.json");
|
|
28036
28405
|
}
|
|
28037
28406
|
function readCache() {
|
|
28038
|
-
if (!
|
|
28407
|
+
if (!existsSync33(cacheFile()))
|
|
28039
28408
|
return null;
|
|
28040
28409
|
try {
|
|
28041
|
-
const raw = JSON.parse(
|
|
28410
|
+
const raw = JSON.parse(readFileSync17(cacheFile(), "utf-8"));
|
|
28042
28411
|
if (typeof raw.latest !== "string" || typeof raw.fetchedAt !== "number")
|
|
28043
28412
|
return null;
|
|
28044
28413
|
return { latest: raw.latest, fetchedAt: raw.fetchedAt };
|
|
@@ -28048,9 +28417,9 @@ function readCache() {
|
|
|
28048
28417
|
}
|
|
28049
28418
|
function writeCache(entry) {
|
|
28050
28419
|
try {
|
|
28051
|
-
if (!
|
|
28052
|
-
|
|
28053
|
-
|
|
28420
|
+
if (!existsSync33(cacheDir()))
|
|
28421
|
+
mkdirSync14(cacheDir(), { recursive: true, mode: 448 });
|
|
28422
|
+
writeFileSync17(cacheFile(), JSON.stringify(entry, null, 2), { mode: 384 });
|
|
28054
28423
|
} catch {}
|
|
28055
28424
|
}
|
|
28056
28425
|
function compareVersions(a, b) {
|
|
@@ -28161,8 +28530,8 @@ function checkNode() {
|
|
|
28161
28530
|
}
|
|
28162
28531
|
function checkConfigFile() {
|
|
28163
28532
|
const t0 = Date.now();
|
|
28164
|
-
const path =
|
|
28165
|
-
if (!
|
|
28533
|
+
const path = join28(homedir9(), ".mcpcloud", "config.json");
|
|
28534
|
+
if (!existsSync34(path)) {
|
|
28166
28535
|
return {
|
|
28167
28536
|
name: "Config file",
|
|
28168
28537
|
status: "warn",
|
|
@@ -28184,7 +28553,7 @@ function checkConfigFile() {
|
|
|
28184
28553
|
} catch {}
|
|
28185
28554
|
}
|
|
28186
28555
|
try {
|
|
28187
|
-
JSON.parse(
|
|
28556
|
+
JSON.parse(readFileSync18(path, "utf-8"));
|
|
28188
28557
|
} catch (err) {
|
|
28189
28558
|
return {
|
|
28190
28559
|
name: "Config file",
|
|
@@ -28319,8 +28688,8 @@ function checkClaudeCli() {
|
|
|
28319
28688
|
for (const dir of PATH.split(delimiter3)) {
|
|
28320
28689
|
if (!dir)
|
|
28321
28690
|
continue;
|
|
28322
|
-
const candidate =
|
|
28323
|
-
if (
|
|
28691
|
+
const candidate = join28(dir, exe);
|
|
28692
|
+
if (existsSync34(candidate)) {
|
|
28324
28693
|
return {
|
|
28325
28694
|
name: "claude CLI",
|
|
28326
28695
|
status: "pass",
|
|
@@ -29261,38 +29630,38 @@ function registerOAuthCommands(program2) {
|
|
|
29261
29630
|
// src/lib/plugins.ts
|
|
29262
29631
|
import { spawn as spawn7 } from "node:child_process";
|
|
29263
29632
|
import {
|
|
29264
|
-
existsSync as
|
|
29265
|
-
mkdirSync as
|
|
29633
|
+
existsSync as existsSync35,
|
|
29634
|
+
mkdirSync as mkdirSync15,
|
|
29266
29635
|
readdirSync as readdirSync4,
|
|
29267
|
-
readFileSync as
|
|
29636
|
+
readFileSync as readFileSync19,
|
|
29268
29637
|
rmSync as rmSync3,
|
|
29269
29638
|
statSync as statSync7
|
|
29270
29639
|
} from "node:fs";
|
|
29271
|
-
import { join as
|
|
29640
|
+
import { join as join29 } from "node:path";
|
|
29272
29641
|
import { pathToFileURL } from "node:url";
|
|
29273
29642
|
function pluginsDir() {
|
|
29274
|
-
return
|
|
29643
|
+
return join29(configDir(), "plugins");
|
|
29275
29644
|
}
|
|
29276
29645
|
function ensureDir2() {
|
|
29277
29646
|
const dir = pluginsDir();
|
|
29278
|
-
if (!
|
|
29279
|
-
|
|
29647
|
+
if (!existsSync35(dir))
|
|
29648
|
+
mkdirSync15(dir, { recursive: true, mode: 448 });
|
|
29280
29649
|
}
|
|
29281
29650
|
function readManifestFromPackageDir(packageDir) {
|
|
29282
|
-
const pkgPath =
|
|
29283
|
-
if (!
|
|
29651
|
+
const pkgPath = join29(packageDir, "package.json");
|
|
29652
|
+
if (!existsSync35(pkgPath))
|
|
29284
29653
|
return null;
|
|
29285
29654
|
let pkg;
|
|
29286
29655
|
try {
|
|
29287
|
-
pkg = JSON.parse(
|
|
29656
|
+
pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
29288
29657
|
} catch {
|
|
29289
29658
|
return null;
|
|
29290
29659
|
}
|
|
29291
29660
|
if (!pkg.name)
|
|
29292
29661
|
return null;
|
|
29293
29662
|
const relEntry = pkg.mcpsh?.register ?? pkg.main ?? "index.js";
|
|
29294
|
-
const entry =
|
|
29295
|
-
if (!
|
|
29663
|
+
const entry = join29(packageDir, relEntry);
|
|
29664
|
+
if (!existsSync35(entry))
|
|
29296
29665
|
return null;
|
|
29297
29666
|
return {
|
|
29298
29667
|
name: pkg.name,
|
|
@@ -29303,11 +29672,11 @@ function readManifestFromPackageDir(packageDir) {
|
|
|
29303
29672
|
}
|
|
29304
29673
|
function listInstalledPlugins() {
|
|
29305
29674
|
const dir = pluginsDir();
|
|
29306
|
-
if (!
|
|
29675
|
+
if (!existsSync35(dir))
|
|
29307
29676
|
return [];
|
|
29308
29677
|
const out = [];
|
|
29309
29678
|
for (const entry of readdirSync4(dir)) {
|
|
29310
|
-
const full =
|
|
29679
|
+
const full = join29(dir, entry);
|
|
29311
29680
|
let s;
|
|
29312
29681
|
try {
|
|
29313
29682
|
s = statSync7(full);
|
|
@@ -29318,7 +29687,7 @@ function listInstalledPlugins() {
|
|
|
29318
29687
|
continue;
|
|
29319
29688
|
if (entry.startsWith("@")) {
|
|
29320
29689
|
for (const child of readdirSync4(full)) {
|
|
29321
|
-
const m2 = readManifestFromPackageDir(
|
|
29690
|
+
const m2 = readManifestFromPackageDir(join29(full, child));
|
|
29322
29691
|
if (m2)
|
|
29323
29692
|
out.push(m2);
|
|
29324
29693
|
}
|
|
@@ -29351,26 +29720,43 @@ async function loadPlugins(program2) {
|
|
|
29351
29720
|
}
|
|
29352
29721
|
}
|
|
29353
29722
|
}
|
|
29354
|
-
|
|
29723
|
+
var PACKAGE_SPEC_PATTERN = /^(@[a-z0-9~-][\w.~-]*\/)?[a-z0-9~-][\w.~-]*(@[-\w.^~><=*+|]+)?$/i;
|
|
29724
|
+
function runNpm(args, cwd) {
|
|
29355
29725
|
return new Promise((resolve7) => {
|
|
29356
|
-
const
|
|
29726
|
+
const isWindows = process.platform === "win32";
|
|
29727
|
+
const child = spawn7(isWindows ? "npm.cmd" : "npm", args, {
|
|
29728
|
+
shell: isWindows,
|
|
29729
|
+
cwd,
|
|
29730
|
+
stdio: "inherit"
|
|
29731
|
+
});
|
|
29357
29732
|
child.on("close", (code) => resolve7(code ?? 1));
|
|
29358
29733
|
child.on("error", () => resolve7(1));
|
|
29359
29734
|
});
|
|
29360
29735
|
}
|
|
29361
29736
|
async function installPlugin(packageSpec) {
|
|
29737
|
+
if (!PACKAGE_SPEC_PATTERN.test(packageSpec)) {
|
|
29738
|
+
throw new Error(`"${packageSpec}" is not a plain name@version npm package spec. URL, git, and path specs are not supported for plugins.`);
|
|
29739
|
+
}
|
|
29362
29740
|
ensureDir2();
|
|
29363
29741
|
const dir = pluginsDir();
|
|
29364
|
-
const code = await
|
|
29742
|
+
const code = await runNpm([
|
|
29743
|
+
"install",
|
|
29744
|
+
"--prefix",
|
|
29745
|
+
dir,
|
|
29746
|
+
"--no-save",
|
|
29747
|
+
"--silent",
|
|
29748
|
+
"--ignore-scripts",
|
|
29749
|
+
packageSpec
|
|
29750
|
+
], dir);
|
|
29365
29751
|
if (code !== 0) {
|
|
29366
29752
|
throw new Error(`npm install ${packageSpec} exited with code ${code}.`);
|
|
29367
29753
|
}
|
|
29368
|
-
const nm =
|
|
29369
|
-
if (!
|
|
29754
|
+
const nm = join29(dir, "node_modules");
|
|
29755
|
+
if (!existsSync35(nm)) {
|
|
29370
29756
|
throw new Error(`npm install ran but produced no node_modules under ${dir}.`);
|
|
29371
29757
|
}
|
|
29372
29758
|
const baseName = packageSpec.replace(/@[^@/]+$/, "");
|
|
29373
|
-
const candidatePath = baseName.startsWith("@") ?
|
|
29759
|
+
const candidatePath = baseName.startsWith("@") ? join29(nm, baseName.split("/")[0], baseName.split("/")[1] ?? "") : join29(nm, baseName);
|
|
29374
29760
|
const manifest = readManifestFromPackageDir(candidatePath);
|
|
29375
29761
|
if (!manifest) {
|
|
29376
29762
|
throw new Error(`Installed but could not read plugin manifest at ${candidatePath}.`);
|
|
@@ -29378,26 +29764,26 @@ async function installPlugin(packageSpec) {
|
|
|
29378
29764
|
return { name: manifest.name, entry: manifest.entry };
|
|
29379
29765
|
}
|
|
29380
29766
|
function removePlugin(name) {
|
|
29381
|
-
const nm =
|
|
29382
|
-
if (!
|
|
29767
|
+
const nm = join29(pluginsDir(), "node_modules");
|
|
29768
|
+
if (!existsSync35(nm))
|
|
29383
29769
|
return false;
|
|
29384
|
-
const target = name.startsWith("@") ?
|
|
29385
|
-
if (!
|
|
29770
|
+
const target = name.startsWith("@") ? join29(nm, name.split("/")[0], name.split("/")[1] ?? "") : join29(nm, name);
|
|
29771
|
+
if (!existsSync35(target))
|
|
29386
29772
|
return false;
|
|
29387
29773
|
rmSync3(target, { recursive: true, force: true });
|
|
29388
29774
|
return true;
|
|
29389
29775
|
}
|
|
29390
29776
|
function listInstalledPluginsCombined() {
|
|
29391
29777
|
const direct = listInstalledPlugins();
|
|
29392
|
-
const nm =
|
|
29393
|
-
if (!
|
|
29778
|
+
const nm = join29(pluginsDir(), "node_modules");
|
|
29779
|
+
if (!existsSync35(nm))
|
|
29394
29780
|
return direct;
|
|
29395
29781
|
const seen = new Set(direct.map((p2) => p2.name));
|
|
29396
29782
|
const out = [...direct];
|
|
29397
29783
|
for (const entry of readdirSync4(nm)) {
|
|
29398
29784
|
if (entry === ".bin" || entry === ".package-lock.json")
|
|
29399
29785
|
continue;
|
|
29400
|
-
const full =
|
|
29786
|
+
const full = join29(nm, entry);
|
|
29401
29787
|
let s;
|
|
29402
29788
|
try {
|
|
29403
29789
|
s = statSync7(full);
|
|
@@ -29408,7 +29794,7 @@ function listInstalledPluginsCombined() {
|
|
|
29408
29794
|
continue;
|
|
29409
29795
|
if (entry.startsWith("@")) {
|
|
29410
29796
|
for (const child of readdirSync4(full)) {
|
|
29411
|
-
const m2 = readManifestFromPackageDir(
|
|
29797
|
+
const m2 = readManifestFromPackageDir(join29(full, child));
|
|
29412
29798
|
if (m2 && !seen.has(m2.name)) {
|
|
29413
29799
|
seen.add(m2.name);
|
|
29414
29800
|
out.push(m2);
|
|
@@ -30994,12 +31380,12 @@ function displayValueFor(field, value) {
|
|
|
30994
31380
|
|
|
30995
31381
|
// src/lib/tui/state-store.ts
|
|
30996
31382
|
import {
|
|
30997
|
-
existsSync as
|
|
30998
|
-
mkdirSync as
|
|
30999
|
-
readFileSync as
|
|
31000
|
-
writeFileSync as
|
|
31383
|
+
existsSync as existsSync36,
|
|
31384
|
+
mkdirSync as mkdirSync16,
|
|
31385
|
+
readFileSync as readFileSync20,
|
|
31386
|
+
writeFileSync as writeFileSync18
|
|
31001
31387
|
} from "node:fs";
|
|
31002
|
-
import { join as
|
|
31388
|
+
import { join as join30 } from "node:path";
|
|
31003
31389
|
var ALL_TABS = [
|
|
31004
31390
|
"servers",
|
|
31005
31391
|
"projects",
|
|
@@ -31009,7 +31395,7 @@ var ALL_TABS = [
|
|
|
31009
31395
|
"devSessions"
|
|
31010
31396
|
];
|
|
31011
31397
|
function tuiStateFile() {
|
|
31012
|
-
return
|
|
31398
|
+
return join30(configDir(), "tui-state.json");
|
|
31013
31399
|
}
|
|
31014
31400
|
function isTab(v2) {
|
|
31015
31401
|
return typeof v2 === "string" && ALL_TABS.includes(v2);
|
|
@@ -31074,11 +31460,11 @@ function sanitizeTuiState(input) {
|
|
|
31074
31460
|
}
|
|
31075
31461
|
function readTuiState() {
|
|
31076
31462
|
const path = tuiStateFile();
|
|
31077
|
-
if (!
|
|
31463
|
+
if (!existsSync36(path))
|
|
31078
31464
|
return {};
|
|
31079
31465
|
let parsed;
|
|
31080
31466
|
try {
|
|
31081
|
-
parsed = JSON.parse(
|
|
31467
|
+
parsed = JSON.parse(readFileSync20(path, "utf-8"));
|
|
31082
31468
|
} catch {
|
|
31083
31469
|
return {};
|
|
31084
31470
|
}
|
|
@@ -31086,10 +31472,10 @@ function readTuiState() {
|
|
|
31086
31472
|
}
|
|
31087
31473
|
function writeTuiState(state) {
|
|
31088
31474
|
try {
|
|
31089
|
-
if (!
|
|
31090
|
-
|
|
31475
|
+
if (!existsSync36(configDir())) {
|
|
31476
|
+
mkdirSync16(configDir(), { recursive: true, mode: 448 });
|
|
31091
31477
|
}
|
|
31092
|
-
|
|
31478
|
+
writeFileSync18(tuiStateFile(), JSON.stringify(state, null, 2), {
|
|
31093
31479
|
encoding: "utf-8",
|
|
31094
31480
|
mode: 384
|
|
31095
31481
|
});
|
|
@@ -33713,7 +34099,7 @@ function registerUiCommand(program2) {
|
|
|
33713
34099
|
|
|
33714
34100
|
// src/commands/update.ts
|
|
33715
34101
|
import { spawn as spawn9 } from "node:child_process";
|
|
33716
|
-
import { dirname as
|
|
34102
|
+
import { dirname as dirname9 } from "node:path";
|
|
33717
34103
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
33718
34104
|
function detectInstallContext() {
|
|
33719
34105
|
const override = process.env["MCPSH_PACKAGE_MANAGER"]?.trim().toLowerCase();
|
|
@@ -33726,7 +34112,7 @@ function detectInstallContext() {
|
|
|
33726
34112
|
}
|
|
33727
34113
|
const here = (() => {
|
|
33728
34114
|
try {
|
|
33729
|
-
return
|
|
34115
|
+
return dirname9(fileURLToPath2(import.meta.url));
|
|
33730
34116
|
} catch {
|
|
33731
34117
|
return process.argv[1] ?? "";
|
|
33732
34118
|
}
|
|
@@ -33773,7 +34159,7 @@ function buildCommand(manager) {
|
|
|
33773
34159
|
return "npm install -g @mcpcloud/cli@latest";
|
|
33774
34160
|
}
|
|
33775
34161
|
}
|
|
33776
|
-
function
|
|
34162
|
+
function runShell(command) {
|
|
33777
34163
|
return new Promise((resolve7) => {
|
|
33778
34164
|
const child = spawn9(command, { shell: true, stdio: "inherit" });
|
|
33779
34165
|
child.on("close", (code) => resolve7(code ?? 1));
|
|
@@ -33821,7 +34207,7 @@ function registerUpdateCommand(program2) {
|
|
|
33821
34207
|
const ctx = detectInstallContext();
|
|
33822
34208
|
printStep(`Running: ${c.cyan(ctx.command)}`);
|
|
33823
34209
|
printInfo(c.dim(` (${ctx.rationale}; override with MCPSH_PACKAGE_MANAGER)`));
|
|
33824
|
-
const code = await
|
|
34210
|
+
const code = await runShell(ctx.command);
|
|
33825
34211
|
if (code !== 0) {
|
|
33826
34212
|
if (isJsonMode())
|
|
33827
34213
|
printJson({
|