@cloudbase/cloudbase-mcp 2.34.6 → 2.34.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.cjs +5 -5
- package/dist/index.cjs +1809 -102
- package/dist/index.js +1823 -104
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import * as __WEBPACK_EXTERNAL_MODULE_lockfile__ from "lockfile";
|
|
|
16
16
|
import * as __WEBPACK_EXTERNAL_MODULE_net__ from "net";
|
|
17
17
|
import * as __WEBPACK_EXTERNAL_MODULE_node_crypto_803ecaf5__ from "node:crypto";
|
|
18
18
|
import * as __WEBPACK_EXTERNAL_MODULE_node_fs_75ed2103__ from "node:fs";
|
|
19
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_os_e12349cb__ from "node:os";
|
|
19
20
|
import * as __WEBPACK_EXTERNAL_MODULE_node_path_02319fef__ from "node:path";
|
|
20
21
|
import * as __WEBPACK_EXTERNAL_MODULE_os__ from "os";
|
|
21
22
|
import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path";
|
|
@@ -51,6 +52,7 @@ exports.getLoginState = getLoginState;
|
|
|
51
52
|
exports.logout = logout;
|
|
52
53
|
const toolbox_1 = __webpack_require__(2090);
|
|
53
54
|
const logger_js_1 = __webpack_require__(781);
|
|
55
|
+
const project_config_js_1 = __webpack_require__(9175);
|
|
54
56
|
const site_map_js_1 = __webpack_require__(4533);
|
|
55
57
|
const auth = toolbox_1.AuthSupervisor.getInstance({});
|
|
56
58
|
const authProgressState = {
|
|
@@ -455,8 +457,7 @@ async function peekLoginState(options) {
|
|
|
455
457
|
if ('_type' in envVarLoginState && envVarLoginState._type === 'api_key') {
|
|
456
458
|
(0, logger_js_1.debug)("peekLoginState: detected CLOUDBASE_API_KEY env var");
|
|
457
459
|
try {
|
|
458
|
-
|
|
459
|
-
const projectCwd = process.env.WORKSPACE_FOLDER_PATHS || process.cwd();
|
|
460
|
+
const projectCwd = (0, project_config_js_1.requireProjectRoot)();
|
|
460
461
|
// 换取网关按站点选型:显式 intl → ap-singapore;domestic/歧义 → toolbox 默认
|
|
461
462
|
// ap-shanghai(国内站多地域环境均经其全局路由,详见 resolveApiKeyExchangeRegion)
|
|
462
463
|
const exchangeRegion = (0, site_map_js_1.resolveApiKeyExchangeRegion)({
|
|
@@ -613,7 +614,7 @@ async function logout(options) {
|
|
|
613
614
|
await toolbox_1.authStore.set("credential", slotted);
|
|
614
615
|
}
|
|
615
616
|
else if (site === LEGACY_SITE) {
|
|
616
|
-
const cwd =
|
|
617
|
+
const cwd = (0, project_config_js_1.requireProjectRoot)();
|
|
617
618
|
await auth.logout({ cwd });
|
|
618
619
|
}
|
|
619
620
|
resetAuthProgressState();
|
|
@@ -652,6 +653,7 @@ const logger_js_1 = __webpack_require__(781);
|
|
|
652
653
|
const tool_result_js_1 = __webpack_require__(9645);
|
|
653
654
|
const site_map_js_1 = __webpack_require__(4533);
|
|
654
655
|
const project_config_js_1 = __webpack_require__(9175);
|
|
656
|
+
const local_endpoint_js_1 = __webpack_require__(6156);
|
|
655
657
|
// Timeout for envId auto-resolution flow.
|
|
656
658
|
// 10 minutes (600 seconds) - matches InteractiveServer timeout
|
|
657
659
|
const ENV_ID_TIMEOUT = 600000;
|
|
@@ -813,7 +815,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
813
815
|
}
|
|
814
816
|
// When CLOUDBASE_ENV_ID is set and credentials are not explicit, skip DescribeEnvs.
|
|
815
817
|
const hasExplicitCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
|
|
816
|
-
if (process.env.CLOUDBASE_ENV_ID && !hasExplicitCredentials) {
|
|
818
|
+
if (process.env.CLOUDBASE_ENV_ID && !hasExplicitCredentials && !cloudBaseOptions?.requestFn && !process.env.CLOUDBASE_LOCAL_ENDPOINT) {
|
|
817
819
|
return [{
|
|
818
820
|
envId: process.env.CLOUDBASE_ENV_ID,
|
|
819
821
|
}];
|
|
@@ -824,7 +826,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
824
826
|
...(regionOverride ? { region: regionOverride } : {}),
|
|
825
827
|
}).region;
|
|
826
828
|
let cloudbase;
|
|
827
|
-
if (cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey) {
|
|
829
|
+
if (cloudBaseOptions?.requestFn || (cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey)) {
|
|
828
830
|
cloudbase = createCloudBaseManagerWithOptions({
|
|
829
831
|
...cloudBaseOptions,
|
|
830
832
|
region,
|
|
@@ -1007,6 +1009,14 @@ class EnvironmentManager {
|
|
|
1007
1009
|
this._setCachedEnvId(loginState.envId);
|
|
1008
1010
|
return loginState.envId;
|
|
1009
1011
|
}
|
|
1012
|
+
// 3.1 未登录必须交回 AUTH_REQUIRED,不能继续往下走「选环境」。
|
|
1013
|
+
// 未登录时拿不到任何环境候选,落到 throwEnvRequiredError 会输出
|
|
1014
|
+
// 「当前已登录,但还没有可用环境」——把「没登录」误诊成「登录了但缺环境」。
|
|
1015
|
+
// 调用方读到这句会去 set_env 选环境,而候选列表永远为空,只能原样重试。
|
|
1016
|
+
// 与 getCloudBaseManager 的登录态分流保持同构。
|
|
1017
|
+
if (!loginState) {
|
|
1018
|
+
throwAuthRequiredError();
|
|
1019
|
+
}
|
|
1010
1020
|
// 4. 单环境自动绑定;多环境时返回结构化引导,不再触发交互弹窗
|
|
1011
1021
|
const envCandidates = await listAvailableEnvCandidates({ loginState });
|
|
1012
1022
|
if (envCandidates.length === 1) {
|
|
@@ -1055,11 +1065,13 @@ const envManager = new EnvironmentManager();
|
|
|
1055
1065
|
exports.envManager = envManager;
|
|
1056
1066
|
// 导出环境ID获取函数
|
|
1057
1067
|
async function getEnvId(cloudBaseOptions) {
|
|
1058
|
-
// 如果传入了 cloudBaseOptions 且包含 envId,直接返回
|
|
1059
1068
|
if (cloudBaseOptions?.envId) {
|
|
1060
1069
|
(0, logger_js_1.debug)('使用传入的 envId:', { envId: cloudBaseOptions.envId });
|
|
1061
1070
|
return cloudBaseOptions.envId;
|
|
1062
1071
|
}
|
|
1072
|
+
if ((0, local_endpoint_js_1.resolveLocalEndpoint)()) {
|
|
1073
|
+
return 'local';
|
|
1074
|
+
}
|
|
1063
1075
|
const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
|
|
1064
1076
|
if (cachedEnvId) {
|
|
1065
1077
|
(0, logger_js_1.debug)('使用缓存中的 envId:', { envId: cachedEnvId });
|
|
@@ -1164,7 +1176,16 @@ async function getDatabaseInstanceId(options) {
|
|
|
1164
1176
|
* 每次都实时获取最新的 token/secretId/secretKey
|
|
1165
1177
|
*/
|
|
1166
1178
|
async function getCloudBaseManager(options = {}) {
|
|
1167
|
-
const { requireEnvId = true,
|
|
1179
|
+
const { requireEnvId = true, authStrategy = 'fail_fast', } = options;
|
|
1180
|
+
let cloudBaseOptions = options.cloudBaseOptions;
|
|
1181
|
+
const localEndpoint = (0, local_endpoint_js_1.resolveLocalEndpoint)();
|
|
1182
|
+
if (localEndpoint && !cloudBaseOptions?.requestFn) {
|
|
1183
|
+
cloudBaseOptions = {
|
|
1184
|
+
...cloudBaseOptions,
|
|
1185
|
+
envId: cloudBaseOptions?.envId || 'local',
|
|
1186
|
+
requestFn: (0, local_endpoint_js_1.createLocalCloudApiRequestFn)(localEndpoint),
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1168
1189
|
const hasDirectCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
|
|
1169
1190
|
const hasRequestFn = !!(cloudBaseOptions?.requestFn);
|
|
1170
1191
|
// 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
|
|
@@ -2269,6 +2290,7 @@ const msgPush_js_1 = __webpack_require__(6191);
|
|
|
2269
2290
|
const setup_js_1 = __webpack_require__(8707);
|
|
2270
2291
|
const envSetup_js_1 = __webpack_require__(7148);
|
|
2271
2292
|
const interactive_js_1 = __webpack_require__(1838);
|
|
2293
|
+
const feedback_js_1 = __webpack_require__(9391);
|
|
2272
2294
|
exports.en = {
|
|
2273
2295
|
env: env_js_1.env.en,
|
|
2274
2296
|
storage: storage_js_1.storage.en,
|
|
@@ -2298,6 +2320,7 @@ exports.en = {
|
|
|
2298
2320
|
setup: setup_js_1.setup.en,
|
|
2299
2321
|
envSetup: envSetup_js_1.envSetup.en,
|
|
2300
2322
|
interactive: interactive_js_1.interactive.en,
|
|
2323
|
+
feedback: feedback_js_1.feedback.en,
|
|
2301
2324
|
};
|
|
2302
2325
|
|
|
2303
2326
|
|
|
@@ -2440,7 +2463,7 @@ const types_js_1 = __webpack_require__(9921);
|
|
|
2440
2463
|
exports.apps = (0, types_js_1.defineModule)({
|
|
2441
2464
|
queryTitle: "查询 CloudBase 应用部署状态",
|
|
2442
2465
|
queryDescription: "查询 CloudBase 应用部署的应用和版本。可查应用列表/详情、版本列表/详情;部署后用 getAppVersion 按 buildId 轮询构建状态;getBuildLog 可查询构建日志用于诊断失败原因。\n" +
|
|
2443
|
-
"action=getUploadUrl(只读)可获取预签名上传 URL:无本地文件系统时(cloud mode),先拿到 uploadUrl 自行 PUT 代码 zip,再用返回的 unixTimestamp 调 manageApps(action=deployApp, cosTimestamp) 触发部署。",
|
|
2466
|
+
"action=getUploadUrl(只读)可获取预签名上传 URL:无本地文件系统时(cloud mode),先拿到 uploadUrl 自行 PUT 代码 zip,再用返回的 unixTimestamp 调 manageApps(action=deployApp, cosTimestamp) 触发部署。uploadUrl 是一次性上传凭据,不要外传或写进工单。",
|
|
2444
2467
|
manageTitle: "部署应用到 CloudBase(独立子域名)",
|
|
2445
2468
|
manageDescription: "部署 Web 应用到 CloudBase(构建前后端,部署到独立子域名)。\n" +
|
|
2446
2469
|
"云端上传通道(cloud mode,无本地文件系统):queryApps(action=getUploadUrl) 或 manageApps(action=getUploadUrl) 获取预签名上传 URL → agent 自行 PUT 代码 zip 到 uploadUrl(带 uploadHeaders 与 Content-Type: application/zip)→ 用返回的 unixTimestamp 作为 cosTimestamp 调 deployApp 触发部署。\n" +
|
|
@@ -2473,7 +2496,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
2473
2496
|
uploadStep1: "1. 将代码打包为 zip(排除 node_modules/.git)",
|
|
2474
2497
|
uploadStep2: "2. 用 PUT 方法把 zip 上传到 uploadUrl,请求头带 Content-Type: application/zip 以及 uploadHeaders 中的每个 header",
|
|
2475
2498
|
uploadStep3: "3. 调用 manageApps(action=\"deployApp\", serviceName=\"{serviceName}\", cosTimestamp=<unixTimestamp>) 触发部署",
|
|
2476
|
-
getUploadUrlSuccess: "预签名上传 URL 获取成功。请将代码 zip PUT 上传到 uploadUrl(携带 uploadHeaders 与 Content-Type: application/zip),然后用返回的 unixTimestamp 作为 cosTimestamp 调用 manageApps(action=deployApp) 触发部署。",
|
|
2499
|
+
getUploadUrlSuccess: "预签名上传 URL 获取成功。请将代码 zip PUT 上传到 uploadUrl(携带 uploadHeaders 与 Content-Type: application/zip),然后用返回的 unixTimestamp 作为 cosTimestamp 调用 manageApps(action=deployApp) 触发部署。uploadUrl 是一次性上传凭据,不要外传或写进工单。",
|
|
2477
2500
|
getSuccess: "CloudBase 应用详情查询成功",
|
|
2478
2501
|
listVersionsSuccess: "CloudBase 应用版本列表查询成功",
|
|
2479
2502
|
buildIdRequired: "action=getBuildLog 时必须提供 buildId",
|
|
@@ -2536,7 +2559,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
2536
2559
|
}, {
|
|
2537
2560
|
queryTitle: "Query CloudBase app deployment status",
|
|
2538
2561
|
queryDescription: "Query CloudBase deployed apps and versions. Supports app list/detail and version list/detail; after deployment, poll build status by buildId with getAppVersion; getBuildLog retrieves build logs to diagnose failures.\n" +
|
|
2539
|
-
"action=getUploadUrl (read-only) returns a pre-signed upload URL: without a local filesystem (cloud mode), fetch the uploadUrl, PUT the code zip yourself, then call manageApps(action=deployApp, cosTimestamp) with the returned unixTimestamp to trigger deployment.",
|
|
2562
|
+
"action=getUploadUrl (read-only) returns a pre-signed upload URL: without a local filesystem (cloud mode), fetch the uploadUrl, PUT the code zip yourself, then call manageApps(action=deployApp, cosTimestamp) with the returned unixTimestamp to trigger deployment. The uploadUrl is a one-time upload credential; do not forward it or paste it into tickets.",
|
|
2540
2563
|
manageTitle: "Deploy app to CloudBase (dedicated subdomain)",
|
|
2541
2564
|
manageDescription: "Deploy web apps to CloudBase (builds frontend and backend, deploys to a dedicated subdomain).\n" +
|
|
2542
2565
|
"Cloud upload channel (cloud mode, no local filesystem): queryApps(action=getUploadUrl) or manageApps(action=getUploadUrl) returns a pre-signed upload URL → agent PUTs the code zip to uploadUrl itself (with uploadHeaders and Content-Type: application/zip) → call deployApp with the returned unixTimestamp as cosTimestamp to trigger deployment.\n" +
|
|
@@ -2569,7 +2592,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
2569
2592
|
uploadStep1: "1. Pack the code into a zip (exclude node_modules/.git)",
|
|
2570
2593
|
uploadStep2: "2. PUT the zip to uploadUrl with header Content-Type: application/zip and every header from uploadHeaders",
|
|
2571
2594
|
uploadStep3: "3. Call manageApps(action=\"deployApp\", serviceName=\"{serviceName}\", cosTimestamp=<unixTimestamp>) to trigger deployment",
|
|
2572
|
-
getUploadUrlSuccess: "Pre-signed upload URL obtained. PUT the code zip to uploadUrl (with uploadHeaders and Content-Type: application/zip), then call manageApps(action=deployApp) with the returned unixTimestamp as cosTimestamp to trigger deployment.",
|
|
2595
|
+
getUploadUrlSuccess: "Pre-signed upload URL obtained. PUT the code zip to uploadUrl (with uploadHeaders and Content-Type: application/zip), then call manageApps(action=deployApp) with the returned unixTimestamp as cosTimestamp to trigger deployment. The uploadUrl is a one-time upload credential; do not forward it or paste it into tickets.",
|
|
2573
2596
|
getSuccess: "CloudBase app details retrieved successfully",
|
|
2574
2597
|
listVersionsSuccess: "CloudBase app version list retrieved successfully",
|
|
2575
2598
|
buildIdRequired: "buildId is required when action=getBuildLog",
|
|
@@ -2651,7 +2674,7 @@ exports.capi = (0, types_js_1.defineModule)({
|
|
|
2651
2674
|
docGuidanceCloudbase: "优先查阅 CloudBase API 概览 {controlPlaneUrl} 与云开发依赖资源接口指引 {dependencyUrl}。",
|
|
2652
2675
|
docGuidanceMonitor: "请优先核对云监控(腾讯云可观测平台)官方 API 文档:API 概览 https://cloud.tencent.com/document/product/649/30343 ,单 Action 详细文档在 https://cloud.tencent.com/document/api/248/ 产品线下。",
|
|
2653
2676
|
docGuidanceGeneric: "请优先核对对应官方云 API 文档;若你的场景其实是通过 HTTP 协议直接集成 auth/functions/cloudrun/storage/mysqldb 等 CloudBase 业务 API,请优先使用 OpenAPI / Swagger 或 searchKnowledgeBase(mode=\"openapi\"),不要继续猜测管控面 Action。",
|
|
2654
|
-
camAuthGuidance: "
|
|
2677
|
+
camAuthGuidance: "这是 CAM 权限不足。先分清是谁缺权限,再决定怎么补:用 auth(action=\"status\") 看 credential_scope,用 callCloudApi(service=\"sts\", action=\"GetCallerIdentity\") 看实际调用者(Type=CAMRole 表示角色扮演身份,UserId 里带角色名)。若缺权限的是角色(如 TCB_QcsRole),补的是挂在**角色**上的策略 —— 给用户一条 cam/role/grant 一键授权链接,拼法与 principal 取值见 skill cloud-api-operations 的 §3.2;若是账号级身份本人,则由主账号给这个身份追加策略(用腾讯云 SecretId/SecretKey 登录时,调用者就是该身份)。环境级 API Key 只能访问绑定环境的数据面,跨产品调用需改用账号级凭据:auth(action=\"start_auth\", authMode=\"device\")。另请确认目标资源确实属于当前账号。",
|
|
2655
2678
|
errorInvalidAction: "Action `{action}` 可能不存在或不对外开放。请不要继续猜测 Action 名称,先确认 service=`{service}` 下该 Action 在当前 API 版本是否真实存在。",
|
|
2656
2679
|
errorSuggestedActions: "可能的 tcb Action:{candidates}。",
|
|
2657
2680
|
errorRegionParam: "Region 不是 Action body 参数。请使用 callCloudApi 顶层参数 region(例如 region=\"ap-singapore\"),对应 X-TC-Region。",
|
|
@@ -2685,7 +2708,7 @@ exports.capi = (0, types_js_1.defineModule)({
|
|
|
2685
2708
|
docGuidanceCloudbase: "Prefer the CloudBase API overview {controlPlaneUrl} and the dependent-resource API guide {dependencyUrl}.",
|
|
2686
2709
|
docGuidanceMonitor: "Check the official Cloud Monitor (Tencent Cloud Observability Platform) API docs first: API overview https://cloud.tencent.com/document/product/649/30343 , per-Action docs live under https://cloud.tencent.com/document/api/248/ .",
|
|
2687
2710
|
docGuidanceGeneric: "Check the corresponding official cloud API docs first; if your scenario is actually integrating CloudBase business APIs such as auth/functions/cloudrun/storage/mysqldb over HTTP, prefer OpenAPI / Swagger or searchKnowledgeBase(mode=\"openapi\") instead of guessing control-plane Actions.",
|
|
2688
|
-
camAuthGuidance: "This is
|
|
2711
|
+
camAuthGuidance: "This is a CAM permission gap. Work out who is missing it before choosing a fix: auth(action=\"status\") shows credential_scope, and callCloudApi(service=\"sts\", action=\"GetCallerIdentity\") shows the actual caller (Type=CAMRole means an assumed role; the UserId carries the role name). When the role is the one missing permission (e.g. TCB_QcsRole), the fix is a policy attached to that role — give the user a cam/role/grant authorization link, built as described in the cloud-api-operations skill, section 3.2. When an account-level identity is the caller, the main account attaches the policy to it (signing in with a Tencent Cloud SecretId/SecretKey makes the caller that identity). An environment-level API Key can only reach the bound environment's data plane; for cross-product calls switch to account-level credentials: auth(action=\"start_auth\", authMode=\"device\"). Also confirm the target resource belongs to the current account.",
|
|
2689
2712
|
errorInvalidAction: "Action `{action}` may not exist or is not publicly available. Do not keep guessing Action names; first confirm the Action actually exists under service=`{service}` in the current API version.",
|
|
2690
2713
|
errorSuggestedActions: "Possible tcb Actions: {candidates}.",
|
|
2691
2714
|
errorRegionParam: "Region is not an Action body parameter. Use the callCloudApi top-level region parameter (e.g. region=\"ap-singapore\"), which maps to X-TC-Region.",
|
|
@@ -2729,7 +2752,7 @@ exports.cloudrun = (0, types_js_1.defineModule)({
|
|
|
2729
2752
|
"manage.description": "管理云托管服务,按开发顺序支持:开通云托管环境(initEnv)、初始化项目(可从模板开始,模板列表可通过 queryCloudRun 查询)、下载服务代码、本地运行(仅函数型服务)、部署代码、仅更新配置(updateConfig,无需重新上传代码)、删除服务。deploy 支持两种方式:1) 源码构建(传入 targetPath,本地代码打包上传,默认路径);2) 已有镜像部署(传入 imageUrl,如 ccr.ccs.tencentyun.com/ns/img:v1,走 DeployType=image 容器型部署,targetPath 可省略)。deploy 语义为「触发部署 + 轻量等待任务注册」(最多约 45s;不需要 buildId 时可传 waitRegistration=false 跳过等待)。源码构建返回 buildId,用 getDeployLog 轮询构建进度后再 getProcessLog;镜像部署(imageUrl)BuildId 常为 0,跳过 getDeployLog,返回 runId/next_step 引导 getProcessLog(或先 getDeployRecords 取 RunId)。若用户明确指定镜像或无需重新构建,必须传 imageUrl,不要仅因本地有源码目录就回退到源码构建。deploy 对已存在服务会先读取远程配置再合并(保留 VpcConf/EnvParams/OpenAccessTypes)。updateConfig 对齐控制台服务设置页。删除操作需要确认,建议设置force=true。新环境首次部署前若提示未开通云托管,先调用 initEnv 开通(异步、幂等)。",
|
|
2730
2753
|
"error.managerInitFailed": "CloudBase Manager 初始化失败,请检查凭据与环境配置。",
|
|
2731
2754
|
"error.unsupportedAction": "不支持的操作:{action}",
|
|
2732
|
-
"error.pathOutsideCwd": "路径必须在当前工作目录内:{cwd}",
|
|
2755
|
+
"error.pathOutsideCwd": "路径必须在当前工作目录内:{cwd}。允许:`{cwd}` 下的路径,或传入项目目录的绝对路径(相对路径不能通过 `../` 逃逸 CWD)。收到的解析路径:{resolvedPath}。建议:将 targetPath 设为项目绝对路径(deploy/download/init)。",
|
|
2733
2756
|
"error.commonServiceQueryEnv": "当前 CloudBase Manager 不支持 commonService,无法查询云托管环境开通状态。",
|
|
2734
2757
|
"error.commonServiceInitEnv": "当前 CloudBase Manager 不支持 commonService,无法初始化云托管环境。",
|
|
2735
2758
|
"error.commonServiceSubmitDiff": "当前 CloudBase Manager 不支持 commonService,无法调用 SubmitServerConfigChangeDiff。",
|
|
@@ -2919,7 +2942,7 @@ exports.cloudrun = (0, types_js_1.defineModule)({
|
|
|
2919
2942
|
"manage.description": "Manage CloudRun services, in development order: provision the CloudRun env (initEnv), initialize a project (optionally from a template; list templates via queryCloudRun), download service code, run locally (function services only), deploy code, update config only (updateConfig, no code upload needed), and delete the service. deploy supports two modes: 1) source build (pass targetPath; local code is packaged and uploaded, the default); 2) existing image deploy (pass imageUrl, e.g. ccr.ccs.tencentyun.com/ns/img:v1; DeployType=image container deploy, targetPath optional). deploy means \"trigger deploy + lightweight wait for task registration\" (up to ~45s; pass waitRegistration=false to skip the wait when you don't need the buildId). Source builds return buildId — poll getDeployLog for build progress, then getProcessLog; image deploys (imageUrl) usually have BuildId=0 — getDeployLog is skipped, and runId/next_step guide you to getProcessLog (or getDeployRecords first for RunId). If the user explicitly specifies an image or no rebuild is needed, you must pass imageUrl instead of falling back to a source build just because a local source directory exists. For existing services, deploy reads the remote config first and merges (preserving VpcConf/EnvParams/OpenAccessTypes). updateConfig aligns with the console service settings page. Deletion requires confirmation; set force=true. If a new env reports CloudRun not provisioned before the first deploy, call initEnv first (async, idempotent).",
|
|
2920
2943
|
"error.managerInitFailed": "Failed to initialize CloudBase manager. Please check your credentials and environment configuration.",
|
|
2921
2944
|
"error.unsupportedAction": "Unsupported action: {action}",
|
|
2922
|
-
"error.pathOutsideCwd": "Path must be within current working directory: {cwd}",
|
|
2945
|
+
"error.pathOutsideCwd": "Path must be within current working directory: {cwd}. Allowed: paths under `{cwd}`, or pass an absolute path to the project directory (relative paths cannot escape CWD via `../`). Received resolved path: {resolvedPath}. Suggestion: set targetPath to the absolute project path (deploy/download/init).",
|
|
2923
2946
|
"error.commonServiceQueryEnv": "Current CloudBase Manager does not support commonService; cannot query CloudRun env status.",
|
|
2924
2947
|
"error.commonServiceInitEnv": "Current CloudBase Manager does not support commonService; cannot initialize CloudRun env.",
|
|
2925
2948
|
"error.commonServiceSubmitDiff": "Current CloudBase Manager does not support commonService; cannot call SubmitServerConfigChangeDiff.",
|
|
@@ -3858,11 +3881,28 @@ exports.databaseSQL = (0, types_js_1.defineModule)({
|
|
|
3858
3881
|
"gate.pgOnlyMode": "当前环境({envId})已开通 PostgreSQL,MySQL 不可用。请改用 managePgDatabase / queryPgDatabase,而不是 manageMysqlDatabase / queryMysqlDatabase。",
|
|
3859
3882
|
"gate.useManagePg": "请使用 managePgDatabase 执行 PostgreSQL 操作",
|
|
3860
3883
|
"queryMysqlDatabase.title": "查询 CloudBase MySQL 数据库状态或执行只读 SQL",
|
|
3861
|
-
"queryMysqlDatabase.description": "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL
|
|
3862
|
-
"schema.query.action": "runQuery=执行只读 SQL;describeCreateResult=查询 CreateMySQL 结果;describeTaskStatus=查询 MySQL 任务状态;getInstanceInfo=获取不含连接凭据的生命周期上下文;describeInstance=getInstanceInfo 的别名;getConnectionInfo=透传可能包含凭据的原始连接/集群载荷(仅限 TCP
|
|
3884
|
+
"queryMysqlDatabase.description": "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL 任务状态、获取当前实例生命周期上下文,以及查询实例慢查询/错误日志(对齐 Manager SDK describeInstanceSlowQueries / describeInstanceErrorLogs)。标准 getInstanceInfo/describeInstance 不返回连接凭据;仅 getConnectionInfo 透传原始连接/集群载荷(含可能的凭据),且仅用于显式 TCP 迁移。业务 CRUD 优先使用 SDK 或 runQuery/runStatement。",
|
|
3885
|
+
"schema.query.action": "runQuery=执行只读 SQL;describeCreateResult=查询 CreateMySQL 结果;describeTaskStatus=查询 MySQL 任务状态;getInstanceInfo=获取不含连接凭据的生命周期上下文;describeInstance=getInstanceInfo 的别名;getConnectionInfo=透传可能包含凭据的原始连接/集群载荷(仅限 TCP 迁移例外场景);describeInstanceSlowQueries=查询实例慢查询日志;describeInstanceErrorLogs=查询实例错误日志",
|
|
3863
3886
|
"schema.query.sql": "action=runQuery 使用的只读 SQL",
|
|
3864
|
-
"schema.query.request": "describeCreateResult/describeTaskStatus
|
|
3865
|
-
"schema.query.dbInstance": "runQuery
|
|
3887
|
+
"schema.query.request": "describeCreateResult/describeTaskStatus/describeInstanceSlowQueries/describeInstanceErrorLogs 使用的官方请求载荷(可含 InstanceId 等)",
|
|
3888
|
+
"schema.query.dbInstance": "runQuery / 慢查/错误日志可选的 SQL 数据库实例上下文",
|
|
3889
|
+
"schema.query.startTime": "慢查/错误日志查询开始时间(YYYY-MM-DD HH:mm:ss)",
|
|
3890
|
+
"schema.query.endTime": "慢查/错误日志查询结束时间(YYYY-MM-DD HH:mm:ss)",
|
|
3891
|
+
"schema.query.limit": "慢查/错误日志返回条数限制",
|
|
3892
|
+
"schema.query.offset": "慢查/错误日志分页偏移",
|
|
3893
|
+
"schema.query.username": "慢查过滤:用户名",
|
|
3894
|
+
"schema.query.host": "慢查过滤:客户端 host",
|
|
3895
|
+
"schema.query.database": "慢查过滤:数据库名",
|
|
3896
|
+
"schema.query.orderBy": "排序字段。慢查支持 QueryTime/LockTime/RowsExamined/RowsSent;错误日志支持 Timestamp",
|
|
3897
|
+
"schema.query.orderByType": "排序方向:asc/desc(大小写均可)",
|
|
3898
|
+
"schema.query.sqlText": "慢查过滤:SQL 文本片段",
|
|
3899
|
+
"schema.query.logLevels": "错误日志等级过滤,可选值:error / warning / note",
|
|
3900
|
+
"schema.query.keyWords": "错误日志关键字模糊搜索列表",
|
|
3901
|
+
"instanceLogs.notProvisioned": "MySQL 尚未开通,无法查询实例慢查/错误日志。",
|
|
3902
|
+
"instanceLogs.instanceIdRequired": "无法解析 CynosDB InstanceId。请先 getInstanceInfo,或通过 dbInstance.instanceId / request.InstanceId 传入。",
|
|
3903
|
+
"instanceLogs.resolveInstanceId": "先查询实例信息以获取可用的 InstanceId。",
|
|
3904
|
+
"instanceLogs.slowQueriesSuccess": "MySQL 实例慢查询日志检索成功。",
|
|
3905
|
+
"instanceLogs.errorLogsSuccess": "MySQL 实例错误日志检索成功。",
|
|
3866
3906
|
"manageMysqlDatabase.title": "管理 CloudBase MySQL 数据库生命周期或执行写入 SQL",
|
|
3867
3907
|
"manageMysqlDatabase.description": "管理 CloudBase MySQL 数据库资源。支持开通 MySQL、销毁 MySQL、执行写入 SQL/DDL,以及初始化数据库 Schema。注意:必须先开通 MySQL(action=provisionMySQL,confirm=true)才能执行 runStatement 或 initializeSchema。若 MySQL 尚未开通,工具会返回 MYSQL_NOT_CREATED 并给出开通的 nextAction 提示。",
|
|
3868
3908
|
"schema.manage.action": "provisionMySQL=创建 MySQL 实例;destroyMySQL=销毁 MySQL 实例;runStatement=执行写入 SQL 或 DDL;initializeSchema=按顺序执行 Schema 初始化语句",
|
|
@@ -3933,11 +3973,28 @@ exports.databaseSQL = (0, types_js_1.defineModule)({
|
|
|
3933
3973
|
"gate.pgOnlyMode": "This environment ({envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of manageMysqlDatabase / queryMysqlDatabase.",
|
|
3934
3974
|
"gate.useManagePg": "Use managePgDatabase for PostgreSQL operations",
|
|
3935
3975
|
"queryMysqlDatabase.title": "Query CloudBase MySQL database status or run read-only SQL",
|
|
3936
|
-
"queryMysqlDatabase.description": "Query CloudBase MySQL database information. Supports running read-only SQL, checking the MySQL provisioning result, querying MySQL task status,
|
|
3937
|
-
"schema.query.action": "runQuery=execute read-only SQL; describeCreateResult=query CreateMySQL result; describeTaskStatus=query MySQL task status; getInstanceInfo=get lifecycle context without connection credentials; describeInstance=alias of getInstanceInfo; getConnectionInfo=passthrough raw connection/cluster payload including possible credentials (TCP migration exception only)",
|
|
3976
|
+
"queryMysqlDatabase.description": "Query CloudBase MySQL database information. Supports running read-only SQL, checking the MySQL provisioning result, querying MySQL task status, getting the current instance lifecycle context, and querying instance slow queries / error logs (aligned with Manager SDK describeInstanceSlowQueries / describeInstanceErrorLogs). Standard getInstanceInfo/describeInstance never returns connection credentials; only getConnectionInfo passes through the raw connection/cluster payload (possibly including credentials), and only for explicit TCP migration. Prefer the SDK or runQuery/runStatement for business CRUD.",
|
|
3977
|
+
"schema.query.action": "runQuery=execute read-only SQL; describeCreateResult=query CreateMySQL result; describeTaskStatus=query MySQL task status; getInstanceInfo=get lifecycle context without connection credentials; describeInstance=alias of getInstanceInfo; getConnectionInfo=passthrough raw connection/cluster payload including possible credentials (TCP migration exception only); describeInstanceSlowQueries=query instance slow query logs; describeInstanceErrorLogs=query instance error logs",
|
|
3938
3978
|
"schema.query.sql": "Read-only SQL used by action=runQuery",
|
|
3939
|
-
"schema.query.request": "Official request payload used by describeCreateResult/describeTaskStatus",
|
|
3940
|
-
"schema.query.dbInstance": "Optional SQL database instance context for runQuery",
|
|
3979
|
+
"schema.query.request": "Official request payload used by describeCreateResult/describeTaskStatus/describeInstanceSlowQueries/describeInstanceErrorLogs (may include InstanceId, etc.)",
|
|
3980
|
+
"schema.query.dbInstance": "Optional SQL database instance context for runQuery / slow-query / error-log actions",
|
|
3981
|
+
"schema.query.startTime": "Slow-query / error-log query start time (YYYY-MM-DD HH:mm:ss)",
|
|
3982
|
+
"schema.query.endTime": "Slow-query / error-log query end time (YYYY-MM-DD HH:mm:ss)",
|
|
3983
|
+
"schema.query.limit": "Max rows for slow-query / error-log results",
|
|
3984
|
+
"schema.query.offset": "Pagination offset for slow-query / error-log results",
|
|
3985
|
+
"schema.query.username": "Slow-query filter: username",
|
|
3986
|
+
"schema.query.host": "Slow-query filter: client host",
|
|
3987
|
+
"schema.query.database": "Slow-query filter: database name",
|
|
3988
|
+
"schema.query.orderBy": "Sort field. Slow queries: QueryTime/LockTime/RowsExamined/RowsSent; error logs: Timestamp",
|
|
3989
|
+
"schema.query.orderByType": "Sort direction: asc/desc (case-insensitive)",
|
|
3990
|
+
"schema.query.sqlText": "Slow-query filter: SQL text fragment",
|
|
3991
|
+
"schema.query.logLevels": "Error log level filter. Allowed values: error / warning / note",
|
|
3992
|
+
"schema.query.keyWords": "Error log keyword fuzzy-search list",
|
|
3993
|
+
"instanceLogs.notProvisioned": "MySQL is not provisioned yet, so instance slow/error logs cannot be queried.",
|
|
3994
|
+
"instanceLogs.instanceIdRequired": "Unable to resolve CynosDB InstanceId. Call getInstanceInfo first, or pass dbInstance.instanceId / request.InstanceId.",
|
|
3995
|
+
"instanceLogs.resolveInstanceId": "Query instance info first to obtain a usable InstanceId.",
|
|
3996
|
+
"instanceLogs.slowQueriesSuccess": "MySQL instance slow query logs retrieved successfully.",
|
|
3997
|
+
"instanceLogs.errorLogsSuccess": "MySQL instance error logs retrieved successfully.",
|
|
3941
3998
|
"manageMysqlDatabase.title": "Manage CloudBase MySQL database lifecycle or run write SQL",
|
|
3942
3999
|
"manageMysqlDatabase.description": "Manage CloudBase MySQL database resources. Supports provisioning MySQL, destroying MySQL, running write SQL/DDL, and initializing the database schema. Note: MySQL must be provisioned first (action=provisionMySQL, confirm=true) before runStatement or initializeSchema can run. If MySQL is not provisioned, the tool returns MYSQL_NOT_CREATED with a provisioning nextAction hint.",
|
|
3943
4000
|
"schema.manage.action": "provisionMySQL=create MySQL instance; destroyMySQL=destroy MySQL instance; runStatement=execute write SQL or DDL; initializeSchema=run ordered schema initialization statements",
|
|
@@ -4747,6 +4804,49 @@ exports.envSetup = (0, types_js_1.defineModule)({
|
|
|
4747
4804
|
});
|
|
4748
4805
|
|
|
4749
4806
|
|
|
4807
|
+
/***/ },
|
|
4808
|
+
|
|
4809
|
+
/***/ 9391
|
|
4810
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
4811
|
+
|
|
4812
|
+
var __webpack_unused_export__;
|
|
4813
|
+
|
|
4814
|
+
__webpack_unused_export__ = ({ value: true });
|
|
4815
|
+
exports.feedback = void 0;
|
|
4816
|
+
const types_js_1 = __webpack_require__(9921);
|
|
4817
|
+
exports.feedback = (0, types_js_1.defineModule)({
|
|
4818
|
+
title: "整理本次开发反馈",
|
|
4819
|
+
description: "把当前这次 CloudBase 开发整理成用户可以自己提交的反馈。" +
|
|
4820
|
+
"作品做出来了,用它生成案例,方便展示;开发不顺利,用它生成复盘,方便把卡点反馈给平台。" +
|
|
4821
|
+
"\n\n**什么时候用**:" +
|
|
4822
|
+
"\n- `channel=\"case\"`:部署或发布已经成功,用户愿意把作品放到案例墙时使用。返回案例草稿;用户确认后附上预填好的新建 issue 链接。" +
|
|
4823
|
+
"\n- `channel=\"retrospective\"`:用户表示这次开发不顺利、想反馈时使用。根据本会话里真实的工具调用失败生成复盘草稿;用户确认后同样附上预填链接。" +
|
|
4824
|
+
"\n\n**怎么用**:" +
|
|
4825
|
+
"\n- 第一次不要传 `confirmed`。先把返回的草稿全文给用户看。" +
|
|
4826
|
+
"\n- 用户明确同意后,再以 `confirmed=true` 调用。这时才会返回可打开的链接。" +
|
|
4827
|
+
"\n- 本工具不会替用户提交。链接里的正文就是本次返回的 draft,不要改写成另一份再让用户提交。" +
|
|
4828
|
+
"\n- 不采集对话轮次,不要编造轮次、作品名、简介或公网地址。" +
|
|
4829
|
+
"\n- 国际站是英文草稿和 GitHub 链接(body 参数)。国内站是中文草稿,链接指向 CNB 上公开的 CloudBase-AI-ToolKit 仓库,正文放在模板字段 session。若页面没自动填上,把 draft 粘贴到「本次会话记录」。",
|
|
4830
|
+
"schema.channel": "反馈用途:`case` 是把已完成的作品整理成案例;`retrospective` 是把这次不顺利的开发整理成复盘。",
|
|
4831
|
+
"schema.confirmed": "用户是否已经看过草稿全文并明确同意提交。省略或 false 时只返回草稿、不给链接。",
|
|
4832
|
+
}, {
|
|
4833
|
+
title: "Prepare feedback for this session",
|
|
4834
|
+
description: "Turn this CloudBase session into feedback the user can submit themselves. " +
|
|
4835
|
+
"Use it to showcase a finished work, or to report a session that was hard to finish." +
|
|
4836
|
+
"\n\n**When to use**:" +
|
|
4837
|
+
"\n- `channel=\"case\"`: the deploy or publish already succeeded and the user wants the work on the case wall. Returns a case draft, and a prefilled new-issue link after the user confirms." +
|
|
4838
|
+
"\n- `channel=\"retrospective\"`: the user says this session went badly and wants to report it. Builds the retrospective from tool failures that actually happened in this session, and adds a prefilled link after confirmation." +
|
|
4839
|
+
"\n\n**How to use**:" +
|
|
4840
|
+
"\n- Do not pass `confirmed` on the first call. Show the returned draft to the user in full." +
|
|
4841
|
+
"\n- Call again with `confirmed=true` only after the user explicitly agrees. That call returns the link." +
|
|
4842
|
+
"\n- This tool does not submit the issue. The link body is the draft in this response. Do not rewrite it and ask the user to submit the rewrite." +
|
|
4843
|
+
"\n- Conversation turns are not collected. Do not invent a turn count, title, summary, or public URL." +
|
|
4844
|
+
"\n- International site: English draft and a GitHub link (body parameter). China site: Chinese draft and a link to the public CloudBase-AI-ToolKit repo on CNB. The draft is placed in the template field id session. If the page does not fill it, paste the draft into that field.",
|
|
4845
|
+
"schema.channel": "What the feedback is for: `case` turns a finished work into a showcase entry; `retrospective` turns a difficult session into a write-up.",
|
|
4846
|
+
"schema.confirmed": "Whether the user has read the full draft and agreed to submit it. Omit or pass false to return the draft only, with no link.",
|
|
4847
|
+
});
|
|
4848
|
+
|
|
4849
|
+
|
|
4750
4850
|
/***/ },
|
|
4751
4851
|
|
|
4752
4852
|
/***/ 8015
|
|
@@ -5056,7 +5156,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5056
5156
|
"opErr.default": "请检查函数名、目录结构和环境中的函数状态后重试。",
|
|
5057
5157
|
"opErr.prefix": "[{operation}] {message}\n建议:",
|
|
5058
5158
|
confirmRequired: "{action} 是危险操作,请显式传入 confirm=true 后再执行",
|
|
5059
|
-
"cloudMode.localOnly": "{action} 在 cloud mode
|
|
5159
|
+
"cloudMode.localOnly": "{action} 在 cloud mode 下不可用,因为该操作依赖本地函数代码目录。可用出路:1) 使用镜像部署(runtime=CustomImage + imageConfig);2) 使用 ZIP 两段式部署:先 queryFunctions action=getFunctionUploadUrl 获取预签名上传地址,PUT 代码 zip 后通过 manageFunctions 的 code 入参部署(阶段 B 同样不依赖本地目录)。",
|
|
5060
5160
|
"cloudMode.contentPathUnsupported": "createLayerVersion 在 cloud mode 下不支持 contentPath,本地文件内容请改为 base64Content 或改用本地模式执行。",
|
|
5061
5161
|
offsetLimitTooLarge: "offset+limit 不能大于 10000",
|
|
5062
5162
|
startTimeInvalid: "startTime 格式错误: \"{value}\"。必须使用 YYYY-MM-DD HH:mm:ss 格式(如 2024-01-01 00:00:00)",
|
|
@@ -5069,6 +5169,9 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5069
5169
|
"deployStatus.cloudMode": "{action} 在 cloud mode 下不可用:异步部署任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略的真实执行在 cloud mode 下都不支持(需要读取本地构建上下文或本地 Docker),因此不会存在任何 taskId。buildStrategy=image 走同步部署,直接在 manageFunctions 的返回里拿结果,也不需要查询部署状态。如需异步镜像构建部署,请改用本地 MCP 模式。",
|
|
5070
5170
|
deployTaskNotFound: "未找到部署任务 {taskId};部署任务不存在,可能已过期、不属于当前环境 {envId},或 MCP Server 已重启(任务仅保存在 MCP 进程内存中)。",
|
|
5071
5171
|
unsupportedAction: "不支持的操作类型: {action}",
|
|
5172
|
+
storageMissing: "当前环境没有可用的对象存储桶(DescribeEnvs 未返回 Storages),无法使用 COS 两段式部署。请检查环境存储配置,或改用本地模式部署。共享存储桶(ExternalStorage)环境同样不支持该通道。",
|
|
5173
|
+
credentialMissing: "当前凭据缺少 SecretId/SecretKey(如 IDE 代理模式),无法本地铸造 COS 预签名上传地址。请改用本地模式或包含永久密钥/临时密钥的登录方式。",
|
|
5174
|
+
uploadTargetNotFound: "代码包上传目标不在本进程的登记里:{objectName}。ZIP 两段式部署要求 code 三元组来自本进程刚返回的 getFunctionUploadUrl(同一个 MCP 进程、同一个环境);MCP Server 已重启、换了环境、或自行拼装 cosObjectName / cosBucketName 都会落到这里。请重新调用 queryFunctions action=getFunctionUploadUrl 取地址,按返回值上传代码包,再用返回的三元组调用本 action。",
|
|
5072
5175
|
// ---- nextActions reasons ----
|
|
5073
5176
|
"reason.continuePolling": "继续查询云函数部署状态",
|
|
5074
5177
|
"reason.getDetail": "查看单个函数详情",
|
|
@@ -5107,6 +5210,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5107
5210
|
"reason.imageFnReady": "确认镜像函数已就绪(Active)",
|
|
5108
5211
|
"reason.imageUpdateReady": "确认镜像更新后函数已就绪(Active)",
|
|
5109
5212
|
"reason.imageNextIteration": "后续迭代只需用新镜像 tag 调用 updateFunctionCode 更新镜像",
|
|
5213
|
+
"reason.cosCreate": "把 PUT 好的代码 zip 通过 code 入参部署为函数(两段式阶段 B)",
|
|
5110
5214
|
"reason.imageGatewayRoute": "如需通过 URL 访问镜像 HTTP 函数,显式创建 Domain/Route 访问入口并传 type=\"HTTP\"(映射 WEB_SCF)",
|
|
5111
5215
|
"reason.latestConfig": "确认最新函数配置",
|
|
5112
5216
|
"reason.publishVersion": "发布函数新版本(对齐 tcb fn publish-version)",
|
|
@@ -5126,12 +5230,15 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5126
5230
|
gotLayerVersionDetail: "已获取层 {layerName} 版本 {layerVersion} 的详情",
|
|
5127
5231
|
gotFunctionTriggers: "已获取函数 {fnName} 的触发器列表",
|
|
5128
5232
|
gotDownloadUrl: "已获取函数 {fnName} 的代码下载链接",
|
|
5233
|
+
gotUploadUrl: "已生成函数代码包上传地址({seconds} 秒内有效)。下一步:PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带),再调用 manageFunctions createFunction/updateFunctionCode 并传入 code 三元组(cosBucketName/cosObjectName/cosBucketRegion)完成部署。该 uploadUrl 等同一次性上传凭据,不要外传或写进工单;若上传前已过期,重新调用 getFunctionUploadUrl 取新地址",
|
|
5129
5234
|
gotFunctionVersions: "已获取函数 {fnName} 的版本列表",
|
|
5130
5235
|
gotFunctionAlias: "已获取函数 {fnName} 的别名 {aliasName}",
|
|
5131
5236
|
publishedVersion: "已发布函数 {fnName} 的新版本 {version}",
|
|
5132
5237
|
updatedFunctionAlias: "已更新函数 {fnName} 别名 {aliasName}(主版本 {version})",
|
|
5133
5238
|
createdHttpFunctionMessage: "已创建 HTTP 函数 {fnName}。如果后续需要通过 URL 访问,请显式调用 manageGateway(action=\"createRoute\"),并把 upstreamResourceType=\"WEB_SCF\" 一起传入,再按实际路径和鉴权需求创建访问入口。评测或其他外部调用方可能会以匿名身份访问,而且失败后不一定会把 EXCEED_AUTHORITY 再反馈给 AI;交付前请主动确认访问路径和函数安全规则,若已出现 EXCEED_AUTHORITY,请先调用 queryPermissions(action=\"getResourcePermission\", resourceType=\"function\", resourceId=\"{fnName}\") 查看当前规则,再按需要使用 managePermissions(action=\"updateResourcePermission\") 调整权限。",
|
|
5134
5239
|
createdFunction: "已创建函数 {fnName}",
|
|
5240
|
+
cosCreatedMessage: "已基于环境 COS 桶中的代码包(deployMode=cos)创建函数 {fnName}。部署后可用 queryFunctions(action=\"getFunctionDetail\") 确认函数已就绪。",
|
|
5241
|
+
cosUpdatedMessage: "已用环境 COS 桶中的新代码包(deployMode=cos)更新函数 {fnName} 的代码。部署后可用 queryFunctions(action=\"getFunctionDetail\") 确认函数已就绪(Active)。",
|
|
5135
5242
|
imageCreatedMessage: "已基于镜像 {imageUri} 创建 HTTP 函数 {fnName}。请确认 TCR、SCF 与构建管道处于同一地域;如需通过 URL 访问,请显式调用 manageGateway(action=\"createRoute\", upstreamResourceType=\"WEB_SCF\") 并按需调整函数安全规则。部署后可用 queryFunctions(action=\"getFunctionDetail\") 确认函数已就绪。",
|
|
5136
5243
|
imageUpdatedMessage: "已将函数 {fnName} 的镜像更新为 {imageUri}。部署后可用 queryFunctions(action=\"getFunctionDetail\") 确认函数已就绪(Active)。",
|
|
5137
5244
|
updatedCode: "已更新函数 {fnName} 的代码",
|
|
@@ -5197,12 +5304,12 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5197
5304
|
"schema.create.layers": "Layer 配置",
|
|
5198
5305
|
"schema.manageLayer.name": "层名称",
|
|
5199
5306
|
"schema.manageLayer.version": "层版本号",
|
|
5200
|
-
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询 CloudBase 云函数执行日志(需要 functionName)\n- `getFunctionLogDetail`: 获取日志详情(需要 requestId)\n- `listFunctionLayers`: 列出函数绑定的层\n- `listLayers`: 列出所有层(账号级视图,含其他环境创建的层)\n- `listLayerVersions`: 列出层的版本(注意:是 Versions 不是 Version;账号级视图)\n- `getLayerVersionDetail`: 获取层版本详情(账号级视图)\n- `listFunctionTriggers`: 列出函数触发器(用于查看定时任务 / cron / timer 配置)\n- `getFunctionDownloadUrl`: 获取函数代码下载地址\n- `getFunctionDeployStatus`: 按 taskId 查询异步部署状态、阶段进度和最终结果。返回 data.build(构建子状态)、data.deploy(部署子状态)、data.progress(阶段事件);status=running 时 data.result 与 data.error 一律为 null,不得报告部署完成。调用方必须持续轮询直到 status=succeeded/failed;status=expired 表示任务超过最长保留时间(2 小时)被终结,云端可能仍在部署,需用 getFunctionDetail 确认。任务只保存在 MCP 进程内存中,过期或 MCP Server 重启后返回 errorCode=DEPLOY_TASK_NOT_FOUND;任务按环境隔离,只能查到当前环境自己发起的部署。cloud mode 下本 action 不可用:异步任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略在 cloud mode 下都不支持真实执行,image 策略则走同步部署不产生 taskId。\n- `listVersionByFunction`: 列出函数已发布版本(对齐 tcb fn list-function-versions / SDK listVersionByFunction;需要 functionName)\n- `getFunctionAlias`: 查询函数别名与流量路由(对齐 tcb fn get-route / SDK getFunctionAlias;需要 functionName;aliasName 默认 $DEFAULT
|
|
5201
|
-
"schema.query.functionName": "CloudBase 云函数名称。`getFunctionDetail`、`listFunctionLogs`、`listFunctionLayers`、`listFunctionTriggers`、`getFunctionDownloadUrl`、`listVersionByFunction`、`getFunctionAlias`
|
|
5307
|
+
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询 CloudBase 云函数执行日志(需要 functionName)\n- `getFunctionLogDetail`: 获取日志详情(需要 requestId)\n- `listFunctionLayers`: 列出函数绑定的层\n- `listLayers`: 列出所有层(账号级视图,含其他环境创建的层)\n- `listLayerVersions`: 列出层的版本(注意:是 Versions 不是 Version;账号级视图)\n- `getLayerVersionDetail`: 获取层版本详情(账号级视图)\n- `listFunctionTriggers`: 列出函数触发器(用于查看定时任务 / cron / timer 配置)\n- `getFunctionDownloadUrl`: 获取函数代码下载地址\n- `getFunctionDeployStatus`: 按 taskId 查询异步部署状态、阶段进度和最终结果。返回 data.build(构建子状态)、data.deploy(部署子状态)、data.progress(阶段事件);status=running 时 data.result 与 data.error 一律为 null,不得报告部署完成。调用方必须持续轮询直到 status=succeeded/failed;status=expired 表示任务超过最长保留时间(2 小时)被终结,云端可能仍在部署,需用 getFunctionDetail 确认。任务只保存在 MCP 进程内存中,过期或 MCP Server 重启后返回 errorCode=DEPLOY_TASK_NOT_FOUND;任务按环境隔离,只能查到当前环境自己发起的部署。cloud mode 下本 action 不可用:异步任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略在 cloud mode 下都不支持真实执行,image 策略则走同步部署不产生 taskId。\n- `listVersionByFunction`: 列出函数已发布版本(对齐 tcb fn list-function-versions / SDK listVersionByFunction;需要 functionName)\n- `getFunctionAlias`: 查询函数别名与流量路由(对齐 tcb fn get-route / SDK getFunctionAlias;需要 functionName;aliasName 默认 $DEFAULT)\n- `getFunctionUploadUrl`: 获取函数代码包的 COS 预签名上传地址(ZIP 两段式部署阶段 A):PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带对应请求头),再调用 manageFunctions 的 createFunction/updateFunctionCode 并传 code 三元组(阶段 B)。functionName 可选,仅用于生成上传对象 key。返回的 uploadUrl 含凭据签名,不得写入日志或持久化;阶段 A 与阶段 B 必须落在同一个 MCP 进程(MCP Server 重启后需重新取地址并重新上传);地址默认 300 秒内有效",
|
|
5308
|
+
"schema.query.functionName": "CloudBase 云函数名称。`getFunctionDetail`、`listFunctionLogs`、`listFunctionLayers`、`listFunctionTriggers`、`getFunctionDownloadUrl`、`listVersionByFunction`、`getFunctionAlias` 时必填;`getFunctionUploadUrl` 可选(仅用于生成上传对象 key)",
|
|
5202
5309
|
"schema.query.limit": "分页数量(limit)。列表类 action 可选,默认值由后端决定",
|
|
5203
5310
|
"schema.query.offset": "分页偏移(offset)。列表类 action 可选,默认 0",
|
|
5204
5311
|
"schema.query.codeSecret": "代码保护密钥,用于解密函数代码",
|
|
5205
|
-
"schema.query.revealEnvValues": "getFunctionDetail / listFunctionTriggers 时是否返回环境变量明文值。默认 false:Value 脱敏为 ***,仅保留 Key 与 ValueLength,足以确认配置了哪些变量及变更是否生效;true 时返回明文,敏感变量会进入模型上下文,谨慎使用。如需查看明文,建议优先使用控制台或 CLI",
|
|
5312
|
+
"schema.query.revealEnvValues": "getFunctionDetail / listFunctionTriggers / listFunctionLayers 时是否返回环境变量明文值。默认 false:Value 脱敏为 ***,仅保留 Key 与 ValueLength,足以确认配置了哪些变量及变更是否生效;true 时返回明文,敏感变量会进入模型上下文,谨慎使用。如需查看明文,建议优先使用控制台或 CLI",
|
|
5206
5313
|
"schema.query.startTime": "日志查询开始时间,格式必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 00:00:00)。与 endTime 间隔不能超过一天。不传时默认查询最近一天",
|
|
5207
5314
|
"schema.query.endTime": "日志查询结束时间,格式必须为 YYYY-MM-DD HH:mm:ss(如 2024-01-01 23:59:59)。与 startTime 间隔不能超过一天。不传时默认为当前时间",
|
|
5208
5315
|
"schema.query.requestId": "日志请求 ID。`getFunctionLogDetail` 操作必填,可从 `listFunctionLogs` 结果中获取",
|
|
@@ -5221,6 +5328,10 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5221
5328
|
"schema.manage.force": "createFunction 时是否覆盖",
|
|
5222
5329
|
"schema.manage.functionName": "目标函数名称(顶层)。updateFunctionCode / updateFunctionConfig / invokeFunction / publishVersion / updateFunctionAliasConfig 等 action 使用此字段。不要只写在 func.name:createFunction 用 func.name,其它 action 用顶层 functionName。若误传 func.name,也会被识别为 functionName。",
|
|
5223
5330
|
"schema.manage.zipFile": "仅兼容特殊场景:预先准备好的代码包 base64 编码。普通 createFunction/updateFunctionCode 默认不要先压缩 zip,优先使用 functionRootPath。",
|
|
5331
|
+
"schema.manage.code": "ZIP 两段式部署阶段 B:代码包已通过 queryFunctions action=getFunctionUploadUrl 上传到环境 COS 桶。三元组(cosBucketName/cosObjectName/cosBucketRegion)直接使用 getFunctionUploadUrl 返回值原样透传。传入 code 后 createFunction/updateFunctionCode 不再读取本地目录(functionRootPath/zipFile 均不需要),默认不触发云端依赖安装(可用 func.installDependency 覆盖)。code 三元组必须是同一个 MCP 进程的 getFunctionUploadUrl 刚返回的那一组(该 process 会在阶段 A 登记上传目标),自行拼装或跨环境复用会被拒绝并要求重新取地址。",
|
|
5332
|
+
"schema.code.cosBucketName": "环境存储桶短名(不含 -appid 后缀),直接使用 getFunctionUploadUrl 返回的 cosBucketName,不要自填",
|
|
5333
|
+
"schema.code.cosObjectName": "上传对象 key,直接使用 getFunctionUploadUrl 返回的 cosObjectName",
|
|
5334
|
+
"schema.code.cosBucketRegion": "存储桶地域,省略时自动使用当前环境存储桶地域",
|
|
5224
5335
|
"schema.manage.handler": "函数入口",
|
|
5225
5336
|
"schema.manage.timeout": "配置更新时的超时时间",
|
|
5226
5337
|
"schema.manage.envVariables": "配置更新时要合并的环境变量。若含 DATABASE_URL / MYSQL_* / POSTGRES_* / REDIS_* 等 TCP 连库变量,必须同时提供真实 vpc(或函数已绑定完整 VPC)。禁止猜测 vpcId/subnetId。",
|
|
@@ -5326,7 +5437,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5326
5437
|
"opErr.default": "Please check the function name, directory structure, and the function status in the environment, then retry.",
|
|
5327
5438
|
"opErr.prefix": "[{operation}] {message}\nSuggestions: ",
|
|
5328
5439
|
confirmRequired: "{action} is a dangerous operation; pass confirm=true explicitly before executing",
|
|
5329
|
-
"cloudMode.localOnly": "{action} is unavailable in cloud mode because the operation depends on a local function code directory.
|
|
5440
|
+
"cloudMode.localOnly": "{action} is unavailable in cloud mode because the operation depends on a local function code directory. Options: 1) use image deployment (runtime=CustomImage + imageConfig); 2) use two-phase ZIP deployment: first call queryFunctions action=getFunctionUploadUrl to get a presigned upload URL, PUT the code zip, then deploy via the manageFunctions code parameter (phase B also needs no local directory).",
|
|
5330
5441
|
"cloudMode.contentPathUnsupported": "createLayerVersion does not support contentPath in cloud mode; switch local file content to base64Content or run in local mode.",
|
|
5331
5442
|
offsetLimitTooLarge: "offset+limit must not be greater than 10000",
|
|
5332
5443
|
startTimeInvalid: "Invalid startTime: \"{value}\". It must use the YYYY-MM-DD HH:mm:ss format (e.g. 2024-01-01 00:00:00)",
|
|
@@ -5339,6 +5450,9 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5339
5450
|
"deployStatus.cloudMode": "{action} is unavailable in cloud mode: async deployment tasks are only created by real deployments with buildStrategy=cloud/local, and real execution of both strategies is unsupported in cloud mode (they need the local build context or local Docker), so no taskId can exist. buildStrategy=image uses synchronous deployment and returns the result directly from manageFunctions, so no deployment status query is needed. For async image build deployment, switch to local MCP mode.",
|
|
5340
5451
|
deployTaskNotFound: "Deployment task {taskId} not found; the task does not exist — it may have expired, belong to a different environment than {envId}, or the MCP Server was restarted (tasks are only kept in MCP process memory).",
|
|
5341
5452
|
unsupportedAction: "Unsupported action: {action}",
|
|
5453
|
+
storageMissing: "The current environment has no usable object storage bucket (DescribeEnvs returned no Storages), so COS two-phase deployment is unavailable. Check the environment storage configuration, or deploy in local mode. Environments with a shared bucket (ExternalStorage) are not supported either.",
|
|
5454
|
+
credentialMissing: "The current credential lacks SecretId/SecretKey (e.g. IDE proxy mode), so a COS presigned upload URL cannot be minted locally. Use local mode or a login method with permanent/temporary keys.",
|
|
5455
|
+
uploadTargetNotFound: "The code package upload target is not registered in this process: {objectName}. Two-phase ZIP deployment requires the code triplet to come from a getFunctionUploadUrl response minted by this same MCP process and environment; a restarted MCP Server, a different environment, or a hand-built cosObjectName / cosBucketName all land here. Call queryFunctions action=getFunctionUploadUrl again, upload the code package to the returned address, then call this action with the returned triplet.",
|
|
5342
5456
|
// ---- nextActions reasons ----
|
|
5343
5457
|
"reason.continuePolling": "Keep polling the cloud function deployment status",
|
|
5344
5458
|
"reason.getDetail": "View details of a single function",
|
|
@@ -5377,6 +5491,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5377
5491
|
"reason.imageFnReady": "Confirm the image function is ready (Active)",
|
|
5378
5492
|
"reason.imageUpdateReady": "Confirm the function is ready (Active) after the image update",
|
|
5379
5493
|
"reason.imageNextIteration": "For later iterations, just call updateFunctionCode with the new image tag to update the image",
|
|
5494
|
+
"reason.cosCreate": "Deploy the uploaded code zip as a function via the code parameter (two-phase deployment phase B)",
|
|
5380
5495
|
"reason.imageGatewayRoute": "To access the image HTTP function via URL, explicitly create a Domain/Route access entry and pass type=\"HTTP\" (mapped to WEB_SCF)",
|
|
5381
5496
|
"reason.latestConfig": "Confirm the latest function configuration",
|
|
5382
5497
|
"reason.publishVersion": "Publish a new function version (aligns with tcb fn publish-version)",
|
|
@@ -5396,12 +5511,15 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5396
5511
|
gotLayerVersionDetail: "Retrieved details of layer {layerName} version {layerVersion}",
|
|
5397
5512
|
gotFunctionTriggers: "Retrieved the trigger list of function {fnName}",
|
|
5398
5513
|
gotDownloadUrl: "Retrieved the code download URL of function {fnName}",
|
|
5514
|
+
gotUploadUrl: "Generated the code package upload URL (valid for {seconds} seconds). Next: PUT the code zip to uploadUrl (include the uploadHeaders when non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (cosBucketName/cosObjectName/cosBucketRegion) to deploy. Treat the uploadUrl as a one-time upload credential: do not forward it or paste it into tickets; if it expires before the upload, call getFunctionUploadUrl again for a fresh address",
|
|
5399
5515
|
gotFunctionVersions: "Retrieved the version list of function {fnName}",
|
|
5400
5516
|
gotFunctionAlias: "Retrieved alias {aliasName} of function {fnName}",
|
|
5401
5517
|
publishedVersion: "Published new version {version} of function {fnName}",
|
|
5402
5518
|
updatedFunctionAlias: "Updated alias {aliasName} of function {fnName} (primary version {version})",
|
|
5403
5519
|
createdHttpFunctionMessage: "Created HTTP function {fnName} from the image. If URL access is needed later, explicitly call manageGateway(action=\"createRoute\") with upstreamResourceType=\"WEB_SCF\", then create the access entry according to the actual path and auth requirements. Evaluators or other external callers may access anonymously, and failures may not feed EXCEED_AUTHORITY back to the AI; before delivery, proactively confirm the access path and the function security rules. If EXCEED_AUTHORITY has already appeared, first call queryPermissions(action=\"getResourcePermission\", resourceType=\"function\", resourceId=\"{fnName}\") to view the current rules, then adjust permissions with managePermissions(action=\"updateResourcePermission\") as needed.",
|
|
5404
5520
|
createdFunction: "Created function {fnName}",
|
|
5521
|
+
cosCreatedMessage: "Created function {fnName} from the code package in the environment COS bucket (deployMode=cos). Use queryFunctions(action=\"getFunctionDetail\") after deployment to confirm the function is ready.",
|
|
5522
|
+
cosUpdatedMessage: "Updated the code of function {fnName} with the new package in the environment COS bucket (deployMode=cos). Use queryFunctions(action=\"getFunctionDetail\") after deployment to confirm the function is ready (Active).",
|
|
5405
5523
|
imageCreatedMessage: "Created HTTP function {fnName} from image {imageUri}. Please confirm TCR, SCF, and the build pipeline are in the same region; for URL access, explicitly call manageGateway(action=\"createRoute\", upstreamResourceType=\"WEB_SCF\") and adjust the function security rules as needed. After deployment, use queryFunctions(action=\"getFunctionDetail\") to confirm the function is ready.",
|
|
5406
5524
|
imageUpdatedMessage: "Updated the image of function {fnName} to {imageUri}. After deployment, use queryFunctions(action=\"getFunctionDetail\") to confirm the function is ready (Active).",
|
|
5407
5525
|
updatedCode: "Updated the code of function {fnName}",
|
|
@@ -5467,12 +5585,12 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5467
5585
|
"schema.create.layers": "Layer configuration",
|
|
5468
5586
|
"schema.manageLayer.name": "Layer name",
|
|
5469
5587
|
"schema.manageLayer.version": "Layer version number",
|
|
5470
|
-
"schema.query.action": "Read-only action type:\n- `listFunctions`: list all CloudBase cloud functions\n- `getFunctionDetail`: get function details (requires functionName)\n- `listFunctionLogs`: query function execution logs (requires functionName)\n- `getFunctionLogDetail`: get log details (requires requestId)\n- `listFunctionLayers`: list layers bound to a function\n- `listLayers`: list all layers (account-level view, including layers from other environments)\n- `listLayerVersions`: list layer versions (Versions, not Version; account-level view)\n- `getLayerVersionDetail`: get layer version details (account-level view)\n- `listFunctionTriggers`: list function triggers (scheduled task / cron / timer configuration)\n- `getFunctionDownloadUrl`: get the function code download URL\n- `getFunctionDeployStatus`: query async deployment status, stage progress, and final result by taskId. Returns data.build, data.deploy, and data.progress. While status=running, data.result and data.error are null and deployment must not be reported as complete. Keep polling until status=succeeded/failed. status=expired means the task exceeded the 2-hour retention limit; cloud deployment may still be running, so confirm with getFunctionDetail. Tasks exist only in MCP process memory; expired tasks or a restarted MCP Server return errorCode=DEPLOY_TASK_NOT_FOUND. Tasks are isolated by environment. This action is unavailable in cloud mode because real cloud/local builds cannot run there, while image deployment is synchronous and creates no taskId.\n- `listVersionByFunction`: list published function versions (aligns with tcb fn list-function-versions / SDK listVersionByFunction; requires functionName)\n- `getFunctionAlias`: get function alias and traffic routing (aligns with tcb fn get-route / SDK getFunctionAlias; requires functionName; aliasName defaults to $DEFAULT)",
|
|
5471
|
-
"schema.query.functionName": "CloudBase cloud function name. Required for `getFunctionDetail`, `listFunctionLogs`, `listFunctionLayers`, `listFunctionTriggers`, `getFunctionDownloadUrl`, `listVersionByFunction`, and `getFunctionAlias`.",
|
|
5588
|
+
"schema.query.action": "Read-only action type:\n- `listFunctions`: list all CloudBase cloud functions\n- `getFunctionDetail`: get function details (requires functionName)\n- `listFunctionLogs`: query function execution logs (requires functionName)\n- `getFunctionLogDetail`: get log details (requires requestId)\n- `listFunctionLayers`: list layers bound to a function\n- `listLayers`: list all layers (account-level view, including layers from other environments)\n- `listLayerVersions`: list layer versions (Versions, not Version; account-level view)\n- `getLayerVersionDetail`: get layer version details (account-level view)\n- `listFunctionTriggers`: list function triggers (scheduled task / cron / timer configuration)\n- `getFunctionDownloadUrl`: get the function code download URL\n- `getFunctionDeployStatus`: query async deployment status, stage progress, and final result by taskId. Returns data.build, data.deploy, and data.progress. While status=running, data.result and data.error are null and deployment must not be reported as complete. Keep polling until status=succeeded/failed. status=expired means the task exceeded the 2-hour retention limit; cloud deployment may still be running, so confirm with getFunctionDetail. Tasks exist only in MCP process memory; expired tasks or a restarted MCP Server return errorCode=DEPLOY_TASK_NOT_FOUND. Tasks are isolated by environment. This action is unavailable in cloud mode because real cloud/local builds cannot run there, while image deployment is synchronous and creates no taskId.\n- `listVersionByFunction`: list published function versions (aligns with tcb fn list-function-versions / SDK listVersionByFunction; requires functionName)\n- `getFunctionAlias`: get function alias and traffic routing (aligns with tcb fn get-route / SDK getFunctionAlias; requires functionName; aliasName defaults to $DEFAULT)\n- `getFunctionUploadUrl`: get a COS presigned upload URL for a function code package (two-phase ZIP deployment phase A): PUT the code zip to uploadUrl (include the corresponding request headers when uploadHeaders is non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (phase B). functionName is optional and only shapes the upload object key. The uploadUrl carries credential-bound signatures; never log or persist it; phase A and phase B must run in the same MCP process (after an MCP Server restart, fetch a new address and upload again); the address is valid for 300 seconds by default",
|
|
5589
|
+
"schema.query.functionName": "CloudBase cloud function name. Required for `getFunctionDetail`, `listFunctionLogs`, `listFunctionLayers`, `listFunctionTriggers`, `getFunctionDownloadUrl`, `listVersionByFunction`, and `getFunctionAlias`. Optional for `getFunctionUploadUrl` (only used to generate the upload object key).",
|
|
5472
5590
|
"schema.query.limit": "Page size (limit). Optional for list actions; the backend determines the default.",
|
|
5473
5591
|
"schema.query.offset": "Pagination offset. Optional for list actions; defaults to 0.",
|
|
5474
5592
|
"schema.query.codeSecret": "Code protection secret used to decrypt function code.",
|
|
5475
|
-
"schema.query.revealEnvValues": "Whether `getFunctionDetail` / `listFunctionTriggers` returns plaintext environment variable values. Defaults to false: Value is masked as ***, while Key and ValueLength remain, which is sufficient to verify configured variables and changes. true returns plaintext and may expose secrets to the model context; use cautiously. Prefer the console or CLI for plaintext values.",
|
|
5593
|
+
"schema.query.revealEnvValues": "Whether `getFunctionDetail` / `listFunctionTriggers` / `listFunctionLayers` returns plaintext environment variable values. Defaults to false: Value is masked as ***, while Key and ValueLength remain, which is sufficient to verify configured variables and changes. true returns plaintext and may expose secrets to the model context; use cautiously. Prefer the console or CLI for plaintext values.",
|
|
5476
5594
|
"schema.query.startTime": "Log query start time in YYYY-MM-DD HH:mm:ss format (for example, 2024-01-01 00:00:00). The interval to endTime must not exceed one day. Defaults to the most recent day when omitted.",
|
|
5477
5595
|
"schema.query.endTime": "Log query end time in YYYY-MM-DD HH:mm:ss format (for example, 2024-01-01 23:59:59). The interval from startTime must not exceed one day. Defaults to the current time when omitted.",
|
|
5478
5596
|
"schema.query.requestId": "Log request ID. Required for `getFunctionLogDetail`; obtain it from `listFunctionLogs`.",
|
|
@@ -5491,6 +5609,10 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5491
5609
|
"schema.manage.force": "Whether createFunction overwrites an existing function.",
|
|
5492
5610
|
"schema.manage.functionName": "Target function name at the top level. Used by updateFunctionCode, updateFunctionConfig, invokeFunction, publishVersion, updateFunctionAliasConfig, and similar actions. createFunction uses func.name; other actions use top-level functionName. A mistakenly supplied func.name is also recognized as functionName.",
|
|
5493
5611
|
"schema.manage.zipFile": "Compatibility only: base64-encoded prebuilt code package. For ordinary createFunction/updateFunctionCode, do not create a ZIP first; prefer functionRootPath.",
|
|
5612
|
+
"schema.manage.code": "Two-phase ZIP deployment phase B: the code package has been uploaded to the environment COS bucket via queryFunctions action=getFunctionUploadUrl. Pass the triplet (cosBucketName/cosObjectName/cosBucketRegion) through unchanged from the getFunctionUploadUrl response. With code provided, createFunction/updateFunctionCode no longer reads local directories (functionRootPath/zipFile are unnecessary), and cloud dependency installation is skipped by default (override with func.installDependency). The code triplet must be the one just returned by getFunctionUploadUrl in the same MCP process (that process registers the upload target in phase A); hand-built triplets or cross-environment reuse are rejected and require fetching a new address.",
|
|
5613
|
+
"schema.code.cosBucketName": "Environment bucket short name (without the -appid suffix); pass through the cosBucketName returned by getFunctionUploadUrl, do not invent one",
|
|
5614
|
+
"schema.code.cosObjectName": "Uploaded object key; pass through the cosObjectName returned by getFunctionUploadUrl",
|
|
5615
|
+
"schema.code.cosBucketRegion": "Bucket region; defaults to the current environment bucket region when omitted",
|
|
5494
5616
|
"schema.manage.handler": "Function entry point",
|
|
5495
5617
|
"schema.manage.timeout": "Timeout used for configuration updates.",
|
|
5496
5618
|
"schema.manage.envVariables": "Environment variables to merge during a configuration update. If they contain TCP database variables such as DATABASE_URL, MYSQL_*, POSTGRES_*, or REDIS_*, also provide a real vpc (or ensure the function already has a complete VPC binding). Never guess vpcId/subnetId.",
|
|
@@ -6119,6 +6241,7 @@ exports.logs = (0, types_js_1.defineModule)({
|
|
|
6119
6241
|
"\n\n**重要区分**:" +
|
|
6120
6242
|
"\n- 查询云函数日志:使用 `queryFunctions(action=\"listFunctionLogs\", functionName=\"xxx\")`" +
|
|
6121
6243
|
"\n- 查询 CLS 日志(跨服务日志聚合):使用本工具 `queryLogs(action=\"searchLogs\")`" +
|
|
6244
|
+
"\n- 开通 CLS 日志服务:使用 `manageLogs(action=\"createLogService\", confirm=true)`" +
|
|
6122
6245
|
"\n\n**适用场景**:" +
|
|
6123
6246
|
"\n- 检查 CLS 日志服务是否开通:`action=\"checkLogService\"`" +
|
|
6124
6247
|
"\n- 跨服务日志搜索(如搜索所有 ERROR 日志):`action=\"searchLogs\"`" +
|
|
@@ -6164,12 +6287,28 @@ exports.logs = (0, types_js_1.defineModule)({
|
|
|
6164
6287
|
"schema.limit": "返回日志条数限制,默认 20",
|
|
6165
6288
|
"schema.context": "翻页上下文,用于继续上一次查询",
|
|
6166
6289
|
"schema.sort": "按时间排序:`asc` 升序,`desc` 降序",
|
|
6290
|
+
"manage.title": "管理 CloudBase 日志服务",
|
|
6291
|
+
"manage.description": "CloudBase 日志域写入入口。用于开通 CLS 日志服务(对齐 Manager SDK `log.createLogService` / CreateEnvResource Resources=['log'])。" +
|
|
6292
|
+
"\n\n**适用场景**:" +
|
|
6293
|
+
"\n- 开通 CLS 日志服务:`action=\"createLogService\", confirm=true`" +
|
|
6294
|
+
"\n\n开通为异步操作:接口成功不代表立即可用,请随后用 `queryLogs(action=\"checkLogService\")` 轮询确认。",
|
|
6295
|
+
"manage.schema.action": "操作类型:" +
|
|
6296
|
+
"\n- `createLogService`: 开通 CLS 日志服务(需 `confirm=true`)",
|
|
6297
|
+
"manage.schema.confirm": "开通日志服务前的显式确认。必须传 `confirm=true`;未传时返回 CONFIRM_REQUIRED。",
|
|
6298
|
+
"manage.create.confirmRequired": "开通日志服务会创建 CLS 日志资源。请使用 `confirm: true` 重新执行以继续。",
|
|
6299
|
+
"manage.create.needsConfirmation": "开通日志服务前需要显式确认。",
|
|
6300
|
+
"manage.create.alreadyEnabled": "当前环境日志服务已开通,无需重复开通。",
|
|
6301
|
+
"manage.create.submitted": "日志服务开通请求已提交。请使用 queryLogs(action=\"checkLogService\") 轮询直至 enabled=true。",
|
|
6302
|
+
"manage.create.nextCheck": "轮询日志服务是否已就绪。",
|
|
6303
|
+
"manage.create.nextSearch": "日志服务已就绪,可开始搜索 CLS 日志。",
|
|
6304
|
+
"manage.unsupportedAction": "不支持的日志管理 action:{action}",
|
|
6167
6305
|
}, {
|
|
6168
6306
|
title: "Query CloudBase log service",
|
|
6169
6307
|
description: "Unified read-only entry for the CloudBase logs domain. Supports checking log service status and searching CLS logs." +
|
|
6170
6308
|
"\n\n**Important distinction**:" +
|
|
6171
6309
|
"\n- Query cloud function logs: use `queryFunctions(action=\"listFunctionLogs\", functionName=\"xxx\")`" +
|
|
6172
6310
|
"\n- Query CLS logs (cross-service log aggregation): use this tool `queryLogs(action=\"searchLogs\")`" +
|
|
6311
|
+
"\n- Enable the CLS log service: use `manageLogs(action=\"createLogService\", confirm=true)`" +
|
|
6173
6312
|
"\n\n**Use cases**:" +
|
|
6174
6313
|
"\n- Check whether the CLS log service is enabled: `action=\"checkLogService\"`" +
|
|
6175
6314
|
"\n- Cross-service log search (e.g. find all ERROR logs): `action=\"searchLogs\"`" +
|
|
@@ -6215,6 +6354,21 @@ exports.logs = (0, types_js_1.defineModule)({
|
|
|
6215
6354
|
"schema.limit": "Maximum number of log entries to return; defaults to 20.",
|
|
6216
6355
|
"schema.context": "Pagination context used to continue the previous query.",
|
|
6217
6356
|
"schema.sort": "Time sort order: `asc` for ascending or `desc` for descending.",
|
|
6357
|
+
"manage.title": "Manage CloudBase log service",
|
|
6358
|
+
"manage.description": "Write entry for the CloudBase logs domain. Enables the CLS log service (aligned with Manager SDK `log.createLogService` / CreateEnvResource Resources=['log'])." +
|
|
6359
|
+
"\n\n**Use cases**:" +
|
|
6360
|
+
"\n- Enable CLS log service: `action=\"createLogService\", confirm=true`" +
|
|
6361
|
+
"\n\nProvisioning is asynchronous: API success does not mean the service is immediately ready. Poll with `queryLogs(action=\"checkLogService\")` afterward.",
|
|
6362
|
+
"manage.schema.action": "Operation type:" +
|
|
6363
|
+
"\n- `createLogService`: Enable the CLS log service (requires `confirm=true`)",
|
|
6364
|
+
"manage.schema.confirm": "Explicit confirmation before enabling the log service. Must pass `confirm=true`; omitting it returns CONFIRM_REQUIRED.",
|
|
6365
|
+
"manage.create.confirmRequired": "Enabling the log service creates CLS log resources. Re-run with `confirm: true` to continue.",
|
|
6366
|
+
"manage.create.needsConfirmation": "Explicit confirmation is required before enabling the log service.",
|
|
6367
|
+
"manage.create.alreadyEnabled": "The log service is already enabled for this environment; no need to enable again.",
|
|
6368
|
+
"manage.create.submitted": "Log service enablement request submitted. Poll with queryLogs(action=\"checkLogService\") until enabled=true.",
|
|
6369
|
+
"manage.create.nextCheck": "Poll whether the log service is ready.",
|
|
6370
|
+
"manage.create.nextSearch": "Log service is ready; you can start searching CLS logs.",
|
|
6371
|
+
"manage.unsupportedAction": "Unsupported log manage action: {action}",
|
|
6218
6372
|
});
|
|
6219
6373
|
|
|
6220
6374
|
|
|
@@ -6508,19 +6662,19 @@ exports.permissions = (0, types_js_1.defineModule)({
|
|
|
6508
6662
|
"或 securityRule='{\"invoke\":true}'(放通所有云函数)。" +
|
|
6509
6663
|
"底层错误:{message}",
|
|
6510
6664
|
mustBeArray: "{label} 必须是数组",
|
|
6511
|
-
roleLookupNote: "如果你需要 app-level admin override(例如 CMS 中 admin 可编辑所有文章,而 editor 只能编辑自己的文章),CUSTOM 规则通常是必要的。一个已验证可用的模式是:角色集合文档主键就是 auth.uid,并在文章权限里写 get(
|
|
6512
|
-
recommendedClientWritePattern: "对于 CMS 文章这类使用 app-level admin override 的 CUSTOM 规则,前端可继续使用 db.collection('{resourceId}').doc(id).update(...) / remove(...)。关键是安全规则要采用已验证模式:get(
|
|
6665
|
+
roleLookupNote: "如果你需要 app-level admin override(例如 CMS 中 admin 可编辑所有文章,而 editor 只能编辑自己的文章),CUSTOM 规则通常是必要的。一个已验证可用的模式是:角色集合文档主键就是 auth.uid,并在文章权限里写 get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid。若现有 schema 已经有 users / profiles / user_roles 其一,请复用已存在且能通过 _id == auth.uid 直接 get() 到的那一份;不要把 where({ uid }) 查询得到的集合误写成 get(`database.users.${auth.uid}`)。",
|
|
6666
|
+
recommendedClientWritePattern: "对于 CMS 文章这类使用 app-level admin override 的 CUSTOM 规则,前端可继续使用 db.collection('{resourceId}').doc(id).update(...) / remove(...)。关键是安全规则要采用已验证模式:get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid,并且文章文档中要真实写入 authorId。",
|
|
6513
6667
|
createRuleSummary: "create 规则不应引用 doc.*,因为 create 时文档尚未存在。",
|
|
6514
6668
|
createRuleDetail: "CloudBase 的 create 规则验证的是写入数据(request.data),此时文档尚不存在,doc.* 不可用。" +
|
|
6515
6669
|
"请将 create 规则改为仅使用 auth.* 检查(如 auth.uid != null && auth.loginType != 'ANONYMOUS')," +
|
|
6516
6670
|
"或在写入时将 owner 字段(如 _openid / authorId)写入 request.data,然后在 create 规则中用 request.data._openid == auth.openid 做校验。" +
|
|
6517
6671
|
"read / update / delete 规则可以使用 doc.* 引用已有文档字段,且客户端查询条件必须是规则约束的子集(如 _openid: '{openid}')。",
|
|
6518
6672
|
docIdWriteSummary: "当前安全规则在 document-id 写入场景下可能被后端直接拒绝。",
|
|
6519
|
-
docIdWriteDetail: "这类规则经常在 owner-only 集合里被写错,但对于 CMS 文章这种“admin 可编辑所有文章、editor 只能编辑自己的文章”的场景,已验证可用的做法是保留 doc.authorId,并通过独立角色集合做 admin override:get(
|
|
6673
|
+
docIdWriteDetail: "这类规则经常在 owner-only 集合里被写错,但对于 CMS 文章这种“admin 可编辑所有文章、editor 只能编辑自己的文章”的场景,已验证可用的做法是保留 doc.authorId,并通过独立角色集合做 admin override:get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid。不要默认改成 where(...),也不要把同集合 owner 判断重写成 ``get(`database.collection.${doc._id}`)``。",
|
|
6520
6674
|
invalidGetPathSummary: "get() 的 path 只应包含 collection 和 documentId,不应把字段名拼进 path 字符串。",
|
|
6521
|
-
invalidGetPathDetail: "请写成 get(
|
|
6522
|
-
templateLiteralSummary: "
|
|
6523
|
-
templateLiteralDetail: "
|
|
6675
|
+
invalidGetPathDetail: "请写成 ``get(`database.collection.${doc._id}`).fieldName``,而不是把字段名拼进 path。安全规则的表达式不支持用 + 拼接 get() 的 path 参数——形如 get('database.collection.' + doc._id) 的规则在保存时就会被判 rule invalid,请改用反引号模板字符串。但在 CMS 文章权限里,不要把同集合文档当成默认首选方案;更稳的模式是读取单独的角色集合:``get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid``。",
|
|
6676
|
+
templateLiteralSummary: "${...} 出现在引号字符串里也能被引擎识别,但官方形态是反引号模板字符串。",
|
|
6677
|
+
templateLiteralDetail: "推荐统一写成 ``get(`database.user_roles.${auth.uid}`).role == 'admin'``。真正会被拒绝的不是 ${...},而是另外两种写法:不含 ${...} 的裸引号字面量(如 get('database.admin_locks.article_lock'),请求时会返回 500),以及用 + 拼接的 get(`database.user_roles.${auth.uid}`)(保存规则时判 rule invalid)。对于 CMS 文章这类需要 app-level admin override 的规则,请优先使用 user_roles + doc.authorId 模式。",
|
|
6524
6678
|
bucketMissing: "存储 Bucket {bucket} 不存在",
|
|
6525
6679
|
bucketsMissing: "以下存储 Bucket 不存在: {buckets}",
|
|
6526
6680
|
paramRequired: "action={action} 时必须提供 {param}",
|
|
@@ -6589,19 +6743,19 @@ exports.permissions = (0, types_js_1.defineModule)({
|
|
|
6589
6743
|
"(package authz.user) or securityRule='{\"invoke\":true}' for public functions. " +
|
|
6590
6744
|
"Underlying error: {message}",
|
|
6591
6745
|
mustBeArray: "{label} must be an array",
|
|
6592
|
-
roleLookupNote: "If you need app-level admin override (e.g. in a CMS, admins can edit all articles while editors can only edit their own), a CUSTOM rule is usually required. A verified pattern is: make the role collection's document primary key auth.uid itself, and in the article permission write get(
|
|
6593
|
-
recommendedClientWritePattern: "For CMS articles using CUSTOM rules with app-level admin override, the frontend can keep using db.collection('{resourceId}').doc(id).update(...) / remove(...). The key is that the security rule uses the verified pattern: get(
|
|
6746
|
+
roleLookupNote: "If you need app-level admin override (e.g. in a CMS, admins can edit all articles while editors can only edit their own), a CUSTOM rule is usually required. A verified pattern is: make the role collection's document primary key auth.uid itself, and in the article permission write get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid. If the existing schema already has users / profiles / user_roles, reuse the one that exists and can be fetched directly via _id == auth.uid with get(); do not mistakenly write the collection obtained by a where({ uid }) query as get(`database.users.${auth.uid}`).",
|
|
6747
|
+
recommendedClientWritePattern: "For CMS articles using CUSTOM rules with app-level admin override, the frontend can keep using db.collection('{resourceId}').doc(id).update(...) / remove(...). The key is that the security rule uses the verified pattern: get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid, and the article document must actually contain the authorId field.",
|
|
6594
6748
|
createRuleSummary: "The create rule should not reference doc.*, because the document does not exist yet at create time.",
|
|
6595
6749
|
createRuleDetail: "CloudBase's create rule validates the written data (request.data); the document does not exist yet, so doc.* is unavailable. " +
|
|
6596
6750
|
"Change the create rule to use only auth.* checks (e.g. auth.uid != null && auth.loginType != 'ANONYMOUS'), " +
|
|
6597
6751
|
"or write the owner field (e.g. _openid / authorId) into request.data at write time, then validate with request.data._openid == auth.openid in the create rule. " +
|
|
6598
6752
|
"read / update / delete rules may use doc.* to reference existing document fields, and the client's query conditions must be a subset of the rule constraints (e.g. _openid: '{openid}').",
|
|
6599
6753
|
docIdWriteSummary: "The current security rule may be rejected by the backend in document-id write scenarios.",
|
|
6600
|
-
docIdWriteDetail: "Such rules are often written incorrectly in owner-only collections, but for the CMS article scenario where \"admins can edit all articles and editors can only edit their own\", the verified approach is to keep doc.authorId and do admin override through a separate role collection: get(
|
|
6754
|
+
docIdWriteDetail: "Such rules are often written incorrectly in owner-only collections, but for the CMS article scenario where \"admins can edit all articles and editors can only edit their own\", the verified approach is to keep doc.authorId and do admin override through a separate role collection: get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid. Do not default to where(...), and do not rewrite the same-collection owner check as ``get(`database.collection.${doc._id}`)``.",
|
|
6601
6755
|
invalidGetPathSummary: "The get() path should only contain the collection and documentId; do not concatenate field names into the path string.",
|
|
6602
|
-
invalidGetPathDetail: "Write get(
|
|
6603
|
-
templateLiteralSummary: "
|
|
6604
|
-
templateLiteralDetail: "
|
|
6756
|
+
invalidGetPathDetail: "Write ``get(`database.collection.${doc._id}`).fieldName`` instead of embedding the field name in the path. Security rule expressions do not support concatenating the get() path with +: a rule such as get('database.collection.' + doc._id) is rejected with rule invalid when the rule is saved, so use a backtick template literal. However, for CMS article permissions, do not treat a same-collection document as the default first choice; the more robust pattern is reading a separate role collection: ``get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid``.",
|
|
6757
|
+
templateLiteralSummary: "${...} inside a quoted string is understood by the engine, but the official form is a backtick template literal.",
|
|
6758
|
+
templateLiteralDetail: "Prefer ``get(`database.user_roles.${auth.uid}`).role == 'admin'``. What actually breaks is not ${...} but two other spellings: a bare quoted literal with no ${...} (e.g. get('database.admin_locks.article_lock'), which returns 500 at request time), and a concatenated path such as get(`database.user_roles.${auth.uid}`) (rejected with rule invalid when the rule is saved). For rules needing app-level admin override like CMS articles, prefer the user_roles + doc.authorId pattern.",
|
|
6605
6759
|
bucketMissing: "Storage bucket {bucket} does not exist",
|
|
6606
6760
|
bucketsMissing: "The following storage buckets do not exist: {buckets}",
|
|
6607
6761
|
paramRequired: "{param} is required when action={action}",
|
|
@@ -6852,6 +7006,7 @@ exports.setup = (0, types_js_1.defineModule)({
|
|
|
6852
7006
|
"schema.template": "要下载的模板类型",
|
|
6853
7007
|
"schema.ide": "指定要下载的IDE类型。",
|
|
6854
7008
|
"schema.overwrite": "是否覆盖已存在的文件,默认为false(不覆盖)",
|
|
7009
|
+
"projectRoot.hostConfigDir": "拒绝把 {dir} 当作项目根目录。这是宿主配置目录,不是项目。请由宿主设置 WORKSPACE_FOLDER_PATHS 为项目目录后再试。",
|
|
6855
7010
|
}, {
|
|
6856
7011
|
"downloadTemplate.title": "Download project template",
|
|
6857
7012
|
"downloadTemplate.description": "Automatically downloads and deploys CloudBase project templates.\n**Note**: Call this tool when the user requests to create a new project using a CloudBase template.\n\nSupported templates:\n- react: React + CloudBase full-stack app template\n- vue: Vue + CloudBase full-stack app template\n- miniprogram: WeChat Mini Program + CloudBase template\n- uniapp: UniApp + CloudBase cross-platform app template\n- rules: AI editor configuration files only (includes configurations for all mainstream editors such as Cursor, WindSurf, and CodeBuddy), suitable for adding AI editor configuration to an existing project\n\nSupported IDE types:\n- all: download configurations for all IDEs\n- cursor: Cursor AI editor\n- see the list below for other IDE types\n\nNote: if the ide parameter is not provided and the IDE cannot be detected from environment variables, an error will be returned asking for the ide parameter\n- windsurf: WindSurf AI editor\n- codebuddy: CodeBuddy AI editor\n- claude-code: Claude Code AI editor\n- cline: Cline AI editor\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI editor\n- qwen-code: Tongyi Lingma\n- baidu-comate: Baidu Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI editor\n- tongyi-lingma: Tongyi Lingma\n- trae: Trae AI editor\n- qoder: Qoder AI editor\n- antigravity: Google Antigravity AI editor\n- vscode: Visual Studio Code\n- kiro: Kiro AI editor\n- aider: Aider AI editor\n\nNotes:\n- the rules template automatically embeds the current MCP version for future maintenance and version tracking\n- when downloading the rules template, if a README.md file already exists in the project, the system protects it from being overwritten (unless overwrite=true is set)",
|
|
@@ -6916,6 +7071,7 @@ exports.setup = (0, types_js_1.defineModule)({
|
|
|
6916
7071
|
"schema.template": "The type of template to download",
|
|
6917
7072
|
"schema.ide": "The IDE type whose configuration should be downloaded.",
|
|
6918
7073
|
"schema.overwrite": "Whether to overwrite existing files. Defaults to false (do not overwrite).",
|
|
7074
|
+
"projectRoot.hostConfigDir": "Refusing to use {dir} as the project root. That directory belongs to the host, not a project. Set WORKSPACE_FOLDER_PATHS to the project directory and retry.",
|
|
6919
7075
|
});
|
|
6920
7076
|
|
|
6921
7077
|
|
|
@@ -7123,6 +7279,7 @@ const msgPush_js_1 = __webpack_require__(6191);
|
|
|
7123
7279
|
const setup_js_1 = __webpack_require__(8707);
|
|
7124
7280
|
const envSetup_js_1 = __webpack_require__(7148);
|
|
7125
7281
|
const interactive_js_1 = __webpack_require__(1838);
|
|
7282
|
+
const feedback_js_1 = __webpack_require__(9391);
|
|
7126
7283
|
exports.zh = {
|
|
7127
7284
|
env: env_js_1.env.zh,
|
|
7128
7285
|
storage: storage_js_1.storage.zh,
|
|
@@ -7152,6 +7309,7 @@ exports.zh = {
|
|
|
7152
7309
|
setup: setup_js_1.setup.zh,
|
|
7153
7310
|
envSetup: envSetup_js_1.envSetup.zh,
|
|
7154
7311
|
interactive: interactive_js_1.interactive.zh,
|
|
7312
|
+
feedback: feedback_js_1.feedback.zh,
|
|
7155
7313
|
};
|
|
7156
7314
|
|
|
7157
7315
|
|
|
@@ -7236,6 +7394,107 @@ function localizeZodSchemaShape(shape, lang, seen = new WeakMap()) {
|
|
|
7236
7394
|
}
|
|
7237
7395
|
|
|
7238
7396
|
|
|
7397
|
+
/***/ },
|
|
7398
|
+
|
|
7399
|
+
/***/ 6156
|
|
7400
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
7401
|
+
|
|
7402
|
+
var __webpack_unused_export__;
|
|
7403
|
+
|
|
7404
|
+
__webpack_unused_export__ = ({ value: true });
|
|
7405
|
+
__webpack_unused_export__ = assertLocalEndpoint;
|
|
7406
|
+
exports.resolveLocalEndpoint = resolveLocalEndpoint;
|
|
7407
|
+
exports.createLocalCloudApiRequestFn = createLocalCloudApiRequestFn;
|
|
7408
|
+
const logger_js_1 = __webpack_require__(781);
|
|
7409
|
+
/** Loopback hosts only. WHATWG URL keeps the brackets on IPv6 hostnames. */
|
|
7410
|
+
const ALLOWED_HOSTS = new Set(['127.0.0.1', '[::1]', 'localhost']);
|
|
7411
|
+
/** Upper bound for one cloud API call, so a hung endpoint cannot block a tool call forever. */
|
|
7412
|
+
const ENDPOINT_TIMEOUT_MS = 30_000;
|
|
7413
|
+
let announcedEndpoint;
|
|
7414
|
+
/**
|
|
7415
|
+
* Validate and normalise CLOUDBASE_LOCAL_ENDPOINT.
|
|
7416
|
+
*
|
|
7417
|
+
* Setting this variable makes cloud API calls skip the login and credential
|
|
7418
|
+
* checks, so it must never point off the local machine.
|
|
7419
|
+
*/
|
|
7420
|
+
function assertLocalEndpoint(endpoint) {
|
|
7421
|
+
let parsed;
|
|
7422
|
+
try {
|
|
7423
|
+
parsed = new URL(endpoint);
|
|
7424
|
+
}
|
|
7425
|
+
catch {
|
|
7426
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT is not a valid URL');
|
|
7427
|
+
}
|
|
7428
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
7429
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT must use http or https');
|
|
7430
|
+
}
|
|
7431
|
+
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
|
|
7432
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT must point at a loopback host');
|
|
7433
|
+
}
|
|
7434
|
+
return endpoint.replace(/\/+$/, '');
|
|
7435
|
+
}
|
|
7436
|
+
/**
|
|
7437
|
+
* Read and validate CLOUDBASE_LOCAL_ENDPOINT. Returns undefined when unset.
|
|
7438
|
+
*
|
|
7439
|
+
* A malformed value throws instead of silently falling back, so a bad config
|
|
7440
|
+
* surfaces as a config error rather than looking like an auth failure.
|
|
7441
|
+
*/
|
|
7442
|
+
function resolveLocalEndpoint() {
|
|
7443
|
+
const raw = process.env.CLOUDBASE_LOCAL_ENDPOINT;
|
|
7444
|
+
if (!raw) {
|
|
7445
|
+
return undefined;
|
|
7446
|
+
}
|
|
7447
|
+
const base = assertLocalEndpoint(raw);
|
|
7448
|
+
if (announcedEndpoint !== base) {
|
|
7449
|
+
announcedEndpoint = base;
|
|
7450
|
+
(0, logger_js_1.warn)(`CLOUDBASE_LOCAL_ENDPOINT is set: cloud API calls go to ${base} and the login/credential check is skipped`);
|
|
7451
|
+
}
|
|
7452
|
+
return base;
|
|
7453
|
+
}
|
|
7454
|
+
/**
|
|
7455
|
+
* manager-node 5.8.8 routes both DatabaseService.executePGSql and
|
|
7456
|
+
* commonService().call through CloudService.request. That method delegates
|
|
7457
|
+
* to context.requestFn and skips TC3 when the function is set.
|
|
7458
|
+
*/
|
|
7459
|
+
function createLocalCloudApiRequestFn(endpoint) {
|
|
7460
|
+
const base = assertLocalEndpoint(endpoint);
|
|
7461
|
+
return async ({ service, action, version, region, payload }) => {
|
|
7462
|
+
const response = await fetch(`${base}/capi`, {
|
|
7463
|
+
method: 'POST',
|
|
7464
|
+
headers: {
|
|
7465
|
+
'content-type': 'application/json',
|
|
7466
|
+
'x-tc-action': action,
|
|
7467
|
+
'x-tc-version': version,
|
|
7468
|
+
'x-tc-region': region,
|
|
7469
|
+
'x-tc-service': service,
|
|
7470
|
+
},
|
|
7471
|
+
body: JSON.stringify(payload ?? {}),
|
|
7472
|
+
signal: AbortSignal.timeout(ENDPOINT_TIMEOUT_MS),
|
|
7473
|
+
redirect: 'manual',
|
|
7474
|
+
});
|
|
7475
|
+
// With redirect: 'manual' a 3xx comes back as an opaque redirect (status 0)
|
|
7476
|
+
// instead of being followed, so both shapes must be rejected explicitly.
|
|
7477
|
+
if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) {
|
|
7478
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT responded with a redirect; redirects are not followed');
|
|
7479
|
+
}
|
|
7480
|
+
const body = await response.json();
|
|
7481
|
+
const inner = body.Response;
|
|
7482
|
+
if (!inner) {
|
|
7483
|
+
const error = new Error('missing Response');
|
|
7484
|
+
error.code = 'InternalError';
|
|
7485
|
+
throw error;
|
|
7486
|
+
}
|
|
7487
|
+
const apiError = inner.Error;
|
|
7488
|
+
if (apiError) {
|
|
7489
|
+
const error = new Error(apiError.Message || apiError.Code || 'cloud api error');
|
|
7490
|
+
error.code = apiError.Code;
|
|
7491
|
+
throw error;
|
|
7492
|
+
}
|
|
7493
|
+
return inner;
|
|
7494
|
+
};
|
|
7495
|
+
}
|
|
7496
|
+
|
|
7497
|
+
|
|
7239
7498
|
/***/ },
|
|
7240
7499
|
|
|
7241
7500
|
/***/ 6324
|
|
@@ -7270,6 +7529,7 @@ const apps_js_1 = __webpack_require__(8267);
|
|
|
7270
7529
|
const logs_js_1 = __webpack_require__(1628);
|
|
7271
7530
|
const permissions_js_1 = __webpack_require__(2639);
|
|
7272
7531
|
const msg_push_js_1 = __webpack_require__(7707);
|
|
7532
|
+
const feedback_js_1 = __webpack_require__(3951);
|
|
7273
7533
|
const index_js_1 = __webpack_require__(4908);
|
|
7274
7534
|
const schema_js_1 = __webpack_require__(6273);
|
|
7275
7535
|
const cloud_mode_js_1 = __webpack_require__(8694);
|
|
@@ -7299,6 +7559,7 @@ const DEFAULT_PLUGINS = [
|
|
|
7299
7559
|
"logs",
|
|
7300
7560
|
"agents",
|
|
7301
7561
|
"capi",
|
|
7562
|
+
"feedback",
|
|
7302
7563
|
];
|
|
7303
7564
|
function registerDatabase(server) {
|
|
7304
7565
|
// NoSQL 数据库按站点能力集合注册(国际站默认不支持 NoSQL)
|
|
@@ -7348,6 +7609,7 @@ const AVAILABLE_PLUGINS = {
|
|
|
7348
7609
|
deploy: { name: "deploy", register: deploy_js_1.registerDeployTools },
|
|
7349
7610
|
capi: { name: "capi", register: capi_js_1.registerCapiTools },
|
|
7350
7611
|
"msg-push": { name: "msg-push", register: msg_push_js_1.registerMsgPushTools },
|
|
7612
|
+
feedback: { name: "feedback", register: feedback_js_1.registerFeedbackTools },
|
|
7351
7613
|
};
|
|
7352
7614
|
const PLUGIN_ALIASES = {
|
|
7353
7615
|
"access-control": "permissions",
|
|
@@ -9832,6 +10094,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
9832
10094
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
9833
10095
|
exports.CLOUDRUN_ENV_TYPE = exports.CLOUDRUN_DEPLOY_REGISTRATION_INTERVAL_MS = exports.CLOUDRUN_DEPLOY_REGISTRATION_MAX_WAIT_MS = exports.MASKED_CLOUDRUN_ENV_VALUE = exports.CLOUDRUN_PACKAGE_TYPES = exports.CLOUDRUN_ACCESS_TYPES = exports.CLOUDRUN_SERVICE_TYPES = void 0;
|
|
9834
10096
|
exports.maskCloudRunDetailEnvParams = maskCloudRunDetailEnvParams;
|
|
10097
|
+
exports.validateAndNormalizePath = validateAndNormalizePath;
|
|
9835
10098
|
exports.resolveCloudRunProjectDir = resolveCloudRunProjectDir;
|
|
9836
10099
|
exports.buildManageCloudRunErrorMessage = buildManageCloudRunErrorMessage;
|
|
9837
10100
|
exports.isValidCloudRunBuildId = isValidCloudRunBuildId;
|
|
@@ -9858,6 +10121,7 @@ const zod_1 = __webpack_require__(2971);
|
|
|
9858
10121
|
const cloudbase_manager_js_1 = __webpack_require__(3109);
|
|
9859
10122
|
const index_js_1 = __webpack_require__(4908);
|
|
9860
10123
|
const logger_js_1 = __webpack_require__(781);
|
|
10124
|
+
const project_config_js_1 = __webpack_require__(9175);
|
|
9861
10125
|
const gateway_access_urls_js_1 = __webpack_require__(4173);
|
|
9862
10126
|
const notification_js_1 = __webpack_require__(4718);
|
|
9863
10127
|
const capi_js_1 = __webpack_require__(8900);
|
|
@@ -10062,31 +10326,20 @@ function checkIfAgentProject(projectPath) {
|
|
|
10062
10326
|
}
|
|
10063
10327
|
}
|
|
10064
10328
|
/**
|
|
10065
|
-
* Validate and normalize file path.
|
|
10066
|
-
*
|
|
10067
|
-
*
|
|
10068
|
-
* @param inputPath User provided path
|
|
10069
|
-
* @returns Absolute path
|
|
10329
|
+
* Validate and normalize a file path.
|
|
10330
|
+
* Absolute paths are accepted as-is. Relative paths resolve against the project
|
|
10331
|
+
* root and must stay inside it.
|
|
10070
10332
|
*/
|
|
10071
10333
|
function validateAndNormalizePath(inputPath) {
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
const
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
// Same filesystem root — ensure the resolved path is still inside CWD
|
|
10082
|
-
// (or is exactly CWD) to block "../" traversal.
|
|
10083
|
-
const prefix = cwd.endsWith(path_1.default.sep) ? cwd : cwd + path_1.default.sep;
|
|
10084
|
-
if (!normalizedPath.startsWith(prefix) && normalizedPath !== cwd) {
|
|
10085
|
-
throw new Error((0, index_js_1.t)("cloudrun.error.pathOutsideCwd", { cwd }));
|
|
10086
|
-
}
|
|
10087
|
-
}
|
|
10088
|
-
// Cross-root absolute paths (e.g. D:\ on Windows when CWD is C:\) are
|
|
10089
|
-
// allowed — the user own the machine and the path is explicitly absolute.
|
|
10334
|
+
if (path_1.default.isAbsolute(inputPath)) {
|
|
10335
|
+
return path_1.default.resolve(inputPath);
|
|
10336
|
+
}
|
|
10337
|
+
const projectRoot = (0, project_config_js_1.requireProjectRoot)();
|
|
10338
|
+
const normalizedPath = path_1.default.resolve(projectRoot, inputPath);
|
|
10339
|
+
const prefix = projectRoot.endsWith(path_1.default.sep) ? projectRoot : projectRoot + path_1.default.sep;
|
|
10340
|
+
if (!normalizedPath.startsWith(prefix) && normalizedPath !== projectRoot) {
|
|
10341
|
+
throw new Error((0, index_js_1.t)("cloudrun.error.pathOutsideCwd", { cwd: projectRoot, resolvedPath: normalizedPath }));
|
|
10342
|
+
}
|
|
10090
10343
|
return normalizedPath;
|
|
10091
10344
|
}
|
|
10092
10345
|
/**
|
|
@@ -14515,6 +14768,7 @@ const zod_1 = __webpack_require__(2971);
|
|
|
14515
14768
|
const cloudbase_manager_js_1 = __webpack_require__(3109);
|
|
14516
14769
|
const env_js_1 = __webpack_require__(6504);
|
|
14517
14770
|
const index_js_1 = __webpack_require__(4908);
|
|
14771
|
+
const project_config_js_1 = __webpack_require__(9175);
|
|
14518
14772
|
const tool_result_js_1 = __webpack_require__(9645);
|
|
14519
14773
|
const sql_risk_js_1 = __webpack_require__(9885);
|
|
14520
14774
|
const CATEGORY = "PostgreSQL database";
|
|
@@ -14799,19 +15053,7 @@ function validateMigrationName(name, actionLabel) {
|
|
|
14799
15053
|
return null;
|
|
14800
15054
|
}
|
|
14801
15055
|
function getMigrationProjectRoot() {
|
|
14802
|
-
|
|
14803
|
-
process.env.PROJECT_ROOT ||
|
|
14804
|
-
process.env.GITHUB_WORKSPACE ||
|
|
14805
|
-
process.env.CI_PROJECT_DIR ||
|
|
14806
|
-
process.env.BUILD_SOURCESDIRECTORY;
|
|
14807
|
-
if (fromEnv && fromEnv.trim()) {
|
|
14808
|
-
// IDEs may inject multiple folders separated by path.delimiter.
|
|
14809
|
-
const first = fromEnv.split(path.delimiter).map((p) => p.trim()).find(Boolean);
|
|
14810
|
-
if (first) {
|
|
14811
|
-
return first;
|
|
14812
|
-
}
|
|
14813
|
-
}
|
|
14814
|
-
return process.cwd();
|
|
15056
|
+
return (0, project_config_js_1.requireProjectRoot)();
|
|
14815
15057
|
}
|
|
14816
15058
|
function buildLocalMigrationFileName(version, name) {
|
|
14817
15059
|
return `${version}_${name}.sql`;
|
|
@@ -17186,7 +17428,17 @@ const QUERY_ACTIONS = [
|
|
|
17186
17428
|
"getInstanceInfo",
|
|
17187
17429
|
"describeInstance",
|
|
17188
17430
|
"getConnectionInfo",
|
|
17431
|
+
"describeInstanceSlowQueries",
|
|
17432
|
+
"describeInstanceErrorLogs",
|
|
17189
17433
|
];
|
|
17434
|
+
const SLOW_QUERY_ORDER_BY = [
|
|
17435
|
+
"QueryTime",
|
|
17436
|
+
"LockTime",
|
|
17437
|
+
"RowsExamined",
|
|
17438
|
+
"RowsSent",
|
|
17439
|
+
];
|
|
17440
|
+
const ERROR_LOG_LEVELS = ["error", "warning", "note"];
|
|
17441
|
+
const ORDER_BY_TYPE = ["asc", "desc", "ASC", "DESC"];
|
|
17190
17442
|
const MANAGE_ACTIONS = [
|
|
17191
17443
|
"provisionMySQL",
|
|
17192
17444
|
"destroyMySQL",
|
|
@@ -17693,6 +17945,138 @@ async function handleGetConnectionInfo(context) {
|
|
|
17693
17945
|
],
|
|
17694
17946
|
});
|
|
17695
17947
|
}
|
|
17948
|
+
function resolveMysqlInstanceId(instanceInfo, args) {
|
|
17949
|
+
const fromRequest = typeof args.request?.InstanceId === "string"
|
|
17950
|
+
? args.request.InstanceId
|
|
17951
|
+
: undefined;
|
|
17952
|
+
const fromDbInstance = args.dbInstance?.instanceId;
|
|
17953
|
+
const candidate = fromRequest || fromDbInstance || instanceInfo.instanceId;
|
|
17954
|
+
if (!candidate || candidate === "default") {
|
|
17955
|
+
return null;
|
|
17956
|
+
}
|
|
17957
|
+
return candidate;
|
|
17958
|
+
}
|
|
17959
|
+
async function requireReadyMysqlInstance(args, context) {
|
|
17960
|
+
const instanceInfo = await getSqlInstanceInfo(context);
|
|
17961
|
+
if (!instanceInfo.exists) {
|
|
17962
|
+
return {
|
|
17963
|
+
ok: false,
|
|
17964
|
+
payload: buildSqlToolResult({
|
|
17965
|
+
success: false,
|
|
17966
|
+
errorCode: "MYSQL_NOT_CREATED",
|
|
17967
|
+
data: sanitizeInstanceInfo(instanceInfo),
|
|
17968
|
+
message: (0, index_js_1.t)("databaseSQL.instanceLogs.notProvisioned"),
|
|
17969
|
+
nextActions: [
|
|
17970
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", (0, index_js_1.t)("databaseSQL.next.provisionBeforeSql"), { action: "provisionMySQL", confirm: true }),
|
|
17971
|
+
],
|
|
17972
|
+
}),
|
|
17973
|
+
};
|
|
17974
|
+
}
|
|
17975
|
+
const instanceId = resolveMysqlInstanceId(instanceInfo, args);
|
|
17976
|
+
if (!instanceId) {
|
|
17977
|
+
return {
|
|
17978
|
+
ok: false,
|
|
17979
|
+
payload: buildSqlToolResult({
|
|
17980
|
+
success: false,
|
|
17981
|
+
errorCode: "MYSQL_INSTANCE_ID_REQUIRED",
|
|
17982
|
+
data: sanitizeInstanceInfo(instanceInfo),
|
|
17983
|
+
message: (0, index_js_1.t)("databaseSQL.instanceLogs.instanceIdRequired"),
|
|
17984
|
+
nextActions: [
|
|
17985
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", (0, index_js_1.t)("databaseSQL.instanceLogs.resolveInstanceId"), { action: "getInstanceInfo" }),
|
|
17986
|
+
],
|
|
17987
|
+
}),
|
|
17988
|
+
};
|
|
17989
|
+
}
|
|
17990
|
+
return { ok: true, instanceInfo, instanceId };
|
|
17991
|
+
}
|
|
17992
|
+
async function handleDescribeInstanceSlowQueries(args, context) {
|
|
17993
|
+
const ready = await requireReadyMysqlInstance(args, context);
|
|
17994
|
+
if (!ready.ok) {
|
|
17995
|
+
return ready.payload;
|
|
17996
|
+
}
|
|
17997
|
+
const request = args.request || {};
|
|
17998
|
+
const cloudbase = await context.getManager();
|
|
17999
|
+
const result = await cloudbase.mysql.describeInstanceSlowQueries({
|
|
18000
|
+
InstanceId: ready.instanceId,
|
|
18001
|
+
StartTime: (typeof request.StartTime === "string" ? request.StartTime : undefined) ??
|
|
18002
|
+
args.startTime,
|
|
18003
|
+
EndTime: (typeof request.EndTime === "string" ? request.EndTime : undefined) ??
|
|
18004
|
+
args.endTime,
|
|
18005
|
+
Limit: (typeof request.Limit === "number" ? request.Limit : undefined) ??
|
|
18006
|
+
args.limit,
|
|
18007
|
+
Offset: (typeof request.Offset === "number" ? request.Offset : undefined) ??
|
|
18008
|
+
args.offset,
|
|
18009
|
+
Username: (typeof request.Username === "string" ? request.Username : undefined) ??
|
|
18010
|
+
args.username,
|
|
18011
|
+
Host: (typeof request.Host === "string" ? request.Host : undefined) ??
|
|
18012
|
+
args.host,
|
|
18013
|
+
Database: (typeof request.Database === "string" ? request.Database : undefined) ??
|
|
18014
|
+
args.database,
|
|
18015
|
+
OrderBy: (typeof request.OrderBy === "string" ? request.OrderBy : undefined) ??
|
|
18016
|
+
args.orderBy,
|
|
18017
|
+
OrderByType: (typeof request.OrderByType === "string"
|
|
18018
|
+
? request.OrderByType
|
|
18019
|
+
: undefined) ?? args.orderByType,
|
|
18020
|
+
SqlText: (typeof request.SqlText === "string" ? request.SqlText : undefined) ??
|
|
18021
|
+
args.sqlText,
|
|
18022
|
+
});
|
|
18023
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(context.server.logger, result);
|
|
18024
|
+
return buildSqlToolResult({
|
|
18025
|
+
success: true,
|
|
18026
|
+
data: {
|
|
18027
|
+
action: "describeInstanceSlowQueries",
|
|
18028
|
+
instanceId: ready.instanceId,
|
|
18029
|
+
totalCount: result.TotalCount ?? 0,
|
|
18030
|
+
slowQueries: result.SlowQueries ?? [],
|
|
18031
|
+
requestId: result.RequestId,
|
|
18032
|
+
raw: result,
|
|
18033
|
+
},
|
|
18034
|
+
message: (0, index_js_1.t)("databaseSQL.instanceLogs.slowQueriesSuccess"),
|
|
18035
|
+
});
|
|
18036
|
+
}
|
|
18037
|
+
async function handleDescribeInstanceErrorLogs(args, context) {
|
|
18038
|
+
const ready = await requireReadyMysqlInstance(args, context);
|
|
18039
|
+
if (!ready.ok) {
|
|
18040
|
+
return ready.payload;
|
|
18041
|
+
}
|
|
18042
|
+
const request = args.request || {};
|
|
18043
|
+
const cloudbase = await context.getManager();
|
|
18044
|
+
const result = await cloudbase.mysql.describeInstanceErrorLogs({
|
|
18045
|
+
InstanceId: ready.instanceId,
|
|
18046
|
+
Limit: (typeof request.Limit === "number" ? request.Limit : undefined) ??
|
|
18047
|
+
args.limit,
|
|
18048
|
+
Offset: (typeof request.Offset === "number" ? request.Offset : undefined) ??
|
|
18049
|
+
args.offset,
|
|
18050
|
+
StartTime: (typeof request.StartTime === "string" ? request.StartTime : undefined) ??
|
|
18051
|
+
args.startTime,
|
|
18052
|
+
EndTime: (typeof request.EndTime === "string" ? request.EndTime : undefined) ??
|
|
18053
|
+
args.endTime,
|
|
18054
|
+
OrderBy: (typeof request.OrderBy === "string" ? request.OrderBy : undefined) ??
|
|
18055
|
+
(args.orderBy === "Timestamp" ? args.orderBy : undefined),
|
|
18056
|
+
OrderByType: (typeof request.OrderByType === "string"
|
|
18057
|
+
? request.OrderByType
|
|
18058
|
+
: undefined) ?? args.orderByType,
|
|
18059
|
+
LogLevels: (Array.isArray(request.LogLevels)
|
|
18060
|
+
? request.LogLevels
|
|
18061
|
+
: undefined) ?? args.logLevels,
|
|
18062
|
+
KeyWords: (Array.isArray(request.KeyWords)
|
|
18063
|
+
? request.KeyWords
|
|
18064
|
+
: undefined) ?? args.keyWords,
|
|
18065
|
+
});
|
|
18066
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(context.server.logger, result);
|
|
18067
|
+
return buildSqlToolResult({
|
|
18068
|
+
success: true,
|
|
18069
|
+
data: {
|
|
18070
|
+
action: "describeInstanceErrorLogs",
|
|
18071
|
+
instanceId: ready.instanceId,
|
|
18072
|
+
totalCount: result.TotalCount ?? 0,
|
|
18073
|
+
errorLogs: result.ErrorLogs ?? [],
|
|
18074
|
+
requestId: result.RequestId,
|
|
18075
|
+
raw: result,
|
|
18076
|
+
},
|
|
18077
|
+
message: (0, index_js_1.t)("databaseSQL.instanceLogs.errorLogsSuccess"),
|
|
18078
|
+
});
|
|
18079
|
+
}
|
|
17696
18080
|
async function handleProvisionMySQL(args, context) {
|
|
17697
18081
|
if (args.confirm !== true) {
|
|
17698
18082
|
return buildSqlToolResult({
|
|
@@ -18063,6 +18447,54 @@ function registerSQLDatabaseTools(server) {
|
|
|
18063
18447
|
})
|
|
18064
18448
|
.optional()
|
|
18065
18449
|
.describe("databaseSQL.schema.query.dbInstance"),
|
|
18450
|
+
startTime: zod_1.z
|
|
18451
|
+
.string()
|
|
18452
|
+
.optional()
|
|
18453
|
+
.describe("databaseSQL.schema.query.startTime"),
|
|
18454
|
+
endTime: zod_1.z
|
|
18455
|
+
.string()
|
|
18456
|
+
.optional()
|
|
18457
|
+
.describe("databaseSQL.schema.query.endTime"),
|
|
18458
|
+
limit: zod_1.z
|
|
18459
|
+
.number()
|
|
18460
|
+
.optional()
|
|
18461
|
+
.describe("databaseSQL.schema.query.limit"),
|
|
18462
|
+
offset: zod_1.z
|
|
18463
|
+
.number()
|
|
18464
|
+
.optional()
|
|
18465
|
+
.describe("databaseSQL.schema.query.offset"),
|
|
18466
|
+
username: zod_1.z
|
|
18467
|
+
.string()
|
|
18468
|
+
.optional()
|
|
18469
|
+
.describe("databaseSQL.schema.query.username"),
|
|
18470
|
+
host: zod_1.z
|
|
18471
|
+
.string()
|
|
18472
|
+
.optional()
|
|
18473
|
+
.describe("databaseSQL.schema.query.host"),
|
|
18474
|
+
database: zod_1.z
|
|
18475
|
+
.string()
|
|
18476
|
+
.optional()
|
|
18477
|
+
.describe("databaseSQL.schema.query.database"),
|
|
18478
|
+
orderBy: zod_1.z
|
|
18479
|
+
.enum([...SLOW_QUERY_ORDER_BY, "Timestamp"])
|
|
18480
|
+
.optional()
|
|
18481
|
+
.describe("databaseSQL.schema.query.orderBy"),
|
|
18482
|
+
orderByType: zod_1.z
|
|
18483
|
+
.enum(ORDER_BY_TYPE)
|
|
18484
|
+
.optional()
|
|
18485
|
+
.describe("databaseSQL.schema.query.orderByType"),
|
|
18486
|
+
sqlText: zod_1.z
|
|
18487
|
+
.string()
|
|
18488
|
+
.optional()
|
|
18489
|
+
.describe("databaseSQL.schema.query.sqlText"),
|
|
18490
|
+
logLevels: zod_1.z
|
|
18491
|
+
.array(zod_1.z.enum(ERROR_LOG_LEVELS))
|
|
18492
|
+
.optional()
|
|
18493
|
+
.describe("databaseSQL.schema.query.logLevels"),
|
|
18494
|
+
keyWords: zod_1.z
|
|
18495
|
+
.array(zod_1.z.string())
|
|
18496
|
+
.optional()
|
|
18497
|
+
.describe("databaseSQL.schema.query.keyWords"),
|
|
18066
18498
|
},
|
|
18067
18499
|
annotations: {
|
|
18068
18500
|
readOnlyHint: true,
|
|
@@ -18086,6 +18518,10 @@ function registerSQLDatabaseTools(server) {
|
|
|
18086
18518
|
return handleGetInstanceInfo(context);
|
|
18087
18519
|
case "getConnectionInfo":
|
|
18088
18520
|
return handleGetConnectionInfo(context);
|
|
18521
|
+
case "describeInstanceSlowQueries":
|
|
18522
|
+
return handleDescribeInstanceSlowQueries(args, context);
|
|
18523
|
+
case "describeInstanceErrorLogs":
|
|
18524
|
+
return handleDescribeInstanceErrorLogs(args, context);
|
|
18089
18525
|
default:
|
|
18090
18526
|
throw new Error((0, index_js_1.t)("databaseSQL.unsupportedQueryAction", { action: args.action }));
|
|
18091
18527
|
}
|
|
@@ -18182,6 +18618,7 @@ const zod_1 = __webpack_require__(2971);
|
|
|
18182
18618
|
const cloudbase_manager_js_1 = __webpack_require__(3109);
|
|
18183
18619
|
const index_js_1 = __webpack_require__(4908);
|
|
18184
18620
|
const json_content_js_1 = __webpack_require__(8027);
|
|
18621
|
+
const project_config_js_1 = __webpack_require__(9175);
|
|
18185
18622
|
const sql_risk_js_1 = __webpack_require__(9885);
|
|
18186
18623
|
const hosting_build_utils_js_1 = __webpack_require__(7572);
|
|
18187
18624
|
// 声明式部署可编排的资源类型,与 DeployOrchestrator 的部署顺序一致:
|
|
@@ -18446,7 +18883,7 @@ function registerDeployTools(server) {
|
|
|
18446
18883
|
},
|
|
18447
18884
|
}, async ({ cwd, mode }) => {
|
|
18448
18885
|
try {
|
|
18449
|
-
const projectRoot =
|
|
18886
|
+
const projectRoot = (0, project_config_js_1.requireProjectRoot)(cwd);
|
|
18450
18887
|
const config = await resolveDeployConfig({ cwd: projectRoot, mode });
|
|
18451
18888
|
assertConfigValid(config);
|
|
18452
18889
|
const hostingItems = Array.isArray(config.hosting)
|
|
@@ -18518,7 +18955,7 @@ function registerDeployTools(server) {
|
|
|
18518
18955
|
},
|
|
18519
18956
|
}, async ({ cwd, mode, envId: envIdInput, only, skip, yes, }) => {
|
|
18520
18957
|
try {
|
|
18521
|
-
const projectRoot =
|
|
18958
|
+
const projectRoot = (0, project_config_js_1.requireProjectRoot)(cwd);
|
|
18522
18959
|
const config = await resolveDeployConfig({ cwd: projectRoot, mode });
|
|
18523
18960
|
assertConfigValid(config);
|
|
18524
18961
|
const envId = await resolveDeployEnvId({
|
|
@@ -18602,7 +19039,7 @@ function registerDeployTools(server) {
|
|
|
18602
19039
|
if (confirm !== true) {
|
|
18603
19040
|
throw new DeployError(exports.DEPLOY_ERROR_CODES.CONFIRM_REQUIRED, (0, index_js_1.t)("deploy.confirmRequired"));
|
|
18604
19041
|
}
|
|
18605
|
-
const projectRoot =
|
|
19042
|
+
const projectRoot = (0, project_config_js_1.requireProjectRoot)(cwd);
|
|
18606
19043
|
const config = await resolveDeployConfig({ cwd: projectRoot, mode });
|
|
18607
19044
|
assertConfigValid(config);
|
|
18608
19045
|
const envId = await resolveDeployEnvId({
|
|
@@ -21579,6 +22016,7 @@ function registerEnvTools(server) {
|
|
|
21579
22016
|
typeof cloudBaseOptions?.envId === "string" &&
|
|
21580
22017
|
cloudBaseOptions.envId.length > 0;
|
|
21581
22018
|
const envIdFromEnv = !cloudBaseOptions?.requestFn &&
|
|
22019
|
+
!process.env.CLOUDBASE_LOCAL_ENDPOINT &&
|
|
21582
22020
|
(process.env.CLOUDBASE_ENV_ID ||
|
|
21583
22021
|
(isEnvScopedCredential ? cloudBaseOptions.envId : undefined));
|
|
21584
22022
|
const shouldPinToEnvVar = Boolean(envIdFromEnv &&
|
|
@@ -22538,6 +22976,512 @@ function registerEnvTools(server) {
|
|
|
22538
22976
|
}
|
|
22539
22977
|
|
|
22540
22978
|
|
|
22979
|
+
/***/ },
|
|
22980
|
+
|
|
22981
|
+
/***/ 3951
|
|
22982
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
22983
|
+
|
|
22984
|
+
var __webpack_unused_export__;
|
|
22985
|
+
|
|
22986
|
+
__webpack_unused_export__ = ({ value: true });
|
|
22987
|
+
exports.bE = exports.NC = exports.RS = void 0;
|
|
22988
|
+
__webpack_unused_export__ = resolveMcpVersion;
|
|
22989
|
+
__webpack_unused_export__ = buildFeedbackIssueUrl;
|
|
22990
|
+
__webpack_unused_export__ = buildFeedbackIssueLink;
|
|
22991
|
+
__webpack_unused_export__ = buildFeedbackPayload;
|
|
22992
|
+
exports.registerFeedbackTools = registerFeedbackTools;
|
|
22993
|
+
const zod_1 = __webpack_require__(2971);
|
|
22994
|
+
const feedback_session_js_1 = __webpack_require__(3379);
|
|
22995
|
+
const json_content_js_1 = __webpack_require__(8027);
|
|
22996
|
+
const site_map_js_1 = __webpack_require__(4533);
|
|
22997
|
+
/**
|
|
22998
|
+
* Not a CloudBase resource, so this does not use the query* / manage* pair.
|
|
22999
|
+
* The feedback plugin is in the default set and always registers this tool.
|
|
23000
|
+
*/
|
|
23001
|
+
exports.RS = "prepareFeedback";
|
|
23002
|
+
const CASE_TEMPLATE_FILE = "1-case-showcase.yml";
|
|
23003
|
+
const RETROSPECTIVE_TEMPLATE_FILE = "2-dev-retrospective.yml";
|
|
23004
|
+
/** Fixed new-issue pages. Intl uses GitHub. Domestic uses the CNB CloudBase-AI-ToolKit repo. */
|
|
23005
|
+
exports.NC = {
|
|
23006
|
+
intl: "https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/issues/new",
|
|
23007
|
+
domestic: "https://cnb.cool/tencent/cloud/cloudbase/CloudBase-AI-ToolKit/-/issues/new",
|
|
23008
|
+
};
|
|
23009
|
+
const RESOURCE_BY_TOOL = {
|
|
23010
|
+
queryHosting: { zh: "静态托管", en: "Static hosting" },
|
|
23011
|
+
manageHosting: { zh: "静态托管", en: "Static hosting" },
|
|
23012
|
+
readNoSqlDatabaseStructure: { zh: "云数据库(文档型)", en: "Document database" },
|
|
23013
|
+
writeNoSqlDatabaseStructure: { zh: "云数据库(文档型)", en: "Document database" },
|
|
23014
|
+
readNoSqlDatabaseContent: { zh: "云数据库(文档型)", en: "Document database" },
|
|
23015
|
+
writeNoSqlDatabaseContent: { zh: "云数据库(文档型)", en: "Document database" },
|
|
23016
|
+
queryMysqlDatabase: { zh: "云数据库(MySQL)", en: "MySQL" },
|
|
23017
|
+
manageMysqlDatabase: { zh: "云数据库(MySQL)", en: "MySQL" },
|
|
23018
|
+
queryPgDatabase: { zh: "云数据库(PostgreSQL)", en: "PostgreSQL" },
|
|
23019
|
+
managePgDatabase: { zh: "云数据库(PostgreSQL)", en: "PostgreSQL" },
|
|
23020
|
+
queryFunctions: { zh: "云函数", en: "Cloud functions" },
|
|
23021
|
+
manageFunctions: { zh: "云函数", en: "Cloud functions" },
|
|
23022
|
+
queryStorage: { zh: "云存储", en: "Cloud storage" },
|
|
23023
|
+
manageStorage: { zh: "云存储", en: "Cloud storage" },
|
|
23024
|
+
queryPgStorage: { zh: "云存储", en: "Cloud storage" },
|
|
23025
|
+
queryAppAuth: { zh: "身份认证", en: "Auth" },
|
|
23026
|
+
manageAppAuth: { zh: "身份认证", en: "Auth" },
|
|
23027
|
+
queryCloudRun: { zh: "CloudRun", en: "CloudRun" },
|
|
23028
|
+
manageCloudRun: { zh: "CloudRun", en: "CloudRun" },
|
|
23029
|
+
};
|
|
23030
|
+
/** Stay under common browser and proxy URL limits. Longer drafts are pasted by the user. */
|
|
23031
|
+
exports.bE = 6000;
|
|
23032
|
+
function resolveMcpVersion(declared, packageVersion) {
|
|
23033
|
+
const fromBuild = typeof declared === "string" ? declared.trim() : "";
|
|
23034
|
+
if (fromBuild) {
|
|
23035
|
+
return fromBuild;
|
|
23036
|
+
}
|
|
23037
|
+
const fromPackage = typeof packageVersion === "string" ? packageVersion.trim() : "";
|
|
23038
|
+
return fromPackage;
|
|
23039
|
+
}
|
|
23040
|
+
function readDeclaredMcpVersion() {
|
|
23041
|
+
return true ? "2.34.8" : 0;
|
|
23042
|
+
}
|
|
23043
|
+
function blank(value, lang) {
|
|
23044
|
+
return value.trim().length > 0 ? value.trim() : (lang === "en" ? "blank" : "留空");
|
|
23045
|
+
}
|
|
23046
|
+
function feedbackSite(server) {
|
|
23047
|
+
return (0, site_map_js_1.resolveSiteAndRegion)({
|
|
23048
|
+
site: server.cloudBaseOptions?.site,
|
|
23049
|
+
region: server.cloudBaseOptions?.region,
|
|
23050
|
+
}).site;
|
|
23051
|
+
}
|
|
23052
|
+
function feedbackLang(site) {
|
|
23053
|
+
return site === "intl" ? "en" : "zh";
|
|
23054
|
+
}
|
|
23055
|
+
function uniqueJoin(parts) {
|
|
23056
|
+
const seen = new Set();
|
|
23057
|
+
const ordered = [];
|
|
23058
|
+
for (const part of parts) {
|
|
23059
|
+
const trimmed = part.trim();
|
|
23060
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
23061
|
+
continue;
|
|
23062
|
+
}
|
|
23063
|
+
seen.add(trimmed);
|
|
23064
|
+
ordered.push(trimmed);
|
|
23065
|
+
}
|
|
23066
|
+
return ordered.join(" / ");
|
|
23067
|
+
}
|
|
23068
|
+
function readAgentLabel(server) {
|
|
23069
|
+
const ide = server.ide || process.env.INTEGRATION_IDE || "";
|
|
23070
|
+
const client = server.client || process.env.CLOUDBASE_MCP_CLIENT || "";
|
|
23071
|
+
return uniqueJoin([ide, client]);
|
|
23072
|
+
}
|
|
23073
|
+
function toLocalIso(iso) {
|
|
23074
|
+
const date = new Date(iso);
|
|
23075
|
+
if (Number.isNaN(date.getTime())) {
|
|
23076
|
+
return "";
|
|
23077
|
+
}
|
|
23078
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
23079
|
+
const offsetMinutes = -date.getTimezoneOffset();
|
|
23080
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
23081
|
+
const absolute = Math.abs(offsetMinutes);
|
|
23082
|
+
return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` +
|
|
23083
|
+
`T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}` +
|
|
23084
|
+
`${sign}${pad(Math.floor(absolute / 60))}:${pad(absolute % 60)}`);
|
|
23085
|
+
}
|
|
23086
|
+
function resourceTypesFrom(outcomes, lang) {
|
|
23087
|
+
const seen = new Set();
|
|
23088
|
+
const types = [];
|
|
23089
|
+
for (const outcome of outcomes) {
|
|
23090
|
+
if (outcome.failed) {
|
|
23091
|
+
continue;
|
|
23092
|
+
}
|
|
23093
|
+
const resourceType = RESOURCE_BY_TOOL[outcome.toolName]?.[lang];
|
|
23094
|
+
if (!resourceType || seen.has(resourceType)) {
|
|
23095
|
+
continue;
|
|
23096
|
+
}
|
|
23097
|
+
seen.add(resourceType);
|
|
23098
|
+
types.push(resourceType);
|
|
23099
|
+
}
|
|
23100
|
+
return types;
|
|
23101
|
+
}
|
|
23102
|
+
function formatDeployDuration(outcomes, lang) {
|
|
23103
|
+
const build = outcomes.filter((item) => !item.failed && item.toolName === "deployBuild");
|
|
23104
|
+
const apply = outcomes.filter((item) => !item.failed && item.toolName === "deployApply");
|
|
23105
|
+
if (build.length === 0 && apply.length === 0) {
|
|
23106
|
+
return "";
|
|
23107
|
+
}
|
|
23108
|
+
const sum = (items) => items.reduce((total, item) => total + item.durationMs, 0);
|
|
23109
|
+
const parts = [];
|
|
23110
|
+
if (build.length > 0) {
|
|
23111
|
+
parts.push(`deployBuild ${sum(build)}ms`);
|
|
23112
|
+
}
|
|
23113
|
+
if (apply.length > 0) {
|
|
23114
|
+
parts.push(`deployApply ${sum(apply)}ms`);
|
|
23115
|
+
}
|
|
23116
|
+
const joined = parts.join(lang === "en" ? "; " : ";");
|
|
23117
|
+
return lang === "en"
|
|
23118
|
+
? `${joined}. Cloud build time and end-to-end time cannot be separated from these tool names.`
|
|
23119
|
+
: `${joined}。无法区分云端构建与端到端,只记录上述工具耗时,未补另一项`;
|
|
23120
|
+
}
|
|
23121
|
+
function latestDeployTime(outcomes) {
|
|
23122
|
+
const deployOutcomes = outcomes.filter((item) => !item.failed && (item.toolName === "deployBuild" || item.toolName === "deployApply"));
|
|
23123
|
+
if (deployOutcomes.length === 0) {
|
|
23124
|
+
return "";
|
|
23125
|
+
}
|
|
23126
|
+
const latest = deployOutcomes.reduce((current, item) => (item.at > current.at ? item : current));
|
|
23127
|
+
return toLocalIso(latest.at);
|
|
23128
|
+
}
|
|
23129
|
+
function failureLines(server, outcomes, lang) {
|
|
23130
|
+
const counts = new Map();
|
|
23131
|
+
for (const outcome of outcomes) {
|
|
23132
|
+
if (!outcome.failed) {
|
|
23133
|
+
continue;
|
|
23134
|
+
}
|
|
23135
|
+
counts.set(outcome.toolName, (counts.get(outcome.toolName) ?? 0) + 1);
|
|
23136
|
+
}
|
|
23137
|
+
const lines = [];
|
|
23138
|
+
for (const [toolName, count] of counts) {
|
|
23139
|
+
lines.push(lang === "en"
|
|
23140
|
+
? `- Verified: tool call failed ${toolName} ×${count}`
|
|
23141
|
+
: `- 可验证事实:工具调用失败 ${toolName} ×${count}`);
|
|
23142
|
+
}
|
|
23143
|
+
const repeatPeak = (0, feedback_session_js_1.readRepeatPeak)(server);
|
|
23144
|
+
if (repeatPeak > 0) {
|
|
23145
|
+
lines.push(lang === "en"
|
|
23146
|
+
? `- Verified: peak consecutive identical structured errors ${repeatPeak}`
|
|
23147
|
+
: `- 可验证事实:连续相同结构化错误峰值 ${repeatPeak}`);
|
|
23148
|
+
}
|
|
23149
|
+
return lines;
|
|
23150
|
+
}
|
|
23151
|
+
function collectSecretValues(server) {
|
|
23152
|
+
const options = server.cloudBaseOptions;
|
|
23153
|
+
return [options?.envId, options?.secretId, options?.secretKey, options?.token].filter((value) => typeof value === "string" && value.trim().length >= 6);
|
|
23154
|
+
}
|
|
23155
|
+
function redact(text, secrets) {
|
|
23156
|
+
let redacted = text;
|
|
23157
|
+
for (const secret of secrets) {
|
|
23158
|
+
redacted = redacted.split(secret).join("");
|
|
23159
|
+
}
|
|
23160
|
+
return redacted;
|
|
23161
|
+
}
|
|
23162
|
+
function buildCaseDraft(server, outcomes, lang) {
|
|
23163
|
+
const resources = resourceTypesFrom(outcomes, lang);
|
|
23164
|
+
const empty = blank("", lang);
|
|
23165
|
+
const resourceText = resources.length > 0 ? resources.join(lang === "en" ? ", " : "、") : empty;
|
|
23166
|
+
const version = blank(resolveMcpVersion(readDeclaredMcpVersion(), process.env.npm_package_version), lang);
|
|
23167
|
+
if (lang === "en") {
|
|
23168
|
+
return [
|
|
23169
|
+
"This issue will be public. Do not add an environment ID, secrets, or user data.",
|
|
23170
|
+
`Work name: ${empty}`,
|
|
23171
|
+
`One-line summary: ${empty}`,
|
|
23172
|
+
`Public URL: ${empty}`,
|
|
23173
|
+
`Cover / screenshot: ${empty}`,
|
|
23174
|
+
`Agent / CLI: ${blank(readAgentLabel(server), lang)}`,
|
|
23175
|
+
`Model: ${empty}`,
|
|
23176
|
+
`MCP version: ${version}`,
|
|
23177
|
+
`Deploy duration: ${blank(formatDeployDuration(outcomes, lang), lang)}`,
|
|
23178
|
+
`Cloud resources: ${resourceText}`,
|
|
23179
|
+
`Deploy time: ${blank(latestDeployTime(outcomes), lang)}`,
|
|
23180
|
+
`Author: ${empty}`,
|
|
23181
|
+
`Pitfalls: ${empty}`,
|
|
23182
|
+
`Other notes: ${empty}`,
|
|
23183
|
+
].join("\n");
|
|
23184
|
+
}
|
|
23185
|
+
return [
|
|
23186
|
+
"这条 Issue 会公开。不要补充环境 ID、密钥或用户数据。",
|
|
23187
|
+
`作品名称:${empty}`,
|
|
23188
|
+
`一句话简介:${empty}`,
|
|
23189
|
+
`公网访问地址:${empty}`,
|
|
23190
|
+
`封面 / 截图地址:${empty}`,
|
|
23191
|
+
`Agent / CLI:${blank(readAgentLabel(server), lang)}`,
|
|
23192
|
+
`所用模型:${empty}`,
|
|
23193
|
+
`MCP 版本:${version}`,
|
|
23194
|
+
`部署耗时:${blank(formatDeployDuration(outcomes, lang), lang)}`,
|
|
23195
|
+
`用到的云资源:${resourceText}`,
|
|
23196
|
+
`部署时间:${blank(latestDeployTime(outcomes), lang)}`,
|
|
23197
|
+
`作者署名 / 主页:${empty}`,
|
|
23198
|
+
`开发过程中踩到的坑:${empty}`,
|
|
23199
|
+
`其他补充:${empty}`,
|
|
23200
|
+
].join("\n");
|
|
23201
|
+
}
|
|
23202
|
+
function buildRetrospectiveDraft(server, outcomes, lang) {
|
|
23203
|
+
const resources = resourceTypesFrom(outcomes, lang);
|
|
23204
|
+
const failures = failureLines(server, outcomes, lang);
|
|
23205
|
+
const empty = blank("", lang);
|
|
23206
|
+
if (lang === "en") {
|
|
23207
|
+
const failureBlock = failures.length > 0
|
|
23208
|
+
? failures.join("\n")
|
|
23209
|
+
: "No tool failures recorded in this session.";
|
|
23210
|
+
const resourceBlock = resources.length > 0
|
|
23211
|
+
? resources.join(", ")
|
|
23212
|
+
: empty;
|
|
23213
|
+
return [
|
|
23214
|
+
"This issue will be public. Do not add an environment ID, secrets, collection names, or function names.",
|
|
23215
|
+
"Conversation turns are not collected. Do not invent a turn count.",
|
|
23216
|
+
"",
|
|
23217
|
+
"Tool failures:",
|
|
23218
|
+
failureBlock,
|
|
23219
|
+
"",
|
|
23220
|
+
"Cloud resources:",
|
|
23221
|
+
resourceBlock,
|
|
23222
|
+
].join("\n");
|
|
23223
|
+
}
|
|
23224
|
+
const failureBlock = failures.length > 0
|
|
23225
|
+
? failures.join("\n")
|
|
23226
|
+
: "本次会话没有记录到工具失败。";
|
|
23227
|
+
const resourceBlock = resources.length > 0
|
|
23228
|
+
? resources.join("、")
|
|
23229
|
+
: empty;
|
|
23230
|
+
return [
|
|
23231
|
+
"这条 Issue 会公开。不要补充环境 ID、密钥、集合名或函数名。",
|
|
23232
|
+
"不采集对话轮次。不要把失败次数写成轮次,也不要补一个数字。",
|
|
23233
|
+
"",
|
|
23234
|
+
"工具失败:",
|
|
23235
|
+
failureBlock,
|
|
23236
|
+
"",
|
|
23237
|
+
"云资源:",
|
|
23238
|
+
resourceBlock,
|
|
23239
|
+
].join("\n");
|
|
23240
|
+
}
|
|
23241
|
+
function buildFeedbackIssueUrl(site, channel, draft) {
|
|
23242
|
+
return buildFeedbackIssueLink(site, channel, draft).url;
|
|
23243
|
+
}
|
|
23244
|
+
function buildFeedbackIssueLink(site, channel, draft) {
|
|
23245
|
+
const title = site === "intl"
|
|
23246
|
+
? (channel === "case" ? "[case] " : "[retrospective] ")
|
|
23247
|
+
: (channel === "case" ? "[案例] " : "[复盘] ");
|
|
23248
|
+
const base = exports.NC[site];
|
|
23249
|
+
const draftQuery = site === "intl"
|
|
23250
|
+
? `body=${encodeURIComponent(draft)}`
|
|
23251
|
+
: `session=${encodeURIComponent(draft)}`;
|
|
23252
|
+
const head = site === "intl"
|
|
23253
|
+
? `${base}?title=${encodeURIComponent(title)}`
|
|
23254
|
+
: `${base}?template=${encodeURIComponent(channel === "case" ? CASE_TEMPLATE_FILE : RETROSPECTIVE_TEMPLATE_FILE)}&title=${encodeURIComponent(title)}`;
|
|
23255
|
+
const prefilled = `${head}&${draftQuery}`;
|
|
23256
|
+
if (prefilled.length <= exports.bE) {
|
|
23257
|
+
return { url: prefilled, prefilled: true };
|
|
23258
|
+
}
|
|
23259
|
+
return { url: head, prefilled: false };
|
|
23260
|
+
}
|
|
23261
|
+
function buildFeedbackPayload(input) {
|
|
23262
|
+
const site = feedbackSite(input.server);
|
|
23263
|
+
const lang = feedbackLang(site);
|
|
23264
|
+
const outcomes = (0, feedback_session_js_1.readToolOutcomes)(input.server);
|
|
23265
|
+
const secrets = collectSecretValues(input.server);
|
|
23266
|
+
const draft = redact(input.channel === "case"
|
|
23267
|
+
? buildCaseDraft(input.server, outcomes, lang)
|
|
23268
|
+
: buildRetrospectiveDraft(input.server, outcomes, lang), secrets);
|
|
23269
|
+
if (!input.confirmed) {
|
|
23270
|
+
return {
|
|
23271
|
+
success: true,
|
|
23272
|
+
channel: input.channel,
|
|
23273
|
+
confirmed: false,
|
|
23274
|
+
submittable: false,
|
|
23275
|
+
draft,
|
|
23276
|
+
nextStep: lang === "en"
|
|
23277
|
+
? "Show this draft to the user unchanged. Do not give a submission link before they explicitly confirm. Do not rewrite it into a different write-up."
|
|
23278
|
+
: "把这份 draft 原样给用户看。用户明确确认之前,不要给出提交链接,也不要改写成另一份说明。",
|
|
23279
|
+
};
|
|
23280
|
+
}
|
|
23281
|
+
const link = buildFeedbackIssueLink(site, input.channel, draft);
|
|
23282
|
+
const pasteHint = link.prefilled
|
|
23283
|
+
? ""
|
|
23284
|
+
: (lang === "en"
|
|
23285
|
+
? " The link does not include the draft because the URL would be too long. Paste the draft into the session field."
|
|
23286
|
+
: " 链接没有带上正文,因为地址过长。请把 draft 粘贴到「本次会话记录」。");
|
|
23287
|
+
return {
|
|
23288
|
+
success: true,
|
|
23289
|
+
channel: input.channel,
|
|
23290
|
+
confirmed: true,
|
|
23291
|
+
submittable: true,
|
|
23292
|
+
draft,
|
|
23293
|
+
url: link.url,
|
|
23294
|
+
nextStep: (lang === "en"
|
|
23295
|
+
? "The user confirmed. The link body is this draft. Do not submit a rewritten version, and do not submit it for them."
|
|
23296
|
+
: "用户已确认。链接里的正文就是这份 draft。不要另写一版再提交,也不要代为提交。") + pasteHint,
|
|
23297
|
+
};
|
|
23298
|
+
}
|
|
23299
|
+
function registerFeedbackTools(server) {
|
|
23300
|
+
server.registerTool(exports.RS, {
|
|
23301
|
+
title: "feedback.title",
|
|
23302
|
+
description: "feedback.description",
|
|
23303
|
+
inputSchema: {
|
|
23304
|
+
channel: zod_1.z
|
|
23305
|
+
.enum(["case", "retrospective"])
|
|
23306
|
+
.describe("feedback.schema.channel"),
|
|
23307
|
+
confirmed: zod_1.z
|
|
23308
|
+
.boolean()
|
|
23309
|
+
.optional()
|
|
23310
|
+
.describe("feedback.schema.confirmed"),
|
|
23311
|
+
},
|
|
23312
|
+
annotations: {
|
|
23313
|
+
readOnlyHint: true,
|
|
23314
|
+
destructiveHint: false,
|
|
23315
|
+
openWorldHint: false,
|
|
23316
|
+
category: "feedback",
|
|
23317
|
+
},
|
|
23318
|
+
}, async ({ channel, confirmed }) => {
|
|
23319
|
+
return (0, json_content_js_1.jsonContent)(buildFeedbackPayload({
|
|
23320
|
+
server,
|
|
23321
|
+
channel,
|
|
23322
|
+
confirmed: confirmed === true,
|
|
23323
|
+
}));
|
|
23324
|
+
});
|
|
23325
|
+
}
|
|
23326
|
+
|
|
23327
|
+
|
|
23328
|
+
/***/ },
|
|
23329
|
+
|
|
23330
|
+
/***/ 5735
|
|
23331
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
23332
|
+
|
|
23333
|
+
var __webpack_unused_export__;
|
|
23334
|
+
|
|
23335
|
+
/**
|
|
23336
|
+
* 云函数 ZIP 两段式部署·阶段 A:生成 COS 预签名上传地址。
|
|
23337
|
+
*
|
|
23338
|
+
* 通道来源(R1 探针实测裁决,见 output/2026-09-23-functions-zip-two-phase-design.md §4):
|
|
23339
|
+
* - DescribeBuildServiceCosInfo / build-service 上传 / GetTempCosInfo 三条通道全部判死
|
|
23340
|
+
* (CosTimestamp 稳定 InternalError;SCF 拉代码强制给桶名拼 -appid 后缀,共享 build 桶
|
|
23341
|
+
* 永远拉不到;tempcos 桶全 region 404)。
|
|
23342
|
+
* - 活通道:用环境自有存储桶(DescribeEnvs → Storages[0].Bucket/Region)+ 用户凭据
|
|
23343
|
+
* 本地铸 COS q-sign 预签名 PUT URL。CloudBase 临时凭据可直接用于 COS(manager-node
|
|
23344
|
+
* storage 同款 SecretId+SecretKey+token 范式),但必须把 x-cos-security-token 纳入
|
|
23345
|
+
* 签名 Headers 且请求时携带同名头。
|
|
23346
|
+
*
|
|
23347
|
+
* 设计约束:
|
|
23348
|
+
* - 纯函数、零第三方依赖(node:crypto 即可):签名算法从 cos-nodejs-sdk-v5 getAuth
|
|
23349
|
+
* 逐行复刻,测试里与 SDK 真实现做黄金值对照,防止复刻漂移。
|
|
23350
|
+
* - 预签名是本地 HMAC 计算:CAM 零新增权限、不暴露 appId(URL 用全桶名,阶段 B 回传
|
|
23351
|
+
* TCB 的 CosBucketName 用短名)、国际站天然可用。
|
|
23352
|
+
*/
|
|
23353
|
+
__webpack_unused_export__ = ({ value: true });
|
|
23354
|
+
exports.stripAppIdSuffix = stripAppIdSuffix;
|
|
23355
|
+
__webpack_unused_export__ = camSafeUrlEncode;
|
|
23356
|
+
__webpack_unused_export__ = buildCosPutAuthorization;
|
|
23357
|
+
exports.buildFunctionZipUpload = buildFunctionZipUpload;
|
|
23358
|
+
const crypto_1 = __webpack_require__(7823);
|
|
23359
|
+
/** 环境存储桶全名形如 `mybucket-1258016615`;TCB CosBucketName 只收短名(不带 -appid 后缀)。 */
|
|
23360
|
+
function stripAppIdSuffix(bucket) {
|
|
23361
|
+
return bucket.replace(/-\d+$/, "");
|
|
23362
|
+
}
|
|
23363
|
+
/** 复刻 cos-nodejs-sdk-v5 util.camSafeUrlEncode:encodeURIComponent 强制编码 !'()* 五个字符。 */
|
|
23364
|
+
function camSafeUrlEncode(str) {
|
|
23365
|
+
return encodeURIComponent(str)
|
|
23366
|
+
.replace(/!/g, "%21")
|
|
23367
|
+
.replace(/'/g, "%27")
|
|
23368
|
+
.replace(/\(/g, "%28")
|
|
23369
|
+
.replace(/\)/g, "%29")
|
|
23370
|
+
.replace(/\*/g, "%2A");
|
|
23371
|
+
}
|
|
23372
|
+
/** 复刻 SDK getObjectKeys:原始 key 按小写比较排序(排序在编码之前)。 */
|
|
23373
|
+
function sortedKeys(obj) {
|
|
23374
|
+
return Object.keys(obj).sort((a, b) => {
|
|
23375
|
+
a = a.toLowerCase();
|
|
23376
|
+
b = b.toLowerCase();
|
|
23377
|
+
return a === b ? 0 : a > b ? 1 : -1;
|
|
23378
|
+
});
|
|
23379
|
+
}
|
|
23380
|
+
/** 复刻 SDK obj2str(obj, true):key 编码后小写、value 编码,按 key 升序以 & 连接。 */
|
|
23381
|
+
function encodeKv(obj) {
|
|
23382
|
+
return sortedKeys(obj)
|
|
23383
|
+
.map((key) => {
|
|
23384
|
+
const k = camSafeUrlEncode(key).toLowerCase();
|
|
23385
|
+
const v = camSafeUrlEncode(obj[key] ?? "");
|
|
23386
|
+
return `${k}=${v}`;
|
|
23387
|
+
})
|
|
23388
|
+
.join("&");
|
|
23389
|
+
}
|
|
23390
|
+
/**
|
|
23391
|
+
* 生成 COS q-sign 预签名授权串(PUT 方法)。
|
|
23392
|
+
* 算法逐行复刻 cos-nodejs-sdk-v5 getAuth:
|
|
23393
|
+
* signKey = HMAC-SHA1(SecretKey, KeyTime)
|
|
23394
|
+
* formatString = method \n pathname \n query-str \n header-str \n
|
|
23395
|
+
* stringToSign = sha1 \n KeyTime \n sha1(formatString) \n
|
|
23396
|
+
* signature = HMAC-SHA1(signKey, stringToSign)
|
|
23397
|
+
* Host 头始终签入(对齐 SDK ForceSignHost 默认 true),query 为空故 q-url-param-list 为空。
|
|
23398
|
+
*/
|
|
23399
|
+
function buildCosPutAuthorization(options) {
|
|
23400
|
+
const { secretId, secretKey, bucket, region, objectKey, securityToken, expiresInSeconds = 300, } = options;
|
|
23401
|
+
if (!secretId)
|
|
23402
|
+
throw new Error("missing param SecretId");
|
|
23403
|
+
if (!secretKey)
|
|
23404
|
+
throw new Error("missing param SecretKey");
|
|
23405
|
+
if (!bucket)
|
|
23406
|
+
throw new Error("missing param Bucket");
|
|
23407
|
+
if (!region)
|
|
23408
|
+
throw new Error("missing param Region");
|
|
23409
|
+
if (!objectKey)
|
|
23410
|
+
throw new Error("missing param objectKey");
|
|
23411
|
+
const headers = {
|
|
23412
|
+
host: `${bucket}.cos.${region}.myqcloud.com`,
|
|
23413
|
+
};
|
|
23414
|
+
if (securityToken) {
|
|
23415
|
+
headers["x-cos-security-token"] = securityToken;
|
|
23416
|
+
}
|
|
23417
|
+
const keyTime = options.keyTime ??
|
|
23418
|
+
(() => {
|
|
23419
|
+
const now = options.now ?? Math.floor(Date.now() / 1000);
|
|
23420
|
+
return `${now - 1};${now + expiresInSeconds}`;
|
|
23421
|
+
})();
|
|
23422
|
+
// 与请求 URL 一致的编码路径(对象 key 仅允许安全字符时与原始 key 相同)。
|
|
23423
|
+
const pathname = `/${objectKey.split("/").map(encodeURIComponent).join("/")}`;
|
|
23424
|
+
const signKey = (0, crypto_1.createHmac)("sha1", secretKey).update(keyTime).digest("hex");
|
|
23425
|
+
const formatString = ["put", pathname, "", encodeKv(headers), ""].join("\n");
|
|
23426
|
+
const stringToSign = [
|
|
23427
|
+
"sha1",
|
|
23428
|
+
keyTime,
|
|
23429
|
+
(0, crypto_1.createHash)("sha1").update(Buffer.from(formatString, "utf8")).digest("hex"),
|
|
23430
|
+
"",
|
|
23431
|
+
].join("\n");
|
|
23432
|
+
const signature = (0, crypto_1.createHmac)("sha1", signKey).update(stringToSign).digest("hex");
|
|
23433
|
+
const headerList = sortedKeys(headers)
|
|
23434
|
+
.map((key) => camSafeUrlEncode(key).toLowerCase())
|
|
23435
|
+
.join(";");
|
|
23436
|
+
return [
|
|
23437
|
+
"q-sign-algorithm=sha1",
|
|
23438
|
+
`q-ak=${secretId}`,
|
|
23439
|
+
`q-sign-time=${keyTime}`,
|
|
23440
|
+
`q-key-time=${keyTime}`,
|
|
23441
|
+
`q-header-list=${headerList}`,
|
|
23442
|
+
"q-url-param-list=",
|
|
23443
|
+
`q-signature=${signature}`,
|
|
23444
|
+
].join("&");
|
|
23445
|
+
}
|
|
23446
|
+
/**
|
|
23447
|
+
* 生成两段式部署阶段 A 的完整返回体:预签名 PUT URL + 阶段 B 所需的 COS 三元组。
|
|
23448
|
+
* 对象 key 形如 `fnzip-upload/{ts}-{rand}/{functionName|code}.zip`。functionName 会被
|
|
23449
|
+
* 收窄到 COS 签名安全字符(字母数字与 -_),保证签名 pathname 与请求 URL 一致。
|
|
23450
|
+
*/
|
|
23451
|
+
function buildFunctionZipUpload(params) {
|
|
23452
|
+
const { storage, credential, functionName } = params;
|
|
23453
|
+
const expiresIn = params.expiresIn ?? 300;
|
|
23454
|
+
const ts = params.now ?? Math.floor(Date.now() / 1000);
|
|
23455
|
+
const rand = params.randomSuffix ?? (0, crypto_1.randomBytes)(8).toString("hex");
|
|
23456
|
+
// functionName 只用于让对象 key 可读,必须收窄:否则 "../" 之类能把对象写到
|
|
23457
|
+
// fnzip-upload/ 前缀之外
|
|
23458
|
+
const safeFunctionName = functionName && /^[A-Za-z0-9_-]{1,64}$/.test(functionName)
|
|
23459
|
+
? functionName
|
|
23460
|
+
: "code";
|
|
23461
|
+
const objectKey = `fnzip-upload/${ts}-${rand}/${safeFunctionName}.zip`;
|
|
23462
|
+
const keyTime = params.keyTime ?? `${ts - 1};${ts + expiresIn}`;
|
|
23463
|
+
const authorization = buildCosPutAuthorization({
|
|
23464
|
+
secretId: credential.secretId,
|
|
23465
|
+
secretKey: credential.secretKey,
|
|
23466
|
+
bucket: storage.bucket,
|
|
23467
|
+
region: storage.region,
|
|
23468
|
+
objectKey,
|
|
23469
|
+
securityToken: credential.token || undefined,
|
|
23470
|
+
keyTime,
|
|
23471
|
+
});
|
|
23472
|
+
return {
|
|
23473
|
+
uploadUrl: `https://${storage.bucket}.cos.${storage.region}.myqcloud.com/${objectKey}?${authorization}`,
|
|
23474
|
+
uploadHeaders: credential.token
|
|
23475
|
+
? [{ Key: "x-cos-security-token", Value: credential.token }]
|
|
23476
|
+
: [],
|
|
23477
|
+
cosBucketName: stripAppIdSuffix(storage.bucket),
|
|
23478
|
+
cosBucketRegion: storage.region,
|
|
23479
|
+
cosObjectName: objectKey,
|
|
23480
|
+
expiresInSeconds: expiresIn,
|
|
23481
|
+
};
|
|
23482
|
+
}
|
|
23483
|
+
|
|
23484
|
+
|
|
22541
23485
|
/***/ },
|
|
22542
23486
|
|
|
22543
23487
|
/***/ 4931
|
|
@@ -23894,6 +24838,127 @@ async function waitUntilFunctionActive(getStatus, options = {}) {
|
|
|
23894
24838
|
}
|
|
23895
24839
|
|
|
23896
24840
|
|
|
24841
|
+
/***/ },
|
|
24842
|
+
|
|
24843
|
+
/***/ 7499
|
|
24844
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
24845
|
+
|
|
24846
|
+
var __webpack_unused_export__;
|
|
24847
|
+
|
|
24848
|
+
__webpack_unused_export__ = ({ value: true });
|
|
24849
|
+
exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = exports.S1 = void 0;
|
|
24850
|
+
exports.registerFunctionUploadTarget = registerFunctionUploadTarget;
|
|
24851
|
+
exports.findFunctionUploadTarget = findFunctionUploadTarget;
|
|
24852
|
+
__webpack_unused_export__ = getFunctionUploadTargetCount;
|
|
24853
|
+
__webpack_unused_export__ = resetFunctionUploadTargets;
|
|
24854
|
+
const function_cos_upload_js_1 = __webpack_require__(5735);
|
|
24855
|
+
/**
|
|
24856
|
+
* 云函数 ZIP 两段式部署的「上传目标」进程内登记。
|
|
24857
|
+
*
|
|
24858
|
+
* 阶段 A(queryFunctions action=getFunctionUploadUrl)铸造预签名上传地址时,
|
|
24859
|
+
* 在本进程登记这次铸造出来的 (envId, bucket, region, objectKey);阶段 B
|
|
24860
|
+
* (manageFunctions createFunction / updateFunctionCode 带 code 三元组)只接受
|
|
24861
|
+
* 登记过的组合。
|
|
24862
|
+
*
|
|
24863
|
+
* 为什么需要它:code.cosObjectName 是模型可以自由填写的字符串,如果不校验,
|
|
24864
|
+
* 它可以指向环境桶里的任意对象,也可以指向另一个桶(包括调用方自己的桶)——
|
|
24865
|
+
* SCF 会用环境角色去拉取那个对象。登记把可用面收窄成「本进程刚为当前环境铸造
|
|
24866
|
+
* 出来的那个 key」。
|
|
24867
|
+
*
|
|
24868
|
+
* 取舍(刻意不做的事):
|
|
24869
|
+
* - 不做「用一次即作废」:同一个 key 在保留期内可以重复提交。上传失败重试、
|
|
24870
|
+
* updateFunctionCode 撞上 ResourceInUse 后的重试、以及同一份代码包重复部署
|
|
24871
|
+
* 都要能重放,收窄的只是「谁能成为目标」,不是「能用几次」。
|
|
24872
|
+
* - 不区分「没登记」与「登记在别的环境」:登记按 envId 隔离,跨环境查询直接
|
|
24873
|
+
* 未命中,调用方只需要知道「这个目标不在登记里,请重新取地址」。
|
|
24874
|
+
*
|
|
24875
|
+
* 登记只保存在当前 MCP 进程内存中,MCP Server 重启即丢失 —— 此时重新调用
|
|
24876
|
+
* getFunctionUploadUrl 取地址、重新上传即可。这与 function-deploy-task-store
|
|
24877
|
+
* 的语义一致(异步部署任务同样只活在进程内)。
|
|
24878
|
+
*/
|
|
24879
|
+
exports.S1 = {
|
|
24880
|
+
/**
|
|
24881
|
+
* 登记的保留时间。远长于上传地址本身的有效期(默认 300 秒):地址过期只影响
|
|
24882
|
+
* 「还能不能 PUT」,而登记要覆盖「取地址 → 上传 → 提交部署」整条链在客户端
|
|
24883
|
+
* 可能的等待(大包上传、人工确认、agent 多轮编排)。
|
|
24884
|
+
*/
|
|
24885
|
+
ttlMs: 60 * 60 * 1000,
|
|
24886
|
+
/** 最大登记数,超出时淘汰最旧的 */
|
|
24887
|
+
maxTargets: 500,
|
|
24888
|
+
};
|
|
24889
|
+
exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = "FUNCTION_UPLOAD_TARGET_NOT_FOUND";
|
|
24890
|
+
const uploadTargets = new Map();
|
|
24891
|
+
/**
|
|
24892
|
+
* envId 与 objectKey 都不可能含 NUL,用它拼主键不会产生歧义;
|
|
24893
|
+
* 反过来,跨环境的查询无法构造出同一主键(前缀 envId 由服务端解析,调用方改不了)。
|
|
24894
|
+
*/
|
|
24895
|
+
function targetKey(envId, objectKey) {
|
|
24896
|
+
return `${envId}\u0000${objectKey}`;
|
|
24897
|
+
}
|
|
24898
|
+
function cleanupUploadTargets(now) {
|
|
24899
|
+
for (const [key, target] of uploadTargets) {
|
|
24900
|
+
if (now - target.createdAtMs > exports.S1.ttlMs) {
|
|
24901
|
+
uploadTargets.delete(key);
|
|
24902
|
+
}
|
|
24903
|
+
}
|
|
24904
|
+
}
|
|
24905
|
+
/**
|
|
24906
|
+
* 达到上限时淘汰最旧的登记。
|
|
24907
|
+
*
|
|
24908
|
+
* 与部署任务表不同,这里每一条登记都可以淘汰 —— 淘汰最坏的结果是调用方重新
|
|
24909
|
+
* 取一次上传地址,不会影响任何正在进行中的云端操作,因此不需要 warn。
|
|
24910
|
+
*/
|
|
24911
|
+
function enforceMaxTargets() {
|
|
24912
|
+
const { maxTargets } = exports.S1;
|
|
24913
|
+
if (uploadTargets.size < maxTargets) {
|
|
24914
|
+
return;
|
|
24915
|
+
}
|
|
24916
|
+
const oldestFirst = [...uploadTargets.entries()].sort((left, right) => left[1].createdAtMs - right[1].createdAtMs);
|
|
24917
|
+
for (const [key] of oldestFirst) {
|
|
24918
|
+
if (uploadTargets.size < maxTargets) {
|
|
24919
|
+
return;
|
|
24920
|
+
}
|
|
24921
|
+
uploadTargets.delete(key);
|
|
24922
|
+
}
|
|
24923
|
+
}
|
|
24924
|
+
/** 阶段 A 登记本次铸造的上传目标。 */
|
|
24925
|
+
function registerFunctionUploadTarget(input) {
|
|
24926
|
+
const now = input.now ?? Date.now();
|
|
24927
|
+
cleanupUploadTargets(now);
|
|
24928
|
+
enforceMaxTargets();
|
|
24929
|
+
uploadTargets.set(targetKey(input.envId, input.objectKey), {
|
|
24930
|
+
envId: input.envId,
|
|
24931
|
+
bucket: input.bucket,
|
|
24932
|
+
region: input.region,
|
|
24933
|
+
objectKey: input.objectKey,
|
|
24934
|
+
createdAtMs: now,
|
|
24935
|
+
});
|
|
24936
|
+
}
|
|
24937
|
+
/**
|
|
24938
|
+
* 阶段 B 校验:命中登记且桶、地域都对得上才返回目标,否则返回 undefined。
|
|
24939
|
+
*
|
|
24940
|
+
* 地域与桶都要比对 —— 只比对象 key 的话,仍然可以把同一个 key 指到别的桶或
|
|
24941
|
+
* 别的地域(例如把代码指到调用方自己的桶)上。
|
|
24942
|
+
*/
|
|
24943
|
+
function findFunctionUploadTarget(input) {
|
|
24944
|
+
const now = input.now ?? Date.now();
|
|
24945
|
+
cleanupUploadTargets(now);
|
|
24946
|
+
const target = uploadTargets.get(targetKey(input.envId, input.objectKey));
|
|
24947
|
+
if (!target) {
|
|
24948
|
+
return undefined;
|
|
24949
|
+
}
|
|
24950
|
+
const bucketMatches = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.bucketName) === (0, function_cos_upload_js_1.stripAppIdSuffix)(target.bucket);
|
|
24951
|
+
return bucketMatches && input.region === target.region ? target : undefined;
|
|
24952
|
+
}
|
|
24953
|
+
function getFunctionUploadTargetCount() {
|
|
24954
|
+
return uploadTargets.size;
|
|
24955
|
+
}
|
|
24956
|
+
/** 测试用:清空登记表 */
|
|
24957
|
+
function resetFunctionUploadTargets() {
|
|
24958
|
+
uploadTargets.clear();
|
|
24959
|
+
}
|
|
24960
|
+
|
|
24961
|
+
|
|
23897
24962
|
/***/ },
|
|
23898
24963
|
|
|
23899
24964
|
/***/ 1546
|
|
@@ -23924,10 +24989,36 @@ const logger_js_1 = __webpack_require__(781);
|
|
|
23924
24989
|
const tool_result_js_1 = __webpack_require__(9645);
|
|
23925
24990
|
const function_deploy_js_1 = __webpack_require__(9151);
|
|
23926
24991
|
const function_deploy_schema_js_1 = __webpack_require__(6427);
|
|
24992
|
+
const function_cos_upload_js_1 = __webpack_require__(5735);
|
|
24993
|
+
const function_upload_target_store_js_1 = __webpack_require__(7499);
|
|
23927
24994
|
const function_updating_js_1 = __webpack_require__(326);
|
|
23928
24995
|
const index_js_1 = __webpack_require__(4908);
|
|
23929
24996
|
const fs_1 = __webpack_require__(4421);
|
|
23930
24997
|
const path_1 = __importDefault(__webpack_require__(2521));
|
|
24998
|
+
/**
|
|
24999
|
+
* 阶段 B 校验:code 三元组必须是本进程阶段 A 登记过的上传目标。
|
|
25000
|
+
*
|
|
25001
|
+
* 未命中时统一按「目标不在登记里」返回,不区分「没登记」与「登记在别的环境」——
|
|
25002
|
+
* 与部署任务表同款取舍,调用方只需要知道下一步该重新取上传地址。
|
|
25003
|
+
*/
|
|
25004
|
+
function assertFunctionUploadTarget(input) {
|
|
25005
|
+
if ((0, function_upload_target_store_js_1.findFunctionUploadTarget)(input)) {
|
|
25006
|
+
return;
|
|
25007
|
+
}
|
|
25008
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
25009
|
+
success: false,
|
|
25010
|
+
errorCode: function_upload_target_store_js_1.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE,
|
|
25011
|
+
data: {
|
|
25012
|
+
action: input.action,
|
|
25013
|
+
cosBucketName: input.bucketName,
|
|
25014
|
+
cosBucketRegion: input.region,
|
|
25015
|
+
cosObjectName: input.objectKey,
|
|
25016
|
+
},
|
|
25017
|
+
message: (0, index_js_1.t)("functions.uploadTargetNotFound", {
|
|
25018
|
+
objectName: input.objectKey,
|
|
25019
|
+
}),
|
|
25020
|
+
});
|
|
25021
|
+
}
|
|
23931
25022
|
exports.SUPPORTED_RUNTIMES = {
|
|
23932
25023
|
nodejs: [
|
|
23933
25024
|
"Nodejs20.19",
|
|
@@ -24005,6 +25096,7 @@ exports.QUERY_FUNCTION_ACTIONS = [
|
|
|
24005
25096
|
"getFunctionDeployStatus",
|
|
24006
25097
|
"listVersionByFunction",
|
|
24007
25098
|
"getFunctionAlias",
|
|
25099
|
+
"getFunctionUploadUrl",
|
|
24008
25100
|
];
|
|
24009
25101
|
exports.MANAGE_FUNCTION_ACTIONS = [
|
|
24010
25102
|
"createFunction",
|
|
@@ -24184,6 +25276,25 @@ const MANAGE_LAYER_SCHEMA = zod_1.z.object({
|
|
|
24184
25276
|
layerName: zod_1.z.string().describe("functions.schema.manageLayer.name"),
|
|
24185
25277
|
layerVersion: zod_1.z.number().describe("functions.schema.manageLayer.version"),
|
|
24186
25278
|
});
|
|
25279
|
+
/**
|
|
25280
|
+
* ZIP 两段式部署阶段 B 的 code 入参(camelCase,映射为 SDK 的 PascalCase code 三元组)。
|
|
25281
|
+
* 三件套均来自 queryFunctions getFunctionUploadUrl 的返回体,原样透传即可。
|
|
25282
|
+
* strict:拼错字段名直接报错,而不是被静默丢弃后按本地目录语义执行。
|
|
25283
|
+
*/
|
|
25284
|
+
const FUNCTION_CODE_SCHEMA = zod_1.z
|
|
25285
|
+
.object({
|
|
25286
|
+
cosBucketName: zod_1.z
|
|
25287
|
+
.string()
|
|
25288
|
+
.describe("functions.schema.code.cosBucketName"),
|
|
25289
|
+
cosObjectName: zod_1.z
|
|
25290
|
+
.string()
|
|
25291
|
+
.describe("functions.schema.code.cosObjectName"),
|
|
25292
|
+
cosBucketRegion: zod_1.z
|
|
25293
|
+
.string()
|
|
25294
|
+
.optional()
|
|
25295
|
+
.describe("functions.schema.code.cosBucketRegion"),
|
|
25296
|
+
})
|
|
25297
|
+
.strict();
|
|
24187
25298
|
const FUNCTION_VERSION_WEIGHT_SCHEMA = zod_1.z.object({
|
|
24188
25299
|
Version: zod_1.z.string().describe("functions.schema.routing.version"),
|
|
24189
25300
|
Weight: zod_1.z.number().describe("functions.schema.routing.weight"),
|
|
@@ -24383,6 +25494,49 @@ function registerFunctionTools(server) {
|
|
|
24383
25494
|
throw new Error((0, index_js_1.t)("functions.confirmRequired", { action }));
|
|
24384
25495
|
}
|
|
24385
25496
|
};
|
|
25497
|
+
/**
|
|
25498
|
+
* 解析当前环境的自有存储桶(DescribeEnvs → Storages[0])。
|
|
25499
|
+
* 两段式部署的上传桶必须用环境自己的桶:共享 build 桶会被 SCF 拉
|
|
25500
|
+
* 代码时的 -appid 拼接判死(R1 探针实测)。无存储的环境直接报错引导。
|
|
25501
|
+
*
|
|
25502
|
+
* DescribeEnvs 是账号级动作,环境级凭据(如 API Key 换取的 STS,
|
|
25503
|
+
* remote MCP 临时 API Key 即此类)调用会被网关拒绝(invalid token),
|
|
25504
|
+
* 此时回退到环境级的 DescribeEnvInfo —— 其 EnvBaseInfo.Storages 与
|
|
25505
|
+
* DescribeEnvs 的 Storages 同构(实测两者均含 Bucket/Region/Status)。
|
|
25506
|
+
*/
|
|
25507
|
+
const resolveEnvFunctionCosStorage = async () => {
|
|
25508
|
+
const cloudbase = await getManager();
|
|
25509
|
+
const envId = cloudBaseOptions?.envId ?? (await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions));
|
|
25510
|
+
const tcbService = cloudbase.commonService("tcb", "2018-06-08");
|
|
25511
|
+
const fetchStorages = async () => {
|
|
25512
|
+
try {
|
|
25513
|
+
const envsResult = (await tcbService.call({
|
|
25514
|
+
Action: "DescribeEnvs",
|
|
25515
|
+
Param: { EnvId: envId },
|
|
25516
|
+
}));
|
|
25517
|
+
const storages = envsResult?.EnvList?.[0]?.Storages ?? envsResult?.EnvInfo?.Storages ?? [];
|
|
25518
|
+
if (storages.length > 0) {
|
|
25519
|
+
return storages;
|
|
25520
|
+
}
|
|
25521
|
+
}
|
|
25522
|
+
catch (e) {
|
|
25523
|
+
(0, logger_js_1.debug)("resolveEnvFunctionCosStorage: DescribeEnvs failed, falling back to DescribeEnvInfo", { envId, error: e instanceof Error ? e.message : String(e) });
|
|
25524
|
+
}
|
|
25525
|
+
const infoResult = (await tcbService.call({
|
|
25526
|
+
Action: "DescribeEnvInfo",
|
|
25527
|
+
Param: { EnvId: envId },
|
|
25528
|
+
}));
|
|
25529
|
+
return infoResult?.EnvInfo?.EnvBaseInfo?.Storages ?? [];
|
|
25530
|
+
};
|
|
25531
|
+
const storages = await fetchStorages();
|
|
25532
|
+
const bucket = storages[0]?.Bucket ?? "";
|
|
25533
|
+
const region = storages[0]?.Region ?? "";
|
|
25534
|
+
if (!bucket || !region) {
|
|
25535
|
+
throw new Error((0, index_js_1.t)("functions.storageMissing"));
|
|
25536
|
+
}
|
|
25537
|
+
// envId 一并返回:阶段 A 的上传目标登记与阶段 B 的校验都按环境隔离
|
|
25538
|
+
return { bucket, region, envId };
|
|
25539
|
+
};
|
|
24386
25540
|
const ensureActionAllowedInCloudMode = (input) => {
|
|
24387
25541
|
if (!(0, cloud_mode_js_1.isCloudMode)()) {
|
|
24388
25542
|
return;
|
|
@@ -24397,6 +25551,11 @@ function registerFunctionTools(server) {
|
|
|
24397
25551
|
if (hasImageDeploy) {
|
|
24398
25552
|
return;
|
|
24399
25553
|
}
|
|
25554
|
+
// 两段式部署阶段 B:代码包已上传到环境 COS 桶,全程不依赖本地目录,
|
|
25555
|
+
// 与镜像部署同属可在 cloud mode 下真实执行的路径。
|
|
25556
|
+
if (Boolean(input.code)) {
|
|
25557
|
+
return;
|
|
25558
|
+
}
|
|
24400
25559
|
throw new Error((0, index_js_1.t)("functions.cloudMode.localOnly", { action: input.action }));
|
|
24401
25560
|
}
|
|
24402
25561
|
if (input.action === "createLayerVersion" && input.contentPath) {
|
|
@@ -24615,7 +25774,13 @@ function registerFunctionTools(server) {
|
|
|
24615
25774
|
}
|
|
24616
25775
|
const cloudbase = await getManager();
|
|
24617
25776
|
const result = await cloudbase.functions.getFunctionDetail(input.functionName, input.codeSecret);
|
|
24618
|
-
|
|
25777
|
+
// 与 getFunctionDetail / listFunctionTriggers 一致:本 action 只想取 Layers,
|
|
25778
|
+
// 但 getFunctionDetail 的返回里带着环境变量明文,日志与 raw 都必须脱敏 ——
|
|
25779
|
+
// 否则一个只读的「看层」动作会把明文环境变量带进模型上下文与持久化日志。
|
|
25780
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, maskFunctionDetailEnvValues(result));
|
|
25781
|
+
const detail = input.revealEnvValues === true
|
|
25782
|
+
? result
|
|
25783
|
+
: maskFunctionDetailEnvValues(result);
|
|
24619
25784
|
const layers = normalizeFunctionLayers(result.Layers);
|
|
24620
25785
|
return buildEnvelope({
|
|
24621
25786
|
action: input.action,
|
|
@@ -24623,7 +25788,7 @@ function registerFunctionTools(server) {
|
|
|
24623
25788
|
layers,
|
|
24624
25789
|
count: layers.length,
|
|
24625
25790
|
requestId: result.RequestId,
|
|
24626
|
-
raw:
|
|
25791
|
+
raw: detail,
|
|
24627
25792
|
}, (0, index_js_1.t)("functions.gotFunctionLayers", { fnName: input.functionName }), [
|
|
24628
25793
|
{
|
|
24629
25794
|
tool: "manageFunctions",
|
|
@@ -24761,7 +25926,9 @@ function registerFunctionTools(server) {
|
|
|
24761
25926
|
}
|
|
24762
25927
|
const cloudbase = await getManager();
|
|
24763
25928
|
const result = await cloudbase.functions.getFunctionDownloadUrl(input.functionName, input.codeSecret);
|
|
24764
|
-
|
|
25929
|
+
// downloadUrl 是带凭据签名的临时链接:与 apps getUploadUrl 同款处理,只落 RequestId,
|
|
25930
|
+
// 避免整条 URL 随宿主日志持久化
|
|
25931
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, { RequestId: result.RequestId });
|
|
24765
25932
|
return buildEnvelope({
|
|
24766
25933
|
action: input.action,
|
|
24767
25934
|
functionName: input.functionName,
|
|
@@ -24843,6 +26010,52 @@ function registerFunctionTools(server) {
|
|
|
24843
26010
|
},
|
|
24844
26011
|
]);
|
|
24845
26012
|
}
|
|
26013
|
+
case "getFunctionUploadUrl": {
|
|
26014
|
+
// ZIP 两段式部署阶段 A:环境自有存储桶 + 用户凭据本地铸 COS 预签名 PUT URL。
|
|
26015
|
+
// functionName 可选,仅用于生成可读的对象 key。
|
|
26016
|
+
const cloudbase = await getManager();
|
|
26017
|
+
const authConfig = cloudbase.currentEnvironment().getAuthConfig();
|
|
26018
|
+
if (!authConfig?.secretId || !authConfig?.secretKey) {
|
|
26019
|
+
throw new Error((0, index_js_1.t)("functions.credentialMissing"));
|
|
26020
|
+
}
|
|
26021
|
+
const storage = await resolveEnvFunctionCosStorage();
|
|
26022
|
+
const upload = (0, function_cos_upload_js_1.buildFunctionZipUpload)({
|
|
26023
|
+
storage,
|
|
26024
|
+
credential: {
|
|
26025
|
+
secretId: authConfig.secretId,
|
|
26026
|
+
secretKey: authConfig.secretKey,
|
|
26027
|
+
// 永久密钥时 token 为空串,转 undefined 才不签入 token 头
|
|
26028
|
+
token: authConfig.token || undefined,
|
|
26029
|
+
},
|
|
26030
|
+
functionName: input.functionName,
|
|
26031
|
+
});
|
|
26032
|
+
// 阶段 A 在进程内登记本次铸造的上传目标:阶段 B 只接受登记过的
|
|
26033
|
+
// (envId, bucket, region, objectKey),cosObjectName 因此不再是任意字符串。
|
|
26034
|
+
(0, function_upload_target_store_js_1.registerFunctionUploadTarget)({
|
|
26035
|
+
envId: storage.envId,
|
|
26036
|
+
bucket: storage.bucket,
|
|
26037
|
+
region: storage.region,
|
|
26038
|
+
objectKey: upload.cosObjectName,
|
|
26039
|
+
});
|
|
26040
|
+
// uploadUrl 内含凭据绑定的签名(临时凭据还绑定 token),禁止落日志
|
|
26041
|
+
(0, logger_js_1.debug)(`[getFunctionUploadUrl] envId=${authConfig.envId ?? "n/a"}, cosObjectName=${upload.cosObjectName}, expiresIn=${upload.expiresInSeconds}s`);
|
|
26042
|
+
return buildEnvelope({
|
|
26043
|
+
action: input.action,
|
|
26044
|
+
...(input.functionName ? { functionName: input.functionName } : {}),
|
|
26045
|
+
uploadUrl: upload.uploadUrl,
|
|
26046
|
+
uploadHeaders: upload.uploadHeaders,
|
|
26047
|
+
cosBucketName: upload.cosBucketName,
|
|
26048
|
+
cosBucketRegion: upload.cosBucketRegion,
|
|
26049
|
+
cosObjectName: upload.cosObjectName,
|
|
26050
|
+
expiresInSeconds: upload.expiresInSeconds,
|
|
26051
|
+
}, (0, index_js_1.t)("functions.gotUploadUrl", { seconds: upload.expiresInSeconds }), [
|
|
26052
|
+
{
|
|
26053
|
+
tool: "manageFunctions",
|
|
26054
|
+
action: "createFunction",
|
|
26055
|
+
reason: (0, index_js_1.t)("functions.reason.cosCreate"),
|
|
26056
|
+
},
|
|
26057
|
+
]);
|
|
26058
|
+
}
|
|
24846
26059
|
default:
|
|
24847
26060
|
throw new Error((0, index_js_1.t)("functions.unsupportedAction", { action: input.action }));
|
|
24848
26061
|
}
|
|
@@ -25099,6 +26312,70 @@ function registerFunctionTools(server) {
|
|
|
25099
26312
|
},
|
|
25100
26313
|
]);
|
|
25101
26314
|
}
|
|
26315
|
+
// code 入参(ZIP 两段式部署阶段 B):代码包已由 getFunctionUploadUrl 上传到
|
|
26316
|
+
// 环境 COS 桶,直接 deployMode=cos 提交,跳过本地目录 / 依赖安装逻辑。
|
|
26317
|
+
if (input.code) {
|
|
26318
|
+
const storage = await resolveEnvFunctionCosStorage();
|
|
26319
|
+
const cosBucketName = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.code.cosBucketName || storage.bucket);
|
|
26320
|
+
const cosBucketRegion = input.code.cosBucketRegion ?? storage.region;
|
|
26321
|
+
assertFunctionUploadTarget({
|
|
26322
|
+
envId: storage.envId,
|
|
26323
|
+
bucketName: input.code.cosBucketName || storage.bucket,
|
|
26324
|
+
region: cosBucketRegion,
|
|
26325
|
+
objectKey: input.code.cosObjectName,
|
|
26326
|
+
action: input.action,
|
|
26327
|
+
});
|
|
26328
|
+
const codeFunc = { ...func };
|
|
26329
|
+
// 用户 zip 自带依赖语义(装没装由上传方决定),默认不触发云端依赖安装
|
|
26330
|
+
delete codeFunc.installDependency;
|
|
26331
|
+
if (input.func?.installDependency !== undefined) {
|
|
26332
|
+
codeFunc.installDependency = input.func.installDependency;
|
|
26333
|
+
}
|
|
26334
|
+
if (codeFunc.type !== "HTTP") {
|
|
26335
|
+
codeFunc.runtime = resolveEventFunctionRuntime(codeFunc.runtime);
|
|
26336
|
+
}
|
|
26337
|
+
let cosCreateResult;
|
|
26338
|
+
try {
|
|
26339
|
+
cosCreateResult = await cloudbase.functions.createFunction({
|
|
26340
|
+
func: codeFunc,
|
|
26341
|
+
code: {
|
|
26342
|
+
CosBucketName: cosBucketName,
|
|
26343
|
+
CosBucketRegion: cosBucketRegion,
|
|
26344
|
+
CosObjectName: input.code.cosObjectName,
|
|
26345
|
+
},
|
|
26346
|
+
deployMode: "cos",
|
|
26347
|
+
force: Boolean(input.force),
|
|
26348
|
+
});
|
|
26349
|
+
}
|
|
26350
|
+
catch (error) {
|
|
26351
|
+
throw wrapFunctionOperationError("createFunction", functionName, undefined, error);
|
|
26352
|
+
}
|
|
26353
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, cosCreateResult);
|
|
26354
|
+
return buildEnvelope({
|
|
26355
|
+
action: input.action,
|
|
26356
|
+
functionName,
|
|
26357
|
+
deployMode: "cos",
|
|
26358
|
+
cosBucketName,
|
|
26359
|
+
cosBucketRegion,
|
|
26360
|
+
cosObjectName: input.code.cosObjectName,
|
|
26361
|
+
raw: cosCreateResult,
|
|
26362
|
+
}, (0, index_js_1.t)("functions.cosCreatedMessage", { fnName: functionName }), [
|
|
26363
|
+
{
|
|
26364
|
+
tool: "queryFunctions",
|
|
26365
|
+
action: "getFunctionDetail",
|
|
26366
|
+
reason: (0, index_js_1.t)("functions.reason.confirmConfig"),
|
|
26367
|
+
},
|
|
26368
|
+
...(codeFunc.type === "HTTP"
|
|
26369
|
+
? [
|
|
26370
|
+
{
|
|
26371
|
+
tool: "manageGateway",
|
|
26372
|
+
action: "createRoute",
|
|
26373
|
+
reason: (0, index_js_1.t)("functions.reason.gatewayRouteForHttp"),
|
|
26374
|
+
},
|
|
26375
|
+
]
|
|
26376
|
+
: []),
|
|
26377
|
+
]);
|
|
26378
|
+
}
|
|
25102
26379
|
if (func.type !== "HTTP") {
|
|
25103
26380
|
const originalRuntime = typeof func.runtime === "string" ? func.runtime : undefined;
|
|
25104
26381
|
func.runtime = resolveEventFunctionRuntime(func.runtime);
|
|
@@ -25307,6 +26584,65 @@ function registerFunctionTools(server) {
|
|
|
25307
26584
|
},
|
|
25308
26585
|
]);
|
|
25309
26586
|
}
|
|
26587
|
+
// code 入参(ZIP 两段式部署阶段 B):zip 已在环境 COS 桶,直接 deployMode=cos
|
|
26588
|
+
// 更新代码包,跳过 functionRootPath / zipFile 本地语义。
|
|
26589
|
+
if (input.code) {
|
|
26590
|
+
const storage = await resolveEnvFunctionCosStorage();
|
|
26591
|
+
const cosBucketName = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.code.cosBucketName || storage.bucket);
|
|
26592
|
+
const cosBucketRegion = input.code.cosBucketRegion ?? storage.region;
|
|
26593
|
+
assertFunctionUploadTarget({
|
|
26594
|
+
envId: storage.envId,
|
|
26595
|
+
bucketName: input.code.cosBucketName || storage.bucket,
|
|
26596
|
+
region: cosBucketRegion,
|
|
26597
|
+
objectKey: input.code.cosObjectName,
|
|
26598
|
+
action: input.action,
|
|
26599
|
+
});
|
|
26600
|
+
let cosUpdateResult;
|
|
26601
|
+
try {
|
|
26602
|
+
cosUpdateResult = await cloudbase.functions.updateFunctionCode({
|
|
26603
|
+
func: {
|
|
26604
|
+
name: input.functionName,
|
|
26605
|
+
// 与 create 的 code 分支一致:默认不触发云端依赖安装,显式传参才覆盖
|
|
26606
|
+
...(input.func?.installDependency !== undefined
|
|
26607
|
+
? { installDependency: input.func.installDependency }
|
|
26608
|
+
: {}),
|
|
26609
|
+
...(input.handler ? { handler: input.handler } : {}),
|
|
26610
|
+
},
|
|
26611
|
+
code: {
|
|
26612
|
+
CosBucketName: cosBucketName,
|
|
26613
|
+
CosBucketRegion: cosBucketRegion,
|
|
26614
|
+
CosObjectName: input.code.cosObjectName,
|
|
26615
|
+
},
|
|
26616
|
+
deployMode: "cos",
|
|
26617
|
+
});
|
|
26618
|
+
}
|
|
26619
|
+
catch (error) {
|
|
26620
|
+
if ((0, function_updating_js_1.isFunctionUpdatingError)(error)) {
|
|
26621
|
+
return (0, function_updating_js_1.buildFunctionUpdatingPayload)({
|
|
26622
|
+
action: "updateFunctionCode",
|
|
26623
|
+
functionName: input.functionName,
|
|
26624
|
+
rawMessage: (0, function_updating_js_1.getErrorMessage)(error),
|
|
26625
|
+
});
|
|
26626
|
+
}
|
|
26627
|
+
throw wrapFunctionOperationError("updateFunctionCode", input.functionName, undefined, error);
|
|
26628
|
+
}
|
|
26629
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, cosUpdateResult);
|
|
26630
|
+
return buildEnvelope({
|
|
26631
|
+
action: input.action,
|
|
26632
|
+
functionName: input.functionName,
|
|
26633
|
+
deployMode: "cos",
|
|
26634
|
+
cosBucketName,
|
|
26635
|
+
cosBucketRegion,
|
|
26636
|
+
cosObjectName: input.code.cosObjectName,
|
|
26637
|
+
raw: cosUpdateResult,
|
|
26638
|
+
}, (0, index_js_1.t)("functions.cosUpdatedMessage", { fnName: input.functionName }), [
|
|
26639
|
+
{
|
|
26640
|
+
tool: "queryFunctions",
|
|
26641
|
+
action: "getFunctionDetail",
|
|
26642
|
+
reason: (0, index_js_1.t)("functions.reason.confirmConfig"),
|
|
26643
|
+
},
|
|
26644
|
+
]);
|
|
26645
|
+
}
|
|
25310
26646
|
const processedRootPath = processFunctionRootPath(input.functionRootPath, input.functionName);
|
|
25311
26647
|
const updateParams = {
|
|
25312
26648
|
func: {
|
|
@@ -25857,6 +27193,7 @@ function registerFunctionTools(server) {
|
|
|
25857
27193
|
.optional()
|
|
25858
27194
|
.describe("functions.schema.manage.functionName"),
|
|
25859
27195
|
zipFile: zod_1.z.string().optional().describe("functions.schema.manage.zipFile"),
|
|
27196
|
+
code: FUNCTION_CODE_SCHEMA.optional().describe("functions.schema.manage.code"),
|
|
25860
27197
|
handler: zod_1.z.string().optional().describe("functions.schema.manage.handler"),
|
|
25861
27198
|
timeout: zod_1.z.number().optional().describe("functions.schema.manage.timeout"),
|
|
25862
27199
|
envVariables: zod_1.z
|
|
@@ -28492,18 +29829,23 @@ const cloudbase_manager_js_1 = __webpack_require__(3109);
|
|
|
28492
29829
|
const json_content_js_1 = __webpack_require__(8027);
|
|
28493
29830
|
const index_js_1 = __webpack_require__(4908);
|
|
28494
29831
|
const QUERY_LOG_ACTIONS = ["checkLogService", "searchLogs"];
|
|
28495
|
-
|
|
29832
|
+
const MANAGE_LOG_ACTIONS = ["createLogService"];
|
|
29833
|
+
function buildEnvelope(data, message, extras) {
|
|
28496
29834
|
return {
|
|
28497
29835
|
success: true,
|
|
28498
29836
|
data,
|
|
28499
29837
|
message,
|
|
29838
|
+
...extras,
|
|
28500
29839
|
};
|
|
28501
29840
|
}
|
|
28502
|
-
function buildErrorEnvelope(error) {
|
|
29841
|
+
function buildErrorEnvelope(error, extras) {
|
|
28503
29842
|
return {
|
|
28504
29843
|
success: false,
|
|
28505
|
-
data: {},
|
|
28506
|
-
message:
|
|
29844
|
+
data: extras?.data ?? {},
|
|
29845
|
+
message: extras?.message ??
|
|
29846
|
+
(error instanceof Error ? error.message : String(error)),
|
|
29847
|
+
errorCode: extras?.errorCode,
|
|
29848
|
+
nextActions: extras?.nextActions,
|
|
28507
29849
|
};
|
|
28508
29850
|
}
|
|
28509
29851
|
function registerLogTools(server) {
|
|
@@ -28576,6 +29918,89 @@ function registerLogTools(server) {
|
|
|
28576
29918
|
return (0, json_content_js_1.jsonContent)(buildErrorEnvelope(error));
|
|
28577
29919
|
}
|
|
28578
29920
|
});
|
|
29921
|
+
server.registerTool?.("manageLogs", {
|
|
29922
|
+
title: "logs.manage.title",
|
|
29923
|
+
description: "logs.manage.description",
|
|
29924
|
+
inputSchema: {
|
|
29925
|
+
action: zod_1.z
|
|
29926
|
+
.enum(MANAGE_LOG_ACTIONS)
|
|
29927
|
+
.describe("logs.manage.schema.action"),
|
|
29928
|
+
confirm: zod_1.z
|
|
29929
|
+
.boolean()
|
|
29930
|
+
.optional()
|
|
29931
|
+
.describe("logs.manage.schema.confirm"),
|
|
29932
|
+
},
|
|
29933
|
+
annotations: {
|
|
29934
|
+
readOnlyHint: false,
|
|
29935
|
+
destructiveHint: false,
|
|
29936
|
+
idempotentHint: false,
|
|
29937
|
+
openWorldHint: false,
|
|
29938
|
+
category: "logs",
|
|
29939
|
+
},
|
|
29940
|
+
}, async ({ action, confirm, }) => {
|
|
29941
|
+
try {
|
|
29942
|
+
if (action !== "createLogService") {
|
|
29943
|
+
return (0, json_content_js_1.jsonContent)(buildErrorEnvelope(new Error((0, index_js_1.t)("logs.manage.unsupportedAction", { action })), {
|
|
29944
|
+
errorCode: "UNSUPPORTED_ACTION",
|
|
29945
|
+
}));
|
|
29946
|
+
}
|
|
29947
|
+
if (confirm !== true) {
|
|
29948
|
+
return (0, json_content_js_1.jsonContent)(buildErrorEnvelope(null, {
|
|
29949
|
+
errorCode: "CONFIRM_REQUIRED",
|
|
29950
|
+
message: (0, index_js_1.t)("logs.manage.create.confirmRequired"),
|
|
29951
|
+
data: { action },
|
|
29952
|
+
nextActions: [
|
|
29953
|
+
{
|
|
29954
|
+
tool: "manageLogs",
|
|
29955
|
+
action: "createLogService",
|
|
29956
|
+
suggested_args: { action: "createLogService", confirm: true },
|
|
29957
|
+
reason: (0, index_js_1.t)("logs.manage.create.needsConfirmation"),
|
|
29958
|
+
},
|
|
29959
|
+
],
|
|
29960
|
+
}));
|
|
29961
|
+
}
|
|
29962
|
+
const cloudbase = await getManager();
|
|
29963
|
+
const enabled = await cloudbase.log.checkLogServiceEnabled();
|
|
29964
|
+
if (enabled) {
|
|
29965
|
+
return (0, json_content_js_1.jsonContent)(buildEnvelope({
|
|
29966
|
+
action,
|
|
29967
|
+
enabled: true,
|
|
29968
|
+
alreadyEnabled: true,
|
|
29969
|
+
}, (0, index_js_1.t)("logs.manage.create.alreadyEnabled"), {
|
|
29970
|
+
nextActions: [
|
|
29971
|
+
{
|
|
29972
|
+
tool: "queryLogs",
|
|
29973
|
+
action: "searchLogs",
|
|
29974
|
+
suggested_args: {
|
|
29975
|
+
action: "searchLogs",
|
|
29976
|
+
queryString: 'log:"ERROR"',
|
|
29977
|
+
},
|
|
29978
|
+
reason: (0, index_js_1.t)("logs.manage.create.nextSearch"),
|
|
29979
|
+
},
|
|
29980
|
+
],
|
|
29981
|
+
}));
|
|
29982
|
+
}
|
|
29983
|
+
const result = await cloudbase.log.createLogService();
|
|
29984
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
29985
|
+
return (0, json_content_js_1.jsonContent)(buildEnvelope({
|
|
29986
|
+
action,
|
|
29987
|
+
requestId: result.RequestId ?? null,
|
|
29988
|
+
raw: result,
|
|
29989
|
+
}, (0, index_js_1.t)("logs.manage.create.submitted"), {
|
|
29990
|
+
nextActions: [
|
|
29991
|
+
{
|
|
29992
|
+
tool: "queryLogs",
|
|
29993
|
+
action: "checkLogService",
|
|
29994
|
+
suggested_args: { action: "checkLogService" },
|
|
29995
|
+
reason: (0, index_js_1.t)("logs.manage.create.nextCheck"),
|
|
29996
|
+
},
|
|
29997
|
+
],
|
|
29998
|
+
}));
|
|
29999
|
+
}
|
|
30000
|
+
catch (error) {
|
|
30001
|
+
return (0, json_content_js_1.jsonContent)(buildErrorEnvelope(error));
|
|
30002
|
+
}
|
|
30003
|
+
});
|
|
28579
30004
|
}
|
|
28580
30005
|
|
|
28581
30006
|
|
|
@@ -29922,7 +31347,7 @@ function extractRiskyDocFieldOperations(securityRule) {
|
|
|
29922
31347
|
continue;
|
|
29923
31348
|
}
|
|
29924
31349
|
const referencesNonIdDocField = /doc\.(?!_id\b)[A-Za-z_][A-Za-z0-9_]*/.test(expression);
|
|
29925
|
-
const usesGetByDocId = /get\('database\.[^']+'\s*\+\s*doc\._id\)/.test(expression);
|
|
31350
|
+
const usesGetByDocId = /get\(('database\.[^']+'\s*\+\s*doc\._id|`database\.[^`]*\$\{\s*doc\._id\s*\})\)/.test(expression);
|
|
29926
31351
|
if (referencesNonIdDocField && !usesGetByDocId) {
|
|
29927
31352
|
operations.push(operation);
|
|
29928
31353
|
}
|
|
@@ -29932,8 +31357,8 @@ function extractRiskyDocFieldOperations(securityRule) {
|
|
|
29932
31357
|
function buildRecommendedOwnerWriteRule(resourceId) {
|
|
29933
31358
|
return JSON.stringify({
|
|
29934
31359
|
create: "auth.uid != null",
|
|
29935
|
-
update: "auth.uid != null && (get(
|
|
29936
|
-
delete: "auth.uid != null && (get(
|
|
31360
|
+
update: "auth.uid != null && (get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid)",
|
|
31361
|
+
delete: "auth.uid != null && (get(`database.user_roles.${auth.uid}`).role == 'admin' || doc.authorId == auth.uid)",
|
|
29937
31362
|
});
|
|
29938
31363
|
}
|
|
29939
31364
|
function buildRoleLookupNote() {
|
|
@@ -29995,7 +31420,9 @@ function buildInvalidGetPathHint(securityRule, resourceId) {
|
|
|
29995
31420
|
if (!securityRule) {
|
|
29996
31421
|
return undefined;
|
|
29997
31422
|
}
|
|
29998
|
-
|
|
31423
|
+
// get() 的 path 里嵌了字段名:拼接形态,或反引号模板里在 ${} 之后又接字段
|
|
31424
|
+
const hasFieldEmbeddedInsideGetPath = /get\('database\.[^']+'\s*\+\s*[^)]*\+\s*'\.[A-Za-z_][A-Za-z0-9_]*'\)/.test(securityRule) ||
|
|
31425
|
+
/get\(`database\.[^`]*\.\$\{[^}]+\}\.[A-Za-z_][A-Za-z0-9_]*`\)/.test(securityRule);
|
|
29999
31426
|
if (!hasFieldEmbeddedInsideGetPath) {
|
|
30000
31427
|
return undefined;
|
|
30001
31428
|
}
|
|
@@ -30015,7 +31442,9 @@ function buildTemplateLiteralRuleHint(securityRule, resourceId) {
|
|
|
30015
31442
|
if (!securityRule) {
|
|
30016
31443
|
return undefined;
|
|
30017
31444
|
}
|
|
30018
|
-
|
|
31445
|
+
// 反引号模板字符串是官方形态,必须先剥掉再判——否则会把正确的写法误报成错误
|
|
31446
|
+
const withoutTemplateLiterals = securityRule.replace(/`[^`]*`/g, '');
|
|
31447
|
+
const usesTemplateLiteralPlaceholderInRule = /['"][^'"]*\$\{(?:auth\.uid|doc\._id|doc\.[A-Za-z_][A-Za-z0-9_]*)\}/.test(withoutTemplateLiterals);
|
|
30019
31448
|
if (!usesTemplateLiteralPlaceholderInRule) {
|
|
30020
31449
|
return undefined;
|
|
30021
31450
|
}
|
|
@@ -31549,6 +32978,7 @@ const url_1 = __webpack_require__(6887);
|
|
|
31549
32978
|
const zod_1 = __webpack_require__(2971);
|
|
31550
32979
|
const index_js_1 = __webpack_require__(4908);
|
|
31551
32980
|
const remote_url_safety_js_1 = __webpack_require__(3694);
|
|
32981
|
+
const project_config_js_1 = __webpack_require__(9175);
|
|
31552
32982
|
// CloudBase 模板配置
|
|
31553
32983
|
const TEMPLATES = {
|
|
31554
32984
|
react: {
|
|
@@ -32034,6 +33464,23 @@ function registerSetupTools(server) {
|
|
|
32034
33464
|
};
|
|
32035
33465
|
}
|
|
32036
33466
|
const resolvedIDE = ideResolution.resolvedIDE;
|
|
33467
|
+
let workspaceFolder;
|
|
33468
|
+
try {
|
|
33469
|
+
workspaceFolder = (0, project_config_js_1.resolveProjectRoot)();
|
|
33470
|
+
}
|
|
33471
|
+
catch (error) {
|
|
33472
|
+
if (error instanceof project_config_js_1.ProjectRootError) {
|
|
33473
|
+
return {
|
|
33474
|
+
content: [
|
|
33475
|
+
{
|
|
33476
|
+
type: "text",
|
|
33477
|
+
text: (0, index_js_1.t)("setup.projectRoot.hostConfigDir", { dir: error.dir }),
|
|
33478
|
+
},
|
|
33479
|
+
],
|
|
33480
|
+
};
|
|
33481
|
+
}
|
|
33482
|
+
throw error;
|
|
33483
|
+
}
|
|
32037
33484
|
// 验证IDE类型
|
|
32038
33485
|
const ideValidation = validateIDE(resolvedIDE);
|
|
32039
33486
|
if (!ideValidation.valid) {
|
|
@@ -32071,7 +33518,6 @@ function registerSetupTools(server) {
|
|
|
32071
33518
|
// 创建过滤后的目录结构(当选择特定IDE时)
|
|
32072
33519
|
const workingDir = await createFilteredDirectory(extractDir, filteredFiles, resolvedIDE);
|
|
32073
33520
|
// 检查是否需要复制到项目目录
|
|
32074
|
-
const workspaceFolder = process.env.WORKSPACE_FOLDER_PATHS || process.cwd();
|
|
32075
33521
|
let finalFiles = [];
|
|
32076
33522
|
let createdCount = 0;
|
|
32077
33523
|
let overwrittenCount = 0;
|
|
@@ -33274,6 +34720,143 @@ function resolveRequestId(error) {
|
|
|
33274
34720
|
}
|
|
33275
34721
|
|
|
33276
34722
|
|
|
34723
|
+
/***/ },
|
|
34724
|
+
|
|
34725
|
+
/***/ 3379
|
|
34726
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
34727
|
+
|
|
34728
|
+
var __webpack_unused_export__;
|
|
34729
|
+
|
|
34730
|
+
/**
|
|
34731
|
+
* In-process log of tool outcomes for an explicitly requested feedback draft.
|
|
34732
|
+
*
|
|
34733
|
+
* Hosted gateways may construct a new server object per request. The log is
|
|
34734
|
+
* therefore keyed by a hash of the credential when one is present, and only
|
|
34735
|
+
* falls back to the server object when no credential is available. The cache
|
|
34736
|
+
* is bounded. Arguments are never stored, and the raw credential is not stored.
|
|
34737
|
+
*/
|
|
34738
|
+
__webpack_unused_export__ = ({ value: true });
|
|
34739
|
+
__webpack_unused_export__ = __webpack_unused_export__ = void 0;
|
|
34740
|
+
exports.recordToolOutcome = recordToolOutcome;
|
|
34741
|
+
exports.readToolOutcomes = readToolOutcomes;
|
|
34742
|
+
exports.noteRepeatCount = noteRepeatCount;
|
|
34743
|
+
exports.readRepeatPeak = readRepeatPeak;
|
|
34744
|
+
__webpack_unused_export__ = clearToolOutcomes;
|
|
34745
|
+
__webpack_unused_export__ = __resetFeedbackSessionsForTests;
|
|
34746
|
+
const node_crypto_1 = __webpack_require__(2561);
|
|
34747
|
+
const MAX_OUTCOMES = 200;
|
|
34748
|
+
const MAX_CREDENTIALS = 64;
|
|
34749
|
+
const MAX_TOOL_NAME_LENGTH = 80;
|
|
34750
|
+
const byCredential = new Map();
|
|
34751
|
+
const byServer = new WeakMap();
|
|
34752
|
+
function credentialKey(server) {
|
|
34753
|
+
const options = server.cloudBaseOptions;
|
|
34754
|
+
const secretId = typeof options?.secretId === "string" ? options.secretId.trim() : "";
|
|
34755
|
+
if (!secretId) {
|
|
34756
|
+
return undefined;
|
|
34757
|
+
}
|
|
34758
|
+
const token = typeof options?.token === "string" ? options.token.trim() : "";
|
|
34759
|
+
const site = typeof options?.site === "string" ? options.site.trim() : "";
|
|
34760
|
+
return (0, node_crypto_1.createHash)("sha256").update(`${site}\n${secretId}\n${token}`).digest("hex");
|
|
34761
|
+
}
|
|
34762
|
+
function emptyBucket() {
|
|
34763
|
+
return { outcomes: [], repeatPeak: 0, touchedAt: Date.now() };
|
|
34764
|
+
}
|
|
34765
|
+
function evictOldestCredential() {
|
|
34766
|
+
let oldestKey;
|
|
34767
|
+
let oldestTouched = Number.POSITIVE_INFINITY;
|
|
34768
|
+
for (const [key, bucket] of byCredential) {
|
|
34769
|
+
if (bucket.touchedAt < oldestTouched) {
|
|
34770
|
+
oldestTouched = bucket.touchedAt;
|
|
34771
|
+
oldestKey = key;
|
|
34772
|
+
}
|
|
34773
|
+
}
|
|
34774
|
+
if (oldestKey) {
|
|
34775
|
+
byCredential.delete(oldestKey);
|
|
34776
|
+
}
|
|
34777
|
+
}
|
|
34778
|
+
function bucketFor(server) {
|
|
34779
|
+
if (!server || typeof server !== "object") {
|
|
34780
|
+
return undefined;
|
|
34781
|
+
}
|
|
34782
|
+
const key = credentialKey(server);
|
|
34783
|
+
if (key) {
|
|
34784
|
+
let bucket = byCredential.get(key);
|
|
34785
|
+
if (!bucket) {
|
|
34786
|
+
if (byCredential.size >= MAX_CREDENTIALS) {
|
|
34787
|
+
evictOldestCredential();
|
|
34788
|
+
}
|
|
34789
|
+
bucket = emptyBucket();
|
|
34790
|
+
byCredential.set(key, bucket);
|
|
34791
|
+
}
|
|
34792
|
+
bucket.touchedAt = Date.now();
|
|
34793
|
+
return bucket;
|
|
34794
|
+
}
|
|
34795
|
+
let bucket = byServer.get(server);
|
|
34796
|
+
if (!bucket) {
|
|
34797
|
+
bucket = emptyBucket();
|
|
34798
|
+
byServer.set(server, bucket);
|
|
34799
|
+
}
|
|
34800
|
+
return bucket;
|
|
34801
|
+
}
|
|
34802
|
+
function recordToolOutcome(server, input) {
|
|
34803
|
+
const bucket = bucketFor(server);
|
|
34804
|
+
if (!bucket) {
|
|
34805
|
+
return;
|
|
34806
|
+
}
|
|
34807
|
+
const toolName = typeof input.toolName === "string" ? input.toolName.trim() : "";
|
|
34808
|
+
if (!toolName) {
|
|
34809
|
+
return;
|
|
34810
|
+
}
|
|
34811
|
+
const durationMs = Number.isFinite(input.durationMs) && input.durationMs >= 0
|
|
34812
|
+
? Math.round(input.durationMs)
|
|
34813
|
+
: 0;
|
|
34814
|
+
const at = typeof input.at === "string" && input.at.length > 0
|
|
34815
|
+
? input.at
|
|
34816
|
+
: new Date().toISOString();
|
|
34817
|
+
bucket.outcomes.push({
|
|
34818
|
+
toolName: toolName.slice(0, MAX_TOOL_NAME_LENGTH),
|
|
34819
|
+
durationMs,
|
|
34820
|
+
failed: input.failed === true,
|
|
34821
|
+
at,
|
|
34822
|
+
});
|
|
34823
|
+
if (bucket.outcomes.length > MAX_OUTCOMES) {
|
|
34824
|
+
bucket.outcomes.splice(0, bucket.outcomes.length - MAX_OUTCOMES);
|
|
34825
|
+
}
|
|
34826
|
+
}
|
|
34827
|
+
function readToolOutcomes(server) {
|
|
34828
|
+
return bucketFor(server)?.outcomes ?? [];
|
|
34829
|
+
}
|
|
34830
|
+
function noteRepeatCount(server, count) {
|
|
34831
|
+
const bucket = bucketFor(server);
|
|
34832
|
+
if (!bucket || !Number.isFinite(count) || count <= 0) {
|
|
34833
|
+
return;
|
|
34834
|
+
}
|
|
34835
|
+
const rounded = Math.round(count);
|
|
34836
|
+
if (rounded > bucket.repeatPeak) {
|
|
34837
|
+
bucket.repeatPeak = rounded;
|
|
34838
|
+
}
|
|
34839
|
+
}
|
|
34840
|
+
function readRepeatPeak(server) {
|
|
34841
|
+
return bucketFor(server)?.repeatPeak ?? 0;
|
|
34842
|
+
}
|
|
34843
|
+
function clearToolOutcomes(server) {
|
|
34844
|
+
const key = server && typeof server === "object" ? credentialKey(server) : undefined;
|
|
34845
|
+
if (key) {
|
|
34846
|
+
byCredential.delete(key);
|
|
34847
|
+
return;
|
|
34848
|
+
}
|
|
34849
|
+
if (server && typeof server === "object") {
|
|
34850
|
+
byServer.delete(server);
|
|
34851
|
+
}
|
|
34852
|
+
}
|
|
34853
|
+
function __resetFeedbackSessionsForTests() {
|
|
34854
|
+
byCredential.clear();
|
|
34855
|
+
}
|
|
34856
|
+
__webpack_unused_export__ = MAX_OUTCOMES;
|
|
34857
|
+
__webpack_unused_export__ = MAX_CREDENTIALS;
|
|
34858
|
+
|
|
34859
|
+
|
|
33277
34860
|
/***/ },
|
|
33278
34861
|
|
|
33279
34862
|
/***/ 4173
|
|
@@ -33738,14 +35321,101 @@ async function sendDeployNotification(server, notificationData) {
|
|
|
33738
35321
|
var __webpack_unused_export__;
|
|
33739
35322
|
|
|
33740
35323
|
__webpack_unused_export__ = ({ value: true });
|
|
35324
|
+
exports.ProjectRootError = void 0;
|
|
35325
|
+
exports.resolveProjectRoot = resolveProjectRoot;
|
|
35326
|
+
exports.requireProjectRoot = requireProjectRoot;
|
|
33741
35327
|
exports.readCloudbaseRcBinding = readCloudbaseRcBinding;
|
|
33742
35328
|
exports.readProjectConfig = readProjectConfig;
|
|
33743
35329
|
exports.readProjectEnvId = readProjectEnvId;
|
|
33744
35330
|
exports.writeProjectConfig = writeProjectConfig;
|
|
33745
35331
|
const node_fs_1 = __webpack_require__(9627);
|
|
35332
|
+
const node_os_1 = __webpack_require__(6674);
|
|
33746
35333
|
const node_path_1 = __webpack_require__(5663);
|
|
33747
35334
|
const toolbox_1 = __webpack_require__(2090);
|
|
35335
|
+
const index_js_1 = __webpack_require__(4908);
|
|
33748
35336
|
const CLOUDBASE_RC_FILENAME = "cloudbaserc.json";
|
|
35337
|
+
const PROJECT_ROOT_ENV_KEYS = [
|
|
35338
|
+
"WORKSPACE_FOLDER_PATHS",
|
|
35339
|
+
"PROJECT_ROOT",
|
|
35340
|
+
"GITHUB_WORKSPACE",
|
|
35341
|
+
"CI_PROJECT_DIR",
|
|
35342
|
+
"BUILD_SOURCESDIRECTORY",
|
|
35343
|
+
];
|
|
35344
|
+
/** Thrown when the resolved directory is a host config root, not a project. */
|
|
35345
|
+
class ProjectRootError extends Error {
|
|
35346
|
+
dir;
|
|
35347
|
+
constructor(dir) {
|
|
35348
|
+
super("setup.projectRoot.hostConfigDir");
|
|
35349
|
+
this.name = "ProjectRootError";
|
|
35350
|
+
this.dir = dir;
|
|
35351
|
+
}
|
|
35352
|
+
}
|
|
35353
|
+
exports.ProjectRootError = ProjectRootError;
|
|
35354
|
+
function firstPathSegment(value) {
|
|
35355
|
+
return value
|
|
35356
|
+
.split(node_path_1.delimiter)
|
|
35357
|
+
.map((segment) => segment.trim())
|
|
35358
|
+
.find((segment) => segment.length > 0);
|
|
35359
|
+
}
|
|
35360
|
+
function isUnderHostConfig(candidate) {
|
|
35361
|
+
const hostRoot = (0, node_path_1.resolve)((0, node_os_1.homedir)(), ".dsh");
|
|
35362
|
+
const resolved = (0, node_path_1.resolve)(candidate);
|
|
35363
|
+
const rel = (0, node_path_1.relative)(hostRoot, resolved);
|
|
35364
|
+
return rel === "" || (!rel.startsWith("..") && !(0, node_path_1.isAbsolute)(rel));
|
|
35365
|
+
}
|
|
35366
|
+
/**
|
|
35367
|
+
* Project directory for reads and writes.
|
|
35368
|
+
*
|
|
35369
|
+
* Explicit path, then host-injected workspace env vars, then process.cwd().
|
|
35370
|
+
* A result under ~/.dsh is refused so tools do not treat the host profile as a project.
|
|
35371
|
+
*/
|
|
35372
|
+
function resolveProjectRoot(explicit) {
|
|
35373
|
+
const trimmed = explicit?.trim();
|
|
35374
|
+
let chosen;
|
|
35375
|
+
if (trimmed) {
|
|
35376
|
+
chosen = (0, node_path_1.resolve)(trimmed);
|
|
35377
|
+
}
|
|
35378
|
+
else {
|
|
35379
|
+
let fromEnv;
|
|
35380
|
+
for (const key of PROJECT_ROOT_ENV_KEYS) {
|
|
35381
|
+
const raw = process.env[key];
|
|
35382
|
+
if (!raw?.trim())
|
|
35383
|
+
continue;
|
|
35384
|
+
const first = firstPathSegment(raw);
|
|
35385
|
+
if (first) {
|
|
35386
|
+
fromEnv = (0, node_path_1.resolve)(first);
|
|
35387
|
+
break;
|
|
35388
|
+
}
|
|
35389
|
+
}
|
|
35390
|
+
chosen = fromEnv ?? (0, node_path_1.resolve)(process.cwd());
|
|
35391
|
+
}
|
|
35392
|
+
if (isUnderHostConfig(chosen)) {
|
|
35393
|
+
throw new ProjectRootError(chosen);
|
|
35394
|
+
}
|
|
35395
|
+
return chosen;
|
|
35396
|
+
}
|
|
35397
|
+
/** Same as resolveProjectRoot, with the refusal already translated for tool output. */
|
|
35398
|
+
function requireProjectRoot(explicit) {
|
|
35399
|
+
try {
|
|
35400
|
+
return resolveProjectRoot(explicit);
|
|
35401
|
+
}
|
|
35402
|
+
catch (error) {
|
|
35403
|
+
if (error instanceof ProjectRootError) {
|
|
35404
|
+
throw new Error((0, index_js_1.t)("setup.projectRoot.hostConfigDir", { dir: error.dir }));
|
|
35405
|
+
}
|
|
35406
|
+
throw error;
|
|
35407
|
+
}
|
|
35408
|
+
}
|
|
35409
|
+
function projectRootForConfig(cwd) {
|
|
35410
|
+
try {
|
|
35411
|
+
return resolveProjectRoot(cwd);
|
|
35412
|
+
}
|
|
35413
|
+
catch (error) {
|
|
35414
|
+
if (error instanceof ProjectRootError)
|
|
35415
|
+
return undefined;
|
|
35416
|
+
throw error;
|
|
35417
|
+
}
|
|
35418
|
+
}
|
|
33749
35419
|
/**
|
|
33750
35420
|
* 解析 cloudbaserc.json 字段值用于绑定(fail-safe:解析不出一律返回 undefined 回落下一级):
|
|
33751
35421
|
* - 字面量 → trim 后直接返回
|
|
@@ -33803,7 +35473,9 @@ function resolveBindingValue(raw, projectRoot) {
|
|
|
33803
35473
|
*/
|
|
33804
35474
|
function readCloudbaseRcBinding(cwd) {
|
|
33805
35475
|
try {
|
|
33806
|
-
const projectRoot = cwd
|
|
35476
|
+
const projectRoot = projectRootForConfig(cwd);
|
|
35477
|
+
if (!projectRoot)
|
|
35478
|
+
return undefined;
|
|
33807
35479
|
const configPath = (0, node_path_1.join)(projectRoot, CLOUDBASE_RC_FILENAME);
|
|
33808
35480
|
if (!(0, node_fs_1.existsSync)(configPath)) {
|
|
33809
35481
|
return undefined;
|
|
@@ -33837,7 +35509,9 @@ function readCloudbaseRcBinding(cwd) {
|
|
|
33837
35509
|
*/
|
|
33838
35510
|
function readProjectConfig(cwd) {
|
|
33839
35511
|
try {
|
|
33840
|
-
const projectRoot = cwd
|
|
35512
|
+
const projectRoot = projectRootForConfig(cwd);
|
|
35513
|
+
if (!projectRoot)
|
|
35514
|
+
return undefined;
|
|
33841
35515
|
const configPath = (0, node_path_1.join)(projectRoot, ".cloudbase", "project.json");
|
|
33842
35516
|
if (!(0, node_fs_1.existsSync)(configPath)) {
|
|
33843
35517
|
return undefined;
|
|
@@ -33885,7 +35559,9 @@ function readProjectEnvId(cwd) {
|
|
|
33885
35559
|
*/
|
|
33886
35560
|
function writeProjectConfig(patch, cwd) {
|
|
33887
35561
|
try {
|
|
33888
|
-
const projectRoot = cwd
|
|
35562
|
+
const projectRoot = projectRootForConfig(cwd);
|
|
35563
|
+
if (!projectRoot)
|
|
35564
|
+
return false;
|
|
33889
35565
|
const configPath = (0, node_path_1.join)(projectRoot, ".cloudbase", "project.json");
|
|
33890
35566
|
let existing = {};
|
|
33891
35567
|
if ((0, node_fs_1.existsSync)(configPath)) {
|
|
@@ -34110,6 +35786,7 @@ var __webpack_unused_export__;
|
|
|
34110
35786
|
|
|
34111
35787
|
__webpack_unused_export__ = ({ value: true });
|
|
34112
35788
|
exports.iA = void 0;
|
|
35789
|
+
exports.getRepeatGuardSnapshot = getRepeatGuardSnapshot;
|
|
34113
35790
|
exports.applyRepeatGuardToPayload = applyRepeatGuardToPayload;
|
|
34114
35791
|
exports.resetRepeatGuard = resetRepeatGuard;
|
|
34115
35792
|
__webpack_unused_export__ = __resetRepeatGuardForTests;
|
|
@@ -34128,6 +35805,13 @@ exports.iA = 3;
|
|
|
34128
35805
|
const REPEAT_GUARD_KEY_MAX_LENGTH = 200;
|
|
34129
35806
|
let lastKey = null;
|
|
34130
35807
|
let consecutiveCount = 0;
|
|
35808
|
+
/**
|
|
35809
|
+
* Live streak only. Does not expose the dedup key: that key contains the raw
|
|
35810
|
+
* error message, which may include secrets or identifiers.
|
|
35811
|
+
*/
|
|
35812
|
+
function getRepeatGuardSnapshot() {
|
|
35813
|
+
return { consecutiveCount };
|
|
35814
|
+
}
|
|
34131
35815
|
function buildRepeatGuardKey(payload) {
|
|
34132
35816
|
const code = typeof payload.code === "string" ? payload.code : "";
|
|
34133
35817
|
const message = typeof payload.message === "string" ? payload.message : "";
|
|
@@ -34599,7 +36283,7 @@ class TelemetryReporter {
|
|
|
34599
36283
|
const arch = os_1.default.arch(); // 系统架构
|
|
34600
36284
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
34601
36285
|
const mcpVersion = process.env.npm_package_version ||
|
|
34602
|
-
( true ? "2.34.
|
|
36286
|
+
( true ? "2.34.8" : 0);
|
|
34603
36287
|
return {
|
|
34604
36288
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
34605
36289
|
deviceId: this.deviceId,
|
|
@@ -35105,7 +36789,7 @@ var __webpack_unused_export__;
|
|
|
35105
36789
|
__webpack_unused_export__ = ({ value: true });
|
|
35106
36790
|
exports.ToolPayloadError = void 0;
|
|
35107
36791
|
exports.buildJsonToolResult = buildJsonToolResult;
|
|
35108
|
-
|
|
36792
|
+
exports.isBusinessFailureToolResult = isBusinessFailureToolResult;
|
|
35109
36793
|
exports.withBusinessFailureIsError = withBusinessFailureIsError;
|
|
35110
36794
|
exports.buildTextErrorResult = buildTextErrorResult;
|
|
35111
36795
|
exports.isToolPayloadError = isToolPayloadError;
|
|
@@ -35246,6 +36930,7 @@ const logger_js_1 = __webpack_require__(781);
|
|
|
35246
36930
|
const telemetry_js_1 = __webpack_require__(5198);
|
|
35247
36931
|
const tool_result_js_1 = __webpack_require__(9645);
|
|
35248
36932
|
const repeat_error_guard_js_1 = __webpack_require__(13);
|
|
36933
|
+
const feedback_session_js_1 = __webpack_require__(3379);
|
|
35249
36934
|
const error_guidance_js_1 = __webpack_require__(1194);
|
|
35250
36935
|
/**
|
|
35251
36936
|
* Mirror annotations.category into _meta.category.
|
|
@@ -35321,7 +37006,7 @@ ${envIdSection}
|
|
|
35321
37006
|
## 环境信息
|
|
35322
37007
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
35323
37008
|
- Node.js版本: ${process.version}
|
|
35324
|
-
- MCP 版本:${( true ? "2.34.
|
|
37009
|
+
- MCP 版本:${( true ? "2.34.8" : 0) || 0 || 0}
|
|
35325
37010
|
- 系统架构: ${os_1.default.arch()}
|
|
35326
37011
|
- 时间: ${new Date().toISOString()}
|
|
35327
37012
|
- 请求ID: ${requestId}
|
|
@@ -35355,6 +37040,8 @@ function createWrappedHandler(name, handler, server) {
|
|
|
35355
37040
|
return async (args) => {
|
|
35356
37041
|
const startTime = Date.now();
|
|
35357
37042
|
let success = false;
|
|
37043
|
+
let businessFailed = false;
|
|
37044
|
+
let repeatCountSeen = 0;
|
|
35358
37045
|
let errorMessage;
|
|
35359
37046
|
let requestId;
|
|
35360
37047
|
try {
|
|
@@ -35366,7 +37053,11 @@ function createWrappedHandler(name, handler, server) {
|
|
|
35366
37053
|
}
|
|
35367
37054
|
// 执行原始处理函数
|
|
35368
37055
|
const result = await handler(args);
|
|
37056
|
+
// Returned { success: false } is a business failure for the local
|
|
37057
|
+
// session log. The telemetry flag below stays on the existing path.
|
|
37058
|
+
businessFailed = (0, tool_result_js_1.isBusinessFailureToolResult)(result);
|
|
35369
37059
|
success = true;
|
|
37060
|
+
repeatCountSeen = (0, repeat_error_guard_js_1.getRepeatGuardSnapshot)().consecutiveCount;
|
|
35370
37061
|
// 任一工具成功说明重复错误循环已被打破,清零连续错误计数
|
|
35371
37062
|
(0, repeat_error_guard_js_1.resetRepeatGuard)();
|
|
35372
37063
|
requestId = extractRequestIdFromToolResult(result);
|
|
@@ -35399,8 +37090,11 @@ function createWrappedHandler(name, handler, server) {
|
|
|
35399
37090
|
if ((0, tool_result_js_1.isToolPayloadError)(error)) {
|
|
35400
37091
|
// 连续相同结构化错误达到阈值时注入 repeat_guard 升级提示,
|
|
35401
37092
|
// 打断无头客户端的原样重试循环(不改写 message,保持遥测聚合稳定)
|
|
35402
|
-
|
|
37093
|
+
const payload = (0, repeat_error_guard_js_1.applyRepeatGuardToPayload)(error.payload);
|
|
37094
|
+
repeatCountSeen = (0, repeat_error_guard_js_1.getRepeatGuardSnapshot)().consecutiveCount;
|
|
37095
|
+
throw new tool_result_js_1.ToolPayloadError(payload);
|
|
35403
37096
|
}
|
|
37097
|
+
repeatCountSeen = (0, repeat_error_guard_js_1.getRepeatGuardSnapshot)().consecutiveCount;
|
|
35404
37098
|
// In tests, avoid any extra work that may block (envId lookup, issue link generation, etc.)
|
|
35405
37099
|
if (isTestEnvironment) {
|
|
35406
37100
|
throw error instanceof Error ? error : new Error(String(error));
|
|
@@ -35410,7 +37104,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
35410
37104
|
requestId,
|
|
35411
37105
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
35412
37106
|
});
|
|
35413
|
-
const mcpVersion = true ? "2.34.
|
|
37107
|
+
const mcpVersion = true ? "2.34.8" : 0;
|
|
35414
37108
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
35415
37109
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
35416
37110
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
|
@@ -35426,6 +37120,20 @@ function createWrappedHandler(name, handler, server) {
|
|
|
35426
37120
|
throw enhancedError;
|
|
35427
37121
|
}
|
|
35428
37122
|
finally {
|
|
37123
|
+
try {
|
|
37124
|
+
(0, feedback_session_js_1.noteRepeatCount)(server, repeatCountSeen);
|
|
37125
|
+
(0, feedback_session_js_1.recordToolOutcome)(server, {
|
|
37126
|
+
toolName: name,
|
|
37127
|
+
durationMs: Date.now() - startTime,
|
|
37128
|
+
failed: Boolean(errorMessage) || businessFailed,
|
|
37129
|
+
});
|
|
37130
|
+
}
|
|
37131
|
+
catch (recordError) {
|
|
37132
|
+
(0, logger_js_1.debug)("feedback session record failed", {
|
|
37133
|
+
toolName: name,
|
|
37134
|
+
error: recordError instanceof Error ? recordError.message : String(recordError),
|
|
37135
|
+
});
|
|
37136
|
+
}
|
|
35429
37137
|
// 上报工具调用数据(测试环境中跳过,避免阻塞)
|
|
35430
37138
|
const isTestEnvironment = false || process.env.VITEST === "true";
|
|
35431
37139
|
if (!isTestEnvironment) {
|
|
@@ -35693,7 +37401,7 @@ var x = (y) => {
|
|
|
35693
37401
|
var x = {}; __webpack_require__.d(x, y); return x
|
|
35694
37402
|
}
|
|
35695
37403
|
var y = (x) => (() => (x))
|
|
35696
|
-
module.exports = x({ ["randomUUID"]: () => (__WEBPACK_EXTERNAL_MODULE_node_crypto_803ecaf5__.randomUUID) });
|
|
37404
|
+
module.exports = x({ ["createHash"]: () => (__WEBPACK_EXTERNAL_MODULE_node_crypto_803ecaf5__.createHash), ["randomUUID"]: () => (__WEBPACK_EXTERNAL_MODULE_node_crypto_803ecaf5__.randomUUID) });
|
|
35697
37405
|
|
|
35698
37406
|
/***/ },
|
|
35699
37407
|
|
|
@@ -35704,6 +37412,17 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_node_fs_75ed2103__;
|
|
|
35704
37412
|
|
|
35705
37413
|
/***/ },
|
|
35706
37414
|
|
|
37415
|
+
/***/ 6674
|
|
37416
|
+
(module, __unused_webpack_exports, __webpack_require__) {
|
|
37417
|
+
|
|
37418
|
+
var x = (y) => {
|
|
37419
|
+
var x = {}; __webpack_require__.d(x, y); return x
|
|
37420
|
+
}
|
|
37421
|
+
var y = (x) => (() => (x))
|
|
37422
|
+
module.exports = x({ ["homedir"]: () => (__WEBPACK_EXTERNAL_MODULE_node_os_e12349cb__.homedir) });
|
|
37423
|
+
|
|
37424
|
+
/***/ },
|
|
37425
|
+
|
|
35707
37426
|
/***/ 5663
|
|
35708
37427
|
(module) {
|
|
35709
37428
|
|