@cloudbase/cli 2.8.27 → 2.9.0
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/.env.local +1 -1
- package/bin/tcb.js +2 -1
- package/cloudbaserc.json +12 -2
- package/dist/standalone/cli.js +6531 -329
- package/lib/commands/account/login.js +2 -6
- package/lib/commands/ai/index.js +2 -2
- package/lib/commands/pull/pull.js +6 -4
- package/lib/help.js +5 -17
- package/lib/utils/ai/banner.js +6 -3
- package/lib/utils/ai/config.js +16 -2
- package/lib/utils/ai/const.js +15 -2
- package/lib/utils/ai/router.js +54 -6
- package/lib/utils/ai/setup.js +45 -2
- package/package.json +2 -2
- package/specs/codebuddy-integration/design.md +152 -0
- package/specs/codebuddy-integration/requirements.md +53 -0
- package/specs/codebuddy-integration/tasks.md +159 -0
- package/types/commands/pull/pull.d.ts +2 -1
- package/types/utils/ai/config.d.ts +7 -3
- package/types/utils/ai/const.d.ts +39 -0
- package/types/utils/ai/router.d.ts +3 -0
- package/types/utils/ai/setup.d.ts +1 -0
|
@@ -37,13 +37,9 @@ const utils_1 = require("../../utils");
|
|
|
37
37
|
function printSuggestion() {
|
|
38
38
|
const tips = `可使用下面命令继续操作:
|
|
39
39
|
|
|
40
|
-
${chalk_1.default.gray('–')}
|
|
40
|
+
${chalk_1.default.gray('–')} 一键开启 AI 开发体验
|
|
41
41
|
|
|
42
|
-
${chalk_1.default.cyan('$ tcb
|
|
43
|
-
|
|
44
|
-
${chalk_1.default.gray('–')} 部署云函数
|
|
45
|
-
|
|
46
|
-
${chalk_1.default.cyan('$ tcb fn deploy')}
|
|
42
|
+
${chalk_1.default.cyan('$ tcb ai')}
|
|
47
43
|
|
|
48
44
|
${chalk_1.default.gray('–')} 查看命令使用介绍
|
|
49
45
|
|
package/lib/commands/ai/index.js
CHANGED
|
@@ -39,7 +39,7 @@ let AICommand = class AICommand extends common_1.Command {
|
|
|
39
39
|
options: [
|
|
40
40
|
{
|
|
41
41
|
flags: '-a, --agent <agent>',
|
|
42
|
-
desc: 'AI CLI 工具 (claude, qwen, codex, aider)'
|
|
42
|
+
desc: 'AI CLI 工具 (claude, qwen, codex, aider, codebuddy)'
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
flags: '-e, --envId <envId>',
|
|
@@ -66,7 +66,7 @@ let AICommand = class AICommand extends common_1.Command {
|
|
|
66
66
|
desc: '指定模板类型 (miniprogram, react, vue, uniapp, rules)'
|
|
67
67
|
}
|
|
68
68
|
],
|
|
69
|
-
desc: 'CloudBase AI ToolKit CLI - 快速启动和配置主流 AI 编程工具\n\n示例:\n tcb ai -a claude -- --continue\n\n说明:-- 后的参数会直接传递给目标 AI CLI。',
|
|
69
|
+
desc: 'CloudBase AI ToolKit CLI - 快速启动和配置主流 AI 编程工具\n\n示例:\n tcb ai -a claude -- --continue\n tcb ai -a codebuddy -- mcp list\n\n说明:-- 后的参数会直接传递给目标 AI CLI。',
|
|
70
70
|
requiredEnvId: false,
|
|
71
71
|
withoutAuth: true,
|
|
72
72
|
allowUnknownOption: true
|
|
@@ -31,6 +31,7 @@ let PullCommand = class PullCommand extends common_1.Command {
|
|
|
31
31
|
get options() {
|
|
32
32
|
return {
|
|
33
33
|
cmd: 'pull',
|
|
34
|
+
childCmd: '<source>',
|
|
34
35
|
options: [
|
|
35
36
|
{
|
|
36
37
|
flags: '-o, --output <output>',
|
|
@@ -46,10 +47,10 @@ let PullCommand = class PullCommand extends common_1.Command {
|
|
|
46
47
|
withoutAuth: true
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
|
-
execute(options, log) {
|
|
50
|
+
execute(options, params, log) {
|
|
50
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
52
|
const { output, force } = options;
|
|
52
|
-
const source =
|
|
53
|
+
const [source] = params || [];
|
|
53
54
|
if (!source || typeof source !== 'string') {
|
|
54
55
|
throw new error_1.CloudBaseError('请指定要拉取的模板来源');
|
|
55
56
|
}
|
|
@@ -89,9 +90,10 @@ let PullCommand = class PullCommand extends common_1.Command {
|
|
|
89
90
|
__decorate([
|
|
90
91
|
(0, decorators_1.InjectParams)(),
|
|
91
92
|
__param(0, (0, decorators_1.ArgsOptions)()),
|
|
92
|
-
__param(1, (0, decorators_1.
|
|
93
|
+
__param(1, (0, decorators_1.ArgsParams)()),
|
|
94
|
+
__param(2, (0, decorators_1.Log)()),
|
|
93
95
|
__metadata("design:type", Function),
|
|
94
|
-
__metadata("design:paramtypes", [Object, log_1.Logger]),
|
|
96
|
+
__metadata("design:paramtypes", [Object, Array, log_1.Logger]),
|
|
95
97
|
__metadata("design:returntype", Promise)
|
|
96
98
|
], PullCommand.prototype, "execute", null);
|
|
97
99
|
PullCommand = __decorate([
|
package/lib/help.js
CHANGED
|
@@ -8,20 +8,15 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const outputHelpInfo = () => {
|
|
9
9
|
const commands = `
|
|
10
10
|
命令
|
|
11
|
-
|
|
11
|
+
ai -- [cmd] 开启 AI 全栈开发体验
|
|
12
12
|
login [options] 登录腾讯云账号
|
|
13
13
|
logout 登出腾讯云账号
|
|
14
14
|
env [cmd] 环境管理操作
|
|
15
15
|
fn [cmd] 操作函数
|
|
16
|
-
framework [cmd] 云开发 Serverless 应用框架操作
|
|
17
16
|
hosting [cmd] 静态托管资源管理操作
|
|
18
|
-
new [appName] [template] 创建新的云开发应用
|
|
19
|
-
open [link] 在浏览器中打开云开发相关连接
|
|
20
17
|
storage [cmd] 云存储资源管理操作
|
|
21
18
|
service [cmd] HTTP 访问服务管理操作
|
|
22
|
-
|
|
23
|
-
run [cmd] 云托管环境管理操作 (TCBR 类型环境)
|
|
24
|
-
cloudrun [cmd] 云托管服务管理操作(新版云开发平台)`;
|
|
19
|
+
cloudrun [cmd] 云托管服务管理操作`;
|
|
25
20
|
const options = `
|
|
26
21
|
选项
|
|
27
22
|
|
|
@@ -38,17 +33,10 @@ const outputHelpInfo = () => {
|
|
|
38
33
|
|
|
39
34
|
${chalk_1.default.cyan('$ tcb login')}
|
|
40
35
|
|
|
41
|
-
${chalk_1.default.gray('–')}
|
|
42
|
-
|
|
43
|
-
${chalk_1.default.cyan('$ tcb new appName')}
|
|
44
|
-
|
|
45
|
-
${chalk_1.default.gray('–')} 部署云函数
|
|
46
|
-
|
|
47
|
-
${chalk_1.default.cyan('$ tcb fn deploy')}
|
|
48
|
-
|
|
49
|
-
${chalk_1.default.gray('–')} 查看命令使用介绍
|
|
36
|
+
${chalk_1.default.gray('–')} 使用 AI 全栈开发部署
|
|
50
37
|
|
|
51
|
-
${chalk_1.default.cyan('$ tcb
|
|
38
|
+
${chalk_1.default.cyan('$ tcb ai')}
|
|
39
|
+
`;
|
|
52
40
|
console.log(commands, '\n', options, '\n', tips);
|
|
53
41
|
};
|
|
54
42
|
exports.outputHelpInfo = outputHelpInfo;
|
package/lib/utils/ai/banner.js
CHANGED
|
@@ -75,12 +75,12 @@ AI ToolKit`, {
|
|
|
75
75
|
log.log(' 🎯 无需运维,极速上线你的创意 💫');
|
|
76
76
|
}
|
|
77
77
|
log.log('');
|
|
78
|
+
log.log('Github:');
|
|
79
|
+
log.log((0, output_1.genClickableLink)('https://github.com/TencentCloudBase/CloudBase-AI-ToolKit'));
|
|
80
|
+
log.log('');
|
|
78
81
|
log.log('使用指引');
|
|
79
82
|
log.log((0, output_1.genClickableLink)('https://docs.cloudbase.net/cli-v1/ai/introduce'));
|
|
80
83
|
log.log('');
|
|
81
|
-
log.log('Beta 能力,如遇问题可创建 issue:');
|
|
82
|
-
log.log((0, output_1.genClickableLink)('https://cnb.cool/tencent/cloud/cloudbase/community/-/issues'));
|
|
83
|
-
log.log('');
|
|
84
84
|
}
|
|
85
85
|
catch (e) {
|
|
86
86
|
log.log(chalk_1.default.bold.cyanBright('⛰︎'), chalk_1.default.bold.hex('#FFFFFF')(' CloudBase AI ToolKit CLI'));
|
|
@@ -89,6 +89,9 @@ AI ToolKit`, {
|
|
|
89
89
|
log.log(chalk_1.default.hex('#34495E')(' ⚡ 生成、部署和托管全栈 Web 应用与小程序、数据库和后端服务'));
|
|
90
90
|
log.log(chalk_1.default.hex('#34495E')(' 🎯 无需运维,极速上线你的创意 💫'));
|
|
91
91
|
log.log('');
|
|
92
|
+
log.log('Github:');
|
|
93
|
+
log.log((0, output_1.genClickableLink)('https://github.com/TencentCloudBase/CloudBase-AI-ToolKit'));
|
|
94
|
+
log.log('');
|
|
92
95
|
log.log('使用指引');
|
|
93
96
|
log.log((0, output_1.genClickableLink)('https://docs.cloudbase.net/cli-v1/ai/introduce'));
|
|
94
97
|
log.log('');
|
package/lib/utils/ai/config.js
CHANGED
|
@@ -25,7 +25,7 @@ const notFoundError = () => {
|
|
|
25
25
|
});
|
|
26
26
|
};
|
|
27
27
|
function isValidAgent(agent) {
|
|
28
|
-
return [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.AIDER, const_1.CURSOR].some((x) => x.value === agent);
|
|
28
|
+
return [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.AIDER, const_1.CURSOR, const_1.CODEBUDDY].some((x) => x.value === agent);
|
|
29
29
|
}
|
|
30
30
|
exports.isValidAgent = isValidAgent;
|
|
31
31
|
exports.TOOLKIT_CONFIGS = {
|
|
@@ -33,6 +33,9 @@ exports.TOOLKIT_CONFIGS = {
|
|
|
33
33
|
mcp: '.mcp.json',
|
|
34
34
|
rules: 'CLAUDE.md'
|
|
35
35
|
},
|
|
36
|
+
[const_1.CODEBUDDY.value]: {
|
|
37
|
+
config: '.env.local'
|
|
38
|
+
},
|
|
36
39
|
[const_1.QWEN.value]: {
|
|
37
40
|
config: '.env.local',
|
|
38
41
|
rules: '.qwen/QWEN.md'
|
|
@@ -45,7 +48,7 @@ exports.TOOLKIT_CONFIGS = {
|
|
|
45
48
|
},
|
|
46
49
|
[const_1.CURSOR.value]: {
|
|
47
50
|
config: '.cursor/mcp.json'
|
|
48
|
-
}
|
|
51
|
+
},
|
|
49
52
|
};
|
|
50
53
|
function createConfigParser() {
|
|
51
54
|
return new toolbox_1.ConfigParser({ configPath: const_1.CONFIG_PATH });
|
|
@@ -253,6 +256,17 @@ class AIConfigManager {
|
|
|
253
256
|
yield this.updateConfig('ai.agents.cursor.type', type);
|
|
254
257
|
});
|
|
255
258
|
}
|
|
259
|
+
updateCodebuddyConfig(type, config) {
|
|
260
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
261
|
+
yield this.updateConfig('ai.agents.codebuddy', {});
|
|
262
|
+
yield this.updateConfig('ai.agents.codebuddy.type', type);
|
|
263
|
+
if (type === 'custom') {
|
|
264
|
+
if (config.apiKey) {
|
|
265
|
+
yield this.updateConfig('ai.agents.codebuddy.apiKey', config.apiKey, 'CODEBUDDY_API_KEY');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
256
270
|
updateConfig(key, value, env) {
|
|
257
271
|
return __awaiter(this, void 0, void 0, function* () {
|
|
258
272
|
const configParser = createConfigParser();
|
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.CURSOR = 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;
|
|
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.CODEBUDDY = exports.CURSOR = 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"));
|
|
@@ -101,11 +101,24 @@ exports.CURSOR = {
|
|
|
101
101
|
type: v3_1.default.literal('none')
|
|
102
102
|
})
|
|
103
103
|
};
|
|
104
|
+
exports.CODEBUDDY = {
|
|
105
|
+
name: 'Codebuddy Code CLI',
|
|
106
|
+
value: 'codebuddy',
|
|
107
|
+
configSchema: v3_1.default.discriminatedUnion('type', [
|
|
108
|
+
v3_1.default.object({
|
|
109
|
+
type: v3_1.default.literal('none')
|
|
110
|
+
}),
|
|
111
|
+
v3_1.default.object({
|
|
112
|
+
type: v3_1.default.literal('custom'),
|
|
113
|
+
apiKey: v3_1.default.string().optional()
|
|
114
|
+
})
|
|
115
|
+
])
|
|
116
|
+
};
|
|
104
117
|
exports.NONE = {
|
|
105
118
|
name: '暂不配置',
|
|
106
119
|
value: 'none'
|
|
107
120
|
};
|
|
108
|
-
exports.AGENTS = [exports.CLAUDE, exports.QWEN, exports.CODEX, exports.AIDER, exports.CURSOR, exports.NONE];
|
|
121
|
+
exports.AGENTS = [exports.CLAUDE, exports.QWEN, exports.CODEX, exports.AIDER, exports.CURSOR, exports.CODEBUDDY, exports.NONE];
|
|
109
122
|
exports.CLOUDBASE_PROVIDERS = [
|
|
110
123
|
{
|
|
111
124
|
name: 'Kimi',
|
package/lib/utils/ai/router.js
CHANGED
|
@@ -140,7 +140,7 @@ class AICommandRouter {
|
|
|
140
140
|
if (missingFiles.length > 0) {
|
|
141
141
|
const skipTemplate = yield this.checkSkipTemplateConfig();
|
|
142
142
|
if (skipTemplate) {
|
|
143
|
-
log.info('🚫
|
|
143
|
+
log.info('🚫 已跳过模板下载,无法使用云开发 MCP 及 AI 规则。如需使用,请参考 tcb pull --help');
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
146
|
log.log('');
|
|
@@ -389,6 +389,13 @@ class AICommandRouter {
|
|
|
389
389
|
args: ['install', '-g', '@google/gemini-cli'],
|
|
390
390
|
message: 'npm install -g @google/gemini-cli'
|
|
391
391
|
};
|
|
392
|
+
case 'codebuddy':
|
|
393
|
+
return {
|
|
394
|
+
success: true,
|
|
395
|
+
command: 'npm',
|
|
396
|
+
args: ['install', '-g', '@tencent-ai/codebuddy-code@beta'],
|
|
397
|
+
message: 'npm install -g @tencent-ai/codebuddy-code@beta'
|
|
398
|
+
};
|
|
392
399
|
default:
|
|
393
400
|
return { success: false, message: `# 请查阅 ${agent} 的官方安装文档` };
|
|
394
401
|
}
|
|
@@ -396,8 +403,7 @@ class AICommandRouter {
|
|
|
396
403
|
executeCommand(command, args, env, log) {
|
|
397
404
|
return __awaiter(this, void 0, void 0, function* () {
|
|
398
405
|
return new Promise((resolve, reject) => {
|
|
399
|
-
const useShell = process.platform
|
|
400
|
-
(process.env.WSL_DISTRO_NAME || process.env.MSYS2 || process.env.GIT_BASH);
|
|
406
|
+
const useShell = process.platform === 'win32';
|
|
401
407
|
const child = (0, child_process_1.spawn)(command, args, {
|
|
402
408
|
stdio: 'inherit',
|
|
403
409
|
env,
|
|
@@ -442,11 +448,9 @@ class AICommandRouter {
|
|
|
442
448
|
isToolAvailable(command) {
|
|
443
449
|
return __awaiter(this, void 0, void 0, function* () {
|
|
444
450
|
return new Promise((resolve) => {
|
|
445
|
-
const useShell = process.platform !== 'win32' ||
|
|
446
|
-
(process.env.WSL_DISTRO_NAME || process.env.MSYS2 || process.env.GIT_BASH);
|
|
447
451
|
const child = (0, child_process_1.spawn)(command, ['--version'], {
|
|
448
452
|
stdio: 'pipe',
|
|
449
|
-
shell:
|
|
453
|
+
shell: true
|
|
450
454
|
});
|
|
451
455
|
child.on('close', (code) => {
|
|
452
456
|
resolve(code === 0);
|
|
@@ -522,6 +526,13 @@ class AICommandRouter {
|
|
|
522
526
|
}
|
|
523
527
|
case const_1.CURSOR.value:
|
|
524
528
|
return yield this.executeNoneCursorAgent(additionalArgs, log);
|
|
529
|
+
case const_1.CODEBUDDY.value:
|
|
530
|
+
if (agentConfig.type === 'custom') {
|
|
531
|
+
return yield this.executeCodebuddyAgent(agentConfig, additionalArgs, log);
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
return yield this.executeNoneCodebuddyAgent(additionalArgs, log);
|
|
535
|
+
}
|
|
525
536
|
default:
|
|
526
537
|
throw new Error(`不支持的 AI 工具: ${agent}`);
|
|
527
538
|
}
|
|
@@ -1201,6 +1212,43 @@ class AICommandRouter {
|
|
|
1201
1212
|
}
|
|
1202
1213
|
return lines.join('\n');
|
|
1203
1214
|
}
|
|
1215
|
+
executeCodebuddyAgent({ apiKey }, additionalArgs, log) {
|
|
1216
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1217
|
+
yield this.ensureCodebuddy(log);
|
|
1218
|
+
yield this.executeCommand('codebuddy', additionalArgs, Object.assign(Object.assign({}, process.env), (apiKey && { CODEBUDDY_API_KEY: apiKey })), log);
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
executeNoneCodebuddyAgent(additionalArgs, log) {
|
|
1222
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1223
|
+
yield this.ensureCodebuddy(log);
|
|
1224
|
+
yield this.executeCommand('codebuddy', additionalArgs, Object.assign({}, process.env), log);
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
ensureCodebuddy(log) {
|
|
1228
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1229
|
+
if (yield this.isToolAvailable('codebuddy')) {
|
|
1230
|
+
log.debug('codebuddy 已安装!');
|
|
1231
|
+
}
|
|
1232
|
+
else {
|
|
1233
|
+
const { shouldInstall } = yield inquirer_1.default.prompt([
|
|
1234
|
+
{
|
|
1235
|
+
type: 'confirm',
|
|
1236
|
+
name: 'shouldInstall',
|
|
1237
|
+
message: `AI 开发缺少 codebuddy 依赖,是否安装? ${(0, const_1.getBooleanHint)(true)}`
|
|
1238
|
+
}
|
|
1239
|
+
]);
|
|
1240
|
+
if (shouldInstall) {
|
|
1241
|
+
yield this.executeCommand('npm', ['install', '-g', '@tencent-ai/codebuddy-code@beta'], process.env, log);
|
|
1242
|
+
log.info('✅ codebuddy 安装完成');
|
|
1243
|
+
}
|
|
1244
|
+
else {
|
|
1245
|
+
log.info('❌ codebuddy 未安装,请手动安装');
|
|
1246
|
+
log.info('📦 安装命令: npm install -g @tencent-ai/codebuddy-code@beta');
|
|
1247
|
+
process.exit(1);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1204
1252
|
}
|
|
1205
1253
|
exports.AICommandRouter = AICommandRouter;
|
|
1206
1254
|
function safeParseJson(json) {
|
package/lib/utils/ai/setup.js
CHANGED
|
@@ -194,7 +194,7 @@ class AISetupWizard {
|
|
|
194
194
|
type: 'list',
|
|
195
195
|
name: 'agent',
|
|
196
196
|
message: `${message} ${const_1.LIST_HINT}`,
|
|
197
|
-
choices: [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.CURSOR, const_1.AIDER, ...(includeNone ? [const_1.NONE] : [])],
|
|
197
|
+
choices: [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.CURSOR, const_1.AIDER, const_1.CODEBUDDY, ...(includeNone ? [const_1.NONE] : [])],
|
|
198
198
|
default: const_1.CLAUDE.value
|
|
199
199
|
}
|
|
200
200
|
]);
|
|
@@ -203,7 +203,7 @@ class AISetupWizard {
|
|
|
203
203
|
}
|
|
204
204
|
configureAgent(agent, log) {
|
|
205
205
|
return __awaiter(this, void 0, void 0, function* () {
|
|
206
|
-
const agentInfo = [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.AIDER, const_1.CURSOR].find((a) => a.value === agent);
|
|
206
|
+
const agentInfo = [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.AIDER, const_1.CURSOR, const_1.CODEBUDDY].find((a) => a.value === agent);
|
|
207
207
|
log.info(`\n📝 配置 ${(agentInfo === null || agentInfo === void 0 ? void 0 : agentInfo.name) || agent.toUpperCase()}:`);
|
|
208
208
|
switch (agent) {
|
|
209
209
|
case const_1.CLAUDE.value:
|
|
@@ -216,6 +216,8 @@ class AISetupWizard {
|
|
|
216
216
|
return yield this.configureAiderAgent(log);
|
|
217
217
|
case const_1.CURSOR.value:
|
|
218
218
|
return yield this.configureCursorAgent(log);
|
|
219
|
+
case const_1.CODEBUDDY.value:
|
|
220
|
+
return yield this.configureCodebuddyAgent(log);
|
|
219
221
|
default:
|
|
220
222
|
throw new Error(`不支持的 AI 工具: ${agent}`);
|
|
221
223
|
}
|
|
@@ -641,5 +643,46 @@ class AISetupWizard {
|
|
|
641
643
|
}
|
|
642
644
|
});
|
|
643
645
|
}
|
|
646
|
+
configureCodebuddyAgent(log) {
|
|
647
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
648
|
+
log.info(`配置说明可参考 ${(0, output_1.genClickableLink)('https://cnb.woa.com/genie/genie/-/tree/main/docs')}`);
|
|
649
|
+
const { configMethod } = yield inquirer_1.default.prompt([
|
|
650
|
+
{
|
|
651
|
+
type: 'list',
|
|
652
|
+
name: 'configMethod',
|
|
653
|
+
message: `选择配置方式: ${const_1.LIST_HINT}`,
|
|
654
|
+
choices: [
|
|
655
|
+
{
|
|
656
|
+
name: '使用 Codebuddy Code CLI 内置鉴权方式(如 OAuth)',
|
|
657
|
+
value: 'none'
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
name: '配置 API KEY(用于无交互环境)',
|
|
661
|
+
value: 'custom'
|
|
662
|
+
}
|
|
663
|
+
],
|
|
664
|
+
default: 'none'
|
|
665
|
+
}
|
|
666
|
+
]);
|
|
667
|
+
if (configMethod === 'custom') {
|
|
668
|
+
const { apiKey } = yield inquirer_1.default.prompt([
|
|
669
|
+
{
|
|
670
|
+
type: 'password',
|
|
671
|
+
name: 'apiKey',
|
|
672
|
+
message: '请输入 Codebuddy API Key:',
|
|
673
|
+
validate: (input) => input.trim().length > 0 || 'API Key 不能为空'
|
|
674
|
+
}
|
|
675
|
+
]);
|
|
676
|
+
yield this.aiConfigManager.updateCodebuddyConfig('custom', {
|
|
677
|
+
apiKey
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
yield this.aiConfigManager.updateCodebuddyConfig('none', {});
|
|
682
|
+
}
|
|
683
|
+
log.info('✅ Codebuddy Code CLI 配置完成');
|
|
684
|
+
log.info('💡 提示:首次使用时会自动打开浏览器进行 OAuth 身份验证');
|
|
685
|
+
});
|
|
686
|
+
}
|
|
644
687
|
}
|
|
645
688
|
exports.AISetupWizard = AISetupWizard;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "cli tool for cloudbase",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"license": "ISC",
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@cloudbase/cloud-api": "^0.5.5",
|
|
51
|
-
"@cloudbase/cloudbase-mcp": "^1.8.
|
|
51
|
+
"@cloudbase/cloudbase-mcp": "^1.8.40",
|
|
52
52
|
"@cloudbase/framework-core": "^1.9.7",
|
|
53
53
|
"@cloudbase/functions-framework": "1.16.0",
|
|
54
54
|
"@cloudbase/iac-core": "0.0.3-alpha.11",
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# 技术方案设计
|
|
2
|
+
|
|
3
|
+
## 架构概述
|
|
4
|
+
|
|
5
|
+
在 CloudBase CLI 的 ai 命令中集成 Codebuddy Code CLI,采用与现有 AI 工具(如 Claude、Qwen、Codex)相同的架构模式,通过命令路由器和配置管理器来实现统一的 AI 工具管理。
|
|
6
|
+
|
|
7
|
+
## 技术架构
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
A[tcb ai -a codebuddy] --> B[AICommandRouter]
|
|
12
|
+
B --> C[executeCodebuddyAgent]
|
|
13
|
+
C --> D[AIConfigManager]
|
|
14
|
+
C --> E[CodebuddyExecutor]
|
|
15
|
+
|
|
16
|
+
D --> F[配置文件管理]
|
|
17
|
+
E --> G[命令执行]
|
|
18
|
+
E --> H[安装检查]
|
|
19
|
+
|
|
20
|
+
F --> I[~/.codebuddy/settings.json]
|
|
21
|
+
F --> J[项目级配置]
|
|
22
|
+
|
|
23
|
+
G --> K[codebuddy CLI]
|
|
24
|
+
H --> L[安装向导]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 技术选型
|
|
28
|
+
|
|
29
|
+
### 核心组件
|
|
30
|
+
- **AICommandRouter**: 现有的命令路由器,负责路由到不同的 AI 工具
|
|
31
|
+
- **CodebuddyConfigManager**: Codebuddy 配置管理器(复用现有的 AIConfigManager)
|
|
32
|
+
- **CodebuddyExecutor**: Codebuddy 命令执行器(集成到现有的 executeAgentWithConfig 方法中)
|
|
33
|
+
|
|
34
|
+
### 配置管理
|
|
35
|
+
- **配置文件格式**: JSON
|
|
36
|
+
- **配置位置**:
|
|
37
|
+
- 用户级: `~/.codebuddy/settings.json`
|
|
38
|
+
- 项目级: `.codebuddy/settings.json`
|
|
39
|
+
- **配置验证**: 使用 Zod 进行配置验证
|
|
40
|
+
- **配置方式**: 主要通过环境变量和命令行参数,配置文件为辅
|
|
41
|
+
|
|
42
|
+
### 命令执行
|
|
43
|
+
- **执行方式**: 子进程执行 `codebuddy` 命令
|
|
44
|
+
- **参数透传**: 通过 `--` 分隔符透传参数
|
|
45
|
+
- **环境变量**: 支持环境变量配置
|
|
46
|
+
|
|
47
|
+
## 数据库/接口设计
|
|
48
|
+
|
|
49
|
+
### 配置结构
|
|
50
|
+
```typescript
|
|
51
|
+
interface CodebuddyConfig {
|
|
52
|
+
type: 'none' | 'custom';
|
|
53
|
+
apiKey?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Codebuddy Code CLI 配置特点:
|
|
57
|
+
// 1. 主要通过环境变量 CODEBUDDY_API_KEY 配置
|
|
58
|
+
// 2. 支持 OAuth 身份验证流程
|
|
59
|
+
// 3. MCP 服务器配置由 Codebuddy CLI 自己管理
|
|
60
|
+
// 4. 通过参数透传实现 MCP 命令管理
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 配置验证 Schema
|
|
64
|
+
```typescript
|
|
65
|
+
const CodebuddyConfigSchema = z.discriminatedUnion('type', [
|
|
66
|
+
z.object({
|
|
67
|
+
type: z.literal('none')
|
|
68
|
+
}),
|
|
69
|
+
z.object({
|
|
70
|
+
type: z.literal('custom'),
|
|
71
|
+
apiKey: z.string().optional()
|
|
72
|
+
})
|
|
73
|
+
])
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 实现策略
|
|
77
|
+
|
|
78
|
+
### 1. 扩展现有架构
|
|
79
|
+
- 在 `src/utils/ai/const.ts` 中添加 Codebuddy 常量定义
|
|
80
|
+
- 在 `src/utils/ai/router.ts` 中添加 Codebuddy 路由逻辑
|
|
81
|
+
- 在 `src/utils/ai/config.ts` 中添加 Codebuddy 配置管理
|
|
82
|
+
|
|
83
|
+
### 2. 命令执行流程
|
|
84
|
+
1. 检查 Codebuddy CLI 是否已安装
|
|
85
|
+
2. 验证配置有效性
|
|
86
|
+
3. 解析透传参数
|
|
87
|
+
4. 执行 Codebuddy 命令
|
|
88
|
+
5. 处理执行结果
|
|
89
|
+
|
|
90
|
+
### 3. 配置管理流程
|
|
91
|
+
1. 检查配置文件是否存在
|
|
92
|
+
2. 验证配置格式
|
|
93
|
+
3. 提供配置向导
|
|
94
|
+
4. 保存配置到指定位置
|
|
95
|
+
|
|
96
|
+
### 4. MCP 服务器管理
|
|
97
|
+
- 通过参数透传实现 MCP 命令管理
|
|
98
|
+
- 支持三种配置作用域
|
|
99
|
+
- 配置文件自动合并
|
|
100
|
+
|
|
101
|
+
## 测试策略
|
|
102
|
+
|
|
103
|
+
### 单元测试
|
|
104
|
+
- 配置验证测试
|
|
105
|
+
- 命令解析测试
|
|
106
|
+
- 参数透传测试
|
|
107
|
+
|
|
108
|
+
### 集成测试
|
|
109
|
+
- 完整命令执行流程测试
|
|
110
|
+
- 配置管理流程测试
|
|
111
|
+
- 错误处理测试
|
|
112
|
+
|
|
113
|
+
### 端到端测试
|
|
114
|
+
- 用户场景测试
|
|
115
|
+
- 安装向导测试
|
|
116
|
+
- MCP 服务器管理测试
|
|
117
|
+
|
|
118
|
+
## 安全性
|
|
119
|
+
|
|
120
|
+
### 配置安全
|
|
121
|
+
- API 密钥加密存储
|
|
122
|
+
- 配置文件权限控制
|
|
123
|
+
- 敏感信息脱敏显示
|
|
124
|
+
|
|
125
|
+
### 命令执行安全
|
|
126
|
+
- 参数验证和过滤
|
|
127
|
+
- 环境变量安全传递
|
|
128
|
+
- 子进程权限控制
|
|
129
|
+
|
|
130
|
+
## 部署和发布
|
|
131
|
+
|
|
132
|
+
### 开发阶段
|
|
133
|
+
1. 实现核心功能
|
|
134
|
+
2. 添加单元测试
|
|
135
|
+
3. 集成测试验证
|
|
136
|
+
|
|
137
|
+
### 发布阶段
|
|
138
|
+
1. 更新文档
|
|
139
|
+
2. 版本发布
|
|
140
|
+
3. 用户反馈收集
|
|
141
|
+
|
|
142
|
+
## 兼容性
|
|
143
|
+
|
|
144
|
+
### 系统兼容性
|
|
145
|
+
- 支持 macOS、Linux、Windows
|
|
146
|
+
- Node.js 18+ 版本要求
|
|
147
|
+
- 与现有 AI 工具共存
|
|
148
|
+
|
|
149
|
+
### 配置兼容性
|
|
150
|
+
- 向后兼容现有配置
|
|
151
|
+
- 支持配置迁移
|
|
152
|
+
- 配置文件格式统一
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 需求文档
|
|
2
|
+
|
|
3
|
+
## 介绍
|
|
4
|
+
|
|
5
|
+
在 CloudBase CLI 的 ai 命令中集成 Codebuddy Code CLI,为用户提供统一的 AI 开发工具入口。Codebuddy Code CLI 是一个面向开发者的自主编排的编程智能体,通过命令行界面为开发者提供强大的 AI 编程能力。
|
|
6
|
+
|
|
7
|
+
## 需求
|
|
8
|
+
|
|
9
|
+
### 需求 1 - Codebuddy Code CLI 基础集成
|
|
10
|
+
|
|
11
|
+
**用户故事:** 作为开发者,我希望在 CloudBase CLI 中能够直接启动和使用 Codebuddy Code CLI,这样我就不需要单独安装和配置 Codebuddy Code CLI。
|
|
12
|
+
|
|
13
|
+
#### 验收标准
|
|
14
|
+
|
|
15
|
+
1. When 用户运行 `tcb ai -a codebuddy` 时,CloudBase CLI 应当启动 Codebuddy Code CLI 工具。
|
|
16
|
+
2. When Codebuddy Code CLI 未安装时,系统应当提示用户安装并提供安装指导。
|
|
17
|
+
3. When 用户运行 `tcb ai -a codebuddy --setup` 时,系统应当运行 Codebuddy Code CLI 的配置向导。
|
|
18
|
+
4. When 用户运行 `tcb ai -a codebuddy --config` 时,系统应当显示当前的 Codebuddy Code CLI 配置信息。
|
|
19
|
+
5. When 用户运行 `tcb ai -a codebuddy --reset` 时,系统应当重置 Codebuddy Code CLI 的配置。
|
|
20
|
+
|
|
21
|
+
### 需求 2 - MCP 服务器管理功能
|
|
22
|
+
|
|
23
|
+
**用户故事:** 作为开发者,我希望能够在 CloudBase CLI 中管理 Codebuddy Code CLI 的 MCP 服务器,这样我就可以方便地连接外部工具和数据源。
|
|
24
|
+
|
|
25
|
+
#### 验收标准
|
|
26
|
+
|
|
27
|
+
1. When 用户运行 `tcb ai -a codebuddy -- mcp add <server-name> --env <env-vars> -- <command>` 时,系统应当添加指定的 MCP 服务器。
|
|
28
|
+
2. When 用户运行 `tcb ai -a codebuddy -- mcp list` 时,系统应当显示所有已配置的 MCP 服务器列表。
|
|
29
|
+
3. When 用户运行 `tcb ai -a codebuddy -- mcp get <server-name>` 时,系统应当显示指定 MCP 服务器的详细信息。
|
|
30
|
+
4. When 用户运行 `tcb ai -a codebuddy -- mcp remove <server-name>` 时,系统应当移除指定的 MCP 服务器。
|
|
31
|
+
5. When 用户配置 MCP 服务器时,系统应当支持 Local、Project、User 三种配置作用域。
|
|
32
|
+
|
|
33
|
+
### 需求 3 - 参数透传和命令执行
|
|
34
|
+
|
|
35
|
+
**用户故事:** 作为开发者,我希望能够将 CloudBase CLI 的参数透传给 Codebuddy Code CLI,这样我就可以使用 Codebuddy Code CLI 的所有功能。
|
|
36
|
+
|
|
37
|
+
#### 验收标准
|
|
38
|
+
|
|
39
|
+
1. When 用户在 `tcb ai -a codebuddy` 后添加 `--` 和参数时,系统应当将这些参数透传给 Codebuddy Code CLI。
|
|
40
|
+
2. When 用户使用 `tcb ai -a codebuddy -- -p "query"` 时,系统应当执行单次查询模式。
|
|
41
|
+
3. When 用户使用 `tcb ai -a codebuddy -- -c` 时,系统应当继续最近的对话。
|
|
42
|
+
4. When 用户使用 `tcb ai -a codebuddy -- -r "session-id" "query"` 时,系统应当恢复特定的会话。
|
|
43
|
+
|
|
44
|
+
### 需求 4 - 配置管理和验证
|
|
45
|
+
|
|
46
|
+
**用户故事:** 作为开发者,我希望 CloudBase CLI 能够管理 Codebuddy Code CLI 的配置,并验证配置的有效性。
|
|
47
|
+
|
|
48
|
+
#### 验收标准
|
|
49
|
+
|
|
50
|
+
1. When 用户首次使用 Codebuddy Code CLI 时,系统应当检查配置并引导用户完成配置。
|
|
51
|
+
2. When 用户配置 Codebuddy Code CLI 时,系统应当验证配置的有效性。
|
|
52
|
+
3. When 配置无效时,系统应当提供清晰的错误信息和修复建议。
|
|
53
|
+
4. When 用户需要身份验证时,系统应当支持本地开发环境、远程开发环境和无交互环境的认证方式。
|