@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.js CHANGED
@@ -15,6 +15,7 @@ import * as __WEBPACK_EXTERNAL_MODULE_http__ from "http";
15
15
  import * as __WEBPACK_EXTERNAL_MODULE_https__ from "https";
16
16
  import * as __WEBPACK_EXTERNAL_MODULE_lockfile__ from "lockfile";
17
17
  import * as __WEBPACK_EXTERNAL_MODULE_net__ from "net";
18
+ import * as __WEBPACK_EXTERNAL_MODULE_node_async_hooks_1fa35564__ from "node:async_hooks";
18
19
  import * as __WEBPACK_EXTERNAL_MODULE_node_crypto_803ecaf5__ from "node:crypto";
19
20
  import * as __WEBPACK_EXTERNAL_MODULE_node_fs_75ed2103__ from "node:fs";
20
21
  import * as __WEBPACK_EXTERNAL_MODULE_node_os_e12349cb__ from "node:os";
@@ -814,7 +815,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
814
815
  return (mod && mod.__esModule) ? mod : { "default": mod };
815
816
  };
816
817
  Object.defineProperty(exports, "__esModule", ({ value: true }));
817
- exports.envManager = void 0;
818
+ exports.envManager = exports.runInEnvSlot = void 0;
818
819
  exports.probeApiKeyCamCapability = probeApiKeyCamCapability;
819
820
  exports.fetchEnvOwnerUin = fetchEnvOwnerUin;
820
821
  exports.probeCamCapabilityForLogin = probeCamCapabilityForLogin;
@@ -836,7 +837,10 @@ const logger_js_1 = __webpack_require__(781);
836
837
  const tool_result_js_1 = __webpack_require__(9645);
837
838
  const site_map_js_1 = __webpack_require__(4533);
838
839
  const project_config_js_1 = __webpack_require__(9175);
840
+ const cloud_mode_js_1 = __webpack_require__(8694);
841
+ const env_binding_js_1 = __webpack_require__(1498);
839
842
  const local_endpoint_js_1 = __webpack_require__(6156);
