@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.
- package/lib/commands/ai/index.js +0 -1
- package/lib/utils/ai/claudeWindows.js +62 -0
- package/lib/utils/ai/const.js +3 -2
- package/lib/utils/ai/ensureFiles.js +1 -0
- package/lib/utils/ai/env.js +29 -0
- package/lib/utils/ai/router.js +143 -98
- package/lib/utils/ai/setup.js +3 -3
- package/package.json +1 -1
- package/types/utils/ai/claudeWindows.d.ts +2 -0
- package/types/utils/ai/const.d.ts +2 -1
- package/types/utils/ai/env.d.ts +2 -0
- package/types/utils/ai/router.d.ts +1 -1
package/lib/commands/ai/index.js
CHANGED
|
@@ -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
|
+
}
|
package/lib/utils/ai/const.js
CHANGED
|
@@ -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 = '
|
|
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;
|
package/lib/utils/ai/router.js
CHANGED
|
@@ -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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
cursor: [
|
|
59
|
+
{ path: '.cursor/rules/cloudbase-rules.mdc' },
|
|
60
|
+
{ path: '.cursor/mcp.json', isMcpConfig: true }
|
|
59
61
|
],
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
],
|
|
73
|
-
|
|
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,
|
|
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,
|
|
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 (
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
-
|
|
462
|
-
|
|
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 [
|
|
928
|
-
for (const
|
|
929
|
-
|
|
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
|
-
|
|
925
|
+
const format = inferConfigFormat(descriptor.path);
|
|
926
|
+
if (format === 'json') {
|
|
932
927
|
yield this.modifyMCPJsonFile(filePath, log);
|
|
933
928
|
}
|
|
934
|
-
else if (
|
|
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') &&
|
|
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
|
|
1087
|
+
const arrayStr = value
|
|
1088
|
+
.map((item) => {
|
|
1045
1089
|
if (typeof item === 'string') {
|
|
1046
1090
|
return `"${item}"`;
|
|
1047
1091
|
}
|
|
1048
1092
|
return item;
|
|
1049
|
-
})
|
|
1093
|
+
})
|
|
1094
|
+
.join(', ');
|
|
1050
1095
|
lines.push(`${key} = [${arrayStr}]`);
|
|
1051
1096
|
}
|
|
1052
1097
|
else if (typeof value === 'string') {
|
package/lib/utils/ai/setup.js
CHANGED
|
@@ -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: '暂不配置,使用
|
|
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: '暂不配置,使用
|
|
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: '暂不配置,使用
|
|
351
|
+
{ name: '暂不配置,使用 OpenAI Codex 内置鉴权方式(如 OAuth)', value: 'none' }
|
|
352
352
|
],
|
|
353
353
|
default: 'cloudbase'
|
|
354
354
|
}
|
package/package.json
CHANGED
|
@@ -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\
|
|
332
|
+
export declare const LIST_HINT = "\u4F7F\u7528\u4E0A\u4E0B\u952E\u9009\u62E9\uFF0C\u6309\u4E0B Enter \u952E\u786E\u8BA4\u9009\u9879";
|
|
@@ -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 {};
|