@cloudbase/cloudbase-mcp 2.10.0 → 2.11.1

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
@@ -22401,11 +22401,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22401
22401
  Object.defineProperty(exports, "__esModule", ({ value: true }));
22402
22402
  exports.getPort = void 0;
22403
22403
  const portfinder_1 = __importDefault(__webpack_require__(31323));
22404
- const DEFAULT_PORT = 9012;
22404
+ // 默认端口
22405
+ const LOCAL_DEFAULT_PORT = 9012;
22406
+ const REMOTE_DEFAULT_PORT = 19012;
22407
+ function isRemoteEnvironment() {
22408
+ return Boolean(process.env.SSH_CONNECTION
22409
+ || process.env.SSH_CLIENT
22410
+ || process.env.SSH_TTY
22411
+ || process.env.VSCODE_IPC_HOOK_CLI
22412
+ || process.env.VSCODE_AGENT_FOLDER
22413
+ || process.env.REMOTE_CONTAINERS
22414
+ || process.env.CODESPACES
22415
+ || process.env.GITPOD_WORKSPACE_ID);
22416
+ }
22417
+ function getStartPort() {
22418
+ const customStartPort = Number(process.env.TCB_WEB_LOGIN_START_PORT);
22419
+ if (Number.isInteger(customStartPort) && customStartPort > 0 && customStartPort < 65535) {
22420
+ return customStartPort;
22421
+ }
22422
+ return isRemoteEnvironment() ? REMOTE_DEFAULT_PORT : LOCAL_DEFAULT_PORT;
22423
+ }
22424
+ // 获取本地可用端口
22405
22425
  function getPort() {
22406
22426
  return __awaiter(this, void 0, void 0, function* () {
22427
+ const startPort = getStartPort();
22407
22428
  const port = yield portfinder_1.default.getPortPromise({
22408
- port: DEFAULT_PORT
22429
+ port: startPort,
22430
+ stopPort: 65535
22409
22431
  });
22410
22432
  return port;
22411
22433
  });
@@ -41982,6 +42004,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
41982
42004
  Object.defineProperty(exports, "__esModule", ({ value: true }));
41983
42005
  exports.getMacAddress = void 0;
41984
42006
  const address_1 = __importDefault(__webpack_require__(56163));
42007
+ // 获取本机 Mac 地址
41985
42008
  function getMacAddress() {
41986
42009
  return __awaiter(this, void 0, void 0, function* () {
41987
42010
  return new Promise((resolve) => {
@@ -42617,6 +42640,9 @@ const DefaultCloudBaseConfig = {
42617
42640
  functionRoot: './functions',
42618
42641
  functions: []
42619
42642
  };
42643
+ /**
42644
+ * 从配置文件中解析 cloudbase 配置
42645
+ */
42620
42646
  function resolveCloudBaseConfig(options) {
42621
42647
  var _a, _b;
42622
42648
  return __awaiter(this, void 0, void 0, function* () {
@@ -42625,17 +42651,21 @@ function resolveCloudBaseConfig(options) {
42625
42651
  searchFrom,
42626
42652
  moduleName: 'tcb'
42627
42653
  });
42654
+ // 检查旧的配置文件
42628
42655
  if (oldTcbConfig) {
42629
42656
  throw new error_1.CloudBaseError('tcbrc.json 配置文件已废弃,请使用 cloudbaserc 配置文件!');
42630
42657
  }
42658
+ // 可能为 null
42631
42659
  const localCloudBaseConfig = yield (0, cosmiconfig_1.loadConfig)({
42632
42660
  searchFrom,
42633
42661
  configPath
42634
42662
  });
42663
+ // localCloudBaseConfig 不为空,且不存在 envId
42635
42664
  if (localCloudBaseConfig && !localCloudBaseConfig.envId) {
42636
42665
  throw new error_1.CloudBaseError('无效的配置文件,配置文件必须包含环境 Id(envId) 字段');
42637
42666
  }
42638
42667
  const cloudbaseConfig = Object.assign(Object.assign({}, DefaultCloudBaseConfig), localCloudBaseConfig);
42668
+ // 兼容不同形式的配置
42639
42669
  if ((_a = cloudbaseConfig.functions) === null || _a === void 0 ? void 0 : _a.length) {
42640
42670
  cloudbaseConfig.functions = (_b = cloudbaseConfig.functions) === null || _b === void 0 ? void 0 : _b.map((func) => {
42641
42671
  if (func.config) {
@@ -42653,19 +42683,25 @@ function resolveCloudBaseConfig(options) {
42653
42683
  });
42654
42684
  }
42655
42685
  exports.resolveCloudBaseConfig = resolveCloudBaseConfig;
42686
+ /**
42687
+ * 从命令行和配置文件中获取 envId
42688
+ */
42656
42689
  function getEnvId(commandOptions) {
42657
42690
  var _a;
42658
42691
  return __awaiter(this, void 0, void 0, function* () {
42659
42692
  const envId = commandOptions === null || commandOptions === void 0 ? void 0 : commandOptions.envId;
42660
42693
  const configPath = (_a = commandOptions === null || commandOptions === void 0 ? void 0 : commandOptions.parent) === null || _a === void 0 ? void 0 : _a.configFile;
42661
42694
  const cloudbaseConfig = yield resolveCloudBaseConfig(configPath);
42695
+ // 命令行 envId 可以覆盖配置文件 envId
42662
42696
  const assignEnvId = envId || (cloudbaseConfig === null || cloudbaseConfig === void 0 ? void 0 : cloudbaseConfig.envId);
42663
42697
  return assignEnvId;
42664
42698
  });
42665
42699
  }
42666
42700
  exports.getEnvId = getEnvId;
42667
42701
  const renderConfig = (template, view) => {
42702
+ // 渲染时不 escape
42668
42703
  mustache_1.default.escape = (text) => {
42704
+ // 将对象转成 JSON 字符串
42669
42705
  if (typeof text === 'object') {
42670
42706
  try {
42671
42707
  return JSON.stringify(text).replace(/"/g, '\\"');
@@ -42679,6 +42715,7 @@ const renderConfig = (template, view) => {
42679
42715
  return mustache_1.default.render(template, view, ['"{{', '}}"']);
42680
42716
  };
42681
42717
  exports.renderConfig = renderConfig;
42718
+ // cloudbase v2+ 配置文件解析器
42682
42719
  class ConfigParser {
42683
42720
  static get(key, defaultValue, options) {
42684
42721
  return __awaiter(this, void 0, void 0, function* () {
@@ -42696,14 +42733,22 @@ class ConfigParser {
42696
42733
  return this.instance.options(options).update(key, value);
42697
42734
  });
42698
42735
  }
42736
+ // 解析配置
42699
42737
  static parseRawConfig(rawConfig, cwd = process.cwd()) {
42700
42738
  return __awaiter(this, void 0, void 0, function* () {
42701
42739
  let config = lodash_1.default.cloneDeep(rawConfig);
42740
+ // 命令行中指定的 envId,优先级最高
42702
42741
  const envId = yargs_1.default.argv.e || yargs_1.default.argv.envId;
42742
+ // 加载本地 env 文件
42703
42743
  const env = (0, env_1.loadEnvVariables)(cwd);
42744
+ // 转换成字符串
42704
42745
  let configString = JSON.stringify(config);
42705
42746
  const envs = {
42706
- env: Object.assign(Object.assign({ ENV_ID: envId || config.envId }, env), process.env),
42747
+ // 环境变量
42748
+ env: Object.assign(Object.assign({
42749
+ // 注入 ENV_ID,同云端部署保持一致
42750
+ ENV_ID: envId || config.envId }, env), process.env),
42751
+ // 云开发相关的变量
42707
42752
  tcb: {
42708
42753
  envId: envId || config.envId
42709
42754
  },
@@ -42711,14 +42756,17 @@ class ConfigParser {
42711
42756
  uid: (0, uid_1.uuid)(24)
42712
42757
  }
42713
42758
  };
42759
+ // --envId 优先级最高
42714
42760
  if (envId) {
42715
42761
  envs.env.envId = envId;
42716
42762
  envs.env.ENV_ID = envId;
42717
42763
  }
42764
+ // 使用模板渲染
42718
42765
  configString = (0, exports.renderConfig)(configString, envs);
42719
42766
  config = JSON.parse(configString, (key, value) => {
42720
42767
  if (typeof value === 'string') {
42721
42768
  try {
42769
+ // 只解析对象
42722
42770
  const parsed = JSON.parse(value);
42723
42771
  if (typeof parsed === 'object') {
42724
42772
  return parsed;
@@ -42737,6 +42785,7 @@ class ConfigParser {
42737
42785
  constructor(options = {}) {
42738
42786
  this.options(options);
42739
42787
  }
42788
+ // 重写内部配置
42740
42789
  options(options = {}) {
42741
42790
  const { cwd = process.cwd(), cover = true, configPath } = options;
42742
42791
  this.cwd = cwd;
@@ -42744,21 +42793,28 @@ class ConfigParser {
42744
42793
  this.configPath = configPath;
42745
42794
  return this;
42746
42795
  }
42796
+ // get config value by lodash object paths
42797
+ // https://lodash.com/docs/4.17.15#get
42747
42798
  get(key, defaultValue) {
42748
42799
  return __awaiter(this, void 0, void 0, function* () {
42749
42800
  const config = yield this.getConfig();
42801
+ // 不带 key,返回整个配置
42750
42802
  if (!key) {
42751
42803
  return config;
42752
42804
  }
42805
+ // 返回具体字段的值
42753
42806
  return lodash_1.default.get(config, key, defaultValue);
42754
42807
  });
42755
42808
  }
42809
+ // update config value by lodash object paths
42810
+ // https://lodash.com/docs/4.17.15#set
42756
42811
  update(key, value, cover) {
42757
42812
  return __awaiter(this, void 0, void 0, function* () {
42758
42813
  const config = yield resolveCloudBaseConfig({
42759
42814
  configPath: this.configPath
42760
42815
  });
42761
42816
  let unionConfig;
42817
+ // 当 value 为 undefined 且 key 为对象时,直接把 key 作为值更新到 config 中
42762
42818
  if (typeof value === 'undefined' && typeof key === 'object') {
42763
42819
  unionConfig = Object.assign(Object.assign({}, config), key);
42764
42820
  }
@@ -42768,24 +42824,34 @@ class ConfigParser {
42768
42824
  yield this.updateConfig(unionConfig, cover);
42769
42825
  });
42770
42826
  }
42827
+ // 读配置,支持外部直接调用
42771
42828
  getConfig() {
42772
42829
  return __awaiter(this, void 0, void 0, function* () {
42830
+ // 配置文件路径不存在
42773
42831
  if (!this.configPath) {
42832
+ // 搜索配置,获取配置目录
42774
42833
  const result = yield (0, cosmiconfig_1.searchConfig)(this.cwd);
42834
+ // 设置 config 路径
42775
42835
  this.configPath = result === null || result === void 0 ? void 0 : result.filepath;
42776
42836
  }
42837
+ // 读取原配置
42777
42838
  const rawConfig = yield resolveCloudBaseConfig({
42778
42839
  configPath: this.configPath
42779
42840
  });
42780
42841
  return ConfigParser.parseRawConfig(rawConfig, this.cwd);
42781
42842
  });
42782
42843
  }
42844
+ // 写配置
42783
42845
  updateConfig(config, cover = this.cover) {
42784
42846
  return __awaiter(this, void 0, void 0, function* () {
42847
+ // 配置文件路径不存在
42785
42848
  if (!this.configPath) {
42849
+ // 搜索配置,获取配置目录
42786
42850
  const result = yield (0, cosmiconfig_1.searchConfig)(this.cwd);
42851
+ // 设置 config 路径,config 可能不存在
42787
42852
  this.configPath = result === null || result === void 0 ? void 0 : result.filepath;
42788
42853
  }
42854
+ // 原配置
42789
42855
  const baseConfig = yield (0, cosmiconfig_1.loadConfig)({
42790
42856
  searchFrom: this.cwd,
42791
42857
  configPath: this.configPath
@@ -42793,14 +42859,17 @@ class ConfigParser {
42793
42859
  const unionConfig = cover
42794
42860
  ? Object.assign(Object.assign({}, baseConfig), config) : Object.assign(Object.assign({}, config), baseConfig);
42795
42861
  let indent = 2;
42862
+ // 文件存在,检测文件缩进
42796
42863
  if (this.configPath) {
42797
42864
  const fileContent = yield fs_1.default.promises.readFile(this.configPath);
42798
42865
  const detectRet = (0, detect_indent_1.detectIndent)(fileContent === null || fileContent === void 0 ? void 0 : fileContent.toString());
42799
42866
  indent = (detectRet === null || detectRet === void 0 ? void 0 : detectRet.amount) || indent;
42800
42867
  }
42801
42868
  else {
42869
+ // 配置文件可能不存在,设置配置文件路径,直接写内容
42802
42870
  this.configPath = path_1.default.join(this.cwd, 'cloudbaserc.json');
42803
42871
  }
42872
+ // 写入配置到 json 文件中
42804
42873
  jsonfile_1.default.writeFileSync(this.configPath, unionConfig, { spaces: indent });
42805
42874
  });
42806
42875
  }
@@ -67211,11 +67280,17 @@ module.exports = flatten;
67211
67280
 
67212
67281
  Object.defineProperty(exports, "__esModule", ({ value: true }));
67213
67282
  exports.getPropertyByPath = void 0;
67283
+ // Resolves property names or property paths defined with period-delimited
67284
+ // strings or arrays of strings. Property names that are found on the source
67285
+ // object are used directly (even if they include a period).
67286
+ // Nested property names that include periods, within a path, are only
67287
+ // understood in array paths.
67214
67288
  function getPropertyByPath(source, path) {
67215
67289
  if (typeof path === 'string' && Object.prototype.hasOwnProperty.call(source, path)) {
67216
67290
  return source[path];
67217
67291
  }
67218
67292
  const parsedPath = typeof path === 'string' ? path.split('.') : path;
67293
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67219
67294
  return parsedPath.reduce((previous, key) => {
67220
67295
  if (previous === undefined) {
67221
67296
  return previous;
@@ -82787,7 +82862,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
82787
82862
  });
82788
82863
  };
82789
82864
  Object.defineProperty(exports, "__esModule", ({ value: true }));
82790
- exports.AuthSupevisor = void 0;
82865
+ exports.AuthSupevisor = exports.AuthSupervisor = void 0;
82791
82866
  const web_auth_1 = __webpack_require__(76097);
82792
82867
  const common_1 = __webpack_require__(96711);
82793
82868
  const credential_1 = __webpack_require__(99795);
@@ -82795,13 +82870,17 @@ const error_1 = __webpack_require__(64119);
82795
82870
  __exportStar(__webpack_require__(96711), exports);
82796
82871
  __exportStar(__webpack_require__(99795), exports);
82797
82872
  __exportStar(__webpack_require__(76097), exports);
82798
- class AuthSupevisor {
82873
+ class AuthSupervisor {
82874
+ /**
82875
+ * 单例模式,全局缓存
82876
+ * @param options
82877
+ */
82799
82878
  static getInstance(options = {}) {
82800
- if (AuthSupevisor.instance) {
82801
- return AuthSupevisor.instance;
82879
+ if (AuthSupervisor.instance) {
82880
+ return AuthSupervisor.instance;
82802
82881
  }
82803
- const instance = new AuthSupevisor(options);
82804
- AuthSupevisor.instance = instance;
82882
+ const instance = new AuthSupervisor(options);
82883
+ AuthSupervisor.instance = instance;
82805
82884
  return instance;
82806
82885
  }
82807
82886
  constructor(options = {}) {
@@ -82814,11 +82893,15 @@ class AuthSupevisor {
82814
82893
  this.cacheExpiredTime = 0;
82815
82894
  this.throwError = throwError;
82816
82895
  }
82896
+ /**
82897
+ * 获取登录状态信息
82898
+ */
82817
82899
  getLoginState() {
82818
82900
  return __awaiter(this, void 0, void 0, function* () {
82819
82901
  if (this.cacheCredential && this.needCache && !this.isCacheExpire()) {
82820
82902
  return this.cacheCredential;
82821
82903
  }
82904
+ // 获取本地登录状态
82822
82905
  const credential = yield (0, credential_1.checkAndGetCredential)(this.requestConfig);
82823
82906
  if (this.needCache && credential) {
82824
82907
  this.cacheCredential = credential;
@@ -82830,17 +82913,25 @@ class AuthSupevisor {
82830
82913
  return credential;
82831
82914
  });
82832
82915
  }
82916
+ /**
82917
+ * 通过网页授权登录
82918
+ * @returns credential
82919
+ */
82833
82920
  loginByWebAuth(options = {}) {
82834
82921
  return __awaiter(this, void 0, void 0, function* () {
82835
- const { getAuthUrl, throwError } = options;
82922
+ const { getAuthUrl, throwError, noBrowser, callbackTimeout } = options;
82836
82923
  if (this.cacheCredential && this.needCache && !this.isCacheExpire()) {
82837
82924
  return this.cacheCredential;
82838
82925
  }
82926
+ // 校验本地秘钥
82839
82927
  let credential = yield (0, credential_1.checkAndGetCredential)(this.requestConfig);
82840
82928
  if (credential)
82841
82929
  return credential;
82930
+ // 兼容临时秘钥
82842
82931
  credential = yield (0, web_auth_1.getAuthTokenFromWeb)({
82843
- getAuthUrl
82932
+ getAuthUrl,
82933
+ noBrowser,
82934
+ callbackTimeout
82844
82935
  });
82845
82936
  try {
82846
82937
  yield (0, common_1.checkAuth)(credential, this.requestConfig);
@@ -82851,8 +82942,10 @@ class AuthSupevisor {
82851
82942
  }
82852
82943
  return null;
82853
82944
  }
82945
+ // 通过 Web 登录时,本地要存储 tmpSecretId 形式,方式 CLI 登录失效
82854
82946
  const webCredential = (0, common_1.resolveWebCredential)(credential);
82855
82947
  yield credential_1.authStore.set('credential', webCredential);
82948
+ // 缓存处理转换后的 credential
82856
82949
  if (this.needCache && credential) {
82857
82950
  this.cacheCredential = credential;
82858
82951
  const { accessTokenExpired } = credential;
@@ -82863,26 +82956,41 @@ class AuthSupevisor {
82863
82956
  return credential;
82864
82957
  });
82865
82958
  }
82866
- loginByApiSecret(secretId, secretKey, token) {
82959
+ /**
82960
+ * 通过 API Secret 登录,支持临时秘钥
82961
+ * @param secretId
82962
+ * @param secretKey
82963
+ * @param token
82964
+ * @param opts 选项配置,包括强制更新和额外的 Credential 字段
82965
+ * @returns credential
82966
+ */
82967
+ // eslint-disable-next-line max-params
82968
+ loginByApiSecret(secretId, secretKey, token, opts) {
82867
82969
  return __awaiter(this, void 0, void 0, function* () {
82868
- if (this.cacheCredential && this.needCache && !this.isCacheExpire()) {
82970
+ const { forceUpdate = false, storeAsWebCredential = false, additionalCredentialFields } = opts || {};
82971
+ if (this.cacheCredential && this.needCache && !this.isCacheExpire() && !forceUpdate) {
82869
82972
  return this.cacheCredential;
82870
82973
  }
82871
- let credential = yield (0, credential_1.checkAndGetCredential)(this.requestConfig);
82872
- if (credential)
82873
- return credential;
82974
+ // 校验本地秘钥(如果不是强制更新)
82975
+ if (!forceUpdate) {
82976
+ let credential = yield (0, credential_1.checkAndGetCredential)(this.requestConfig);
82977
+ if (credential)
82978
+ return credential;
82979
+ }
82980
+ // 当本地身份信息不存在时,才使用传入参数进行校验
82874
82981
  if (!secretId || !secretKey) {
82875
82982
  throw new error_1.CloudBaseError('secretId 或 secretKey 不能为空');
82876
82983
  }
82877
- credential = {
82878
- secretId,
82984
+ const credential = Object.assign(Object.assign({}, additionalCredentialFields), { secretId,
82879
82985
  secretKey,
82880
- token
82881
- };
82986
+ token });
82882
82987
  try {
82883
82988
  yield (0, common_1.checkAuth)(credential, this.requestConfig);
82884
82989
  }
82885
82990
  catch (e) {
82991
+ // CAM 错误视为登录正常
82992
+ // if (isCamRefused(e)) return credential;
82993
+ // 请求超时
82886
82994
  if (e.type === 'request-timeout') {
82887
82995
  throw new error_1.CloudBaseError('请求超时,请检查你的网络,如果终端无法直接访问公网,请设置终端 HTTP 请求代理!');
82888
82996
  }
@@ -82891,7 +82999,12 @@ class AuthSupevisor {
82891
82999
  }
82892
83000
  return null;
82893
83001
  }
82894
- yield credential_1.authStore.set('credential', credential);
83002
+ // 根据选项决定存储格式
83003
+ const credentialToStore = storeAsWebCredential
83004
+ ? (0, common_1.resolveWebCredential)(credential)
83005
+ : credential;
83006
+ // 存储信息
83007
+ yield credential_1.authStore.set('credential', credentialToStore);
82895
83008
  if (this.needCache && credential) {
82896
83009
  this.cacheCredential = credential;
82897
83010
  this.cacheExpiredTime = Date.now() + 3600 * 1000;
@@ -82904,10 +83017,11 @@ class AuthSupevisor {
82904
83017
  if (this.cacheCredential) {
82905
83018
  this.cacheCredential = null;
82906
83019
  }
82907
- const credentail = yield (0, credential_1.getCredentialWithoutCheck)();
83020
+ const credential = yield (0, credential_1.getCredentialWithoutCheck)();
82908
83021
  try {
82909
- if (credentail === null || credentail === void 0 ? void 0 : credentail.refreshToken) {
82910
- yield (0, credential_1.refreshTmpToken)(Object.assign(Object.assign({}, credentail), { isLogout: true }));
83022
+ // 仅使用 Web 控制台授权登录时才删除 token
83023
+ if (credential === null || credential === void 0 ? void 0 : credential.refreshToken) {
83024
+ yield (0, credential_1.refreshTmpToken)(Object.assign(Object.assign({}, credential), { isLogout: true }));
82911
83025
  }
82912
83026
  yield credential_1.authStore.delete('credential');
82913
83027
  }
@@ -82922,6 +83036,29 @@ class AuthSupevisor {
82922
83036
  return now >= this.cacheExpiredTime;
82923
83037
  }
82924
83038
  }
83039
+ exports.AuthSupervisor = AuthSupervisor;
83040
+ /**
83041
+ * @deprecated Use `AuthSupervisor` instead. This class has a spelling error and will be removed in a future version.
83042
+ */
83043
+ class AuthSupevisor extends AuthSupervisor {
83044
+ /**
83045
+ * @deprecated Use `AuthSupervisor.getInstance` instead
83046
+ */
83047
+ static getInstance(options = {}) {
83048
+ if (AuthSupevisor.instance) {
83049
+ return AuthSupevisor.instance;
83050
+ }
83051
+ const instance = new AuthSupevisor(options);
83052
+ AuthSupevisor.instance = instance;
83053
+ return instance;
83054
+ }
83055
+ /**
83056
+ * @deprecated Use `AuthSupervisor` constructor instead
83057
+ */
83058
+ constructor(options = {}) {
83059
+ super(options);
83060
+ }
83061
+ }
82925
83062
  exports.AuthSupevisor = AuthSupevisor;
82926
83063
 
82927
83064
 
@@ -84723,14 +84860,17 @@ exports.getDataFromWeb = void 0;
84723
84860
  const open_1 = __importDefault(__webpack_require__(30353));
84724
84861
  const query_string_1 = __importDefault(__webpack_require__(86663));
84725
84862
  const http_1 = __importDefault(__webpack_require__(81630));
84863
+ const child_process_1 = __webpack_require__(79646);
84726
84864
  const system_1 = __webpack_require__(62179);
84727
84865
  const error_1 = __webpack_require__(64119);
84728
84866
  const html_1 = __webpack_require__(74856);
84867
+ // 创建本地 Web 服务器,接受 Web 控制台传入的信息
84729
84868
  function createLocalServer() {
84730
84869
  return __awaiter(this, void 0, void 0, function* () {
84731
84870
  const server = http_1.default.createServer();
84732
84871
  const port = yield (0, system_1.getPort)();
84733
84872
  return new Promise((resolve, reject) => {
84873
+ // 服务启动异常
84734
84874
  server.on('error', (e) => {
84735
84875
  reject(e);
84736
84876
  });
@@ -84743,6 +84883,7 @@ function createLocalServer() {
84743
84883
  });
84744
84884
  });
84745
84885
  }
84886
+ // 返回 HTML 响应
84746
84887
  function respondWithFile(options) {
84747
84888
  const { req, res, statusCode, filename } = options;
84748
84889
  return new Promise(function (resolve) {
@@ -84756,20 +84897,108 @@ function respondWithFile(options) {
84756
84897
  resolve();
84757
84898
  });
84758
84899
  }
84759
- function getDataFromWeb(getUrl, type) {
84900
+ function isTruthyFlag(value) {
84901
+ if (!value) {
84902
+ return false;
84903
+ }
84904
+ return ['1', 'true', 'yes', 'on'].includes(String(value).trim().toLowerCase());
84905
+ }
84906
+ function isVSCodeEnvironment() {
84907
+ return Boolean(process.env.VSCODE_IPC_HOOK_CLI
84908
+ || process.env.VSCODE_PID
84909
+ || process.env.TERM_PROGRAM === 'vscode');
84910
+ }
84911
+ function parseBrowserCommand(browser) {
84912
+ const parts = browser.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
84913
+ return parts.map((item) => item.replace(/^"(.*)"$/, '$1'));
84914
+ }
84915
+ function openUrlByBrowserEnv(url) {
84916
+ var _a;
84917
+ return __awaiter(this, void 0, void 0, function* () {
84918
+ const browser = (_a = process.env.BROWSER) === null || _a === void 0 ? void 0 : _a.trim();
84919
+ if (!browser) {
84920
+ return false;
84921
+ }
84922
+ const [command, ...args] = parseBrowserCommand(browser);
84923
+ if (!command) {
84924
+ return false;
84925
+ }
84926
+ const finalArgs = args.map((arg) => (arg === '%s' ? url : arg));
84927
+ if (!args.includes('%s')) {
84928
+ finalArgs.push(url);
84929
+ }
84930
+ return new Promise((resolve) => {
84931
+ (0, child_process_1.execFile)(command, finalArgs, (error) => {
84932
+ resolve(!error);
84933
+ });
84934
+ });
84935
+ });
84936
+ }
84937
+ function shouldUseBrowserEnvFallback() {
84938
+ return process.platform === 'linux' && isVSCodeEnvironment();
84939
+ }
84940
+ function openUrl(url) {
84760
84941
  return __awaiter(this, void 0, void 0, function* () {
84761
- const { server, port } = yield createLocalServer();
84762
- const url = getUrl(port);
84763
84942
  try {
84764
- yield (0, open_1.default)(url, { url: true });
84943
+ const child = yield (0, open_1.default)(url, { url: true });
84944
+ if (child === null || child === void 0 ? void 0 : child.once) {
84945
+ child.once('error', (error) => __awaiter(this, void 0, void 0, function* () {
84946
+ if (shouldUseBrowserEnvFallback()) {
84947
+ yield openUrlByBrowserEnv(url);
84948
+ }
84949
+ }));
84950
+ }
84951
+ return true;
84765
84952
  }
84766
84953
  catch (e) {
84767
- throw new error_1.CloudBaseError('打开浏览器失败,请尝试使用其他登录方式');
84954
+ if (shouldUseBrowserEnvFallback()) {
84955
+ return openUrlByBrowserEnv(url);
84956
+ }
84957
+ return false;
84958
+ }
84959
+ });
84960
+ }
84961
+ // 从 Web 页面中获取数据
84962
+ function getDataFromWeb(getUrl, type, options = {}) {
84963
+ var _a, _b;
84964
+ return __awaiter(this, void 0, void 0, function* () {
84965
+ const { server, port } = yield createLocalServer();
84966
+ const noBrowser = (_a = options.noBrowser) !== null && _a !== void 0 ? _a : isTruthyFlag(process.env.TCB_NO_BROWSER);
84967
+ const callbackTimeout = (_b = options.callbackTimeout) !== null && _b !== void 0 ? _b : 180000;
84968
+ if (!Number.isFinite(callbackTimeout) || callbackTimeout <= 0) {
84969
+ throw new error_1.CloudBaseError('callbackTimeout must be a positive number');
84970
+ }
84971
+ const url = getUrl(port);
84972
+ console.log('\n\n若链接未自动打开,请手动复制至浏览器,或尝试其他登录方式:');
84973
+ console.log(`\n${url}\n`);
84974
+ if (!noBrowser) {
84975
+ // 对 url 转码, 避免 wsl 无法正常打开地址
84976
+ // https://www.npmjs.com/package/open#url
84977
+ // https://github.com/sindresorhus/open/blob/master/index.js#L48
84978
+ yield openUrl(url);
84768
84979
  }
84769
84980
  return new Promise((resolve, reject) => {
84981
+ let finished = false;
84982
+ const timer = setTimeout(() => {
84983
+ if (finished) {
84984
+ return;
84985
+ }
84986
+ finished = true;
84987
+ server.close();
84988
+ reject(new error_1.CloudBaseError(`等待浏览器授权回调超时(${Math.floor(callbackTimeout / 1000)}s)!`));
84989
+ }, callbackTimeout);
84990
+ const finish = (fn) => {
84991
+ if (finished) {
84992
+ return;
84993
+ }
84994
+ finished = true;
84995
+ clearTimeout(timer);
84996
+ fn();
84997
+ };
84770
84998
  server.on('request', (req, res) => {
84771
- const { url } = req;
84999
+ const url = req.url || '/';
84772
85000
  const { query } = query_string_1.default.parseUrl(url);
85001
+ // 响应 HTML 文件
84773
85002
  if (query === null || query === void 0 ? void 0 : query.html) {
84774
85003
  return respondWithFile({
84775
85004
  req,
@@ -84777,25 +85006,33 @@ function getDataFromWeb(getUrl, type) {
84777
85006
  statusCode: 200,
84778
85007
  filename: `${type}Success`
84779
85008
  }).then(() => {
84780
- server.close();
84781
- resolve(query);
85009
+ finish(() => {
85010
+ server.close();
85011
+ resolve(query);
85012
+ });
84782
85013
  }).catch((e) => {
84783
- server.close();
84784
- reject(e);
85014
+ finish(() => {
85015
+ server.close();
85016
+ reject(e);
85017
+ });
84785
85018
  });
84786
85019
  }
85020
+ // CORS 响应普通文本
84787
85021
  res.writeHead(200, {
84788
85022
  'Access-Control-Allow-Origin': '*',
84789
85023
  'Access-Control-Allow-Methods': '*',
84790
85024
  'Access-Control-Allow-Headers': '*',
84791
85025
  'Content-Type': 'text/plain',
85026
+ // 立即关闭 http 连接
84792
85027
  Connection: 'close'
84793
85028
  });
84794
85029
  res.end();
84795
85030
  if (req.method !== 'OPTIONS') {
84796
85031
  server.close();
84797
85032
  }
84798
- resolve(query);
85033
+ finish(() => {
85034
+ resolve(query);
85035
+ });
84799
85036
  });
84800
85037
  });
84801
85038
  });
@@ -89001,6 +89238,7 @@ __exportStar(__webpack_require__(31153), exports);
89001
89238
  __exportStar(__webpack_require__(33283), exports);
89002
89239
  __exportStar(__webpack_require__(79998), exports);
89003
89240
  __exportStar(__webpack_require__(19835), exports);
89241
+ // export types
89004
89242
  __exportStar(__webpack_require__(42612), exports);
89005
89243
 
89006
89244
 
@@ -93051,6 +93289,7 @@ const cloud_api_1 = __webpack_require__(2090);
93051
93289
  const constant_1 = __webpack_require__(53393);
93052
93290
  let commonCredential;
93053
93291
  class CloudApiService {
93292
+ // 单例模式
93054
93293
  static getInstance(service) {
93055
93294
  var _a;
93056
93295
  if ((_a = CloudApiService.serviceCacheMap) === null || _a === void 0 ? void 0 : _a[service]) {
@@ -93061,6 +93300,7 @@ class CloudApiService {
93061
93300
  return apiService;
93062
93301
  }
93063
93302
  constructor(service, baseParams, version = '') {
93303
+ // 初始化 API 实例
93064
93304
  this.apiService = new cloud_api_1.CloudApiService({
93065
93305
  service,
93066
93306
  version,
@@ -93089,6 +93329,7 @@ class CloudApiService {
93089
93329
  }
93090
93330
  }
93091
93331
  exports.CloudApiService = CloudApiService;
93332
+ // 缓存请求实例
93092
93333
  CloudApiService.serviceCacheMap = {};
93093
93334
 
93094
93335
 
@@ -101388,8 +101629,16 @@ const archiver_1 = __importDefault(__webpack_require__(30989));
101388
101629
  exports.decompress = decompress_1.default;
101389
101630
  const unzip = (zipFile, dest) => (0, exports.decompress)(zipFile, dest);
101390
101631
  exports.unzip = unzip;
101632
+ /**
101633
+ * 解压流(使用临时 zip 包)
101634
+ * @param source 可读流
101635
+ * @param dest 解压目标文件夹
101636
+ * @param name 可选的临时 zip 包名
101637
+ */
101391
101638
  const unzipStream = (source, dest, name = 'gape3il5rk8.zip') => __awaiter(void 0, void 0, void 0, function* () {
101639
+ // 确保文件夹存在
101392
101640
  yield (0, fs_2.mkdirAsync)(dest);
101641
+ // 使用一个临时文件下载 zip 包
101393
101642
  const zipPath = path_1.default.join(dest, `${name}.zip`);
101394
101643
  const zip = fs_1.default.createWriteStream(zipPath);
101395
101644
  source.pipe(zip);
@@ -101432,13 +101681,16 @@ function zipFiles(allFilesPath, outputPath, ignore) {
101432
101681
  archive.pipe(output);
101433
101682
  allFilesPath.forEach(filePath => {
101434
101683
  if (fs_1.default.statSync(filePath).isDirectory()) {
101684
+ // append files from a glob pattern
101435
101685
  archive.glob('**/*', {
101686
+ // 目标路径
101436
101687
  cwd: filePath,
101437
101688
  ignore: ignore,
101438
101689
  dot: true
101439
101690
  });
101440
101691
  }
101441
101692
  else {
101693
+ // append file
101442
101694
  archive.file(filePath);
101443
101695
  }
101444
101696
  });
@@ -112046,7 +112298,11 @@ Promise.PromiseInspection = PromiseInspection;
112046
112298
  Object.defineProperty(exports, "__esModule", ({ value: true }));
112047
112299
  exports.AsyncMerge = void 0;
112048
112300
  const cache_1 = __webpack_require__(51995);
112301
+ // 使用 Symbol 值,判断缓存结果时,可以准确判断是否为 Error 类型
112049
112302
  const ERROR_KEY = Symbol('ERROR_KEY');
112303
+ /**
112304
+ * 异步任务合并
112305
+ */
112050
112306
  class AsyncMerge {
112051
112307
  constructor() {
112052
112308
  this.tasks = {};
@@ -112060,7 +112316,10 @@ class AsyncMerge {
112060
112316
  throw new Error('AsyncMerge taskId could not be empty, it will cause unexpected result!');
112061
112317
  }
112062
112318
  return new Promise((resolve, reject) => {
112319
+ // 取缓存
112063
112320
  const cacheRet = cache_1.nilCache.get(taskId);
112321
+ // 校验缓存,缓存结果可能为 null, undefined 等空值
112322
+ // 使用 Symbol 值做判断
112064
112323
  if (maxAge > 0 && cacheRet !== cache_1.Cache.NIL) {
112065
112324
  const e = cacheRet[ERROR_KEY];
112066
112325
  if (e) {
@@ -112082,6 +112341,7 @@ class AsyncMerge {
112082
112341
  }
112083
112342
  });
112084
112343
  }
112344
+ // eslint-disable-next-line
112085
112345
  runTask(fn, taskId, taskOptions, cb) {
112086
112346
  const { tasks } = this;
112087
112347
  const { maxAge = 0, timeout = 60000 } = taskOptions;
@@ -112093,15 +112353,18 @@ class AsyncMerge {
112093
112353
  }
112094
112354
  tasks[taskId].callbacks.push(cb);
112095
112355
  const task = tasks[taskId];
112356
+ // 当前类型的任务没有运行
112096
112357
  if (!task.lock) {
112097
112358
  let timerId = null;
112098
112359
  if (timeout) {
112099
112360
  timerId = setTimeout(() => {
112361
+ // 超时回调
112100
112362
  task.callbacks.forEach((cb) => cb(new Error('TASK_TIMEOUT')));
112101
112363
  task.lock = false;
112102
112364
  delete tasks[taskId];
112103
112365
  }, timeout);
112104
112366
  }
112367
+ // 上锁,标志任务处理开始
112105
112368
  task.lock = true;
112106
112369
  fn()
112107
112370
  .then((res) => {
@@ -112115,6 +112378,7 @@ class AsyncMerge {
112115
112378
  clearTimeout(timerId);
112116
112379
  task.lock = false;
112117
112380
  delete tasks[taskId];
112381
+ // 任务异常,缓存异常值
112118
112382
  maxAge > 0 && cache_1.nilCache.set(taskId, { ERROR_KEY: e }, maxAge);
112119
112383
  task.callbacks.forEach((cb) => cb(e));
112120
112384
  });
@@ -124758,6 +125022,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
124758
125022
  exports.md5Encoding = void 0;
124759
125023
  const crypto_1 = __importDefault(__webpack_require__(55511));
124760
125024
  const error_1 = __webpack_require__(64119);
125025
+ // MD5
124761
125026
  function md5Encoding(str = '') {
124762
125027
  if (typeof str !== 'string')
124763
125028
  throw new error_1.CloudBaseError('参数必须为字符串!');
@@ -125537,9 +125802,13 @@ const FileAsync_1 = __importDefault(__webpack_require__(19778));
125537
125802
  const FileSync_1 = __importDefault(__webpack_require__(29303));
125538
125803
  const fs_1 = __webpack_require__(96185);
125539
125804
  const homeDir = os_1.default.homedir();
125805
+ // 系统配置目录
125540
125806
  const homeAccessible = (0, fs_1.checkFullAccess)(homeDir);
125807
+ // 仅当 home 目录可访问时,才使用 home 目录,否则使用临时目录
125541
125808
  const configDir = homeDir && homeAccessible ? path_1.default.join(homeDir, '.config') : path_1.default.join(os_1.default.tmpdir(), '.config');
125809
+ // cloudbase 配置目录
125542
125810
  exports.cloudbaseConfigDir = path_1.default.join(configDir, '.cloudbase');
125811
+ // 确保目录存在
125543
125812
  make_dir_1.default.sync(exports.cloudbaseConfigDir);
125544
125813
  function getAsyncDB(file) {
125545
125814
  const dbPath = path_1.default.join(exports.cloudbaseConfigDir, `${file}.json`);
@@ -126762,9 +127031,11 @@ function handleTimeout(e) {
126762
127031
  throw new error_1.CloudBaseError('请求超时,请检查你的网络,如果终端无法直接访问公网,请设置终端 HTTP 请求代理!');
126763
127032
  }
126764
127033
  else {
127034
+ // 其他错误,抛出
126765
127035
  throw e;
126766
127036
  }
126767
127037
  }
127038
+ // 使用 fetch + 代理
126768
127039
  function fetch(url, config = {}) {
126769
127040
  return __awaiter(this, void 0, void 0, function* () {
126770
127041
  const proxy = (0, system_1.getProxy)();
@@ -126787,6 +127058,7 @@ function fetch(url, config = {}) {
126787
127058
  });
126788
127059
  }
126789
127060
  exports.fetch = fetch;
127061
+ // 使用 fetch + 代理
126790
127062
  function postFetch(url, data) {
126791
127063
  return __awaiter(this, void 0, void 0, function* () {
126792
127064
  const proxy = (0, system_1.getProxy)();
@@ -126833,6 +127105,7 @@ function fetchStream(url, config = {}) {
126833
127105
  });
126834
127106
  }
126835
127107
  exports.fetchStream = fetchStream;
127108
+ // 使用 fetch + 代理
126836
127109
  function putFetch(url, config = {}) {
126837
127110
  return __awaiter(this, void 0, void 0, function* () {
126838
127111
  const proxy = (0, system_1.getProxy)();
@@ -136935,7 +137208,7 @@ class TelemetryReporter {
136935
137208
  const nodeVersion = process.version; // Node.js版本
136936
137209
  const arch = os_1.default.arch(); // 系统架构
136937
137210
  // 从构建时注入的版本号获取MCP版本信息
136938
- const mcpVersion = process.env.npm_package_version || "2.10.0" || 0;
137211
+ const mcpVersion = process.env.npm_package_version || "2.11.1" || 0;
136939
137212
  return {
136940
137213
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
136941
137214
  deviceId: this.deviceId,
@@ -137261,6 +137534,9 @@ exports.getRegion = exports.getCloudBaseConfig = void 0;
137261
137534
  const yargs_1 = __importDefault(__webpack_require__(5945));
137262
137535
  const path_1 = __importDefault(__webpack_require__(39902));
137263
137536
  const cloudbase_1 = __webpack_require__(10304);
137537
+ /**
137538
+ * 获取当前目录下的 cloudbase 配置
137539
+ */
137264
137540
  const getCloudBaseConfig = (configPath) => __awaiter(void 0, void 0, void 0, function* () {
137265
137541
  let specificConfigPath = configPath || yargs_1.default.argv['config-path'];
137266
137542
  specificConfigPath = specificConfigPath ? path_1.default.resolve(specificConfigPath) : undefined;
@@ -137271,7 +137547,11 @@ const getCloudBaseConfig = (configPath) => __awaiter(void 0, void 0, void 0, fun
137271
137547
  return config;
137272
137548
  });
137273
137549
  exports.getCloudBaseConfig = getCloudBaseConfig;
137550
+ /**
137551
+ * 从命令行参数和配置文件中读取 region
137552
+ */
137274
137553
  const getRegion = (noDefault = false) => __awaiter(void 0, void 0, void 0, function* () {
137554
+ // region 缩写
137275
137555
  const regionMap = {
137276
137556
  gz: 'ap-guangzhou',
137277
137557
  bj: 'ap-beijing',
@@ -137280,16 +137560,19 @@ const getRegion = (noDefault = false) => __awaiter(void 0, void 0, void 0, funct
137280
137560
  cd: 'ap-chengdu',
137281
137561
  cq: 'ap-chongqing'
137282
137562
  };
137563
+ // 命令行中指定的 region
137283
137564
  const argvRegion = (yargs_1.default.argv.r || yargs_1.default.argv.region);
137284
137565
  if (argvRegion && regionMap[argvRegion]) {
137285
137566
  return regionMap[argvRegion];
137286
137567
  }
137287
137568
  if (argvRegion)
137288
137569
  return argvRegion;
137570
+ // 配置文件中的 region
137289
137571
  const config = yield (0, exports.getCloudBaseConfig)();
137290
137572
  if ((config === null || config === void 0 ? void 0 : config.region) && regionMap[config === null || config === void 0 ? void 0 : config.region]) {
137291
137573
  return regionMap[config.region];
137292
137574
  }
137575
+ // 不使用默认值时,不会默认返回 region
137293
137576
  return noDefault ? config === null || config === void 0 ? void 0 : config.region : (config === null || config === void 0 ? void 0 : config.region) || 'ap-shanghai';
137294
137577
  });
137295
137578
  exports.getRegion = getRegion;
@@ -141824,8 +142107,10 @@ function getJavaScripts(wsPort) {
141824
142107
  }
141825
142108
  }
141826
142109
 
141827
- // WebSocket connection
141828
- const ws = new WebSocket('ws://localhost:${wsPort}');
142110
+ // WebSocket: same host as page so it works in remote VS Code / Cloud IDE (no localhost)
142111
+ const wsScheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
142112
+ const wsUrl = wsScheme + '//' + window.location.host;
142113
+ const ws = new WebSocket(wsUrl);
141829
142114
 
141830
142115
  ws.onopen = () => {
141831
142116
  console.log('[env-setup] WebSocket connected');
@@ -154757,6 +155042,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
154757
155042
  exports.getOSInfo = exports.getPlatformRelease = void 0;
154758
155043
  const os_1 = __importDefault(__webpack_require__(21820));
154759
155044
  const macOSMap = new Map([
155045
+ [24, 'Sequoia'],
155046
+ [23, 'Sonoma'],
155047
+ [22, 'Ventura'],
155048
+ [21, 'Monterey'],
154760
155049
  [20, 'BigSur'],
154761
155050
  [19, 'Catalina'],
154762
155051
  [18, 'Mojave'],
@@ -154772,9 +155061,19 @@ const macOSMap = new Map([
154772
155061
  [8, 'Tiger'],
154773
155062
  [7, 'Panther'],
154774
155063
  [6, 'Jaguar'],
154775
- [5, 'Puma']
155064
+ [5, 'Puma'] // macOS 10.1 Puma (2001)
154776
155065
  ]);
154777
155066
  const winMap = new Map([
155067
+ ['10.0.22000', '11'],
155068
+ ['10.0.19041', '10'],
155069
+ ['10.0.18363', '10'],
155070
+ ['10.0.17763', '10'],
155071
+ ['10.0.17134', '10'],
155072
+ ['10.0.16299', '10'],
155073
+ ['10.0.15063', '10'],
155074
+ ['10.0.14393', '10'],
155075
+ ['10.0.10586', '10'],
155076
+ ['10.0.10240', '10'],
154778
155077
  ['10.0', '10'],
154779
155078
  ['6.3', '8.1'],
154780
155079
  ['6.2', '8'],
@@ -154785,28 +155084,55 @@ const winMap = new Map([
154785
155084
  ['5.0', '2000'],
154786
155085
  ['4.9', 'ME'],
154787
155086
  ['4.1', '98'],
154788
- ['4.0', '95']
155087
+ ['4.0', '95'] // Windows 95 (1995)
154789
155088
  ]);
154790
155089
  function getPlatformRelease(platform, release) {
155090
+ // macOS
154791
155091
  if (platform === 'darwin') {
154792
- const releaseNum = Number(release.split('.')[0]);
154793
- const name = macOSMap.get(releaseNum);
155092
+ const releaseParts = release.split('.');
155093
+ const majorNum = Number(releaseParts[0]);
155094
+ const minorNum = Number(releaseParts[1]) || 0;
155095
+ const name = macOSMap.get(majorNum) || 'macOS';
154794
155096
  let version;
154795
- if (releaseNum >= 20) {
154796
- version = '11.' + (releaseNum - 20);
155097
+ // macOS 11 及以上版本 (majorNum >= 20)
155098
+ if (majorNum >= 20) {
155099
+ // releaseNum 20 -> macOS 11, 21 -> macOS 12, etc.
155100
+ const majorVersion = majorNum - 9;
155101
+ version = `${majorVersion}.${minorNum}`;
155102
+ // macOS 10.x 版本 (majorNum < 20)
154797
155103
  }
154798
155104
  else {
154799
- version = '10.' + (releaseNum - 4);
155105
+ // releaseNum 19 -> 10.15, 18 -> 10.14, etc.
155106
+ const minorVersion = majorNum - 4;
155107
+ version = `10.${minorVersion}`;
154800
155108
  }
154801
155109
  return `${name} ${version}`;
154802
155110
  }
155111
+ // windows
154803
155112
  if (platform === 'win32') {
154804
- const version = (/\d+\.\d/.exec(release) || [])[0];
154805
- return `Windows ${winMap.get(version)}`;
155113
+ // 尝试精确匹配完整版本号
155114
+ let windowsVersion = winMap.get(release);
155115
+ if (!windowsVersion) {
155116
+ // 如果没有精确匹配,尝试匹配主版本号
155117
+ const majorVersion = (/^\d+\.\d+/.exec(release) || [])[0];
155118
+ windowsVersion = winMap.get(majorVersion);
155119
+ }
155120
+ if (!windowsVersion) {
155121
+ // 如果还是没有匹配,尝试只匹配第一部分
155122
+ const firstPart = (/^\d+/.exec(release) || [])[0];
155123
+ if (firstPart === '10') {
155124
+ windowsVersion = '10';
155125
+ }
155126
+ }
155127
+ // 显示完整的版本信息
155128
+ const versionDisplay = windowsVersion || release;
155129
+ return `Windows ${versionDisplay}`;
154806
155130
  }
155131
+ // 其他 Linux
154807
155132
  return 'Linux';
154808
155133
  }
154809
155134
  exports.getPlatformRelease = getPlatformRelease;
155135
+ // 获取 hostname 和平台信息
154810
155136
  function getOSInfo() {
154811
155137
  const hostname = os_1.default.hostname();
154812
155138
  const platform = os_1.default.platform();
@@ -155004,12 +155330,18 @@ function readFile(target) {
155004
155330
  return '';
155005
155331
  }
155006
155332
  }
155333
+ // 从 env 文件中加载环境变量
155334
+ // 参考 https://cli.vuejs.org/zh/guide/mode-and-env.html
155007
155335
  function loadEnvVariables(from = process.cwd()) {
155008
155336
  const mode = yargs_1.default.argv.mode;
155337
+ // .env
155009
155338
  const baseEnv = dotenv_1.default.parse(readFile(path_1.default.join(from, '.env')));
155339
+ // .env.local
155010
155340
  const localEnv = dotenv_1.default.parse(readFile(path_1.default.join(from, '.env.local')));
155341
+ // .env.mode
155011
155342
  const modeEnv = dotenv_1.default.parse(readFile(path_1.default.join(from, `.env.${mode}`)));
155012
155343
  const unionConfig = lodash_1.default.merge({}, baseEnv, localEnv, modeEnv);
155344
+ // 扩展 dotenv 解析模式,支持 functions.xxx=xxx 形式设置对象
155013
155345
  return Object.keys(unionConfig).reduce((prev, key) => {
155014
155346
  return lodash_1.default.set(prev, key, unionConfig[key]);
155015
155347
  }, {});
@@ -155095,28 +155427,46 @@ module.exports = diff
155095
155427
  Object.defineProperty(exports, "__esModule", ({ value: true }));
155096
155428
  exports.nilCache = exports.memoryCache = exports.Cache = void 0;
155097
155429
  class Entry {
155430
+ // eslint-disable-next-line
155098
155431
  constructor(key, value, now, maxAge) {
155099
155432
  this.key = key;
155100
155433
  this.value = value;
155101
155434
  this.now = now;
155102
155435
  this.maxAge = maxAge;
155103
155436
  }
155437
+ // 当前 entry 是否过期
155104
155438
  isExpired() {
155105
155439
  const now = Date.now();
155106
155440
  return this.now + this.maxAge <= now;
155107
155441
  }
155108
155442
  }
155443
+ /**
155444
+ * 缓存模块
155445
+ * 1. 内存缓存
155446
+ * 2. TODO: 本地缓存
155447
+ */
155109
155448
  class Cache {
155110
155449
  constructor(nil) {
155450
+ // use map to cache
155111
155451
  this.store = new Map();
155112
155452
  this.nil = false;
155113
155453
  this.nil = nil;
155114
155454
  }
155455
+ /**
155456
+ * 设置缓存
155457
+ * @param key 缓存 key
155458
+ * @param value 缓存值
155459
+ * @param maxAge 缓存保持时间,单位 ms
155460
+ */
155115
155461
  set(key, value, maxAge = 0) {
155116
155462
  const now = maxAge ? Date.now() : 0;
155117
155463
  const entry = new Entry(key, value, now, maxAge);
155118
155464
  this.store.set(key, entry);
155119
155465
  }
155466
+ /**
155467
+ * 获取缓存结果
155468
+ * @param key 缓存 key
155469
+ */
155120
155470
  get(key) {
155121
155471
  const { nil } = this;
155122
155472
  const entry = this.store.get(key);
@@ -155130,6 +155480,7 @@ class Cache {
155130
155480
  }
155131
155481
  }
155132
155482
  exports.Cache = Cache;
155483
+ // 标志缓存不存在或过期
155133
155484
  Cache.NIL = Symbol('NIL');
155134
155485
  exports.memoryCache = new Cache();
155135
155486
  exports.nilCache = new Cache(true);
@@ -162451,6 +162802,7 @@ class Explorer extends ExplorerBase_1.ExplorerBase {
162451
162802
  return placeResult;
162452
162803
  }
162453
162804
  }
162805
+ // config not found
162454
162806
  return null;
162455
162807
  });
162456
162808
  }
@@ -181629,12 +181981,15 @@ exports.execWithLoading = exports.loadingFactory = void 0;
181629
181981
  const ora_1 = __importDefault(__webpack_require__(88267));
181630
181982
  class Loading {
181631
181983
  constructor() {
181984
+ // @ts-ignore
181632
181985
  process.on('tcbExit', this.stop.bind(this));
181986
+ // @ts-ignore
181633
181987
  process.on('tcbError', this.stop.bind(this));
181634
181988
  this.spinner = (0, ora_1.default)({
181635
181989
  discardStdin: false
181636
181990
  });
181637
181991
  }
181992
+ // eslint-disable-next-line
181638
181993
  set text(text) {
181639
181994
  this.spinner.text = text;
181640
181995
  }
@@ -181661,9 +182016,15 @@ const loadingFactory = () => {
181661
182016
  return new Loading();
181662
182017
  };
181663
182018
  exports.loadingFactory = loadingFactory;
182019
+ /**
182020
+ * 执行异步任务,显示 loading 动画
182021
+ * @param task
182022
+ * @param options
182023
+ */
181664
182024
  const execWithLoading = (task, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
181665
182025
  const { startTip, successTip, failTip } = options;
181666
182026
  const loading = (0, exports.loadingFactory)();
182027
+ // 刷新 loading 提示
181667
182028
  const flush = (text) => {
181668
182029
  loading.text = text;
181669
182030
  };
@@ -196377,6 +196738,7 @@ module.exports = {
196377
196738
 
196378
196739
  Object.defineProperty(exports, "__esModule", ({ value: true }));
196379
196740
  exports.getProxy = void 0;
196741
+ // 解析 Proxy 配置
196380
196742
  function getProxy() {
196381
196743
  const httpProxy = process.env.http_proxy ||
196382
196744
  process.env.HTTP_PROXY ||
@@ -203507,7 +203869,7 @@ ${envIdSection}
203507
203869
  ## 环境信息
203508
203870
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
203509
203871
  - Node.js版本: ${process.version}
203510
- - MCP 版本:${process.env.npm_package_version || "2.10.0" || 0}
203872
+ - MCP 版本:${process.env.npm_package_version || "2.11.1" || 0}
203511
203873
  - 系统架构: ${os_1.default.arch()}
203512
203874
  - 时间: ${new Date().toISOString()}
203513
203875
  - 请求ID: ${requestId}
@@ -203892,12 +204254,17 @@ const getSearchPlaces = (moduleName) => [
203892
204254
  `${moduleName}rc.js`,
203893
204255
  `${moduleName}.config.js`
203894
204256
  ];
204257
+ /**
204258
+ * 搜索指定配置文件,返回包含路径等信息
204259
+ */
203895
204260
  function searchConfig(dest, moduleName = MODULE_NAME) {
203896
204261
  return __awaiter(this, void 0, void 0, function* () {
203897
204262
  const explorer = (0, explorer_1.cosmiconfig)(moduleName, {
204263
+ // 不向上搜索
203898
204264
  stopDir: process.cwd(),
203899
204265
  searchPlaces: getSearchPlaces(moduleName)
203900
204266
  });
204267
+ // 搜索配置文件
203901
204268
  try {
203902
204269
  return explorer.search(dest || process.cwd());
203903
204270
  }
@@ -203907,14 +204274,21 @@ function searchConfig(dest, moduleName = MODULE_NAME) {
203907
204274
  });
203908
204275
  }
203909
204276
  exports.searchConfig = searchConfig;
204277
+ /**
204278
+ * 搜索或指定配置文件路径
204279
+ * 加载配置文件内容
204280
+ */
203910
204281
  function loadConfig(options = {}) {
203911
204282
  return __awaiter(this, void 0, void 0, function* () {
203912
204283
  const { moduleName = MODULE_NAME, configPath, searchFrom } = options;
203913
204284
  const explorer = (0, explorer_1.cosmiconfig)(moduleName, {
204285
+ // 不向上搜索
203914
204286
  stopDir: process.cwd(),
203915
204287
  searchPlaces: getSearchPlaces(moduleName)
203916
204288
  });
204289
+ // 从指定路径加载配置文件
203917
204290
  if (configPath) {
204291
+ // 校验路径是否存在
203918
204292
  (0, fs_1.checkReadable)(configPath, true);
203919
204293
  try {
203920
204294
  const result = yield explorer.load(configPath);
@@ -203929,6 +204303,7 @@ function loadConfig(options = {}) {
203929
204303
  });
203930
204304
  }
203931
204305
  }
204306
+ // 搜索配置文件
203932
204307
  try {
203933
204308
  const result = yield searchConfig(searchFrom || process.cwd(), moduleName);
203934
204309
  if (!result)
@@ -205414,6 +205789,7 @@ function cosmiconfig(moduleName, options = {}) {
205414
205789
  };
205415
205790
  }
205416
205791
  exports.cosmiconfig = cosmiconfig;
205792
+ // do not allow mutation of default loaders. Make sure it is set inside options
205417
205793
  const defaultLoaders = Object.freeze({
205418
205794
  '.js': loaders_1.loaders.loadJs,
205419
205795
  '.json': loaders_1.loaders.loadJson,
@@ -211109,11 +211485,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
211109
211485
  };
211110
211486
  Object.defineProperty(exports, "__esModule", ({ value: true }));
211111
211487
  exports.yaml = exports.yamlStringify = exports.yamlParse = void 0;
211488
+ // https://github.com/nodeca/js-yaml
211112
211489
  const yaml_1 = __importDefault(__webpack_require__(51381));
211490
+ // 解析 YAML 字符串
211113
211491
  const yamlParse = (doc) => {
211114
211492
  return yaml_1.default.parse(doc);
211115
211493
  };
211116
211494
  exports.yamlParse = yamlParse;
211495
+ // 导出为 YAML 字符串
211117
211496
  const yamlStringify = (object) => {
211118
211497
  return yaml_1.default.stringify(object);
211119
211498
  };
@@ -211651,8 +212030,11 @@ checkIndex: 检查索引是否存在`),
211651
212030
  title: "修改 NoSQL 数据库结构",
211652
212031
  description: "修改 NoSQL 数据库结构",
211653
212032
  inputSchema: {
211654
- action: zod_1.z.enum(["createCollection", "updateCollection", "deleteCollection"])
211655
- .describe(`createCollection: 创建集合
212033
+ action: zod_1.z.enum([
212034
+ "createCollection",
212035
+ "updateCollection",
212036
+ "deleteCollection",
212037
+ ]).describe(`createCollection: 创建集合
211656
212038
  updateCollection: 更新集合
211657
212039
  deleteCollection: 删除集合`),
211658
212040
  collectionName: zod_1.z.string().describe("集合名称"),
@@ -211732,9 +212114,7 @@ deleteCollection: 删除集合`),
211732
212114
  success: true,
211733
212115
  requestId: result.RequestId,
211734
212116
  action,
211735
- message: result.Exists === false
211736
- ? "集合不存在"
211737
- : "云开发数据库集合删除成功",
212117
+ message: result.Exists === false ? "集合不存在" : "云开发数据库集合删除成功",
211738
212118
  };
211739
212119
  if (result.Exists === false) {
211740
212120
  body.exists = false;
@@ -211765,9 +212145,17 @@ deleteCollection: 删除集合`),
211765
212145
  .optional()
211766
212146
  .describe("返回字段投影(对象或字符串,推荐对象)"),
211767
212147
  sort: zod_1.z
211768
- .union([zod_1.z.object({}).passthrough(), zod_1.z.string()])
212148
+ .union([
212149
+ zod_1.z.array(zod_1.z
212150
+ .object({
212151
+ key: zod_1.z.string().describe("sort 字段名"),
212152
+ direction: zod_1.z.number().describe("排序方向,1:升序,-1:降序"),
212153
+ })
212154
+ .passthrough()),
212155
+ zod_1.z.string(),
212156
+ ])
211769
212157
  .optional()
211770
- .describe("排序条件(对象或字符串,推荐对象)"),
212158
+ .describe("排序条件,使用对象或字符串。"),
211771
212159
  limit: zod_1.z.number().optional().describe("返回数量限制"),
211772
212160
  offset: zod_1.z.number().optional().describe("跳过的记录数"),
211773
212161
  },
@@ -211813,7 +212201,8 @@ deleteCollection: 删除集合`),
211813
212201
  title: "修改 NoSQL 数据库数据记录",
211814
212202
  description: "修改 NoSQL 数据库数据记录",
211815
212203
  inputSchema: {
211816
- action: zod_1.z.enum(["insert", "update", "delete"])
212204
+ action: zod_1.z
212205
+ .enum(["insert", "update", "delete"])
211817
212206
  .describe(`insert: 插入数据(新增文档)\nupdate: 更新数据\ndelete: 删除数据`),
211818
212207
  collectionName: zod_1.z.string().describe("集合名称"),
211819
212208
  documents: zod_1.z
@@ -217366,24 +217755,38 @@ const common_1 = __webpack_require__(96711);
217366
217755
  const coding_1 = __webpack_require__(40540);
217367
217756
  const web_1 = __webpack_require__(2240);
217368
217757
  const system_1 = __webpack_require__(62179);
217369
- const CliAuthBaseUrl = 'https://tcb.cloud.tencent.com/dev#/cli-auth';
217758
+ const CliAuthBaseUrl = 'https://tcb.cloud.tencent.com/dev';
217759
+ // 打开云开发控制台,获取授权
217370
217760
  function getAuthTokenFromWeb(options = {}) {
217371
217761
  return __awaiter(this, void 0, void 0, function* () {
217372
- const { getAuthUrl } = options;
217762
+ const { getAuthUrl, noBrowser, callbackTimeout } = options;
217373
217763
  const mac = yield (0, system_1.getMacAddress)();
217374
217764
  const os = (0, system_1.getOSInfo)();
217375
217765
  const macHash = (0, coding_1.md5Encoding)(mac);
217376
217766
  const query = yield (0, web_1.getDataFromWeb)((port) => {
217377
- let cliAuthUrl = `${CliAuthBaseUrl}?port=${port}&hash=${macHash}&mac=${mac}&os=${os}&from=cli`;
217767
+ const callbackUrl = `http://127.0.0.1:${port}`;
217768
+ const encodedQuery = `port=${encodeURIComponent(String(port))}`
217769
+ + `&hash=${encodeURIComponent(macHash)}`
217770
+ + `&mac=${encodeURIComponent(mac)}`
217771
+ + `&os=${encodeURIComponent(os)}`
217772
+ + '&from=cli';
217773
+ const encodedCallbackUrl = encodeURIComponent(callbackUrl);
217774
+ // 授权链接
217775
+ const rawAuthUrl = `${CliAuthBaseUrl}?authCallbackUrl=${encodedCallbackUrl}#/cli-auth?${encodedQuery}`;
217776
+ let cliAuthUrl = rawAuthUrl;
217378
217777
  if (getAuthUrl) {
217379
217778
  try {
217380
- cliAuthUrl = getAuthUrl(`${CliAuthBaseUrl}?port=${port}&hash=${macHash}&mac=${mac}&os=${os}&from=cli`);
217779
+ cliAuthUrl = getAuthUrl(rawAuthUrl);
217381
217780
  }
217382
217781
  catch (error) {
217782
+ // 忽略错误
217383
217783
  }
217384
217784
  }
217385
217785
  return cliAuthUrl;
217386
- }, 'login');
217786
+ }, 'login', {
217787
+ noBrowser,
217788
+ callbackTimeout
217789
+ });
217387
217790
  const credential = (0, common_1.resolveCredential)(query);
217388
217791
  return credential;
217389
217792
  });
@@ -218223,7 +218626,7 @@ function registerSetupTools(server) {
218223
218626
  title: "下载项目模板",
218224
218627
  description: `自动下载并部署CloudBase项目模板。⚠️ **MANDATORY FOR NEW PROJECTS** ⚠️
218225
218628
 
218226
- **CRITICAL**: This tool MUST be called FIRST when starting a new project.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.10.0" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
218629
+ **CRITICAL**: This tool MUST be called FIRST when starting a new project.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.11.1" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
218227
218630
  inputSchema: {
218228
218631
  template: zod_1.z
218229
218632
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -255443,6 +255846,7 @@ module.exports = exports
255443
255846
 
255444
255847
  Object.defineProperty(exports, "__esModule", ({ value: true }));
255445
255848
  exports.detectIndent = void 0;
255849
+ // https://github.com/sindresorhus/detect-indent/blob/master/index.js
255446
255850
  const INDENT_REGEX = /^(?:( )+|\t+)/;
255447
255851
  const INDENT_TYPE_SPACE = 'space';
255448
255852
  const INDENT_TYPE_TAB = 'tab';
@@ -255453,6 +255857,7 @@ function makeIndentsMap(string) {
255453
255857
  let key;
255454
255858
  for (const line of string.split(/\n/g)) {
255455
255859
  if (!line) {
255860
+ // Ignore empty lines
255456
255861
  continue;
255457
255862
  }
255458
255863
  let indent;
@@ -255479,16 +255884,19 @@ function makeIndentsMap(string) {
255479
255884
  weight = 0;
255480
255885
  const indentDifference = indent - previousSize;
255481
255886
  previousSize = indent;
255887
+ // Previous line have same indent?
255482
255888
  if (indentDifference === 0) {
255483
255889
  weight++;
255890
+ // We use the key from previous loop
255484
255891
  }
255485
255892
  else {
255486
255893
  const absoluteIndentDifference = indentDifference > 0 ? indentDifference : -indentDifference;
255487
255894
  key = encodeIndentsKey(indentType, absoluteIndentDifference);
255488
255895
  }
255896
+ // Update the stats
255489
255897
  entry = indents.get(key);
255490
255898
  if (entry === undefined) {
255491
- entry = [1, 0];
255899
+ entry = [1, 0]; // Init
255492
255900
  }
255493
255901
  else {
255494
255902
  entry = [++entry[0], entry[1] + weight];
@@ -255498,16 +255906,20 @@ function makeIndentsMap(string) {
255498
255906
  }
255499
255907
  return indents;
255500
255908
  }
255909
+ // Encode the indent type and amount as a string (e.g. 's4') for use as a compound key in the indents Map.
255501
255910
  function encodeIndentsKey(indentType, indentAmount) {
255502
255911
  const typeCharacter = indentType === INDENT_TYPE_SPACE ? 's' : 't';
255503
255912
  return typeCharacter + String(indentAmount);
255504
255913
  }
255914
+ // Extract the indent type and amount from a key of the indents Map.
255505
255915
  function decodeIndentsKey(indentsKey) {
255506
255916
  const keyHasTypeSpace = indentsKey[0] === 's';
255507
255917
  const type = keyHasTypeSpace ? INDENT_TYPE_SPACE : INDENT_TYPE_TAB;
255508
255918
  const amount = Number(indentsKey.slice(1));
255509
255919
  return { type, amount };
255510
255920
  }
255921
+ // Return the key (e.g. 's4') from the indents Map that represents the most common indent,
255922
+ // or return undefined if there are no indents.
255511
255923
  function getMostUsedKey(indents) {
255512
255924
  let result;
255513
255925
  let maxUsed = 0;
@@ -256217,11 +256629,43 @@ exports.resetInteractiveServer = resetInteractiveServer;
256217
256629
  exports.getInteractiveServerSafe = getInteractiveServerSafe;
256218
256630
  const express_1 = __importDefault(__webpack_require__(26083));
256219
256631
  const http_1 = __importDefault(__webpack_require__(81630));
256632
+ const child_process_1 = __webpack_require__(79646);
256220
256633
  const open_1 = __importDefault(__webpack_require__(45368));
256221
256634
  const ws_1 = __webpack_require__(17699);
256222
256635
  const index_js_1 = __webpack_require__(79529);
256223
256636
  const logger_js_1 = __webpack_require__(13039);
256224
- // 动态导入 open 模块,兼容 ESM/CJS 环境
256637
+ function isVSCodeEnvironment() {
256638
+ return Boolean(process.env.VSCODE_IPC_HOOK_CLI ||
256639
+ process.env.VSCODE_PID ||
256640
+ process.env.TERM_PROGRAM === "vscode");
256641
+ }
256642
+ function parseBrowserCommand(browser) {
256643
+ const parts = browser.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
256644
+ return parts.map((item) => item.replace(/^"(.*)"$/, "$1"));
256645
+ }
256646
+ async function openUrlByBrowserEnv(url) {
256647
+ const browser = process.env.BROWSER?.trim();
256648
+ if (!browser) {
256649
+ return false;
256650
+ }
256651
+ const [command, ...args] = parseBrowserCommand(browser);
256652
+ if (!command) {
256653
+ return false;
256654
+ }
256655
+ const finalArgs = args.map((arg) => (arg === "%s" ? url : arg));
256656
+ if (!args.includes("%s")) {
256657
+ finalArgs.push(url);
256658
+ }
256659
+ return new Promise((resolve) => {
256660
+ (0, child_process_1.execFile)(command, finalArgs, (execError) => {
256661
+ resolve(!execError);
256662
+ });
256663
+ });
256664
+ }
256665
+ function shouldUseBrowserEnvFallback() {
256666
+ return process.platform === "linux" && isVSCodeEnvironment();
256667
+ }
256668
+ // Dynamic open behavior with IDE awareness and VSCode/Linux fallback
256225
256669
  async function openUrl(url, options, mcpServer) {
256226
256670
  // mcpServer 是 ExtendedMcpServer 实例,它有 server 和 ide 属性
256227
256671
  // server 属性是 MCP server 的内部 server 实例,有 sendLoggingMessage 方法
@@ -256253,13 +256697,28 @@ async function openUrl(url, options, mcpServer) {
256253
256697
  return;
256254
256698
  }
256255
256699
  }
256256
- // 默认行为:直接打开网页
256700
+ // 默认行为:直接打开网页(带 VSCode/Linux 降级逻辑)
256257
256701
  (0, logger_js_1.debug)(`[openUrl] Opening URL in browser: ${url}`);
256258
256702
  try {
256259
- return await (0, open_1.default)(url, options);
256703
+ const openOptions = options ? { url: true, ...options } : { url: true };
256704
+ const child = await (0, open_1.default)(url, openOptions);
256705
+ if (child?.once) {
256706
+ child.once("error", async () => {
256707
+ if (shouldUseBrowserEnvFallback()) {
256708
+ (0, logger_js_1.debug)("[openUrl] open() failed, trying BROWSER fallback");
256709
+ await openUrlByBrowserEnv(url);
256710
+ }
256711
+ });
256712
+ }
256713
+ return;
256260
256714
  }
256261
256715
  catch (err) {
256262
256716
  (0, logger_js_1.error)(`Failed to open ${url} ${options} ${err instanceof Error ? err.message : err} `, err instanceof Error ? err : new Error(String(err)));
256717
+ if (shouldUseBrowserEnvFallback()) {
256718
+ (0, logger_js_1.debug)("[openUrl] open() threw, trying BROWSER fallback");
256719
+ await openUrlByBrowserEnv(url);
256720
+ return;
256721
+ }
256263
256722
  (0, logger_js_1.warn)(`Please manually open: ${url}`);
256264
256723
  }
256265
256724
  }
@@ -256284,10 +256743,15 @@ class InteractiveServer {
256284
256743
  3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733,
256285
256744
  3734, 3735,
256286
256745
  ];
256746
+ /** Idle timeout for HTTP/WS connections (e.g. long login). Avoids "connection disconnected" after ~1 min. */
256747
+ static SERVER_IDLE_MS = 30 * 60 * 1000; // 30 minutes
256748
+ /** WebSocket ping interval to keep connection alive past proxies/firewalls. */
256749
+ static WS_PING_INTERVAL_MS = 25 * 1000; // 25 seconds
256287
256750
  constructor(mcpServer) {
256288
256751
  this._mcpServer = mcpServer;
256289
256752
  this.app = (0, express_1.default)();
256290
256753
  this.server = http_1.default.createServer(this.app);
256754
+ this.applyServerTimeouts();
256291
256755
  this.wss = new ws_1.WebSocketServer({ server: this.server });
256292
256756
  this.setupExpress();
256293
256757
  this.setupWebSocket();
@@ -256303,6 +256767,16 @@ class InteractiveServer {
256303
256767
  this.isRunning = false;
256304
256768
  }
256305
256769
  }
256770
+ /** Apply timeouts so long-lived login does not cause "connection disconnected". */
256771
+ applyServerTimeouts() {
256772
+ this.server.timeout = 0;
256773
+ if (typeof this.server.keepAliveTimeout === "number") {
256774
+ this.server.keepAliveTimeout = InteractiveServer.SERVER_IDLE_MS;
256775
+ }
256776
+ if (typeof this.server.headersTimeout === "number") {
256777
+ this.server.headersTimeout = Math.max(this.server.headersTimeout || 0, InteractiveServer.SERVER_IDLE_MS);
256778
+ }
256779
+ }
256306
256780
  setupExpress() {
256307
256781
  this.app.use(express_1.default.json());
256308
256782
  this.app.get("/env-setup/:sessionId", (req, res) => {
@@ -256406,6 +256880,16 @@ class InteractiveServer {
256406
256880
  setupWebSocket() {
256407
256881
  this.wss.on("connection", (ws) => {
256408
256882
  (0, logger_js_1.debug)("WebSocket client connected");
256883
+ // Keep connection alive during long login so proxies/firewalls do not close it
256884
+ const pingInterval = setInterval(() => {
256885
+ if (ws.readyState === ws_1.WebSocket.OPEN) {
256886
+ ws.ping();
256887
+ }
256888
+ }, InteractiveServer.WS_PING_INTERVAL_MS);
256889
+ ws.on("close", () => {
256890
+ clearInterval(pingInterval);
256891
+ (0, logger_js_1.debug)("WebSocket client disconnected");
256892
+ });
256409
256893
  ws.on("message", async (message) => {
256410
256894
  try {
256411
256895
  const data = JSON.parse(message.toString());
@@ -256515,9 +256999,6 @@ class InteractiveServer {
256515
256999
  (0, logger_js_1.error)("WebSocket message parsing error", err instanceof Error ? err : new Error(String(err)));
256516
257000
  }
256517
257001
  });
256518
- ws.on("close", () => {
256519
- (0, logger_js_1.debug)("WebSocket client disconnected");
256520
- });
256521
257002
  });
256522
257003
  }
256523
257004
  async start() {
@@ -256559,13 +257040,15 @@ class InteractiveServer {
256559
257040
  reject(err);
256560
257041
  }
256561
257042
  };
257043
+ // Host: default 0.0.0.0 so Cloud IDE / VSCode Remote port-forward can connect; set INTERACTIVE_SERVER_HOST=127.0.0.1 for local-only
257044
+ const host = process.env.INTERACTIVE_SERVER_HOST ?? "0.0.0.0";
256562
257045
  // 设置成功监听处理
256563
257046
  const listeningHandler = () => {
256564
257047
  const address = this.server.address();
256565
257048
  if (address && typeof address === "object") {
256566
257049
  this.port = address.port;
256567
257050
  this.isRunning = true;
256568
- (0, logger_js_1.info)(`Interactive server started successfully on http://localhost:${this.port}`);
257051
+ (0, logger_js_1.info)(`Interactive server started successfully on http://${host}:${this.port}`);
256569
257052
  // 移除临时监听器
256570
257053
  this.server.removeListener("error", errorHandler);
256571
257054
  this.server.removeListener("listening", listeningHandler);
@@ -256580,7 +257063,7 @@ class InteractiveServer {
256580
257063
  this.server.once("error", errorHandler);
256581
257064
  this.server.once("listening", listeningHandler);
256582
257065
  try {
256583
- this.server.listen(portToTry, "127.0.0.1");
257066
+ this.server.listen(portToTry, host);
256584
257067
  }
256585
257068
  catch (err) {
256586
257069
  (0, logger_js_1.error)(`Failed to bind to port ${portToTry}:`, err instanceof Error ? err : new Error(String(err)));
@@ -256621,6 +257104,7 @@ class InteractiveServer {
256621
257104
  this.port = 0;
256622
257105
  // 重新创建整个服务器实例以便下次使用
256623
257106
  this.server = http_1.default.createServer(this.app);
257107
+ this.applyServerTimeouts();
256624
257108
  this.wss = new ws_1.WebSocketServer({ server: this.server });
256625
257109
  this.setupWebSocket();
256626
257110
  (0, logger_js_1.debug)("HTTP and WebSocket servers recreated for next use");
@@ -256711,11 +257195,9 @@ class InteractiveServer {
256711
257195
  (0, logger_js_1.warn)(`Please manually open: ${url}`);
256712
257196
  }
256713
257197
  (0, logger_js_1.info)("Waiting for user selection...");
256714
- // Use shorter timeout for CodeBuddy when notification is sent (2 minutes)
256715
- // This prevents hanging while still giving users enough time to respond
256716
- // Otherwise use the default 10 minutes timeout
256717
- const timeoutDuration = (isCodeBuddy && notificationSent) ? 2 * 60 * 1000 : 10 * 60 * 1000;
256718
- (0, logger_js_1.debug)(`[collectEnvId] Using timeout duration: ${timeoutDuration / 1000} seconds (CodeBuddy: ${isCodeBuddy}, notification sent: ${notificationSent})`);
257198
+ // Use same 10 minutes for all IDEs so long login (re-auth, switch account) does not close the server
257199
+ const timeoutDuration = 10 * 60 * 1000;
257200
+ (0, logger_js_1.debug)(`[collectEnvId] Using timeout duration: ${timeoutDuration / 1000} seconds`);
256719
257201
  return new Promise((resolve) => {
256720
257202
  this.currentResolver = (result) => {
256721
257203
  // 用户选择完成后,关闭服务器
@@ -274943,8 +275425,14 @@ const fs_1 = __importDefault(__webpack_require__(29021));
274943
275425
  const del_1 = __importDefault(__webpack_require__(62958));
274944
275426
  const make_dir_1 = __importDefault(__webpack_require__(55589));
274945
275427
  const error_1 = __webpack_require__(64119);
275428
+ /**
275429
+ * 检查路径是否可以访问(读、写)
275430
+ * @param dest 目标路径
275431
+ * @param throwError 无权限时是否抛出异常
275432
+ */
274946
275433
  function checkFullAccess(dest, throwError = false) {
274947
275434
  try {
275435
+ // 可见、可写
274948
275436
  fs_1.default.accessSync(dest, fs_1.default.constants.F_OK);
274949
275437
  fs_1.default.accessSync(dest, fs_1.default.constants.W_OK);
274950
275438
  fs_1.default.accessSync(dest, fs_1.default.constants.R_OK);
@@ -274960,8 +275448,14 @@ function checkFullAccess(dest, throwError = false) {
274960
275448
  }
274961
275449
  }
274962
275450
  exports.checkFullAccess = checkFullAccess;
275451
+ /**
275452
+ * 检查路径是否可以读
275453
+ * @param dest 目标路径
275454
+ * @param throwError 无权限时是否抛出异常
275455
+ */
274963
275456
  function checkWritable(dest, throwError = false) {
274964
275457
  try {
275458
+ // 可见、可写
274965
275459
  fs_1.default.accessSync(dest, fs_1.default.constants.F_OK);
274966
275460
  fs_1.default.accessSync(dest, fs_1.default.constants.W_OK);
274967
275461
  return true;
@@ -274976,8 +275470,14 @@ function checkWritable(dest, throwError = false) {
274976
275470
  }
274977
275471
  }
274978
275472
  exports.checkWritable = checkWritable;
275473
+ /**
275474
+ * 检查路径是否可以写
275475
+ * @param dest 目标路径
275476
+ * @param throwError 无权限或路径不存在时是否抛出异常
275477
+ */
274979
275478
  function checkReadable(dest, throwError = false) {
274980
275479
  try {
275480
+ // 可见、可读
274981
275481
  fs_1.default.accessSync(dest, fs_1.default.constants.F_OK);
274982
275482
  fs_1.default.accessSync(dest, fs_1.default.constants.R_OK);
274983
275483
  return true;
@@ -274992,10 +275492,18 @@ function checkReadable(dest, throwError = false) {
274992
275492
  }
274993
275493
  }
274994
275494
  exports.checkReadable = checkReadable;
275495
+ /**
275496
+ * 检查指定路径是否为文件夹
275497
+ * @param dest 目标路径
275498
+ */
274995
275499
  function isDirectorySync(dest) {
274996
275500
  return fs_1.default.statSync(dest).isDirectory();
274997
275501
  }
274998
275502
  exports.isDirectorySync = isDirectorySync;
275503
+ /**
275504
+ * 检查指定路径是否为文件夹,异步
275505
+ * @param dest 目标路径
275506
+ */
274999
275507
  function isDirectoryAsync(dest) {
275000
275508
  return __awaiter(this, void 0, void 0, function* () {
275001
275509
  const stat = yield fs_1.default.promises.stat(dest);
@@ -275003,6 +275511,12 @@ function isDirectoryAsync(dest) {
275003
275511
  });
275004
275512
  }
275005
275513
  exports.isDirectoryAsync = isDirectoryAsync;
275514
+ /**
275515
+ * 格式化文件大小,保留两位小数
275516
+ * @param size 原数据,单位 Byte
275517
+ * @param unit 目标单位,支持 KB、MB、GB、TB
275518
+ * @param fixed 保留小数位数,默认 2 位
275519
+ */
275006
275520
  function formateFileSize(size, unit, fixed) {
275007
275521
  const numSize = Number(size);
275008
275522
  const unitMap = {
@@ -275014,6 +275528,7 @@ function formateFileSize(size, unit, fixed) {
275014
275528
  return Number(numSize / unitMap[unit]).toFixed(fixed);
275015
275529
  }
275016
275530
  exports.formateFileSize = formateFileSize;
275531
+ // 创建文件夹
275017
275532
  function mkdirSync(dest) {
275018
275533
  make_dir_1.default.sync(dest);
275019
275534
  }
@@ -275024,6 +275539,7 @@ function mkdirAsync(dest) {
275024
275539
  });
275025
275540
  }
275026
275541
  exports.mkdirAsync = mkdirAsync;
275542
+ // 转换 Windows 下的反斜杠路径
275027
275543
  const slash = (input) => {
275028
275544
  const isExtendedLengthPath = /^\\\\\?\\/.test(input);
275029
275545
  if (isExtendedLengthPath) {
@@ -275032,8 +275548,10 @@ const slash = (input) => {
275032
275548
  return input.replace(/\\/g, '/');
275033
275549
  };
275034
275550
  exports.slash = slash;
275551
+ // 删除文件
275035
275552
  function delSync(patterns) {
275036
275553
  let paths;
275554
+ // 不能再使用反斜杠,修复 Windows 下的问题 https://github.com/sindresorhus/del/releases/tag/v5.0.0
275037
275555
  if (Array.isArray(patterns)) {
275038
275556
  paths = patterns.map((item) => (0, exports.slash)(item));
275039
275557
  }
@@ -275732,8 +276250,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
275732
276250
  exports.resolveWebCredential = exports.resolveCredential = exports.checkAuth = void 0;
275733
276251
  const cloud_api_1 = __webpack_require__(2090);
275734
276252
  const config_1 = __webpack_require__(88472);
276253
+ // 调用 env:list 接口,检查密钥是否有效
275735
276254
  function checkAuth(credential, options = {}) {
275736
276255
  return __awaiter(this, void 0, void 0, function* () {
276256
+ // 兼容原临时秘钥
275737
276257
  const { secretId, secretKey, token } = resolveCredential(credential);
275738
276258
  const { proxy, timeout } = options;
275739
276259
  const region = yield (0, config_1.getRegion)();
@@ -275754,8 +276274,10 @@ function checkAuth(credential, options = {}) {
275754
276274
  });
275755
276275
  }
275756
276276
  exports.checkAuth = checkAuth;
276277
+ // 兼容解析旧的登录态
275757
276278
  function resolveCredential(data) {
275758
276279
  let { secretId, secretKey, token, accessTokenExpired, tmpSecretId, tmpSecretKey, tmpToken, tmpExpired, expired, authTime, refreshToken, uin, hash, envId } = data;
276280
+ // 兼容旧的登录态信息
275759
276281
  token = token || tmpToken;
275760
276282
  secretId = secretId || tmpSecretId;
275761
276283
  secretKey = secretKey || tmpSecretKey;
@@ -281712,6 +282234,7 @@ function resolveCredentialFormEnv() {
281712
282234
  token
281713
282235
  };
281714
282236
  }
282237
+ // 获取 credential 数据
281715
282238
  function getCredentialData() {
281716
282239
  return __awaiter(this, void 0, void 0, function* () {
281717
282240
  const localData = (yield exports.authStore.get('credential'));
@@ -281720,6 +282243,7 @@ function getCredentialData() {
281720
282243
  const keys = Object.keys(credential)
281721
282244
  .filter((key) => credential[key])
281722
282245
  .filter((key) => key !== '-');
282246
+ // 检查是否为空对象
281723
282247
  if (!credential || keys.length === 0) {
281724
282248
  return null;
281725
282249
  }
@@ -281727,6 +282251,7 @@ function getCredentialData() {
281727
282251
  });
281728
282252
  }
281729
282253
  exports.getCredentialData = getCredentialData;
282254
+ // 临时密钥过期后,进行续期
281730
282255
  function refreshTmpToken(metaData) {
281731
282256
  return __awaiter(this, void 0, void 0, function* () {
281732
282257
  const mac = yield (0, system_1.getMacAddress)();
@@ -281735,6 +282260,7 @@ function refreshTmpToken(metaData) {
281735
282260
  const credential = (0, common_1.resolveWebCredential)(metaData);
281736
282261
  const res = yield async_1.AsyncMerge.merge(() => (0, cloud_api_1.fetch)(refreshTokenUrl, {
281737
282262
  method: 'POST',
282263
+ // 超时时间:15S
281738
282264
  timeout: 15000,
281739
282265
  body: JSON.stringify(credential),
281740
282266
  headers: { 'Content-Type': 'application/json' }
@@ -281758,6 +282284,7 @@ function refreshTmpToken(metaData) {
281758
282284
  });
281759
282285
  }
281760
282286
  exports.refreshTmpToken = refreshTmpToken;
282287
+ // 是否为 CAM 权限错误
281761
282288
  const isCamRefused = (e) => {
281762
282289
  return (Number(e.code) === 4102 ||
281763
282290
  Number(e.code) === 42 ||
@@ -281765,16 +282292,22 @@ const isCamRefused = (e) => {
281765
282292
  e.code === 'AuthFailure.UnauthorizedOperation');
281766
282293
  };
281767
282294
  exports.isCamRefused = isCamRefused;
282295
+ // 报错返回 null 值
281768
282296
  function wrapCheckAuth(credential, options) {
281769
282297
  return __awaiter(this, void 0, void 0, function* () {
281770
282298
  const { timeout = 15000 } = options;
281771
282299
  try {
282300
+ // 合并请求,避免超过接口限频
281772
282301
  yield async_1.AsyncMerge.merge(() => (0, common_1.checkAuth)(credential, options), 'checkAuth', {
282302
+ // 超时时间不能小于发送请求的超时时间
281773
282303
  timeout: Number(timeout) ? (timeout < 15000 ? 15000 : timeout + 1000) : 15000
281774
282304
  });
281775
282305
  return credential;
281776
282306
  }
281777
282307
  catch (e) {
282308
+ // CAM 错误视为登录正常
282309
+ // if (isCamRefused(e)) return credential;
282310
+ // 请求超时
281778
282311
  if (e.type === 'request-timeout') {
281779
282312
  throw new error_1.CloudBaseError('请求超时,请检查你的网络,如果终端无法直接访问公网,请设置终端 HTTP 请求代理!');
281780
282313
  }
@@ -281782,38 +282315,50 @@ function wrapCheckAuth(credential, options) {
281782
282315
  }
281783
282316
  });
281784
282317
  }
282318
+ // token 将在 n 分钟内过期
281785
282319
  const isTokenExpired = (credential, gap = 120) => credential.accessTokenExpired &&
281786
282320
  Number(credential.accessTokenExpired) < Date.now() + gap * 1000;
282321
+ // 获取身份认证信息并校验、自动刷新
281787
282322
  function checkAndGetCredential(options = {}) {
281788
282323
  return __awaiter(this, void 0, void 0, function* () {
282324
+ // 从本地存储中读取 credential
281789
282325
  const credential = yield getCredentialData();
281790
282326
  if (!credential) {
281791
282327
  return null;
281792
282328
  }
282329
+ // 存在临时密钥信息
281793
282330
  if (credential.refreshToken) {
282331
+ // 临时密钥在 2 小时有效期内,可以直接使用
281794
282332
  if (!isTokenExpired(credential)) {
282333
+ // 检查 credential
281795
282334
  return wrapCheckAuth(credential, options);
281796
282335
  }
281797
282336
  else if (Date.now() < Number(credential.expired)) {
282337
+ // 临时密钥超过两小时有效期,但在 1 个月 refresh 有效期内,刷新临时密钥
281798
282338
  let refreshCredential;
281799
282339
  try {
281800
282340
  refreshCredential = yield refreshTmpToken(credential);
281801
282341
  }
281802
282342
  catch (e) {
282343
+ // 登录态失效
281803
282344
  if (e.code === 'AUTH_FAIL') {
281804
282345
  return null;
281805
282346
  }
281806
282347
  else if (e.code === 'InternalError.GetRoleError') {
282348
+ // 用户未开通服务,视为登录态失效
281807
282349
  return null;
281808
282350
  }
281809
282351
  else {
282352
+ // 异常错误
281810
282353
  throw e;
281811
282354
  }
281812
282355
  }
282356
+ // 存储新的秘钥
281813
282357
  yield exports.authStore.set('credential', refreshCredential || {});
281814
282358
  return wrapCheckAuth((0, common_1.resolveCredential)(refreshCredential), options);
281815
282359
  }
281816
282360
  }
282361
+ // 存在永久密钥
281817
282362
  if (credential.secretId && credential.secretKey) {
281818
282363
  return wrapCheckAuth(credential, options);
281819
282364
  }
@@ -281821,36 +282366,45 @@ function checkAndGetCredential(options = {}) {
281821
282366
  });
281822
282367
  }
281823
282368
  exports.checkAndGetCredential = checkAndGetCredential;
282369
+ // 获取身份认证信息,不校验
281824
282370
  function getCredentialWithoutCheck() {
281825
282371
  return __awaiter(this, void 0, void 0, function* () {
281826
282372
  const credential = yield getCredentialData();
281827
282373
  if (!credential) {
281828
282374
  return null;
281829
282375
  }
282376
+ // 存在临时密钥信息
281830
282377
  if (credential.refreshToken) {
282378
+ // 临时密钥在 2 小时有效期内,可以直接使用
281831
282379
  if (!isTokenExpired(credential)) {
281832
282380
  return credential;
281833
282381
  }
281834
282382
  else if (Date.now() < Number(credential.expired)) {
282383
+ // 临时密钥超过两小时有效期,但在 1 个月 refresh 有效期内,刷新临时密钥
281835
282384
  let refreshCredential;
281836
282385
  try {
281837
282386
  refreshCredential = yield refreshTmpToken(credential);
281838
282387
  }
281839
282388
  catch (e) {
282389
+ // 登录态失效
281840
282390
  if (e.code === 'AUTH_FAIL') {
281841
282391
  return null;
281842
282392
  }
281843
282393
  else if (e.code === 'InternalError.GetRoleError') {
282394
+ // 用户未开通服务,视为登录态失效
281844
282395
  return null;
281845
282396
  }
281846
282397
  else {
282398
+ // 异常错误
281847
282399
  throw e;
281848
282400
  }
281849
282401
  }
282402
+ // 存储新的秘钥
281850
282403
  yield exports.authStore.set('credential', refreshCredential || {});
281851
282404
  return (0, common_1.resolveCredential)(refreshCredential);
281852
282405
  }
281853
282406
  }
282407
+ // 存在永久密钥
281854
282408
  if (credential.secretId && credential.secretKey) {
281855
282409
  return credential;
281856
282410
  }