843
+ const describe_envs_query_js_1 = __webpack_require__(1284);
840
844
  function toEnvCandidates(envList) {
841
845
  if (!Array.isArray(envList)) {
842
846
  return [];
@@ -1022,11 +1026,7 @@ async function listAvailableEnvCandidates(options) {
1022
1026
  try {
1023
1027
  const result = await cloudbase.commonService("tcb", "2018-06-08").call({
1024
1028
  Action: "DescribeEnvs",
1025
- Param: {
1026
- EnvTypes: ["weda", "baas"],
1027
- IsVisible: false,
1028
- Channels: ["dcloud", "iotenable", "tem", "scene_module"],
1029
- },
1029
+ Param: (0, describe_envs_query_js_1.buildDescribeEnvsFilter)(),
1030
1030
  });
1031
1031
  const envList = result?.EnvList || result?.Data?.EnvList || [];
1032
1032
  return toEnvCandidates(envList);
@@ -1244,6 +1244,7 @@ class EnvironmentManager {
1244
1244
  // 手动设置环境ID(用于外部调用)
1245
1245
  async setEnvId(envId) {
1246
1246
  this._setCachedEnvId(envId);
1247
+ (0, env_binding_js_1.noteEnvBinding)({ envId, source: "envManager.cachedEnvId" });
1247
1248
  (0, logger_js_1.debug)('手动设置环境ID并更新缓存:', { envId });
1248
1249
  }
1249
1250
  // Get cached envId without triggering fetch (for optimization)
@@ -1254,44 +1255,136 @@ class EnvironmentManager {
1254
1255
  // 全局实例
1255
1256
  const envManager = new EnvironmentManager();
1256
1257
  exports.envManager = envManager;
1257
- // 导出环境ID获取函数
1258
+ function requestHasCloudCredentials(cloudBaseOptions) {
1259
+ return Boolean((cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey) ||
1260
+ cloudBaseOptions?.requestFn);
1261
+ }
1262
+ function throwCloudModeEnvRequired(envCandidates) {
1263
+ const singleEnvId = envCandidates.length === 1 ? envCandidates[0].envId : undefined;
1264
+ (0, tool_result_js_1.throwToolPayloadError)({
1265
+ ok: false,
1266
+ code: "ENV_REQUIRED",
1267
+ message: "当前请求没有带 envId。Cloud mode 不读取本机登录态、项目配置或进程环境变量。",
1268
+ env_candidates: envCandidates,
1269
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("set_env", {
1270
+ requiredParams: singleEnvId ? undefined : ["envId"],
1271
+ suggestedArgs: singleEnvId
1272
+ ? { action: "set_env", envId: singleEnvId }
1273
+ : { action: "set_env" },
1274
+ }),
1275
+ });
1276
+ }
1277
+ /**
1278
+ * Cloud mode only sees this request. No envManager, no CLOUDBASE_ENV_ID, no project file, no auth.json.
1279
+ * A single environment is written back onto this request's options and is not cached on the process.
1280
+ */
1281
+ async function resolveCloudModeEnvId(cloudBaseOptions, requireEnvId) {
1282
+ if (cloudBaseOptions?.envId) {
1283
+ (0, env_binding_js_1.noteEnvBinding)({ envId: cloudBaseOptions.envId, source: "cloudBaseOptions" });
1284
+ return cloudBaseOptions.envId;
1285
+ }
1286
+ if (!requireEnvId) {
1287
+ return undefined;
1288
+ }
1289
+ if (!requestHasCloudCredentials(cloudBaseOptions)) {
1290
+ throwCloudModeEnvRequired([]);
1291
+ }
1292
+ const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
1293
+ if (envCandidates.length === 1) {
1294
+ const singleEnvId = envCandidates[0].envId;
1295
+ if (cloudBaseOptions) {
1296
+ cloudBaseOptions.envId = singleEnvId;
1297
+ }
1298
+ (0, env_binding_js_1.noteEnvBinding)({ envId: singleEnvId, source: "auto_bound" });
1299
+ return singleEnvId;
1300
+ }
1301
+ throwCloudModeEnvRequired(envCandidates);
1302
+ }
1303
+ async function getCloudBaseManagerCloudMode(options) {
1304
+ const requireEnvId = options.requireEnvId !== false;
1305
+ const cloudBaseOptions = options.cloudBaseOptions;
1306
+ if (!requestHasCloudCredentials(cloudBaseOptions)) {
1307
+ throwAuthRequiredError();
1308
+ }
1309
+ const resolvedEnvId = await resolveCloudModeEnvId(cloudBaseOptions, requireEnvId);
1310
+ return createCloudBaseManagerWithOptions({
1311
+ ...(cloudBaseOptions ?? {}),
1312
+ envId: resolvedEnvId,
1313
+ });
1314
+ }
1315
+ /**
1316
+ * Fresh slot for tests. Production stdio/hosted pass their own slot into `runWithEnvSlot`.
1317
+ * Re-exported from `env-binding.ts` so there is only one definition.
1318
+ */
1319
+ var env_binding_js_2 = __webpack_require__(1498);
1320
+ Object.defineProperty(exports, "runInEnvSlot", ({ enumerable: true, get: function () { return env_binding_js_2.runInEnvSlot; } }));
1258
1321
  async function getEnvId(cloudBaseOptions) {
1322
+ if ((0, cloud_mode_js_1.isCloudMode)()) {
1323
+ const envId = await resolveCloudModeEnvId(cloudBaseOptions, true);
1324
+ if (!envId) {
1325
+ throwCloudModeEnvRequired([]);
1326
+ }
1327
+ return envId;
1328
+ }
1329
+ return resolveEnvIdForCall(cloudBaseOptions);
1330
+ }
1331
+ async function resolveEnvIdForCall(cloudBaseOptions) {
1259
1332
  if (cloudBaseOptions?.envId) {
1260
1333
  (0, logger_js_1.debug)('使用传入的 envId:', { envId: cloudBaseOptions.envId });
1334
+ (0, env_binding_js_1.noteEnvBinding)({ envId: cloudBaseOptions.envId, source: "cloudBaseOptions" });
1261
1335
  return cloudBaseOptions.envId;
1262
1336
  }
1263
1337
  if ((0, local_endpoint_js_1.resolveLocalEndpoint)()) {
1264
1338
  return 'local';
1265
1339
  }
1266
- const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
1340
+ const cachedEnvId = envManager.getCachedEnvId();
1267
1341
  if (cachedEnvId) {
1268
1342
  (0, logger_js_1.debug)('使用缓存中的 envId:', { envId: cachedEnvId });
1343
+ (0, env_binding_js_1.noteEnvBinding)({ envId: cachedEnvId, source: "envManager.cachedEnvId" });
1269
1344
  return cachedEnvId;
1270
1345
  }
1271
- // 项目级配置固定的环境优先于账号级登录态,保证「打开仓库即连对环境」,
1272
- // 且同一仓库的每个 Git worktree / 每个新进程都不需要重复 set_env。
1346
+ if (process.env.CLOUDBASE_ENV_ID) {
1347
+ (0, logger_js_1.debug)('使用进程环境变量的 envId:', { envId: process.env.CLOUDBASE_ENV_ID });
1348
+ (0, env_binding_js_1.noteEnvBinding)({
1349
+ envId: process.env.CLOUDBASE_ENV_ID,
1350
+ source: "process.env.CLOUDBASE_ENV_ID",
1351
+ });
1352
+ return process.env.CLOUDBASE_ENV_ID;
1353
+ }
1354
+ // Project config stays ahead of the account login env, and still writes the cache.
1273
1355
  const projectEnvId = (0, project_config_js_1.readProjectEnvId)();
1274
1356
  if (projectEnvId) {
1275
1357
  (0, logger_js_1.debug)('使用项目配置(.cloudbase/project.json)的 envId:', { envId: projectEnvId });
1276
1358
  await envManager.setEnvId(projectEnvId);
1359
+ (0, env_binding_js_1.noteEnvBinding)({ envId: projectEnvId, source: "project" });
1277
1360
  return projectEnvId;
1278
1361
  }
1279
1362
  const loginState = await (0, auth_js_1.peekLoginState)();
1280
1363
  if (typeof loginState?.envId === 'string' && loginState.envId.length > 0) {
1281
1364
  (0, logger_js_1.debug)('使用登录态中的 envId:', { envId: loginState.envId });
1365
+ // Do not cache. A project file that appears later in this process must still win.
1366
+ (0, env_binding_js_1.noteEnvBinding)({ envId: loginState.envId, source: "login_state" });
1282
1367
  return loginState.envId;
1283
1368
  }
1284
- // 否则使用默认逻辑
1285
- return envManager.getEnvId();
1369
+ const envId = await envManager.getEnvId();
1370
+ (0, env_binding_js_1.noteEnvBinding)({ envId, source: "auto_bound" });
1371
+ return envId;
1286
1372
  }
1287
- // 导出函数保持兼容性
1288
1373
  function resetCloudBaseManagerCache() {
1289
1374
  envManager.reset();
1375
+ (0, env_binding_js_1.clearEnvBinding)();
1290
1376
  }
1291
1377
  // 导出获取缓存环境ID的函数,供遥测模块使用
1292
1378
  function getCachedEnvId() {
1293
1379
  return envManager.getCachedEnvId();
1294
1380
  }
1381
+ /**
1382
+ * 实例 ID 是环境关联的 PaaS 资源标识,正常情况下与 envId 同生命周期。
1383
+ * 但失效通知跨系统没有出口(invalidate 在生产路径上没有任何调用点),
1384
+ * 所以用一个长 TTL 兜底:宁可每半小时多查一次环境信息,
1385
+ * 也不要拿着一份没人能证明还正确的实例 ID 一直用下去。
1386
+ */
1387
+ const DATABASE_INSTANCE_ID_CACHE_TTL_MS = 30 * 60 * 1000;
1295
1388
  const databaseInstanceIdCache = new Map();
1296
1389
  function buildDatabaseInstanceIdCacheKey(options) {
1297
1390
  const envId = options?.envId ?? options?.cloudBaseOptions?.envId ?? process.env.CLOUDBASE_ENV_ID ?? 'unknown';
@@ -1322,11 +1415,16 @@ async function getDatabaseInstanceId(options) {
1322
1415
  });
1323
1416
  const cachedEntry = databaseInstanceIdCache.get(cacheKey);
1324
1417
  if (cachedEntry?.instanceId) {
1325
- return {
1326
- instanceId: cachedEntry.instanceId,
1327
- source: 'cache',
1328
- cacheKey,
1329
- };
1418
+ if (cachedEntry.expiresAt && cachedEntry.expiresAt <= Date.now()) {
1419
+ databaseInstanceIdCache.delete(cacheKey);
1420
+ }
1421
+ else {
1422
+ return {
1423
+ instanceId: cachedEntry.instanceId,
1424
+ source: 'cache',
1425
+ cacheKey,
1426
+ };
1427
+ }
1330
1428
  }
1331
1429
  if (cachedEntry?.inflightPromise) {
1332
1430
  const instanceId = await cachedEntry.inflightPromise;
@@ -1351,6 +1449,7 @@ async function getDatabaseInstanceId(options) {
1351
1449
  const instanceId = await inflightPromise;
1352
1450
  databaseInstanceIdCache.set(cacheKey, {
1353
1451
  instanceId,
1452
+ expiresAt: Date.now() + DATABASE_INSTANCE_ID_CACHE_TTL_MS,
1354
1453
  });
1355
1454
  return {
1356
1455
  instanceId,
@@ -1367,6 +1466,9 @@ async function getDatabaseInstanceId(options) {
1367
1466
  * 每次都实时获取最新的 token/secretId/secretKey
1368
1467
  */
1369
1468
  async function getCloudBaseManager(options = {}) {
1469
+ if ((0, cloud_mode_js_1.isCloudMode)()) {
1470
+ return getCloudBaseManagerCloudMode(options);
1471
+ }
1370
1472
  const { requireEnvId = true, authStrategy = 'fail_fast', } = options;
1371
1473
  let cloudBaseOptions = options.cloudBaseOptions;
1372
1474
  const localEndpoint = (0, local_endpoint_js_1.resolveLocalEndpoint)();
@@ -1382,12 +1484,14 @@ async function getCloudBaseManager(options = {}) {
1382
1484
  // 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
1383
1485
  if (cloudBaseOptions && (hasDirectCredentials || hasRequestFn)) {
1384
1486
  let resolvedEnvId = cloudBaseOptions.envId;
1487
+ let explicitSource = cloudBaseOptions.envId ? "cloudBaseOptions" : "default";
1385
1488
  if (requireEnvId && !resolvedEnvId) {
1386
1489
  const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
1387
1490
  if (envCandidates.length === 1) {
1388
1491
  const singleEnvId = envCandidates[0].envId;
1389
1492
  cloudBaseOptions.envId = singleEnvId;
1390
1493
  resolvedEnvId = singleEnvId;
1494
+ explicitSource = "auto_bound";
1391
1495
  (0, logger_js_1.debug)('自动绑定唯一环境(显式配置):', { envId: singleEnvId });
1392
1496
  }
1393
1497
  else if (authStrategy === 'fail_fast') {
@@ -1407,6 +1511,9 @@ async function getCloudBaseManager(options = {}) {
1407
1511
  }
1408
1512
  }
1409
1513
  (0, logger_js_1.debug)('使用传入的 CloudBase 配置');
1514
+ if (resolvedEnvId && explicitSource !== "default") {
1515
+ (0, env_binding_js_1.noteEnvBinding)({ envId: resolvedEnvId, source: explicitSource });
1516
+ }
1410
1517
  return createCloudBaseManagerWithOptions({
1411
1518
  ...cloudBaseOptions,
1412
1519
  envId: resolvedEnvId,
@@ -1428,27 +1535,33 @@ async function getCloudBaseManager(options = {}) {
1428
1535
  }
1429
1536
  const { envId: loginEnvId, secretId, secretKey, token } = loginState;
1430
1537
  let finalEnvId = cloudBaseOptions?.envId;
1538
+ let envSource = finalEnvId ? "cloudBaseOptions" : undefined;
1431
1539
  if (requireEnvId) {
1432
1540
  if (!finalEnvId) {
1433
- // Optimize: Check if envManager has cached envId first (fast path)
1434
- // If cached, use it directly; otherwise check loginEnvId before calling getEnvId()
1435
- // This avoids unnecessary async calls when we have a valid envId available
1436
- const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
1437
- const projectEnvId = cachedEnvId ? undefined : (0, project_config_js_1.readProjectEnvId)();
1541
+ const cachedEnvId = envManager.getCachedEnvId();
1542
+ const envFromProcess = process.env.CLOUDBASE_ENV_ID;
1543
+ const projectEnvId = (cachedEnvId || envFromProcess) ? undefined : (0, project_config_js_1.readProjectEnvId)();
1438
1544
  if (cachedEnvId) {
1439
1545
  (0, logger_js_1.debug)('使用 envManager 缓存的环境ID:', { cachedEnvId });
1440
1546
  finalEnvId = cachedEnvId;
1547
+ envSource = "envManager.cachedEnvId";
1548
+ }
1549
+ else if (envFromProcess) {
1550
+ (0, logger_js_1.debug)('使用进程环境变量的环境ID:', { envId: envFromProcess });
1551
+ finalEnvId = envFromProcess;
1552
+ envSource = "process.env.CLOUDBASE_ENV_ID";
1441
1553
  }
1442
1554
  else if (projectEnvId) {
1443
- // 项目级绑定优先于全局登录态 envId:后者可能来自另一个仓库
1555
+ // Project binding stays ahead of the account login env.
1444
1556
  (0, logger_js_1.debug)('使用项目配置(project.json/cloudbaserc.json)的环境ID:', { projectEnvId });
1445
1557
  await envManager.setEnvId(projectEnvId);
1446
1558
  finalEnvId = projectEnvId;
1559
+ envSource = "project";
1447
1560
  }
1448
1561
  else if (loginEnvId) {
1449
- // If no cache but loginState has envId, use it directly
1450
1562
  (0, logger_js_1.debug)('使用 loginState 中的环境ID:', { loginEnvId });
1451
1563
  finalEnvId = loginEnvId;
1564
+ envSource = "login_state";
1452
1565
  }
1453
1566
  else {
1454
1567
  if (authStrategy === 'fail_fast') {
@@ -1457,6 +1570,7 @@ async function getCloudBaseManager(options = {}) {
1457
1570
  const singleEnvId = envCandidates[0].envId;
1458
1571
  await envManager.setEnvId(singleEnvId);
1459
1572
  finalEnvId = singleEnvId;
1573
+ envSource = "auto_bound";
1460
1574
  (0, logger_js_1.debug)('自动绑定唯一环境:', { envId: singleEnvId });
1461
1575
  }
1462
1576
  else {
@@ -1464,14 +1578,19 @@ async function getCloudBaseManager(options = {}) {
1464
1578
  }
1465
1579
  }
1466
1580
  else {
1467
- // ensure 模式下也保持非交互:单环境自动绑定,多环境返回 ENV_REQUIRED
1468
1581
  finalEnvId = await envManager.getEnvId();
1582
+ envSource = "auto_bound";
1469
1583
  }
1470
1584
  }
1471
1585
  }
1472
1586
  }
1473
- // envId priority: explicit option > envManager cache > loginState.envId
1474
1587
  const resolvedEnvId = finalEnvId || loginEnvId;
1588
+ if (!envSource && resolvedEnvId && resolvedEnvId === loginEnvId) {
1589
+ envSource = "login_state";
1590
+ }
1591
+ if (resolvedEnvId && envSource) {
1592
+ (0, env_binding_js_1.noteEnvBinding)({ envId: resolvedEnvId, source: envSource });
1593
+ }
1475
1594
  // region 直接使用 fallbackRegion(resolveSiteAndRegion 统一解析)
1476
1595
  // 不再通过 DescribeEnvs 查询 region,以兼容 STS 临时密钥场景
1477
1596
  const region = fallbackRegion;
@@ -2200,6 +2319,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
2200
2319
  exports.handleHostedMcpRequest = handleHostedMcpRequest;
2201
2320
  const streamableHttp_js_1 = __webpack_require__(6519);
2202
2321
  const server_js_1 = __webpack_require__(6324);
2322
+ const env_binding_js_1 = __webpack_require__(1498);
2203
2323
  const feedback_session_js_1 = __webpack_require__(3379);
2204
2324
  const client_info_cache_js_1 = __webpack_require__(5454);
2205
2325
  function readInitializeClientInfo(body) {
@@ -2277,36 +2397,42 @@ async function handleHostedMcpRequest(input) {
2277
2397
  const closeBoth = () => {
2278
2398
  void Promise.allSettled([transport?.close(), server?.close()]);
2279
2399
  };
2400
+ const injectedEnvId = input.serverOptions.cloudBaseOptions?.envId;
2401
+ const requestSlot = {
2402
+ binding: injectedEnvId
2403
+ ? { envId: injectedEnvId, source: "cloudBaseOptions" }
2404
+ : null,
2405
+ };
2280
2406
  try {
2281
- server = await (0, server_js_1.createCloudBaseMcpServer)({
2282
- name: input.serverOptions.name,
2283
- version: input.serverOptions.version,
2284
- enableTelemetry: input.serverOptions.enableTelemetry,
2285
- cloudBaseOptions: input.serverOptions.cloudBaseOptions,
2286
- cloudMode: input.serverOptions.cloudMode ?? true,
2287
- ide: input.serverOptions.ide,
2288
- client: input.serverOptions.client,
2289
- clientInfo,
2290
- // 会话级遥测的身份来源:把**当前** transport 的 sessionId 交给 server(公开 getter)。
2291
- // 这里是无状态传输(本文件 `:165` `sessionIdGenerator: undefined`)⇒ 今天它恒为 undefined、
2292
- // 上报按"一个实例一个会话"计;将来若有状态化,sessionId 会自动出现在这里。
2293
- getSessionId: () => transport?.sessionId,
2294
- lang: input.serverOptions.lang,
2295
- pluginsEnabled: input.serverOptions.pluginsEnabled,
2296
- pluginsDisabled: input.serverOptions.pluginsDisabled,
2297
- });
2298
- input.logger?.({
2299
- type: "cloudbase-mcp-server-create",
2300
- timeCost: Date.now() - startedAt,
2301
- });
2302
- transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
2303
- sessionIdGenerator: undefined,
2304
- enableJsonResponse: true,
2407
+ await (0, env_binding_js_1.runWithEnvSlot)(requestSlot, async () => {
2408
+ server = await (0, server_js_1.createCloudBaseMcpServer)({
2409
+ name: input.serverOptions.name,
2410
+ version: input.serverOptions.version,
2411
+ enableTelemetry: input.serverOptions.enableTelemetry,
2412
+ cloudBaseOptions: input.serverOptions.cloudBaseOptions,
2413
+ cloudMode: input.serverOptions.cloudMode ?? true,
2414
+ ide: input.serverOptions.ide,
2415
+ client: input.serverOptions.client,
2416
+ clientInfo,
2417
+ // Session id comes from this transport. Stateless mode leaves it undefined.
2418
+ getSessionId: () => transport?.sessionId,
2419
+ lang: input.serverOptions.lang,
2420
+ pluginsEnabled: input.serverOptions.pluginsEnabled,
2421
+ pluginsDisabled: input.serverOptions.pluginsDisabled,
2422
+ });
2423
+ input.logger?.({
2424
+ type: "cloudbase-mcp-server-create",
2425
+ timeCost: Date.now() - startedAt,
2426
+ });
2427
+ transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
2428
+ sessionIdGenerator: undefined,
2429
+ enableJsonResponse: true,
2430
+ });
2431
+ input.res.on("close", closeBoth);
2432
+ input.req.on("aborted", closeBoth);
2433
+ await server.connect(transport);
2434
+ await transport.handleRequest(input.req, input.res, input.body);
2305
2435
  });
2306
- input.res.on("close", closeBoth);
2307
- input.req.on("aborted", closeBoth);
2308
- await server.connect(transport);
2309
- await transport.handleRequest(input.req, input.res, input.body);
2310
2436
  }
2311
2437
  catch (error) {
2312
2438
  await Promise.allSettled([transport?.close(), server?.close()]);
@@ -9575,7 +9701,7 @@ __webpack_unused_export__ = buildEnvCreditsHtml;
9575
9701
  exports.registerEnvCreditsResource = registerEnvCreditsResource;
9576
9702
  const mcp_js_1 = __webpack_require__(4619);
9577
9703
  const index_js_1 = __webpack_require__(4908);
9578
- const cloudbase_manager_js_1 = __webpack_require__(3109);
9704
+ const env_binding_js_1 = __webpack_require__(1498);
9579
9705
  const site_map_js_1 = __webpack_require__(4533);
9580
9706
  const logger_js_1 = __webpack_require__(781);
9581
9707
  const telemetry_js_1 = __webpack_require__(5198);
@@ -9645,17 +9771,12 @@ function buildEnvCreditsConsoleUrl(key, envId, site) {
9645
9771
  return (0, site_map_js_1.getConsoleDevUrl)(envId ?? undefined, exports.BL[key], site);
9646
9772
  }
9647
9773
  /**
9648
- * 从 server 实例派生静态兜底值。
9649
- *
9650
- * 环境 ID 的取值优先级(与 get-started 同口径,新增来源时同步两处):
9651
- * ① 本次工具结果携带(面板侧覆盖,见 EnvCreditsPayload)
9652
- * → ② `server.cloudBaseOptions.envId` / `process.env.CLOUDBASE_ENV_ID`
9653
- * → ③ 进程缓存 `getCachedEnvId()`
9654
- * → ④ 降级:不显示 ID
9655
- * hosted 是无状态的,进程缓存不可靠,因此 ③ 只是本地兜底;面板永远以工具结果为准。
9774
+ * Static fallback until a tool result arrives.
9775
+ * Explicit `cloudBaseOptions.envId` wins. Otherwise the current slot.
9776
+ * Does not read `CLOUDBASE_ENV_ID` or the process cache.
9656
9777
  */
9657
9778
  function resolveEnvCreditsFallback(server) {
9658
- const envId = server.cloudBaseOptions?.envId || process.env.CLOUDBASE_ENV_ID || (0, cloudbase_manager_js_1.getCachedEnvId)() || null;
9779
+ const envId = (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId);
9659
9780
  const { site, region } = (0, site_map_js_1.resolveSiteAndRegion)({
9660
9781
  site: server.cloudBaseOptions?.site,
9661
9782
  region: server.cloudBaseOptions?.region,
@@ -10816,7 +10937,7 @@ exports.registerGetStartedResource = registerGetStartedResource;
10816
10937
  * 注入;`t()` 在 read 回调里求值,晚于 `setInstanceLang`,英文实例自动出英文。
10817
10938
  * 注入分两路:HTML 文本走 `escapeHtml`,脚本里的字符串走 `jsLiteral`(JSON 转义 +
10818
10939
  * 转义 `<`,避免 `</script>` 截断)。
10819
- * 3. **只读无密钥**:状态值只来自 `server.cloudBaseOptions` / 环境变量 / 缓存 / 站点解析,
10940
+ * 3. **只读无密钥**:环境 ID 来自这次调用槽;槽是空的才用 `server.cloudBaseOptions.envId`。不读环境变量和缓存。站点仍走站点解析。
10820
10941
  * 读资源时不发网络请求;面板自己只会发两类调用——只读的
10821
10942
  * `auth(action:"status")`(「重新检查」)和只改本地绑定的
10822
10943
  * `auth(action:"set_env")`(点「可选环境」里的一行)。两者都不动云端资源,也不碰密钥。
@@ -10837,7 +10958,7 @@ exports.registerGetStartedResource = registerGetStartedResource;
10837
10958
  */
10838
10959
  const mcp_js_1 = __webpack_require__(4619);
10839
10960
  const index_js_1 = __webpack_require__(4908);
10840
- const cloudbase_manager_js_1 = __webpack_require__(3109);
10961
+ const env_binding_js_1 = __webpack_require__(1498);
10841
10962
  const site_map_js_1 = __webpack_require__(4533);
10842
10963
  const logger_js_1 = __webpack_require__(781);
10843
10964
  const telemetry_js_1 = __webpack_require__(5198);
@@ -10881,12 +11002,9 @@ function escapeHtml(value) {
10881
11002
  function jsLiteral(value) {
10882
11003
  return JSON.stringify(value).replace(/</g, "\\u003c");
10883
11004
  }
10884
- /** 从 server 实例派生静态兜底状态;只读本地状态,不发起任何请求。 */
11005
+ /** Static fallback for the panel. Reads the current slot, then this server's explicit envId. No network. */
10885
11006
  function resolveGetStartedStatus(server) {
10886
- const envId = server.cloudBaseOptions?.envId ||
10887
- process.env.CLOUDBASE_ENV_ID ||
10888
- (0, cloudbase_manager_js_1.getCachedEnvId)() ||
10889
- null;
11007
+ const envId = (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId);
10890
11008
  const { site, region } = (0, site_map_js_1.resolveSiteAndRegion)({
10891
11009
  site: server.cloudBaseOptions?.site,
10892
11010
  region: server.cloudBaseOptions?.region,
@@ -11894,6 +12012,7 @@ const index_js_1 = __webpack_require__(4908);
11894
12012
  const schema_js_1 = __webpack_require__(6273);
11895
12013
  const server_instructions_js_1 = __webpack_require__(1808);
11896
12014
  const cloud_mode_js_1 = __webpack_require__(8694);
12015
+ const env_binding_js_1 = __webpack_require__(1498);
11897
12016
  const logger_js_1 = __webpack_require__(781);
11898
12017
  const site_map_js_1 = __webpack_require__(4533);
11899
12018
  const tool_result_js_1 = __webpack_require__(9645);
@@ -12082,6 +12201,8 @@ async function createCloudBaseMcpServer(options) {
12082
12201
  });
12083
12202
  // 初始化 toolDefs,用于外部提取工具列表(如微信 IDE)
12084
12203
  server.toolDefs = [];
12204
+ const envSlot = { binding: null };
12205
+ server.envSlot = envSlot;
12085
12206
  // 实例语言解析(须在工具注册前完成:registerTool 包装层按 lang 解析词典 key 形式的 description)
12086
12207
  server.lang = instanceLang;
12087
12208
  // 同步到 i18n 模块级 instanceLang:否则 t() 无 langOverride 时会退化成
@@ -12239,6 +12360,23 @@ async function createCloudBaseMcpServer(options) {
12239
12360
  // 产物卡片:挂在三个部署类工具上,只读展示部署状态与访问地址,写意图一律交给会话。
12240
12361
  (0, artifact_card_js_1.registerArtifactCardResource)(server);
12241
12362
  }
12363
+ const originalConnect = server.connect.bind(server);
12364
+ server.connect = async (transport) => {
12365
+ await originalConnect(transport);
12366
+ const deliver = transport.onmessage;
12367
+ if (!deliver) {
12368
+ return;
12369
+ }
12370
+ transport.onmessage = (message, extra) => {
12371
+ if ((0, env_binding_js_1.hasEnvSlot)()) {
12372
+ deliver(message, extra);
12373
+ return;
12374
+ }
12375
+ (0, env_binding_js_1.runWithEnvSlot)(envSlot, () => {
12376
+ deliver(message, extra);
12377
+ });
12378
+ };
12379
+ };
12242
12380
  return server;
12243
12381
  }
12244
12382
  /**
@@ -24276,6 +24414,7 @@ var __webpack_unused_export__;
24276
24414
  * - Error handling and telemetry reporting
24277
24415
  */
24278
24416
  __webpack_unused_export__ = ({ value: true });
24417
+ exports.TCB_PURCHASE_URL = void 0;
24279
24418
  exports.checkAndInitTcbService = checkAndInitTcbService;
24280
24419
  exports.checkAndCreateFreeEnv = checkAndCreateFreeEnv;
24281
24420
  __webpack_unused_export__ = getUinForTelemetry;
@@ -24283,6 +24422,17 @@ const auth_js_1 = __webpack_require__(561);
24283
24422
  const index_js_1 = __webpack_require__(4908);
24284
24423
  const logger_js_1 = __webpack_require__(781);
24285
24424
  const telemetry_js_1 = __webpack_require__(5198);
24425
+ /**
24426
+ * 开通 CloudBase 环境的购买页。
24427
+ *
24428
+ * ⚠️ 别再写回 `/lowcode?buyType=tcb&channel=mcp`:那条路径现在 302 到 `/CloudBase`,
24429
+ * **重定向时把 query 全丢了**(实测 `location: https://buy.cloud.tencent.com/CloudBase`),
24430
+ * 用户会落到购买页首页、来源标记也一起丢。
24431
+ *
24432
+ * ⚠️ `region` / `sqlType` 是写死的:国内站默认 ap-shanghai + PG 版。国际站
24433
+ * (`buy.tencentcloud.com`)的域名与路径同构性未验证,见 `specs/site-domain-governance`。
24434
+ */
24435
+ exports.TCB_PURCHASE_URL = "https://buy.cloud.tencent.com/CloudBase?buyType=tcb&region=ap-shanghai&sqlType=pg";
24286
24436
  /**
24287
24437
  * Parse InitTcb error and extract user-friendly information
24288
24438
  */
@@ -24305,7 +24455,7 @@ function parseInitTcbError(err) {
24305
24455
  const errorInfo = {
24306
24456
  code: errorCode,
24307
24457
  message: friendlyMessage,
24308
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp",
24458
+ helpUrl: exports.TCB_PURCHASE_URL,
24309
24459
  actionText,
24310
24460
  requestId
24311
24461
  };
@@ -24541,7 +24691,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
24541
24691
  newContext.createEnvError = {
24542
24692
  code: "NoPromotionalActivity",
24543
24693
  message: (0, index_js_1.t)("envSetup.noPromotionalActivity"),
24544
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp"
24694
+ helpUrl: exports.TCB_PURCHASE_URL
24545
24695
  };
24546
24696
  return {
24547
24697
  success: false,
@@ -24607,7 +24757,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
24607
24757
  newContext.createEnvError = {
24608
24758
  code: "InvalidEnvId",
24609
24759
  message: (0, index_js_1.t)("envSetup.invalidEnvId"),
24610
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp"
24760
+ helpUrl: exports.TCB_PURCHASE_URL
24611
24761
  };
24612
24762
  return {
24613
24763
  success: false,
@@ -24668,7 +24818,7 @@ async function checkAndCreateFreeEnv(cloudbase, context) {
24668
24818
  newContext.createEnvError = {
24669
24819
  code: createErr.code || createErr.Code || "UnknownError",
24670
24820
  message: errorMessage,
24671
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp"
24821
+ helpUrl: exports.TCB_PURCHASE_URL
24672
24822
  };
24673
24823
  (0, logger_js_1.debug)('[env-setup] CreateFreeEnvByActivity failed:', {
24674
24824
  code: newContext.createEnvError.code,
@@ -24767,12 +24917,14 @@ const cloudbase_manager_js_1 = __webpack_require__(3109);
24767
24917
  const logger_js_1 = __webpack_require__(781);
24768
24918
  const site_map_js_1 = __webpack_require__(4533);
24769
24919
  const project_config_js_1 = __webpack_require__(9175);
24920
+ const describe_envs_query_js_1 = __webpack_require__(1284);
24770
24921
  const index_js_1 = __webpack_require__(4908);
24771
24922
  const tool_result_js_1 = __webpack_require__(9645);
24772
24923
  const gateway_access_urls_js_1 = __webpack_require__(4173);
24773
24924
  const env_setup_js_1 = __webpack_require__(7528);
24774
24925
  const env_credits_payload_js_1 = __webpack_require__(3880);
24775
24926
  const mcp_ui_js_1 = __webpack_require__(5880);
24927
+ const env_setup_js_2 = __webpack_require__(7528);
24776
24928
  /**
24777
24929
  * Resources accepted by CreateEnv. Matches Cloud API / Manager SDK contract.
24778
24930
  * `postgresql` enables CloudBase PostgreSQL (PG mode) when supported by the package.
@@ -25561,7 +25713,7 @@ async function prepareAuthEnvironment(params) {
25561
25713
  reason: "tcb_init_failed",
25562
25714
  errorCode: "TCB_INIT_FAILED",
25563
25715
  message: (0, index_js_1.t)("env.prepare.tcbInitFailed"),
25564
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp",
25716
+ helpUrl: env_setup_js_2.TCB_PURCHASE_URL,
25565
25717
  });
25566
25718
  return {
25567
25719
  currentEnvId: null,
@@ -25614,7 +25766,7 @@ async function prepareAuthEnvironment(params) {
25614
25766
  reason: "env_creation_failed",
25615
25767
  errorCode: "ENV_CREATION_FAILED",
25616
25768
  message: (0, index_js_1.t)("env.prepare.envCreateFailed"),
25617
- helpUrl: "https://buy.cloud.tencent.com/lowcode?buyType=tcb&channel=mcp",
25769
+ helpUrl: env_setup_js_2.TCB_PURCHASE_URL,
25618
25770
  });
25619
25771
  const failureMessage = userNotice
25620
25772
  ? `${userNotice}\n${createFailure.message}`
@@ -27294,11 +27446,8 @@ function registerEnvTools(server) {
27294
27446
  // Filter parameters match the reference conditions provided by user
27295
27447
  result = await cloudbaseList.commonService("tcb", "2018-06-08").call({
27296
27448
  Action: "DescribeEnvs",
27297
- Param: {
27298
- EnvTypes: ["weda", "baas"], // Include weda and baas (normal) environments
27299
- IsVisible: false, // Filter out invisible environments
27300
- Channels: ["dcloud", "iotenable", "tem", "scene_module"], // Filter special channels
27301
- },
27449
+ // 过滤口径与 cloudbase-manager 共用一份,别在这里另写白名单
27450
+ Param: (0, describe_envs_query_js_1.buildDescribeEnvsFilter)(),
27302
27451
  });
27303
27452
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
27304
27453
  // Transform response format to match original listEnvs() format
@@ -40581,7 +40730,7 @@ __webpack_unused_export__ = readSkipList;
40581
40730
  __webpack_unused_export__ = isSkipped;
40582
40731
  __webpack_unused_export__ = readAutoApprovePolicy;
40583
40732
  exports.guardDestructiveAction = guardDestructiveAction;
40584
- const cloudbase_manager_js_1 = __webpack_require__(3109);
40733
+ const env_binding_js_1 = __webpack_require__(1498);
40585
40734
  const index_js_1 = __webpack_require__(4908);
40586
40735
  const elicitation_js_1 = __webpack_require__(5048);
40587
40736
  const destructive_actions_js_1 = __webpack_require__(2827);
@@ -40650,16 +40799,7 @@ function readAutoApprovePolicy() {
40650
40799
  return "allow";
40651
40800
  }
40652
40801
  function resolveEnvId(server) {
40653
- const fromOptions = server.cloudBaseOptions?.envId;
40654
- if (typeof fromOptions === "string" && fromOptions.length > 0) {
40655
- return fromOptions;
40656
- }
40657
- try {
40658
- return (0, cloudbase_manager_js_1.getCachedEnvId)() ?? (0, index_js_1.t)("confirmation.message.unknownEnv");
40659
- }
40660
- catch {
40661
- return (0, index_js_1.t)("confirmation.message.unknownEnv");
40662
- }
40802
+ return (0, env_binding_js_1.readDisplayedEnvId)(server.cloudBaseOptions?.envId) ?? (0, index_js_1.t)("confirmation.message.unknownEnv");
40663
40803
  }
40664
40804
  function blockedText(status, actionKey, targetInfo, params) {
40665
40805
  const keyByStatus = {
@@ -41027,6 +41167,47 @@ async function guardCredentialWrite(server, params) {
41027
41167
  }
41028
41168
 
41029
41169
 
41170
+ /***/ },
41171
+
41172
+ /***/ 1284
41173
+ (__unused_webpack_module, exports) {
41174
+
41175
+ var __webpack_unused_export__;
41176
+
41177
+ /**
41178
+ * 账号级 DescribeEnvs 的查询口径 —— 唯一真源。
41179
+ *
41180
+ * EnvTypes 是白名单语义(不为空时以该字段为准):少写一个值不会报错,只会静默
41181
+ * 少一类环境。2026-10 的客户案例就是这样:平台侧代建的环境 EnvType=platform,
41182
+ * 控制台能列、MCP 拉不到,用户看到的是「请先创建环境」,现场没有任何错误可看。
41183
+ *
41184
+ * - baas / weda:标准云开发、微搭,MCP 工具主要面向这两类
41185
+ * - platform:平台侧代建的环境(site-* 一类),控制台列这类
41186
+ *
41187
+ * 未纳入 hosting / run(云托管)、tcbgw、paas:MCP 历史上就没列过,加进来会让
41188
+ * 用户在环境候选里看到一堆用不了的托管环境。授权页那份白名单多一个 hosting,
41189
+ * 是历史原因,两边差异是有意的。
41190
+ */
41191
+ __webpack_unused_export__ = ({ value: true });
41192
+ exports.hI = exports.jC = void 0;
41193
+ exports.buildDescribeEnvsFilter = buildDescribeEnvsFilter;
41194
+ /** 允许出现在环境候选列表里的 EnvType */
41195
+ exports.jC = ["baas", "weda", "platform"];
41196
+ /**
41197
+ * IsVisible=false 表示 Channels 是「排除列表」:
41198
+ * 这 4 个渠道创建的环境不参与环境候选,其余渠道(含控制台的 qc_console)正常返回。
41199
+ */
41200
+ exports.hI = ["dcloud", "iotenable", "tem", "scene_module"];
41201
+ /** 生成 DescribeEnvs 的 Param 过滤段;每次返回新数组,避免调用方改到共享常量 */
41202
+ function buildDescribeEnvsFilter() {
41203
+ return {
41204
+ EnvTypes: [...exports.jC],
41205
+ IsVisible: false,
41206
+ Channels: [...exports.hI],
41207
+ };
41208
+ }
41209
+
41210
+
41030
41211
  /***/ },
41031
41212
 
41032
41213
  /***/ 2827
@@ -41377,6 +41558,212 @@ function resolveDestructiveAction(toolName, args) {
41377
41558
  }
41378
41559
 
41379
41560
 
41561
+ /***/ },
41562
+
41563
+ /***/ 6953
41564
+ (__unused_webpack_module, exports, __webpack_require__) {
41565
+
41566
+
41567
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41568
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41569
+ };
41570
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
41571
+ exports.readSystemAnchor = readSystemAnchor;
41572
+ exports.physicalMacAddresses = physicalMacAddresses;
41573
+ exports.collectHostSignal = collectHostSignal;
41574
+ exports.computeDeviceId = computeDeviceId;
41575
+ const crypto_1 = __importDefault(__webpack_require__(7823));
41576
+ const child_process_1 = __webpack_require__(5814);
41577
+ const fs_1 = __importDefault(__webpack_require__(4421));
41578
+ const os_1 = __importDefault(__webpack_require__(8116));
41579
+ /**
41580
+ * 匿名设备指纹。
41581
+ *
41582
+ * 为什么要有这个文件:旧实现是 `sha256(hostname | CPU model | 全部非内部网卡 MAC)`,
41583
+ * 锚点选错了 —— macOS 开着「私有 Wi-Fi 地址」时每个 SSID 一个随机 MAC,`awdl0` / `llw0` /
41584
+ * `bridge0` 的 MAC 随系统状态漂移,容器里 hostname 和 MAC 每次重建都变。结果是同一台 Mac
41585
+ * 一天能上报成几十个「设备」(2026-10-26 实测:Mac 指纹 82% 只在那一天出现过,
41586
+ * Windows 同口径 22%)。
41587
+ *
41588
+ * 现在的取值顺序:
41589
+ * 1. 系统级不可变标识 —— macOS `IOPlatformUUID`、Windows `MachineGuid`、Linux `/etc/machine-id`;
41590
+ * 2. 取不到时退到 `hostname + CPU model + 过滤后的物理网卡 MAC`;
41591
+ * 3. 再取不到只留 `hostname + CPU model`。
41592
+ *
41593
+ * 三条纪律:
41594
+ * - **格式不变**:仍是 SHA256 前 32 位 hex,灯塔 `A2` 字段与后端都不用改。
41595
+ * - **绝不用随机数兜底**。旧实现取不到信息时 `crypto.randomBytes(16)`,等于每次启动都是
41596
+ * 一台新设备 —— 正是要消灭的行为。宁可所有机器共用一个弱指纹,也不要一堆假设备。
41597
+ * - **只在构造时跑一次**。锚点要起子进程(`ioreg` / `reg`),1s 超时就降级,
41598
+ * 绝不放进每次上报的路径。
41599
+ *
41600
+ * 口径变化(换锚点当天就会看到,报表侧要提前打招呼):
41601
+ * - 历史 `A2` 全部失效,老设备会以新指纹重新出现 —— 报表上「装机量跳一下」不是增长。
41602
+ * - 容器内多实例若共享镜像固化的 `/etc/machine-id`,会被合并成同一台设备(以前是各算一个新设备)。
41603
+ */
41604
+ /** 取系统级锚点的子进程超时:超了直接降级,不能拖慢进程启动 */
41605
+ const ANCHOR_TIMEOUT_MS = 1000;
41606
+ /**
41607
+ * 虚拟 / 隧道网卡名前缀(小写比较)。这些接口的 MAC 会随系统状态漂移或每次重建都变,
41608
+ * 拼进指纹就等于给同一台机器发新身份。
41609
+ */
41610
+ const VIRTUAL_NIC_PREFIXES = [
41611
+ 'awdl', // Apple Wireless Direct Link
41612
+ 'llw', // Apple 低延迟 WLAN
41613
+ 'bridge', // macOS / Windows 网桥
41614
+ 'utun', // macOS / iOS VPN 隧道
41615
+ 'tun',
41616
+ 'tap',
41617
+ 'veth', // 容器 veth pair
41618
+ 'docker',
41619
+ 'br-', // docker bridge
41620
+ 'vmnet', // VMware
41621
+ 'vboxnet', // VirtualBox
41622
+ 'vether', // Hyper-V 虚拟交换机(vEthernet)
41623
+ 'zt', // ZeroTier
41624
+ 'tailscale',
41625
+ 'wg', // WireGuard
41626
+ 'lo', // loopback(正常情况下 internal 已过滤,兜一层)
41627
+ ];
41628
+ function sha256Short(input) {
41629
+ return crypto_1.default.createHash('sha256').update(input).digest('hex').substring(0, 32);
41630
+ }
41631
+ /** `machine-id` 合法值:16–64 位 hex,且不能是全 0(有些镜像里就是全 0 的空壳) */
41632
+ function isUsableMachineId(value) {
41633
+ if (!/^[0-9a-f]{16,64}$/i.test(value)) {
41634
+ return false;
41635
+ }
41636
+ return !/^0+$/.test(value);
41637
+ }
41638
+ function readFileQuietly(filePath) {
41639
+ try {
41640
+ return fs_1.default.readFileSync(filePath, 'utf8').trim();
41641
+ }
41642
+ catch {
41643
+ return undefined;
41644
+ }
41645
+ }
41646
+ /** 起一次子进程读锚点。超时 / 不存在 / 权限不足一律返回 undefined,由调用方降级。 */
41647
+ function execQuietly(file, args) {
41648
+ try {
41649
+ return (0, child_process_1.execFileSync)(file, args, {
41650
+ timeout: ANCHOR_TIMEOUT_MS,
41651
+ encoding: 'utf8',
41652
+ // 子进程的 stderr 全部吞掉:`ioreg` 在受限环境会打噪音,`reg` 在 32 位 Node
41653
+ // 下可能报找不到键,这些都不该出现在 MCP 的 stdout(stdio transport 上是协议流)
41654
+ stdio: ['ignore', 'pipe', 'ignore'],
41655
+ windowsHide: true,
41656
+ });
41657
+ }
41658
+ catch {
41659
+ return undefined;
41660
+ }
41661
+ }
41662
+ /**
41663
+ * 读系统级不可变标识。**只读一次**,失败即降级。
41664
+ * `platform` 参数只为测试注入,正常运行不传。
41665
+ */
41666
+ function readSystemAnchor(platform = process.platform) {
41667
+ if (platform === 'darwin') {
41668
+ const out = execQuietly('ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice']);
41669
+ const matched = out && /"IOPlatformUUID"\s*=\s*"([^"]+)"/.exec(out);
41670
+ if (matched?.[1]) {
41671
+ return { value: matched[1].trim(), source: 'platform-uuid' };
41672
+ }
41673
+ return undefined;
41674
+ }
41675
+ if (platform === 'win32') {
41676
+ const out = execQuietly('reg', [
41677
+ 'query',
41678
+ 'HKLM\\SOFTWARE\\Microsoft\\Cryptography',
41679
+ '/v',
41680
+ 'MachineGuid',
41681
+ ]);
41682
+ // 形如:` MachineGuid REG_SZ 3f2a....`(分隔符是多个空格或 tab)
41683
+ const matched = out && /MachineGuid\s+REG_SZ\s+([0-9a-fA-F-]{8,})/.exec(out);
41684
+ if (matched?.[1]) {
41685
+ return { value: matched[1].trim().toLowerCase(), source: 'machine-guid' };
41686
+ }
41687
+ return undefined;
41688
+ }
41689
+ // linux / openharmony / 其他类 Unix:先 /etc/machine-id,再 dbus 那份
41690
+ for (const candidate of ['/etc/machine-id', '/var/lib/dbus/machine-id']) {
41691
+ const raw = readFileQuietly(candidate);
41692
+ if (raw && isUsableMachineId(raw)) {
41693
+ return { value: raw.toLowerCase(), source: 'machine-id' };
41694
+ }
41695
+ }
41696
+ return undefined;
41697
+ }
41698
+ function isVirtualNic(name) {
41699
+ const lower = name.toLowerCase();
41700
+ return VIRTUAL_NIC_PREFIXES.some((prefix) => lower.startsWith(prefix));
41701
+ }
41702
+ /**
41703
+ * 非内部、非虚拟、MAC 不是全 0 / 广播地址的网卡 MAC,去重后排序。
41704
+ * 排序是为了让指纹与网卡枚举顺序无关(枚举顺序在重启后可能变)。
41705
+ */
41706
+ function physicalMacAddresses(interfaces = os_1.default.networkInterfaces()) {
41707
+ const macs = new Set();
41708
+ for (const [name, list] of Object.entries(interfaces)) {
41709
+ if (!list || isVirtualNic(name)) {
41710
+ continue;
41711
+ }
41712
+ for (const nic of list) {
41713
+ const mac = nic?.mac?.toLowerCase();
41714
+ if (!nic || nic.internal || !mac) {
41715
+ continue;
41716
+ }
41717
+ if (mac === '00:00:00:00:00:00' || mac === 'ff:ff:ff:ff:ff:ff') {
41718
+ continue;
41719
+ }
41720
+ macs.add(mac);
41721
+ }
41722
+ }
41723
+ return [...macs].sort();
41724
+ }
41725
+ /** 取不到系统锚点时的兜底信号:**不含虚拟网卡**,主机名与 CPU 型号足够稳。 */
41726
+ function collectHostSignal() {
41727
+ let hostname = 'unknown-host';
41728
+ try {
41729
+ hostname = os_1.default.hostname() || hostname;
41730
+ }
41731
+ catch {
41732
+ // 主机名读不到不影响降级:CPU + MAC 仍可用
41733
+ }
41734
+ let cpu = '';
41735
+ try {
41736
+ cpu = os_1.default
41737
+ .cpus()
41738
+ .map((item) => item.model)
41739
+ .join(',');
41740
+ }
41741
+ catch {
41742
+ // 同上
41743
+ }
41744
+ let macs = [];
41745
+ try {
41746
+ macs = physicalMacAddresses();
41747
+ }
41748
+ catch {
41749
+ // 同上
41750
+ }
41751
+ const parts = [hostname, cpu, ...macs].filter((part) => Boolean(part));
41752
+ return {
41753
+ value: parts.join('|'),
41754
+ source: macs.length > 0 ? 'host-fallback' : 'host-only',
41755
+ };
41756
+ }
41757
+ /**
41758
+ * 计算匿名设备指纹(SHA256 前 32 位 hex),并返回这次用的锚点来源 ——
41759
+ * 来源只进 debug 日志,用于上线后确认「到底有多少机器走到了兜底」。
41760
+ */
41761
+ function computeDeviceId(platform = process.platform) {
41762
+ const anchor = readSystemAnchor(platform) ?? collectHostSignal();
41763
+ return { deviceId: sha256Short(anchor.value), source: anchor.source };
41764
+ }
41765
+
41766
+
41380
41767
  /***/ },
41381
41768
 
41382
41769
  /***/ 5048
@@ -41517,6 +41904,112 @@ async function requestChoiceElicitation(server, params) {
41517
41904
  }
41518
41905
 
41519
41906
 
41907
+ /***/ },
41908
+
41909
+ /***/ 1498
41910
+ (__unused_webpack_module, exports, __webpack_require__) {
41911
+
41912
+
41913
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
41914
+ exports.ENV_SOURCES = void 0;
41915
+ exports.noteEnvBinding = noteEnvBinding;
41916
+ exports.clearEnvBinding = clearEnvBinding;
41917
+ exports.hasEnvSlot = hasEnvSlot;
41918
+ exports.readReportedEnv = readReportedEnv;
41919
+ exports.readDisplayedEnvId = readDisplayedEnvId;
41920
+ exports.runWithEnvSlot = runWithEnvSlot;
41921
+ exports.runInEnvSlot = runInEnvSlot;
41922
+ exports.peekLocalEnvBinding = peekLocalEnvBinding;
41923
+ const node_async_hooks_1 = __webpack_require__(4579);
41924
+ const project_config_js_1 = __webpack_require__(9175);
41925
+ /**
41926
+ * Where this resolution got its env id.
41927
+ * The first four values are already in shipped queries. Do not rename them.
41928
+ * `default` stays `default` (an empty result, not a rename to `unresolved`).
41929
+ */
41930
+ exports.ENV_SOURCES = [
41931
+ "cloudBaseOptions",
41932
+ "process.env.CLOUDBASE_ENV_ID",
41933
+ "envManager.cachedEnvId",
41934
+ "project",
41935
+ "login_state",
41936
+ "auto_bound",
41937
+ "default",
41938
+ ];
41939
+ const envCall = new node_async_hooks_1.AsyncLocalStorage();
41940
+ function isReportableEnvId(envId) {
41941
+ return !!envId && envId !== "local" && envId !== "unknown";
41942
+ }
41943
+ /** Write into the current slot. Outside a slot this is a no-op and does not touch process globals. */
41944
+ function noteEnvBinding(binding) {
41945
+ const slot = envCall.getStore();
41946
+ if (!slot || binding.source === "default" || !isReportableEnvId(binding.envId)) {
41947
+ return;
41948
+ }
41949
+ slot.binding = { envId: binding.envId, source: binding.source };
41950
+ }
41951
+ function clearEnvBinding() {
41952
+ const slot = envCall.getStore();
41953
+ if (slot) {
41954
+ slot.binding = null;
41955
+ }
41956
+ }
41957
+ function hasEnvSlot() {
41958
+ return envCall.getStore() !== undefined;
41959
+ }
41960
+ function readReportedEnv() {
41961
+ const binding = envCall.getStore()?.binding;
41962
+ if (!binding || binding.source === "default" || !isReportableEnvId(binding.envId)) {
41963
+ return { envId: "unknown", envIdSource: "default" };
41964
+ }
41965
+ return { envId: binding.envId, envIdSource: binding.source };
41966
+ }
41967
+ /**
41968
+ * Env id shown on the start page, the usage card, and confirmation text.
41969
+ * An explicit envId on this call wins, matching the resolver ladder.
41970
+ * Otherwise the current slot (login state, project, cache, or env var already noted).
41971
+ * Does not read process.env or the manager cache: on a hosted request those belong to the server machine.
41972
+ */
41973
+ function readDisplayedEnvId(explicitEnvId) {
41974
+ if (isReportableEnvId(explicitEnvId)) {
41975
+ return explicitEnvId;
41976
+ }
41977
+ const reported = readReportedEnv();
41978
+ if (reported.envIdSource !== "default") {
41979
+ return reported.envId;
41980
+ }
41981
+ return null;
41982
+ }
41983
+ function runWithEnvSlot(slot, fn) {
41984
+ return envCall.run(slot, fn);
41985
+ }
41986
+ /** One fresh slot. Tests and any caller that must not share another request's binding. */
41987
+ function runInEnvSlot(fn) {
41988
+ return envCall.run({ binding: null }, fn);
41989
+ }
41990
+ /**
41991
+ * Read-only snapshot for process start. Does not call setEnvId and does not list envs.
41992
+ * `cachedEnvId` is passed in so this module does not import the manager (that import cycles).
41993
+ */
41994
+ function peekLocalEnvBinding(input) {
41995
+ if (isReportableEnvId(input.cachedEnvId)) {
41996
+ return { envId: input.cachedEnvId, source: "envManager.cachedEnvId" };
41997
+ }
41998
+ const fromEnv = process.env.CLOUDBASE_ENV_ID;
41999
+ if (isReportableEnvId(fromEnv)) {
42000
+ return { envId: fromEnv, source: "process.env.CLOUDBASE_ENV_ID" };
42001
+ }
42002
+ const projectEnvId = (0, project_config_js_1.readProjectEnvId)();
42003
+ if (isReportableEnvId(projectEnvId)) {
42004
+ return { envId: projectEnvId, source: "project" };
42005
+ }
42006
+ if (isReportableEnvId(input.loginEnvId)) {
42007
+ return { envId: input.loginEnvId, source: "login_state" };
42008
+ }
42009
+ return { envId: null, source: "default" };
42010
+ }
42011
+
42012
+
41520
42013
  /***/ },
41521
42014
 
41522
42015
  /***/ 1194
@@ -43192,6 +43685,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
43192
43685
  };
43193
43686
  Object.defineProperty(exports, "__esModule", ({ value: true }));
43194
43687
  exports.reportToolkitSessionInitialized = exports.reportToolkitLifecycle = exports.reportResourceRead = exports.reportElicitationResult = exports.reportToolCall = exports.MCP_UI_EXTENSION = exports.telemetryReporter = void 0;
43688
+ exports.seedStdioEnvBinding = seedStdioEnvBinding;
43195
43689
  exports.extractMcpClientInfo = extractMcpClientInfo;
43196
43690
  exports.readMcpClientInfoFromServer = readMcpClientInfoFromServer;
43197
43691
  exports.normalizeClientName = normalizeClientName;
@@ -43205,6 +43699,8 @@ const os_1 = __importDefault(__webpack_require__(8116));
43205
43699
  const auth_js_1 = __webpack_require__(561);
43206
43700
  const cloudbase_manager_js_1 = __webpack_require__(3109);
43207
43701
  const cloud_mode_js_1 = __webpack_require__(8694);
43702
+ const env_binding_js_1 = __webpack_require__(1498);
43703
+ const device_id_js_1 = __webpack_require__(6953);
43208
43704
  const logger_js_1 = __webpack_require__(781);
43209
43705
  const site_map_js_1 = __webpack_require__(4533);
43210
43706
  /**
@@ -43260,7 +43756,7 @@ class TelemetryReporter {
43260
43756
  const arch = os_1.default.arch(); // 系统架构
43261
43757
  // Build-time injected version; guard for vitest / non-webpack runtimes.
43262
43758
  const mcpVersion = process.env.npm_package_version ||
43263
- ( true ? "2.36.1" : 0);
43759
+ ( true ? "2.36.2" : 0);
43264
43760
  return {
43265
43761
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
43266
43762
  deviceId: this.deviceId,
@@ -43273,26 +43769,25 @@ class TelemetryReporter {
43273
43769
  }
43274
43770
  /**
43275
43771
  * 获取设备唯一标识
43276
- * 基于主机名、CPU信息和MAC地址生成匿名设备指纹
43772
+ *
43773
+ * 锚点与降级顺序见 `utils/device-id.ts`:优先系统级不可变标识(IOPlatformUUID /
43774
+ * MachineGuid / machine-id),取不到才退到 hostname + CPU + 过滤后的物理网卡 MAC。
43775
+ * 容器里 hostname 每次重建都变、macOS 私有 Wi-Fi 地址让 MAC 随 SSID 漂移,
43776
+ * 两者都不能当锚点 —— 旧实现把它们全拼进去,同一台 Mac 一天能上报成几十个设备。
43777
+ *
43778
+ * 子进程(ioreg / reg)只在这里跑一次(构造时),1s 超时即降级。
43277
43779
  */
43278
43780
  getDeviceId() {
43279
43781
  try {
43280
- // 获取设备信息组合
43281
- const deviceInfo = [
43282
- os_1.default.hostname(),
43283
- os_1.default.cpus().map((cpu) => cpu.model).join(','),
43284
- Object.values(os_1.default.networkInterfaces())
43285
- .reduce((acc, val) => acc.concat(val || []), [])
43286
- .filter((nic) => nic && !nic.internal && nic.mac)
43287
- .map((nic) => nic.mac)
43288
- .join(',')
43289
- ].join('|');
43290
- // 生成SHA256哈希作为设备ID
43291
- return crypto_1.default.createHash('sha256').update(deviceInfo).digest('hex').substring(0, 32);
43782
+ const { deviceId, source } = (0, device_id_js_1.computeDeviceId)();
43783
+ (0, logger_js_1.debug)('device_id_resolved', { source, deviceId: deviceId.substring(0, 8) + '...' });
43784
+ return deviceId;
43292
43785
  }
43293
43786
  catch (err) {
43294
- // 如果获取设备信息失败,生成随机ID
43295
- return crypto_1.default.randomBytes(16).toString('hex');
43787
+ // 走到这里说明连 hostname / CPU 都读不到:用固定串兜底,**绝不能**用随机数
43788
+ // (随机数等于每次启动都是一台新设备,正是这次要消灭的行为)。
43789
+ (0, logger_js_1.debug)('获取设备标识失败,回落到固定串', err instanceof Error ? err : new Error(String(err)));
43790
+ return crypto_1.default.createHash('sha256').update('cloudbase-mcp|no-device-signal').digest('hex').substring(0, 32);
43296
43791
  }
43297
43792
  }
43298
43793
  /**
@@ -43408,39 +43903,40 @@ class TelemetryReporter {
43408
43903
  // 创建全局实例
43409
43904
  exports.telemetryReporter = new TelemetryReporter();
43410
43905
  /**
43411
- * 解析环境ID
43412
- * 优先级:传入配置 > envManager缓存 > 环境变量 > unknown
43906
+ * Reports read the current AsyncLocalStorage slot.
43907
+ * They do not re-read envManager or CLOUDBASE_ENV_ID.
43908
+ * An explicit envId on this call is only used when the slot is still empty
43909
+ * (hosted initialized, before a resolver runs, when the request already carried one).
43910
+ *
43911
+ * The source list lives in `env-binding.ts` (`ENV_SOURCES`) — one definition only.
43413
43912
  */
43414
43913
  function resolveEnvId(cloudBaseOptions) {
43415
- let envId = 'unknown';
43416
- let envIdSource = 'unknown';
43417
- try {
43418
- if (cloudBaseOptions?.envId) {
43419
- envId = cloudBaseOptions.envId;
43420
- envIdSource = 'cloudBaseOptions';
43421
- }
43422
- else {
43423
- const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
43424
- if (cachedEnvId) {
43425
- envId = cachedEnvId;
43426
- envIdSource = 'envManager.cachedEnvId';
43427
- }
43428
- else if (process.env.CLOUDBASE_ENV_ID) {
43429
- envId = process.env.CLOUDBASE_ENV_ID;
43430
- envIdSource = 'process.env.CLOUDBASE_ENV_ID';
43431
- }
43432
- else {
43433
- envId = 'unknown';
43434
- envIdSource = 'default';
43435
- }
43436
- }
43914
+ const reported = (0, env_binding_js_1.readReportedEnv)();
43915
+ if (reported.envIdSource !== "default") {
43916
+ return reported;
43437
43917
  }
43438
- catch (err) {
43439
- (0, logger_js_1.debug)('获取环境ID失败,遥测数据将使用 unknown', err instanceof Error ? err : new Error(String(err)));
43440
- envId = 'unknown';
43441
- envIdSource = 'error';
43918
+ if (cloudBaseOptions?.envId) {
43919
+ return { envId: cloudBaseOptions.envId, envIdSource: "cloudBaseOptions" };
43920
+ }
43921
+ return { envId: "unknown", envIdSource: "default" };
43922
+ }
43923
+ /**
43924
+ * Stdio start: reuse the login warm (one peekLoginState per process) and one project-file read.
43925
+ * Does not call setEnvId and does not list environments. Cloud mode does not read local files.
43926
+ */
43927
+ async function seedStdioEnvBinding(slot) {
43928
+ if ((0, cloud_mode_js_1.isCloudMode)()) {
43929
+ return;
43930
+ }
43931
+ await warmLocalLoginState();
43932
+ const loginEnvId = typeof localLoginState?.envId === "string" ? localLoginState.envId : null;
43933
+ const binding = (0, env_binding_js_1.peekLocalEnvBinding)({
43934
+ cachedEnvId: (0, cloudbase_manager_js_1.getCachedEnvId)(),
43935
+ loginEnvId,
43936
+ });
43937
+ if (binding.envId && binding.source !== "default") {
43938
+ slot.binding = binding;
43442
43939
  }
43443
- return { envId, envIdSource };
43444
43940
  }
43445
43941
  /**
43446
43942
  * Normalize SDK Implementation / clientInfo into telemetry-safe fields.
@@ -43747,6 +44243,9 @@ const reportToolCall = async (params) => {
43747
44243
  duration: params.duration !== undefined ? String(params.duration) : undefined,
43748
44244
  error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
43749
44245
  envId: envId || 'unknown',
44246
+ // 取值来源(cloudBaseOptions / envManager.cachedEnvId / process.env / default):
44247
+ // 这一列就是「envId 为什么是 unknown」的判据,别再靠猜
44248
+ envIdSource,
43750
44249
  region: siteRegion.region,
43751
44250
  site: siteRegion.site,
43752
44251
  login_uin: loginUin,
@@ -43760,6 +44259,13 @@ const reportToolCall = async (params) => {
43760
44259
  if (params.action !== undefined) {
43761
44260
  eventData.action = params.action;
43762
44261
  }
44262
+ // 环境准备结果:拿不到就不占列(与能力字段同一纪律,不写 unknown 假值)
44263
+ if (params.envSetupStatus !== undefined) {
44264
+ eventData.envSetupStatus = params.envSetupStatus;
44265
+ }
44266
+ if (params.envSetupFailReason !== undefined) {
44267
+ eventData.envSetupFailReason = params.envSetupFailReason;
44268
+ }
43763
44269
  // 添加入参信息(如果提供)
43764
44270
  if (params.inputParams !== undefined) {
43765
44271
  try {
@@ -43881,7 +44387,15 @@ const reportToolkitLifecycle = async (params) => {
43881
44387
  // 安全获取环境ID,优先使用传入的配置
43882
44388
  const { envId, envIdSource } = resolveEnvId(params.cloudBaseOptions);
43883
44389
  const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
43884
- const loginUin = await resolveLoginUin(params.cloudBaseOptions, { allowResolve: false });
44390
+ // `start` 在进程最早期发出:此时既没有宿主注入的 uin,也还没人 warm 过本地登录态。
44391
+ // 卡死 `allowResolve: false` 就只能读到空缓存 → 恒 'unknown'(2026-10-26 实测:这一列
44392
+ // 有真实 uin 的行是 0)。start 允许解析:`warmLocalLoginState()` 进程内只跑一次
44393
+ // (读本地 auth.json;临时密钥过期时可能续期一次,与工具调用本来就要付的开销同源),
44394
+ // 不会挂到每次上报上。
44395
+ // `exit` 仍保持不允许 —— 退出路径不能等,拿不到就是 unknown,`start` 那次已经把值带出去了。
44396
+ const loginUin = await resolveLoginUin(params.cloudBaseOptions, {
44397
+ allowResolve: params.event !== 'exit',
44398
+ });
43885
44399
  (0, logger_js_1.debug)('[telemetry] 生命周期事件 envId 获取结果', {
43886
44400
  event: params.event,
43887
44401
  envId,
@@ -43896,6 +44410,9 @@ const reportToolkitLifecycle = async (params) => {
43896
44410
  exitCode: params.exitCode !== undefined ? String(params.exitCode) : undefined,
43897
44411
  error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
43898
44412
  envId: envId || 'unknown',
44413
+ // 取值来源(cloudBaseOptions / envManager.cachedEnvId / process.env / default):
44414
+ // 这一列就是「envId 为什么是 unknown」的判据,别再靠猜
44415
+ envIdSource,
43899
44416
  region: siteRegion.region,
43900
44417
  site: siteRegion.site,
43901
44418
  login_uin: loginUin,
@@ -43952,12 +44469,15 @@ exports.reportToolkitLifecycle = reportToolkitLifecycle;
43952
44469
  */
43953
44470
  const reportToolkitSessionInitialized = async (params) => {
43954
44471
  const { nodeVersion, osType, osRelease, arch, mcpVersion } = exports.telemetryReporter.getUserAgent();
43955
- const { envId } = resolveEnvId(params.cloudBaseOptions);
44472
+ const { envId, envIdSource } = resolveEnvId(params.cloudBaseOptions);
43956
44473
  const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
43957
- const loginUin = await resolveLoginUin(params.cloudBaseOptions, { allowResolve: false });
44474
+ // 与 `start` 同理:`initialized` 紧跟在 `start` 之后,也是不允许等的分支就会白报一条 unknown。
44475
+ // 这里放开解析;若 `start` 已经 warm 过,这一句直接命中进程内缓存,零额外成本。
44476
+ const loginUin = await resolveLoginUin(params.cloudBaseOptions);
43958
44477
  const eventData = {
43959
44478
  event: 'initialized',
43960
44479
  envId: envId || 'unknown',
44480
+ envIdSource,
43961
44481
  region: siteRegion.region,
43962
44482
  site: siteRegion.site,
43963
44483
  login_uin: loginUin,
@@ -44131,7 +44651,6 @@ var __webpack_unused_export__;
44131
44651
  __webpack_unused_export__ = ({ value: true });
44132
44652
  exports.applyCategoryAnnotationMeta = applyCategoryAnnotationMeta;
44133
44653
  exports.wrapServerWithTelemetry = wrapServerWithTelemetry;
44134
- const cloudbase_manager_js_1 = __webpack_require__(3109);
44135
44654
  const cloud_mode_js_1 = __webpack_require__(8694);
44136
44655
  const logger_js_1 = __webpack_require__(781);
44137
44656
  const telemetry_js_1 = __webpack_require__(5198);
@@ -44194,8 +44713,56 @@ function contributionHint(server) {
44194
44713
  ].join("\n");
44195
44714
  }
44196
44715
  /**
44197
- * 创建包装后的处理函数,添加数据上报功能
44716
+ * 从 `auth` 的返回里取出「环境准备」的结果,供遥测上报。
44717
+ *
44718
+ * 为什么要从返回体里抠:`env_setup_status` / `env_setup_failure.reason` 只存在于
44719
+ * `auth` 的 payload 里,不是 `reportToolCall` 的入参。而工具 wrapper 是唯一同时
44720
+ * 看得见 args 和 result 的地方。
44721
+ *
44722
+ * 现状(2026-10-27):这两项只回给模型、没进埋点,于是「无环境的用户卡在购买页、
44723
+ * 实名、还是 CAM 授权」在数据里长得一模一样,加文案也无法验收。
44198
44724
  */
44725
+ function readEnvSetupOutcome(result) {
44726
+ const rec = result;
44727
+ if (!rec || typeof rec !== 'object')
44728
+ return undefined;
44729
+ // 优先 structuredContent(MCP 规范位),退到 content[0].text 里的 JSON
44730
+ const candidates = [];
44731
+ if (rec.structuredContent)
44732
+ candidates.push(rec.structuredContent);
44733
+ const content = Array.isArray(rec.content) ? rec.content : [];
44734
+ for (const item of content) {
44735
+ const text = item?.text;
44736
+ if (typeof text === 'string' && text.trim().startsWith('{')) {
44737
+ try {
44738
+ candidates.push(JSON.parse(text));
44739
+ }
44740
+ catch {
44741
+ /* 不是 JSON 就跳过,不要因为解析失败影响正常返回 */
44742
+ }
44743
+ }
44744
+ }
44745
+ for (const payload of candidates) {
44746
+ const p = payload;
44747
+ const status = typeof p?.env_setup_status === 'string' ? p.env_setup_status : undefined;
44748
+ if (!status)
44749
+ continue;
44750
+ const failure = p?.env_setup_failure;
44751
+ const reason = typeof failure?.reason === 'string' ? failure.reason : undefined;
44752
+ // 把两个布尔压进 reason 的后缀:一列就能看清「卡在哪」,
44753
+ // 单看 reason 只知道「建环境失败」,不知道是实名还是 CAM 授权拦住的
44754
+ const gates = [];
44755
+ if (failure?.need_real_name_auth === true)
44756
+ gates.push('realname');
44757
+ if (failure?.need_cam_auth === true)
44758
+ gates.push('cam');
44759
+ return {
44760
+ status,
44761
+ reason: reason ? (gates.length ? `${reason}+${gates.join('+')}` : reason) : undefined,
44762
+ };
44763
+ }
44764
+ return undefined;
44765
+ }
44199
44766
  /**
44200
44767
  * 工具自己返回的失败:结构化 `{ success: false }`(`isBusinessFailureToolResult` 已覆盖
44201
44768
  * 顶层 / structuredContent / JSON 文本三种挂法),**或**已经显式带 `isError: true` 的回执。
@@ -44215,7 +44782,7 @@ function isReturnedFailureResult(result) {
44215
44782
  * 所以两条路径对同一个底层错误得到的文本逐字相同(🆔 RequestId + 📦 版本页脚都在这里)。
44216
44783
  */
44217
44784
  function buildFailureClientText(errorMessage, requestId, server) {
44218
- const mcpVersion = true ? "2.36.1" : 0;
44785
+ const mcpVersion = true ? "2.36.2" : 0;
44219
44786
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
44220
44787
  return `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n${contributionHint(server)}`;
44221
44788
  }
@@ -44275,12 +44842,18 @@ function withEnhancedFailureText(result, errorMessage, requestId, server) {
44275
44842
  }
44276
44843
  return result;
44277
44844
  }
44845
+ /**
44846
+ * 创建包装后的处理函数,添加数据上报功能
44847
+ */
44278
44848
  function createWrappedHandler(name, handler, server) {
44279
44849
  return async (args, extra) => {
44280
44850
  const startTime = Date.now();
44281
44851
  let success = false;
44282
44852
  let errorMessage;
44283
44853
  let requestId;
44854
+ // 提到 try 外:finally 里要读 auth 的环境准备结果(env_setup_status / failure.reason)。
44855
+ // 护栏拦截的早退路径不会赋值,finally 里按 undefined 处理。
44856
+ let result;
44284
44857
  try {
44285
44858
  (0, logger_js_1.debug)(`开始执行工具: ${name}`, { args: sanitizeArgs(args) });
44286
44859
  // In test environment, skip logger to avoid potential blocking
@@ -44312,7 +44885,7 @@ function createWrappedHandler(name, handler, server) {
44312
44885
  return guardDecision.result;
44313
44886
  }
44314
44887
  // 执行原始处理函数(extra 一并透传,工具可据此拿到在途请求 id)
44315
- const result = await handler(args, extra);
44888
+ result = await handler(args, extra);
44316
44889
  // 工具**自己返回**的失败(`{ success: false }` 结构化载荷,或已经带 `isError: true` 的
44317
44890
  // 失败回执)与"抛错"是同一件事:遥测要按失败记,文案要吃同一套收尾(增强 + RequestId +
44318
44891
  // 版本页脚)。护栏拦截的返回走不到这里——它在上面就 return 了,且它的载荷既没有
@@ -44393,24 +44966,19 @@ function createWrappedHandler(name, handler, server) {
44393
44966
  const isTestEnvironment = false || process.env.VITEST === "true";
44394
44967
  if (!isTestEnvironment) {
44395
44968
  const duration = Date.now() - startTime;
44396
- // 如果 server.cloudBaseOptions 为空或没有 envId,尝试从缓存获取并更新
44397
- let cloudBaseOptions = server.cloudBaseOptions;
44398
- if (!cloudBaseOptions?.envId) {
44399
- const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
44400
- if (cachedEnvId) {
44401
- cloudBaseOptions = { ...cloudBaseOptions, envId: cachedEnvId };
44402
- }
44403
- }
44969
+ const envSetup = name === 'auth' ? readEnvSetupOutcome(result) : undefined;
44404
44970
  // 异步上报,不阻塞工具返回
44405
44971
  (0, telemetry_js_1.reportToolCall)({
44406
44972
  toolName: name,
44973
+ envSetupStatus: envSetup?.status,
44974
+ envSetupFailReason: envSetup?.reason,
44407
44975
  success,
44408
44976
  requestId,
44409
44977
  duration,
44410
44978
  error: errorMessage,
44411
44979
  inputParams: sanitizeArgs(args), // 添加入参上报
44412
44980
  action: args?.action, // 工具级 action(如 auth 的 status/set_env)
44413
- cloudBaseOptions: cloudBaseOptions, // 传递 CloudBase 配置(可能已更新)
44981
+ cloudBaseOptions: server.cloudBaseOptions,
44414
44982
  ide: server.ide || process.env.INTEGRATION_IDE, // 传递集成IDE信息
44415
44983
  client: server.client || process.env.CLOUDBASE_MCP_CLIENT, // 传递 MCP client 来源标识
44416
44984
  mcpClientInfo: (0, telemetry_js_1.readMcpClientInfoFromServer)(server),
@@ -44602,7 +45170,7 @@ var x = (y) => {
44602
45170
  var x = {}; __webpack_require__.d(x, y); return x
44603
45171
  }
44604
45172
  var y = (x) => (() => (x))
44605
- module.exports = x({ ["spawn"]: () => (__WEBPACK_EXTERNAL_MODULE_child_process__.spawn) });
45173
+ module.exports = x({ ["execFileSync"]: () => (__WEBPACK_EXTERNAL_MODULE_child_process__.execFileSync), ["spawn"]: () => (__WEBPACK_EXTERNAL_MODULE_child_process__.spawn) });
44606
45174
 
44607
45175
  /***/ },
44608
45176
 
@@ -44662,6 +45230,17 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_net__;
44662
45230
 
44663
45231
  /***/ },
44664
45232
 
45233
+ /***/ 4579
45234
+ (module, __unused_webpack_exports, __webpack_require__) {
45235
+
45236
+ var x = (y) => {
45237
+ var x = {}; __webpack_require__.d(x, y); return x
45238
+ }
45239
+ var y = (x) => (() => (x))
45240
+ module.exports = x({ ["AsyncLocalStorage"]: () => (__WEBPACK_EXTERNAL_MODULE_node_async_hooks_1fa35564__.AsyncLocalStorage) });
45241
+
45242
+ /***/ },
45243
+
44665
45244
  /***/ 2561
44666
45245
  (module, __unused_webpack_exports, __webpack_require__) {
44667
45246
 
@@ -44799,7 +45378,7 @@ var __webpack_exports__ = {};
44799
45378
  var exports = __webpack_exports__;
44800
45379
 
44801
45380
  Object.defineProperty(exports, "__esModule", ({ value: true }));
44802
- 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;
45381
+ 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;
44803
45382
  // CloudBase MCP Server Library
44804
45383
  var server_js_1 = __webpack_require__(6324);
44805
45384
  Object.defineProperty(exports, "createCloudBaseMcpServer", ({ enumerable: true, get: function () { return server_js_1.createCloudBaseMcpServer; } }));
@@ -44819,6 +45398,13 @@ Object.defineProperty(exports, "isCloudMode", ({ enumerable: true, get: function
44819
45398
  Object.defineProperty(exports, "enableCloudMode", ({ enumerable: true, get: function () { return cloud_mode_js_1.enableCloudMode; } }));
44820
45399
  Object.defineProperty(exports, "getCloudModeStatus", ({ enumerable: true, get: function () { return cloud_mode_js_1.getCloudModeStatus; } }));
44821
45400
  Object.defineProperty(exports, "shouldRegisterTool", ({ enumerable: true, get: function () { return cloud_mode_js_1.shouldRegisterTool; } }));
45401
+ /**
45402
+ * 环境绑定槽。外部宿主(自己起 transport 的那种)要上报真实的 envId,
45403
+ * 就得在自己的一次 run 里跑 server 的消息处理,否则上报恒为 `default`。
45404
+ */
45405
+ var env_binding_js_1 = __webpack_require__(1498);
45406
+ Object.defineProperty(exports, "ENV_SOURCES", ({ enumerable: true, get: function () { return env_binding_js_1.ENV_SOURCES; } }));
45407
+ Object.defineProperty(exports, "runWithEnvSlot", ({ enumerable: true, get: function () { return env_binding_js_1.runWithEnvSlot; } }));
44822
45408
  var cloudbase_manager_js_1 = __webpack_require__(3109);
44823
45409
  Object.defineProperty(exports, "getCloudBaseManager", ({ enumerable: true, get: function () { return cloudbase_manager_js_1.getCloudBaseManager; } }));
44824
45410
  Object.defineProperty(exports, "getEnvId", ({ enumerable: true, get: function () { return cloudbase_manager_js_1.getEnvId; } }));
@@ -44851,6 +45437,7 @@ Object.defineProperty(exports, "validateTimerCron", ({ enumerable: true, get: fu
44851
45437
  const __webpack_exports__ALL_SUPPORTED_RUNTIMES = __webpack_exports__.ALL_SUPPORTED_RUNTIMES;
44852
45438
  const __webpack_exports__DEFAULT_NODEJS_RUNTIME = __webpack_exports__.DEFAULT_NODEJS_RUNTIME;
44853
45439
  const __webpack_exports__DEFAULT_RUNTIME = __webpack_exports__.DEFAULT_RUNTIME;
45440
+ const __webpack_exports__ENV_SOURCES = __webpack_exports__.ENV_SOURCES;
44854
45441
  const __webpack_exports__HOSTED_CLIENT_INFO_CACHE_CAPACITY = __webpack_exports__.HOSTED_CLIENT_INFO_CACHE_CAPACITY;
44855
45442
  const __webpack_exports__HOSTED_CLIENT_INFO_CACHE_TTL_MS = __webpack_exports__.HOSTED_CLIENT_INFO_CACHE_TTL_MS;
44856
45443
  const __webpack_exports__RAW_IDE_FILE_MAPPINGS = __webpack_exports__.RAW_IDE_FILE_MAPPINGS;
@@ -44877,10 +45464,11 @@ const __webpack_exports__logout = __webpack_exports__.logout;
44877
45464
  const __webpack_exports__reportToolCall = __webpack_exports__.reportToolCall;
44878
45465
  const __webpack_exports__reportToolkitLifecycle = __webpack_exports__.reportToolkitLifecycle;
44879
45466
  const __webpack_exports__resetCloudBaseManagerCache = __webpack_exports__.resetCloudBaseManagerCache;
45467
+ const __webpack_exports__runWithEnvSlot = __webpack_exports__.runWithEnvSlot;
44880
45468
  const __webpack_exports__shouldRegisterTool = __webpack_exports__.shouldRegisterTool;
44881
45469
  const __webpack_exports__simplifyEnvList = __webpack_exports__.simplifyEnvList;
44882
45470
  const __webpack_exports__telemetryReporter = __webpack_exports__.telemetryReporter;
44883
45471
  const __webpack_exports__validateTimerCron = __webpack_exports__.validateTimerCron;
44884
45472
  const __webpack_exports__warmupHostedResources = __webpack_exports__.warmupHostedResources;
44885
45473
  const __webpack_exports__warn = __webpack_exports__.warn;
44886
- export { __webpack_exports__ALL_SUPPORTED_RUNTIMES as ALL_SUPPORTED_RUNTIMES, __webpack_exports__DEFAULT_NODEJS_RUNTIME as DEFAULT_NODEJS_RUNTIME, __webpack_exports__DEFAULT_RUNTIME as DEFAULT_RUNTIME, __webpack_exports__HOSTED_CLIENT_INFO_CACHE_CAPACITY as HOSTED_CLIENT_INFO_CACHE_CAPACITY, __webpack_exports__HOSTED_CLIENT_INFO_CACHE_TTL_MS as HOSTED_CLIENT_INFO_CACHE_TTL_MS, __webpack_exports__RAW_IDE_FILE_MAPPINGS as RAW_IDE_FILE_MAPPINGS, __webpack_exports__RECOMMENDED_RUNTIMES as RECOMMENDED_RUNTIMES, __webpack_exports__SUPPORTED_NODEJS_RUNTIMES as SUPPORTED_NODEJS_RUNTIMES, __webpack_exports__SUPPORTED_RUNTIMES as SUPPORTED_RUNTIMES, __webpack_exports__StdioServerTransport as StdioServerTransport, __webpack_exports___esModule as __esModule, __webpack_exports__createCloudBaseManagerWithOptions as createCloudBaseManagerWithOptions, __webpack_exports__createCloudBaseMcpServer as createCloudBaseMcpServer, __webpack_exports__enableCloudMode as enableCloudMode, __webpack_exports__envManager as envManager, __webpack_exports__error as error, __webpack_exports__formatRuntimeList as formatRuntimeList, __webpack_exports__getCloudBaseManager as getCloudBaseManager, __webpack_exports__getCloudModeStatus as getCloudModeStatus, __webpack_exports__getDefaultServer as getDefaultServer, __webpack_exports__getEnvId as getEnvId, __webpack_exports__getLoginState as getLoginState, __webpack_exports__handleHostedMcpRequest as handleHostedMcpRequest, __webpack_exports__info as info, __webpack_exports__isCloudMode as isCloudMode, __webpack_exports__logout as logout, __webpack_exports__reportToolCall as reportToolCall, __webpack_exports__reportToolkitLifecycle as reportToolkitLifecycle, __webpack_exports__resetCloudBaseManagerCache as resetCloudBaseManagerCache, __webpack_exports__shouldRegisterTool as shouldRegisterTool, __webpack_exports__simplifyEnvList as simplifyEnvList, __webpack_exports__telemetryReporter as telemetryReporter, __webpack_exports__validateTimerCron as validateTimerCron, __webpack_exports__warmupHostedResources as warmupHostedResources, __webpack_exports__warn as warn, __webpack_exports__ as default };
45474
+ export { __webpack_exports__ALL_SUPPORTED_RUNTIMES as ALL_SUPPORTED_RUNTIMES, __webpack_exports__DEFAULT_NODEJS_RUNTIME as DEFAULT_NODEJS_RUNTIME, __webpack_exports__DEFAULT_RUNTIME as DEFAULT_RUNTIME, __webpack_exports__ENV_SOURCES as ENV_SOURCES, __webpack_exports__HOSTED_CLIENT_INFO_CACHE_CAPACITY as HOSTED_CLIENT_INFO_CACHE_CAPACITY, __webpack_exports__HOSTED_CLIENT_INFO_CACHE_TTL_MS as HOSTED_CLIENT_INFO_CACHE_TTL_MS, __webpack_exports__RAW_IDE_FILE_MAPPINGS as RAW_IDE_FILE_MAPPINGS, __webpack_exports__RECOMMENDED_RUNTIMES as RECOMMENDED_RUNTIMES, __webpack_exports__SUPPORTED_NODEJS_RUNTIMES as SUPPORTED_NODEJS_RUNTIMES, __webpack_exports__SUPPORTED_RUNTIMES as SUPPORTED_RUNTIMES, __webpack_exports__StdioServerTransport as StdioServerTransport, __webpack_exports___esModule as __esModule, __webpack_exports__createCloudBaseManagerWithOptions as createCloudBaseManagerWithOptions, __webpack_exports__createCloudBaseMcpServer as createCloudBaseMcpServer, __webpack_exports__enableCloudMode as enableCloudMode, __webpack_exports__envManager as envManager, __webpack_exports__error as error, __webpack_exports__formatRuntimeList as formatRuntimeList, __webpack_exports__getCloudBaseManager as getCloudBaseManager, __webpack_exports__getCloudModeStatus as getCloudModeStatus, __webpack_exports__getDefaultServer as getDefaultServer, __webpack_exports__getEnvId as getEnvId, __webpack_exports__getLoginState as getLoginState, __webpack_exports__handleHostedMcpRequest as handleHostedMcpRequest, __webpack_exports__info as info, __webpack_exports__isCloudMode as isCloudMode, __webpack_exports__logout as logout, __webpack_exports__reportToolCall as reportToolCall, __webpack_exports__reportToolkitLifecycle as reportToolkitLifecycle, __webpack_exports__resetCloudBaseManagerCache as resetCloudBaseManagerCache, __webpack_exports__runWithEnvSlot as runWithEnvSlot, __webpack_exports__shouldRegisterTool as shouldRegisterTool, __webpack_exports__simplifyEnvList as simplifyEnvList, __webpack_exports__telemetryReporter as telemetryReporter, __webpack_exports__validateTimerCron as validateTimerCron, __webpack_exports__warmupHostedResources as warmupHostedResources, __webpack_exports__warn as warn, __webpack_exports__ as default };