@cloudbase/cli 2.8.2-beta.1 → 2.8.2-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -84,7 +84,6 @@ let AICommand = class AICommand extends common_1.Command {
84
84
  return yield this.showConfig(configManager, log);
85
85
  }
86
86
  if (!(yield configManager.isConfigured())) {
87
- log.info('AI 功能未配置,正在启动配置向导...');
88
87
  const wizard = new setup_1.AISetupWizard(envId);
89
88
  const { defaultAgent } = yield wizard.setUpDefault(log);
90
89
  agent = defaultAgent;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.claudeWindowsCheck = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const path_1 = require("path");
6
+ const output_1 = require("../output");
7
+ function claudeWindowsCheck(log) {
8
+ const claudeWindowsCheck = checkWindowsClaudeOk();
9
+ if ('error' in claudeWindowsCheck) {
10
+ log.error(claudeWindowsCheck.error);
11
+ process.exit(1);
12
+ }
13
+ }
14
+ exports.claudeWindowsCheck = claudeWindowsCheck;
15
+ function checkWindowsClaudeOk() {
16
+ if (process.platform !== 'win32')
17
+ return { success: true };
18
+ if (process.env.CLAUDE_CODE_GIT_BASH_PATH) {
19
+ if (pathExistsOnWindows(process.env.CLAUDE_CODE_GIT_BASH_PATH))
20
+ return { success: true };
21
+ return {
22
+ error: `环境变量 CLAUDE_CODE_GIT_BASH_PATH 指定的路径 "${process.env.CLAUDE_CODE_GIT_BASH_PATH}" 不存在,请检查`
23
+ };
24
+ }
25
+ let gitExecutablePath = resolveWindowsExecutablePath('git');
26
+ if (gitExecutablePath) {
27
+ let bashExeCandidate = path_1.win32.join(gitExecutablePath, '..', '..', 'bin', 'bash.exe');
28
+ if (pathExistsOnWindows(bashExeCandidate))
29
+ return { success: true };
30
+ }
31
+ return {
32
+ error: `Claude Code 在 Windows 上需要 git-bash (https://git-scm.com/downloads/win)。如果已安装但不在 PATH 中,请设置环境变量 CLAUDE_CODE_GIT_BASH_PATH 指向你的 bash.exe,类似:CLAUDE_CODE_GIT_BASH_PATH=C:\\Program Files\\Git\\bin\\bash.exe
33
+ 或者使用 WSL 运行。详情可阅读官方文档 ${(0, output_1.genClickableLink)('https://docs.anthropic.com/zh-CN/docs/claude-code/setup#windows-%E8%AE%BE%E7%BD%AE')}`
34
+ };
35
+ }
36
+ function pathExistsOnWindows(targetPath) {
37
+ try {
38
+ return (0, child_process_1.execSync)(`dir "${targetPath}"`, { stdio: 'pipe' });
39
+ }
40
+ catch (_a) {
41
+ return !1;
42
+ }
43
+ }
44
+ function resolveWindowsExecutablePath(executableName) {
45
+ if (executableName === 'git') {
46
+ let candidatePaths = [
47
+ 'C:\\Program Files\\Git\\cmd\\git.exe',
48
+ 'C:\\Program Files (x86)\\Git\\cmd\\git.exe'
49
+ ];
50
+ for (let candidatePath of candidatePaths)
51
+ if (pathExistsOnWindows(candidatePath))
52
+ return candidatePath;
53
+ }
54
+ try {
55
+ return ((0, child_process_1.execSync)(`where.exe ${executableName}`, { stdio: 'pipe', encoding: 'utf8' }).trim()
56
+ .split(`\r
57
+ `)[0] || null);
58
+ }
59
+ catch (_a) {
60
+ return null;
61
+ }
62
+ }
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.LIST_HINT = exports.getBooleanHint = exports.getDefaultModelByBaseUrl = exports.BASE_URL_MODEL_MAPPING = exports.getAgentConfigValidator = exports.getDefaultConfig = exports.CLOUDBASE_PROVIDERS = exports.AGENTS = exports.NONE = exports.AIDER = exports.CODEX = exports.QWEN = exports.CLAUDE = exports.DEFAULT_CONFIG = exports.CLOUDBASE_MCP_CONFIG_PATH = exports.CLAUDE_CODE_ROUTER_LOG_PATH = exports.CLAUDE_CODE_ROUTER_CONFIG_PATH = exports.ENV_LOCAL_PATH = exports.CONFIG_PATH = void 0;
6
+ exports.LIST_HINT = exports.getBooleanHint = exports.getDefaultModelByBaseUrl = exports.BASE_URL_MODEL_MAPPING = exports.getAgentConfigValidator = exports.getDefaultConfig = exports.CLOUDBASE_PROVIDERS = exports.AGENTS = exports.NONE = exports.AIDER = exports.CODEX = exports.QWEN = exports.CLAUDE = exports.DEFAULT_CONFIG = exports.CLOUDBASE_MCP_CONFIG_PATH = exports.CLAUDE_CODE_ROUTER_LOGS_DIR_PATH = exports.CLAUDE_CODE_ROUTER_LOG_PATH = exports.CLAUDE_CODE_ROUTER_CONFIG_PATH = exports.ENV_LOCAL_PATH = exports.CONFIG_PATH = void 0;
7
7
  const os_1 = __importDefault(require("os"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const v3_1 = __importDefault(require("zod/v3"));
@@ -11,6 +11,7 @@ exports.CONFIG_PATH = path_1.default.join(process.cwd(), 'cloudbaserc.json');
11
11
  exports.ENV_LOCAL_PATH = path_1.default.join(process.cwd(), '.env.local');
12
12
  exports.CLAUDE_CODE_ROUTER_CONFIG_PATH = path_1.default.join(os_1.default.homedir(), '.claude-code-router', 'config.json');
13
13
  exports.CLAUDE_CODE_ROUTER_LOG_PATH = path_1.default.join(os_1.default.homedir(), '.claude-code-router', 'claude-code-router.log');
14
+ exports.CLAUDE_CODE_ROUTER_LOGS_DIR_PATH = path_1.default.join(os_1.default.homedir(), '.claude-code-router', 'logs');
14
15
  exports.CLOUDBASE_MCP_CONFIG_PATH = path_1.default.join(os_1.default.homedir(), '.cloudbase-env-id');
15
16
  exports.DEFAULT_CONFIG = `{
16
17
  "envId": "{{env.ENV_ID}}"
@@ -168,4 +169,4 @@ function getBooleanHint(defaultValue) {
168
169
  return `y 是${defaultValue === true ? '(留空默认)' : ''}; n 否${defaultValue === false ? '(留空默认)' : ''}; enter 确认`;
169
170
  }
170
171
  exports.getBooleanHint = getBooleanHint;
171
- exports.LIST_HINT = '使用上下键选择,输入 enter 确认选项';
172
+ exports.LIST_HINT = '使用上下键选择,按下 Enter 键确认选项';
@@ -21,6 +21,7 @@ function ensureFiles() {
21
21
  if (!(yield fs_extra_1.default.exists(const_1.CONFIG_PATH))) {
22
22
  yield fs_extra_1.default.writeFile(const_1.CONFIG_PATH, const_1.DEFAULT_CONFIG);
23
23
  }
24
+ yield fs_extra_1.default.ensureDir(const_1.CLAUDE_CODE_ROUTER_LOGS_DIR_PATH);
24
25
  });
25
26
  }
26
27
  exports.ensureFiles = ensureFiles;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ensureValidEnv = void 0;
13
+ const env_1 = require("../../env");
14
+ const constants_1 = require("../../commands/constants");
15
+ function ensureValidEnv(envId, log) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const envs = yield (0, env_1.listEnvs)({ source: [constants_1.EnvSource.MINIAPP, constants_1.EnvSource.QCLOUD] });
18
+ const validEnv = envs.find((env) => env.EnvId === envId);
19
+ if (!validEnv) {
20
+ log.error(`❌ 环境 ${envId} 与当前账号不匹配,请运行 tcb ai --setup 配置其他环境`);
21
+ process.exit(1);
22
+ }
23
+ if (validEnv.Status !== constants_1.EnvStatus.NORMAL) {
24
+ log.error(`❌ 环境 ${envId} 不可用,请运行 tcb ai --setup 配置其他环境 ${validEnv.Status}`);
25
+ process.exit(1);
26
+ }
27
+ });
28
+ }
29
+ exports.ensureValidEnv = ensureValidEnv;
@@ -52,68 +52,50 @@ const const_1 = require("./const");
52
52
  const utils_1 = require("../../commands/utils");
53
53
  const auth_1 = require("../../auth");
54
54
  const nodeVersion_1 = require("./nodeVersion");
55
+ const claudeWindows_1 = require("./claudeWindows");
56
+ const env_1 = require("./env");
55
57
  const IDE_FILE_MAPPINGS = {
56
- "cursor": [
57
- ".cursor/rules/cloudbase-rules.mdc",
58
- ".cursor/mcp.json"
58
+ cursor: [
59
+ { path: '.cursor/rules/cloudbase-rules.mdc' },
60
+ { path: '.cursor/mcp.json', isMcpConfig: true }
59
61
  ],
60
- "windsurf": [
61
- ".windsurf/rules/cloudbase-rules.md"
62
+ windsurf: [{ path: '.windsurf/rules/cloudbase-rules.md' }],
63
+ codebuddy: [{ path: '.rules/cloudbase-rules.md' }],
64
+ 'claude-code': [{ path: 'CLAUDE.md' }, { path: '.mcp.json', isMcpConfig: true }],
65
+ cline: [{ path: '.clinerules/cloudbase-rules.mdc' }],
66
+ 'gemini-cli': [
67
+ { path: '.gemini/GEMINI.md' },
68
+ { path: '.gemini/settings.json', isMcpConfig: true }
62
69
  ],
63
- "codebuddy": [
64
- ".rules/cloudbase-rules.md"
70
+ opencode: [{ path: '.opencode.json', isMcpConfig: true }],
71
+ 'qwen-code': [{ path: '.qwen/QWEN.md' }, { path: '.qwen/settings.json', isMcpConfig: true }],
72
+ 'baidu-comate': [
73
+ { path: '.comate/rules/cloudbase-rules.mdr' },
74
+ { path: '.comate/rules/cloudbaase-rules.mdr' },
75
+ { path: '.comate/mcp.json', isMcpConfig: true }
65
76
  ],
66
- "claude-code": [
67
- "CLAUDE.md",
68
- ".mcp.json"
77
+ 'openai-codex-cli': [{ path: '.codex/config.toml', isMcpConfig: true }, { path: 'AGENTS.md' }],
78
+ 'augment-code': [{ path: '.augment-guidelines' }],
79
+ 'github-copilot': [{ path: '.github/copilot-instructions.md' }],
80
+ roocode: [
81
+ { path: '.roo/rules/cloudbaase-rules.md' },
82
+ { path: '.roo/mcp.json', isMcpConfig: true }
69
83
  ],
70
- "cline": [
71
- ".clinerules/cloudbase-rules.mdc"
72
- ],
73
- "gemini-cli": [
74
- ".gemini/GEMINI.md",
75
- ".gemini/settings.json"
76
- ],
77
- "opencode": [
78
- ".opencode.json"
79
- ],
80
- "qwen-code": [
81
- ".qwen/QWEN.md",
82
- ".qwen/settings.json"
83
- ],
84
- "baidu-comate": [
85
- ".comate/rules/cloudbase-rules.mdr",
86
- ".comate/rules/cloudbaase-rules.mdr",
87
- ".comate/mcp.json"
88
- ],
89
- "openai-codex-cli": [
90
- ".codex/config.toml",
91
- "AGENTS.md",
92
- ],
93
- "augment-code": [
94
- ".augment-guidelines"
95
- ],
96
- "github-copilot": [
97
- ".github/copilot-instructions.md"
98
- ],
99
- "roocode": [
100
- ".roo/rules/cloudbaase-rules.md",
101
- ".roo/mcp.json"
102
- ],
103
- "tongyi-lingma": [
104
- ".lingma/rules/cloudbaase-rules.md"
105
- ],
106
- "trae": [
107
- ".trae/rules/cloudbase-rules.md"
108
- ],
109
- "vscode": [
110
- ".vscode/mcp.json",
111
- ".vscode/settings.json"
112
- ],
113
- "aider": [
114
- "mcp.json"
115
- ]
84
+ 'tongyi-lingma': [{ path: '.lingma/rules/cloudbaase-rules.md' }],
85
+ trae: [{ path: '.trae/rules/cloudbase-rules.md' }],
86
+ vscode: [{ path: '.vscode/mcp.json', isMcpConfig: true }, { path: '.vscode/settings.json' }],
87
+ aider: [{ path: 'mcp.json', isMcpConfig: true }]
116
88
  };
89
+ const MCP_CONFIG_SET = new Set(Object.values(IDE_FILE_MAPPINGS).reduce((acc, descriptors) => {
90
+ for (const d of descriptors) {
91
+ if (d.isMcpConfig)
92
+ acc.push(d.path);
93
+ }
94
+ return acc;
95
+ }, []));
96
+ function inferConfigFormat(filePath) {
97
+ return filePath.toLowerCase().endsWith('.toml') ? 'toml' : 'json';
98
+ }
117
99
  class AICommandRouter {
118
100
  constructor() {
119
101
  this.configManager = new config_1.AIConfigManager();
@@ -183,21 +165,8 @@ class AICommandRouter {
183
165
  if (templateType === 'none') {
184
166
  return;
185
167
  }
186
- const shouldCheckOverwrite = yield this.shouldCheckOverwrite(templateType);
187
- let overwrite = false;
188
- if (shouldCheckOverwrite) {
189
- const { confirmOverwrite } = yield inquirer_1.default.prompt([
190
- {
191
- type: 'confirm',
192
- name: 'confirmOverwrite',
193
- message: `检测到已存在文件,是否覆盖? ${(0, const_1.getBooleanHint)(false)}`,
194
- default: false
195
- }
196
- ]);
197
- overwrite = confirmOverwrite;
198
- }
199
168
  log.info(`📦 正在下载并解压 ${templateType} 模板...`);
200
- yield this.downloadAndExtractTemplate(templateType, overwrite, log);
169
+ yield this.downloadAndExtractTemplate(templateType, log);
201
170
  log.info(`✅ ${templateType} 模板配置完成`);
202
171
  }
203
172
  catch (error) {
@@ -206,7 +175,7 @@ class AICommandRouter {
206
175
  }
207
176
  });
208
177
  }
209
- downloadAndExtractTemplate(templateType, overwrite, log) {
178
+ downloadAndExtractTemplate(templateType, log) {
210
179
  var _a, e_1, _b, _c;
211
180
  return __awaiter(this, void 0, void 0, function* () {
212
181
  const fs = yield Promise.resolve().then(() => __importStar(require('fs-extra')));
@@ -277,6 +246,15 @@ class AICommandRouter {
277
246
  entry.autodrain();
278
247
  continue;
279
248
  }
249
+ if (MCP_CONFIG_SET.has(entryPath)) {
250
+ try {
251
+ yield this.mergeMcpConfig(entry, destPath, inferConfigFormat(entryPath), log);
252
+ }
253
+ catch (e) {
254
+ log.warn(`MCP 配置合并失败 ${entryPath}:${e.message},已跳过`);
255
+ }
256
+ continue;
257
+ }
280
258
  if (entryPath === 'cloudbaserc.json' && (yield fs.pathExists(destPath))) {
281
259
  try {
282
260
  const templateContent = yield entry.buffer();
@@ -306,9 +284,19 @@ class AICommandRouter {
306
284
  }
307
285
  continue;
308
286
  }
309
- if (!overwrite && (yield fs.pathExists(destPath))) {
310
- entry.autodrain();
311
- continue;
287
+ if (yield fs.pathExists(destPath)) {
288
+ const { confirmOverwriteFile } = yield inquirer_1.default.prompt([
289
+ {
290
+ type: 'confirm',
291
+ name: 'confirmOverwriteFile',
292
+ message: `检测到已存在文件 ${entryPath},是否覆盖? ${(0, const_1.getBooleanHint)(false)}`,
293
+ default: false
294
+ }
295
+ ]);
296
+ if (!confirmOverwriteFile) {
297
+ entry.autodrain();
298
+ continue;
299
+ }
312
300
  }
313
301
  yield fs.ensureDir(path.dirname(destPath));
314
302
  yield new Promise((res, rej) => {
@@ -365,12 +353,6 @@ class AICommandRouter {
365
353
  return { success: false, message: `# 请查阅 ${agent} 的官方安装文档` };
366
354
  }
367
355
  }
368
- shouldCheckOverwrite(templateType) {
369
- return __awaiter(this, void 0, void 0, function* () {
370
- const fs = yield Promise.resolve().then(() => __importStar(require('fs-extra')));
371
- return (yield fs.pathExists('.mcp.json')) || (yield fs.pathExists('CLAUDE.md'));
372
- });
373
- }
374
356
  executeCommand(command, args, env, log) {
375
357
  return __awaiter(this, void 0, void 0, function* () {
376
358
  return new Promise((resolve, reject) => {
@@ -452,14 +434,20 @@ class AICommandRouter {
452
434
  return __awaiter(this, void 0, void 0, function* () {
453
435
  switch (agent) {
454
436
  case const_1.CLAUDE.value:
455
- if (agentConfig.type === 'cloudbase') {
456
- return yield this.executeClaudeCloudbaseAgent(agentConfig, additionalArgs, log);
457
- }
458
- else if (agentConfig.type === 'custom') {
459
- return yield this.executeClaudeAgent(agentConfig, additionalArgs, log);
437
+ try {
438
+ if (agentConfig.type === 'cloudbase') {
439
+ return yield this.executeClaudeCloudbaseAgent(agentConfig, additionalArgs, log);
440
+ }
441
+ else if (agentConfig.type === 'custom') {
442
+ return yield this.executeClaudeAgent(agentConfig, additionalArgs, log);
443
+ }
444
+ else {
445
+ return yield this.executeNoneClaudeAgent(additionalArgs, log);
446
+ }
460
447
  }
461
- else {
462
- return yield this.executeNoneClaudeAgent(additionalArgs, log);
448
+ catch (_) {
449
+ (0, claudeWindows_1.claudeWindowsCheck)(log);
450
+ return process.exit(1);
463
451
  }
464
452
  case const_1.QWEN.value:
465
453
  if (agentConfig.type === 'cloudbase') {
@@ -526,6 +514,7 @@ class AICommandRouter {
526
514
  const envId = yield (0, config_1.createConfigParser)().get('envId');
527
515
  yield (0, auth_1.checkLogin)();
528
516
  const credential = yield (0, utils_1.getCredential)({}, {});
517
+ yield (0, env_1.ensureValidEnv)(envId, log);
529
518
  const accessToken = yield (0, utils_1.rawFetchAccessToken)({
530
519
  envId,
531
520
  secretId: credential.secretId,
@@ -605,6 +594,7 @@ class AICommandRouter {
605
594
  const envId = yield (0, config_1.createConfigParser)().get('envId');
606
595
  yield (0, auth_1.checkLogin)();
607
596
  const credential = yield (0, utils_1.getCredential)({}, {});
597
+ yield (0, env_1.ensureValidEnv)(envId, log);
608
598
  const accessToken = yield (0, utils_1.rawFetchAccessToken)({
609
599
  envId,
610
600
  secretId: credential.secretId,
@@ -802,6 +792,7 @@ class AICommandRouter {
802
792
  const envId = yield (0, config_1.createConfigParser)().get('envId');
803
793
  yield (0, auth_1.checkLogin)();
804
794
  const credential = yield (0, utils_1.getCredential)({}, {});
795
+ yield (0, env_1.ensureValidEnv)(envId, log);
805
796
  const accessToken = yield (0, utils_1.rawFetchAccessToken)({
806
797
  envId,
807
798
  secretId: credential.secretId,
@@ -870,6 +861,7 @@ class AICommandRouter {
870
861
  const envId = yield (0, config_1.createConfigParser)().get('envId');
871
862
  yield (0, auth_1.checkLogin)();
872
863
  const credential = yield (0, utils_1.getCredential)({}, {});
864
+ yield (0, env_1.ensureValidEnv)(envId, log);
873
865
  const accessToken = yield (0, utils_1.rawFetchAccessToken)({
874
866
  envId,
875
867
  secretId: credential.secretId,
@@ -924,14 +916,17 @@ class AICommandRouter {
924
916
  const path = yield Promise.resolve().then(() => __importStar(require('path')));
925
917
  try {
926
918
  log.info('🔧 正在修改 MCP 配置文件...');
927
- for (const [ide, files] of Object.entries(IDE_FILE_MAPPINGS)) {
928
- for (const file of files) {
929
- const filePath = path.join(extractDir, file);
919
+ for (const [, files] of Object.entries(IDE_FILE_MAPPINGS)) {
920
+ for (const descriptor of files) {
921
+ if (!descriptor.isMcpConfig)
922
+ continue;
923
+ const filePath = path.join(extractDir, descriptor.path);
930
924
  if (yield fs.pathExists(filePath)) {
931
- if (file.endsWith('.json')) {
925
+ const format = inferConfigFormat(descriptor.path);
926
+ if (format === 'json') {
932
927
  yield this.modifyMCPJsonFile(filePath, log);
933
928
  }
934
- else if (file.endsWith('.toml')) {
929
+ else if (format === 'toml') {
935
930
  yield this.modifyMCPTomlFile(filePath, log);
936
931
  }
937
932
  }
@@ -956,12 +951,13 @@ class AICommandRouter {
956
951
  return obj;
957
952
  }
958
953
  if (Array.isArray(obj)) {
959
- return obj.map(item => modifyCommands(item));
954
+ return obj.map((item) => modifyCommands(item));
960
955
  }
961
956
  const result = Object.assign({}, obj);
962
957
  if (result.command === 'npx' && Array.isArray(result.args)) {
963
958
  const argsStr = result.args.join(' ');
964
- if (argsStr.includes('npm-global-exec@latest') && argsStr.includes('@cloudbase/cloudbase-mcp@latest')) {
959
+ if (argsStr.includes('npm-global-exec@latest') &&
960
+ argsStr.includes('@cloudbase/cloudbase-mcp@latest')) {
965
961
  result.command = 'cloudbase-mcp';
966
962
  result.args = [];
967
963
  result.env = {
@@ -990,7 +986,7 @@ class AICommandRouter {
990
986
  modifyMCPTomlFile(filePath, log) {
991
987
  return __awaiter(this, void 0, void 0, function* () {
992
988
  const fs = yield Promise.resolve().then(() => __importStar(require('fs-extra')));
993
- const toml = require('toml');
989
+ const toml = yield Promise.resolve().then(() => __importStar(require('toml')));
994
990
  try {
995
991
  const content = yield fs.readFile(filePath, 'utf-8');
996
992
  const config = toml.parse(content);
@@ -1000,7 +996,7 @@ class AICommandRouter {
1000
996
  return obj;
1001
997
  }
1002
998
  if (Array.isArray(obj)) {
1003
- return obj.map(item => modifyCommands(item));
999
+ return obj.map((item) => modifyCommands(item));
1004
1000
  }
1005
1001
  const result = Object.assign({}, obj);
1006
1002
  if (result.command === 'npx' && Array.isArray(result.args)) {
@@ -1032,6 +1028,53 @@ class AICommandRouter {
1032
1028
  }
1033
1029
  });
1034
1030
  }
1031
+ mergeMcpConfig(entry, destPath, format, log) {
1032
+ return __awaiter(this, void 0, void 0, function* () {
1033
+ const fs = yield Promise.resolve().then(() => __importStar(require('fs-extra')));
1034
+ const path = yield Promise.resolve().then(() => __importStar(require('path')));
1035
+ const incomingStr = (yield entry.buffer()).toString('utf8');
1036
+ const deepMerge = (target, source) => {
1037
+ if (typeof target !== 'object' || typeof source !== 'object' || !target || !source) {
1038
+ return target;
1039
+ }
1040
+ const result = Array.isArray(target) ? [...target] : Object.assign(Object.assign({}, source), target);
1041
+ for (const key of Object.keys(source)) {
1042
+ if (key in target &&
1043
+ typeof target[key] === 'object' &&
1044
+ typeof source[key] === 'object') {
1045
+ result[key] = deepMerge(target[key], source[key]);
1046
+ }
1047
+ }
1048
+ return result;
1049
+ };
1050
+ yield fs.ensureDir(path.dirname(destPath));
1051
+ if (format === 'json') {
1052
+ const incomingObj = JSON.parse(incomingStr);
1053
+ if (yield fs.pathExists(destPath)) {
1054
+ const existingObj = yield fs.readJson(destPath);
1055
+ const merged = deepMerge(existingObj, incomingObj);
1056
+ yield fs.writeJson(destPath, merged, { spaces: 2 });
1057
+ }
1058
+ else {
1059
+ yield fs.writeJson(destPath, incomingObj, { spaces: 2 });
1060
+ }
1061
+ return;
1062
+ }
1063
+ const toml = yield Promise.resolve().then(() => __importStar(require('toml')));
1064
+ const incomingObj = toml.parse(incomingStr);
1065
+ if (yield fs.pathExists(destPath)) {
1066
+ const existingStr = yield fs.readFile(destPath, 'utf-8');
1067
+ const existingObj = toml.parse(existingStr);
1068
+ const merged = deepMerge(existingObj, incomingObj);
1069
+ const out = this.objectToToml(merged);
1070
+ yield fs.writeFile(destPath, out, 'utf-8');
1071
+ }
1072
+ else {
1073
+ const out = this.objectToToml(incomingObj);
1074
+ yield fs.writeFile(destPath, out, 'utf-8');
1075
+ }
1076
+ });
1077
+ }
1035
1078
  objectToToml(obj, prefix = '') {
1036
1079
  const lines = [];
1037
1080
  for (const [key, value] of Object.entries(obj)) {
@@ -1041,12 +1084,14 @@ class AICommandRouter {
1041
1084
  lines.push(this.objectToToml(value, fullKey));
1042
1085
  }
1043
1086
  else if (Array.isArray(value)) {
1044
- const arrayStr = value.map(item => {
1087
+ const arrayStr = value
1088
+ .map((item) => {
1045
1089
  if (typeof item === 'string') {
1046
1090
  return `"${item}"`;
1047
1091
  }
1048
1092
  return item;
1049
- }).join(', ');
1093
+ })
1094
+ .join(', ');
1050
1095
  lines.push(`${key} = [${arrayStr}]`);
1051
1096
  }
1052
1097
  else if (typeof value === 'string') {
@@ -229,7 +229,7 @@ class AISetupWizard {
229
229
  choices: [
230
230
  { name: '使用 CloudBase 服务,一键登录,无需配置', value: 'cloudbase' },
231
231
  { name: '自配置 API KEY 和 Base URL', value: 'custom' },
232
- { name: '暂不配置,使用 AI CLI 内置鉴权方式(如 OAuth)', value: 'none' }
232
+ { name: '暂不配置,使用 Claude Code 内置鉴权方式(如 OAuth)', value: 'none' }
233
233
  ],
234
234
  default: 'cloudbase'
235
235
  }
@@ -296,7 +296,7 @@ class AISetupWizard {
296
296
  choices: [
297
297
  { name: '使用 CloudBase 服务,一键登录,无需配置', value: 'cloudbase' },
298
298
  { name: '自配置 API KEY 和 Base URL', value: 'custom' },
299
- { name: '暂不配置,使用 AI CLI 内置鉴权方式(如 OAuth)', value: 'none' }
299
+ { name: '暂不配置,使用 Qwen Code 内置鉴权方式(如 OAuth)', value: 'none' }
300
300
  ],
301
301
  default: 'cloudbase'
302
302
  }
@@ -348,7 +348,7 @@ class AISetupWizard {
348
348
  choices: [
349
349
  { name: '使用 CloudBase 服务,一键登录,无需配置', value: 'cloudbase' },
350
350
  { name: '自配置 API KEY 和 Base URL', value: 'custom' },
351
- { name: '暂不配置,使用 AI CLI 内置鉴权方式(如 OAuth)', value: 'none' }
351
+ { name: '暂不配置,使用 OpenAI Codex 内置鉴权方式(如 OAuth)', value: 'none' }
352
352
  ],
353
353
  default: 'cloudbase'
354
354
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/cli",
3
- "version": "2.8.2-beta.1",
3
+ "version": "2.8.2-beta.3",
4
4
  "description": "cli tool for cloudbase",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -0,0 +1,2 @@
1
+ import { Logger } from '../log';
2
+ export declare function claudeWindowsCheck(log: Logger): void;
@@ -3,6 +3,7 @@ export declare const CONFIG_PATH: string;
3
3
  export declare const ENV_LOCAL_PATH: string;
4
4
  export declare const CLAUDE_CODE_ROUTER_CONFIG_PATH: string;
5
5
  export declare const CLAUDE_CODE_ROUTER_LOG_PATH: string;
6
+ export declare const CLAUDE_CODE_ROUTER_LOGS_DIR_PATH: string;
6
7
  export declare const CLOUDBASE_MCP_CONFIG_PATH: string;
7
8
  export declare const DEFAULT_CONFIG = "{\n \"envId\": \"{{env.ENV_ID}}\"\n}";
8
9
  export declare const CLAUDE: {
@@ -328,4 +329,4 @@ export declare const BASE_URL_MODEL_MAPPING: {
328
329
  };
329
330
  export declare function getDefaultModelByBaseUrl(baseUrl: string): string;
330
331
  export declare function getBooleanHint(defaultValue?: boolean): string;
331
- export declare const LIST_HINT = "\u4F7F\u7528\u4E0A\u4E0B\u952E\u9009\u62E9\uFF0C\u8F93\u5165 enter \u786E\u8BA4\u9009\u9879";
332
+ export declare const LIST_HINT = "\u4F7F\u7528\u4E0A\u4E0B\u952E\u9009\u62E9\uFF0C\u6309\u4E0B Enter \u952E\u786E\u8BA4\u9009\u9879";
@@ -0,0 +1,2 @@
1
+ import { Logger } from '../log';
2
+ export declare function ensureValidEnv(envId: string, log: Logger): Promise<void>;
@@ -13,7 +13,6 @@ export declare class AICommandRouter {
13
13
  private downloadTemplate;
14
14
  private downloadAndExtractTemplate;
15
15
  private getInstallCommand;
16
- private shouldCheckOverwrite;
17
16
  private executeCommand;
18
17
  private isToolAvailable;
19
18
  private validateAgentConfig;
@@ -41,6 +40,7 @@ export declare class AICommandRouter {
41
40
  private modifyMCPConfigs;
42
41
  private modifyMCPJsonFile;
43
42
  private modifyMCPTomlFile;
43
+ private mergeMcpConfig;
44
44
  private objectToToml;
45
45
  }
46
46
  export {};