@cloudbase/cloudbase-mcp 2.34.1 → 2.34.3
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 +5 -5
- package/dist/index.cjs +316 -70
- package/dist/index.js +316 -70
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -201380,6 +201380,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
201380
201380
|
getSuccess: "CloudBase 应用详情查询成功",
|
|
201381
201381
|
listVersionsSuccess: "CloudBase 应用版本列表查询成功",
|
|
201382
201382
|
buildIdRequired: "action=getBuildLog 时必须提供 buildId",
|
|
201383
|
+
buildIdMustBeNumeric: "buildId 必须是数字(云 API DescribeCloudBaseRunBuildLog 的 BuildId 为整数)。收到的值:{buildId}。请使用部署回执或 getAppVersion 返回的 BuildId。",
|
|
201383
201384
|
buildLogFound: "查询到 {count} 条构建日志",
|
|
201384
201385
|
buildLogEmpty: "暂无构建日志",
|
|
201385
201386
|
nextStepQueryBuildLog: "查询构建日志",
|
|
@@ -201451,6 +201452,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
201451
201452
|
getSuccess: "CloudBase app details retrieved successfully",
|
|
201452
201453
|
listVersionsSuccess: "CloudBase app version list retrieved successfully",
|
|
201453
201454
|
buildIdRequired: "buildId is required when action=getBuildLog",
|
|
201455
|
+
buildIdMustBeNumeric: "buildId must be numeric (the BuildId of the cloud API DescribeCloudBaseRunBuildLog is an integer). Received: {buildId}. Use the BuildId returned by the deploy response or getAppVersion.",
|
|
201454
201456
|
buildLogFound: "Retrieved {count} build log entries",
|
|
201455
201457
|
buildLogEmpty: "No build logs yet",
|
|
201456
201458
|
nextStepQueryBuildLog: "Query build logs",
|
|
@@ -202710,7 +202712,7 @@ exports.env = (0, types_js_1.defineModule)({
|
|
|
202710
202712
|
"auth.deviceCodeMissing": "未获取到设备码信息,请重试设备码登录",
|
|
202711
202713
|
"auth.deviceStarted": "已发起设备码登录,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。授权完成后请再次调用 auth(action=\"status\")。",
|
|
202712
202714
|
"auth.loginStateMissing": "未获取到登录态,请先完成认证",
|
|
202713
|
-
"auth.apiKeyArgsRequired": "action=login_by_api_key 时必须同时提供 apiKey 和
|
|
202715
|
+
"auth.apiKeyArgsRequired": "action=login_by_api_key 时必须同时提供 apiKey 和 apiKeyEnvId。",
|
|
202714
202716
|
"auth.apiKeySuccess": "API Key 认证成功,已获取临时密钥。",
|
|
202715
202717
|
"auth.apiKeyExchangeFailed": "API Key 换取临时密钥失败。",
|
|
202716
202718
|
"auth.apiKeyDiagLogin": "\n\n诊断信息:\n- CLOUDBASE_ENV_ID: {envId}\n- CLOUDBASE_API_KEY: {apiKeyPrefix}...(已截断)\n- TCB_SITE: {site}\n\n可能原因:\n1. API Key 已过期或被删除\n2. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配\n3. API Key 与站点不匹配:国际站环境的 Key 需配置 TCB_SITE=intl(走 ap-singapore 网关);国内站环境(含 ap-guangzhou/ap-singapore 地域)不要配置 intl\n4. 网络连接问题\n\n建议:请检查 API Key 和环境 ID 是否正确。",
|
|
@@ -202923,7 +202925,7 @@ exports.env = (0, types_js_1.defineModule)({
|
|
|
202923
202925
|
"auth.deviceCodeMissing": "No device code info was returned; please retry device-code login",
|
|
202924
202926
|
"auth.deviceStarted": "Device-code login started. Open verification_uri in the browser and enter user_code to complete the authorization. Once authorized, call auth(action=\"status\") again.",
|
|
202925
202927
|
"auth.loginStateMissing": "No login state was obtained; please complete authentication first",
|
|
202926
|
-
"auth.apiKeyArgsRequired": "Both apiKey and
|
|
202928
|
+
"auth.apiKeyArgsRequired": "Both apiKey and apiKeyEnvId must be provided when action=login_by_api_key.",
|
|
202927
202929
|
"auth.apiKeySuccess": "API Key authentication succeeded; temporary credentials obtained.",
|
|
202928
202930
|
"auth.apiKeyExchangeFailed": "Failed to exchange the API Key for temporary credentials.",
|
|
202929
202931
|
"auth.apiKeyDiagLogin": "\n\nDiagnostics:\n- CLOUDBASE_ENV_ID: {envId}\n- CLOUDBASE_API_KEY: {apiKeyPrefix}... (truncated)\n- TCB_SITE: {site}\n\nPossible causes:\n1. The API Key has expired or was deleted\n2. CLOUDBASE_ENV_ID does not match the environment the API Key belongs to\n3. The API Key does not match the site: keys for international-site environments need TCB_SITE=intl (routed via the ap-singapore gateway); do not set intl for domestic-site environments (including the ap-guangzhou/ap-singapore regions)\n4. Network connectivity issue\n\nSuggestion: check that the API Key and environment ID are correct.",
|
|
@@ -203585,6 +203587,9 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
203585
203587
|
"create.backendError": "为目标资源配置访问路由失败(后端内部错误)。请确保:1) 目标云函数已成功创建并处于 Active 状态;2) 环境默认 HTTP 域名已完成初始化(IsDefault);3) 该访问路径未被占用。",
|
|
203586
203588
|
"create.backendErrorScfHint": "此外注意:HTTP 云函数必须用 upstreamResourceType=WEB_SCF,Event 云函数必须用 SCF;互标会导致此错误。",
|
|
203587
203589
|
"create.backendErrorSuffix": " 原始错误:{message}",
|
|
203590
|
+
"create.upstreamNotFound": "createRoute 未执行:上游目标不存在。upstreamResourceType={type}、targetName={name} 在环境中未找到,未创建任何路由。请先创建该资源(或核对名称/类型),再重新调用 createRoute。",
|
|
203591
|
+
"create.upstreamCandidates": "当前环境已有的 {type} 目标(最多 10 个,供核对名称):{candidates}",
|
|
203592
|
+
"create.upstreamNotFoundReason": "核对上游资源名称与 upstreamResourceType 后重试 createRoute",
|
|
203588
203593
|
"create.privilegeOffHint": "⚠️ HTTP 网关总开关未开启,路由创建成功后访问仍将返回 HTTPSERVICE_NONACTIVATED(403);请先调用 manageGateway(action=\"enableService\", enable=true) 开启,再立刻探测 accessUrl(通常数秒到约 30 秒内生效,勿盲等 60 秒以上)。",
|
|
203589
203594
|
"create.privilegeOffReason": "开启 HTTP 网关总开关(EnableService),否则访问路由会报 HTTPSERVICE_NONACTIVATED(403)",
|
|
203590
203595
|
"create.privilegeUnknownHint": "(无法确认 HTTP 网关开关状态;若访问报 HTTPSERVICE_NONACTIVATED,请用 queryGateway(action=\"getPrivilege\") 查询后用 manageGateway(action=\"enableService\") 开启)",
|
|
@@ -203670,6 +203675,9 @@ exports.gateway = (0, types_js_1.defineModule)({
|
|
|
203670
203675
|
"create.backendError": "Failed to configure the access route for the target resource (backend internal error). Ensure: 1) the target cloud function is created and Active; 2) the env default HTTP domain is initialized (IsDefault); 3) the access path is not taken.",
|
|
203671
203676
|
"create.backendErrorScfHint": "Also note: HTTP cloud functions must use upstreamResourceType=WEB_SCF, Event cloud functions must use SCF; swapping them causes this error.",
|
|
203672
203677
|
"create.backendErrorSuffix": " Original error: {message}",
|
|
203678
|
+
"create.upstreamNotFound": "createRoute skipped: the upstream target does not exist. upstreamResourceType={type}, targetName={name} was not found in this environment; no route was created. Create the resource (or fix the name/type), then call createRoute again.",
|
|
203679
|
+
"create.upstreamCandidates": "Existing {type} targets in this environment (up to 10, for name verification): {candidates}",
|
|
203680
|
+
"create.upstreamNotFoundReason": "Verify the upstream resource name and upstreamResourceType, then retry createRoute",
|
|
203673
203681
|
"create.privilegeOffHint": "⚠️ The HTTP gateway master switch is off; after the route is created, access will still return HTTPSERVICE_NONACTIVATED (403). Call manageGateway(action=\"enableService\", enable=true) first, then probe accessUrl immediately (usually takes effect within a few seconds to ~30 seconds; do not wait 60+ seconds).",
|
|
203674
203682
|
"create.privilegeOffReason": "Turn on the HTTP gateway master switch (EnableService), otherwise accessing the route returns HTTPSERVICE_NONACTIVATED (403)",
|
|
203675
203683
|
"create.privilegeUnknownHint": " (Could not confirm the HTTP gateway switch status; if access returns HTTPSERVICE_NONACTIVATED, query via queryGateway(action=\"getPrivilege\") and enable via manageGateway(action=\"enableService\"))",
|
|
@@ -204157,9 +204165,9 @@ exports.permissions = void 0;
|
|
|
204157
204165
|
const types_js_1 = __webpack_require__(89921);
|
|
204158
204166
|
exports.permissions = (0, types_js_1.defineModule)({
|
|
204159
204167
|
queryTitle: "查询 CloudBase 权限与用户配置",
|
|
204160
|
-
queryDescription: "查询 CloudBase 权限与用户配置,支持查询资源权限(数据库/云函数/存储桶等)、角色列表/详情、应用用户列表/详情,以及网关 OPA 授权策略(对齐 CLI `tcb policy list/get`)。\n\n示例:\n- 查询存储桶权限:`action=\"getResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\"`\n- 列出旧网关策略:`action=\"listPolicy\"`(PG / OPA 引擎环境返回空列表,与 CLI 一致)\n- 读取用户 Rego:`action=\"getPolicy\"`;平台扩展策略:`action=\"getPolicy\", extension=true`\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`。`resourceType=\"noSqlDatabase\"` 查询的是 CloudBase NoSQL 集合规则,与 CloudBase PostgreSQL(PG)表的行级安全(RLS)是两套独立机制——同一个 PG 环境里 NoSQL 集合若仍在使用,对那些集合查询本工具结果**仍然有效**。要查 PG 表 RLS,请改用 `queryPgDatabase(action=\"sql\", sql=\"SELECT * FROM pg_policies WHERE tablename=...\")`。本工具不涉及 MySQL 权限。\n\n⚠️ PostgreSQL 环境:平台 `DescribeResourcePermission` 对 PG 环境会直接拒绝。当 `resourceType=\"function\"` 时,本工具会自动回退到 Manager SDK `describeEnvAuthzConfig`(与 CLI `tcb policy get` 一致,读取 `authz.user.rego`)。显式 OPA 策略请用 `listPolicy` / `getPolicy
|
|
204168
|
+
queryDescription: "查询 CloudBase 权限与用户配置,支持查询资源权限(数据库/云函数/存储桶等)、角色列表/详情、应用用户列表/详情,以及网关 OPA 授权策略(对齐 CLI `tcb policy list/get`)。\n\n示例:\n- 查询存储桶权限:`action=\"getResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\"`\n- 列出旧网关策略:`action=\"listPolicy\"`(PG / OPA 引擎环境返回空列表,与 CLI 一致)\n- 读取用户 Rego:`action=\"getPolicy\"`;平台扩展策略:`action=\"getPolicy\", extension=true`\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`。`resourceType=\"noSqlDatabase\"` 查询的是 CloudBase NoSQL 集合规则,与 CloudBase PostgreSQL(PG)表的行级安全(RLS)是两套独立机制——同一个 PG 环境里 NoSQL 集合若仍在使用,对那些集合查询本工具结果**仍然有效**。要查 PG 表 RLS,请改用 `queryPgDatabase(action=\"sql\", sql=\"SELECT * FROM pg_policies WHERE tablename=...\")`。本工具不涉及 MySQL 权限。\n\n⚠️ PostgreSQL 环境:平台 `DescribeResourcePermission` 对 PG 环境会直接拒绝。当 `resourceType=\"function\"` 时,本工具会自动回退到 Manager SDK `describeEnvAuthzConfig`(与 CLI `tcb policy get` 一致,读取 `authz.user.rego`)。显式 OPA 策略请用 `listPolicy` / `getPolicy`。\n\n⚠️ 角色类 action(`listRoles` / `getRole`)在 **PostgreSQL 类型环境**下平台侧一律拒绝(`The current API does not support PostgreSQL type environments.`)——这是平台能力边界,不是配置问题,**不要在 PG 环境反复重试**;PG 环境请改用 RLS(`managePgDatabase(action=\"execute\")` 跑 `CREATE POLICY`)或控制台管理权限。",
|
|
204161
204169
|
manageTitle: "管理 CloudBase 权限与用户配置",
|
|
204162
|
-
manageDescription: "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD,以及设置网关 OPA Rego 策略(对齐 CLI `tcb policy set`)。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n- 放开云函数匿名/未登录访问(PG 会走 OPA,对齐 CLI `tcb policy set`):`action=\"updateResourcePermission\", resourceType=\"function\", resourceId=\"myFn\", permission=\"CUSTOM\", securityRule='{\"invoke\":true}'`\n- 直接设置用户 Rego:`action=\"setPolicy\", regoContent=\"package authz.user\\n\\ndefault allow := false\\n\", confirm=true`(⚠️ 立即禁用旧网关鉴权)\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。直接在浏览器里用 `auth.signUp` 创建用户名密码用户取决于 SDK/provider 支持,使用前必须验证;不支持时应走后端或管理端边界,不能在浏览器暴露密钥。`securityRule` 的详细语义取决于 `resourceType`:`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则;配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`:\n- `resourceType=\"noSqlDatabase\"` 仅作用于 CloudBase NoSQL 文档数据库的集合;CloudBase PostgreSQL(PG)表的行级权限**不**受它控制——PG 表请改用 RLS:`managePgDatabase(action=\"execute\", confirm=true)` 跑 `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` 与 `CREATE POLICY ...`。同一个 PG 环境里如果还有 NoSQL 集合在用,对那些**集合**继续使用 `noSqlDatabase` 规则是正确的——不是\"PG 环境就禁用本工具\"。\n- `resourceType=\"storage\"` 控制的是 NoSQL/COS 存储桶 ACL;PG 的 `pgstore` bucket 不在此 `resourceType` 覆盖范围内。\n- 本工具不涉及 MySQL;MySQL 数据库权限请走 MySQL 自身的 GRANT/REVOKE 语句(通过 `manageMysqlDatabase`)。\n\n⚠️ PostgreSQL 环境:平台 `ModifyResourcePermission` 对 PG 环境会直接拒绝。当 `resourceType=\"function\"` 时,本工具会自动回退到 Manager SDK `modifyEnvAuthzConfig`(与 CLI `tcb policy set` 一致,写入 `authz.user.rego`)。`securityRule` 可传完整 Rego(`package authz.user`)或 `'{\"invoke\":true}'`(自动生成放通 anonymous/unauthenticated 调 functions 的策略)。设置 Rego 后旧网关鉴权会失效,行为与 CLI 相同。显式 OPA 策略请优先用 `action=\"setPolicy\"
|
|
204170
|
+
manageDescription: "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD,以及设置网关 OPA Rego 策略(对齐 CLI `tcb policy set`)。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n- 放开云函数匿名/未登录访问(PG 会走 OPA,对齐 CLI `tcb policy set`):`action=\"updateResourcePermission\", resourceType=\"function\", resourceId=\"myFn\", permission=\"CUSTOM\", securityRule='{\"invoke\":true}'`\n- 直接设置用户 Rego:`action=\"setPolicy\", regoContent=\"package authz.user\\n\\ndefault allow := false\\n\", confirm=true`(⚠️ 立即禁用旧网关鉴权)\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。直接在浏览器里用 `auth.signUp` 创建用户名密码用户取决于 SDK/provider 支持,使用前必须验证;不支持时应走后端或管理端边界,不能在浏览器暴露密钥。`securityRule` 的详细语义取决于 `resourceType`:`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则;配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`:\n- `resourceType=\"noSqlDatabase\"` 仅作用于 CloudBase NoSQL 文档数据库的集合;CloudBase PostgreSQL(PG)表的行级权限**不**受它控制——PG 表请改用 RLS:`managePgDatabase(action=\"execute\", confirm=true)` 跑 `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` 与 `CREATE POLICY ...`。同一个 PG 环境里如果还有 NoSQL 集合在用,对那些**集合**继续使用 `noSqlDatabase` 规则是正确的——不是\"PG 环境就禁用本工具\"。\n- `resourceType=\"storage\"` 控制的是 NoSQL/COS 存储桶 ACL;PG 的 `pgstore` bucket 不在此 `resourceType` 覆盖范围内。\n- 本工具不涉及 MySQL;MySQL 数据库权限请走 MySQL 自身的 GRANT/REVOKE 语句(通过 `manageMysqlDatabase`)。\n\n⚠️ PostgreSQL 环境:平台 `ModifyResourcePermission` 对 PG 环境会直接拒绝。当 `resourceType=\"function\"` 时,本工具会自动回退到 Manager SDK `modifyEnvAuthzConfig`(与 CLI `tcb policy set` 一致,写入 `authz.user.rego`)。`securityRule` 可传完整 Rego(`package authz.user`)或 `'{\"invoke\":true}'`(自动生成放通 anonymous/unauthenticated 调 functions 的策略)。设置 Rego 后旧网关鉴权会失效,行为与 CLI 相同。显式 OPA 策略请优先用 `action=\"setPolicy\"`。\n\n⚠️ 角色类 action(`createRole` / `deleteRoles` / `updateRole`)在 **PostgreSQL 类型环境**下平台侧一律拒绝(`The current API does not support PostgreSQL type environments.`)——平台能力边界,不是配置问题,**不要在 PG 环境反复重试**;PG 环境请改用 RLS(`managePgDatabase(action=\"execute\")` 跑 `CREATE POLICY`)或控制台管理权限。",
|
|
204163
204171
|
writeVerificationHint: "对于 {resourceId} 这类有后端权限控制的集合,前端调用 .doc(id).update() / .doc(id).remove() 后,不能只看是否没有抛异常。请显式检查返回结果中的 updated / deleted 是否大于 0;如果 result.code、result.message 存在,或 updated / deleted 为 0,要把它当作真实失败并向上抛错。",
|
|
204164
204172
|
permissionPropagationHint: "刚更新完 {resourceId} 的安全规则时,后端权限通常在数秒到约 30 秒内生效。若紧接着的真实写操作仍返回 DATABASE_PERMISSION_DENIED,请先间隔数秒用同一登录态重试同一条 .doc(id).update() / .doc(id).remove();不要盲等数分钟,也不要立刻连续重写规则,更不要在短暂传播窗口里把旧拒绝直接当成规则表达式仍然错误。",
|
|
204165
204173
|
validateRegoEmpty: "action=setPolicy 需要非空 regoContent(对齐 CLI `tcb policy set <regoContent>`)。",
|
|
@@ -204226,9 +204234,9 @@ exports.permissions = (0, types_js_1.defineModule)({
|
|
|
204226
204234
|
setPolicySuccess: "用户 OPA Rego 策略设置成功(旧网关鉴权已失效)",
|
|
204227
204235
|
}, {
|
|
204228
204236
|
queryTitle: "Query CloudBase permissions and user config",
|
|
204229
|
-
queryDescription: "Query CloudBase permissions and user config: resource permissions (database/functions/buckets etc.), role list/detail, app user list/detail, and gateway OPA authorization policies (aligned with CLI `tcb policy list/get`).\n\nExamples:\n- Query bucket permission: `action=\"getResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\"`\n- List legacy gateway policies: `action=\"listPolicy\"` (returns an empty list on PG / OPA engine environments, consistent with the CLI)\n- Read user Rego: `action=\"getPolicy\"`; platform extension policy: `action=\"getPolicy\", extension=true`\n\n📌 Cross-backend boundary note: before calling, check `EnvInfo.RuntimeBackends` via `envQuery(action=\"info\", envId=...)`. `resourceType=\"noSqlDatabase\"` queries CloudBase NoSQL collection rules, which are a separate mechanism from row-level security (RLS) on CloudBase PostgreSQL (PG) tables — in the same PG environment, if NoSQL collections are still in use, querying them with this tool **remains valid**. To query PG table RLS, use `queryPgDatabase(action=\"sql\", sql=\"SELECT * FROM pg_policies WHERE tablename=...\")` instead. This tool does not cover MySQL permissions.\n\n⚠️ PostgreSQL environments: the platform `DescribeResourcePermission` API rejects PG environments outright. When `resourceType=\"function\"`, this tool automatically falls back to the Manager SDK `describeEnvAuthzConfig` (aligned with CLI `tcb policy get`, reading `authz.user.rego`). For explicit OPA policies use `listPolicy` / `getPolicy
|
|
204237
|
+
queryDescription: "Query CloudBase permissions and user config: resource permissions (database/functions/buckets etc.), role list/detail, app user list/detail, and gateway OPA authorization policies (aligned with CLI `tcb policy list/get`).\n\nExamples:\n- Query bucket permission: `action=\"getResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\"`\n- List legacy gateway policies: `action=\"listPolicy\"` (returns an empty list on PG / OPA engine environments, consistent with the CLI)\n- Read user Rego: `action=\"getPolicy\"`; platform extension policy: `action=\"getPolicy\", extension=true`\n\n📌 Cross-backend boundary note: before calling, check `EnvInfo.RuntimeBackends` via `envQuery(action=\"info\", envId=...)`. `resourceType=\"noSqlDatabase\"` queries CloudBase NoSQL collection rules, which are a separate mechanism from row-level security (RLS) on CloudBase PostgreSQL (PG) tables — in the same PG environment, if NoSQL collections are still in use, querying them with this tool **remains valid**. To query PG table RLS, use `queryPgDatabase(action=\"sql\", sql=\"SELECT * FROM pg_policies WHERE tablename=...\")` instead. This tool does not cover MySQL permissions.\n\n⚠️ PostgreSQL environments: the platform `DescribeResourcePermission` API rejects PG environments outright. When `resourceType=\"function\"`, this tool automatically falls back to the Manager SDK `describeEnvAuthzConfig` (aligned with CLI `tcb policy get`, reading `authz.user.rego`). For explicit OPA policies use `listPolicy` / `getPolicy`.\n\n⚠️ Role actions (`listRoles` / `getRole`) are rejected outright by the platform on **PostgreSQL environments** (`The current API does not support PostgreSQL type environments.`). This is a platform capability boundary, not a configuration problem — **do not keep retrying on PG**; use RLS (`managePgDatabase(action=\"execute\")` with `CREATE POLICY`) or the console to manage permissions instead.",
|
|
204230
204238
|
manageTitle: "Manage CloudBase permissions and user config",
|
|
204231
|
-
manageDescription: "Manage CloudBase permissions and user config: modify resource permissions (database/functions/buckets etc.), role management, member/policy add & remove, app user CRUD, and setting gateway OPA Rego policies (aligned with CLI `tcb policy set`).\n\nExamples:\n- Set a bucket to private: `action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- Create a role: `action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n- Open a cloud function to anonymous/unauthenticated access (PG goes through OPA, aligned with CLI `tcb policy set`): `action=\"updateResourcePermission\", resourceType=\"function\", resourceId=\"myFn\", permission=\"CUSTOM\", securityRule='{\"invoke\":true}'`\n- Set user Rego directly: `action=\"setPolicy\", regoContent=\"package authz.user\\n\\ndefault allow := false\\n\", confirm=true` (⚠️ immediately disables legacy gateway authorization)\n\nNote: `createUser` / `updateUser` are environment-side app user management capabilities, suitable for test accounts, administrators, or pre-provisioned users; they should not replace the Web SDK signup form in the browser. For frontend username/password signup use `auth.signUp({ username, password })` and for login `auth.signInWithPassword({ username, password })`. Creating username/password users directly in the browser with `auth.signUp` depends on SDK/provider support and must be verified before use; if unsupported, go through a backend or management API boundary and never expose keys in the browser. The detailed semantics of `securityRule` depend on `resourceType`: `doc._openid`, `auth.openid`, query-condition subset validation, and the `create` / `update` / `delete` JSON templates only apply to document database security rules with `resourceType=\"noSqlDatabase\"`; when configuring `function` or `storage`, refer to their official security rule docs instead of reusing NoSQL templates.\n\n📌 Cross-backend boundary note: before calling, check `EnvInfo.RuntimeBackends` via `envQuery(action=\"info\", envId=...)`:\n- `resourceType=\"noSqlDatabase\"` only affects CloudBase NoSQL document database collections; row-level permissions of CloudBase PostgreSQL (PG) tables are **not** controlled by it — for PG tables use RLS instead: run `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` and `CREATE POLICY ...` via `managePgDatabase(action=\"execute\", confirm=true)`. In the same PG environment, if NoSQL collections are still in use, continuing to use `noSqlDatabase` rules for those **collections** is correct — it does not mean \"this tool is disabled on PG environments\".\n- `resourceType=\"storage\"` controls NoSQL/COS bucket ACLs; PG `pgstore` buckets are not covered by this `resourceType`.\n- This tool does not cover MySQL; for MySQL database permissions use MySQL's own GRANT/REVOKE statements (via `manageMysqlDatabase`).\n\n⚠️ PostgreSQL environments: the platform `ModifyResourcePermission` API rejects PG environments outright. When `resourceType=\"function\"`, this tool automatically falls back to the Manager SDK `modifyEnvAuthzConfig` (aligned with CLI `tcb policy set`, writing `authz.user.rego`). `securityRule` accepts a full Rego document (`package authz.user`) or `'{\"invoke\":true}'` (auto-generates a policy allowing anonymous/unauthenticated calls to functions). Setting Rego disables legacy gateway authorization, same as the CLI. Prefer `action=\"setPolicy\"` for explicit OPA policies.",
|
|
204239
|
+
manageDescription: "Manage CloudBase permissions and user config: modify resource permissions (database/functions/buckets etc.), role management, member/policy add & remove, app user CRUD, and setting gateway OPA Rego policies (aligned with CLI `tcb policy set`).\n\nExamples:\n- Set a bucket to private: `action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- Create a role: `action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n- Open a cloud function to anonymous/unauthenticated access (PG goes through OPA, aligned with CLI `tcb policy set`): `action=\"updateResourcePermission\", resourceType=\"function\", resourceId=\"myFn\", permission=\"CUSTOM\", securityRule='{\"invoke\":true}'`\n- Set user Rego directly: `action=\"setPolicy\", regoContent=\"package authz.user\\n\\ndefault allow := false\\n\", confirm=true` (⚠️ immediately disables legacy gateway authorization)\n\nNote: `createUser` / `updateUser` are environment-side app user management capabilities, suitable for test accounts, administrators, or pre-provisioned users; they should not replace the Web SDK signup form in the browser. For frontend username/password signup use `auth.signUp({ username, password })` and for login `auth.signInWithPassword({ username, password })`. Creating username/password users directly in the browser with `auth.signUp` depends on SDK/provider support and must be verified before use; if unsupported, go through a backend or management API boundary and never expose keys in the browser. The detailed semantics of `securityRule` depend on `resourceType`: `doc._openid`, `auth.openid`, query-condition subset validation, and the `create` / `update` / `delete` JSON templates only apply to document database security rules with `resourceType=\"noSqlDatabase\"`; when configuring `function` or `storage`, refer to their official security rule docs instead of reusing NoSQL templates.\n\n📌 Cross-backend boundary note: before calling, check `EnvInfo.RuntimeBackends` via `envQuery(action=\"info\", envId=...)`:\n- `resourceType=\"noSqlDatabase\"` only affects CloudBase NoSQL document database collections; row-level permissions of CloudBase PostgreSQL (PG) tables are **not** controlled by it — for PG tables use RLS instead: run `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` and `CREATE POLICY ...` via `managePgDatabase(action=\"execute\", confirm=true)`. In the same PG environment, if NoSQL collections are still in use, continuing to use `noSqlDatabase` rules for those **collections** is correct — it does not mean \"this tool is disabled on PG environments\".\n- `resourceType=\"storage\"` controls NoSQL/COS bucket ACLs; PG `pgstore` buckets are not covered by this `resourceType`.\n- This tool does not cover MySQL; for MySQL database permissions use MySQL's own GRANT/REVOKE statements (via `manageMysqlDatabase`).\n\n⚠️ PostgreSQL environments: the platform `ModifyResourcePermission` API rejects PG environments outright. When `resourceType=\"function\"`, this tool automatically falls back to the Manager SDK `modifyEnvAuthzConfig` (aligned with CLI `tcb policy set`, writing `authz.user.rego`). `securityRule` accepts a full Rego document (`package authz.user`) or `'{\"invoke\":true}'` (auto-generates a policy allowing anonymous/unauthenticated calls to functions). Setting Rego disables legacy gateway authorization, same as the CLI. Prefer `action=\"setPolicy\"` for explicit OPA policies.\n\n⚠️ Role actions (`createRole` / `deleteRoles` / `updateRole`) are rejected outright by the platform on **PostgreSQL environments** (`The current API does not support PostgreSQL type environments.`). This is a platform capability boundary, not a configuration problem — **do not keep retrying on PG**; use RLS (`managePgDatabase(action=\"execute\")` with `CREATE POLICY`) or the console to manage permissions instead.",
|
|
204232
204240
|
writeVerificationHint: "For collections with backend permission control like {resourceId}, after the frontend calls .doc(id).update() / .doc(id).remove(), do not just check that no exception was thrown. Explicitly verify that updated / deleted in the result is greater than 0; if result.code or result.message exists, or updated / deleted is 0, treat it as a real failure and propagate the error.",
|
|
204233
204241
|
permissionPropagationHint: "Right after updating security rules for {resourceId}, backend permissions usually take effect within a few seconds to about 30 seconds. If an immediate real write still returns DATABASE_PERMISSION_DENIED, wait a few seconds and retry the same .doc(id).update() / .doc(id).remove() with the same login state; do not wait blindly for minutes, do not immediately rewrite the rules repeatedly, and do not treat an old rejection during the short propagation window as evidence that the rule expression is still wrong.",
|
|
204234
204242
|
validateRegoEmpty: "action=setPolicy requires non-empty regoContent (aligned with CLI `tcb policy set <regoContent>`).",
|
|
@@ -206180,9 +206188,15 @@ function registerAppTools(server) {
|
|
|
206180
206188
|
.optional()
|
|
206181
206189
|
.describe("版本名称。getAppVersion 时可与 buildId 二选一;已知版本号时优先传该值。"),
|
|
206182
206190
|
buildId: zod_1.z
|
|
206183
|
-
|
|
206191
|
+
// ⚠️ 同一字段驱动两条链路、类型要求不同(F13):
|
|
206192
|
+
// getAppVersion → SDK describeAppVersion,收 **string**
|
|
206193
|
+
// getBuildLog → 云 API DescribeCloudBaseRunBuildLog,BuildId 是 **Integer(int64)**
|
|
206194
|
+
// 收 string | number 并统一归一成 string(保证 getAppVersion 链路不回退),
|
|
206195
|
+
// getBuildLog 分支再转 number 传给云 API。
|
|
206196
|
+
.union([zod_1.z.string(), zod_1.z.number()])
|
|
206197
|
+
.transform((value) => String(value).trim())
|
|
206184
206198
|
.optional()
|
|
206185
|
-
.describe("构建 ID
|
|
206199
|
+
.describe("构建 ID(数字或数字字符串均可)。getAppVersion 时可与 versionName 二选一;部署返回 BuildId 后可直接用它轮询状态。getBuildLog 时必填。"),
|
|
206186
206200
|
start: zod_1.z
|
|
206187
206201
|
.number()
|
|
206188
206202
|
.optional()
|
|
@@ -206284,15 +206298,22 @@ function registerAppTools(server) {
|
|
|
206284
206298
|
}, (0, index_js_1.t)("apps.listVersionsSuccess")));
|
|
206285
206299
|
}
|
|
206286
206300
|
if (action === "getBuildLog") {
|
|
206287
|
-
if (
|
|
206301
|
+
if (buildId === undefined || buildId === null || String(buildId).trim() === "") {
|
|
206288
206302
|
throw new Error((0, index_js_1.t)("apps.buildIdRequired"));
|
|
206289
206303
|
}
|
|
206304
|
+
// DescribeCloudBaseRunBuildLog 的 BuildId 是 Integer(int64)(官方文档 876/135707),
|
|
206305
|
+
// 传 string 会被后端拒:The value type of parameter BuildId is not valid, input type
|
|
206306
|
+
// should be int64。schema 侧已归一成 string(getAppVersion 需要 string),此处转 number。
|
|
206307
|
+
const numericBuildId = Number(String(buildId).trim());
|
|
206308
|
+
if (!Number.isInteger(numericBuildId) || numericBuildId <= 0) {
|
|
206309
|
+
throw new Error((0, index_js_1.t)("apps.buildIdMustBeNumeric", { buildId: String(buildId) }));
|
|
206310
|
+
}
|
|
206290
206311
|
const result = await cloudbase.commonService("tcb", "2018-06-08").call({
|
|
206291
206312
|
Action: "DescribeCloudBaseRunBuildLog",
|
|
206292
206313
|
Param: {
|
|
206293
206314
|
EnvId: cloudBaseOptions?.envId || process.env.CLOUDBASE_ENV_ID,
|
|
206294
206315
|
ServiceName: serviceName,
|
|
206295
|
-
BuildId:
|
|
206316
|
+
BuildId: numericBuildId,
|
|
206296
206317
|
Start: start ?? 0,
|
|
206297
206318
|
},
|
|
206298
206319
|
});
|
|
@@ -206301,7 +206322,7 @@ function registerAppTools(server) {
|
|
|
206301
206322
|
return (0, json_content_js_1.jsonContent)(buildEnvelope({
|
|
206302
206323
|
action,
|
|
206303
206324
|
serviceName,
|
|
206304
|
-
buildId,
|
|
206325
|
+
buildId: String(numericBuildId),
|
|
206305
206326
|
logs,
|
|
206306
206327
|
total: result.Response?.Total || logs.length,
|
|
206307
206328
|
nextStart: result.Response?.NextStart,
|
|
@@ -206314,7 +206335,8 @@ function registerAppTools(server) {
|
|
|
206314
206335
|
deployType: "static-hosting",
|
|
206315
206336
|
serviceName,
|
|
206316
206337
|
versionName,
|
|
206317
|
-
|
|
206338
|
+
// 该链路要 string(SDK 类型 IDescribeCloudAppVersionParams.BuildId: string)
|
|
206339
|
+
buildId: buildId === undefined ? undefined : String(buildId),
|
|
206318
206340
|
});
|
|
206319
206341
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
206320
206342
|
// Platform may return Failed/failed; normalize before matching.
|
|
@@ -206366,12 +206388,21 @@ function registerAppTools(server) {
|
|
|
206366
206388
|
.optional()
|
|
206367
206389
|
.describe("要上传并部署的本地项目根目录绝对路径。本地模式下 deployApp 时必填;通常传源码所在目录(含 package.json 和源码),不是 dist 目录。构建产物目录请用 buildPath 指定。cloud mode 下无需传此参数,改用 cosTimestamp。"),
|
|
206368
206390
|
cosTimestamp: zod_1.z
|
|
206369
|
-
.coerce
|
|
206370
|
-
.
|
|
206371
|
-
|
|
206372
|
-
|
|
206391
|
+
// ⚠️ 不能用 z.coerce.number():SDK 的 StaticConfig.CosTimestamp(manager-node
|
|
206392
|
+
// types/cloudApp/types.d.ts `CosTimestamp?: string | null`)与后端 CreateCloudApp
|
|
206393
|
+
// 都要求 **string**。coerce 会把外部传入的值(含 getUploadUrl 返回的 unixTimestamp)
|
|
206394
|
+
// 强制转成 number,后端直接拒绝:
|
|
206395
|
+
// The value type of parameter `StaticConfig.CosTimestamp` is not valid,
|
|
206396
|
+
// input type should be `string`
|
|
206397
|
+
// 本地路径不受影响,是因为 cosTs 来自 SDK uploadCode() 的 string 返回值、不经 zod。
|
|
206398
|
+
// 因此这里收 string | number,统一归一成 string 后再透传。
|
|
206399
|
+
.union([zod_1.z.string(), zod_1.z.number()])
|
|
206400
|
+
.transform((value) => String(value).trim())
|
|
206401
|
+
.refine((value) => /^[1-9]\d*$/.test(value), {
|
|
206402
|
+
message: "cosTimestamp 必须是由数字组成的正整数时间戳,字符串或数字均可;直接使用 getUploadUrl 返回的 unixTimestamp 即可。",
|
|
206403
|
+
})
|
|
206373
206404
|
.optional()
|
|
206374
|
-
.describe("COS
|
|
206405
|
+
.describe("COS 时间戳(getUploadUrl 返回的 unixTimestamp,字符串或数字均可)。传入则直接用已上传的代码创建应用,跳过本地打包上传;需先 getUploadUrl 拿预签名 URL 并 PUT ZIP。cloud mode 必填。与 filePath 严格二选一,同时提供或都不提供都会报错。"),
|
|
206375
206406
|
appPath: zod_1.z
|
|
206376
206407
|
.string()
|
|
206377
206408
|
.optional()
|
|
@@ -206505,7 +206536,10 @@ function registerAppTools(server) {
|
|
|
206505
206536
|
}
|
|
206506
206537
|
}
|
|
206507
206538
|
// Local stdio only: pack directory and upload. Cloud mode must never reach uploadCode.
|
|
206508
|
-
|
|
206539
|
+
// ⚠️ 类型契约(F12):SDK `StaticConfig.CosTimestamp` 与后端 CreateCloudApp 都要求
|
|
206540
|
+
// **string**。本地路径拿到的 `uploadResult.cosTimestamp` 本就是 SDK 给的 string;
|
|
206541
|
+
// 外部传入的可能是 number(MCP 客户端按 JSON Schema 传数字),这里统一归一。
|
|
206542
|
+
let cosTs = cosTimestamp === undefined ? undefined : String(cosTimestamp);
|
|
206509
206543
|
if (!(0, cloud_mode_js_1.isCloudMode)() && filePath) {
|
|
206510
206544
|
// Default excludes large build dirs (empirically target/ can be tens of GB).
|
|
206511
206545
|
// Merge caller ignore with defaults so explicit ignore does not drop safety excludes.
|
|
@@ -206520,7 +206554,9 @@ function registerAppTools(server) {
|
|
|
206520
206554
|
ignore: mergedIgnore,
|
|
206521
206555
|
});
|
|
206522
206556
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, uploadResult);
|
|
206523
|
-
cosTs = uploadResult.cosTimestamp
|
|
206557
|
+
cosTs = uploadResult.cosTimestamp === undefined
|
|
206558
|
+
? undefined
|
|
206559
|
+
: String(uploadResult.cosTimestamp);
|
|
206524
206560
|
}
|
|
206525
206561
|
// 构建命令智能默认值
|
|
206526
206562
|
const resolvedInstallCmd = installCmd ?? "npm install";
|
|
@@ -207049,7 +207085,15 @@ function registerCapiTools(server) {
|
|
|
207049
207085
|
const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions, requireEnvId: false });
|
|
207050
207086
|
server.registerTool?.("callCloudApi", {
|
|
207051
207087
|
title: "capi.title",
|
|
207052
|
-
description: "capi.description"
|
|
207088
|
+
// ⚠️ 不能写成 `description: "capi.description"`(纯词典 key):注册包装层解析
|
|
207089
|
+
// key 时**不带插值参数**,而 {controlPlaneUrl}/{dependencyUrl} 只在错误路径
|
|
207090
|
+
// (下方 t("capi.errorBuild", …))传入 → 描述里的占位符永远替换不了,
|
|
207091
|
+
// tools/list 在 zh 与 en 下都会吐字面 `{controlPlaneUrl}`。
|
|
207092
|
+
// 因此这里按实例语言先解析成最终文案(与 env.ts 的 envQuery 别名同款处理)。
|
|
207093
|
+
description: (0, index_js_1.t)("capi.description", {
|
|
207094
|
+
controlPlaneUrl: CLOUDBASE_CONTROL_PLANE_DOC_URL,
|
|
207095
|
+
dependencyUrl: CLOUDBASE_DEPENDENCY_API_DOC_URL,
|
|
207096
|
+
}, server.lang),
|
|
207053
207097
|
inputSchema: {
|
|
207054
207098
|
service: zod_1.z
|
|
207055
207099
|
.enum(exports.ALLOWED_SERVICES)
|
|
@@ -207377,6 +207421,7 @@ exports.buildCloudRunDeployNextStep = buildCloudRunDeployNextStep;
|
|
|
207377
207421
|
exports.buildCloudRunDeployProgressHint = buildCloudRunDeployProgressHint;
|
|
207378
207422
|
exports.queryCloudRunEnvStatus = queryCloudRunEnvStatus;
|
|
207379
207423
|
exports.describeCloudRunEnvStatus = describeCloudRunEnvStatus;
|
|
207424
|
+
exports.isCloudRunEnvNotOpenedError = isCloudRunEnvNotOpenedError;
|
|
207380
207425
|
exports.extractEnvBaseInfoVpc = extractEnvBaseInfoVpc;
|
|
207381
207426
|
exports.resolveCloudRunDeployVpcInfo = resolveCloudRunDeployVpcInfo;
|
|
207382
207427
|
exports.buildCreateCloudRunEnvParam = buildCreateCloudRunEnvParam;
|
|
@@ -207957,6 +208002,36 @@ async function describeCloudRunEnvStatus(manager, envId) {
|
|
|
207957
208002
|
: "unknown";
|
|
207958
208003
|
return { isExist: true, status, baseInfo };
|
|
207959
208004
|
}
|
|
208005
|
+
/**
|
|
208006
|
+
* 判断「云托管环境未开通 / 不存在」类错误,用于 `describeCloudRunEnvStatus` 失败的归一化分支。
|
|
208007
|
+
*
|
|
208008
|
+
* ⚠️ 必须**同时**看 `error.code` 与 `error.message`:
|
|
208009
|
+
* 报错文案有三套来源且会不一致 —— 英文错误码(`ResourceNotFound.CloudRunEnv`)、
|
|
208010
|
+
* 中文兜底(`[DescribeEnvBaseInfo] 资源不存在`)、旧式 `InvalidParameter.*Env`。
|
|
208011
|
+
* 只匹配 message 时,中文「资源不存在」不含 `ResourceNotFound`/`未开通`/`未初始化`,
|
|
208012
|
+
* 守卫会失效并把裸错误抛给模型(国际站未开通云托管的环境实测命中,见 F2)。
|
|
208013
|
+
*
|
|
208014
|
+
* 调用方只有 `DescribeEnvBaseInfo`(唯一资源就是环境),因此把「资源不存在」纳入
|
|
208015
|
+
* 未开通判定不会误伤其他语义。
|
|
208016
|
+
*/
|
|
208017
|
+
function isCloudRunEnvNotOpenedError(error) {
|
|
208018
|
+
if (!error) {
|
|
208019
|
+
return false;
|
|
208020
|
+
}
|
|
208021
|
+
const codeCandidates = [
|
|
208022
|
+
error.code,
|
|
208023
|
+
error.Code,
|
|
208024
|
+
error.original?.code,
|
|
208025
|
+
error.original?.Code,
|
|
208026
|
+
];
|
|
208027
|
+
const codes = codeCandidates
|
|
208028
|
+
.filter((value) => typeof value === "string")
|
|
208029
|
+
.join(" ");
|
|
208030
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
208031
|
+
const haystack = `${codes} ${message}`;
|
|
208032
|
+
return (/ResourceNotFound|not.?initialized|未开通|未初始化|资源不存在|环境不存在/i.test(haystack) ||
|
|
208033
|
+
/InvalidParameter.*(?:Env|CloudRun)/i.test(haystack));
|
|
208034
|
+
}
|
|
207960
208035
|
/** CloudRun EnvType for CreateCloudRunEnv (baas DescribeEnvBaseInfo enum). */
|
|
207961
208036
|
exports.CLOUDRUN_ENV_TYPE = "baas";
|
|
207962
208037
|
/**
|
|
@@ -208057,12 +208132,11 @@ async function ensureCloudRunEnvInitialized(options) {
|
|
|
208057
208132
|
return true;
|
|
208058
208133
|
}
|
|
208059
208134
|
catch (error) {
|
|
208060
|
-
|
|
208061
|
-
//
|
|
208135
|
+
// 错误兜底:未初始化/未开通类错误码。判据统一收敛到 isCloudRunEnvNotOpenedError,
|
|
208136
|
+
// 避免「只匹配 message」被本地化文案(中文「资源不存在」)绕过。
|
|
208062
208137
|
// 注意:裸 InvalidParameter 可能是普通参数错误,不拦截;仅当其带 Env/CloudRun
|
|
208063
208138
|
// 上下文(疑似 "EnvironmentId not found / CloudRun Env 未开通")时才按未初始化处理。
|
|
208064
|
-
if (
|
|
208065
|
-
/InvalidParameter.*(?:Env|CloudRun)/i.test(msg)) {
|
|
208139
|
+
if (isCloudRunEnvNotOpenedError(error)) {
|
|
208066
208140
|
throwCloudRunEnvNotInitialized(options.envId);
|
|
208067
208141
|
}
|
|
208068
208142
|
// 其他错误(网络/权限等)不拦截,让上层按原逻辑处理。
|
|
@@ -208626,8 +208700,7 @@ function registerCloudRunTools(server) {
|
|
|
208626
208700
|
}
|
|
208627
208701
|
catch (error) {
|
|
208628
208702
|
const baseMessage = error instanceof Error ? error.message : String(error);
|
|
208629
|
-
if (
|
|
208630
|
-
/InvalidParameter.*(?:Env|CloudRun)/i.test(baseMessage)) {
|
|
208703
|
+
if (isCloudRunEnvNotOpenedError(error)) {
|
|
208631
208704
|
status = { isExist: false, status: "unopened", baseInfo: {} };
|
|
208632
208705
|
}
|
|
208633
208706
|
else {
|
|
@@ -208720,8 +208793,7 @@ function registerCloudRunTools(server) {
|
|
|
208720
208793
|
}
|
|
208721
208794
|
catch (error) {
|
|
208722
208795
|
const baseMessage = error instanceof Error ? error.message : String(error);
|
|
208723
|
-
if (
|
|
208724
|
-
/InvalidParameter.*(?:Env|CloudRun)/i.test(baseMessage)) {
|
|
208796
|
+
if (isCloudRunEnvNotOpenedError(error)) {
|
|
208725
208797
|
current = { isExist: false, status: "unopened", baseInfo: {} };
|
|
208726
208798
|
}
|
|
208727
208799
|
else {
|
|
@@ -218658,7 +218730,7 @@ function registerEnvTools(server) {
|
|
|
218658
218730
|
code: "INVALID_ARGS",
|
|
218659
218731
|
message: (0, index_js_1.t)("env.auth.apiKeyArgsRequired", undefined, outLang),
|
|
218660
218732
|
next_step: (0, tool_result_js_1.buildAuthNextStep)("login_by_api_key", {
|
|
218661
|
-
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>",
|
|
218733
|
+
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>", apiKeyEnvId: "<your-env-id>" },
|
|
218662
218734
|
}),
|
|
218663
218735
|
});
|
|
218664
218736
|
}
|
|
@@ -218703,7 +218775,7 @@ function registerEnvTools(server) {
|
|
|
218703
218775
|
auth_mode: "api_key",
|
|
218704
218776
|
envId: toolApiKeyEnvId,
|
|
218705
218777
|
next_step: (0, tool_result_js_1.buildAuthNextStep)("login_by_api_key", {
|
|
218706
|
-
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>",
|
|
218778
|
+
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>", apiKeyEnvId: "<your-env-id>" },
|
|
218707
218779
|
}),
|
|
218708
218780
|
});
|
|
218709
218781
|
}
|
|
@@ -218718,7 +218790,7 @@ function registerEnvTools(server) {
|
|
|
218718
218790
|
message: (0, index_js_1.t)("env.auth.apiKeyException", { message }, outLang),
|
|
218719
218791
|
auth_mode: "api_key",
|
|
218720
218792
|
next_step: (0, tool_result_js_1.buildAuthNextStep)("login_by_api_key", {
|
|
218721
|
-
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>",
|
|
218793
|
+
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>", apiKeyEnvId: "<your-env-id>" },
|
|
218722
218794
|
}),
|
|
218723
218795
|
});
|
|
218724
218796
|
}
|
|
@@ -219027,14 +219099,7 @@ function registerEnvTools(server) {
|
|
|
219027
219099
|
}
|
|
219028
219100
|
(0, logger_js_1.debug)("降级到 listEnvs() 也失败:", fallbackError instanceof Error ? fallbackError : new Error(String(fallbackError)));
|
|
219029
219101
|
const enhancedMessage = buildEnvQueryErrorMessage(fallbackError, "list");
|
|
219030
|
-
return
|
|
219031
|
-
content: [
|
|
219032
|
-
{
|
|
219033
|
-
type: "text",
|
|
219034
|
-
text: enhancedMessage,
|
|
219035
|
-
},
|
|
219036
|
-
],
|
|
219037
|
-
};
|
|
219102
|
+
return (0, tool_result_js_1.buildTextErrorResult)(enhancedMessage);
|
|
219038
219103
|
}
|
|
219039
219104
|
}
|
|
219040
219105
|
result = buildEnvQueryListResult({
|
|
@@ -219217,14 +219282,7 @@ function registerEnvTools(server) {
|
|
|
219217
219282
|
return toolPayloadResult;
|
|
219218
219283
|
}
|
|
219219
219284
|
const enhancedMessage = buildEnvQueryErrorMessage(error, action);
|
|
219220
|
-
return
|
|
219221
|
-
content: [
|
|
219222
|
-
{
|
|
219223
|
-
type: "text",
|
|
219224
|
-
text: enhancedMessage,
|
|
219225
|
-
},
|
|
219226
|
-
],
|
|
219227
|
-
};
|
|
219285
|
+
return (0, tool_result_js_1.buildTextErrorResult)(enhancedMessage);
|
|
219228
219286
|
}
|
|
219229
219287
|
};
|
|
219230
219288
|
// Register primary tool name (queryEnv)
|
|
@@ -219358,16 +219416,9 @@ function registerEnvTools(server) {
|
|
|
219358
219416
|
if (toolPayloadResult) {
|
|
219359
219417
|
return toolPayloadResult;
|
|
219360
219418
|
}
|
|
219361
|
-
return {
|
|
219362
|
-
|
|
219363
|
-
|
|
219364
|
-
type: "text",
|
|
219365
|
-
text: (0, index_js_1.t)("env.domain.operationFailed", {
|
|
219366
|
-
message: error instanceof Error ? error.message : String(error),
|
|
219367
|
-
}),
|
|
219368
|
-
},
|
|
219369
|
-
],
|
|
219370
|
-
};
|
|
219419
|
+
return (0, tool_result_js_1.buildTextErrorResult)((0, index_js_1.t)("env.domain.operationFailed", {
|
|
219420
|
+
message: error instanceof Error ? error.message : String(error),
|
|
219421
|
+
}));
|
|
219371
219422
|
}
|
|
219372
219423
|
});
|
|
219373
219424
|
} // end: wxide guard for envDomainManagement
|
|
@@ -219893,14 +219944,7 @@ function registerEnvTools(server) {
|
|
|
219893
219944
|
message: (0, index_js_1.t)("env.manage.listPackagesFailed", { message: errorMessage }),
|
|
219894
219945
|
});
|
|
219895
219946
|
}
|
|
219896
|
-
return {
|
|
219897
|
-
content: [
|
|
219898
|
-
{
|
|
219899
|
-
type: "text",
|
|
219900
|
-
text: (0, index_js_1.t)("env.manage.operationFailed", { message: errorMessage }),
|
|
219901
|
-
},
|
|
219902
|
-
],
|
|
219903
|
-
};
|
|
219947
|
+
return (0, tool_result_js_1.buildTextErrorResult)((0, index_js_1.t)("env.manage.operationFailed", { message: errorMessage }));
|
|
219904
219948
|
}
|
|
219905
219949
|
});
|
|
219906
219950
|
}
|
|
@@ -223251,6 +223295,123 @@ function registerGatewayTools(server) {
|
|
|
223251
223295
|
data: {},
|
|
223252
223296
|
message: error instanceof Error ? error.message : String(error),
|
|
223253
223297
|
});
|
|
223298
|
+
/**
|
|
223299
|
+
* 上游目标存在性校验(F1)。
|
|
223300
|
+
*
|
|
223301
|
+
* 背景:`createHttpServiceRoute` 不校验 `UpstreamResourceName` 是否存在,预检
|
|
223302
|
+
* (VerifyHTTPServiceRoute)也只查域名归属/证书/配额,因此**不存在的上游也能真实落库并
|
|
223303
|
+
* 返回 success**,形成悬空路由(path 被占用、指向不存在的目标)。实测两站复现。
|
|
223304
|
+
*
|
|
223305
|
+
* 设计原则:**只在能证明「不存在」时拒绝**。
|
|
223306
|
+
* - 列表接口报错、分页未扫全、类型不支持 → `unknown`,放行并记日志(fail-open)。
|
|
223307
|
+
* 校验失败绝不该阻塞用户创建合法路由。
|
|
223308
|
+
* - 只有扫完全量且确实没有该名称时,才返回 `missing`。
|
|
223309
|
+
*
|
|
223310
|
+
* 覆盖范围:SCF / WEB_SCF(函数列表)、CBR(云托管服务列表)。
|
|
223311
|
+
* NOT covered:STATIC_STORE 的 UpstreamResourceName 是静态托管**实例名/固定别名
|
|
223312
|
+
* staticstore**(不是 CloudApp 应用名),可靠列举要额外走 DescribeStaticStore,且该资源
|
|
223313
|
+
* 随托管启用必然存在、悬空风险低;LH(轻量应用服务器)无列举接口。两者一律 fail-open。
|
|
223314
|
+
*/
|
|
223315
|
+
const UPSTREAM_PROBE_PAGE_SIZE = 100;
|
|
223316
|
+
const UPSTREAM_PROBE_MAX_PAGES = 5;
|
|
223317
|
+
const UPSTREAM_PROBE_CANDIDATE_LIMIT = 10;
|
|
223318
|
+
const probeUpstreamResource = async (cloudbase, params) => {
|
|
223319
|
+
const wanted = params.upstreamResourceName.trim();
|
|
223320
|
+
const upstreamResourceType = params.upstreamResourceType;
|
|
223321
|
+
try {
|
|
223322
|
+
if (upstreamResourceType === "SCF" || upstreamResourceType === "WEB_SCF") {
|
|
223323
|
+
// fail-open:老 SDK / mock 没有该 API 时不校验,绝不让「拿不到列表」变成「判定不存在」。
|
|
223324
|
+
if (typeof cloudbase.functions?.getFunctionList !== "function") {
|
|
223325
|
+
return { status: "unknown", reason: "function-list-api-unavailable" };
|
|
223326
|
+
}
|
|
223327
|
+
const names = new Set();
|
|
223328
|
+
let scanned = 0;
|
|
223329
|
+
let total = Number.POSITIVE_INFINITY;
|
|
223330
|
+
for (let page = 0; page < UPSTREAM_PROBE_MAX_PAGES; page += 1) {
|
|
223331
|
+
const res = await cloudbase.functions.getFunctionList(UPSTREAM_PROBE_PAGE_SIZE, scanned);
|
|
223332
|
+
const list = Array.isArray(res?.Functions) ? res.Functions : [];
|
|
223333
|
+
for (const item of list) {
|
|
223334
|
+
const name = item?.FunctionName;
|
|
223335
|
+
if (typeof name === "string" && name) {
|
|
223336
|
+
names.add(name);
|
|
223337
|
+
}
|
|
223338
|
+
}
|
|
223339
|
+
scanned += list.length;
|
|
223340
|
+
total = typeof res?.TotalCount === "number" ? res.TotalCount : scanned;
|
|
223341
|
+
if (names.has(wanted) || list.length === 0 || scanned >= total) {
|
|
223342
|
+
break;
|
|
223343
|
+
}
|
|
223344
|
+
}
|
|
223345
|
+
if (names.has(wanted)) {
|
|
223346
|
+
return { status: "exists" };
|
|
223347
|
+
}
|
|
223348
|
+
if (scanned >= total) {
|
|
223349
|
+
return {
|
|
223350
|
+
status: "missing",
|
|
223351
|
+
candidates: [...names].slice(0, UPSTREAM_PROBE_CANDIDATE_LIMIT),
|
|
223352
|
+
};
|
|
223353
|
+
}
|
|
223354
|
+
return { status: "unknown", reason: "function-list-partially-scanned" };
|
|
223355
|
+
}
|
|
223356
|
+
if (upstreamResourceType === "CBR") {
|
|
223357
|
+
// fail-open:同上,`cloudrun?.list` 缺失时会短路成 undefined,若不显式拦截会被
|
|
223358
|
+
// 误判成「列表为空 = 目标不存在」,从而错误拒绝合法路由。
|
|
223359
|
+
if (typeof cloudbase.cloudrun?.list !== "function") {
|
|
223360
|
+
return { status: "unknown", reason: "cloudrun-list-api-unavailable" };
|
|
223361
|
+
}
|
|
223362
|
+
const names = new Set();
|
|
223363
|
+
for (let page = 1; page <= UPSTREAM_PROBE_MAX_PAGES; page += 1) {
|
|
223364
|
+
const res = await cloudbase.cloudrun.list({
|
|
223365
|
+
pageSize: UPSTREAM_PROBE_PAGE_SIZE,
|
|
223366
|
+
pageNum: page,
|
|
223367
|
+
});
|
|
223368
|
+
const list = Array.isArray(res?.ServerList) ? res.ServerList : [];
|
|
223369
|
+
for (const item of list) {
|
|
223370
|
+
const record = item;
|
|
223371
|
+
const name = record?.ServerName ?? record?.Name;
|
|
223372
|
+
if (typeof name === "string" && name) {
|
|
223373
|
+
names.add(name);
|
|
223374
|
+
}
|
|
223375
|
+
}
|
|
223376
|
+
const total = typeof res?.Total === "number" ? res.Total : names.size;
|
|
223377
|
+
if (names.has(wanted) || list.length === 0 || names.size >= total) {
|
|
223378
|
+
break;
|
|
223379
|
+
}
|
|
223380
|
+
}
|
|
223381
|
+
if (names.has(wanted)) {
|
|
223382
|
+
return { status: "exists" };
|
|
223383
|
+
}
|
|
223384
|
+
return {
|
|
223385
|
+
status: "missing",
|
|
223386
|
+
candidates: [...names].slice(0, UPSTREAM_PROBE_CANDIDATE_LIMIT),
|
|
223387
|
+
};
|
|
223388
|
+
}
|
|
223389
|
+
// STATIC_STORE / LH:无可靠的实例列举通路,不校验(见上方说明)。
|
|
223390
|
+
return { status: "unknown", reason: `unsupported-upstream-type:${upstreamResourceType}` };
|
|
223391
|
+
}
|
|
223392
|
+
catch (error) {
|
|
223393
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
223394
|
+
return { status: "unknown", reason: message };
|
|
223395
|
+
}
|
|
223396
|
+
};
|
|
223397
|
+
/** 上游缺失时的候选列举工具,按类型给出下一步可用的只读入口。 */
|
|
223398
|
+
const upstreamProbeNextAction = (upstreamResourceType) => {
|
|
223399
|
+
if (upstreamResourceType === "SCF" || upstreamResourceType === "WEB_SCF") {
|
|
223400
|
+
return {
|
|
223401
|
+
tool: "queryFunctions",
|
|
223402
|
+
action: "listFunctions",
|
|
223403
|
+
reason: (0, index_js_1.t)("gateway.create.upstreamNotFoundReason"),
|
|
223404
|
+
};
|
|
223405
|
+
}
|
|
223406
|
+
if (upstreamResourceType === "CBR") {
|
|
223407
|
+
return {
|
|
223408
|
+
tool: "queryCloudRun",
|
|
223409
|
+
action: "list",
|
|
223410
|
+
reason: (0, index_js_1.t)("gateway.create.upstreamNotFoundReason"),
|
|
223411
|
+
};
|
|
223412
|
+
}
|
|
223413
|
+
return null;
|
|
223414
|
+
};
|
|
223254
223415
|
const verifyHttpServiceRouteOrFail = async (params) => {
|
|
223255
223416
|
const cloudbase = await getManager();
|
|
223256
223417
|
let result;
|
|
@@ -223737,6 +223898,46 @@ function registerGatewayTools(server) {
|
|
|
223737
223898
|
case "createRoute": {
|
|
223738
223899
|
const cloudbase = await getManager();
|
|
223739
223900
|
const payload = await normalizeRoutePayload(input);
|
|
223901
|
+
// 上游目标存在性校验(F1):平台侧不校验 UpstreamResourceName,不存在的目标也会
|
|
223902
|
+
// 真实落库形成悬空路由并返回 success。能证明不存在就拒绝,校验不了就放行(fail-open)。
|
|
223903
|
+
const upstreamProbe = await probeUpstreamResource(cloudbase, {
|
|
223904
|
+
upstreamResourceType: payload.resolved.upstreamResourceType,
|
|
223905
|
+
upstreamResourceName: payload.resolved.upstreamResourceName,
|
|
223906
|
+
});
|
|
223907
|
+
if (upstreamProbe.status === "missing") {
|
|
223908
|
+
const nextAction = upstreamProbeNextAction(payload.resolved.upstreamResourceType);
|
|
223909
|
+
return {
|
|
223910
|
+
success: false,
|
|
223911
|
+
data: {
|
|
223912
|
+
action: "createRoute",
|
|
223913
|
+
upstreamResourceType: payload.resolved.upstreamResourceType,
|
|
223914
|
+
targetName: payload.resolved.upstreamResourceName,
|
|
223915
|
+
path: payload.resolved.path,
|
|
223916
|
+
candidates: upstreamProbe.candidates,
|
|
223917
|
+
...(upstreamProbe.candidates.length
|
|
223918
|
+
? {
|
|
223919
|
+
candidateHint: (0, index_js_1.t)("gateway.create.upstreamCandidates", {
|
|
223920
|
+
type: payload.resolved.upstreamResourceType,
|
|
223921
|
+
candidates: upstreamProbe.candidates.join("、"),
|
|
223922
|
+
}),
|
|
223923
|
+
}
|
|
223924
|
+
: {}),
|
|
223925
|
+
},
|
|
223926
|
+
message: (0, index_js_1.t)("gateway.create.upstreamNotFound", {
|
|
223927
|
+
type: payload.resolved.upstreamResourceType,
|
|
223928
|
+
name: payload.resolved.upstreamResourceName,
|
|
223929
|
+
}),
|
|
223930
|
+
...(nextAction ? { nextActions: [nextAction] } : {}),
|
|
223931
|
+
};
|
|
223932
|
+
}
|
|
223933
|
+
if (upstreamProbe.status === "unknown") {
|
|
223934
|
+
// 校验不了不阻塞创建,但要留痕,便于排查「为什么这次没拦住」。
|
|
223935
|
+
server.logger?.({
|
|
223936
|
+
type: "errorToolCall",
|
|
223937
|
+
toolName: "manageGateway",
|
|
223938
|
+
message: `createRoute upstream probe skipped (${payload.resolved.upstreamResourceType}/${payload.resolved.upstreamResourceName}): ${upstreamProbe.reason}`,
|
|
223939
|
+
});
|
|
223940
|
+
}
|
|
223740
223941
|
// Probe → create: ownership / cert / quota / conflict checks before create.
|
|
223741
223942
|
const verifyFailure = await verifyHttpServiceRouteOrFail({
|
|
223742
223943
|
envId: payload.EnvId,
|
|
@@ -225328,9 +225529,28 @@ function registerHostingTools(server) {
|
|
|
225328
225529
|
try {
|
|
225329
225530
|
const checkResult = await cloudbase.hosting.findFiles({
|
|
225330
225531
|
prefix: input.cloudPath,
|
|
225331
|
-
maxKeys:
|
|
225532
|
+
maxKeys: 100,
|
|
225332
225533
|
});
|
|
225333
|
-
|
|
225534
|
+
// ⚠️ 回查有两个坑,都会让 verified 失真:
|
|
225535
|
+
// 1) findFiles 返回 **COS 风格对象**(列表在 Contents 内),直接用
|
|
225536
|
+
// `Array.isArray(checkResult)` 判断会静默失效、恒判 verified=true。
|
|
225537
|
+
// 统一走 extractFileList 归一化。
|
|
225538
|
+
// 2) findFiles 是 **prefix** 语义:删单文件 /a/b.txt 时,若同前缀的
|
|
225539
|
+
// /a/b.txt.bak 还在也会命中 → 把「已删成功」误判成未验证。
|
|
225540
|
+
// 单文件场景必须精确比对 Key(前缀场景见 normalizeFileFields 的 key 字段)。
|
|
225541
|
+
const remaining = normalizeFileFields(checkResult);
|
|
225542
|
+
const stripLeadingSlash = (value) => value.replace(/^\/+/, '');
|
|
225543
|
+
const targetPath = stripLeadingSlash(input.cloudPath ?? '');
|
|
225544
|
+
const stillExists = input.isDir
|
|
225545
|
+
? remaining.length > 0
|
|
225546
|
+
: remaining.some((file) => {
|
|
225547
|
+
const key = typeof file.key === 'string' ? file.key : '';
|
|
225548
|
+
// 拿不到 Key 时保守按「仍存在」处理,避免误报已验证
|
|
225549
|
+
if (!key)
|
|
225550
|
+
return true;
|
|
225551
|
+
return stripLeadingSlash(key) === targetPath;
|
|
225552
|
+
});
|
|
225553
|
+
if (stillExists) {
|
|
225334
225554
|
deleteVerified = false;
|
|
225335
225555
|
verificationError = verificationError ?? (0, index_js_1.t)('hosting.deleteVerifyFailed');
|
|
225336
225556
|
}
|
|
@@ -231562,7 +231782,7 @@ class TelemetryReporter {
|
|
|
231562
231782
|
const arch = os_1.default.arch(); // 系统架构
|
|
231563
231783
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
231564
231784
|
const mcpVersion = process.env.npm_package_version ||
|
|
231565
|
-
( true ? "2.34.
|
|
231785
|
+
( true ? "2.34.3" : 0);
|
|
231566
231786
|
return {
|
|
231567
231787
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
231568
231788
|
deviceId: this.deviceId,
|
|
@@ -231966,6 +232186,7 @@ exports.ToolPayloadError = void 0;
|
|
|
231966
232186
|
exports.buildJsonToolResult = buildJsonToolResult;
|
|
231967
232187
|
exports.isBusinessFailureToolResult = isBusinessFailureToolResult;
|
|
231968
232188
|
exports.withBusinessFailureIsError = withBusinessFailureIsError;
|
|
232189
|
+
exports.buildTextErrorResult = buildTextErrorResult;
|
|
231969
232190
|
exports.isToolPayloadError = isToolPayloadError;
|
|
231970
232191
|
exports.toolPayloadErrorToResult = toolPayloadErrorToResult;
|
|
231971
232192
|
exports.buildAuthNextStep = buildAuthNextStep;
|
|
@@ -232032,6 +232253,28 @@ function withBusinessFailureIsError(result) {
|
|
|
232032
232253
|
}
|
|
232033
232254
|
return { ...record, isError: true };
|
|
232034
232255
|
}
|
|
232256
|
+
/**
|
|
232257
|
+
* 纯文本失败回执:**必须显式带 `isError: true`**。
|
|
232258
|
+
*
|
|
232259
|
+
* 为什么需要它:`withBusinessFailureIsError` 只能识别结构化的 `{ success: false }`
|
|
232260
|
+
* 载荷(`isBusinessFailureToolResult` 会 JSON.parse 文本内容再嗅 `success`)。工具在自己
|
|
232261
|
+
* 的 catch 里返回 `{ content: [{ type: "text", text }] }` 这种**纯文本**回执时,文本不是
|
|
232262
|
+
* JSON,嗅探不到任何失败标记 → 客户端只看到 `isError: false`,把失败当成功处理。
|
|
232263
|
+
*
|
|
232264
|
+
* 实测(F7):`queryEnv(action="usage")` 不带 envId 时抛出的引导文案就是这样返回的,
|
|
232265
|
+
* 只看 `isError` 的客户端会漏判。MCP 协议里 `isError` 是唯一可靠的失败标记,别省。
|
|
232266
|
+
*/
|
|
232267
|
+
function buildTextErrorResult(text) {
|
|
232268
|
+
return {
|
|
232269
|
+
content: [
|
|
232270
|
+
{
|
|
232271
|
+
type: "text",
|
|
232272
|
+
text,
|
|
232273
|
+
},
|
|
232274
|
+
],
|
|
232275
|
+
isError: true,
|
|
232276
|
+
};
|
|
232277
|
+
}
|
|
232035
232278
|
class ToolPayloadError extends Error {
|
|
232036
232279
|
payload;
|
|
232037
232280
|
constructor(payload) {
|
|
@@ -232144,6 +232387,9 @@ ${envId}
|
|
|
232144
232387
|
// 构建标题
|
|
232145
232388
|
const title = `MCP工具错误: ${toolName}`;
|
|
232146
232389
|
// 构建问题描述
|
|
232390
|
+
// ⚠️ MCP 版本必须优先取构建期注入的 __MCP_VERSION__:hosted 场景下进程是 BFF 的进程,
|
|
232391
|
+
// process.env.npm_package_version 是**宿主应用**的版本(实测报出 0.0.1,与 MCP 自身
|
|
232392
|
+
// 版本 2.34.2 自相矛盾);仅在未注入(源码直跑)时才回退到它。
|
|
232147
232393
|
const body = `## 错误描述
|
|
232148
232394
|
工具 \`${toolName}\` 执行时发生错误
|
|
232149
232395
|
|
|
@@ -232155,7 +232401,7 @@ ${envIdSection}
|
|
|
232155
232401
|
## 环境信息
|
|
232156
232402
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
232157
232403
|
- Node.js版本: ${process.version}
|
|
232158
|
-
- MCP 版本:${
|
|
232404
|
+
- MCP 版本:${( true ? "2.34.3" : 0) || 0 || 0}
|
|
232159
232405
|
- 系统架构: ${os_1.default.arch()}
|
|
232160
232406
|
- 时间: ${new Date().toISOString()}
|
|
232161
232407
|
- 请求ID: ${requestId}
|
|
@@ -232244,7 +232490,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
232244
232490
|
requestId,
|
|
232245
232491
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
232246
232492
|
});
|
|
232247
|
-
const mcpVersion = true ? "2.34.
|
|
232493
|
+
const mcpVersion = true ? "2.34.3" : 0;
|
|
232248
232494
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
232249
232495
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
232250
232496
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|