@cloudbase/cloudbase-mcp 2.36.1 → 2.36.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -200596,7 +200596,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
200596
200596
  return (mod && mod.__esModule) ? mod : { "default": mod };
200597
200597
  };
200598
200598
  Object.defineProperty(exports, "__esModule", ({ value: true }));
200599
- exports.envManager = void 0;
200599
+ exports.envManager = exports.runInEnvSlot = void 0;
200600
200600
  exports.probeApiKeyCamCapability = probeApiKeyCamCapability;
200601
200601
  exports.fetchEnvOwnerUin = fetchEnvOwnerUin;
200602
200602
  exports.probeCamCapabilityForLogin = probeCamCapabilityForLogin;
@@ -200618,7 +200618,10 @@ const logger_js_1 = __webpack_require__(40781);
200618
200618
  const tool_result_js_1 = __webpack_require__(69645);
200619
200619
  const site_map_js_1 = __webpack_require__(34533);
200620
200620
  const project_config_js_1 = __webpack_require__(39175);
200621
+ const cloud_mode_js_1 = __webpack_require__(88694);
200622
+ const env_binding_js_1 = __webpack_require__(61498);
200621
200623
  const local_endpoint_js_1 = __webpack_require__(16156);
200624
+ const describe_envs_query_js_1 = __webpack_require__(31284);
200622
200625
  function toEnvCandidates(envList) {
200623
200626
  if (!Array.isArray(envList)) {
200624
200627
  return [];
@@ -200804,11 +200807,7 @@ async function listAvailableEnvCandidates(options) {
200804
200807
  try {
200805
200808
  const result = await cloudbase.commonService("tcb", "2018-06-08").call({
200806
200809
  Action: "DescribeEnvs",
200807
- Param: {
200808
- EnvTypes: ["weda", "baas"],
200809
- IsVisible: false,
200810
- Channels: ["dcloud", "iotenable", "tem", "scene_module"],
200811
- },
200810
+ Param: (0, describe_envs_query_js_1.buildDescribeEnvsFilter)(),
200812
200811
  });
200813
200812
  const envList = result?.EnvList || result?.Data?.EnvList || [];
200814
200813
  return toEnvCandidates(envList);
@@ -201026,6 +201025,7 @@ class EnvironmentManager {
201026
201025
  // 手动设置环境ID(用于外部调用)
201027
201026
  async setEnvId(envId) {
201028
201027
  this._setCachedEnvId(envId);
201028
+ (0, env_binding_js_1.noteEnvBinding)({ envId, source: "envManager.cachedEnvId" });
201029
201029
  (0, logger_js_1.debug)('手动设置环境ID并更新缓存:', { envId });
201030
201030
  }
201031
201031
  // Get cached envId without triggering fetch (for optimization)
@@ -201036,44 +201036,136 @@ class EnvironmentManager {
201036
201036
  // 全局实例
201037
201037
  const envManager = new EnvironmentManager();
201038
201038
  exports.envManager = envManager;
201039
- // 导出环境ID获取函数
201039
+ function requestHasCloudCredentials(cloudBaseOptions) {
201040
+ return Boolean((cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey) ||
201041
+ cloudBaseOptions?.requestFn);
201042
+ }
201043
+ function throwCloudModeEnvRequired(envCandidates) {
201044
+ const singleEnvId = envCandidates.length === 1 ? envCandidates[0].envId : undefined;
201045
+ (0, tool_result_js_1.throwToolPayloadError)({
201046
+ ok: false,
201047
+ code: "ENV_REQUIRED",
201048
+ message: "当前请求没有带 envId。Cloud mode 不读取本机登录态、项目配置或进程环境变量。",
201049
+ env_candidates: envCandidates,
201050
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("set_env", {
201051
+ requiredParams: singleEnvId ? undefined : ["envId"],
201052
+ suggestedArgs: singleEnvId
201053
+ ? { action: "set_env", envId: singleEnvId }
201054
+ : { action: "set_env" },
201055
+ }),
201056
+ });
201057
+ }
201058
+ /**
201059
+ * Cloud mode only sees this request. No envManager, no CLOUDBASE_ENV_ID, no project file, no auth.json.
201060
+ * A single environment is written back onto this request's options and is not cached on the process.
201061
+ */
201062
+ async function resolveCloudModeEnvId(cloudBaseOptions, requireEnvId) {
201063
+ if (cloudBaseOptions?.envId) {
201064
+ (0, env_binding_js_1.noteEnvBinding)({ envId: cloudBaseOptions.envId, source: "cloudBaseOptions" });
201065
+ return cloudBaseOptions.envId;
201066
+ }
201067
+ if (!requireEnvId) {
201068
+ return undefined;
201069
+ }
201070
+ if (!requestHasCloudCredentials(cloudBaseOptions)) {
201071
+ throwCloudModeEnvRequired([]);
201072
+ }
201073
+ const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
201074
+ if (envCandidates.length === 1) {
201075
+ const singleEnvId = envCandidates[0].envId;
201076
+ if (cloudBaseOptions) {
201077
+ cloudBaseOptions.envId = singleEnvId;
201078
+ }
201079
+ (0, env_binding_js_1.noteEnvBinding)({ envId: singleEnvId, source: "auto_bound" });
201080
+ return singleEnvId;
201081
+ }
201082
+ throwCloudModeEnvRequired(envCandidates);
201083
+ }
201084
+ async function getCloudBaseManagerCloudMode(options) {
201085
+ const requireEnvId = options.requireEnvId !== false;
201086
+ const cloudBaseOptions = options.cloudBaseOptions;
201087
+ if (!requestHasCloudCredentials(cloudBaseOptions)) {
201088
+ throwAuthRequiredError();
201089
+ }
201090
+ const resolvedEnvId = await resolveCloudModeEnvId(cloudBaseOptions, requireEnvId);
201091
+ return createCloudBaseManagerWithOptions({
201092
+ ...(cloudBaseOptions ?? {}),
201093
+ envId: resolvedEnvId,
201094
+ });
201095
+ }
201096
+ /**
201097
+ * Fresh slot for tests. Production stdio/hosted pass their own slot into `runWithEnvSlot`.
201098
+ * Re-exported from `env-binding.ts` so there is only one definition.
201099
+ */
201100
+ var env_binding_js_2 = __webpack_require__(61498);
201101
+ Object.defineProperty(exports, "runInEnvSlot", ({ enumerable: true, get: function () { return env_binding_js_2.runInEnvSlot; } }));
201040
201102
  async function getEnvId(cloudBaseOptions) {
201103
+ if ((0, cloud_mode_js_1.isCloudMode)()) {
201104
+ const envId = await resolveCloudModeEnvId(cloudBaseOptions, true);
201105
+ if (!envId) {
201106
+ throwCloudModeEnvRequired([]);
201107
+ }
201108
+ return envId;
201109
+ }
201110
+ return resolveEnvIdForCall(cloudBaseOptions);
201111
+ }
201112
+ async function resolveEnvIdForCall(cloudBaseOptions) {
201041
201113
  if (cloudBaseOptions?.envId) {
201042
201114
  (0, logger_js_1.debug)('使用传入的 envId:', { envId: cloudBaseOptions.envId });
201115
+ (0, env_binding_js_1.noteEnvBinding)({ envId: cloudBaseOptions.envId, source: "cloudBaseOptions" });
201043
201116
  return cloudBaseOptions.envId;
201044
201117
  }
201045
201118
  if ((0, local_endpoint_js_1.resolveLocalEndpoint)()) {
201046
201119
  return 'local';
201047
201120
  }
201048
- const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
201121
+ const cachedEnvId = envManager.getCachedEnvId();
201049
201122
  if (cachedEnvId) {
201050
201123
  (0, logger_js_1.debug)('使用缓存中的 envId:', { envId: cachedEnvId });
201124
+ (0, env_binding_js_1.noteEnvBinding)({ envId: cachedEnvId, source: "envManager.cachedEnvId" });
201051
201125
  return cachedEnvId;
201052
201126
  }
201053
- // 项目级配置固定的环境优先于账号级登录态,保证「打开仓库即连对环境」,
201054
- // 且同一仓库的每个 Git worktree / 每个新进程都不需要重复 set_env。
201127
+ if (process.env.CLOUDBASE_ENV_ID) {
201128
+ (0, logger_js_1.debug)('使用进程环境变量的 envId:', { envId: process.env.CLOUDBASE_ENV_ID });
201129
+ (0, env_binding_js_1.noteEnvBinding)({
201130
+ envId: process.env.CLOUDBASE_ENV_ID,
201131
+ source: "process.env.CLOUDBASE_ENV_ID",
201132
+ });
201133
+ return process.env.CLOUDBASE_ENV_ID;
201134
+ }
201135
+ // Project config stays ahead of the account login env, and still writes the cache.
201055
201136
  const projectEnvId = (0, project_config_js_1.readProjectEnvId)();
201056
201137
  if (projectEnvId) {
201057
201138
  (0, logger_js_1.debug)('使用项目配置(.cloudbase/project.json)的 envId:', { envId: projectEnvId });
201058
201139
  await envManager.setEnvId(projectEnvId);
201140
+ (0, env_binding_js_1.noteEnvBinding)({ envId: projectEnvId, source: "project" });
201059
201141
  return projectEnvId;
201060
201142
  }
201061
201143
  const loginState = await (0, auth_js_1.peekLoginState)();
201062
201144
  if (typeof loginState?.envId === 'string' && loginState.envId.length > 0) {
201063
201145
  (0, logger_js_1.debug)('使用登录态中的 envId:', { envId: loginState.envId });
201146
+ // Do not cache. A project file that appears later in this process must still win.
201147
+ (0, env_binding_js_1.noteEnvBinding)({ envId: loginState.envId, source: "login_state" });
201064
201148
  return loginState.envId;
201065
201149
  }
201066
- // 否则使用默认逻辑
201067
- return envManager.getEnvId();
201150
+ const envId = await envManager.getEnvId();
201151
+ (0, env_binding_js_1.noteEnvBinding)({ envId, source: "auto_bound" });
201152
+ return envId;
201068
201153
  }
201069
- // 导出函数保持兼容性
201070
201154
  function resetCloudBaseManagerCache() {
201071
201155
  envManager.reset();
201156
+ (0, env_binding_js_1.clearEnvBinding)();
201072
201157
  }
201073
201158
  // 导出获取缓存环境ID的函数,供遥测模块使用
201074
201159
  function getCachedEnvId() {
201075
201160
  return envManager.getCachedEnvId();
201076
201161
  }
201162
+ /**
201163
+ * 实例 ID 是环境关联的 PaaS 资源标识,正常情况下与 envId 同生命周期。
201164
+ * 但失效通知跨系统没有出口(invalidate 在生产路径上没有任何调用点),
201165
+ * 所以用一个长 TTL 兜底:宁可每半小时多查一次环境信息,
201166
+ * 也不要拿着一份没人能证明还正确的实例 ID 一直用下去。
201167
+ */
201168
+ const DATABASE_INSTANCE_ID_CACHE_TTL_MS = 30 * 60 * 1000;
201077
201169
  const databaseInstanceIdCache = new Map();
201078
201170
  function buildDatabaseInstanceIdCacheKey(options) {
201079
201171
  const envId = options?.envId ?? options?.cloudBaseOptions?.envId ?? process.env.CLOUDBASE_ENV_ID ?? 'unknown';
@@ -201104,11 +201196,16 @@ async function getDatabaseInstanceId(options) {
201104
201196
  });
201105
201197
  const cachedEntry = databaseInstanceIdCache.get(cacheKey);
201106
201198
  if (cachedEntry?.instanceId) {
201107
- return {
201108
- instanceId: cachedEntry.instanceId,
201109
- source: 'cache',
201110
- cacheKey,
201111
- };
201199
+ if (cachedEntry.expiresAt && cachedEntry.expiresAt <= Date.now()) {
201200
+ databaseInstanceIdCache.delete(cacheKey);
201201
+ }
201202
+ else {
201203
+ return {
201204
+ instanceId: cachedEntry.instanceId,
201205
+ source: 'cache',
201206
+ cacheKey,
201207
+ };
201208
+ }
201112
201209
  }
201113
201210
  if (cachedEntry?.inflightPromise) {
201114
201211
  const instanceId = await cachedEntry.inflightPromise;
@@ -201133,6 +201230,7 @@ async function getDatabaseInstanceId(options) {
201133
201230
  const instanceId = await inflightPromise;
201134
201231
  databaseInstanceIdCache.set(cacheKey, {
201135
201232
  instanceId,
201233
+ expiresAt: Date.now() + DATABASE_INSTANCE_ID_CACHE_TTL_MS,
201136
201234
  });
201137
201235
  return {
201138
201236
  instanceId,
@@ -201149,6 +201247,9 @@ async function getDatabaseInstanceId(options) {
201149
201247
  * 每次都实时获取最新的 token/secretId/secretKey
201150
201248
  */
201151
201249
  async function getCloudBaseManager(options = {}) {
201250
+ if ((0, cloud_mode_js_1.isCloudMode)()) {
201251
+ return getCloudBaseManagerCloudMode(options);
201252
+ }
201152
201253
  const { requireEnvId = true, authStrategy = 'fail_fast', } = options;
201153
201254
  let cloudBaseOptions = options.cloudBaseOptions;
201154
201255
  const localEndpoint = (0, local_endpoint_js_1.resolveLocalEndpoint)();
@@ -201164,12 +201265,14 @@ async function getCloudBaseManager(options = {}) {
201164
201265
  // 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
201165
201266
  if (cloudBaseOptions && (hasDirectCredentials || hasRequestFn)) {
201166
201267
  let resolvedEnvId = cloudBaseOptions.envId;
201268
+ let explicitSource = cloudBaseOptions.envId ? "cloudBaseOptions" : "default";
201167
201269
  if (requireEnvId && !resolvedEnvId) {
201168
201270
  const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
201169
201271
  if (envCandidates.length === 1) {
201170
201272
  const singleEnvId = envCandidates[0].envId;
201171
201273
  cloudBaseOptions.envId = singleEnvId;
201172
201274
  resolvedEnvId = singleEnvId;
201275
+ explicitSource = "auto_bound";
201173
201276
  (0, logger_js_1.debug)('自动绑定唯一环境(显式配置):', { envId: singleEnvId });
201174
201277
  }
201175
201278
  else if (authStrategy === 'fail_fast') {
@@ -201189,6 +201292,9 @@ async function getCloudBaseManager(options = {}) {
201189
201292
  }
201190
201293
  }
201191
201294
  (0, logger_js_1.debug)('使用传入的 CloudBase 配置');
201295
+ if (resolvedEnvId && explicitSource !== "default") {
201296
+ (0, env_binding_js_1.noteEnvBinding)({ envId: resolvedEnvId, source: explicitSource });
201297
+ }
201192
201298
  return createCloudBaseManagerWithOptions({
201193
201299
  ...cloudBaseOptions,
201194
201300
  envId: resolvedEnvId,
@@ -201210,27 +201316,33 @@ async function getCloudBaseManager(options = {}) {
201210
201316
  }
201211
201317
  const { envId: loginEnvId, secretId, secretKey, token } = loginState;
201212
201318
  let finalEnvId = cloudBaseOptions?.envId;
201319
+ let envSource = finalEnvId ? "cloudBaseOptions" : undefined;
201213
201320
  if (requireEnvId) {
201214
201321
  if (!finalEnvId) {
201215
- // Optimize: Check if envManager has cached envId first (fast path)
201216
- // If cached, use it directly; otherwise check loginEnvId before calling getEnvId()
201217
- // This avoids unnecessary async calls when we have a valid envId available
201218
- const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
201219
- const projectEnvId = cachedEnvId ? undefined : (0, project_config_js_1.readProjectEnvId)();
201322
+ const cachedEnvId = envManager.getCachedEnvId();
201323
+ const envFromProcess = process.env.CLOUDBASE_ENV_ID;
201324
+ const projectEnvId = (cachedEnvId || envFromProcess) ? undefined : (0, project_config_js_1.readProjectEnvId)();
201220
201325
  if (cachedEnvId) {
201221
201326
  (0, logger_js_1.debug)('使用 envManager 缓存的环境ID:', { cachedEnvId });
201222
201327
  finalEnvId = cachedEnvId;
201328
+ envSource = "envManager.cachedEnvId";
201329
+ }
201330
+ else if (envFromProcess) {
201331
+ (0, logger_js_1.debug)('使用进程环境变量的环境ID:', { envId: envFromProcess });
201332
+ finalEnvId = envFromProcess;
201333
+ envSource = "process.env.CLOUDBASE_ENV_ID";
201223
201334
  }
201224
201335
  else if (projectEnvId) {
201225
- // 项目级绑定优先于全局登录态 envId:后者可能来自另一个仓库
201336
+ // Project binding stays ahead of the account login env.
201226
201337
  (0, logger_js_1.debug)('使用项目配置(project.json/cloudbaserc.json)的环境ID:', { projectEnvId });
201227
201338
  await envManager.setEnvId(projectEnvId);
201228
201339
  finalEnvId = projectEnvId;
201340
+ envSource = "project";
201229
201341
  }
201230
201342
  else if (loginEnvId) {
201231
- // If no cache but loginState has envId, use it directly
201232
201343
  (0, logger_js_1.debug)('使用 loginState 中的环境ID:', { loginEnvId });
201233
201344
  finalEnvId = loginEnvId;
201345
+ envSource = "login_state";
201234
201346
  }
201235
201347
  else {
201236
201348
  if (authStrategy === 'fail_fast') {
@@ -201239,6 +201351,7 @@ async function getCloudBaseManager(options = {}) {
201239
201351
  const singleEnvId = envCandidates[0].envId;
201240
201352
  await envManager.setEnvId(singleEnvId);
201241
201353
  finalEnvId = singleEnvId;
201354
+ envSource = "auto_bound";
201242
201355
  (0, logger_js_1.debug)('自动绑定唯一环境:', { envId: singleEnvId });
201243
201356
  }
201244
201357
  else {
@@ -201246,14 +201359,19 @@ async function getCloudBaseManager(options = {}) {
201246
201359
  }
201247
201360
  }
201248
201361
  else {
201249
- // ensure 模式下也保持非交互:单环境自动绑定,多环境返回 ENV_REQUIRED
201250
201362
  finalEnvId = await envManager.getEnvId();
201363
+ envSource = "auto_bound";
201251
201364
  }
201252
201365
  }
201253
201366
  }
201254
201367
  }
201255
- // envId priority: explicit option > envManager cache > loginState.envId
201256
201368
  const resolvedEnvId = finalEnvId || loginEnvId;
201369
+ if (!envSource && resolvedEnvId && resolvedEnvId === loginEnvId) {
201370
+ envSource = "login_state";
201371
+ }
201372
+ if (resolvedEnvId && envSource) {
201373
+ (0, env_binding_js_1.noteEnvBinding)({ envId: resolvedEnvId, source: envSource });
201374
+ }
201257
201375
  // region 直接使用 fallbackRegion(resolveSiteAndRegion 统一解析)
201258
201376
  // 不再通过 DescribeEnvs 查询 region,以兼容 STS 临时密钥场景
201259
201377
  const region = fallbackRegion;
@@ -201984,6 +202102,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
201984
202102
  exports.handleHostedMcpRequest = handleHostedMcpRequest;
201985
202103
  const streamableHttp_js_1 = __webpack_require__(52827);
201986
202104
  const server_js_1 = __webpack_require__(46324);
202105
+ const env_binding_js_1 = __webpack_require__(61498);
201987
202106
  const feedback_session_js_1 = __webpack_require__(23379);
201988
202107
  const client_info_cache_js_1 = __webpack_require__(65454);
201989
202108
  function readInitializeClientInfo(body) {
@@ -202061,36 +202180,42 @@ async function handleHostedMcpRequest(input) {
202061
202180
  const closeBoth = () => {
202062
202181
  void Promise.allSettled([transport?.close(), server?.close()]);
202063
202182
  };
202183
+ const injectedEnvId = input.serverOptions.cloudBaseOptions?.envId;
202184
+ const requestSlot = {
202185
+ binding: injectedEnvId
202186
+ ? { envId: injectedEnvId, source: "cloudBaseOptions" }
202187
+ : null,
202188
+ };
202064
202189
  try {
202065
- server = await (0, server_js_1.createCloudBaseMcpServer)({
202066
- name: input.serverOptions.name,
202067
- version: input.serverOptions.version,
202068
- enableTelemetry: input.serverOptions.enableTelemetry,
202069
- cloudBaseOptions: input.serverOptions.cloudBaseOptions,
202070
- cloudMode: input.serverOptions.cloudMode ?? true,
202071
- ide: input.serverOptions.ide,
202072
- client: input.serverOptions.client,
202073
- clientInfo,
202074
- // 会话级遥测的身份来源:把**当前** transport 的 sessionId 交给 server(公开 getter)。
202075
- // 这里是无状态传输(本文件 `:165` `sessionIdGenerator: undefined`)⇒ 今天它恒为 undefined、
202076
- // 上报按"一个实例一个会话"计;将来若有状态化,sessionId 会自动出现在这里。
202077
- getSessionId: () => transport?.sessionId,
202078
- lang: input.serverOptions.lang,
202079
- pluginsEnabled: input.serverOptions.pluginsEnabled,
202080
- pluginsDisabled: input.serverOptions.pluginsDisabled,
202081
- });
202082
- input.logger?.({
202083
- type: "cloudbase-mcp-server-create",
202084
- timeCost: Date.now() - startedAt,
202085
- });
202086
- transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
202087
- sessionIdGenerator: undefined,
202088
- enableJsonResponse: true,
202190
+ await (0, env_binding_js_1.runWithEnvSlot)(requestSlot, async () => {
202191
+ server = await (0, server_js_1.createCloudBaseMcpServer)({
202192
+ name: input.serverOptions.name,
202193
+ version: input.serverOptions.version,
202194
+ enableTelemetry: input.serverOptions.enableTelemetry,
202195
+ cloudBaseOptions: input.serverOptions.cloudBaseOptions,
202196
+ cloudMode: input.serverOptions.cloudMode ?? true,
202197
+ ide: input.serverOptions.ide,
202198
+ client: input.serverOptions.client,
202199
+ clientInfo,
202200
+ // Session id comes from this transport. Stateless mode leaves it undefined.
202201
+ getSessionId: () => transport?.sessionId,
202202
+ lang: input.serverOptions.lang,
202203
+ pluginsEnabled: input.serverOptions.pluginsEnabled,
202204
+ pluginsDisabled: input.serverOptions.pluginsDisabled,
202205
+ });
202206
+ input.logger?.({
202207
+ type: "cloudbase-mcp-server-create",
202208
+ timeCost: Date.now() - startedAt,
202209
+ });
202210
+ transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
202211
+ sessionIdGenerator: undefined,
202212
+ enableJsonResponse: true,
202213
+ });
202214
+ input.res.on("close", closeBoth);
202215
+ input.req.on("aborted", closeBoth);
202216
+ await server.connect(transport);
202217
+ await transport.handleRequest(input.req, input.res, input.body);
202089
202218
  });
202090
- input.res.on("close", closeBoth);
202091
- input.req.on("aborted", closeBoth);
202092
- await server.connect(transport);
202093
- await transport.handleRequest(input.req, input.res, input.body);
202094
202219
  }
202095
202220
  catch (error) {
202096
202221
  await Promise.allSettled([transport?.close(), server?.close()]);
@@ -208260,7 +208385,7 @@ function localizeZodSchemaShape(shape, lang, seen = new WeakMap()) {
208260
208385
  "use strict";
208261
208386
 
208262
208387
  Object.defineProperty(exports, "__esModule", ({ value: true }));
208263
- exports.validateTimerCron = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.formatRuntimeList = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = exports.HOSTED_CLIENT_INFO_CACHE_TTL_MS = exports.HOSTED_CLIENT_INFO_CACHE_CAPACITY = exports.handleHostedMcpRequest = exports.warmupHostedResources = exports.RAW_IDE_FILE_MAPPINGS = exports.simplifyEnvList = exports.envManager = exports.createCloudBaseManagerWithOptions = exports.resetCloudBaseManagerCache = exports.getEnvId = exports.getCloudBaseManager = exports.shouldRegisterTool = exports.getCloudModeStatus = exports.enableCloudMode = exports.isCloudMode = exports.logout = exports.getLoginState = exports.warn = exports.error = exports.info = exports.reportToolCall = exports.reportToolkitLifecycle = exports.telemetryReporter = exports.StdioServerTransport = exports.getDefaultServer = exports.createCloudBaseMcpServer = void 0;
208388
+ exports.validateTimerCron = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.formatRuntimeList = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = exports.HOSTED_CLIENT_INFO_CACHE_TTL_MS = exports.HOSTED_CLIENT_INFO_CACHE_CAPACITY = exports.handleHostedMcpRequest = exports.warmupHostedResources = exports.RAW_IDE_FILE_MAPPINGS = exports.simplifyEnvList = exports.envManager = exports.createCloudBaseManagerWithOptions = exports.resetCloudBaseManagerCache = exports.getEnvId = exports.getCloudBaseManager = exports.runWithEnvSlot = exports.ENV_SOURCES = exports.shouldRegisterTool = exports.getCloudModeStatus = exports.enableCloudMode = exports.isCloudMode = exports.logout = exports.getLoginState = exports.warn = exports.error = exports.info = exports.reportToolCall = exports.reportToolkitLifecycle = exports.telemetryReporter = exports.StdioServerTransport = exports.getDefaultServer = exports.createCloudBaseMcpServer = void 0;
208264
208389
  // CloudBase MCP Server Library
208265
208390
  var server_js_1 = __webpack_require__(46324);
208266
208391
  Object.defineProperty(exports, "createCloudBaseMcpServer", ({ enumerable: true, get: function () { return server_js_1.createCloudBaseMcpServer; } }));
@@ -208280,6 +208405,13 @@ Object.defineProperty(exports, "isCloudMode", ({ enumerable: true, get: function
208280
208405
  Object.defineProperty(exports, "enableCloudMode", ({ enumerable: true, get: function () { return cloud_mode_js_1.enableCloudMode; } }));
208281
208406
  Object.defineProperty(exports, "getCloudModeStatus", ({ enumerable: true, get: function () { return cloud_mode_js_1.getCloudModeStatus; } }));
208282
208407
  Object.defineProperty(exports, "shouldRegisterTool", ({ enumerable: true, get: function () { return cloud_mode_js_1.shouldRegisterTool; } }));
208408
+ /**
208409
+ * 环境绑定槽。外部宿主(自己起 transport 的那种)要上报真实的 envId,
208410
+ * 就得在自己的一次 run 里跑 server 的消息处理,否则上报恒为 `default`。
208411
+ */
208412
+ var env_binding_js_1 = __webpack_require__(61498);
208413
+ Object.defineProperty(exports, "ENV_SOURCES", ({ enumerable: true, get: function () { return env_binding_js_1.ENV_SOURCES; } }));
208414
+ Object.defineProperty(exports, "runWithEnvSlot", ({ enumerable: true, get: function () { return env_binding_js_1.runWithEnvSlot; } }));
208283
208415
  var cloudbase_manager_js_1 = __webpack_require__(33109);
208284
208416
  Object.defineProperty(exports, "getCloudBaseManager", ({ enumerable: true, get: function () { return cloudbase_manager_js_1.getCloudBaseManager; } }));
208285
208417
  Object.defineProperty(exports, "getEnvId", ({ enumerable: true, get: function () { return cloudbase_manager_js_1.getEnvId; } }));
@@ -209416,7 +209548,7 @@ exports.buildEnvCreditsHtml = buildEnvCreditsHtml;
209416
209548
  exports.registerEnvCreditsResource = registerEnvCreditsResource;
209417
209549
  const mcp_js_1 = __webpack_require__(55375);
209418
209550
  const index_js_1 = __webpack_require__(24908);
209419
- const cloudbase_manager_js_1 = __webpack_require__(33109);
209551
+ const env_binding_js_1 = __webpack_require__(61498);
209420
209552
  const site_map_js_1 = __webpack_require__(34533);
209421
209553
  const logger_js_1 = __webpack_require__(40781);
209422
209554
  const telemetry_js_1 = __webpack_require__(5198);
@@ -209486,17 +209618,12 @@ function buildEnvCreditsConsoleUrl(key, envId, site) {
209486
209618
  return (0, site_map_js_1.getConsoleDevUrl)(envId ?? undefined, exports.ENV_CREDITS_ENV_LINK_HASH[key], site);
209487
209619
  }
209488
209620
  /**
209489
- * 从 server 实例派生静态兜底值。
209490
- *
209491
- * 环境 ID 的取值优先级(与 get-started 同口径,新增来源时同步两处):
209492
- * ① 本次工具结果携带(面板侧覆盖,见 EnvCreditsPayload)
209493
- * → ② `server.cloudBaseOptions.envId` / `process.env.CLOUDBASE_ENV_ID`
209494
- * → ③ 进程缓存 `getCachedEnvId()`
209495
- * → ④ 降级:不显示 ID
209496
- * hosted 是无状态的,进程缓存不可靠,因此 ③ 只是本地兜底;面板永远以工具结果为准。
209621
+ * Static fallback until a tool result arrives.
209622
+ * Explicit `cloudBaseOptions.envId` wins. Otherwise the current slot.
209623
+ * Does not read `CLOUDBASE_ENV_ID` or the process cache.
209497
209624
  */
209498
209625
  function resolveEnvCreditsFallback(server) {
209499
- const envId = server.cloudBaseOptions?.envId || process.env.CLOUDBASE_ENV_ID || (0, cloudbase_manager_js_1.getCachedEnvId)() || null;
209626
+ const envId = (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId);
209500
209627
  const { site, region } = (0, site_map_js_1.resolveSiteAndRegion)({
209501
209628
  site: server.cloudBaseOptions?.site,
209502
209629
  region: server.cloudBaseOptions?.region,
@@ -210657,7 +210784,7 @@ exports.registerGetStartedResource = registerGetStartedResource;
210657
210784
  * 注入;`t()` 在 read 回调里求值,晚于 `setInstanceLang`,英文实例自动出英文。
210658
210785
  * 注入分两路:HTML 文本走 `escapeHtml`,脚本里的字符串走 `jsLiteral`(JSON 转义 +
210659
210786
  * 转义 `<`,避免 `</script>` 截断)。
210660
- * 3. **只读无密钥**:状态值只来自 `server.cloudBaseOptions` / 环境变量 / 缓存 / 站点解析,
210787
+ * 3. **只读无密钥**:环境 ID 来自这次调用槽;槽是空的才用 `server.cloudBaseOptions.envId`。不读环境变量和缓存。站点仍走站点解析。
210661
210788
  * 读资源时不发网络请求;面板自己只会发两类调用——只读的
210662
210789
  * `auth(action:"status")`(「重新检查」)和只改本地绑定的
210663
210790
  * `auth(action:"set_env")`(点「可选环境」里的一行)。两者都不动云端资源,也不碰密钥。
@@ -210678,7 +210805,7 @@ exports.registerGetStartedResource = registerGetStartedResource;
210678
210805
  */
210679
210806
  const mcp_js_1 = __webpack_require__(55375);
210680
210807
  const index_js_1 = __webpack_require__(24908);
210681
- const cloudbase_manager_js_1 = __webpack_require__(33109);
210808
+ const env_binding_js_1 = __webpack_require__(61498);
210682
210809
  const site_map_js_1 = __webpack_require__(34533);
210683
210810
  const logger_js_1 = __webpack_require__(40781);
210684
210811
  const telemetry_js_1 = __webpack_require__(5198);
@@ -210722,12 +210849,9 @@ function escapeHtml(value) {
210722
210849
  function jsLiteral(value) {
210723
210850
  return JSON.stringify(value).replace(/</g, "\\u003c");
210724
210851
  }
210725
- /** 从 server 实例派生静态兜底状态;只读本地状态,不发起任何请求。 */
210852
+ /** Static fallback for the panel. Reads the current slot, then this server's explicit envId. No network. */
210726
210853
  function resolveGetStartedStatus(server) {
210727
- const envId = server.cloudBaseOptions?.envId ||
210728
- process.env.CLOUDBASE_ENV_ID ||
210729
- (0, cloudbase_manager_js_1.getCachedEnvId)() ||
210730
- null;
210854
+ const envId = (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId);
210731
210855
  const { site, region } = (0, site_map_js_1.resolveSiteAndRegion)({
210732
210856
  site: server.cloudBaseOptions?.site,
210733
210857
  region: server.cloudBaseOptions?.region,
@@ -211736,6 +211860,7 @@ const index_js_1 = __webpack_require__(24908);
211736
211860
  const schema_js_1 = __webpack_require__(56273);
211737
211861
  const server_instructions_js_1 = __webpack_require__(81808);
211738
211862
  const cloud_mode_js_1 = __webpack_require__(88694);
211863
+ const env_binding_js_1 = __webpack_require__(61498);
211739
211864
  const logger_js_1 = __webpack_require__(40781);
211740
211865
  const site_map_js_1 = __webpack_require__(34533);
211741
211866
  const tool_result_js_1 = __webpack_require__(69645);
@@ -211924,6 +212049,8 @@ async function createCloudBaseMcpServer(options) {
211924
212049
  });
211925
212050
  // 初始化 toolDefs,用于外部提取工具列表(如微信 IDE)
211926
212051
  server.toolDefs = [];
212052
+ const envSlot = { binding: null };
212053
+ server.envSlot = envSlot;
211927
212054
  // 实例语言解析(须在工具注册前完成:registerTool 包装层按 lang 解析词典 key 形式的 description)
211928
212055
  server.lang = instanceLang;
211929
212056
  // 同步到 i18n 模块级 instanceLang:否则 t() 无 langOverride 时会退化成
@@ -212081,6 +212208,23 @@ async function createCloudBaseMcpServer(options) {
212081
212208
  // 产物卡片:挂在三个部署类工具上,只读展示部署状态与访问地址,写意图一律交给会话。
212082
212209
  (0, artifact_card_js_1.registerArtifactCardResource)(server);
212083
212210
  }
212211
+ const originalConnect = server.connect.bind(server);
212212
+ server.connect = async (transport) => {
212213
+ await originalConnect(transport);
212214
+ const deliver = transport.onmessage;
212215
+ if (!deliver) {
212216
+ return;
212217
+ }
212218
+ transport.onmessage = (message, extra) => {
212219
+ if ((0, env_binding_js_1.hasEnvSlot)()) {
212220
+ deliver(message, extra);
212221
+ return;
212222
+ }
212223
+ (0, env_binding_js_1.runWithEnvSlot)(envSlot, () => {
212224
+ deliver(message, extra);
212225
+ });
212226
+ };
212227
+ };
212084
212228
  return server;
212085
212229
  }
212086
212230
  /**
@@ -224121,6 +224265,7 @@ function buildEnvMetricsPayload(input) {
224121
224265
  * - Error handling and telemetry reporting
224122
224266
  */
224123
224267
  Object.defineProperty(exports, "__esModule", ({ value: true }));
224268
+ exports.TCB_PURCHASE_URL = void 0;
224124
224269
  exports.checkAndInitTcbService = checkAndInitTcbService;
224125
224270
  exports.checkAndCreateFreeEnv = checkAndCreateFreeEnv;
224126
224271
  exports.getUinForTelemetry = getUinForTelemetry;
@@ -224128,6 +224273,17 @@ const auth_js_1 = __webpack_require__(561);
224128
224273
  const index_js_1 = __webpack_require__(24908);
224129
224274
  const logger_js_1 = __webpack_require__(40781);
224130
224275
  const telemetry_js_1 = __webpack_require__(5198);
224276
+ /**
224277
+ * 开通 CloudBase 环境的购买页。
224278
+ *
224279
+ * ⚠️ 别再写回 `/lowcode?buyType=tcb&channel=mcp`:那条路径现在 302 到 `/CloudBase`,
224280
+ * **重定向时把 query 全丢了**(实测 `location: https://buy.cloud.tencent.com/CloudBase`),
224281
+ * 用户会落到购买页首页、来源标记也一起丢。
224282
+ *
224283
+ * ⚠️ `region` / `sqlType` 是写死的:国内站默认 ap-shanghai + PG 版。国际站
224284
+ * (`buy.tencentcloud.com`)的域名与路径同构性未验证,见 `specs/site-domain-governance`。
224285
+ */
224286
+ exports.TCB_PURCHASE_URL = "https://buy.cloud.tencent.com/CloudBase?buyType=tcb&region=ap-shanghai&sqlType=pg";
224131
224287
  /**
224132
224288
  * Parse InitTcb error and extract user-friendly information
224133
224289
  */
@@ -224150,7 +224306,7 @@ function parseInitTcbError(err) {
224150
224306
  const errorInfo = {
224151
224307
  code: errorCode,
224152
224308
  message: friendlyMessage,
224153
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp",
224309
+ helpUrl: exports.TCB_PURCHASE_URL,
224154
224310
  actionText,
224155
224311
  requestId
224156
224312
  };
@@ -224386,7 +224542,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
224386
224542
  newContext.createEnvError = {
224387
224543
  code: "NoPromotionalActivity",
224388
224544
  message: (0, index_js_1.t)("envSetup.noPromotionalActivity"),
224389
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp"
224545
+ helpUrl: exports.TCB_PURCHASE_URL
224390
224546
  };
224391
224547
  return {
224392
224548
  success: false,
@@ -224452,7 +224608,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
224452
224608
  newContext.createEnvError = {
224453
224609
  code: "InvalidEnvId",
224454
224610
  message: (0, index_js_1.t)("envSetup.invalidEnvId"),
224455
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp"
224611
+ helpUrl: exports.TCB_PURCHASE_URL
224456
224612
  };
224457
224613
  return {
224458
224614
  success: false,
@@ -224513,7 +224669,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
224513
224669
  newContext.createEnvError = {
224514
224670
  code: createErr.code || createErr.Code || "UnknownError",
224515
224671
  message: errorMessage,
224516
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp"
224672
+ helpUrl: exports.TCB_PURCHASE_URL
224517
224673
  };
224518
224674
  (0, logger_js_1.debug)('[env-setup] CreateFreeEnvByActivity failed:', {
224519
224675
  code: newContext.createEnvError.code,
@@ -224613,12 +224769,14 @@ const cloudbase_manager_js_1 = __webpack_require__(33109);
224613
224769
  const logger_js_1 = __webpack_require__(40781);
224614
224770
  const site_map_js_1 = __webpack_require__(34533);
224615
224771
  const project_config_js_1 = __webpack_require__(39175);
224772
+ const describe_envs_query_js_1 = __webpack_require__(31284);
224616
224773
  const index_js_1 = __webpack_require__(24908);
224617
224774
  const tool_result_js_1 = __webpack_require__(69645);
224618
224775
  const gateway_access_urls_js_1 = __webpack_require__(84173);
224619
224776
  const env_setup_js_1 = __webpack_require__(27528);
224620
224777
  const env_credits_payload_js_1 = __webpack_require__(63880);
224621
224778
  const mcp_ui_js_1 = __webpack_require__(55880);
224779
+ const env_setup_js_2 = __webpack_require__(27528);
224622
224780
  /**
224623
224781
  * Resources accepted by CreateEnv. Matches Cloud API / Manager SDK contract.
224624
224782
  * `postgresql` enables CloudBase PostgreSQL (PG mode) when supported by the package.
@@ -225407,7 +225565,7 @@ async function prepareAuthEnvironment(params) {
225407
225565
  reason: "tcb_init_failed",
225408
225566
  errorCode: "TCB_INIT_FAILED",
225409
225567
  message: (0, index_js_1.t)("env.prepare.tcbInitFailed"),
225410
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp",
225568
+ helpUrl: env_setup_js_2.TCB_PURCHASE_URL,
225411
225569
  });
225412
225570
  return {
225413
225571
  currentEnvId: null,
@@ -225460,7 +225618,7 @@ async function prepareAuthEnvironment(params) {
225460
225618
  reason: "env_creation_failed",
225461
225619
  errorCode: "ENV_CREATION_FAILED",
225462
225620
  message: (0, index_js_1.t)("env.prepare.envCreateFailed"),
225463
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp",
225621
+ helpUrl: env_setup_js_2.TCB_PURCHASE_URL,
225464
225622
  });
225465
225623
  const failureMessage = userNotice
225466
225624
  ? `${userNotice}\n${createFailure.message}`
@@ -227140,11 +227298,8 @@ function registerEnvTools(server) {
227140
227298
  // Filter parameters match the reference conditions provided by user
227141
227299
  result = await cloudbaseList.commonService("tcb", "2018-06-08").call({
227142
227300
  Action: "DescribeEnvs",
227143
- Param: {
227144
- EnvTypes: ["weda", "baas"], // Include weda and baas (normal) environments
227145
- IsVisible: false, // Filter out invisible environments
227146
- Channels: ["dcloud", "iotenable", "tem", "scene_module"], // Filter special channels
227147
- },
227301
+ // 过滤口径与 cloudbase-manager 共用一份,别在这里另写白名单
227302
+ Param: (0, describe_envs_query_js_1.buildDescribeEnvsFilter)(),
227148
227303
  });
227149
227304
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
227150
227305
  // Transform response format to match original listEnvs() format
@@ -240437,7 +240592,7 @@ exports.readSkipList = readSkipList;
240437
240592
  exports.isSkipped = isSkipped;
240438
240593
  exports.readAutoApprovePolicy = readAutoApprovePolicy;
240439
240594
  exports.guardDestructiveAction = guardDestructiveAction;
240440
- const cloudbase_manager_js_1 = __webpack_require__(33109);
240595
+ const env_binding_js_1 = __webpack_require__(61498);
240441
240596
  const index_js_1 = __webpack_require__(24908);
240442
240597
  const elicitation_js_1 = __webpack_require__(65048);
240443
240598
  const destructive_actions_js_1 = __webpack_require__(72827);
@@ -240506,16 +240661,7 @@ function readAutoApprovePolicy() {
240506
240661
  return "allow";
240507
240662
  }
240508
240663
  function resolveEnvId(server) {
240509
- const fromOptions = server.cloudBaseOptions?.envId;
240510
- if (typeof fromOptions === "string" && fromOptions.length > 0) {
240511
- return fromOptions;
240512
- }
240513
- try {
240514
- return (0, cloudbase_manager_js_1.getCachedEnvId)() ?? (0, index_js_1.t)("confirmation.message.unknownEnv");
240515
- }
240516
- catch {
240517
- return (0, index_js_1.t)("confirmation.message.unknownEnv");
240518
- }
240664
+ return (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId) ?? (0, index_js_1.t)("confirmation.message.unknownEnv");
240519
240665
  }
240520
240666
  function blockedText(status, actionKey, targetInfo, params) {
240521
240667
  const keyByStatus = {
@@ -240883,6 +241029,47 @@ async function guardCredentialWrite(server, params) {
240883
241029
  }
240884
241030
 
240885
241031
 
241032
+ /***/ },
241033
+
241034
+ /***/ 31284
241035
+ (__unused_webpack_module, exports) {
241036
+
241037
+ "use strict";
241038
+
241039
+ /**
241040
+ * 账号级 DescribeEnvs 的查询口径 —— 唯一真源。
241041
+ *
241042
+ * EnvTypes 是白名单语义(不为空时以该字段为准):少写一个值不会报错,只会静默
241043
+ * 少一类环境。2026-10 的客户案例就是这样:平台侧代建的环境 EnvType=platform,
241044
+ * 控制台能列、MCP 拉不到,用户看到的是「请先创建环境」,现场没有任何错误可看。
241045
+ *
241046
+ * - baas / weda:标准云开发、微搭,MCP 工具主要面向这两类
241047
+ * - platform:平台侧代建的环境(site-* 一类),控制台列这类
241048
+ *
241049
+ * 未纳入 hosting / run(云托管)、tcbgw、paas:MCP 历史上就没列过,加进来会让
241050
+ * 用户在环境候选里看到一堆用不了的托管环境。授权页那份白名单多一个 hosting,
241051
+ * 是历史原因,两边差异是有意的。
241052
+ */
241053
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
241054
+ exports.DESCRIBE_ENVS_EXCLUDED_CHANNELS = exports.DESCRIBE_ENVS_ENV_TYPES = void 0;
241055
+ exports.buildDescribeEnvsFilter = buildDescribeEnvsFilter;
241056
+ /** 允许出现在环境候选列表里的 EnvType */
241057
+ exports.DESCRIBE_ENVS_ENV_TYPES = ["baas", "weda", "platform"];
241058
+ /**
241059
+ * IsVisible=false 表示 Channels 是「排除列表」:
241060
+ * 这 4 个渠道创建的环境不参与环境候选,其余渠道(含控制台的 qc_console)正常返回。
241061
+ */
241062
+ exports.DESCRIBE_ENVS_EXCLUDED_CHANNELS = ["dcloud", "iotenable", "tem", "scene_module"];
241063
+ /** 生成 DescribeEnvs 的 Param 过滤段;每次返回新数组,避免调用方改到共享常量 */
241064
+ function buildDescribeEnvsFilter() {
241065
+ return {
241066
+ EnvTypes: [...exports.DESCRIBE_ENVS_ENV_TYPES],
241067
+ IsVisible: false,
241068
+ Channels: [...exports.DESCRIBE_ENVS_EXCLUDED_CHANNELS],
241069
+ };
241070
+ }
241071
+
241072
+
240886
241073
  /***/ },
240887
241074
 
240888
241075
  /***/ 72827
@@ -241233,6 +241420,213 @@ function resolveDestructiveAction(toolName, args) {
241233
241420
  }
241234
241421
 
241235
241422
 
241423
+ /***/ },
241424
+
241425
+ /***/ 36953
241426
+ (__unused_webpack_module, exports, __webpack_require__) {
241427
+
241428
+ "use strict";
241429
+
241430
+ var __importDefault = (this && this.__importDefault) || function (mod) {
241431
+ return (mod && mod.__esModule) ? mod : { "default": mod };
241432
+ };
241433
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
241434
+ exports.readSystemAnchor = readSystemAnchor;
241435
+ exports.physicalMacAddresses = physicalMacAddresses;
241436
+ exports.collectHostSignal = collectHostSignal;
241437
+ exports.computeDeviceId = computeDeviceId;
241438
+ const crypto_1 = __importDefault(__webpack_require__(55511));
241439
+ const child_process_1 = __webpack_require__(79646);
241440
+ const fs_1 = __importDefault(__webpack_require__(29021));
241441
+ const os_1 = __importDefault(__webpack_require__(21820));
241442
+ /**
241443
+ * 匿名设备指纹。
241444
+ *
241445
+ * 为什么要有这个文件:旧实现是 `sha256(hostname | CPU model | 全部非内部网卡 MAC)`,
241446
+ * 锚点选错了 —— macOS 开着「私有 Wi-Fi 地址」时每个 SSID 一个随机 MAC,`awdl0` / `llw0` /
241447
+ * `bridge0` 的 MAC 随系统状态漂移,容器里 hostname 和 MAC 每次重建都变。结果是同一台 Mac
241448
+ * 一天能上报成几十个「设备」(2026-10-26 实测:Mac 指纹 82% 只在那一天出现过,
241449
+ * Windows 同口径 22%)。
241450
+ *
241451
+ * 现在的取值顺序:
241452
+ * 1. 系统级不可变标识 —— macOS `IOPlatformUUID`、Windows `MachineGuid`、Linux `/etc/machine-id`;
241453
+ * 2. 取不到时退到 `hostname + CPU model + 过滤后的物理网卡 MAC`;
241454
+ * 3. 再取不到只留 `hostname + CPU model`。
241455
+ *
241456
+ * 三条纪律:
241457
+ * - **格式不变**:仍是 SHA256 前 32 位 hex,灯塔 `A2` 字段与后端都不用改。
241458
+ * - **绝不用随机数兜底**。旧实现取不到信息时 `crypto.randomBytes(16)`,等于每次启动都是
241459
+ * 一台新设备 —— 正是要消灭的行为。宁可所有机器共用一个弱指纹,也不要一堆假设备。
241460
+ * - **只在构造时跑一次**。锚点要起子进程(`ioreg` / `reg`),1s 超时就降级,
241461
+ * 绝不放进每次上报的路径。
241462
+ *
241463
+ * 口径变化(换锚点当天就会看到,报表侧要提前打招呼):
241464
+ * - 历史 `A2` 全部失效,老设备会以新指纹重新出现 —— 报表上「装机量跳一下」不是增长。
241465
+ * - 容器内多实例若共享镜像固化的 `/etc/machine-id`,会被合并成同一台设备(以前是各算一个新设备)。
241466
+ */
241467
+ /** 取系统级锚点的子进程超时:超了直接降级,不能拖慢进程启动 */
241468
+ const ANCHOR_TIMEOUT_MS = 1000;
241469
+ /**
241470
+ * 虚拟 / 隧道网卡名前缀(小写比较)。这些接口的 MAC 会随系统状态漂移或每次重建都变,
241471
+ * 拼进指纹就等于给同一台机器发新身份。
241472
+ */
241473
+ const VIRTUAL_NIC_PREFIXES = [
241474
+ 'awdl', // Apple Wireless Direct Link
241475
+ 'llw', // Apple 低延迟 WLAN
241476
+ 'bridge', // macOS / Windows 网桥
241477
+ 'utun', // macOS / iOS VPN 隧道
241478
+ 'tun',
241479
+ 'tap',
241480
+ 'veth', // 容器 veth pair
241481
+ 'docker',
241482
+ 'br-', // docker bridge
241483
+ 'vmnet', // VMware
241484
+ 'vboxnet', // VirtualBox
241485
+ 'vether', // Hyper-V 虚拟交换机(vEthernet)
241486
+ 'zt', // ZeroTier
241487
+ 'tailscale',
241488
+ 'wg', // WireGuard
241489
+ 'lo', // loopback(正常情况下 internal 已过滤,兜一层)
241490
+ ];
241491
+ function sha256Short(input) {
241492
+ return crypto_1.default.createHash('sha256').update(input).digest('hex').substring(0, 32);
241493
+ }
241494
+ /** `machine-id` 合法值:16–64 位 hex,且不能是全 0(有些镜像里就是全 0 的空壳) */
241495
+ function isUsableMachineId(value) {
241496
+ if (!/^[0-9a-f]{16,64}$/i.test(value)) {
241497
+ return false;
241498
+ }
241499
+ return !/^0+$/.test(value);
241500
+ }
241501
+ function readFileQuietly(filePath) {
241502
+ try {
241503
+ return fs_1.default.readFileSync(filePath, 'utf8').trim();
241504
+ }
241505
+ catch {
241506
+ return undefined;
241507
+ }
241508
+ }
241509
+ /** 起一次子进程读锚点。超时 / 不存在 / 权限不足一律返回 undefined,由调用方降级。 */
241510
+ function execQuietly(file, args) {
241511
+ try {
241512
+ return (0, child_process_1.execFileSync)(file, args, {
241513
+ timeout: ANCHOR_TIMEOUT_MS,
241514
+ encoding: 'utf8',
241515
+ // 子进程的 stderr 全部吞掉:`ioreg` 在受限环境会打噪音,`reg` 在 32 位 Node
241516
+ // 下可能报找不到键,这些都不该出现在 MCP 的 stdout(stdio transport 上是协议流)
241517
+ stdio: ['ignore', 'pipe', 'ignore'],
241518
+ windowsHide: true,
241519
+ });
241520
+ }
241521
+ catch {
241522
+ return undefined;
241523
+ }
241524
+ }
241525
+ /**
241526
+ * 读系统级不可变标识。**只读一次**,失败即降级。
241527
+ * `platform` 参数只为测试注入,正常运行不传。
241528
+ */
241529
+ function readSystemAnchor(platform = process.platform) {
241530
+ if (platform === 'darwin') {
241531
+ const out = execQuietly('ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice']);
241532
+ const matched = out && /"IOPlatformUUID"\s*=\s*"([^"]+)"/.exec(out);
241533
+ if (matched?.[1]) {
241534
+ return { value: matched[1].trim(), source: 'platform-uuid' };
241535
+ }
241536
+ return undefined;
241537
+ }
241538
+ if (platform === 'win32') {
241539
+ const out = execQuietly('reg', [
241540
+ 'query',
241541
+ 'HKLM\\SOFTWARE\\Microsoft\\Cryptography',
241542
+ '/v',
241543
+ 'MachineGuid',
241544
+ ]);
241545
+ // 形如:` MachineGuid REG_SZ 3f2a....`(分隔符是多个空格或 tab)
241546
+ const matched = out && /MachineGuid\s+REG_SZ\s+([0-9a-fA-F-]{8,})/.exec(out);
241547
+ if (matched?.[1]) {
241548
+ return { value: matched[1].trim().toLowerCase(), source: 'machine-guid' };
241549
+ }
241550
+ return undefined;
241551
+ }
241552
+ // linux / openharmony / 其他类 Unix:先 /etc/machine-id,再 dbus 那份
241553
+ for (const candidate of ['/etc/machine-id', '/var/lib/dbus/machine-id']) {
241554
+ const raw = readFileQuietly(candidate);
241555
+ if (raw && isUsableMachineId(raw)) {
241556
+ return { value: raw.toLowerCase(), source: 'machine-id' };
241557
+ }
241558
+ }
241559
+ return undefined;
241560
+ }
241561
+ function isVirtualNic(name) {
241562
+ const lower = name.toLowerCase();
241563
+ return VIRTUAL_NIC_PREFIXES.some((prefix) => lower.startsWith(prefix));
241564
+ }
241565
+ /**
241566
+ * 非内部、非虚拟、MAC 不是全 0 / 广播地址的网卡 MAC,去重后排序。
241567
+ * 排序是为了让指纹与网卡枚举顺序无关(枚举顺序在重启后可能变)。
241568
+ */
241569
+ function physicalMacAddresses(interfaces = os_1.default.networkInterfaces()) {
241570
+ const macs = new Set();
241571
+ for (const [name, list] of Object.entries(interfaces)) {
241572
+ if (!list || isVirtualNic(name)) {
241573
+ continue;
241574
+ }
241575
+ for (const nic of list) {
241576
+ const mac = nic?.mac?.toLowerCase();
241577
+ if (!nic || nic.internal || !mac) {
241578
+ continue;
241579
+ }
241580
+ if (mac === '00:00:00:00:00:00' || mac === 'ff:ff:ff:ff:ff:ff') {
241581
+ continue;
241582
+ }
241583
+ macs.add(mac);
241584
+ }
241585
+ }
241586
+ return [...macs].sort();
241587
+ }
241588
+ /** 取不到系统锚点时的兜底信号:**不含虚拟网卡**,主机名与 CPU 型号足够稳。 */
241589
+ function collectHostSignal() {
241590
+ let hostname = 'unknown-host';
241591
+ try {
241592
+ hostname = os_1.default.hostname() || hostname;
241593
+ }
241594
+ catch {
241595
+ // 主机名读不到不影响降级:CPU + MAC 仍可用
241596
+ }
241597
+ let cpu = '';
241598
+ try {
241599
+ cpu = os_1.default
241600
+ .cpus()
241601
+ .map((item) => item.model)
241602
+ .join(',');
241603
+ }
241604
+ catch {
241605
+ // 同上
241606
+ }
241607
+ let macs = [];
241608
+ try {
241609
+ macs = physicalMacAddresses();
241610
+ }
241611
+ catch {
241612
+ // 同上
241613
+ }
241614
+ const parts = [hostname, cpu, ...macs].filter((part) => Boolean(part));
241615
+ return {
241616
+ value: parts.join('|'),
241617
+ source: macs.length > 0 ? 'host-fallback' : 'host-only',
241618
+ };
241619
+ }
241620
+ /**
241621
+ * 计算匿名设备指纹(SHA256 前 32 位 hex),并返回这次用的锚点来源 ——
241622
+ * 来源只进 debug 日志,用于上线后确认「到底有多少机器走到了兜底」。
241623
+ */
241624
+ function computeDeviceId(platform = process.platform) {
241625
+ const anchor = readSystemAnchor(platform) ?? collectHostSignal();
241626
+ return { deviceId: sha256Short(anchor.value), source: anchor.source };
241627
+ }
241628
+
241629
+
241236
241630
  /***/ },
241237
241631
 
241238
241632
  /***/ 65048
@@ -241373,6 +241767,113 @@ async function requestChoiceElicitation(server, params) {
241373
241767
  }
241374
241768
 
241375
241769
 
241770
+ /***/ },
241771
+
241772
+ /***/ 61498
241773
+ (__unused_webpack_module, exports, __webpack_require__) {
241774
+
241775
+ "use strict";
241776
+
241777
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
241778
+ exports.ENV_SOURCES = void 0;
241779
+ exports.noteEnvBinding = noteEnvBinding;
241780
+ exports.clearEnvBinding = clearEnvBinding;
241781
+ exports.hasEnvSlot = hasEnvSlot;
241782
+ exports.readReportedEnv = readReportedEnv;
241783
+ exports.readDisplayedEnvId = readDisplayedEnvId;
241784
+ exports.runWithEnvSlot = runWithEnvSlot;
241785
+ exports.runInEnvSlot = runInEnvSlot;
241786
+ exports.peekLocalEnvBinding = peekLocalEnvBinding;
241787
+ const node_async_hooks_1 = __webpack_require__(18667);
241788
+ const project_config_js_1 = __webpack_require__(39175);
241789
+ /**
241790
+ * Where this resolution got its env id.
241791
+ * The first four values are already in shipped queries. Do not rename them.
241792
+ * `default` stays `default` (an empty result, not a rename to `unresolved`).
241793
+ */
241794
+ exports.ENV_SOURCES = [
241795
+ "cloudBaseOptions",
241796
+ "process.env.CLOUDBASE_ENV_ID",
241797
+ "envManager.cachedEnvId",
241798
+ "project",
241799
+ "login_state",
241800
+ "auto_bound",
241801
+ "default",
241802
+ ];
241803
+ const envCall = new node_async_hooks_1.AsyncLocalStorage();
241804
+ function isReportableEnvId(envId) {
241805
+ return !!envId && envId !== "local" && envId !== "unknown";
241806
+ }
241807
+ /** Write into the current slot. Outside a slot this is a no-op and does not touch process globals. */
241808
+ function noteEnvBinding(binding) {
241809
+ const slot = envCall.getStore();
241810
+ if (!slot || binding.source === "default" || !isReportableEnvId(binding.envId)) {
241811
+ return;
241812
+ }
241813
+ slot.binding = { envId: binding.envId, source: binding.source };
241814
+ }
241815
+ function clearEnvBinding() {
241816
+ const slot = envCall.getStore();
241817
+ if (slot) {
241818
+ slot.binding = null;
241819
+ }
241820
+ }
241821
+ function hasEnvSlot() {
241822
+ return envCall.getStore() !== undefined;
241823
+ }
241824
+ function readReportedEnv() {
241825
+ const binding = envCall.getStore()?.binding;
241826
+ if (!binding || binding.source === "default" || !isReportableEnvId(binding.envId)) {
241827
+ return { envId: "unknown", envIdSource: "default" };
241828
+ }
241829
+ return { envId: binding.envId, envIdSource: binding.source };
241830
+ }
241831
+ /**
241832
+ * Env id shown on the start page, the usage card, and confirmation text.
241833
+ * An explicit envId on this call wins, matching the resolver ladder.
241834
+ * Otherwise the current slot (login state, project, cache, or env var already noted).
241835
+ * Does not read process.env or the manager cache: on a hosted request those belong to the server machine.
241836
+ */
241837
+ function readDisplayedEnvId(explicitEnvId) {
241838
+ if (isReportableEnvId(explicitEnvId)) {
241839
+ return explicitEnvId;
241840
+ }
241841
+ const reported = readReportedEnv();
241842
+ if (reported.envIdSource !== "default") {
241843
+ return reported.envId;
241844
+ }
241845
+ return null;
241846
+ }
241847
+ function runWithEnvSlot(slot, fn) {
241848
+ return envCall.run(slot, fn);
241849
+ }
241850
+ /** One fresh slot. Tests and any caller that must not share another request's binding. */
241851
+ function runInEnvSlot(fn) {
241852
+ return envCall.run({ binding: null }, fn);
241853
+ }
241854
+ /**
241855
+ * Read-only snapshot for process start. Does not call setEnvId and does not list envs.
241856
+ * `cachedEnvId` is passed in so this module does not import the manager (that import cycles).
241857
+ */
241858
+ function peekLocalEnvBinding(input) {
241859
+ if (isReportableEnvId(input.cachedEnvId)) {
241860
+ return { envId: input.cachedEnvId, source: "envManager.cachedEnvId" };
241861
+ }
241862
+ const fromEnv = process.env.CLOUDBASE_ENV_ID;
241863
+ if (isReportableEnvId(fromEnv)) {
241864
+ return { envId: fromEnv, source: "process.env.CLOUDBASE_ENV_ID" };
241865
+ }
241866
+ const projectEnvId = (0, project_config_js_1.readProjectEnvId)();
241867
+ if (isReportableEnvId(projectEnvId)) {
241868
+ return { envId: projectEnvId, source: "project" };
241869
+ }
241870
+ if (isReportableEnvId(input.loginEnvId)) {
241871
+ return { envId: input.loginEnvId, source: "login_state" };
241872
+ }
241873
+ return { envId: null, source: "default" };
241874
+ }
241875
+
241876
+
241376
241877
  /***/ },
241377
241878
 
241378
241879
  /***/ 81194
@@ -243051,6 +243552,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
243051
243552
  };
243052
243553
  Object.defineProperty(exports, "__esModule", ({ value: true }));
243053
243554
  exports.reportToolkitSessionInitialized = exports.reportToolkitLifecycle = exports.reportResourceRead = exports.reportElicitationResult = exports.reportToolCall = exports.MCP_UI_EXTENSION = exports.telemetryReporter = void 0;
243555
+ exports.seedStdioEnvBinding = seedStdioEnvBinding;
243054
243556
  exports.extractMcpClientInfo = extractMcpClientInfo;
243055
243557
  exports.readMcpClientInfoFromServer = readMcpClientInfoFromServer;
243056
243558
  exports.normalizeClientName = normalizeClientName;
@@ -243064,6 +243566,8 @@ const os_1 = __importDefault(__webpack_require__(21820));
243064
243566
  const auth_js_1 = __webpack_require__(561);
243065
243567
  const cloudbase_manager_js_1 = __webpack_require__(33109);
243066
243568
  const cloud_mode_js_1 = __webpack_require__(88694);
243569
+ const env_binding_js_1 = __webpack_require__(61498);
243570
+ const device_id_js_1 = __webpack_require__(36953);
243067
243571
  const logger_js_1 = __webpack_require__(40781);
243068
243572
  const site_map_js_1 = __webpack_require__(34533);
243069
243573
  /**
@@ -243119,7 +243623,7 @@ class TelemetryReporter {
243119
243623
  const arch = os_1.default.arch(); // 系统架构
243120
243624
  // Build-time injected version; guard for vitest / non-webpack runtimes.
243121
243625
  const mcpVersion = process.env.npm_package_version ||
243122
- ( true ? "2.36.1" : 0);
243626
+ ( true ? "2.36.2" : 0);
243123
243627
  return {
243124
243628
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
243125
243629
  deviceId: this.deviceId,
@@ -243132,26 +243636,25 @@ class TelemetryReporter {
243132
243636
  }
243133
243637
  /**
243134
243638
  * 获取设备唯一标识
243135
- * 基于主机名、CPU信息和MAC地址生成匿名设备指纹
243639
+ *
243640
+ * 锚点与降级顺序见 `utils/device-id.ts`:优先系统级不可变标识(IOPlatformUUID /
243641
+ * MachineGuid / machine-id),取不到才退到 hostname + CPU + 过滤后的物理网卡 MAC。
243642
+ * 容器里 hostname 每次重建都变、macOS 私有 Wi-Fi 地址让 MAC 随 SSID 漂移,
243643
+ * 两者都不能当锚点 —— 旧实现把它们全拼进去,同一台 Mac 一天能上报成几十个设备。
243644
+ *
243645
+ * 子进程(ioreg / reg)只在这里跑一次(构造时),1s 超时即降级。
243136
243646
  */
243137
243647
  getDeviceId() {
243138
243648
  try {
243139
- // 获取设备信息组合
243140
- const deviceInfo = [
243141
- os_1.default.hostname(),
243142
- os_1.default.cpus().map((cpu) => cpu.model).join(','),
243143
- Object.values(os_1.default.networkInterfaces())
243144
- .reduce((acc, val) => acc.concat(val || []), [])
243145
- .filter((nic) => nic && !nic.internal && nic.mac)
243146
- .map((nic) => nic.mac)
243147
- .join(',')
243148
- ].join('|');
243149
- // 生成SHA256哈希作为设备ID
243150
- return crypto_1.default.createHash('sha256').update(deviceInfo).digest('hex').substring(0, 32);
243649
+ const { deviceId, source } = (0, device_id_js_1.computeDeviceId)();
243650
+ (0, logger_js_1.debug)('device_id_resolved', { source, deviceId: deviceId.substring(0, 8) + '...' });
243651
+ return deviceId;
243151
243652
  }
243152
243653
  catch (err) {
243153
- // 如果获取设备信息失败,生成随机ID
243154
- return crypto_1.default.randomBytes(16).toString('hex');
243654
+ // 走到这里说明连 hostname / CPU 都读不到:用固定串兜底,**绝不能**用随机数
243655
+ // (随机数等于每次启动都是一台新设备,正是这次要消灭的行为)。
243656
+ (0, logger_js_1.debug)('获取设备标识失败,回落到固定串', err instanceof Error ? err : new Error(String(err)));
243657
+ return crypto_1.default.createHash('sha256').update('cloudbase-mcp|no-device-signal').digest('hex').substring(0, 32);
243155
243658
  }
243156
243659
  }
243157
243660
  /**
@@ -243267,39 +243770,40 @@ class TelemetryReporter {
243267
243770
  // 创建全局实例
243268
243771
  exports.telemetryReporter = new TelemetryReporter();
243269
243772
  /**
243270
- * 解析环境ID
243271
- * 优先级:传入配置 > envManager缓存 > 环境变量 > unknown
243773
+ * Reports read the current AsyncLocalStorage slot.
243774
+ * They do not re-read envManager or CLOUDBASE_ENV_ID.
243775
+ * An explicit envId on this call is only used when the slot is still empty
243776
+ * (hosted initialized, before a resolver runs, when the request already carried one).
243777
+ *
243778
+ * The source list lives in `env-binding.ts` (`ENV_SOURCES`) — one definition only.
243272
243779
  */
243273
243780
  function resolveEnvId(cloudBaseOptions) {
243274
- let envId = 'unknown';
243275
- let envIdSource = 'unknown';
243276
- try {
243277
- if (cloudBaseOptions?.envId) {
243278
- envId = cloudBaseOptions.envId;
243279
- envIdSource = 'cloudBaseOptions';
243280
- }
243281
- else {
243282
- const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
243283
- if (cachedEnvId) {
243284
- envId = cachedEnvId;
243285
- envIdSource = 'envManager.cachedEnvId';
243286
- }
243287
- else if (process.env.CLOUDBASE_ENV_ID) {
243288
- envId = process.env.CLOUDBASE_ENV_ID;
243289
- envIdSource = 'process.env.CLOUDBASE_ENV_ID';
243290
- }
243291
- else {
243292
- envId = 'unknown';
243293
- envIdSource = 'default';
243294
- }
243295
- }
243781
+ const reported = (0, env_binding_js_1.readReportedEnv)();
243782
+ if (reported.envIdSource !== "default") {
243783
+ return reported;
243296
243784
  }
243297
- catch (err) {
243298
- (0, logger_js_1.debug)('获取环境ID失败,遥测数据将使用 unknown', err instanceof Error ? err : new Error(String(err)));
243299
- envId = 'unknown';
243300
- envIdSource = 'error';
243785
+ if (cloudBaseOptions?.envId) {
243786
+ return { envId: cloudBaseOptions.envId, envIdSource: "cloudBaseOptions" };
243787
+ }
243788
+ return { envId: "unknown", envIdSource: "default" };
243789
+ }
243790
+ /**
243791
+ * Stdio start: reuse the login warm (one peekLoginState per process) and one project-file read.
243792
+ * Does not call setEnvId and does not list environments. Cloud mode does not read local files.
243793
+ */
243794
+ async function seedStdioEnvBinding(slot) {
243795
+ if ((0, cloud_mode_js_1.isCloudMode)()) {
243796
+ return;
243797
+ }
243798
+ await warmLocalLoginState();
243799
+ const loginEnvId = typeof localLoginState?.envId === "string" ? localLoginState.envId : null;
243800
+ const binding = (0, env_binding_js_1.peekLocalEnvBinding)({
243801
+ cachedEnvId: (0, cloudbase_manager_js_1.getCachedEnvId)(),
243802
+ loginEnvId,
243803
+ });
243804
+ if (binding.envId && binding.source !== "default") {
243805
+ slot.binding = binding;
243301
243806
  }
243302
- return { envId, envIdSource };
243303
243807
  }
243304
243808
  /**
243305
243809
  * Normalize SDK Implementation / clientInfo into telemetry-safe fields.
@@ -243606,6 +244110,9 @@ const reportToolCall = async (params) => {
243606
244110
  duration: params.duration !== undefined ? String(params.duration) : undefined,
243607
244111
  error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
243608
244112
  envId: envId || 'unknown',
244113
+ // 取值来源(cloudBaseOptions / envManager.cachedEnvId / process.env / default):
244114
+ // 这一列就是「envId 为什么是 unknown」的判据,别再靠猜
244115
+ envIdSource,
243609
244116
  region: siteRegion.region,
243610
244117
  site: siteRegion.site,
243611
244118
  login_uin: loginUin,
@@ -243619,6 +244126,13 @@ const reportToolCall = async (params) => {
243619
244126
  if (params.action !== undefined) {
243620
244127
  eventData.action = params.action;
243621
244128
  }
244129
+ // 环境准备结果:拿不到就不占列(与能力字段同一纪律,不写 unknown 假值)
244130
+ if (params.envSetupStatus !== undefined) {
244131
+ eventData.envSetupStatus = params.envSetupStatus;
244132
+ }
244133
+ if (params.envSetupFailReason !== undefined) {
244134
+ eventData.envSetupFailReason = params.envSetupFailReason;
244135
+ }
243622
244136
  // 添加入参信息(如果提供)
243623
244137
  if (params.inputParams !== undefined) {
243624
244138
  try {
@@ -243740,7 +244254,15 @@ const reportToolkitLifecycle = async (params) => {
243740
244254
  // 安全获取环境ID,优先使用传入的配置
243741
244255
  const { envId, envIdSource } = resolveEnvId(params.cloudBaseOptions);
243742
244256
  const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
243743
- const loginUin = await resolveLoginUin(params.cloudBaseOptions, { allowResolve: false });
244257
+ // `start` 在进程最早期发出:此时既没有宿主注入的 uin,也还没人 warm 过本地登录态。
244258
+ // 卡死 `allowResolve: false` 就只能读到空缓存 → 恒 'unknown'(2026-10-26 实测:这一列
244259
+ // 有真实 uin 的行是 0)。start 允许解析:`warmLocalLoginState()` 进程内只跑一次
244260
+ // (读本地 auth.json;临时密钥过期时可能续期一次,与工具调用本来就要付的开销同源),
244261
+ // 不会挂到每次上报上。
244262
+ // `exit` 仍保持不允许 —— 退出路径不能等,拿不到就是 unknown,`start` 那次已经把值带出去了。
244263
+ const loginUin = await resolveLoginUin(params.cloudBaseOptions, {
244264
+ allowResolve: params.event !== 'exit',
244265
+ });
243744
244266
  (0, logger_js_1.debug)('[telemetry] 生命周期事件 envId 获取结果', {
243745
244267
  event: params.event,
243746
244268
  envId,
@@ -243755,6 +244277,9 @@ const reportToolkitLifecycle = async (params) => {
243755
244277
  exitCode: params.exitCode !== undefined ? String(params.exitCode) : undefined,
243756
244278
  error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
243757
244279
  envId: envId || 'unknown',
244280
+ // 取值来源(cloudBaseOptions / envManager.cachedEnvId / process.env / default):
244281
+ // 这一列就是「envId 为什么是 unknown」的判据,别再靠猜
244282
+ envIdSource,
243758
244283
  region: siteRegion.region,
243759
244284
  site: siteRegion.site,
243760
244285
  login_uin: loginUin,
@@ -243811,12 +244336,15 @@ exports.reportToolkitLifecycle = reportToolkitLifecycle;
243811
244336
  */
243812
244337
  const reportToolkitSessionInitialized = async (params) => {
243813
244338
  const { nodeVersion, osType, osRelease, arch, mcpVersion } = exports.telemetryReporter.getUserAgent();
243814
- const { envId } = resolveEnvId(params.cloudBaseOptions);
244339
+ const { envId, envIdSource } = resolveEnvId(params.cloudBaseOptions);
243815
244340
  const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
243816
- const loginUin = await resolveLoginUin(params.cloudBaseOptions, { allowResolve: false });
244341
+ // 与 `start` 同理:`initialized` 紧跟在 `start` 之后,也是不允许等的分支就会白报一条 unknown。
244342
+ // 这里放开解析;若 `start` 已经 warm 过,这一句直接命中进程内缓存,零额外成本。
244343
+ const loginUin = await resolveLoginUin(params.cloudBaseOptions);
243817
244344
  const eventData = {
243818
244345
  event: 'initialized',
243819
244346
  envId: envId || 'unknown',
244347
+ envIdSource,
243820
244348
  region: siteRegion.region,
243821
244349
  site: siteRegion.site,
243822
244350
  login_uin: loginUin,
@@ -243990,7 +244518,6 @@ function throwToolPayloadError(payload) {
243990
244518
  Object.defineProperty(exports, "__esModule", ({ value: true }));
243991
244519
  exports.applyCategoryAnnotationMeta = applyCategoryAnnotationMeta;
243992
244520
  exports.wrapServerWithTelemetry = wrapServerWithTelemetry;
243993
- const cloudbase_manager_js_1 = __webpack_require__(33109);
243994
244521
  const cloud_mode_js_1 = __webpack_require__(88694);
243995
244522
  const logger_js_1 = __webpack_require__(40781);
243996
244523
  const telemetry_js_1 = __webpack_require__(5198);
@@ -244053,8 +244580,56 @@ function contributionHint(server) {
244053
244580
  ].join("\n");
244054
244581
  }
244055
244582
  /**
244056
- * 创建包装后的处理函数,添加数据上报功能
244583
+ * 从 `auth` 的返回里取出「环境准备」的结果,供遥测上报。
244584
+ *
244585
+ * 为什么要从返回体里抠:`env_setup_status` / `env_setup_failure.reason` 只存在于
244586
+ * `auth` 的 payload 里,不是 `reportToolCall` 的入参。而工具 wrapper 是唯一同时
244587
+ * 看得见 args 和 result 的地方。
244588
+ *
244589
+ * 现状(2026-10-27):这两项只回给模型、没进埋点,于是「无环境的用户卡在购买页、
244590
+ * 实名、还是 CAM 授权」在数据里长得一模一样,加文案也无法验收。
244057
244591
  */
244592
+ function readEnvSetupOutcome(result) {
244593
+ const rec = result;
244594
+ if (!rec || typeof rec !== 'object')
244595
+ return undefined;
244596
+ // 优先 structuredContent(MCP 规范位),退到 content[0].text 里的 JSON
244597
+ const candidates = [];
244598
+ if (rec.structuredContent)
244599
+ candidates.push(rec.structuredContent);
244600
+ const content = Array.isArray(rec.content) ? rec.content : [];
244601
+ for (const item of content) {
244602
+ const text = item?.text;
244603
+ if (typeof text === 'string' && text.trim().startsWith('{')) {
244604
+ try {
244605
+ candidates.push(JSON.parse(text));
244606
+ }
244607
+ catch {
244608
+ /* 不是 JSON 就跳过,不要因为解析失败影响正常返回 */
244609
+ }
244610
+ }
244611
+ }
244612
+ for (const payload of candidates) {
244613
+ const p = payload;
244614
+ const status = typeof p?.env_setup_status === 'string' ? p.env_setup_status : undefined;
244615
+ if (!status)
244616
+ continue;
244617
+ const failure = p?.env_setup_failure;
244618
+ const reason = typeof failure?.reason === 'string' ? failure.reason : undefined;
244619
+ // 把两个布尔压进 reason 的后缀:一列就能看清「卡在哪」,
244620
+ // 单看 reason 只知道「建环境失败」,不知道是实名还是 CAM 授权拦住的
244621
+ const gates = [];
244622
+ if (failure?.need_real_name_auth === true)
244623
+ gates.push('realname');
244624
+ if (failure?.need_cam_auth === true)
244625
+ gates.push('cam');
244626
+ return {
244627
+ status,
244628
+ reason: reason ? (gates.length ? `${reason}+${gates.join('+')}` : reason) : undefined,
244629
+ };
244630
+ }
244631
+ return undefined;
244632
+ }
244058
244633
  /**
244059
244634
  * 工具自己返回的失败:结构化 `{ success: false }`(`isBusinessFailureToolResult` 已覆盖
244060
244635
  * 顶层 / structuredContent / JSON 文本三种挂法),**或**已经显式带 `isError: true` 的回执。
@@ -244074,7 +244649,7 @@ function isReturnedFailureResult(result) {
244074
244649
  * 所以两条路径对同一个底层错误得到的文本逐字相同(🆔 RequestId + 📦 版本页脚都在这里)。
244075
244650
  */
244076
244651
  function buildFailureClientText(errorMessage, requestId, server) {
244077
- const mcpVersion = true ? "2.36.1" : 0;
244652
+ const mcpVersion = true ? "2.36.2" : 0;
244078
244653
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
244079
244654
  return `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n${contributionHint(server)}`;
244080
244655
  }
@@ -244134,12 +244709,18 @@ function withEnhancedFailureText(result, errorMessage, requestId, server) {
244134
244709
  }
244135
244710
  return result;
244136
244711
  }
244712
+ /**
244713
+ * 创建包装后的处理函数,添加数据上报功能
244714
+ */
244137
244715
  function createWrappedHandler(name, handler, server) {
244138
244716
  return async (args, extra) => {
244139
244717
  const startTime = Date.now();
244140
244718
  let success = false;
244141
244719
  let errorMessage;
244142
244720
  let requestId;
244721
+ // 提到 try 外:finally 里要读 auth 的环境准备结果(env_setup_status / failure.reason)。
244722
+ // 护栏拦截的早退路径不会赋值,finally 里按 undefined 处理。
244723
+ let result;
244143
244724
  try {
244144
244725
  (0, logger_js_1.debug)(`开始执行工具: ${name}`, { args: sanitizeArgs(args) });
244145
244726
  // In test environment, skip logger to avoid potential blocking
@@ -244171,7 +244752,7 @@ function createWrappedHandler(name, handler, server) {
244171
244752
  return guardDecision.result;
244172
244753
  }
244173
244754
  // 执行原始处理函数(extra 一并透传,工具可据此拿到在途请求 id)
244174
- const result = await handler(args, extra);
244755
+ result = await handler(args, extra);
244175
244756
  // 工具**自己返回**的失败(`{ success: false }` 结构化载荷,或已经带 `isError: true` 的
244176
244757
  // 失败回执)与"抛错"是同一件事:遥测要按失败记,文案要吃同一套收尾(增强 + RequestId +
244177
244758
  // 版本页脚)。护栏拦截的返回走不到这里——它在上面就 return 了,且它的载荷既没有
@@ -244252,24 +244833,19 @@ function createWrappedHandler(name, handler, server) {
244252
244833
  const isTestEnvironment = false || process.env.VITEST === "true";
244253
244834
  if (!isTestEnvironment) {
244254
244835
  const duration = Date.now() - startTime;
244255
- // 如果 server.cloudBaseOptions 为空或没有 envId,尝试从缓存获取并更新
244256
- let cloudBaseOptions = server.cloudBaseOptions;
244257
- if (!cloudBaseOptions?.envId) {
244258
- const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
244259
- if (cachedEnvId) {
244260
- cloudBaseOptions = { ...cloudBaseOptions, envId: cachedEnvId };
244261
- }
244262
- }
244836
+ const envSetup = name === 'auth' ? readEnvSetupOutcome(result) : undefined;
244263
244837
  // 异步上报,不阻塞工具返回
244264
244838
  (0, telemetry_js_1.reportToolCall)({
244265
244839
  toolName: name,
244840
+ envSetupStatus: envSetup?.status,
244841
+ envSetupFailReason: envSetup?.reason,
244266
244842
  success,
244267
244843
  requestId,
244268
244844
  duration,
244269
244845
  error: errorMessage,
244270
244846
  inputParams: sanitizeArgs(args), // 添加入参上报
244271
244847
  action: args?.action, // 工具级 action(如 auth 的 status/set_env)
244272
- cloudBaseOptions: cloudBaseOptions, // 传递 CloudBase 配置(可能已更新)
244848
+ cloudBaseOptions: server.cloudBaseOptions,
244273
244849
  ide: server.ide || process.env.INTEGRATION_IDE, // 传递集成IDE信息
244274
244850
  client: server.client || process.env.CLOUDBASE_MCP_CLIENT, // 传递 MCP client 来源标识
244275
244851
  mcpClientInfo: (0, telemetry_js_1.readMcpClientInfoFromServer)(server),
@@ -264583,6 +265159,14 @@ module.exports = require("net");
264583
265159
 
264584
265160
  /***/ },
264585
265161
 
265162
+ /***/ 18667
265163
+ (module) {
265164
+
265165
+ "use strict";
265166
+ module.exports = require("node:async_hooks");
265167
+
265168
+ /***/ },
265169
+
264586
265170
  /***/ 75305
264587
265171
  (module) {
264588
265172