@cloudbase/cloudbase-mcp 2.25.0 → 2.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -84648,6 +84648,154 @@ exports.colors = {
84648
84648
  })));
84649
84649
 
84650
84650
 
84651
+ /***/ }),
84652
+
84653
+ /***/ 22435:
84654
+ /***/ ((__unused_webpack_module, exports) => {
84655
+
84656
+ "use strict";
84657
+
84658
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
84659
+ exports.rankGatewayAccessUrls = rankGatewayAccessUrls;
84660
+ exports.flattenHttpServiceRoutes = flattenHttpServiceRoutes;
84661
+ exports.filterRoutesByUpstream = filterRoutesByUpstream;
84662
+ exports.toAccessUrlEnvelope = toAccessUrlEnvelope;
84663
+ exports.resolveGatewayAccessUrls = resolveGatewayAccessUrls;
84664
+ exports.preferGatewayOrFallback = preferGatewayOrFallback;
84665
+ function normalizeAccessPath(path) {
84666
+ if (!path) {
84667
+ return "/";
84668
+ }
84669
+ return path.startsWith("/") ? path : `/${path}`;
84670
+ }
84671
+ function buildHttpsUrl(domain, path) {
84672
+ return `https://${domain}${normalizeAccessPath(path)}`;
84673
+ }
84674
+ /**
84675
+ * Rank gateway route URLs: custom domains (IsDefault !== true) before default domain.
84676
+ * Stable within each group; dedupe by full URL.
84677
+ */
84678
+ function rankGatewayAccessUrls(routes) {
84679
+ const mapped = routes
84680
+ .filter((route) => Boolean(route.Domain))
84681
+ .map((route) => {
84682
+ const path = normalizeAccessPath(route.Path);
84683
+ const isDefault = route.IsDefault === true;
84684
+ return {
84685
+ url: buildHttpsUrl(route.Domain, path),
84686
+ domain: route.Domain,
84687
+ path,
84688
+ isDefault,
84689
+ source: (isDefault
84690
+ ? "gateway.default"
84691
+ : "gateway.custom"),
84692
+ };
84693
+ });
84694
+ mapped.sort((a, b) => {
84695
+ if (a.isDefault === b.isDefault) {
84696
+ return 0;
84697
+ }
84698
+ return a.isDefault ? 1 : -1;
84699
+ });
84700
+ const seen = new Set();
84701
+ const deduped = [];
84702
+ for (const item of mapped) {
84703
+ if (seen.has(item.url)) {
84704
+ continue;
84705
+ }
84706
+ seen.add(item.url);
84707
+ deduped.push(item);
84708
+ }
84709
+ return deduped;
84710
+ }
84711
+ function flattenHttpServiceRoutes(result) {
84712
+ return (result.Domains ?? []).flatMap((domainItem) => (domainItem.Routes ?? []).map((route) => ({
84713
+ Domain: domainItem.Domain ?? "",
84714
+ IsDefault: domainItem.IsDefault,
84715
+ Path: typeof route.Path === "string" ? route.Path : undefined,
84716
+ UpstreamResourceType: typeof route.UpstreamResourceType === "string"
84717
+ ? route.UpstreamResourceType
84718
+ : undefined,
84719
+ UpstreamResourceName: typeof route.UpstreamResourceName === "string"
84720
+ ? route.UpstreamResourceName
84721
+ : undefined,
84722
+ })));
84723
+ }
84724
+ function filterRoutesByUpstream(routes, input) {
84725
+ const name = input.upstreamResourceName;
84726
+ const types = input.upstreamResourceTypes?.map((t) => String(t));
84727
+ return routes.filter((route) => {
84728
+ if (route.UpstreamResourceName !== name) {
84729
+ return false;
84730
+ }
84731
+ if (!types || types.length === 0) {
84732
+ return true;
84733
+ }
84734
+ return Boolean(route.UpstreamResourceType &&
84735
+ types.includes(String(route.UpstreamResourceType)));
84736
+ });
84737
+ }
84738
+ function toAccessUrlEnvelope(ranked) {
84739
+ if (ranked.length === 0) {
84740
+ return { accessUrls: [], routes: [] };
84741
+ }
84742
+ return {
84743
+ accessUrl: ranked[0].url,
84744
+ accessUrls: ranked.map((item) => item.url),
84745
+ accessUrlSource: ranked[0].source,
84746
+ routes: ranked,
84747
+ };
84748
+ }
84749
+ /**
84750
+ * Best-effort lookup of gateway access URLs for an upstream resource.
84751
+ * Never throws — returns empty lists on failure.
84752
+ */
84753
+ async function resolveGatewayAccessUrls(input) {
84754
+ try {
84755
+ const manager = await input.getManager();
84756
+ const result = await manager.env.describeHttpServiceRoute({
84757
+ EnvId: input.envId,
84758
+ Limit: 1000,
84759
+ });
84760
+ const flattened = flattenHttpServiceRoutes(result);
84761
+ const matched = filterRoutesByUpstream(flattened, {
84762
+ upstreamResourceName: input.upstreamResourceName,
84763
+ upstreamResourceTypes: input.upstreamResourceTypes,
84764
+ });
84765
+ return toAccessUrlEnvelope(rankGatewayAccessUrls(matched));
84766
+ }
84767
+ catch {
84768
+ return { accessUrls: [], routes: [] };
84769
+ }
84770
+ }
84771
+ /**
84772
+ * Merge ranked gateway URLs with a resource-native fallback URL.
84773
+ * Gateway custom/default always win over the fallback when present.
84774
+ */
84775
+ function preferGatewayOrFallback(input) {
84776
+ if (input.gateway.accessUrl) {
84777
+ const urls = [...input.gateway.accessUrls];
84778
+ if (input.fallbackUrl &&
84779
+ !urls.includes(input.fallbackUrl)) {
84780
+ urls.push(input.fallbackUrl);
84781
+ }
84782
+ return {
84783
+ accessUrl: input.gateway.accessUrl,
84784
+ accessUrls: urls,
84785
+ accessUrlSource: input.gateway.accessUrlSource,
84786
+ };
84787
+ }
84788
+ if (input.fallbackUrl) {
84789
+ return {
84790
+ accessUrl: input.fallbackUrl,
84791
+ accessUrls: [input.fallbackUrl],
84792
+ accessUrlSource: input.fallbackSource,
84793
+ };
84794
+ }
84795
+ return { accessUrls: [] };
84796
+ }
84797
+
84798
+
84651
84799
  /***/ }),
84652
84800
 
84653
84801
  /***/ 22573:
@@ -90059,6 +90207,7 @@ exports.registerFunctionTools = registerFunctionTools;
90059
90207
  const zod_1 = __webpack_require__(21614);
90060
90208
  const cloudbase_manager_js_1 = __webpack_require__(3431);
90061
90209
  const cloud_mode_js_1 = __webpack_require__(89684);
90210
+ const gateway_access_urls_js_1 = __webpack_require__(22435);
90062
90211
  const json_content_js_1 = __webpack_require__(4365);
90063
90212
  const logger_js_1 = __webpack_require__(13039);
90064
90213
  const fs_1 = __webpack_require__(29021);
@@ -90811,7 +90960,7 @@ function registerFunctionTools(server) {
90811
90960
  raw: imageResult,
90812
90961
  }, `已基于镜像 ${createImageConfig.imageUri} 创建 HTTP 函数 ${functionName}。` +
90813
90962
  `请确认 TCR、SCF 与构建管道处于同一地域;如需通过 URL 访问,请显式调用 ` +
90814
- `manageGateway(action="createRoute", type="HTTP") 并按需调整函数安全规则。` +
90963
+ `manageGateway(action="createRoute", upstreamResourceType="WEB_SCF") 并按需调整函数安全规则。` +
90815
90964
  `部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪。`, [
90816
90965
  {
90817
90966
  tool: "queryFunctions",
@@ -90882,7 +91031,7 @@ function registerFunctionTools(server) {
90882
91031
  nextActions.push({
90883
91032
  tool: "manageGateway",
90884
91033
  action: "createRoute",
90885
- reason: "如果需要通过 URL 访问 HTTP 函数,请调用 manageGateway(action=\"createRoute\") 并显式传 type=\"HTTP\"(映射 WEB_SCF),再按实际路径和鉴权需求创建访问入口,不要默认假设 /函数名 已存在",
91034
+ reason: "如果需要通过 URL 访问 HTTP 函数,请调用 manageGateway(action=\"createRoute\") 并显式传 upstreamResourceType=\"WEB_SCF\",再按实际路径和鉴权需求创建访问入口,不要默认假设 /函数名 已存在",
90886
91035
  });
90887
91036
  nextActions.push({
90888
91037
  tool: "queryGateway",
@@ -90901,11 +91050,35 @@ function registerFunctionTools(server) {
90901
91050
  });
90902
91051
  }
90903
91052
  const message = func.type === "HTTP"
90904
- ? `已创建 HTTP 函数 ${functionName}。如果后续需要通过 URL 访问,请显式调用 manageGateway(action="createRoute"),并把 type="HTTP" 一起传入(映射 UpstreamResourceType=WEB_SCF),再按实际路径和鉴权需求创建访问入口。评测或其他外部调用方可能会以匿名身份访问,而且失败后不一定会把 EXCEED_AUTHORITY 再反馈给 AI;交付前请主动确认访问路径和函数安全规则,若已出现 EXCEED_AUTHORITY,请先调用 queryPermissions(action="getResourcePermission", resourceType="function", resourceId="${functionName}") 查看当前规则,再按需要使用 managePermissions(action="updateResourcePermission") 调整权限。`
91053
+ ? `已创建 HTTP 函数 ${functionName}。如果后续需要通过 URL 访问,请显式调用 manageGateway(action="createRoute"),并把 upstreamResourceType="WEB_SCF" 一起传入,再按实际路径和鉴权需求创建访问入口。评测或其他外部调用方可能会以匿名身份访问,而且失败后不一定会把 EXCEED_AUTHORITY 再反馈给 AI;交付前请主动确认访问路径和函数安全规则,若已出现 EXCEED_AUTHORITY,请先调用 queryPermissions(action="getResourcePermission", resourceType="function", resourceId="${functionName}") 查看当前规则,再按需要使用 managePermissions(action="updateResourcePermission") 调整权限。`
90905
91054
  : `已创建函数 ${functionName}`;
91055
+ let accessUrl;
91056
+ let accessUrls = [];
91057
+ let accessUrlSource;
91058
+ if (func.type === "HTTP") {
91059
+ const envId = cloudBaseOptions?.envId ?? await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
91060
+ const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
91061
+ envId,
91062
+ upstreamResourceName: functionName,
91063
+ upstreamResourceTypes: ["WEB_SCF", "SCF"],
91064
+ getManager: async () => {
91065
+ const manager = await getManager();
91066
+ if (!manager) {
91067
+ throw new Error("cloudbase manager unavailable");
91068
+ }
91069
+ return manager;
91070
+ },
91071
+ });
91072
+ accessUrl = gateway.accessUrl;
91073
+ accessUrls = gateway.accessUrls;
91074
+ accessUrlSource = gateway.accessUrlSource;
91075
+ }
90906
91076
  return buildEnvelope({
90907
91077
  action: input.action,
90908
91078
  functionName,
91079
+ ...(accessUrl ? { accessUrl } : {}),
91080
+ ...(accessUrls.length > 0 ? { accessUrls } : {}),
91081
+ ...(accessUrlSource ? { accessUrlSource } : {}),
90909
91082
  raw: result,
90910
91083
  }, message, nextActions);
90911
91084
  }
