@cloudbase/cloudbase-mcp 2.25.4 → 2.25.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +2 -2
- package/dist/index.cjs +320 -38
- package/dist/index.js +320 -38
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -138355,7 +138355,7 @@ class TelemetryReporter {
|
|
|
138355
138355
|
const nodeVersion = process.version; // Node.js版本
|
|
138356
138356
|
const arch = os_1.default.arch(); // 系统架构
|
|
138357
138357
|
// 从构建时注入的版本号获取MCP版本信息
|
|
138358
|
-
const mcpVersion = process.env.npm_package_version || "2.25.
|
|
138358
|
+
const mcpVersion = process.env.npm_package_version || "2.25.5" || 0;
|
|
138359
138359
|
return {
|
|
138360
138360
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
138361
138361
|
deviceId: this.deviceId,
|
|
@@ -162268,6 +162268,14 @@ function collectMigrationVersions(value, found = new Set()) {
|
|
|
162268
162268
|
/** Brief retries before concluding a pushed migration never landed (Push can be async). */
|
|
162269
162269
|
const MIGRATION_VERIFY_ATTEMPTS = 4;
|
|
162270
162270
|
const MIGRATION_VERIFY_DELAY_MS = 1500;
|
|
162271
|
+
/** Page size when hydrating remote migration history into a Push/Preview payload. */
|
|
162272
|
+
const MIGRATION_LIST_PAGE_SIZE = 100;
|
|
162273
|
+
/**
|
|
162274
|
+
* PushPGUserMigrations is async: poll DescribeTaskResult until Succeed/Failed.
|
|
162275
|
+
* Aligns with CLI `tcb db pg migration up` and Manager SDK docs.
|
|
162276
|
+
*/
|
|
162277
|
+
const MIGRATION_TASK_POLL_INTERVAL_MS = 1500;
|
|
162278
|
+
const MIGRATION_TASK_MAX_WAIT_MS = 90_000;
|
|
162271
162279
|
/**
|
|
162272
162280
|
* Confirm a pushed migration version is present in the remote migration history.
|
|
162273
162281
|
*
|
|
@@ -162301,6 +162309,99 @@ async function verifyMigrationApplied(context, version, cloudBaseOptions) {
|
|
|
162301
162309
|
}
|
|
162302
162310
|
return { applied: null, error: lastError };
|
|
162303
162311
|
}
|
|
162312
|
+
function extractMigrationSummaries(history) {
|
|
162313
|
+
const raw = history.Migrations;
|
|
162314
|
+
if (!Array.isArray(raw)) {
|
|
162315
|
+
return [];
|
|
162316
|
+
}
|
|
162317
|
+
const summaries = [];
|
|
162318
|
+
for (const item of raw) {
|
|
162319
|
+
if (!item || typeof item !== "object") {
|
|
162320
|
+
continue;
|
|
162321
|
+
}
|
|
162322
|
+
const row = item;
|
|
162323
|
+
const version = typeof row.Version === "string" ? row.Version.trim() : "";
|
|
162324
|
+
const name = typeof row.Name === "string" ? row.Name.trim() : "";
|
|
162325
|
+
if (version) {
|
|
162326
|
+
summaries.push({ Version: version, Name: name || version });
|
|
162327
|
+
}
|
|
162328
|
+
}
|
|
162329
|
+
return summaries;
|
|
162330
|
+
}
|
|
162331
|
+
/**
|
|
162332
|
+
* List every remote migration summary (paginated). Required before Push/Preview:
|
|
162333
|
+
* submitting only the pending migration while remote history exists yields
|
|
162334
|
+
* Executable=false with Conflicts reason remote_history_not_found_locally, and the
|
|
162335
|
+
* async task fails with "migration plan is not executable".
|
|
162336
|
+
*/
|
|
162337
|
+
async function listAllRemoteMigrationSummaries(context, cloudBaseOptions) {
|
|
162338
|
+
const summaries = [];
|
|
162339
|
+
let offset = 0;
|
|
162340
|
+
let latestVersion = "";
|
|
162341
|
+
let total = 0;
|
|
162342
|
+
while (true) {
|
|
162343
|
+
const page = await callPgMigrationApi(context, "ListPGUserMigrations", { Limit: MIGRATION_LIST_PAGE_SIZE, Offset: offset }, cloudBaseOptions);
|
|
162344
|
+
const pageItems = extractMigrationSummaries(page);
|
|
162345
|
+
summaries.push(...pageItems);
|
|
162346
|
+
if (typeof page.LatestVersion === "string" && page.LatestVersion.trim()) {
|
|
162347
|
+
latestVersion = page.LatestVersion.trim();
|
|
162348
|
+
}
|
|
162349
|
+
if (typeof page.Total === "number" && Number.isFinite(page.Total)) {
|
|
162350
|
+
total = page.Total;
|
|
162351
|
+
}
|
|
162352
|
+
else {
|
|
162353
|
+
total = summaries.length;
|
|
162354
|
+
}
|
|
162355
|
+
if (pageItems.length < MIGRATION_LIST_PAGE_SIZE) {
|
|
162356
|
+
break;
|
|
162357
|
+
}
|
|
162358
|
+
offset += MIGRATION_LIST_PAGE_SIZE;
|
|
162359
|
+
}
|
|
162360
|
+
return { summaries, latestVersion, total };
|
|
162361
|
+
}
|
|
162362
|
+
/**
|
|
162363
|
+
* Build Push/Preview Migrations = remote history Queries + the pending migration.
|
|
162364
|
+
* Matches CLI behavior (submit full set; server skips already-applied versions).
|
|
162365
|
+
*/
|
|
162366
|
+
async function buildMigrationsPayloadWithRemoteHistory(context, pending, cloudBaseOptions) {
|
|
162367
|
+
const { summaries, latestVersion } = await listAllRemoteMigrationSummaries(context, cloudBaseOptions);
|
|
162368
|
+
const migrations = [];
|
|
162369
|
+
for (const summary of summaries) {
|
|
162370
|
+
if (summary.Version === pending.Version) {
|
|
162371
|
+
// Caller supplies the authoritative SQL for this version.
|
|
162372
|
+
continue;
|
|
162373
|
+
}
|
|
162374
|
+
const detail = await callPgMigrationApi(context, "DescribePGUserMigration", { MigrationVersion: summary.Version }, cloudBaseOptions);
|
|
162375
|
+
const query = typeof detail.Query === "string" ? detail.Query : "";
|
|
162376
|
+
if (!query.trim()) {
|
|
162377
|
+
throw new Error(`DescribePGUserMigration returned empty Query for version=${summary.Version} (${summary.Name}). ` +
|
|
162378
|
+
"Cannot hydrate remote history for PushPGUserMigrations.");
|
|
162379
|
+
}
|
|
162380
|
+
migrations.push({
|
|
162381
|
+
Version: typeof detail.Version === "string" && detail.Version.trim() ? detail.Version.trim() : summary.Version,
|
|
162382
|
+
Name: typeof detail.Name === "string" && detail.Name.trim() ? detail.Name.trim() : summary.Name,
|
|
162383
|
+
Query: query,
|
|
162384
|
+
});
|
|
162385
|
+
}
|
|
162386
|
+
migrations.push(pending);
|
|
162387
|
+
return { migrations, remoteCount: summaries.length, latestVersion };
|
|
162388
|
+
}
|
|
162389
|
+
async function waitPgMigrationTask(context, taskId, cloudBaseOptions) {
|
|
162390
|
+
const deadline = Date.now() + MIGRATION_TASK_MAX_WAIT_MS;
|
|
162391
|
+
let last = { TaskId: taskId };
|
|
162392
|
+
while (Date.now() <= deadline) {
|
|
162393
|
+
last = (await callPgMigrationApi(context, "DescribeTaskResult", { TaskId: taskId }, cloudBaseOptions));
|
|
162394
|
+
const status = String(last.Status || "").toLowerCase();
|
|
162395
|
+
if (status === "succeed" || status === "failed") {
|
|
162396
|
+
return last;
|
|
162397
|
+
}
|
|
162398
|
+
await sleep(MIGRATION_TASK_POLL_INTERVAL_MS);
|
|
162399
|
+
}
|
|
162400
|
+
const error = new Error(`DescribeTaskResult timed out after ${Math.floor(MIGRATION_TASK_MAX_WAIT_MS / 1000)}s ` +
|
|
162401
|
+
`for TaskId=${taskId} (last Status=${last.Status || "-"}, Phase=${last.Phase || "-"}).`);
|
|
162402
|
+
error.lastTask = last;
|
|
162403
|
+
throw error;
|
|
162404
|
+
}
|
|
162304
162405
|
const MIGRATION_VERSION_REQUIRED_MESSAGE = "migrationVersion is required (14-digit UTC timestamp YYYYMMDDHHMMSS). " +
|
|
162305
162406
|
"Decide the version first, write local file migrations/<version>_<migrationName>.sql, " +
|
|
162306
162407
|
"then call planMigration/applyMigration with the same migrationVersion and migrationName.";
|
|
@@ -163087,29 +163188,38 @@ async function handlePlanMigration(args, context, deps, cloudBaseOptions) {
|
|
|
163087
163188
|
}
|
|
163088
163189
|
const version = versionOrError;
|
|
163089
163190
|
const localFileHint = buildLocalMigrationFileHint(version, args.migrationName);
|
|
163090
|
-
const
|
|
163191
|
+
const pending = {
|
|
163091
163192
|
Version: version,
|
|
163092
163193
|
Name: args.migrationName,
|
|
163093
163194
|
Query: args.sql,
|
|
163094
163195
|
};
|
|
163095
163196
|
if (args.rollbackSql?.trim()) {
|
|
163096
|
-
|
|
163197
|
+
pending.Rollback = args.rollbackSql;
|
|
163097
163198
|
}
|
|
163098
163199
|
try {
|
|
163200
|
+
const hydrated = await buildMigrationsPayloadWithRemoteHistory(context, pending, cloudBaseOptions);
|
|
163099
163201
|
const result = await callPgMigrationApi(context, "PreviewPGUserMigrations", {
|
|
163100
|
-
Migrations:
|
|
163202
|
+
Migrations: hydrated.migrations,
|
|
163101
163203
|
}, cloudBaseOptions);
|
|
163204
|
+
const executable = result.Executable === true;
|
|
163102
163205
|
return buildPgToolResult({
|
|
163103
163206
|
success: true,
|
|
163104
163207
|
data: {
|
|
163105
163208
|
migrationVersion: version,
|
|
163106
163209
|
migrationName: args.migrationName,
|
|
163107
163210
|
localFileHint,
|
|
163211
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163212
|
+
latestRemoteVersion: hydrated.latestVersion || null,
|
|
163213
|
+
executable,
|
|
163108
163214
|
apiResult: result,
|
|
163109
163215
|
},
|
|
163110
|
-
message:
|
|
163216
|
+
message: executable
|
|
163217
|
+
? `Migration plan generated via PreviewPGUserMigrations (hydrated ${hydrated.remoteCount} remote migration(s)). Reuse migrationVersion=${version} on applyMigration. Ensure local file ${localFileHint} exists and matches.`
|
|
163218
|
+
: `Migration plan is NOT executable (PreviewPGUserMigrations.Executable=false after hydrating ${hydrated.remoteCount} remote migration(s)). Inspect apiResult.Conflicts before applyMigration. Common causes: version older than latest remote (${hydrated.latestVersion || "unknown"}), or checksum mismatch.`,
|
|
163111
163219
|
nextActions: [
|
|
163112
|
-
buildNextAction(MANAGE_PG_DATABASE, "applyMigration",
|
|
163220
|
+
buildNextAction(MANAGE_PG_DATABASE, "applyMigration", executable
|
|
163221
|
+
? "Review the plan above. If it looks correct, call applyMigration with the same migrationVersion."
|
|
163222
|
+
: "Resolve Conflicts (often pick a migrationVersion newer than LatestVersion), then retry planMigration/applyMigration.", {
|
|
163113
163223
|
action: "applyMigration",
|
|
163114
163224
|
migrationName: args.migrationName,
|
|
163115
163225
|
migrationVersion: version,
|
|
@@ -163156,26 +163266,118 @@ async function handleApplyMigration(args, context, deps, cloudBaseOptions) {
|
|
|
163156
163266
|
}
|
|
163157
163267
|
const version = versionOrError;
|
|
163158
163268
|
const localFileHint = buildLocalMigrationFileHint(version, args.migrationName);
|
|
163159
|
-
const
|
|
163269
|
+
const pending = {
|
|
163160
163270
|
Version: version,
|
|
163161
163271
|
Name: args.migrationName,
|
|
163162
163272
|
Query: args.sql,
|
|
163163
163273
|
};
|
|
163164
163274
|
if (args.rollbackSql?.trim()) {
|
|
163165
|
-
|
|
163166
|
-
}
|
|
163167
|
-
const params = { Migrations: [migration] };
|
|
163168
|
-
if (args.lockTimeoutMs !== undefined) {
|
|
163169
|
-
params.LockTimeoutMs = args.lockTimeoutMs;
|
|
163170
|
-
}
|
|
163171
|
-
if (args.statementTimeoutMs !== undefined) {
|
|
163172
|
-
params.StatementTimeoutMs = args.statementTimeoutMs;
|
|
163275
|
+
pending.Rollback = args.rollbackSql;
|
|
163173
163276
|
}
|
|
163174
163277
|
try {
|
|
163278
|
+
// Pushing only the pending migration while remote history exists makes the plan
|
|
163279
|
+
// non-executable (remote_history_not_found_locally). Hydrate remote Queries first,
|
|
163280
|
+
// matching CLI `tcb db pg migration up` (full list; server skips applied).
|
|
163281
|
+
const hydrated = await buildMigrationsPayloadWithRemoteHistory(context, pending, cloudBaseOptions);
|
|
163282
|
+
const preview = await callPgMigrationApi(context, "PreviewPGUserMigrations", { Migrations: hydrated.migrations }, cloudBaseOptions);
|
|
163283
|
+
if (preview.Executable !== true) {
|
|
163284
|
+
return buildPgToolResult({
|
|
163285
|
+
success: false,
|
|
163286
|
+
errorCode: "MIGRATION_NOT_EXECUTABLE",
|
|
163287
|
+
data: {
|
|
163288
|
+
migrationVersion: version,
|
|
163289
|
+
migrationName: args.migrationName,
|
|
163290
|
+
localFileHint,
|
|
163291
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163292
|
+
latestRemoteVersion: hydrated.latestVersion || null,
|
|
163293
|
+
previewResult: preview,
|
|
163294
|
+
verified: false,
|
|
163295
|
+
},
|
|
163296
|
+
message: `PreviewPGUserMigrations reported Executable=false for migrationVersion=${version} ` +
|
|
163297
|
+
`(latest remote=${hydrated.latestVersion || "unknown"}, hydratedRemoteCount=${hydrated.remoteCount}). ` +
|
|
163298
|
+
"Push was NOT submitted. Inspect previewResult.Conflicts — common reasons: " +
|
|
163299
|
+
"local_migration_before_latest_remote (pick a newer 14-digit version) or checksum_mismatch. " +
|
|
163300
|
+
"If the schema change is urgent you may fall back to action=execute with allowDdlViaExecute=true, but that bypasses migration history.",
|
|
163301
|
+
nextActions: [
|
|
163302
|
+
buildNextAction(MANAGE_PG_DATABASE, "listMigrations", "Check LatestVersion and pick a migrationVersion strictly newer than it.", { action: "listMigrations", limit: 20 }),
|
|
163303
|
+
buildNextAction(MANAGE_PG_DATABASE, "planMigration", "Re-run planMigration after adjusting migrationVersion/SQL.", {
|
|
163304
|
+
action: "planMigration",
|
|
163305
|
+
migrationName: args.migrationName,
|
|
163306
|
+
migrationVersion: version,
|
|
163307
|
+
sql: args.sql,
|
|
163308
|
+
...(args.rollbackSql ? { rollbackSql: args.rollbackSql } : {}),
|
|
163309
|
+
}),
|
|
163310
|
+
],
|
|
163311
|
+
});
|
|
163312
|
+
}
|
|
163313
|
+
const params = { Migrations: hydrated.migrations };
|
|
163314
|
+
if (args.lockTimeoutMs !== undefined) {
|
|
163315
|
+
params.LockTimeoutMs = args.lockTimeoutMs;
|
|
163316
|
+
}
|
|
163317
|
+
if (args.statementTimeoutMs !== undefined) {
|
|
163318
|
+
params.StatementTimeoutMs = args.statementTimeoutMs;
|
|
163319
|
+
}
|
|
163175
163320
|
const result = await callPgMigrationApi(context, "PushPGUserMigrations", params, cloudBaseOptions);
|
|
163176
|
-
|
|
163177
|
-
|
|
163178
|
-
|
|
163321
|
+
const taskId = typeof result.TaskId === "string" ? result.TaskId.trim() : "";
|
|
163322
|
+
let taskResult = null;
|
|
163323
|
+
if (taskId) {
|
|
163324
|
+
try {
|
|
163325
|
+
taskResult = await waitPgMigrationTask(context, taskId, cloudBaseOptions);
|
|
163326
|
+
}
|
|
163327
|
+
catch (error) {
|
|
163328
|
+
const lastTask = error.lastTask;
|
|
163329
|
+
return buildPgToolResult({
|
|
163330
|
+
success: false,
|
|
163331
|
+
errorCode: "MIGRATION_TASK_TIMEOUT",
|
|
163332
|
+
data: {
|
|
163333
|
+
migrationVersion: version,
|
|
163334
|
+
migrationName: args.migrationName,
|
|
163335
|
+
localFileHint,
|
|
163336
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163337
|
+
apiResult: result,
|
|
163338
|
+
taskResult: lastTask ?? { TaskId: taskId },
|
|
163339
|
+
verified: null,
|
|
163340
|
+
},
|
|
163341
|
+
message: `PushPGUserMigrations returned TaskId=${taskId}, but waiting for DescribeTaskResult timed out: ` +
|
|
163342
|
+
`${error instanceof Error ? error.message : String(error)}. ` +
|
|
163343
|
+
"The migration may still be running — check action=listMigrations before retrying or falling back to execute.",
|
|
163344
|
+
nextActions: [
|
|
163345
|
+
buildNextAction(MANAGE_PG_DATABASE, "listMigrations", "Check whether the migrationVersion eventually landed.", { action: "listMigrations", limit: 20 }),
|
|
163346
|
+
],
|
|
163347
|
+
});
|
|
163348
|
+
}
|
|
163349
|
+
const status = String(taskResult.Status || "").toLowerCase();
|
|
163350
|
+
if (status === "failed") {
|
|
163351
|
+
return buildPgToolResult({
|
|
163352
|
+
success: false,
|
|
163353
|
+
errorCode: "MIGRATION_TASK_FAILED",
|
|
163354
|
+
data: {
|
|
163355
|
+
migrationVersion: version,
|
|
163356
|
+
migrationName: args.migrationName,
|
|
163357
|
+
localFileHint,
|
|
163358
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163359
|
+
apiResult: result,
|
|
163360
|
+
taskResult: taskResult,
|
|
163361
|
+
verified: false,
|
|
163362
|
+
},
|
|
163363
|
+
message: `PushPGUserMigrations TaskId=${taskId} failed at phase=${taskResult.Phase || "-"}: ` +
|
|
163364
|
+
`${taskResult.Reason || "unknown reason"}. ` +
|
|
163365
|
+
"The migration did NOT take effect. Fix Conflicts/SQL (or use a newer migrationVersion), then retry applyMigration. " +
|
|
163366
|
+
"Urgent bypass: action=execute with allowDdlViaExecute=true (skips migration history).",
|
|
163367
|
+
nextActions: [
|
|
163368
|
+
buildNextAction(MANAGE_PG_DATABASE, "planMigration", "Preview again to inspect Conflicts before retrying apply.", {
|
|
163369
|
+
action: "planMigration",
|
|
163370
|
+
migrationName: args.migrationName,
|
|
163371
|
+
migrationVersion: version,
|
|
163372
|
+
sql: args.sql,
|
|
163373
|
+
...(args.rollbackSql ? { rollbackSql: args.rollbackSql } : {}),
|
|
163374
|
+
}),
|
|
163375
|
+
buildNextAction(MANAGE_PG_DATABASE, "listMigrations", "Confirm the version is still absent from remote history.", { action: "listMigrations", limit: 20 }),
|
|
163376
|
+
],
|
|
163377
|
+
});
|
|
163378
|
+
}
|
|
163379
|
+
}
|
|
163380
|
+
// Task Succeed (or sync response without TaskId): confirm history records the version.
|
|
163179
163381
|
const verification = await verifyMigrationApplied(context, version, cloudBaseOptions);
|
|
163180
163382
|
if (verification.applied === false) {
|
|
163181
163383
|
return buildPgToolResult({
|
|
@@ -163185,10 +163387,12 @@ async function handleApplyMigration(args, context, deps, cloudBaseOptions) {
|
|
|
163185
163387
|
migrationVersion: version,
|
|
163186
163388
|
migrationName: args.migrationName,
|
|
163187
163389
|
localFileHint,
|
|
163390
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163188
163391
|
apiResult: result,
|
|
163392
|
+
taskResult: taskResult,
|
|
163189
163393
|
verified: false,
|
|
163190
163394
|
},
|
|
163191
|
-
message: `PushPGUserMigrations
|
|
163395
|
+
message: `PushPGUserMigrations completed (TaskId=${taskId || "none"}), but migrationVersion=${version} is not present in the remote migration history, ` +
|
|
163192
163396
|
"so the migration did NOT take effect. Do not assume the schema change is applied. " +
|
|
163193
163397
|
"Re-check the SQL and migrationVersion, inspect the migration with action=migrationDetail, and retry action=applyMigration. " +
|
|
163194
163398
|
"If the schema change is urgent you may fall back to action=execute with allowDdlViaExecute=true, but that bypasses migration history.",
|
|
@@ -163206,7 +163410,9 @@ async function handleApplyMigration(args, context, deps, cloudBaseOptions) {
|
|
|
163206
163410
|
migrationVersion: version,
|
|
163207
163411
|
migrationName: args.migrationName,
|
|
163208
163412
|
localFileHint,
|
|
163413
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163209
163414
|
apiResult: result,
|
|
163415
|
+
taskResult: taskResult,
|
|
163210
163416
|
verified: null,
|
|
163211
163417
|
},
|
|
163212
163418
|
message: `PushPGUserMigrations was submitted, but verifying migrationVersion=${version} against the remote history failed: ${verification.error}. ` +
|
|
@@ -163222,10 +163428,12 @@ async function handleApplyMigration(args, context, deps, cloudBaseOptions) {
|
|
|
163222
163428
|
migrationVersion: version,
|
|
163223
163429
|
migrationName: args.migrationName,
|
|
163224
163430
|
localFileHint,
|
|
163431
|
+
hydratedRemoteCount: hydrated.remoteCount,
|
|
163225
163432
|
apiResult: result,
|
|
163433
|
+
taskResult: taskResult,
|
|
163226
163434
|
verified: true,
|
|
163227
163435
|
},
|
|
163228
|
-
message: `Migrations applied via PushPGUserMigrations
|
|
163436
|
+
message: `Migrations applied via PushPGUserMigrations (hydrated ${hydrated.remoteCount} remote migration(s)), task ${taskId ? `TaskId=${taskId} ` : ""}verified present in the remote migration history. Ensure local file ${localFileHint} exists and matches.`,
|
|
163229
163437
|
});
|
|
163230
163438
|
}
|
|
163231
163439
|
catch (error) {
|
|
@@ -198768,7 +198976,7 @@ ${envIdSection}
|
|
|
198768
198976
|
## 环境信息
|
|
198769
198977
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
198770
198978
|
- Node.js版本: ${process.version}
|
|
198771
|
-
- MCP 版本:${process.env.npm_package_version || "2.25.
|
|
198979
|
+
- MCP 版本:${process.env.npm_package_version || "2.25.5" || 0}
|
|
198772
198980
|
- 系统架构: ${os_1.default.arch()}
|
|
198773
198981
|
- 时间: ${new Date().toISOString()}
|
|
198774
198982
|
- 请求ID: ${requestId}
|
|
@@ -198849,7 +199057,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
198849
199057
|
requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
|
|
198850
199058
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
198851
199059
|
});
|
|
198852
|
-
const mcpVersion = true ? "2.25.
|
|
199060
|
+
const mcpVersion = true ? "2.25.5" : 0;
|
|
198853
199061
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
198854
199062
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
198855
199063
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
|
@@ -215437,7 +215645,7 @@ function registerSetupTools(server) {
|
|
|
215437
215645
|
server.registerTool("downloadTemplate", {
|
|
215438
215646
|
title: "下载项目模板",
|
|
215439
215647
|
description: `自动下载并部署CloudBase项目模板。
|
|
215440
|
-
**Note**: Call this tool when the user requests to create a new project using a CloudBase template.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.25.
|
|
215648
|
+
**Note**: Call this tool when the user requests to create a new project using a CloudBase template.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.25.5" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
|
|
215441
215649
|
inputSchema: {
|
|
215442
215650
|
template: zod_1.z
|
|
215443
215651
|
.enum(["react", "vue", "miniprogram", "uniapp", "rules"])
|
|
@@ -232661,7 +232869,11 @@ function registerGatewayTools(server) {
|
|
|
232661
232869
|
return result ?? {};
|
|
232662
232870
|
};
|
|
232663
232871
|
const buildPrivilegeDescription = (privilege) => {
|
|
232664
|
-
const serviceStatus = privilege.EnableService ===
|
|
232872
|
+
const serviceStatus = privilege.EnableService === undefined
|
|
232873
|
+
? "未知"
|
|
232874
|
+
: privilege.EnableService === true
|
|
232875
|
+
? "已开启"
|
|
232876
|
+
: "未开启";
|
|
232665
232877
|
const authStatus = privilege.EnableAuth === undefined
|
|
232666
232878
|
? "未知"
|
|
232667
232879
|
: privilege.EnableAuth === true
|
|
@@ -233001,12 +233213,28 @@ function registerGatewayTools(server) {
|
|
|
233001
233213
|
if (!input.domain || !input.certificateId) {
|
|
233002
233214
|
throw new Error("action=bindCustomDomain 时必须提供 domain 和 certificateId");
|
|
233003
233215
|
}
|
|
233216
|
+
const accessType = input.accessType ?? "DIRECT";
|
|
233217
|
+
if (accessType === "CUSTOM" && !input.customCname) {
|
|
233218
|
+
throw new Error("action=bindCustomDomain 且 accessType=CUSTOM 时必须提供 customCname(自有 CDN/WAF 的回源/回填地址,不是 DNS 解析目标)。" +
|
|
233219
|
+
"说明:https://docs.cloudbase.net/service/custom-domain");
|
|
233220
|
+
}
|
|
233221
|
+
if (accessType !== "CUSTOM" && input.customCname) {
|
|
233222
|
+
throw new Error("customCname 仅在 accessType=CUSTOM 时可用;普通绑定用默认 DIRECT,不要传 customCname。" +
|
|
233223
|
+
"说明:https://docs.cloudbase.net/service/custom-domain");
|
|
233224
|
+
}
|
|
233004
233225
|
const cloudbase = await getManager();
|
|
233005
233226
|
const result = await cloudbase.env.bindCustomDomain({
|
|
233006
233227
|
EnvId: await resolveEnvId(),
|
|
233007
233228
|
Domain: {
|
|
233008
233229
|
Domain: input.domain,
|
|
233009
233230
|
CertId: input.certificateId,
|
|
233231
|
+
AccessType: accessType,
|
|
233232
|
+
...(input.enable !== undefined
|
|
233233
|
+
? { Enable: input.enable }
|
|
233234
|
+
: {}),
|
|
233235
|
+
...(input.customCname
|
|
233236
|
+
? { CustomCname: input.customCname }
|
|
233237
|
+
: {}),
|
|
233010
233238
|
},
|
|
233011
233239
|
});
|
|
233012
233240
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
@@ -233014,24 +233242,64 @@ function registerGatewayTools(server) {
|
|
|
233014
233242
|
action: input.action,
|
|
233015
233243
|
domain: input.domain,
|
|
233016
233244
|
certificateId: input.certificateId,
|
|
233245
|
+
accessType,
|
|
233246
|
+
...(input.customCname
|
|
233247
|
+
? { customCname: input.customCname }
|
|
233248
|
+
: {}),
|
|
233249
|
+
...(input.enable !== undefined
|
|
233250
|
+
? { enable: input.enable }
|
|
233251
|
+
: {}),
|
|
233017
233252
|
raw: result,
|
|
233018
|
-
},
|
|
233253
|
+
}, `自定义域名绑定成功(${accessType})`, [
|
|
233254
|
+
{
|
|
233255
|
+
tool: "manageGateway",
|
|
233256
|
+
action: "createRoute",
|
|
233257
|
+
reason: "绑定后需 createRoute 添加访问路径,并完成 DNS CNAME 解析后才可访问",
|
|
233258
|
+
},
|
|
233259
|
+
]);
|
|
233019
233260
|
}
|
|
233020
233261
|
case "deleteCustomDomain": {
|
|
233021
233262
|
if (!input.domain) {
|
|
233022
233263
|
throw new Error("action=deleteCustomDomain 时必须提供 domain");
|
|
233023
233264
|
}
|
|
233024
233265
|
const cloudbase = await getManager();
|
|
233025
|
-
|
|
233026
|
-
|
|
233027
|
-
|
|
233028
|
-
|
|
233029
|
-
|
|
233030
|
-
|
|
233031
|
-
|
|
233032
|
-
|
|
233033
|
-
|
|
233034
|
-
|
|
233266
|
+
try {
|
|
233267
|
+
const result = await cloudbase.env.deleteCustomDomain({
|
|
233268
|
+
EnvId: await resolveEnvId(),
|
|
233269
|
+
Domain: input.domain,
|
|
233270
|
+
});
|
|
233271
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
233272
|
+
return buildEnvelope({
|
|
233273
|
+
action: input.action,
|
|
233274
|
+
domain: input.domain,
|
|
233275
|
+
raw: result,
|
|
233276
|
+
}, "自定义域名删除成功");
|
|
233277
|
+
}
|
|
233278
|
+
catch (error) {
|
|
233279
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
233280
|
+
// SDK 在域名下仍有路由绑定时抛错,需先删路由再删域名
|
|
233281
|
+
if (/route binding/i.test(message)) {
|
|
233282
|
+
return {
|
|
233283
|
+
success: false,
|
|
233284
|
+
data: { action: input.action, domain: input.domain },
|
|
233285
|
+
message: `域名 ${input.domain} 下仍有路由绑定,需先删除路由再删除域名。` +
|
|
233286
|
+
`原始错误:${message}`,
|
|
233287
|
+
nextActions: [
|
|
233288
|
+
{
|
|
233289
|
+
tool: "queryGateway",
|
|
233290
|
+
action: "listRoutes",
|
|
233291
|
+
reason: "查看该域名下的路由,确认需要删除的路径",
|
|
233292
|
+
},
|
|
233293
|
+
{
|
|
233294
|
+
tool: "manageGateway",
|
|
233295
|
+
action: "deleteRoute",
|
|
233296
|
+
reason: "先删除该域名下的全部路由(逐个 deleteRoute),再重试 deleteCustomDomain",
|
|
233297
|
+
},
|
|
233298
|
+
],
|
|
233299
|
+
};
|
|
233300
|
+
}
|
|
233301
|
+
throw error;
|
|
233302
|
+
}
|
|
233035
233303
|
}
|
|
233036
233304
|
case "enableService": {
|
|
233037
233305
|
if (typeof input.enable !== "boolean") {
|
|
@@ -233144,7 +233412,8 @@ function registerGatewayTools(server) {
|
|
|
233144
233412
|
"enableService/authSwitch 开关 HTTP 网关总开关与访问鉴权(需配合 enable 参数)。" +
|
|
233145
233413
|
"createRoute/updateRoute 必须提供 upstreamResourceType。" +
|
|
233146
233414
|
"已有自定义域名时优先 createRoute(domain=已有域名) 实现访问,不必再次 bindCustomDomain / 传入 certificateId;" +
|
|
233147
|
-
"bindCustomDomain
|
|
233415
|
+
"bindCustomDomain 仅用于首次绑定新域名(需 certificateId;可选 accessType=DIRECT|CDN|CUSTOM,CUSTOM 需 customCname;普通场景用默认 DIRECT)。" +
|
|
233416
|
+
"接入说明:https://docs.cloudbase.net/service/custom-domain"),
|
|
233148
233417
|
targetName: zod_1.z
|
|
233149
233418
|
.string()
|
|
233150
233419
|
.optional()
|
|
@@ -233207,11 +233476,24 @@ function registerGatewayTools(server) {
|
|
|
233207
233476
|
.optional()
|
|
233208
233477
|
.describe("证书 ID。仅首次 bindCustomDomain 必填。" +
|
|
233209
233478
|
"在已有自定义域名上 createRoute / updateRoute / deleteRoute 不需要 certificateId。"),
|
|
233479
|
+
accessType: zod_1.z
|
|
233480
|
+
.enum(["DIRECT", "CDN", "CUSTOM"])
|
|
233481
|
+
.optional()
|
|
233482
|
+
.describe("绑定类型(仅 bindCustomDomain,默认 DIRECT)。" +
|
|
233483
|
+
"DIRECT=直连(普通绑域名用这个);CDN=云开发 CDN;CUSTOM=自有 CDN/WAF(需 customCname)。" +
|
|
233484
|
+
"详见 https://docs.cloudbase.net/service/custom-domain"),
|
|
233485
|
+
customCname: zod_1.z
|
|
233486
|
+
.string()
|
|
233487
|
+
.optional()
|
|
233488
|
+
.describe("自有 CDN/WAF 的回源/回填地址(仅 bindCustomDomain 且 accessType=CUSTOM)。" +
|
|
233489
|
+
"不是 DNS 里用户域名要解析到的那个 CNAME;DIRECT/CDN 不要传。" +
|
|
233490
|
+
"详见 https://docs.cloudbase.net/service/custom-domain"),
|
|
233210
233491
|
enable: zod_1.z
|
|
233211
233492
|
.boolean()
|
|
233212
233493
|
.optional()
|
|
233213
|
-
.describe("
|
|
233214
|
-
"
|
|
233494
|
+
.describe("开关目标状态(enableService / authSwitch 必填):enable=true 开启,enable=false 关闭。" +
|
|
233495
|
+
"bindCustomDomain 可选:enable=false 表示绑定后禁用域名(默认启用)。" +
|
|
233496
|
+
"省略或非布尔值会返回参数错误。"),
|
|
233215
233497
|
},
|
|
233216
233498
|
annotations: {
|
|
233217
233499
|
readOnlyHint: false,
|