@@ -90944,11 +91117,33 @@ function registerFunctionTools(server) {
90944
91117
  throw wrapFunctionOperationError("updateFunctionCode", input.functionName, undefined, error);
90945
91118
  }
90946
91119
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, imageResult);
91120
+ const envId = cloudBaseOptions?.envId ?? await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
91121
+ const imageGatewayAccess = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
91122
+ envId,
91123
+ upstreamResourceName: input.functionName,
91124
+ upstreamResourceTypes: ["WEB_SCF", "SCF"],
91125
+ getManager: async () => {
91126
+ const manager = await getManager();
91127
+ if (!manager) {
91128
+ throw new Error("cloudbase manager unavailable");
91129
+ }
91130
+ return manager;
91131
+ },
91132
+ });
90947
91133
  return buildEnvelope({
90948
91134
  action: input.action,
90949
91135
  functionName: input.functionName,
90950
91136
  deployMode: "image",
90951
91137
  imageUri: updateImageConfig.imageUri,
91138
+ ...(imageGatewayAccess.accessUrl
91139
+ ? { accessUrl: imageGatewayAccess.accessUrl }
91140
+ : {}),
91141
+ ...(imageGatewayAccess.accessUrls.length > 0
91142
+ ? { accessUrls: imageGatewayAccess.accessUrls }
91143
+ : {}),
91144
+ ...(imageGatewayAccess.accessUrlSource
91145
+ ? { accessUrlSource: imageGatewayAccess.accessUrlSource }
91146
+ : {}),
90952
91147
  raw: imageResult,
90953
91148
  }, `已将函数 ${input.functionName} 的镜像更新为 ${updateImageConfig.imageUri}。` +
90954
91149
  `部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪(Active)。`, [
@@ -90979,9 +91174,29 @@ function registerFunctionTools(server) {
90979
91174
  throw wrapFunctionOperationError("updateFunctionCode", input.functionName, processedRootPath, error);
90980
91175
  }
90981
91176
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
91177
+ const envId = cloudBaseOptions?.envId ?? await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
91178
+ const gatewayAccess = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
91179
+ envId,
91180
+ upstreamResourceName: input.functionName,
91181
+ upstreamResourceTypes: ["WEB_SCF", "SCF"],
91182
+ getManager: async () => {
91183
+ const manager = await getManager();
91184
+ if (!manager) {
91185
+ throw new Error("cloudbase manager unavailable");
91186
+ }
91187
+ return manager;
91188
+ },
91189
+ });
90982
91190
  return buildEnvelope({
90983
91191
  action: input.action,
90984
91192
  functionName: input.functionName,
91193
+ ...(gatewayAccess.accessUrl ? { accessUrl: gatewayAccess.accessUrl } : {}),
91194
+ ...(gatewayAccess.accessUrls.length > 0
91195
+ ? { accessUrls: gatewayAccess.accessUrls }
91196
+ : {}),
91197
+ ...(gatewayAccess.accessUrlSource
91198
+ ? { accessUrlSource: gatewayAccess.accessUrlSource }
91199
+ : {}),
90985
91200
  raw: result,
90986
91201
  }, `已更新函数 ${input.functionName} 的代码`, [
90987
91202
  {
@@ -103680,7 +103895,6 @@ const capi_js_1 = __webpack_require__(40738);
103680
103895
  const cloudrun_js_1 = __webpack_require__(35023);
103681
103896
  const dataModel_js_1 = __webpack_require__(34052);
103682
103897
  const gateway_js_1 = __webpack_require__(84319);
103683
- const invite_code_js_1 = __webpack_require__(44760);
103684
103898
  const agents_js_1 = __webpack_require__(9527);
103685
103899
  const app_auth_js_1 = __webpack_require__(5313);
103686
103900
  const apps_js_1 = __webpack_require__(36817);
@@ -103711,7 +103925,6 @@ const DEFAULT_PLUGINS = [
103711
103925
  "logs",
103712
103926
  "agents",
103713
103927
  "download",
103714
- "invite-code",
103715
103928
  "capi",
103716
103929
  ];
103717
103930
  function registerDatabase(server) {
@@ -103753,7 +103966,6 @@ const AVAILABLE_PLUGINS = {
103753
103966
  logs: { name: "logs", register: logs_js_1.registerLogTools },
103754
103967
  agents: { name: "agents", register: agents_js_1.registerAgentTools },
103755
103968
  apps: { name: "apps", register: apps_js_1.registerAppTools },
103756
- "invite-code": { name: "invite-code", register: invite_code_js_1.registerInviteCodeTools },
103757
103969
  cloudrun: { name: "cloudrun", register: cloudrun_js_1.registerCloudRunTools },
103758
103970
  capi: { name: "capi", register: capi_js_1.registerCapiTools },
103759
103971
  };
@@ -114241,7 +114453,9 @@ const path_1 = __importDefault(__webpack_require__(39902));
114241
114453
  const zod_1 = __webpack_require__(21614);
114242
114454
  const cloudbase_manager_js_1 = __webpack_require__(3431);
114243
114455
  const logger_js_1 = __webpack_require__(13039);
114456
+ const gateway_access_urls_js_1 = __webpack_require__(22435);
114244
114457
  const notification_js_1 = __webpack_require__(32720);
114458
+ const cloudrun_config_js_1 = __webpack_require__(48266);
114245
114459
  // CloudRun service types
114246
114460
  exports.CLOUDRUN_SERVICE_TYPES = ['function', 'container'];
114247
114461
  // CloudRun access types
@@ -114260,10 +114474,11 @@ const queryCloudRunInputSchema = {
114260
114474
  };
114261
114475
  // Input schema for manageCloudRun tool
114262
114476
  const ManageCloudRunInputSchema = {
114263
- action: zod_1.z.enum(['init', 'download', 'run', 'deploy', 'delete', 'createAgent']).describe('云托管服务管理操作类型:init=从模板初始化新的云托管项目代码(在targetPath目录下创建以serverName命名的子目录,支持多种语言和框架模板),download=从云端下载现有服务的代码到本地进行开发,run=在本地运行函数型云托管服务(用于开发和调试,仅支持函数型服务),deploy=将本地代码部署到云端云托管服务(支持函数型和容器型),delete=删除指定的云托管服务(不可恢复,需要确认),createAgent=创建函数型Agent(基于函数型云托管开发AI智能体)'),
114477
+ action: zod_1.z.enum(['init', 'download', 'run', 'deploy', 'delete', 'createAgent', 'updateConfig']).describe('云托管服务管理操作类型:init=从模板初始化新的云托管项目代码(在targetPath目录下创建以serverName命名的子目录,支持多种语言和框架模板),download=从云端下载现有服务的代码到本地进行开发,run=在本地运行函数型云托管服务(用于开发和调试,仅支持函数型服务),deploy=将本地代码部署到云端云托管服务(支持函数型和容器型;已存在服务会 Read-Merge-Write 保留远程 VpcConf/EnvParams/OpenAccessTypes),updateConfig=仅更新服务配置不重新上传代码(对齐控制台服务设置,走 SubmitServerConfigChangeDiff;不需要 targetPath),delete=删除指定的云托管服务(不可恢复,需要确认),createAgent=创建函数型Agent(基于函数型云托管开发AI智能体)'),
114264
114478
  serverName: zod_1.z.string().describe('云托管服务名称,用于标识和管理服务。命名规则:支持大小写字母、数字、连字符和下划线,必须以字母开头,长度3-45个字符。在init操作中会作为在targetPath下创建的子目录名,在其他操作中作为目标服务名'),
114265
114479
  // Deploy operation parameters
114266
- targetPath: zod_1.z.string().optional().describe('本地代码路径,必须是绝对路径。在deploy操作中指定要部署的代码目录,在download操作中指定下载目标目录,在init操作中指定云托管服务的上级目录(会在该目录下创建以serverName命名的子目录)。建议约定:项目根目录下的cloudrun/目录,例如:/Users/username/projects/my-project/cloudrun'),
114480
+ targetPath: zod_1.z.string().optional().describe('本地代码路径,必须是绝对路径。在deploy操作中指定要部署的代码目录,在download操作中指定下载目标目录,在init操作中指定云托管服务的上级目录(会在该目录下创建以serverName命名的子目录)。updateConfig 不需要此参数。建议约定:项目根目录下的cloudrun/目录,例如:/Users/username/projects/my-project/cloudrun'),
114481
+ envParamsReplaceAll: zod_1.z.boolean().optional().default(false).describe('EnvParams 合并策略(deploy / updateConfig):false(默认)= 与远程按 key 合并(输入覆盖同名 key,远程其余 key 保留);true= 用输入 EnvParams 整包替换远程。仅当显式传入 EnvParams 时生效'),
114267
114482
  serverConfig: zod_1.z.object({
114268
114483
  OpenAccessTypes: zod_1.z.array(zod_1.z.enum(exports.CLOUDRUN_ACCESS_TYPES)).optional().describe('公网访问类型配置,控制服务的访问权限:OA=办公网访问,PUBLIC=公网访问(默认,可通过HTTPS域名访问),MINIAPP=小程序访问,VPC=VPC访问(仅同VPC内可访问)。可配置多个类型'),
114269
114484
  Cpu: zod_1.z.number().positive().optional().describe('CPU规格配置,单位为核。可选值:0.25、0.5、1、2、4、8等。注意:内存规格必须是CPU规格的2倍(如CPU=0.25时内存=0.5,CPU=1时内存=2)。影响服务性能和计费'),
@@ -114302,7 +114517,7 @@ const ManageCloudRunInputSchema = {
114302
114517
  VpcConf: zod_1.z.object({
114303
114518
  VpcId: zod_1.z.string().describe('VPC网络ID,格式如 vpc-xxxxxxxx。必须与目标数据库/Redis 处于同一地域,并优先选择同一 VPC。禁止猜测或使用占位符;须来自数据库控制台、已有资源详情、callCloudApi 或用户确认。建议首次创建即配置;已存在服务也可在 deploy 时传入,部署后必须用 queryCloudRun detail 复核是否生效'),
114304
114519
  SubnetId: zod_1.z.string().describe('子网ID,格式如 subnet-xxxxxxxx。云托管实例将占用该子网 IP,需确保有足够可用 IP'),
114305
- }).optional().describe('VPC网络配置(实例出网/私有网络)。用于让云托管实例接入指定 VPC,从而内网访问 MySQL/PostgreSQL/Redis/CVM 等资源。与 OpenAccessTypes(外部如何访问本服务)是不同概念。TCP 连库场景必须配置。禁止猜测 VpcId/SubnetId,须来自数据库控制台、已有资源详情、callCloudApi 或用户确认。MCP 在创建时会将 VpcConf 映射为 SDK vpcInfo(CreateType=2);更新后必须用 queryCloudRun detail 复核 ServerConfig.VpcConf,未生效再走控制台网络设置或删建兜底'),
114520
+ }).optional().describe('VPC网络配置(实例出网/私有网络)。用于让云托管实例接入指定 VPC,从而内网访问 MySQL/PostgreSQL/Redis/CVM 等资源。与 OpenAccessTypes(外部如何访问本服务)是不同概念。TCP 连库场景必须配置。禁止猜测 VpcId/SubnetId,须来自数据库控制台、已有资源详情、callCloudApi 或用户确认。创建时映射为 SDK vpcInfo(CreateType=2);已存在服务可用 updateConfig 或 deploy(RMW 会保留未传入的远程 VpcConf)。部署/更新后必须用 queryCloudRun detail 复核 ServerConfig.VpcConf'),
114306
114521
  VolumesConf: zod_1.z.array(zod_1.z.object({
114307
114522
  VolumeName: zod_1.z.string().describe('存储卷名称'),
114308
114523
  VolumeType: zod_1.z.string().describe('存储卷类型,如CFS表示云文件存储'),
@@ -114312,7 +114527,7 @@ const ManageCloudRunInputSchema = {
114312
114527
  PublicAccess: zod_1.z.boolean().optional().describe('是否开启公网访问,true=开启公网访问,false=关闭公网访问'),
114313
114528
  PublicAccessPath: zod_1.z.string().optional().describe('公网访问路径配置')
114314
114529
  }).optional().describe('公网访问配置,用于控制服务的公网访问策略。可配置是否开启公网访问及访问路径'),
114315
- }).optional().describe('服务配置项,用于部署时设置服务的运行参数。包括资源规格、访问权限、环境变量、日志、网络等配置。不提供时使用默认配置'),
114530
+ }).optional().describe('服务配置项,用于 deploy / updateConfig。包括资源规格、访问权限、环境变量、日志、网络等。deploy 未提供时对已存在服务仍会从远程合并保留 VpcConf/EnvParams/OpenAccessTypes;updateConfig 至少需要一个配置字段'),
114316
114531
  // Init operation parameters
114317
114532
  template: zod_1.z.string().optional().default('helloworld').describe('项目模板标识符,用于指定初始化项目时使用的模板。可通过queryCloudRun的templates操作获取可用模板列表。常用模板:helloworld=Hello World示例,nodejs=Node.js项目模板,python=Python项目模板等'),
114318
114533
  // Run operation parameters (function services only)
@@ -114496,6 +114711,30 @@ function normalizeProcessLogText(logs) {
114496
114711
  })
114497
114712
  .join("\n");
114498
114713
  }
114714
+ function normalizeCloudRunDomainUrl(input) {
114715
+ if (typeof input !== "string" || !input.trim())
114716
+ return undefined;
114717
+ const raw = input.trim();
114718
+ return raw.startsWith("http://") || raw.startsWith("https://")
114719
+ ? raw
114720
+ : `https://${raw}`;
114721
+ }
114722
+ function resolveCloudRunFallbackAccess(details) {
114723
+ const custom = normalizeCloudRunDomainUrl(details?.BaseInfo?.CustomDomainName);
114724
+ if (custom)
114725
+ return { url: custom, source: "cloudrun.customDomain" };
114726
+ const defaultDomain = normalizeCloudRunDomainUrl(details?.BaseInfo?.DefaultDomainName);
114727
+ if (defaultDomain)
114728
+ return { url: defaultDomain, source: "cloudrun.defaultDomain" };
114729
+ const publicDomain = normalizeCloudRunDomainUrl(details?.BaseInfo?.PublicDomain) ??
114730
+ normalizeCloudRunDomainUrl(details?.AccessInfo?.PublicDomain);
114731
+ if (publicDomain)
114732
+ return { url: publicDomain, source: "cloudrun.publicDomain" };
114733
+ const internal = normalizeCloudRunDomainUrl(details?.BaseInfo?.InternalDomain);
114734
+ if (internal)
114735
+ return { url: internal, source: "cloudrun.internalDomain" };
114736
+ return {};
114737
+ }
114499
114738
  /**
114500
114739
  * Format CloudRun service info for display
114501
114740
  */
@@ -114729,7 +114968,7 @@ function registerCloudRunTools(server) {
114729
114968
  // Tool 2: Manage CloudRun services (write operations)
114730
114969
  server.registerTool("manageCloudRun", {
114731
114970
  title: "管理 CloudRun 服务",
114732
- description: "管理云托管服务,按开发顺序支持:初始化项目(可从模板开始,模板列表可通过 queryCloudRun 查询)、下载服务代码、本地运行(仅函数型服务)、部署代码、删除服务。部署可配置CPU、内存、实例数、访问类型等参数。删除操作需要确认,建议设置force=true。",
114971
+ description: "管理云托管服务,按开发顺序支持:初始化项目(可从模板开始,模板列表可通过 queryCloudRun 查询)、下载服务代码、本地运行(仅函数型服务)、部署代码、仅更新配置(updateConfig,无需重新上传代码)、删除服务。deploy 对已存在服务会先读取远程配置再合并(保留 VpcConf/EnvParams/OpenAccessTypes)。updateConfig 对齐控制台服务设置页。删除操作需要确认,建议设置force=true。",
114733
114972
  inputSchema: ManageCloudRunInputSchema,
114734
114973
  annotations: {
114735
114974
  readOnlyHint: false,
@@ -114920,6 +115159,8 @@ for await (let x of res.textStream) {
114920
115159
  }
114921
115160
  // Determine service type - use input.serverType if provided, otherwise auto-detect
114922
115161
  let serverType;
115162
+ let remoteServerConfig = null;
115163
+ let existingService = false;
114923
115164
  if (input.serverType) {
114924
115165
  serverType = input.serverType;
114925
115166
  }
@@ -114928,6 +115169,8 @@ for await (let x of res.textStream) {
114928
115169
  // First try to get existing service details
114929
115170
  const details = await cloudrunService.detail({ serverName: input.serverName });
114930
115171
  serverType = details.BaseInfo?.ServerType || 'container';
115172
+ remoteServerConfig = (details.ServerConfig || null);
115173
+ existingService = true;
114931
115174
  }
114932
115175
  catch (e) {
114933
115176
  // If service doesn't exist, determine by project structure
@@ -114961,20 +115204,40 @@ for await (let x of res.textStream) {
114961
115204
  }
114962
115205
  }
114963
115206
  }
115207
+ // When serverType was provided explicitly, still try to load remote config for RMW.
115208
+ if (!existingService) {
115209
+ try {
115210
+ const details = await cloudrunService.detail({ serverName: input.serverName });
115211
+ remoteServerConfig = (details.ServerConfig || null);
115212
+ existingService = true;
115213
+ }
115214
+ catch {
115215
+ // New service create path
115216
+ }
115217
+ }
115218
+ let mergedFromRemote = [];
115219
+ let effectiveServerConfig = input.serverConfig;
115220
+ if (existingService) {
115221
+ const mergedResult = (0, cloudrun_config_js_1.mergeCloudRunServerConfig)({
115222
+ remote: remoteServerConfig,
115223
+ input: input.serverConfig || {},
115224
+ envParamsReplaceAll: Boolean(input.envParamsReplaceAll),
115225
+ });
115226
+ effectiveServerConfig = mergedResult.merged;
115227
+ mergedFromRemote = mergedResult.mergedFromRemote;
115228
+ }
114964
115229
  const deployParams = {
114965
115230
  serverName: input.serverName,
114966
115231
  targetPath: targetPath,
114967
115232
  force: input.force,
114968
115233
  serverType: serverType,
114969
115234
  };
114970
- // Add server configuration if provided
114971
- if (input.serverConfig) {
114972
- deployParams.serverConfig = input.serverConfig;
115235
+ if (effectiveServerConfig && Object.keys(effectiveServerConfig).length > 0) {
115236
+ deployParams.serverConfig = effectiveServerConfig;
114973
115237
  }
114974
115238
  // Manager SDK create path prefers top-level vpcInfo (CreateCloudRunServer.VpcInfo).
114975
115239
  // Map serverConfig.VpcConf → vpcInfo so first-time create actually binds VPC.
114976
- // Update path still sends Items.VpcConf; platform may ignore VPC changes on existing services.
114977
- const vpcConf = input.serverConfig?.VpcConf;
115240
+ const vpcConf = effectiveServerConfig?.VpcConf;
114978
115241
  if (vpcConf?.VpcId?.trim() && vpcConf?.SubnetId?.trim()) {
114979
115242
  deployParams.vpcInfo = {
114980
115243
  VpcId: vpcConf.VpcId.trim(),
@@ -115005,47 +115268,46 @@ for await (let x of res.textStream) {
115005
115268
  catch (error) {
115006
115269
  (0, logger_js_1.debug)('cloudbaserc.json creation skipped:', error instanceof Error ? error : new Error(String(error)));
115007
115270
  }
115271
+ let preferredAccessUrl;
115272
+ let preferredAccessUrls = [];
115273
+ let preferredAccessSource;
115274
+ let verifiedConfigSnapshot;
115275
+ try {
115276
+ const serviceDetails = await cloudrunService.detail({
115277
+ serverName: input.serverName,
115278
+ });
115279
+ verifiedConfigSnapshot = (0, cloudrun_config_js_1.summarizeConfigSnapshot)(serviceDetails?.ServerConfig);
115280
+ const fallback = resolveCloudRunFallbackAccess(serviceDetails);
115281
+ const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
115282
+ envId: currentEnvId,
115283
+ upstreamResourceName: input.serverName,
115284
+ upstreamResourceTypes: ["CBR"],
115285
+ getManager: async () => {
115286
+ const manager = await getManager();
115287
+ if (!manager) {
115288
+ throw new Error("cloudbase manager unavailable");
115289
+ }
115290
+ return manager;
115291
+ },
115292
+ });
115293
+ const preferred = (0, gateway_access_urls_js_1.preferGatewayOrFallback)({
115294
+ gateway,
115295
+ fallbackUrl: fallback.url,
115296
+ fallbackSource: fallback.source,
115297
+ });
115298
+ preferredAccessUrl = preferred.accessUrl;
115299
+ preferredAccessUrls = preferred.accessUrls;
115300
+ preferredAccessSource = preferred.accessUrlSource;
115301
+ }
115302
+ catch {
115303
+ // best-effort URL enrichment only
115304
+ }
115008
115305
  // Send deployment notification to CodeBuddy IDE
115009
115306
  try {
115010
- // Query service details to get access URL
115011
- let serviceUrl = "";
115012
- try {
115013
- const serviceDetails = await cloudrunService.detail({ serverName: input.serverName });
115014
- // Extract access URL from service details
115015
- // Priority: DefaultDomainName > CustomDomainName > PublicDomain > InternalDomain
115016
- const details = serviceDetails; // Use any to access dynamic properties
115017
- if (details?.BaseInfo?.DefaultDomainName) {
115018
- // DefaultDomainName is already a complete URL (e.g., https://...)
115019
- serviceUrl = details.BaseInfo.DefaultDomainName;
115020
- }
115021
- else if (details?.BaseInfo?.CustomDomainName) {
115022
- // CustomDomainName might be a domain without protocol
115023
- const customDomain = details.BaseInfo.CustomDomainName;
115024
- serviceUrl = customDomain.startsWith('http') ? customDomain : `https://${customDomain}`;
115025
- }
115026
- else if (details?.BaseInfo?.PublicDomain) {
115027
- serviceUrl = `https://${details.BaseInfo.PublicDomain}`;
115028
- }
115029
- else if (details?.BaseInfo?.InternalDomain) {
115030
- serviceUrl = `https://${details.BaseInfo.InternalDomain}`;
115031
- }
115032
- else if (details?.AccessInfo?.PublicDomain) {
115033
- serviceUrl = `https://${details.AccessInfo.PublicDomain}`;
115034
- }
115035
- else {
115036
- serviceUrl = ""; // URL not available
115037
- }
115038
- }
115039
- catch (detailErr) {
115040
- // If query fails, continue with empty URL
115041
- serviceUrl = "";
115042
- }
115043
- // Extract project name from targetPath
115044
115307
  const projectName = path_1.default.basename(targetPath);
115045
- // Send notification
115046
115308
  await (0, notification_js_1.sendDeployNotification)(server, {
115047
115309
  deployType: 'cloudrun',
115048
- url: serviceUrl,
115310
+ url: preferredAccessUrl ?? "",
115049
115311
  projectId: currentEnvId,
115050
115312
  projectName: projectName,
115051
115313
  consoleUrl: consoleUrl
@@ -115056,8 +115318,8 @@ for await (let x of res.textStream) {
115056
115318
  // Error is already logged in sendDeployNotification
115057
115319
  }
115058
115320
  const dbNetworkRisk = detectCloudRunDbNetworkRisk({
115059
- envParams: input.serverConfig?.EnvParams,
115060
- vpcConf: input.serverConfig?.VpcConf,
115321
+ envParams: effectiveServerConfig?.EnvParams,
115322
+ vpcConf: effectiveServerConfig?.VpcConf,
115061
115323
  });
115062
115324
  const warnings = dbNetworkRisk ? [dbNetworkRisk] : [];
115063
115325
  const warningSuffix = dbNetworkRisk
@@ -115076,6 +115338,25 @@ for await (let x of res.textStream) {
115076
115338
  serverType: serverType,
115077
115339
  cloudbasercGenerated: true,
115078
115340
  consoleUrl,
115341
+ ...(existingService
115342
+ ? {
115343
+ configMerge: {
115344
+ existingService: true,
115345
+ mergedFromRemote,
115346
+ appliedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(effectiveServerConfig),
115347
+ ...(verifiedConfigSnapshot
115348
+ ? { verifiedAfterDeploy: verifiedConfigSnapshot }
115349
+ : {}),
115350
+ },
115351
+ }
115352
+ : {}),
115353
+ ...(preferredAccessUrl ? { accessUrl: preferredAccessUrl } : {}),
115354
+ ...(preferredAccessUrls.length > 0
115355
+ ? { accessUrls: preferredAccessUrls }
115356
+ : {}),
115357
+ ...(preferredAccessSource
115358
+ ? { accessUrlSource: preferredAccessSource }
115359
+ : {}),
115079
115360
  ...(warnings.length > 0 ? { warnings } : {}),
115080
115361
  },
115081
115362
  message: `Triggered deployment for ${serverType} service '${input.serverName}' from ${targetPath}. You can follow the progress in ${consoleUrl}.${warningSuffix}`
@@ -115084,6 +115365,125 @@ for await (let x of res.textStream) {
115084
115365
  ]
115085
115366
  };
115086
115367
  }
115368
+ case 'updateConfig': {
115369
+ if (!input.serverConfig || Object.keys(input.serverConfig).length === 0) {
115370
+ throw new Error("serverConfig with at least one field is required for updateConfig");
115371
+ }
115372
+ let remoteServerConfig = {};
115373
+ try {
115374
+ const details = await cloudrunService.detail({
115375
+ serverName: input.serverName,
115376
+ });
115377
+ remoteServerConfig = (details.ServerConfig ||
115378
+ {});
115379
+ }
115380
+ catch (error) {
115381
+ throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, error));
115382
+ }
115383
+ // EnvParams on Diff replaces the whole blob — merge keys unless replaceAll.
115384
+ const dirty = { ...input.serverConfig };
115385
+ if (Object.prototype.hasOwnProperty.call(input.serverConfig, "EnvParams")) {
115386
+ const { merged } = (0, cloudrun_config_js_1.mergeCloudRunServerConfig)({
115387
+ remote: { EnvParams: remoteServerConfig.EnvParams },
115388
+ input: { EnvParams: input.serverConfig.EnvParams },
115389
+ envParamsReplaceAll: Boolean(input.envParamsReplaceAll),
115390
+ });
115391
+ if (merged.EnvParams !== undefined) {
115392
+ dirty.EnvParams = merged.EnvParams;
115393
+ }
115394
+ }
115395
+ let Items;
115396
+ try {
115397
+ Items = (0, cloudrun_config_js_1.parseServerConfigToDiffItems)(dirty);
115398
+ }
115399
+ catch (error) {
115400
+ throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, error));
115401
+ }
115402
+ if (Items.length === 0) {
115403
+ return {
115404
+ content: [
115405
+ {
115406
+ type: "text",
115407
+ text: JSON.stringify({
115408
+ success: true,
115409
+ data: {
115410
+ serviceName: input.serverName,
115411
+ status: "noop",
115412
+ itemsCount: 0,
115413
+ appliedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(dirty),
115414
+ verifiedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(remoteServerConfig),
115415
+ },
115416
+ message: `No effective config changes for '${input.serverName}'.`,
115417
+ }, null, 2),
115418
+ },
115419
+ ],
115420
+ };
115421
+ }
115422
+ const currentEnvId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
115423
+ if (!manager.commonService) {
115424
+ throw new Error("Current CloudBase Manager does not support commonService; cannot call SubmitServerConfigChangeDiff.");
115425
+ }
115426
+ let diffResult;
115427
+ try {
115428
+ diffResult = await manager
115429
+ .commonService("tcbr", "2022-02-17")
115430
+ .call({
115431
+ Action: "SubmitServerConfigChangeDiff",
115432
+ Param: {
115433
+ EnvId: currentEnvId,
115434
+ ServerName: input.serverName,
115435
+ Items,
115436
+ },
115437
+ });
115438
+ }
115439
+ catch (error) {
115440
+ const msg = error instanceof Error ? error.message : String(error);
115441
+ if (/ResourceInUse|task|running|进行中/i.test(msg)) {
115442
+ throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, new Error(`${msg} A deploy or config task may still be running. Wait, then retry; or use queryCloudRun(action="getDeployLog").`)));
115443
+ }
115444
+ throw new Error(buildManageCloudRunErrorMessage("updateConfig", input.serverName, error));
115445
+ }
115446
+ let verifiedConfig = (0, cloudrun_config_js_1.summarizeConfigSnapshot)(remoteServerConfig);
115447
+ try {
115448
+ const after = await cloudrunService.detail({
115449
+ serverName: input.serverName,
115450
+ });
115451
+ verifiedConfig = (0, cloudrun_config_js_1.summarizeConfigSnapshot)(after?.ServerConfig);
115452
+ }
115453
+ catch {
115454
+ // best-effort verify
115455
+ }
115456
+ const likelyRedeploy = (0, cloudrun_config_js_1.listLikelyRedeployFields)(dirty);
115457
+ const consoleUrl = `https://tcb.cloud.tencent.com/dev?envId=${currentEnvId}#/platform-run/service/detail?serverName=${input.serverName}&tabId=overview&envId=${currentEnvId}`;
115458
+ const taskId = diffResult?.TaskId ??
115459
+ diffResult?.Response?.TaskId ??
115460
+ diffResult?.taskId;
115461
+ const redeployHint = likelyRedeploy.length > 0
115462
+ ? ` Fields that often trigger redeploy-with-online-image: ${likelyRedeploy.join(", ")}.`
115463
+ : " Change may apply as a hot update (e.g. MinNum/MaxNum/AccessTypes).";
115464
+ return {
115465
+ content: [
115466
+ {
115467
+ type: "text",
115468
+ text: JSON.stringify({
115469
+ success: true,
115470
+ data: {
115471
+ serviceName: input.serverName,
115472
+ status: "configUpdating",
115473
+ itemsCount: Items.length,
115474
+ itemsKeys: Items.map((i) => i.Key),
115475
+ ...(taskId ? { taskId } : {}),
115476
+ appliedConfig: (0, cloudrun_config_js_1.summarizeConfigSnapshot)(dirty),
115477
+ verifiedConfig,
115478
+ likelyRedeployFields: likelyRedeploy,
115479
+ consoleUrl,
115480
+ },
115481
+ message: `Submitted config change for '${input.serverName}'.${redeployHint} Verify with queryCloudRun(action="detail"). Console: ${consoleUrl}`,
115482
+ }, null, 2),
115483
+ },
115484
+ ],
115485
+ };
115486
+ }
115087
115487
  case 'run': {
115088
115488
  if (!targetPath) {
115089
115489
  throw new Error("targetPath is required for run operation");
@@ -117771,6 +118171,7 @@ const zod_1 = __webpack_require__(21614);
117771
118171
  const cloudbase_manager_js_1 = __webpack_require__(3431);
117772
118172
  const json_content_js_1 = __webpack_require__(4365);
117773
118173
  const cloud_mode_js_1 = __webpack_require__(89684);
118174
+ const gateway_access_urls_js_1 = __webpack_require__(22435);
117774
118175
  const QUERY_APP_ACTIONS = ["listApps", "getApp", "listAppVersions", "getAppVersion", "getBuildLog"];
117775
118176
  const MANAGE_APP_ACTIONS = ["deployApp", "getUploadUrl", "deleteApp", "deleteAppVersion"];
117776
118177
  const APP_FRAMEWORKS = ["vue", "react", "next", "nuxt", "vite", "angular", "static"];
@@ -118147,6 +118548,8 @@ function registerAppTools(server) {
118147
118548
  let appInfo;
118148
118549
  let domain;
118149
118550
  let accessUrl;
118551
+ let accessUrls = [];
118552
+ let accessUrlSource;
118150
118553
  let accessUrlLookupWarning;
118151
118554
  try {
118152
118555
  appInfo = await appService.describeAppInfo({
@@ -118155,9 +118558,34 @@ function registerAppTools(server) {
118155
118558
  });
118156
118559
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, appInfo);
118157
118560
  ({ domain, accessUrl } = normalizeAccessUrlFromDomain(appInfo?.Domain));
118561
+ const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
118562
+ const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
118563
+ envId,
118564
+ upstreamResourceName: serviceName,
118565
+ upstreamResourceTypes: ["STATIC_STORE"],
118566
+ getManager: async () => {
118567
+ const manager = await getManager();
118568
+ if (!manager) {
118569
+ throw new Error("cloudbase manager unavailable");
118570
+ }
118571
+ return manager;
118572
+ },
118573
+ });
118574
+ const preferred = (0, gateway_access_urls_js_1.preferGatewayOrFallback)({
118575
+ gateway,
118576
+ fallbackUrl: accessUrl,
118577
+ fallbackSource: "describeAppInfo.Domain",
118578
+ });
118579
+ accessUrl = preferred.accessUrl;
118580
+ accessUrls = preferred.accessUrls;
118581
+ accessUrlSource = preferred.accessUrlSource;
118158
118582
  }
118159
118583
  catch (error) {
118160
118584
  accessUrlLookupWarning = error instanceof Error ? error.message : String(error);
118585
+ if (accessUrl) {
118586
+ accessUrls = [accessUrl];
118587
+ accessUrlSource = "describeAppInfo.Domain";
118588
+ }
118161
118589
  }
118162
118590
  return (0, json_content_js_1.jsonContent)(buildEnvelope({
118163
118591
  action,
@@ -118166,7 +118594,8 @@ function registerAppTools(server) {
118166
118594
  buildId: BuildId,
118167
118595
  domain,
118168
118596
  accessUrl,
118169
- accessUrlSource: accessUrl ? "describeAppInfo.Domain" : undefined,
118597
+ accessUrls: accessUrls.length > 0 ? accessUrls : undefined,
118598
+ accessUrlSource,
118170
118599
  accessUrlLookupWarning,
118171
118600
  app: appInfo,
118172
118601
  upload: { cosTimestamp: cosTs },
@@ -119540,6 +119969,7 @@ const path_1 = __importDefault(__webpack_require__(39902));
119540
119969
  const zod_1 = __webpack_require__(21614);
119541
119970
  const cloudbase_manager_js_1 = __webpack_require__(3431);
119542
119971
  const cloud_mode_js_1 = __webpack_require__(89684);
119972
+ const gateway_access_urls_js_1 = __webpack_require__(22435);
119543
119973
  const notification_js_1 = __webpack_require__(32720);
119544
119974
  const tool_result_js_1 = __webpack_require__(9835);
119545
119975
  const HOSTING_CDN_SWITCH_VALUES = ['on', 'off'];
@@ -120075,9 +120505,48 @@ function registerHostingTools(server) {
120075
120505
  // StaticDomain there but not in DescribeStaticStore.
120076
120506
  const cdnFromStore = (store.CdnDomain ?? store.StaticDomain);
120077
120507
  const staticDomain = cdnFromStore || await resolveHostingStaticDomain(cloudbase, server.logger);
120078
- const accessUrl = buildHostingAccessUrl(staticDomain, input.cloudPath, input.localPath);
120508
+ const fallbackAccessUrl = buildHostingAccessUrl(staticDomain, input.cloudPath, input.localPath);
120509
+ const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
120510
+ const gatewayCandidates = Array.from(new Set([
120511
+ store.StaticStoreName,
120512
+ store.Name,
120513
+ store.StoreName,
120514
+ store.Bucket,
120515
+ "staticstore",
120516
+ ]
120517
+ .map((item) => (typeof item === "string" ? item.trim() : ""))
120518
+ .filter(Boolean)));
120519
+ let accessUrl = fallbackAccessUrl;
120520
+ let accessUrls = accessUrl ? [accessUrl] : [];
120521
+ let accessUrlSource = accessUrl
120522
+ ? "hosting.staticDomain"
120523
+ : undefined;
120524
+ for (const upstreamName of gatewayCandidates) {
120525
+ const gateway = await (0, gateway_access_urls_js_1.resolveGatewayAccessUrls)({
120526
+ envId,
120527
+ upstreamResourceName: upstreamName,
120528
+ upstreamResourceTypes: ["STATIC_STORE"],
120529
+ getManager: async () => {
120530
+ const manager = await getManager();
120531
+ if (!manager) {
120532
+ throw new Error("cloudbase manager unavailable");
120533
+ }
120534
+ return manager;
120535
+ },
120536
+ });
120537
+ const preferred = (0, gateway_access_urls_js_1.preferGatewayOrFallback)({
120538
+ gateway,
120539
+ fallbackUrl: fallbackAccessUrl || undefined,
120540
+ fallbackSource: "hosting.staticDomain",
120541
+ });
120542
+ if (preferred.accessUrl) {
120543
+ accessUrl = preferred.accessUrl;
120544
+ accessUrls = preferred.accessUrls;
120545
+ accessUrlSource = preferred.accessUrlSource;
120546
+ break;
120547
+ }
120548
+ }
120079
120549
  try {
120080
- const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
120081
120550
  let projectName = 'unknown';
120082
120551
  if (input.localPath) {
120083
120552
  try {
@@ -120112,6 +120581,8 @@ function registerHostingTools(server) {
120112
120581
  ignore: input.ignore,
120113
120582
  staticDomain,
120114
120583
  accessUrl,
120584
+ accessUrls,
120585
+ accessUrlSource,
120115
120586
  result,
120116
120587
  nextActions: uploadPrefix ? [buildFindFilesNextStep(uploadPrefix.replace(/^\/+/, ''))] : undefined,
120117
120588
  },
@@ -133297,71 +133768,6 @@ util.inherits(ArchiverError, Error);
133297
133768
 
133298
133769
  exports = module.exports = ArchiverError;
133299
133770
 
133300
- /***/ }),
133301
-
133302
- /***/ 44760:
133303
- /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
133304
-
133305
- "use strict";
133306
-
133307
- Object.defineProperty(exports, "__esModule", ({ value: true }));
133308
- exports.registerInviteCodeTools = registerInviteCodeTools;
133309
- const zod_1 = __webpack_require__(21614);
133310
- const cloudbase_manager_js_1 = __webpack_require__(3431);
133311
- function registerInviteCodeTools(server) {
133312
- const cloudBaseOptions = server.cloudBaseOptions;
133313
- const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
133314
- server.registerTool?.("activateInviteCode", {
133315
- title: "激活邀请码",
133316
- description: "云开发 AI编程激励计划,通过邀请码激活用户激励。",
133317
- inputSchema: {
133318
- InviteCode: zod_1.z.string().describe("待激活的邀请码")
133319
- },
133320
- annotations: {
133321
- readOnlyHint: false,
133322
- destructiveHint: false,
133323
- idempotentHint: false,
133324
- openWorldHint: true,
133325
- category: "invite-code"
133326
- }
133327
- }, async ({ InviteCode }) => {
133328
- if (!InviteCode) {
133329
- return {
133330
- content: [
133331
- {
133332
- type: "text",
133333
- text: JSON.stringify({
133334
- ErrorCode: 'MissingParameter',
133335
- ErrorMsg: '邀请码为必填项',
133336
- RequestId: ''
133337
- }, null, 2)
133338
- }
133339
- ]
133340
- };
133341
- }
133342
- const manager = await getManager();
133343
- const EnvId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
133344
- const result = await manager.commonService().call({
133345
- Action: 'ActivateInviteCode',
133346
- Param: { InviteCode, EnvId }
133347
- });
133348
- (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
133349
- return {
133350
- content: [
133351
- {
133352
- type: "text",
133353
- text: JSON.stringify({
133354
- ErrorCode: result?.ErrorCode || '',
133355
- ErrorMsg: result?.ErrorMsg || '',
133356
- RequestId: result?.RequestId || ''
133357
- }, null, 2)
133358
- }
133359
- ]
133360
- };
133361
- });
133362
- }
133363
-
133364
-
133365
133771
  /***/ }),
133366
133772
 
133367
133773
  /***/ 44763:
@@ -137273,7 +137679,7 @@ class TelemetryReporter {
137273
137679
  const nodeVersion = process.version; // Node.js版本
137274
137680
  const arch = os_1.default.arch(); // 系统架构
137275
137681
  // 从构建时注入的版本号获取MCP版本信息
137276
- const mcpVersion = process.env.npm_package_version || "2.25.0" || 0;
137682
+ const mcpVersion = process.env.npm_package_version || "2.25.2" || 0;
137277
137683
  return {
137278
137684
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
137279
137685
  deviceId: this.deviceId,
@@ -148242,6 +148648,220 @@ function compileAsync(schema, meta, callback) {
148242
148648
  }
148243
148649
 
148244
148650
 
148651
+ /***/ }),
148652
+
148653
+ /***/ 48266:
148654
+ /***/ ((__unused_webpack_module, exports) => {
148655
+
148656
+ "use strict";
148657
+
148658
+ /**
148659
+ * CloudRun serverConfig merge (RMW) and DiffConfigItem helpers.
148660
+ * Aligns with console SubmitServerConfigChangeDiff field mapping.
148661
+ */
148662
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
148663
+ exports.CONFIG_FIELDS_LIKELY_REDEPLOY = void 0;
148664
+ exports.mergeCloudRunServerConfig = mergeCloudRunServerConfig;
148665
+ exports.assertCpuMemPair = assertCpuMemPair;
148666
+ exports.parseServerConfigToDiffItems = parseServerConfigToDiffItems;
148667
+ exports.summarizeConfigSnapshot = summarizeConfigSnapshot;
148668
+ exports.listLikelyRedeployFields = listLikelyRedeployFields;
148669
+ const SUBMIT_DIFF_MAP = {
148670
+ Cpu: "CpuSpecs",
148671
+ Mem: "MemSpecs",
148672
+ OpenAccessTypes: "AccessTypes",
148673
+ EnvParams: "EnvParam",
148674
+ CustomLogs: "LogPath",
148675
+ };
148676
+ const STRING_KEYS = new Set([
148677
+ "CustomLogs",
148678
+ "EnvParams",
148679
+ "CreateTime",
148680
+ "Dockerfile",
148681
+ "BuildDir",
148682
+ "LogType",
148683
+ "LogSetId",
148684
+ "LogTopicId",
148685
+ "LogParseType",
148686
+ "Tag",
148687
+ "InternalAccess",
148688
+ "InternalDomain",
148689
+ "OperationMode",
148690
+ "SessionAffinity",
148691
+ ]);
148692
+ const INT_KEYS = new Set(["MinNum", "MaxNum", "InitialDelaySeconds", "Port"]);
148693
+ const BOOL_KEYS = new Set(["HasDockerfile"]);
148694
+ const FLOAT_KEYS = new Set(["Cpu", "Mem"]);
148695
+ const ARRAY_KEYS = new Set(["OpenAccessTypes", "EntryPoint", "Cmd"]);
148696
+ function parseEnvParamsObject(raw) {
148697
+ if (!raw || !String(raw).trim()) {
148698
+ return {};
148699
+ }
148700
+ try {
148701
+ const value = JSON.parse(String(raw));
148702
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
148703
+ return {};
148704
+ }
148705
+ const out = {};
148706
+ for (const [k, v] of Object.entries(value)) {
148707
+ if (v === undefined || v === null)
148708
+ continue;
148709
+ out[k] = typeof v === "string" ? v : String(v);
148710
+ }
148711
+ return out;
148712
+ }
148713
+ catch {
148714
+ return {};
148715
+ }
148716
+ }
148717
+ function stringifyEnvParams(obj) {
148718
+ return JSON.stringify(obj);
148719
+ }
148720
+ function isCompleteVpcConf(vpc) {
148721
+ return Boolean(vpc?.VpcId?.trim() && vpc?.SubnetId?.trim());
148722
+ }
148723
+ /**
148724
+ * Merge remote ServerConfig with deploy/update input.
148725
+ * Explicit input wins for provided fields; EnvParams merges by key unless replaceAll.
148726
+ */
148727
+ function mergeCloudRunServerConfig(options) {
148728
+ const remote = options.remote || {};
148729
+ const input = options.input || {};
148730
+ const mergedFromRemote = [];
148731
+ const merged = { ...input };
148732
+ if (isCompleteVpcConf(input.VpcConf)) {
148733
+ merged.VpcConf = {
148734
+ VpcId: input.VpcConf.VpcId.trim(),
148735
+ SubnetId: input.VpcConf.SubnetId.trim(),
148736
+ ...(input.VpcConf.VpcCIDR ? { VpcCIDR: input.VpcConf.VpcCIDR } : {}),
148737
+ ...(input.VpcConf.SubnetCIDR ? { SubnetCIDR: input.VpcConf.SubnetCIDR } : {}),
148738
+ };
148739
+ }
148740
+ else if (isCompleteVpcConf(remote.VpcConf)) {
148741
+ merged.VpcConf = {
148742
+ VpcId: remote.VpcConf.VpcId.trim(),
148743
+ SubnetId: remote.VpcConf.SubnetId.trim(),
148744
+ ...(remote.VpcConf.VpcCIDR ? { VpcCIDR: remote.VpcConf.VpcCIDR } : {}),
148745
+ ...(remote.VpcConf.SubnetCIDR ? { SubnetCIDR: remote.VpcConf.SubnetCIDR } : {}),
148746
+ };
148747
+ mergedFromRemote.push("VpcConf");
148748
+ }
148749
+ else {
148750
+ delete merged.VpcConf;
148751
+ }
148752
+ const inputHasEnv = Object.prototype.hasOwnProperty.call(input, "EnvParams");
148753
+ const remoteEnv = parseEnvParamsObject(remote.EnvParams);
148754
+ const inputEnv = parseEnvParamsObject(input.EnvParams);
148755
+ if (options.envParamsReplaceAll && inputHasEnv) {
148756
+ merged.EnvParams = stringifyEnvParams(inputEnv);
148757
+ }
148758
+ else if (inputHasEnv || Object.keys(remoteEnv).length > 0) {
148759
+ const combined = options.envParamsReplaceAll
148760
+ ? { ...inputEnv }
148761
+ : { ...remoteEnv, ...inputEnv };
148762
+ if (Object.keys(remoteEnv).length > 0 && !options.envParamsReplaceAll) {
148763
+ const preserved = Object.keys(remoteEnv).filter((k) => !(k in inputEnv));
148764
+ if (preserved.length > 0) {
148765
+ mergedFromRemote.push("EnvParams");
148766
+ }
148767
+ }
148768
+ if (Object.keys(combined).length > 0 || inputHasEnv) {
148769
+ merged.EnvParams = stringifyEnvParams(combined);
148770
+ }
148771
+ }
148772
+ // Must be explicit so Manager SDK update path cannot wipe with OA/PUBLIC/MINIAPP defaults.
148773
+ if (Array.isArray(input.OpenAccessTypes) && input.OpenAccessTypes.length > 0) {
148774
+ merged.OpenAccessTypes = [...input.OpenAccessTypes];
148775
+ }
148776
+ else if (Array.isArray(remote.OpenAccessTypes) && remote.OpenAccessTypes.length > 0) {
148777
+ merged.OpenAccessTypes = [...remote.OpenAccessTypes];
148778
+ mergedFromRemote.push("OpenAccessTypes");
148779
+ }
148780
+ return { merged, mergedFromRemote };
148781
+ }
148782
+ function assertCpuMemPair(config) {
148783
+ const hasCpu = config.Cpu !== undefined && config.Cpu !== null;
148784
+ const hasMem = config.Mem !== undefined && config.Mem !== null;
148785
+ if (hasCpu !== hasMem) {
148786
+ throw new Error("Cpu and Mem must be provided together when updating CloudRun config (platform requires the pair).");
148787
+ }
148788
+ }
148789
+ /**
148790
+ * Convert serverConfig object to DiffConfigItem[] for SubmitServerConfigChangeDiff.
148791
+ */
148792
+ function parseServerConfigToDiffItems(data) {
148793
+ assertCpuMemPair(data);
148794
+ const Items = [];
148795
+ for (const [k, v] of Object.entries(data)) {
148796
+ if (v === undefined || v === null)
148797
+ continue;
148798
+ const Key = SUBMIT_DIFF_MAP[k] || k;
148799
+ if (STRING_KEYS.has(k)) {
148800
+ if (v !== "") {
148801
+ Items.push({ Key, Value: String(v) });
148802
+ }
148803
+ }
148804
+ else if (INT_KEYS.has(k)) {
148805
+ Items.push({ Key, IntValue: Number(v) });
148806
+ }
148807
+ else if (BOOL_KEYS.has(k)) {
148808
+ Items.push({ Key, BoolValue: Boolean(v) });
148809
+ }
148810
+ else if (FLOAT_KEYS.has(k)) {
148811
+ Items.push({ Key, FloatValue: Number(v) });
148812
+ }
148813
+ else if (ARRAY_KEYS.has(k)) {
148814
+ Items.push({ Key, ArrayValue: v });
148815
+ }
148816
+ else if (k === "PolicyDetails") {
148817
+ Items.push({ Key, PolicyDetails: v });
148818
+ }
148819
+ else if (k === "TimerScale") {
148820
+ Items.push({ Key, TimerScale: v });
148821
+ }
148822
+ else if (k === "VpcConf") {
148823
+ Items.push({ Key, VpcConf: v });
148824
+ }
148825
+ else if (k === "VolumesConf") {
148826
+ Items.push({ Key, VolumesConf: v });
148827
+ }
148828
+ else if (k === "PublicNetConf") {
148829
+ Items.push({ Key, PublicNetConf: v });
148830
+ }
148831
+ }
148832
+ return Items;
148833
+ }
148834
+ function summarizeConfigSnapshot(config) {
148835
+ const vpc = config?.VpcConf;
148836
+ const envKeys = Object.keys(parseEnvParamsObject(config?.EnvParams));
148837
+ return {
148838
+ hasVpcConf: isCompleteVpcConf(vpc),
148839
+ ...(vpc?.VpcId ? { vpcId: vpc.VpcId } : {}),
148840
+ ...(vpc?.SubnetId ? { subnetId: vpc.SubnetId } : {}),
148841
+ ...(Array.isArray(config?.OpenAccessTypes)
148842
+ ? { openAccessTypes: config.OpenAccessTypes }
148843
+ : {}),
148844
+ envParamKeys: envKeys,
148845
+ };
148846
+ }
148847
+ exports.CONFIG_FIELDS_LIKELY_REDEPLOY = [
148848
+ "VpcConf",
148849
+ "EnvParams",
148850
+ "Cpu",
148851
+ "Mem",
148852
+ "Port",
148853
+ "Dockerfile",
148854
+ "BuildDir",
148855
+ "VolumesConf",
148856
+ "LogType",
148857
+ "LogSetId",
148858
+ "LogTopicId",
148859
+ ];
148860
+ function listLikelyRedeployFields(config) {
148861
+ return exports.CONFIG_FIELDS_LIKELY_REDEPLOY.filter((k) => Object.prototype.hasOwnProperty.call(config, k));
148862
+ }
148863
+
148864
+
148245
148865
  /***/ }),
148246
148866
 
148247
148867
  /***/ 48303:
@@ -197369,7 +197989,7 @@ ${envIdSection}
197369
197989
  ## 环境信息
197370
197990
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
197371
197991
  - Node.js版本: ${process.version}
197372
- - MCP 版本:${process.env.npm_package_version || "2.25.0" || 0}
197992
+ - MCP 版本:${process.env.npm_package_version || "2.25.2" || 0}
197373
197993
  - 系统架构: ${os_1.default.arch()}
197374
197994
  - 时间: ${new Date().toISOString()}
197375
197995
  - 请求ID: ${requestId}
@@ -197450,7 +198070,7 @@ function createWrappedHandler(name, handler, server) {
197450
198070
  requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
197451
198071
  ide: server.ide || process.env.INTEGRATION_IDE || ''
197452
198072
  });
197453
- const mcpVersion = true ? "2.25.0" : 0;
198073
+ const mcpVersion = true ? "2.25.2" : 0;
197454
198074
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
197455
198075
  const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
197456
198076
  // 创建新的错误对象,保持原有的错误类型但更新消息
@@ -214038,7 +214658,7 @@ function registerSetupTools(server) {
214038
214658
  server.registerTool("downloadTemplate", {
214039
214659
  title: "下载项目模板",
214040
214660
  description: `自动下载并部署CloudBase项目模板。
214041
- **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.0" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
214661
+ **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.2" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
214042
214662
  inputSchema: {
214043
214663
  template: zod_1.z
214044
214664
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -231136,6 +231756,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
231136
231756
  exports.registerGatewayTools = registerGatewayTools;
231137
231757
  const zod_1 = __webpack_require__(21614);
231138
231758
  const cloudbase_manager_js_1 = __webpack_require__(3431);
231759
+ const gateway_access_urls_js_1 = __webpack_require__(22435);
231139
231760
  const json_content_js_1 = __webpack_require__(4365);
231140
231761
  const QUERY_GATEWAY_ACTIONS = [
231141
231762
  "listRoutes",
@@ -231211,9 +231832,33 @@ function registerGatewayTools(server) {
231211
231832
  IsDefault: domainItem.IsDefault,
231212
231833
  ...route,
231213
231834
  })));
231214
- const buildRouteUrls = (routes) => Array.from(new Set(routes
231215
- .filter((route) => route.Domain && route.Path)
231216
- .map((route) => `https://${route.Domain}${normalizeAccessPath(String(route.Path))}`)));
231835
+ const buildRouteUrls = (routes) => {
231836
+ const candidates = routes.map((route) => ({
231837
+ Domain: route.Domain,
231838
+ Path: route.Path,
231839
+ IsDefault: route.IsDefault,
231840
+ UpstreamResourceType: route.UpstreamResourceType,
231841
+ UpstreamResourceName: route.UpstreamResourceName,
231842
+ }));
231843
+ return (0, gateway_access_urls_js_1.rankGatewayAccessUrls)(candidates).map((item) => item.url);
231844
+ };
231845
+ const buildAccessUrlFields = (routes) => {
231846
+ const candidates = routes.map((route) => ({
231847
+ Domain: route.Domain,
231848
+ Path: route.Path,
231849
+ IsDefault: route.IsDefault,
231850
+ UpstreamResourceType: route.UpstreamResourceType,
231851
+ UpstreamResourceName: route.UpstreamResourceName,
231852
+ }));
231853
+ const envelope = (0, gateway_access_urls_js_1.toAccessUrlEnvelope)((0, gateway_access_urls_js_1.rankGatewayAccessUrls)(candidates));
231854
+ return {
231855
+ ...(envelope.accessUrl ? { accessUrl: envelope.accessUrl } : {}),
231856
+ accessUrls: envelope.accessUrls,
231857
+ ...(envelope.accessUrlSource
231858
+ ? { accessUrlSource: envelope.accessUrlSource }
231859
+ : {}),
231860
+ };
231861
+ };
231217
231862
  const resolveDefaultHttpDomain = async () => {
231218
231863
  const routeInfo = await listHttpServiceRoutes();
231219
231864
  const domains = routeInfo.Domains ?? [];
@@ -231232,36 +231877,24 @@ function registerGatewayTools(server) {
231232
231877
  }
231233
231878
  return resolveDefaultHttpDomain();
231234
231879
  };
231235
- const mapUpstreamResourceType = (input) => {
231236
- if (input.upstreamResourceType) {
231237
- return input.upstreamResourceType;
231238
- }
231239
- if (input.type === "HTTP") {
231240
- return "WEB_SCF";
231241
- }
231242
- if (input.type === "Event") {
231243
- return "SCF";
231244
- }
231245
- if (input.requiresFunctionType || input.targetType === "function") {
231246
- throw new Error("为云函数创建/更新路由时必须显式提供 type(HTTP→WEB_SCF,Event→SCF)或 route.upstreamResourceType。省略会导致 HTTP 与 Event 函数互相误标,访问时可能返回 FUNCTION_PARAM_INVALID 或网关内部错误。");
231247
- }
231248
- throw new Error("必须提供 route.upstreamResourceType(SCF / WEB_SCF / CBR / STATIC_STORE / LH),或在函数场景提供 type=\"HTTP\"|\"Event\"。");
231880
+ const resolveUpstreamResourceType = (input) => {
231881
+ const resolved = input.routeUpstreamResourceType ?? input.upstreamResourceType;
231882
+ if (resolved) {
231883
+ return resolved;
231884
+ }
231885
+ throw new Error("必须提供 upstreamResourceType(或 route.upstreamResourceType):" +
231886
+ "WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
231887
+ "禁止仅凭 targetName/serviceName 推断上游类型。");
231249
231888
  };
231250
231889
  const normalizeRoutePayload = async (input) => {
231251
231890
  const upstreamResourceName = input.route?.serviceName ?? input.targetName;
231252
231891
  if (!upstreamResourceName) {
231253
- throw new Error("必须提供 targetName 或 route.serviceName 作为上游资源名称(例如云函数名)");
231254
- }
231255
- const isFunctionRoute = input.targetType === "function" ||
231256
- input.type !== undefined ||
231257
- input.route?.upstreamResourceType === "SCF" ||
231258
- input.route?.upstreamResourceType === "WEB_SCF" ||
231259
- (!input.route?.upstreamResourceType && Boolean(input.targetName));
231260
- const upstreamResourceType = mapUpstreamResourceType({
231261
- type: input.type,
231262
- targetType: input.targetType,
231263
- upstreamResourceType: input.route?.upstreamResourceType,
231264
- requiresFunctionType: isFunctionRoute,
231892
+ throw new Error("必须提供 targetName 或 route.serviceName 作为上游资源名称:" +
231893
+ "云函数名、云托管服务名,或静态托管实例名(常见为 staticstore)。");
231894
+ }
231895
+ const upstreamResourceType = resolveUpstreamResourceType({
231896
+ upstreamResourceType: input.upstreamResourceType,
231897
+ routeUpstreamResourceType: input.route?.upstreamResourceType,
231265
231898
  });
231266
231899
  const path = normalizeAccessPath(input.route?.path ?? input.path ?? `/${upstreamResourceName}`);
231267
231900
  const domain = await resolveRouteDomain(input.domain);
@@ -231270,18 +231903,25 @@ function registerGatewayTools(server) {
231270
231903
  : input.auth !== undefined
231271
231904
  ? input.auth
231272
231905
  : undefined;
231906
+ const enablePathTransmission = input.route?.enablePathTransmission !== undefined
231907
+ ? input.route.enablePathTransmission
231908
+ : input.enablePathTransmission !== undefined
231909
+ ? input.enablePathTransmission
231910
+ : undefined;
231911
+ const route = {
231912
+ Path: path,
231913
+ UpstreamResourceType: upstreamResourceType,
231914
+ UpstreamResourceName: upstreamResourceName,
231915
+ EnableAuth: enableAuth,
231916
+ };
231917
+ if (enablePathTransmission !== undefined) {
231918
+ route.EnablePathTransmission = enablePathTransmission;
231919
+ }
231273
231920
  return {
231274
231921
  EnvId: await resolveEnvId(),
231275
231922
  Domain: {
231276
231923
  Domain: domain,
231277
- Routes: [
231278
- {
231279
- Path: path,
231280
- UpstreamResourceType: upstreamResourceType,
231281
- UpstreamResourceName: upstreamResourceName,
231282
- EnableAuth: enableAuth,
231283
- },
231284
- ],
231924
+ Routes: [route],
231285
231925
  },
231286
231926
  resolved: {
231287
231927
  domain,
@@ -231289,6 +231929,7 @@ function registerGatewayTools(server) {
231289
231929
  upstreamResourceType,
231290
231930
  upstreamResourceName,
231291
231931
  enableAuth,
231932
+ enablePathTransmission,
231292
231933
  },
231293
231934
  };
231294
231935
  };
@@ -231328,6 +231969,7 @@ function registerGatewayTools(server) {
231328
231969
  action: input.action,
231329
231970
  routes,
231330
231971
  urls: buildRouteUrls(routes),
231972
+ ...buildAccessUrlFields(routes),
231331
231973
  total: result.TotalCount ?? routes.length,
231332
231974
  raw: result,
231333
231975
  }, `已获取 ${result.TotalCount ?? routes.length} 条 HTTP 路由`);
@@ -231369,6 +232011,7 @@ function registerGatewayTools(server) {
231369
232011
  routes: matches,
231370
232012
  total: matches.length,
231371
232013
  urls,
232014
+ ...buildAccessUrlFields(matches),
231372
232015
  raw: result,
231373
232016
  }, matches.length === 0
231374
232017
  ? "未找到对应路由"
@@ -231402,9 +232045,10 @@ function registerGatewayTools(server) {
231402
232045
  const message = err instanceof Error ? err.message : String(err);
231403
232046
  if (message.includes("An error has occurred")) {
231404
232047
  let hint = "为目标资源配置访问路由失败(后端内部错误)。请确保:1) 目标云函数已成功创建并处于 Active 状态;2) 环境默认 HTTP 域名已完成初始化(IsDefault);3) 该访问路径未被占用。";
231405
- if (input.type === "HTTP") {
232048
+ if (payload.resolved.upstreamResourceType === "WEB_SCF" ||
232049
+ payload.resolved.upstreamResourceType === "SCF") {
231406
232050
  hint +=
231407
- "此外注意:如果目标函数最初是作为 Event 函数创建的,这里 type 仍必须传 Event(UpstreamResourceType=SCF);误传 HTTP/WEB_SCF 会导致此错误。";
232051
+ "此外注意:HTTP 云函数必须用 upstreamResourceType=WEB_SCF,Event 云函数必须用 SCF;互标会导致此错误。";
231408
232052
  }
231409
232053
  throw new Error(`${hint} 原始错误:${message}`);
231410
232054
  }
@@ -231414,15 +232058,26 @@ function registerGatewayTools(server) {
231414
232058
  return buildEnvelope({
231415
232059
  action: input.action,
231416
232060
  model: "httpServiceRoute",
231417
- targetType: input.targetType ?? null,
231418
232061
  targetName: payload.resolved.upstreamResourceName,
231419
232062
  domain: payload.resolved.domain,
231420
232063
  path: payload.resolved.path,
231421
232064
  upstreamResourceType: payload.resolved.upstreamResourceType,
231422
232065
  upstreamResourceName: payload.resolved.upstreamResourceName,
231423
232066
  auth: payload.resolved.enableAuth ?? null,
232067
+ enablePathTransmission: payload.resolved.enablePathTransmission ?? null,
232068
+ accessUrl: `https://${payload.resolved.domain}${payload.resolved.path}`,
232069
+ accessUrls: [`https://${payload.resolved.domain}${payload.resolved.path}`],
232070
+ accessUrlSource: input.domain && input.domain === payload.resolved.domain
232071
+ ? "gateway.custom"
232072
+ : "gateway.default",
231424
232073
  raw: result,
231425
- }, `已为目标 ${payload.resolved.upstreamResourceName} 在域名 ${payload.resolved.domain} 创建路由 ${payload.resolved.path}(${payload.resolved.upstreamResourceType})。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`, routeMutationNextActions(payload.resolved.upstreamResourceName));
232074
+ }, `已为目标 ${payload.resolved.upstreamResourceName} 在域名 ${payload.resolved.domain} 创建路由 ${payload.resolved.path}(${payload.resolved.upstreamResourceType})` +
232075
+ (payload.resolved.enablePathTransmission === true
232076
+ ? ";已开启路径透传(后端收到完整请求路径)"
232077
+ : payload.resolved.enablePathTransmission === false
232078
+ ? ";路径透传关闭(网关会剥掉触发路径前缀后再转发给后端)"
232079
+ : ";路径透传未显式设置(平台默认 false,会剥掉触发路径前缀)") +
232080
+ `。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开上游权限;若上游是云函数且需要匿名或浏览器直接访问,请继续检查函数资源权限。`, routeMutationNextActions(payload.resolved.upstreamResourceName));
231426
232081
  }
231427
232082
  case "updateRoute": {
231428
232083
  const cloudbase = await getManager();
@@ -231440,8 +232095,20 @@ function registerGatewayTools(server) {
231440
232095
  upstreamResourceType: payload.resolved.upstreamResourceType,
231441
232096
  upstreamResourceName: payload.resolved.upstreamResourceName,
231442
232097
  auth: payload.resolved.enableAuth ?? null,
232098
+ enablePathTransmission: payload.resolved.enablePathTransmission ?? null,
232099
+ accessUrl: `https://${payload.resolved.domain}${payload.resolved.path}`,
232100
+ accessUrls: [`https://${payload.resolved.domain}${payload.resolved.path}`],
232101
+ accessUrlSource: input.domain && input.domain === payload.resolved.domain
232102
+ ? "gateway.custom"
232103
+ : "gateway.default",
231443
232104
  raw: result,
231444
- }, `HTTP 路由更新成功(${payload.resolved.domain}${payload.resolved.path})`, routeMutationNextActions(payload.resolved.upstreamResourceName));
232105
+ }, `HTTP 路由更新成功(${payload.resolved.domain}${payload.resolved.path}` +
232106
+ (payload.resolved.enablePathTransmission === true
232107
+ ? ",路径透传=开启"
232108
+ : payload.resolved.enablePathTransmission === false
232109
+ ? ",路径透传=关闭"
232110
+ : "") +
232111
+ `)`, routeMutationNextActions(payload.resolved.upstreamResourceName));
231445
232112
  }
231446
232113
  case "deleteRoute": {
231447
232114
  const routePath = input.route?.path ?? input.path;
@@ -231507,19 +232174,17 @@ function registerGatewayTools(server) {
231507
232174
  };
231508
232175
  server.registerTool?.("queryGateway", {
231509
232176
  title: "查询 CloudBase 网关",
231510
- description: "CloudBase 网关统一只读入口(Domain/Route 模型)。通过 listRoutes / getRoute / listCustomDomains 查询域名与路由;主键为 Domain + Path,上游类型为 SCF / WEB_SCF / CBR / STATIC_STORE / LH。",
232177
+ description: "CloudBase HTTP 网关统一只读入口(Domain/Route)。查询域名下路径路由及其上游:" +
232178
+ "WEB_SCF/SCF=云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
232179
+ "主键为 Domain + Path;listRoutes / getRoute / listCustomDomains。",
231511
232180
  inputSchema: {
231512
232181
  action: zod_1.z
231513
232182
  .enum(QUERY_GATEWAY_ACTIONS)
231514
232183
  .describe("只读操作类型:listRoutes、getRoute、listCustomDomains"),
231515
- targetType: zod_1.z
231516
- .enum(["function"])
231517
- .optional()
231518
- .describe("目标资源类型。当前支持 function"),
231519
232184
  targetName: zod_1.z
231520
232185
  .string()
231521
232186
  .optional()
231522
- .describe("上游资源名称。getRoute 时可按云函数名过滤"),
232187
+ .describe("上游资源名过滤(UpstreamResourceName):云函数名、云托管服务名,或静态托管实例名(常见 staticstore)。"),
231523
232188
  routeId: zod_1.z.string().optional().describe("路由 ID。getRoute 时可选"),
231524
232189
  path: zod_1.z
231525
232190
  .string()
@@ -231538,40 +232203,68 @@ function registerGatewayTools(server) {
231538
232203
  }, async (input) => withEnvelope(() => handleQueryGateway(input)));
231539
232204
  server.registerTool?.("manageGateway", {
231540
232205
  title: "管理 CloudBase 网关",
231541
- description: "CloudBase 网关统一写入口(Domain/Route 模型)。为已存在的 HTTP 云函数补默认域名访问时,使用 createRoute,并提供 targetType=\"function\"、targetName、type=\"HTTP\"(映射 WEB_SCF)与期望 path;Event 函数传 type=\"Event\"(映射 SCF)。未传 domain 时自动解析 IsDefault 默认域名。注意 createRoute 只创建网关入口,不会自动修改函数资源权限。更新鉴权用 updateRoute;删除用 deleteRoute(Domain+Path)。⚠️ 绑定带 SSL 证书的自定义域名用 bindCustomDomain;CORS/安全域名请使用 envDomainManagement。",
232206
+ description: "CloudBase HTTP 网关统一写入口(Domain/Route)。createRoute/updateRoute/deleteRoute 把域名下的 path 转到上游;未传 domain 时用 IsDefault 默认域名。" +
232207
+ "上游类型只用一个参数 upstreamResourceType(也可写在 route.upstreamResourceType,route 优先):" +
232208
+ "WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器;" +
232209
+ "配合 targetName 或 route.serviceName(云函数名/云托管服务名/静态托管实例名,常见 staticstore)。" +
232210
+ "createRoute 只建网关入口,不改上游权限。" +
232211
+ "enablePathTransmission:默认 false 剥触发路径前缀;true 透传完整路径(CBR 多路由、WEB_SCF 自管子路径常需 true;STATIC_STORE 自定义触发路径映射站点根通常 false)。" +
232212
+ "⚠️ SSL 自定义域名用 bindCustomDomain;CORS/安全域名用 envDomainManagement。",
231542
232213
  inputSchema: {
231543
232214
  action: zod_1.z
231544
232215
  .enum(MANAGE_GATEWAY_ACTIONS)
231545
- .describe("写操作类型。为已有函数补默认域名访问入口时使用 createRoute;函数场景必须显式提供 type(HTTP→WEB_SCF,Event→SCF)或 route.upstreamResourceType。"),
231546
- targetType: zod_1.z
231547
- .enum(["function"])
231548
- .optional()
231549
- .describe("目标资源类型。当前支持 function"),
232216
+ .describe("写操作:createRoute/updateRoute/deleteRoute 管理路由;bindCustomDomain/deleteCustomDomain 管理自定义域名。" +
232217
+ "createRoute/updateRoute 必须提供 upstreamResourceType。"),
231550
232218
  targetName: zod_1.z
231551
232219
  .string()
231552
232220
  .optional()
231553
- .describe("目标资源名称。createRoute 到云函数时填写函数名"),
232221
+ .describe("上游资源名称(UpstreamResourceName),与 route.serviceName 二选一(route 优先)。" +
232222
+ "云函数=函数名;云托管=服务名;静态托管=实例名(常见 staticstore)。不会自动推断上游类型。"),
231554
232223
  path: zod_1.z
231555
232224
  .string()
231556
232225
  .optional()
231557
- .describe("访问路径,默认 /{targetName}。例如为 HTTP 函数暴露 /api/hello 时传 /api/hello。该参数只创建网关入口,不会自动放开函数资源权限。"),
231558
- type: zod_1.z
231559
- .enum(["Event", "HTTP"])
232226
+ .describe("触发路径(网关匹配前缀),默认 /{上游名}。例:云函数 /api/hello、云托管 /api、静态托管 / 或 /app。" +
232227
+ "只建网关入口;与 enablePathTransmission 共同决定上游实际收到的路径。"),
232228
+ upstreamResourceType: zod_1.z
232229
+ .enum(UPSTREAM_RESOURCE_TYPES)
231560
232230
  .optional()
231561
- .describe("目标函数运行时类型,不是接入协议。HTTP 云函数传 HTTP(UpstreamResourceType=WEB_SCF);Event 函数传 Event(SCF)。误标会导致 FUNCTION_PARAM_INVALID 或网关错误。函数路由场景必须显式提供 type 或 route.upstreamResourceType。"),
232231
+ .describe("上游类型(与 route.upstreamResourceType 二选一,route 优先)。" +
232232
+ "WEB_SCF=HTTP云函数,SCF=Event云函数,CBR=云托管,STATIC_STORE=静态托管,LH=轻量应用服务器。" +
232233
+ "createRoute/updateRoute 必填其一;勿把 manageFunctions 的 type=HTTP|Event 传到本字段。"),
231562
232234
  auth: zod_1.z
231563
232235
  .boolean()
231564
232236
  .optional()
231565
- .describe("是否开启网关路径鉴权(EnableAuth)。若要走默认域名做匿名或浏览器访问,通常设为 false;该开关仅控制网关入口本身,不会修改函数资源权限。"),
232237
+ .describe("网关路径鉴权(EnableAuth)。匿名/浏览器公网访问通常 false。" +
232238
+ "只控制网关入口;云函数安全规则、云托管鉴权、静态托管权限需各自工具另行配置。"),
232239
+ enablePathTransmission: zod_1.z
232240
+ .boolean()
232241
+ .optional()
232242
+ .describe("路径透传(EnablePathTransmission),平台默认 false。例 path=/api 且请求 /api/users:" +
232243
+ "false→上游收到 /users;true→上游收到 /api/users。" +
232244
+ "CBR 云托管(Express 等自管子路由)与 WEB_SCF 多路径函数常需 true;" +
232245
+ "STATIC_STORE 把触发路径映射到站点根目录(如 /app → 托管 /)时通常 false;" +
232246
+ "单入口/根路径处理保持 false。也可用 route.enablePathTransmission(route 优先)。"),
231566
232247
  route: zod_1.z
231567
232248
  .object({
231568
232249
  path: zod_1.z.string().optional(),
231569
- serviceName: zod_1.z.string().optional(),
231570
- upstreamResourceType: zod_1.z.enum(UPSTREAM_RESOURCE_TYPES).optional(),
232250
+ serviceName: zod_1.z
232251
+ .string()
232252
+ .optional()
232253
+ .describe("上游实例名:云函数名 / 云托管服务名 / 静态托管实例名(常见 staticstore)/ LH 实例。优先于顶层 targetName。"),
232254
+ upstreamResourceType: zod_1.z
232255
+ .enum(UPSTREAM_RESOURCE_TYPES)
232256
+ .optional()
232257
+ .describe("同顶层 upstreamResourceType。route 内设置时优先于顶层。"),
231571
232258
  auth: zod_1.z.boolean().optional(),
232259
+ enablePathTransmission: zod_1.z
232260
+ .boolean()
232261
+ .optional()
232262
+ .describe("同顶层 enablePathTransmission。route 内设置时优先于顶层。"),
231572
232263
  })
231573
232264
  .optional()
231574
- .describe("HTTP 路由配置。upstreamResourceType 可选 SCF / WEB_SCF / CBR / STATIC_STORE / LH"),
232265
+ .describe("路由对象(可选写法)。例:云函数 {upstreamResourceType:\"WEB_SCF\",serviceName:\"fn\",path:\"/api\"};" +
232266
+ "云托管 {upstreamResourceType:\"CBR\",serviceName:\"svc\",path:\"/api\"};" +
232267
+ "静态托管 {upstreamResourceType:\"STATIC_STORE\",serviceName:\"staticstore\",path:\"/\"}。"),
231575
232268
  domain: zod_1.z
231576
232269
  .string()
231577
232270
  .optional()