@cloudbase/cli 2.9.3 → 2.9.4
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/standalone/cli.js +270 -12
- package/lib/commands/functions/layer/bind.js +11 -10
- package/lib/commands/functions/layer/create.js +5 -5
- package/lib/commands/functions/layer/delete.js +7 -5
- package/lib/commands/functions/layer/download.js +10 -5
- package/lib/commands/functions/layer/list.js +4 -9
- package/lib/commands/functions/layer/sort.js +1 -1
- package/lib/commands/functions/trigger-create.js +3 -6
- package/lib/commands/functions/trigger-delete.js +4 -7
- package/lib/commands/pull/pull.js +2 -1
- package/lib/utils/ai/const.js +8 -1
- package/lib/utils/ai/setup.js +21 -6
- package/lib/utils/config.js +1 -0
- package/lib/utils/template-manager.js +19 -2
- package/package.json +4 -4
- package/specs/tcb-pull-cnb-support/design.md +134 -0
- package/specs/tcb-pull-cnb-support/requirements.md +53 -0
- package/specs/tcb-pull-cnb-support/tasks.md +98 -0
- package/specs/tcb-pull-mcp-integration/design.md +5 -0
- package/specs/tcb-pull-mcp-integration/implementation-summary.md +5 -0
- package/specs/tcb-pull-mcp-integration/requirements.md +5 -0
- package/types/utils/ai/const.d.ts +6 -0
package/dist/standalone/cli.js
CHANGED
|
@@ -42400,7 +42400,7 @@ module.exports = function generate_pattern(it, $keyword, $ruleType) {
|
|
|
42400
42400
|
/***/ ((module) => {
|
|
42401
42401
|
|
|
42402
42402
|
"use strict";
|
|
42403
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@cloudbase/cli","version":"2.9.
|
|
42403
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@cloudbase/cli","version":"2.9.3","description":"cli tool for cloudbase","main":"lib/index.js","scripts":{"build":"rimraf lib types && tsc --resolveJsonModule && cpx \\"src/**/*.html\\" lib","watch":"rimraf lib types && tsc -w","dev":"rimraf lib types && cpx \\"src/**/*.html\\" lib && tsc -w","eslint":"eslint \\"./**/*.ts\\"","test":"node --experimental-vm-modules node_modules/jest/bin/jest.js --runInBand --forceExit --detectOpenHandles --coverage --verbose --testTimeout=10000","tsc":"tsc","pkg":"pkg ./bin/cloudbase.js --out-path ./pkg","postinstall":"node ./post-install.js || exit 0 && patch-package","prepublishOnly":"npm run build","debug":"bin/tcb.js lowcode watch","build:bundle":"webpack --config build/webpack/cli.cjs && webpack --config build/webpack/ccr.cjs","package:darwin-arm64":"OS=darwin ARCH=arm64 VERSION= node -e \\"require(\'child_process\').execSync(\'bash build/scripts/package.sh\',{stdio:\'inherit\'})\\"","package:darwin-x64":"OS=darwin ARCH=x64 VERSION= node -e \\"require(\'child_process\').execSync(\'bash build/scripts/package.sh\',{stdio:\'inherit\'})\\"","package:linux-arm64":"OS=linux ARCH=arm64 VERSION= node -e \\"require(\'child_process\').execSync(\'bash build/scripts/package.sh\',{stdio:\'inherit\'})\\"","package:linux-x64":"OS=linux ARCH=x64 VERSION= node -e \\"require(\'child_process\').execSync(\'bash build/scripts/package.sh\',{stdio:\'inherit\'})\\"","package:all":"bash build/scripts/build-all.sh","node:fetch:one":"node -e \\"require(\'child_process\').execSync(\'bash build/scripts/fetch-node.sh\',{stdio:\'inherit\'})\\"","node:fetch:all":"NODE_VERSION=22.18.0 bash build/scripts/fetch-node.sh --all","node:fetch:win-x64":"OS=windows ARCH=x64 NODE_VERSION=22.18.0 bash build/scripts/fetch-node.sh","node:fetch:win-arm64":"OS=windows ARCH=arm64 NODE_VERSION=22.18.0 bash build/scripts/fetch-node.sh","package:windows-x64":"OS=windows ARCH=x64 VERSION= node -e \\"require(\'child_process\').execSync(\'bash build/scripts/package.sh\',{stdio:\'inherit\'})\\"","package:windows-arm64":"OS=windows ARCH=arm64 VERSION= node -e \\"require(\'child_process\').execSync(\'bash build/scripts/package.sh\',{stdio:\'inherit\'})\\"","package:windows-all":"npm run -s node:fetch:win-x64 && npm run -s node:fetch:win-arm64 && npm run -s package:windows-x64 && npm run -s package:windows-arm64","out:prune":"bash build/scripts/prune-out.sh"},"repository":{"type":"git","url":"https://github.com/TencentCloudBase/cloud-base-cli.git"},"bin":{"cloudbase":"bin/cloudbase.js","cloudbase-mcp":"bin/cloudbase-mcp.cjs","tcb":"bin/tcb.js","ccr":"bin/ccr.js"},"husky":{"hooks":{"pre-commit":"npm run build"}},"author":"cwuyiqing@gmail.com","license":"ISC","dependencies":{"@cloudbase/cloud-api":"^0.5.5","@cloudbase/cloudbase-mcp":"^1.8.41","@cloudbase/framework-core":"^1.9.7","@cloudbase/functions-framework":"1.16.0","@cloudbase/iac-core":"0.0.3-alpha.11","@cloudbase/lowcode-cli":"^0.22.2","@cloudbase/manager-node":"4.5.0","@cloudbase/toolbox":"^0.7.9","@dotenvx/dotenvx":"^1.48.3","@musistudio/claude-code-router":"1.0.36","address":"^1.1.2","camelcase-keys":"^7.0.2","chalk":"^2.4.2","cli-table3":"^0.5.1","commander":"7","del":"^5.1.0","didyoumean":"^1.2.2","enquirer":"^2.3.6","execa":"^4.0.3","figlet":"^1.7.0","fs-extra":"^8.1.0","gradient-string":"^2.0.2","https-proxy-agent":"^5.0.1","i":"^0.3.7","inquirer":"^6.5.0","json-schema-to-typescript":"^14.0.5","lodash":"^4.17.21","log-symbols":"^3.0.0","lowdb":"^1.0.0","make-dir":"^3.0.0","node-fetch":"^2.6.0","nodemon":"^3.1.4","npm":"^11.5.2","open":"^7.0.0","ora":"^4.0.2","patch-package":"^8.0.0","portfinder":"^1.0.28","progress":"^2.0.3","query-string":"^6.8.1","reflect-metadata":"^0.1.13","semver":"^7.3.7","simple-git":"^3.28.0","tar-fs":"^2.0.1","terminal-link":"^2.1.1","toml":"^3.0.0","unzipper":"^0.10.10","update-notifier":"^4.0.0","xdg-basedir":"^4.0.0","yargs":"^16.2.0","yargs-parser":"^21.0.1","zod":"^4.0.13"},"devDependencies":{"@types/fs-extra":"^11.0.4","@types/jest":"^27","@types/koa__router":"^8.0.11","@types/lodash":"^4.14.182","@types/node":"^12.12.38","@types/node-fetch":"^2.5.4","@types/react":"^17.0.37","@types/semver":"^7.3.9","@types/unzipper":"^0.10.11","@types/webpack-dev-server":"^3.11.1","@typescript-eslint/eslint-plugin":"^4.8.1","@typescript-eslint/parser":"^4.8.1","cpx":"^1.5.0","eslint":"^7.14.0","eslint-config-alloy":"^3.8.2","husky":"^3.0.9","jest":"^27","rimraf":"^3.0.2","ts-jest":"^27","typescript":"^4.7.2","webpack":"^5.92.0","webpack-cli":"^5.1.4"},"packageManager":"yarn@3.6.2+sha512.2c2f8b9615e6659773f65cdec7cf92ef773a98a99e611579601f61c7a91ec94c89c929aac86f1cee819421a9b0db7acfd53ec3ebb95af44f77f77634b08b9557"}');
|
|
42404
42404
|
|
|
42405
42405
|
/***/ }),
|
|
42406
42406
|
|
|
@@ -67569,7 +67569,7 @@ class AISetupWizard {
|
|
|
67569
67569
|
type: 'list',
|
|
67570
67570
|
name: 'agent',
|
|
67571
67571
|
message: `${message} ${const_1.LIST_HINT}`,
|
|
67572
|
-
choices: [const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.CURSOR, const_1.AIDER,
|
|
67572
|
+
choices: [const_1.CLAUDE, const_1.CODEBUDDY, const_1.QWEN, const_1.CODEX, const_1.CURSOR, const_1.AIDER, ...(includeNone ? [const_1.NONE] : [])],
|
|
67573
67573
|
default: const_1.CLAUDE.value
|
|
67574
67574
|
}
|
|
67575
67575
|
]);
|
|
@@ -68028,11 +68028,11 @@ class AISetupWizard {
|
|
|
68028
68028
|
message: `选择配置方式: ${const_1.LIST_HINT}`,
|
|
68029
68029
|
choices: [
|
|
68030
68030
|
{
|
|
68031
|
-
name: '使用
|
|
68031
|
+
name: '使用 CodeBuddy 账号登录',
|
|
68032
68032
|
value: 'none'
|
|
68033
68033
|
},
|
|
68034
68034
|
{
|
|
68035
|
-
name: '配置 API KEY(用于无交互环境)',
|
|
68035
|
+
name: '配置 CodeBuddy API KEY(用于无交互环境)',
|
|
68036
68036
|
value: 'custom'
|
|
68037
68037
|
}
|
|
68038
68038
|
],
|
|
@@ -68044,7 +68044,7 @@ class AISetupWizard {
|
|
|
68044
68044
|
{
|
|
68045
68045
|
type: 'password',
|
|
68046
68046
|
name: 'apiKey',
|
|
68047
|
-
message: '请输入
|
|
68047
|
+
message: '请输入 CodeBuddy API Key:',
|
|
68048
68048
|
validate: (input) => input.trim().length > 0 || 'API Key 不能为空'
|
|
68049
68049
|
}
|
|
68050
68050
|
]);
|
|
@@ -68055,7 +68055,7 @@ class AISetupWizard {
|
|
|
68055
68055
|
else {
|
|
68056
68056
|
yield this.aiConfigManager.updateCodebuddyConfig('none', {});
|
|
68057
68057
|
}
|
|
68058
|
-
log.info('✅
|
|
68058
|
+
log.info('✅ CodeBuddy Code 配置完成');
|
|
68059
68059
|
log.info('💡 提示:首次使用时会自动打开浏览器进行 OAuth 身份验证');
|
|
68060
68060
|
});
|
|
68061
68061
|
}
|
|
@@ -309000,6 +309000,248 @@ module.exports = {
|
|
|
309000
309000
|
})));
|
|
309001
309001
|
|
|
309002
309002
|
|
|
309003
|
+
/***/ }),
|
|
309004
|
+
|
|
309005
|
+
/***/ 54698:
|
|
309006
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
309007
|
+
|
|
309008
|
+
"use strict";
|
|
309009
|
+
|
|
309010
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
309011
|
+
if (k2 === undefined) k2 = k;
|
|
309012
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
309013
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
309014
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
309015
|
+
}
|
|
309016
|
+
Object.defineProperty(o, k2, desc);
|
|
309017
|
+
}) : (function(o, m, k, k2) {
|
|
309018
|
+
if (k2 === undefined) k2 = k;
|
|
309019
|
+
o[k2] = m[k];
|
|
309020
|
+
}));
|
|
309021
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
309022
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
309023
|
+
}) : function(o, v) {
|
|
309024
|
+
o["default"] = v;
|
|
309025
|
+
});
|
|
309026
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
309027
|
+
if (mod && mod.__esModule) return mod;
|
|
309028
|
+
var result = {};
|
|
309029
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
309030
|
+
__setModuleDefault(result, mod);
|
|
309031
|
+
return result;
|
|
309032
|
+
};
|
|
309033
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
309034
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
309035
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
309036
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
309037
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
309038
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
309039
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
309040
|
+
});
|
|
309041
|
+
};
|
|
309042
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
309043
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
309044
|
+
};
|
|
309045
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
309046
|
+
exports.MCPConfigModifier = void 0;
|
|
309047
|
+
const fs_extra_1 = __importDefault(__webpack_require__(21605));
|
|
309048
|
+
const path_1 = __importDefault(__webpack_require__(16928));
|
|
309049
|
+
const IDE_FILE_MAPPINGS = {
|
|
309050
|
+
cursor: [
|
|
309051
|
+
{ path: '.cursor/rules/cloudbase-rules.mdc' },
|
|
309052
|
+
{ path: '.cursor/mcp.json', isMcpConfig: true }
|
|
309053
|
+
],
|
|
309054
|
+
windsurf: [{ path: '.windsurf/rules/cloudbase-rules.md' }],
|
|
309055
|
+
codebuddy: [{ path: '.rules/cloudbase-rules.md' }],
|
|
309056
|
+
'claude-code': [{ path: 'CLAUDE.md' }, { path: '.mcp.json', isMcpConfig: true }],
|
|
309057
|
+
cline: [{ path: '.clinerules/cloudbase-rules.mdc' }],
|
|
309058
|
+
'gemini-cli': [
|
|
309059
|
+
{ path: '.gemini/GEMINI.md' },
|
|
309060
|
+
{ path: '.gemini/settings.json', isMcpConfig: true }
|
|
309061
|
+
],
|
|
309062
|
+
opencode: [{ path: '.opencode.json', isMcpConfig: true }],
|
|
309063
|
+
'qwen-code': [{ path: '.qwen/QWEN.md' }, { path: '.qwen/settings.json', isMcpConfig: true }],
|
|
309064
|
+
'baidu-comate': [
|
|
309065
|
+
{ path: '.comate/rules/cloudbase-rules.mdr' },
|
|
309066
|
+
{ path: '.comate/rules/cloudbaase-rules.mdr' },
|
|
309067
|
+
{ path: '.comate/mcp.json', isMcpConfig: true }
|
|
309068
|
+
],
|
|
309069
|
+
'openai-codex-cli': [{ path: '.codex/config.toml', isMcpConfig: true }, { path: 'AGENTS.md' }],
|
|
309070
|
+
'augment-code': [{ path: '.augment-guidelines' }],
|
|
309071
|
+
'github-copilot': [{ path: '.github/copilot-instructions.md' }],
|
|
309072
|
+
roocode: [
|
|
309073
|
+
{ path: '.roo/rules/cloudbaase-rules.md' },
|
|
309074
|
+
{ path: '.roo/mcp.json', isMcpConfig: true }
|
|
309075
|
+
],
|
|
309076
|
+
'tongyi-lingma': [{ path: '.lingma/rules/cloudbaase-rules.md' }],
|
|
309077
|
+
trae: [{ path: '.trae/rules/cloudbase-rules.md' }],
|
|
309078
|
+
vscode: [{ path: '.vscode/mcp.json', isMcpConfig: true }, { path: '.vscode/settings.json' }],
|
|
309079
|
+
aider: [{ path: 'mcp.json', isMcpConfig: true }]
|
|
309080
|
+
};
|
|
309081
|
+
function inferConfigFormat(filePath) {
|
|
309082
|
+
return filePath.toLowerCase().endsWith('.toml') ? 'toml' : 'json';
|
|
309083
|
+
}
|
|
309084
|
+
class MCPConfigModifier {
|
|
309085
|
+
modifyMCPConfigs(extractDir, log) {
|
|
309086
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
309087
|
+
try {
|
|
309088
|
+
log.info('🔧 正在修改 MCP 配置文件...');
|
|
309089
|
+
for (const [ide, files] of Object.entries(IDE_FILE_MAPPINGS)) {
|
|
309090
|
+
for (const descriptor of files) {
|
|
309091
|
+
if (!descriptor.isMcpConfig)
|
|
309092
|
+
continue;
|
|
309093
|
+
const filePath = path_1.default.join(extractDir, descriptor.path);
|
|
309094
|
+
log.debug(`检查文件: ${filePath}`);
|
|
309095
|
+
if (yield fs_extra_1.default.pathExists(filePath)) {
|
|
309096
|
+
log.debug(`找到 MCP 配置文件: ${filePath}`);
|
|
309097
|
+
const format = inferConfigFormat(descriptor.path);
|
|
309098
|
+
if (format === 'json') {
|
|
309099
|
+
yield this.modifyMCPJsonFile(filePath, log);
|
|
309100
|
+
}
|
|
309101
|
+
else if (format === 'toml') {
|
|
309102
|
+
yield this.modifyMCPTomlFile(filePath, log);
|
|
309103
|
+
}
|
|
309104
|
+
}
|
|
309105
|
+
else {
|
|
309106
|
+
log.debug(`文件不存在: ${filePath}`);
|
|
309107
|
+
}
|
|
309108
|
+
}
|
|
309109
|
+
}
|
|
309110
|
+
log.info('✅ MCP 配置文件修改完成');
|
|
309111
|
+
}
|
|
309112
|
+
catch (error) {
|
|
309113
|
+
log.warn(`⚠️ MCP 配置文件修改失败: ${error.message}`);
|
|
309114
|
+
}
|
|
309115
|
+
});
|
|
309116
|
+
}
|
|
309117
|
+
modifyMCPJsonFile(filePath, log) {
|
|
309118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
309119
|
+
try {
|
|
309120
|
+
const content = yield fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
309121
|
+
const config = JSON.parse(content);
|
|
309122
|
+
log.debug(`读取配置文件 ${filePath}: ${JSON.stringify(config)}`);
|
|
309123
|
+
let modified = false;
|
|
309124
|
+
const modifyCommands = (obj) => {
|
|
309125
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
309126
|
+
return obj;
|
|
309127
|
+
}
|
|
309128
|
+
if (Array.isArray(obj)) {
|
|
309129
|
+
return obj.map((item) => modifyCommands(item));
|
|
309130
|
+
}
|
|
309131
|
+
const result = Object.assign({}, obj);
|
|
309132
|
+
if (result.command === 'npx' && Array.isArray(result.args)) {
|
|
309133
|
+
const argsStr = result.args.join(' ');
|
|
309134
|
+
log.debug(`检查命令: command=${result.command}, args=${JSON.stringify(result.args)}`);
|
|
309135
|
+
if (argsStr.includes('npm-global-exec@latest') &&
|
|
309136
|
+
argsStr.includes('@cloudbase/cloudbase-mcp@latest')) {
|
|
309137
|
+
log.debug(`匹配到需要修改的命令: ${argsStr}`);
|
|
309138
|
+
result.command = 'cloudbase-mcp';
|
|
309139
|
+
result.args = [];
|
|
309140
|
+
result.env = {
|
|
309141
|
+
INTEGRATION_IDE: process.env.INTEGRATION_IDE || 'CloudBaseCLI'
|
|
309142
|
+
};
|
|
309143
|
+
modified = true;
|
|
309144
|
+
log.debug(`修改配置文件 ${filePath}: npx -> cloudbase-mcp`);
|
|
309145
|
+
}
|
|
309146
|
+
else {
|
|
309147
|
+
log.debug(`命令不匹配修改条件: ${argsStr}`);
|
|
309148
|
+
}
|
|
309149
|
+
}
|
|
309150
|
+
for (const [key, value] of Object.entries(result)) {
|
|
309151
|
+
result[key] = modifyCommands(value);
|
|
309152
|
+
}
|
|
309153
|
+
return result;
|
|
309154
|
+
};
|
|
309155
|
+
const modifiedConfig = modifyCommands(config);
|
|
309156
|
+
if (modified) {
|
|
309157
|
+
yield fs_extra_1.default.writeJson(filePath, modifiedConfig, { spaces: 2 });
|
|
309158
|
+
log.debug(`✅ 已修改 ${filePath}`);
|
|
309159
|
+
}
|
|
309160
|
+
else {
|
|
309161
|
+
log.debug(`⚠️ 配置文件 ${filePath} 未发生修改`);
|
|
309162
|
+
}
|
|
309163
|
+
}
|
|
309164
|
+
catch (error) {
|
|
309165
|
+
log.warn(`⚠️ 修改配置文件 ${filePath} 失败: ${error.message}`);
|
|
309166
|
+
}
|
|
309167
|
+
});
|
|
309168
|
+
}
|
|
309169
|
+
modifyMCPTomlFile(filePath, log) {
|
|
309170
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
309171
|
+
try {
|
|
309172
|
+
const content = yield fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
309173
|
+
const toml = yield Promise.resolve().then(() => __importStar(__webpack_require__(1293)));
|
|
309174
|
+
const config = toml.parse(content);
|
|
309175
|
+
let modified = false;
|
|
309176
|
+
const modifyCommands = (obj) => {
|
|
309177
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
309178
|
+
return obj;
|
|
309179
|
+
}
|
|
309180
|
+
if (Array.isArray(obj)) {
|
|
309181
|
+
return obj.map((item) => modifyCommands(item));
|
|
309182
|
+
}
|
|
309183
|
+
const result = Object.assign({}, obj);
|
|
309184
|
+
if (result.command === 'npx' && Array.isArray(result.args)) {
|
|
309185
|
+
const argsStr = result.args.join(' ');
|
|
309186
|
+
if (argsStr.includes('@cloudbase/cloudbase-mcp@latest')) {
|
|
309187
|
+
result.command = 'cloudbase-mcp';
|
|
309188
|
+
result.args = [];
|
|
309189
|
+
result.env = {
|
|
309190
|
+
INTEGRATION_IDE: process.env.INTEGRATION_IDE || 'CloudBaseCLI'
|
|
309191
|
+
};
|
|
309192
|
+
modified = true;
|
|
309193
|
+
log.debug(`修改配置文件 ${filePath}: npx -> cloudbase-mcp`);
|
|
309194
|
+
}
|
|
309195
|
+
}
|
|
309196
|
+
for (const [key, value] of Object.entries(result)) {
|
|
309197
|
+
result[key] = modifyCommands(value);
|
|
309198
|
+
}
|
|
309199
|
+
return result;
|
|
309200
|
+
};
|
|
309201
|
+
const modifiedConfig = modifyCommands(config);
|
|
309202
|
+
if (modified) {
|
|
309203
|
+
const tomlString = this.objectToToml(modifiedConfig);
|
|
309204
|
+
yield fs_extra_1.default.writeFile(filePath, tomlString, 'utf-8');
|
|
309205
|
+
log.debug(`✅ 已修改 ${filePath}`);
|
|
309206
|
+
}
|
|
309207
|
+
}
|
|
309208
|
+
catch (error) {
|
|
309209
|
+
log.warn(`⚠️ 修改配置文件 ${filePath} 失败: ${error.message}`);
|
|
309210
|
+
}
|
|
309211
|
+
});
|
|
309212
|
+
}
|
|
309213
|
+
objectToToml(obj, prefix = '') {
|
|
309214
|
+
const lines = [];
|
|
309215
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
309216
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
309217
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
309218
|
+
lines.push(`[${fullKey}]`);
|
|
309219
|
+
lines.push(this.objectToToml(value, fullKey));
|
|
309220
|
+
}
|
|
309221
|
+
else if (Array.isArray(value)) {
|
|
309222
|
+
const arrayStr = value
|
|
309223
|
+
.map((item) => {
|
|
309224
|
+
if (typeof item === 'string') {
|
|
309225
|
+
return `"${item}"`;
|
|
309226
|
+
}
|
|
309227
|
+
return item;
|
|
309228
|
+
})
|
|
309229
|
+
.join(', ');
|
|
309230
|
+
lines.push(`${key} = [${arrayStr}]`);
|
|
309231
|
+
}
|
|
309232
|
+
else if (typeof value === 'string') {
|
|
309233
|
+
lines.push(`${key} = "${value}"`);
|
|
309234
|
+
}
|
|
309235
|
+
else {
|
|
309236
|
+
lines.push(`${key} = ${value}`);
|
|
309237
|
+
}
|
|
309238
|
+
}
|
|
309239
|
+
return lines.join('\n');
|
|
309240
|
+
}
|
|
309241
|
+
}
|
|
309242
|
+
exports.MCPConfigModifier = MCPConfigModifier;
|
|
309243
|
+
|
|
309244
|
+
|
|
309003
309245
|
/***/ }),
|
|
309004
309246
|
|
|
309005
309247
|
/***/ 54723:
|
|
@@ -467866,7 +468108,7 @@ exports.CURSOR = {
|
|
|
467866
468108
|
})
|
|
467867
468109
|
};
|
|
467868
468110
|
exports.CODEBUDDY = {
|
|
467869
|
-
name: '
|
|
468111
|
+
name: 'CodeBuddy Code',
|
|
467870
468112
|
value: 'codebuddy',
|
|
467871
468113
|
configSchema: v3_1.default.discriminatedUnion('type', [
|
|
467872
468114
|
v3_1.default.object({
|
|
@@ -467882,7 +468124,7 @@ exports.NONE = {
|
|
|
467882
468124
|
name: '暂不配置',
|
|
467883
468125
|
value: 'none'
|
|
467884
468126
|
};
|
|
467885
|
-
exports.AGENTS = [exports.CLAUDE, exports.QWEN, exports.CODEX, exports.AIDER, exports.CURSOR, exports.
|
|
468127
|
+
exports.AGENTS = [exports.CLAUDE, exports.CODEBUDDY, exports.QWEN, exports.CODEX, exports.AIDER, exports.CURSOR, exports.NONE];
|
|
467886
468128
|
exports.CLOUDBASE_PROVIDERS = [
|
|
467887
468129
|
{
|
|
467888
468130
|
name: 'Kimi',
|
|
@@ -469697,6 +469939,7 @@ const fs_extra_1 = __importDefault(__webpack_require__(21605));
|
|
|
469697
469939
|
const path_1 = __importDefault(__webpack_require__(16928));
|
|
469698
469940
|
const simple_git_1 = __webpack_require__(94662);
|
|
469699
469941
|
const error_1 = __webpack_require__(66759);
|
|
469942
|
+
const mcp_config_modifier_1 = __webpack_require__(54698);
|
|
469700
469943
|
const BUILTIN_TEMPLATES = {
|
|
469701
469944
|
miniprogram: {
|
|
469702
469945
|
url: 'https://static.cloudbase.net/cloudbase-examples/miniprogram-cloudbase-miniprogram-template.zip',
|
|
@@ -469722,6 +469965,7 @@ const BUILTIN_TEMPLATES = {
|
|
|
469722
469965
|
class TemplateManager {
|
|
469723
469966
|
constructor() {
|
|
469724
469967
|
this.git = (0, simple_git_1.simpleGit)();
|
|
469968
|
+
this.mcpConfigModifier = new mcp_config_modifier_1.MCPConfigModifier();
|
|
469725
469969
|
}
|
|
469726
469970
|
pullTemplate(source, options = {}, log) {
|
|
469727
469971
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -469885,6 +470129,14 @@ class TemplateManager {
|
|
|
469885
470129
|
yield this.copyFilesSkipExisting(tempDir, targetPath, log);
|
|
469886
470130
|
}
|
|
469887
470131
|
log.info(`✅ 模板复制完成`);
|
|
470132
|
+
try {
|
|
470133
|
+
log.debug('🔧 开始调用 MCP 配置修改器...');
|
|
470134
|
+
yield this.mcpConfigModifier.modifyMCPConfigs(targetPath, log);
|
|
470135
|
+
log.debug('✅ MCP 配置修改器调用完成');
|
|
470136
|
+
}
|
|
470137
|
+
catch (error) {
|
|
470138
|
+
log.warn(`⚠️ MCP 配置修改失败: ${error.message}`);
|
|
470139
|
+
}
|
|
469888
470140
|
}
|
|
469889
470141
|
catch (error) {
|
|
469890
470142
|
throw new error_1.CloudBaseError(`复制模板失败: ${error.message}`, { original: error });
|
|
@@ -611803,20 +612055,26 @@ exports.TOOLKIT_CONFIGS = {
|
|
|
611803
612055
|
rules: 'CLAUDE.md'
|
|
611804
612056
|
},
|
|
611805
612057
|
[const_1.CODEBUDDY.value]: {
|
|
611806
|
-
config: '.env.local'
|
|
612058
|
+
config: '.env.local',
|
|
612059
|
+
mcp: '.mcp.json',
|
|
612060
|
+
rules: 'CODEBUDDY.md'
|
|
611807
612061
|
},
|
|
611808
612062
|
[const_1.QWEN.value]: {
|
|
611809
612063
|
config: '.env.local',
|
|
612064
|
+
mcp: '.qwen/settings.json',
|
|
611810
612065
|
rules: '.qwen/QWEN.md'
|
|
611811
612066
|
},
|
|
611812
612067
|
[const_1.CODEX.value]: {
|
|
611813
|
-
config: '.env.local'
|
|
612068
|
+
config: '.env.local',
|
|
612069
|
+
mcp: '.codex/config.toml',
|
|
612070
|
+
rules: 'AGENTS.md'
|
|
611814
612071
|
},
|
|
611815
612072
|
[const_1.AIDER.value]: {
|
|
611816
|
-
config: '.env.local'
|
|
612073
|
+
config: '.env.local',
|
|
611817
612074
|
},
|
|
611818
612075
|
[const_1.CURSOR.value]: {
|
|
611819
|
-
config: '.cursor/mcp.json'
|
|
612076
|
+
config: '.cursor/mcp.json',
|
|
612077
|
+
rules: '.cursor/rules/cloudbase-rules.mdc'
|
|
611820
612078
|
},
|
|
611821
612079
|
};
|
|
611822
612080
|
function createConfigParser() {
|
|
@@ -52,9 +52,9 @@ let AttachFileLayer = class AttachFileLayer extends common_1.Command {
|
|
|
52
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
53
|
const { codeSecret } = options;
|
|
54
54
|
const fnName = params === null || params === void 0 ? void 0 : params[0];
|
|
55
|
+
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
55
56
|
const loading = (0, utils_1.loadingFactory)();
|
|
56
57
|
loading.start('数据加载中...');
|
|
57
|
-
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
58
58
|
const envFunctions = yield functionService.listAllFunctions({
|
|
59
59
|
envId
|
|
60
60
|
});
|
|
@@ -62,33 +62,34 @@ let AttachFileLayer = class AttachFileLayer extends common_1.Command {
|
|
|
62
62
|
if (!exist) {
|
|
63
63
|
throw new error_1.CloudBaseError(`当前环境不存在此函数 [${fnName}]`);
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
const listLayersRes = yield functionService.listLayers({
|
|
66
66
|
offset: 0,
|
|
67
67
|
limit: 200,
|
|
68
|
-
searchSrc: `TCB_${envId}`
|
|
69
68
|
});
|
|
69
|
+
const layers = listLayersRes.Layers || [];
|
|
70
70
|
loading.stop();
|
|
71
|
-
|
|
71
|
+
const newLayers = layers.map((item) => ({
|
|
72
72
|
name: `[${LayerStatusMap[item.Status] || '异常'}] ${item.LayerName}`,
|
|
73
73
|
value: item.LayerName
|
|
74
74
|
}));
|
|
75
|
-
if (!
|
|
75
|
+
if (!newLayers.length) {
|
|
76
76
|
throw new error_1.CloudBaseError('没有可用的文件层,请先创建文件层!');
|
|
77
77
|
}
|
|
78
78
|
const { layer } = yield (0, enquirer_1.prompt)({
|
|
79
79
|
type: 'select',
|
|
80
80
|
name: 'layer',
|
|
81
81
|
message: '选择文件层名称',
|
|
82
|
-
choices:
|
|
82
|
+
choices: newLayers,
|
|
83
83
|
result(choices) {
|
|
84
84
|
const keys = Object.values(this.map(choices));
|
|
85
85
|
return keys[0];
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
-
let
|
|
88
|
+
let listLayerVersionsRes = yield functionService.listLayerVersions({
|
|
89
89
|
name: layer
|
|
90
90
|
});
|
|
91
|
-
|
|
91
|
+
let layerVersions = listLayerVersionsRes.LayerVersions || [];
|
|
92
|
+
const versions = layerVersions.map((item) => String(item.LayerVersion));
|
|
92
93
|
if (!versions.length) {
|
|
93
94
|
throw new error_1.CloudBaseError('没有可用的文件层版本,请先创建文件层版本!');
|
|
94
95
|
}
|
|
@@ -99,7 +100,7 @@ let AttachFileLayer = class AttachFileLayer extends common_1.Command {
|
|
|
99
100
|
choices: versions
|
|
100
101
|
});
|
|
101
102
|
loading.start('文件层绑定中...');
|
|
102
|
-
yield
|
|
103
|
+
yield functionService.attachLayer({
|
|
103
104
|
envId,
|
|
104
105
|
functionName: fnName,
|
|
105
106
|
layerName: layer,
|
|
@@ -163,7 +164,7 @@ let UnAttachFileLayer = class UnAttachFileLayer extends common_1.Command {
|
|
|
163
164
|
}
|
|
164
165
|
});
|
|
165
166
|
loading.start('文件层解绑中...');
|
|
166
|
-
yield
|
|
167
|
+
yield functionService.unAttachLayer({
|
|
167
168
|
envId,
|
|
168
169
|
functionName: fnName,
|
|
169
170
|
layerName: layer.LayerName,
|
|
@@ -51,20 +51,20 @@ let CreateFileLayer = class CreateFileLayer extends common_1.Command {
|
|
|
51
51
|
const alias = params === null || params === void 0 ? void 0 : params[0];
|
|
52
52
|
const { file } = options;
|
|
53
53
|
const layerName = `${alias}_${envId}`;
|
|
54
|
-
const
|
|
54
|
+
const listLayerRes = yield functionsService.listLayers({
|
|
55
55
|
offset: 0,
|
|
56
56
|
limit: 200
|
|
57
57
|
});
|
|
58
|
+
const layers = listLayerRes.Layers || [];
|
|
58
59
|
if (layers.find(({ LayerName }) => LayerName === layerName)) {
|
|
59
60
|
throw new toolbox_1.CloudBaseError(`层名称 ${layerName} 已被您的当前环境或其他环境占用,请换用别的名称`);
|
|
60
61
|
}
|
|
61
62
|
const filePath = path_1.default.resolve(file);
|
|
62
|
-
const runtimes = ['Nodejs12.16', 'Nodejs8.9', 'Php7', 'Java8'];
|
|
63
|
+
const runtimes = ['Nodejs14.18', 'Nodejs12.16', 'Nodejs8.9', 'Php7', 'Java8'];
|
|
63
64
|
const loading = (0, utils_1.loadingFactory)();
|
|
64
65
|
loading.start('文件层创建中...');
|
|
65
|
-
yield
|
|
66
|
-
|
|
67
|
-
layerName,
|
|
66
|
+
yield functionsService.createLayer({
|
|
67
|
+
name: layerName,
|
|
68
68
|
runtimes,
|
|
69
69
|
contentPath: filePath
|
|
70
70
|
});
|
|
@@ -42,12 +42,13 @@ let DeleteFileLayer = class DeleteFileLayer extends common_1.Command {
|
|
|
42
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
43
43
|
const loading = (0, utils_1.loadingFactory)();
|
|
44
44
|
loading.start('数据加载中...');
|
|
45
|
-
const
|
|
45
|
+
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
46
|
+
const listLayersRes = yield functionService.listLayers({
|
|
46
47
|
offset: 0,
|
|
47
48
|
limit: 200,
|
|
48
|
-
searchSrc: `TCB_${envId}`
|
|
49
49
|
});
|
|
50
50
|
loading.stop();
|
|
51
|
+
const layers = listLayersRes.Layers || [];
|
|
51
52
|
if (!layers.length) {
|
|
52
53
|
throw new error_1.CloudBaseError('当前环境没有可用的文件层,请先创建文件层!');
|
|
53
54
|
}
|
|
@@ -57,10 +58,11 @@ let DeleteFileLayer = class DeleteFileLayer extends common_1.Command {
|
|
|
57
58
|
message: '选择文件层名称',
|
|
58
59
|
choices: layers.map((item) => item.LayerName)
|
|
59
60
|
});
|
|
60
|
-
let
|
|
61
|
+
let listLayerVersionsRes = yield functionService.listLayerVersions({
|
|
61
62
|
name: layer
|
|
62
63
|
});
|
|
63
|
-
|
|
64
|
+
const layerVersions = listLayerVersionsRes.LayerVersions || [];
|
|
65
|
+
const versions = layerVersions.map((item) => String(item.LayerVersion));
|
|
64
66
|
const { version } = yield (0, enquirer_1.prompt)({
|
|
65
67
|
type: 'select',
|
|
66
68
|
name: 'version',
|
|
@@ -68,7 +70,7 @@ let DeleteFileLayer = class DeleteFileLayer extends common_1.Command {
|
|
|
68
70
|
choices: versions
|
|
69
71
|
});
|
|
70
72
|
loading.start('文件层删除中...');
|
|
71
|
-
yield
|
|
73
|
+
yield functionService.deleteLayerVersion({
|
|
72
74
|
name: layer,
|
|
73
75
|
version: Number(version)
|
|
74
76
|
});
|
|
@@ -50,13 +50,14 @@ let DownloadFileLayer = class DownloadFileLayer extends common_1.Command {
|
|
|
50
50
|
execute(envId, options) {
|
|
51
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
52
|
const { dest } = options;
|
|
53
|
+
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
53
54
|
const loading = (0, utils_1.loadingFactory)();
|
|
54
55
|
loading.start('数据加载中...');
|
|
55
|
-
const
|
|
56
|
+
const listLayersRes = yield functionService.listLayers({
|
|
56
57
|
offset: 0,
|
|
57
58
|
limit: 200,
|
|
58
|
-
searchSrc: `TCB_${envId}`
|
|
59
59
|
});
|
|
60
|
+
const layers = listLayersRes.Layers || [];
|
|
60
61
|
loading.stop();
|
|
61
62
|
if (!layers.length) {
|
|
62
63
|
throw new error_1.CloudBaseError('当前环境没有可用的文件层,请先创建文件层!');
|
|
@@ -67,10 +68,11 @@ let DownloadFileLayer = class DownloadFileLayer extends common_1.Command {
|
|
|
67
68
|
message: '选择文件层名称',
|
|
68
69
|
choices: layers.map((item) => item.LayerName)
|
|
69
70
|
});
|
|
70
|
-
let
|
|
71
|
+
let listLayerVersionsRes = yield functionService.listLayerVersions({
|
|
71
72
|
name: layer
|
|
72
73
|
});
|
|
73
|
-
|
|
74
|
+
const layerVersions = listLayerVersionsRes.LayerVersions || [];
|
|
75
|
+
const versions = layerVersions.map((item) => String(item.LayerVersion));
|
|
74
76
|
const { version } = yield (0, enquirer_1.prompt)({
|
|
75
77
|
type: 'select',
|
|
76
78
|
name: 'version',
|
|
@@ -81,9 +83,12 @@ let DownloadFileLayer = class DownloadFileLayer extends common_1.Command {
|
|
|
81
83
|
if (!dest) {
|
|
82
84
|
destPath = path_1.default.resolve(process.cwd(), 'layers');
|
|
83
85
|
}
|
|
86
|
+
else {
|
|
87
|
+
destPath = path_1.default.resolve(dest);
|
|
88
|
+
}
|
|
84
89
|
loading.start('文件下载中...');
|
|
85
90
|
yield fs_extra_1.default.ensureDir(destPath);
|
|
86
|
-
yield
|
|
91
|
+
yield functionService.downloadLayer({
|
|
87
92
|
destPath,
|
|
88
93
|
version: Number(version),
|
|
89
94
|
name: layer
|
|
@@ -57,26 +57,21 @@ let ListFileLayer = class ListFileLayer extends common_1.Command {
|
|
|
57
57
|
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
58
58
|
if (layer && typeof layer === 'string') {
|
|
59
59
|
const layerName = `${layer}_${envId}`;
|
|
60
|
-
|
|
60
|
+
const listLayerVersionsRes = yield functionService.listLayerVersions({
|
|
61
61
|
name: layerName
|
|
62
62
|
});
|
|
63
|
+
data = listLayerVersionsRes.LayerVersions || [];
|
|
63
64
|
}
|
|
64
65
|
else if (name && typeof name === 'string') {
|
|
65
66
|
const res = yield functionService.getFunctionDetail(name, codeSecret);
|
|
66
67
|
data = (res === null || res === void 0 ? void 0 : res.Layers) || [];
|
|
67
68
|
}
|
|
68
|
-
else if (envId) {
|
|
69
|
-
data = yield (0, function_1.listLayers)({
|
|
70
|
-
offset: 0,
|
|
71
|
-
limit: 200,
|
|
72
|
-
searchSrc: `TCB_${envId}`
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
69
|
else {
|
|
76
|
-
|
|
70
|
+
const listLayersRes = yield functionService.listLayers({
|
|
77
71
|
offset: 0,
|
|
78
72
|
limit: 200
|
|
79
73
|
});
|
|
74
|
+
data = listLayersRes.Layers || [];
|
|
80
75
|
}
|
|
81
76
|
loading.stop();
|
|
82
77
|
const head = ['优先级', '名称', '状态', '版本', '证书', '支持运行时', '创建时间'];
|
|
@@ -75,7 +75,7 @@ let SortFileLayer = class SortFileLayer extends common_1.Command {
|
|
|
75
75
|
});
|
|
76
76
|
sortLayers = sortLayers.map((item) => lodash_1.default.pick(item, ['LayerName', 'LayerVersion']));
|
|
77
77
|
loading.start('文件层排序中...');
|
|
78
|
-
yield
|
|
78
|
+
yield functionService.updateFunctionLayer({
|
|
79
79
|
envId,
|
|
80
80
|
functionName: fnName,
|
|
81
81
|
layers: sortLayers
|
|
@@ -51,6 +51,7 @@ let CreateTrigger = class CreateTrigger extends common_1.Command {
|
|
|
51
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
52
|
const { envId, config: { functions } } = ctx;
|
|
53
53
|
const name = params === null || params === void 0 ? void 0 : params[0];
|
|
54
|
+
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
54
55
|
let isBatchCreateTrigger = false;
|
|
55
56
|
if (!name) {
|
|
56
57
|
const { isBatch } = yield inquirer_1.default.prompt({
|
|
@@ -65,7 +66,7 @@ let CreateTrigger = class CreateTrigger extends common_1.Command {
|
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
if (isBatchCreateTrigger) {
|
|
68
|
-
return
|
|
69
|
+
return functionService.batchCreateTriggers({
|
|
69
70
|
envId,
|
|
70
71
|
functions
|
|
71
72
|
});
|
|
@@ -78,11 +79,7 @@ let CreateTrigger = class CreateTrigger extends common_1.Command {
|
|
|
78
79
|
if (!triggers || !triggers.length) {
|
|
79
80
|
throw new error_1.CloudBaseError('触发器配置不能为空');
|
|
80
81
|
}
|
|
81
|
-
yield (
|
|
82
|
-
envId,
|
|
83
|
-
functionName: name,
|
|
84
|
-
triggers
|
|
85
|
-
});
|
|
82
|
+
yield functionService.createFunctionTriggers(name, triggers);
|
|
86
83
|
(0, logger_1.successLog)(`[${name}] 创建云函数触发器成功!`);
|
|
87
84
|
});
|
|
88
85
|
}
|
|
@@ -51,6 +51,7 @@ let DeleteTrigger = class DeleteTrigger extends common_1.Command {
|
|
|
51
51
|
const { envId, config: { functions } } = ctx;
|
|
52
52
|
const name = params === null || params === void 0 ? void 0 : params[0];
|
|
53
53
|
const triggerName = params === null || params === void 0 ? void 0 : params[1];
|
|
54
|
+
const functionService = yield (0, function_1.getFunctionService)(envId);
|
|
54
55
|
let isBatchDeleteTriggers;
|
|
55
56
|
let isBatchDeleteFunctionTriggers = false;
|
|
56
57
|
if (!name) {
|
|
@@ -74,7 +75,7 @@ let DeleteTrigger = class DeleteTrigger extends common_1.Command {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
if (isBatchDeleteTriggers) {
|
|
77
|
-
return
|
|
78
|
+
return functionService.batchDeleteTriggers({
|
|
78
79
|
envId,
|
|
79
80
|
functions
|
|
80
81
|
});
|
|
@@ -93,7 +94,7 @@ let DeleteTrigger = class DeleteTrigger extends common_1.Command {
|
|
|
93
94
|
}
|
|
94
95
|
if (isBatchDeleteFunctionTriggers) {
|
|
95
96
|
const func = functions.find((item) => item.name === name);
|
|
96
|
-
return
|
|
97
|
+
return functionService.batchDeleteTriggers({
|
|
97
98
|
envId,
|
|
98
99
|
functions: [func]
|
|
99
100
|
});
|
|
@@ -101,11 +102,7 @@ let DeleteTrigger = class DeleteTrigger extends common_1.Command {
|
|
|
101
102
|
if (!triggerName) {
|
|
102
103
|
throw new error_1.CloudBaseError('触发器名称不能为空');
|
|
103
104
|
}
|
|
104
|
-
yield (
|
|
105
|
-
envId,
|
|
106
|
-
functionName: name,
|
|
107
|
-
triggerName
|
|
108
|
-
});
|
|
105
|
+
yield functionService.deleteFunctionTrigger(name, triggerName);
|
|
109
106
|
});
|
|
110
107
|
}
|
|
111
108
|
};
|
|
@@ -45,7 +45,7 @@ let PullCommand = class PullCommand extends common_1.Command {
|
|
|
45
45
|
desc: '强制清理目标输出目录(慎用)'
|
|
46
46
|
}
|
|
47
47
|
],
|
|
48
|
-
desc: '拉取项目模板\n\n支持的内置模板:\n miniprogram - 微信小程序 + CloudBase\n react - Web 应用 - React + CloudBase\n vue - Web 应用 - Vue + CloudBase\n uniapp - 跨端应用 - UniApp + CloudBase\n rules - AI 规则和配置\n\n支持的 Git 仓库:\n GitHub: https://github.com/user/repo\n Gitee: https://gitee.com/user/repo\n SSH: git@github.com:user/repo.git\n\n支持 Git 子目录:\n https://github.com/user/repo/tree/main/src/templates\n\n示例:\n tcb pull miniprogram\n tcb pull https://github.com/user/repo\n tcb pull https://
|
|
48
|
+
desc: '拉取项目模板\n\n支持的内置模板:\n miniprogram - 微信小程序 + CloudBase\n react - Web 应用 - React + CloudBase\n vue - Web 应用 - Vue + CloudBase\n uniapp - 跨端应用 - UniApp + CloudBase\n rules - AI 规则和配置\n\n支持的 Git 仓库:\n GitHub: https://github.com/user/repo\n Gitee: https://gitee.com/user/repo\n CNB: https://cnb.cool/user/repo\n SSH: git@github.com:user/repo.git\n\n支持 Git 子目录:\n https://github.com/user/repo/tree/main/src/templates\n https://cnb.cool/user/repo/tree/main/examples\n\n示例:\n tcb pull miniprogram\n tcb pull https://github.com/user/repo\n tcb pull https://cnb.cool/user/repo\n tcb pull https://cnb.cool/user/repo/tree/main/examples --output ./my-project',
|
|
49
49
|
requiredEnvId: false,
|
|
50
50
|
withoutAuth: true
|
|
51
51
|
};
|
|
@@ -84,6 +84,7 @@ let PullCommand = class PullCommand extends common_1.Command {
|
|
|
84
84
|
log.info('\n🌐 支持的 Git 仓库格式:');
|
|
85
85
|
log.info(' GitHub: https://github.com/user/repo');
|
|
86
86
|
log.info(' Gitee: https://gitee.com/user/repo');
|
|
87
|
+
log.info(' CNB: https://cnb.cool/user/repo');
|
|
87
88
|
log.info(' SSH: git@github.com:user/repo.git');
|
|
88
89
|
log.info('\n📁 支持 Git 子目录:');
|
|
89
90
|
log.info(' https://github.com/user/repo/tree/main/src/templates');
|
package/lib/utils/ai/const.js
CHANGED
|
@@ -132,6 +132,12 @@ exports.CLOUDBASE_PROVIDERS = [
|
|
|
132
132
|
models: ['deepseek-v3'],
|
|
133
133
|
transformer: 'deepseek'
|
|
134
134
|
},
|
|
135
|
+
{
|
|
136
|
+
name: 'LongCat',
|
|
137
|
+
value: 'longcat',
|
|
138
|
+
models: ['LongCat-Flash-Chat'],
|
|
139
|
+
transformer: undefined
|
|
140
|
+
},
|
|
135
141
|
];
|
|
136
142
|
function getDefaultConfig(agent) {
|
|
137
143
|
const agentConfig = exports.AGENTS.find((a) => a.value === agent);
|
|
@@ -157,7 +163,8 @@ function getAgentConfigValidator(agent) {
|
|
|
157
163
|
exports.getAgentConfigValidator = getAgentConfigValidator;
|
|
158
164
|
exports.BASE_URL_MODEL_MAPPING = {
|
|
159
165
|
'https://api.moonshot.cn/v1': 'kimi-k2-0711-preview',
|
|
160
|
-
'https://open.bigmodel.cn/api/paas/v4': 'glm-4.5'
|
|
166
|
+
'https://open.bigmodel.cn/api/paas/v4': 'glm-4.5',
|
|
167
|
+
'https://api.longcat.chat/openai': 'LongCat-Flash-Chat'
|
|
161
168
|
};
|
|
162
169
|
function getDefaultModelByBaseUrl(baseUrl) {
|
|
163
170
|
return exports.BASE_URL_MODEL_MAPPING[baseUrl] || 'gpt-4';
|
package/lib/utils/ai/setup.js
CHANGED
|
@@ -194,8 +194,8 @@ class AISetupWizard {
|
|
|
194
194
|
type: 'list',
|
|
195
195
|
name: 'agent',
|
|
196
196
|
message: `${message} ${const_1.LIST_HINT}`,
|
|
197
|
-
choices: [const_1.
|
|
198
|
-
default: const_1.
|
|
197
|
+
choices: [const_1.CODEBUDDY, const_1.CLAUDE, const_1.QWEN, const_1.CODEX, const_1.CURSOR, const_1.AIDER, ...(includeNone ? [const_1.NONE] : [])],
|
|
198
|
+
default: const_1.CODEBUDDY.value
|
|
199
199
|
}
|
|
200
200
|
]);
|
|
201
201
|
return agent;
|
|
@@ -271,6 +271,10 @@ class AISetupWizard {
|
|
|
271
271
|
name: 'DeepSeek - https://api.deepseek.com/anthropic',
|
|
272
272
|
value: 'https://api.deepseek.com/anthropic'
|
|
273
273
|
},
|
|
274
|
+
{
|
|
275
|
+
name: 'LongCat - https://api.longcat.chat/anthropic',
|
|
276
|
+
value: 'https://api.longcat.chat/anthropic'
|
|
277
|
+
},
|
|
274
278
|
{ name: '🛠️ 自定义 URL', value: 'custom' }
|
|
275
279
|
],
|
|
276
280
|
default: 'https://api.moonshot.cn/anthropic'
|
|
@@ -295,7 +299,7 @@ class AISetupWizard {
|
|
|
295
299
|
{
|
|
296
300
|
type: 'password',
|
|
297
301
|
name: 'apiKey',
|
|
298
|
-
message: '
|
|
302
|
+
message: 'Auth Token:',
|
|
299
303
|
validate: (input) => input.length > 0 || '请输入有效的 Auth Token'
|
|
300
304
|
}
|
|
301
305
|
]);
|
|
@@ -312,6 +316,9 @@ class AISetupWizard {
|
|
|
312
316
|
else if (baseUrl === 'https://api.deepseek.com/anthropic') {
|
|
313
317
|
defaultModel = 'deepseek-chat';
|
|
314
318
|
}
|
|
319
|
+
else if (baseUrl === 'https://api.longcat.chat/anthropic') {
|
|
320
|
+
defaultModel = 'LongCat-Flash-Chat';
|
|
321
|
+
}
|
|
315
322
|
else {
|
|
316
323
|
defaultModel = '';
|
|
317
324
|
}
|
|
@@ -370,7 +377,7 @@ class AISetupWizard {
|
|
|
370
377
|
{
|
|
371
378
|
type: 'password',
|
|
372
379
|
name: 'apiKey',
|
|
373
|
-
message: '
|
|
380
|
+
message: 'API Key:',
|
|
374
381
|
validate: (input) => input.length > 0 || '请输入有效的 API Key'
|
|
375
382
|
},
|
|
376
383
|
{
|
|
@@ -426,6 +433,10 @@ class AISetupWizard {
|
|
|
426
433
|
name: '智谱 - https://open.bigmodel.cn/api/paas/v4',
|
|
427
434
|
value: 'https://open.bigmodel.cn/api/paas/v4'
|
|
428
435
|
},
|
|
436
|
+
{
|
|
437
|
+
name: 'LongCat - https://api.longcat.chat/openai',
|
|
438
|
+
value: 'https://api.longcat.chat/openai'
|
|
439
|
+
},
|
|
429
440
|
{ name: '🛠️ 自定义 URL', value: 'custom' }
|
|
430
441
|
],
|
|
431
442
|
default: 'https://api.moonshot.cn/v1'
|
|
@@ -505,6 +516,10 @@ class AISetupWizard {
|
|
|
505
516
|
name: '智谱 - https://open.bigmodel.cn/api/paas/v4',
|
|
506
517
|
value: 'https://open.bigmodel.cn/api/paas/v4'
|
|
507
518
|
},
|
|
519
|
+
{
|
|
520
|
+
name: 'LongCat - https://api.longcat.chat/openai',
|
|
521
|
+
value: 'https://api.longcat.chat/openai'
|
|
522
|
+
},
|
|
508
523
|
{ name: '🛠️ 自定义 URL', value: 'custom' }
|
|
509
524
|
],
|
|
510
525
|
default: 'https://api.moonshot.cn/v1'
|
|
@@ -669,8 +684,8 @@ class AISetupWizard {
|
|
|
669
684
|
{
|
|
670
685
|
type: 'password',
|
|
671
686
|
name: 'apiKey',
|
|
672
|
-
message: '
|
|
673
|
-
validate: (input) => input.trim().length > 0 || 'API Key
|
|
687
|
+
message: 'API Key:',
|
|
688
|
+
validate: (input) => input.trim().length > 0 || '请输入有效的 API Key'
|
|
674
689
|
}
|
|
675
690
|
]);
|
|
676
691
|
yield this.aiConfigManager.updateCodebuddyConfig('custom', {
|
package/lib/utils/config.js
CHANGED
|
@@ -100,7 +100,8 @@ class TemplateManager {
|
|
|
100
100
|
if (!source || typeof source !== 'string') {
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
|
-
return source.startsWith('http') || source.startsWith('git@') ||
|
|
103
|
+
return source.startsWith('http') || source.startsWith('git@') ||
|
|
104
|
+
source.includes('github.com') || source.includes('gitee.com') || source.includes('cnb.cool');
|
|
104
105
|
}
|
|
105
106
|
parseGitUrl(url) {
|
|
106
107
|
const githubMatch = url.match(/https?:\/\/github\.com\/([^\/]+)\/([^\/]+)(?:\/tree\/([^\/]+)\/(.+))?/);
|
|
@@ -123,10 +124,23 @@ class TemplateManager {
|
|
|
123
124
|
subpath: giteeMatch[4]
|
|
124
125
|
};
|
|
125
126
|
}
|
|
127
|
+
const cnbMatch = url.match(/https?:\/\/cnb\.cool\/(.+?)(?:\/tree\/([^\/]+)\/(.+))?$/);
|
|
128
|
+
if (cnbMatch) {
|
|
129
|
+
const pathParts = cnbMatch[1].split('/').filter(p => p.length > 0);
|
|
130
|
+
if (pathParts.length >= 2) {
|
|
131
|
+
return {
|
|
132
|
+
platform: 'cnb',
|
|
133
|
+
owner: pathParts[0],
|
|
134
|
+
repo: pathParts.slice(1).join('/'),
|
|
135
|
+
branch: cnbMatch[2] || 'main',
|
|
136
|
+
subpath: cnbMatch[3]
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
126
140
|
const sshMatch = url.match(/git@([^:]+):([^\/]+)\/([^\/]+)\.git/);
|
|
127
141
|
if (sshMatch) {
|
|
128
142
|
return {
|
|
129
|
-
platform: sshMatch[1] === 'github.com' ? 'github' : 'gitee',
|
|
143
|
+
platform: sshMatch[1] === 'github.com' ? 'github' : (sshMatch[1] === 'cnb.cool' ? 'cnb' : 'gitee'),
|
|
130
144
|
owner: sshMatch[2],
|
|
131
145
|
repo: sshMatch[3],
|
|
132
146
|
branch: 'main'
|
|
@@ -141,6 +155,9 @@ class TemplateManager {
|
|
|
141
155
|
else if (gitInfo.platform === 'gitee') {
|
|
142
156
|
return `https://gitee.com/${gitInfo.owner}/${gitInfo.repo}.git`;
|
|
143
157
|
}
|
|
158
|
+
else if (gitInfo.platform === 'cnb') {
|
|
159
|
+
return `https://cnb.cool/${gitInfo.owner}/${gitInfo.repo}.git`;
|
|
160
|
+
}
|
|
144
161
|
throw new error_1.CloudBaseError(`不支持的 Git 平台: ${gitInfo.platform}`);
|
|
145
162
|
}
|
|
146
163
|
cloneWithSubpath(gitUrl, tempDir, gitInfo, log) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/cli",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.4",
|
|
4
4
|
"description": "cli tool for cloudbase",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"url": "https://github.com/TencentCloudBase/cloud-base-cli.git"
|
|
35
35
|
},
|
|
36
36
|
"bin": {
|
|
37
|
+
"ccr": "bin/ccr.js",
|
|
37
38
|
"cloudbase": "bin/cloudbase.js",
|
|
38
39
|
"cloudbase-mcp": "bin/cloudbase-mcp.cjs",
|
|
39
|
-
"tcb": "bin/tcb.js"
|
|
40
|
-
"ccr": "bin/ccr.js"
|
|
40
|
+
"tcb": "bin/tcb.js"
|
|
41
41
|
},
|
|
42
42
|
"husky": {
|
|
43
43
|
"hooks": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@cloudbase/functions-framework": "1.16.0",
|
|
54
54
|
"@cloudbase/iac-core": "0.0.3-alpha.11",
|
|
55
55
|
"@cloudbase/lowcode-cli": "^0.22.2",
|
|
56
|
-
"@cloudbase/manager-node": "4.
|
|
56
|
+
"@cloudbase/manager-node": "4.6.1",
|
|
57
57
|
"@cloudbase/toolbox": "^0.7.9",
|
|
58
58
|
"@dotenvx/dotenvx": "^1.48.3",
|
|
59
59
|
"@musistudio/claude-code-router": "1.0.36",
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# 技术方案设计
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
为 `tcb pull` 命令增加 cnb.cool 仓库的支持,使开发者能够直接从 cnb.cool 平台拉取项目模板。
|
|
6
|
+
|
|
7
|
+
## 技术架构
|
|
8
|
+
|
|
9
|
+
### 当前架构分析
|
|
10
|
+
|
|
11
|
+
`tcb pull` 命令基于 `TemplateManager` 类实现,支持:
|
|
12
|
+
- 内置模板下载(ZIP 文件)
|
|
13
|
+
- Git 仓库克隆(GitHub, Gitee, SSH)
|
|
14
|
+
|
|
15
|
+
### 新增功能架构
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
TemplateManager
|
|
19
|
+
├── isGitUrl() # 新增 cnb.cool URL 识别
|
|
20
|
+
├── parseGitUrl() # 新增 cnb.cool URL 解析
|
|
21
|
+
├── buildGitUrl() # 新增 cnb.cool Git URL 构建
|
|
22
|
+
└── downloadGitTemplateToTemp() # 复用现有 Git 下载逻辑
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 技术选型
|
|
26
|
+
|
|
27
|
+
### URL 格式识别
|
|
28
|
+
- 使用正则表达式匹配 cnb.cool URL 格式
|
|
29
|
+
- 支持 HTTP 和 HTTPS 协议
|
|
30
|
+
- 支持带分支和子目录的 URL
|
|
31
|
+
|
|
32
|
+
### URL 解析逻辑
|
|
33
|
+
- 解析格式:`https://cnb.cool/{owner}/{repo}[/tree/{branch}[/{subpath}]]`
|
|
34
|
+
- 默认分支:main(与 GitHub 保持一致)
|
|
35
|
+
- 支持子目录拉取
|
|
36
|
+
|
|
37
|
+
### Git URL 构建
|
|
38
|
+
- 构建格式:`https://cnb.cool/{owner}/{repo}.git`
|
|
39
|
+
- 复用现有的 Git 克隆逻辑
|
|
40
|
+
|
|
41
|
+
## 实现细节
|
|
42
|
+
|
|
43
|
+
### 1. 接口扩展
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
interface GitUrlInfo {
|
|
47
|
+
platform: 'github' | 'gitee' | 'git' | 'cnb' // 新增 'cnb'
|
|
48
|
+
owner: string
|
|
49
|
+
repo: string
|
|
50
|
+
branch: string
|
|
51
|
+
subpath?: string
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. URL 解析实现
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// 新增 cnb.cool URL 解析
|
|
59
|
+
const cnbMatch = url.match(/https?:\/\/cnb\.cool\/([^\/]+)\/([^\/]+)(?:\/tree\/([^\/]+)\/(.+))?/)
|
|
60
|
+
if (cnbMatch) {
|
|
61
|
+
return {
|
|
62
|
+
platform: 'cnb',
|
|
63
|
+
owner: cnbMatch[1],
|
|
64
|
+
repo: cnbMatch[2],
|
|
65
|
+
branch: cnbMatch[3] || 'main',
|
|
66
|
+
subpath: cnbMatch[4]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Git URL 构建
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
if (gitInfo.platform === 'cnb') {
|
|
75
|
+
return `https://cnb.cool/${gitInfo.owner}/${gitInfo.repo}.git`
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 安全考虑
|
|
80
|
+
|
|
81
|
+
### URL 验证
|
|
82
|
+
- 严格的正则表达式匹配,确保只识别合法的 cnb.cool URL
|
|
83
|
+
- 防止恶意 URL 注入
|
|
84
|
+
|
|
85
|
+
### 网络安全
|
|
86
|
+
- 复用现有的 Git 克隆安全机制
|
|
87
|
+
- 支持 HTTPS 协议,确保传输安全
|
|
88
|
+
|
|
89
|
+
## 兼容性
|
|
90
|
+
|
|
91
|
+
### 向后兼容
|
|
92
|
+
- 不影响现有的 GitHub/Gitee/SSH 支持
|
|
93
|
+
- 保持现有的 API 接口不变
|
|
94
|
+
|
|
95
|
+
### 前向兼容
|
|
96
|
+
- 支持 cnb.cool 的未来 URL 格式变更
|
|
97
|
+
- 预留扩展空间
|
|
98
|
+
|
|
99
|
+
## 测试策略
|
|
100
|
+
|
|
101
|
+
### 单元测试
|
|
102
|
+
- URL 解析测试(基础 URL、带分支、带子目录)
|
|
103
|
+
- URL 验证测试
|
|
104
|
+
- Git URL 构建测试
|
|
105
|
+
|
|
106
|
+
### 集成测试
|
|
107
|
+
- 实际 cnb.cool 仓库拉取测试
|
|
108
|
+
- 错误处理测试
|
|
109
|
+
|
|
110
|
+
## 部署策略
|
|
111
|
+
|
|
112
|
+
### 渐进式部署
|
|
113
|
+
1. 代码合并到主分支
|
|
114
|
+
2. 在测试环境验证功能
|
|
115
|
+
3. 生产环境灰度发布
|
|
116
|
+
4. 全量发布
|
|
117
|
+
|
|
118
|
+
### 回滚策略
|
|
119
|
+
- 代码层面:可通过条件编译回滚
|
|
120
|
+
- 配置层面:可通过配置开关控制
|
|
121
|
+
|
|
122
|
+
## 监控和运维
|
|
123
|
+
|
|
124
|
+
### 错误监控
|
|
125
|
+
- 记录 cnb.cool 拉取失败的错误信息
|
|
126
|
+
- 监控 URL 解析失败的情况
|
|
127
|
+
|
|
128
|
+
### 性能监控
|
|
129
|
+
- 监控 cnb.cool 仓库的拉取时间
|
|
130
|
+
- 监控网络请求的成功率
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 需求文档
|
|
2
|
+
|
|
3
|
+
## 介绍
|
|
4
|
+
|
|
5
|
+
为 `tcb pull` 命令增加 cnb.cool 仓库的支持,使开发者能够直接从 cnb.cool 平台拉取项目模板。
|
|
6
|
+
|
|
7
|
+
## 需求
|
|
8
|
+
|
|
9
|
+
### 需求 1 - 支持 cnb.cool URL 解析
|
|
10
|
+
|
|
11
|
+
**用户故事:** 作为开发者,我希望能够通过 `tcb pull https://cnb.cool/username/repo` 直接拉取 cnb.cool 上的项目模板。
|
|
12
|
+
|
|
13
|
+
#### 验收标准
|
|
14
|
+
|
|
15
|
+
1. When 用户输入 `tcb pull https://cnb.cool/username/repo`,the tcb pull 命令 shall 识别出这是一个 cnb.cool URL 并进行相应处理。
|
|
16
|
+
2. When 用户输入 `tcb pull https://cnb.cool/username/repo/tree/branch/path`,the tcb pull 命令 shall 支持拉取 cnb.cool 仓库的指定分支和子目录。
|
|
17
|
+
3. When 用户输入无效的 cnb.cool URL,the tcb pull 命令 shall 显示清晰的错误提示信息。
|
|
18
|
+
|
|
19
|
+
### 需求 2 - cnb.cool 仓库拉取功能
|
|
20
|
+
|
|
21
|
+
**用户故事:** 作为开发者,我希望 `tcb pull` 命令能够成功拉取 cnb.cool 上的项目模板到本地。
|
|
22
|
+
|
|
23
|
+
#### 验收标准
|
|
24
|
+
|
|
25
|
+
1. When 用户执行 `tcb pull https://cnb.cool/username/repo`,the 系统 shall 成功下载并解压 cnb.cool 上的仓库内容。
|
|
26
|
+
2. When 用户指定输出目录时,the 系统 shall 将模板内容保存到指定的目录中。
|
|
27
|
+
3. When 拉取过程中发生错误,the 系统 shall 显示详细的错误信息并提供可能的解决方案。
|
|
28
|
+
|
|
29
|
+
### 需求 3 - 命令帮助更新
|
|
30
|
+
|
|
31
|
+
**用户故事:** 作为开发者,我希望在 `tcb pull` 命令的帮助信息中看到 cnb.cool 的使用说明。
|
|
32
|
+
|
|
33
|
+
#### 验收标准
|
|
34
|
+
|
|
35
|
+
1. When 用户执行 `tcb pull --help`,the 帮助信息 shall 包含 cnb.cool 的支持说明和示例。
|
|
36
|
+
2. When 用户执行 `tcb pull list`,the 模板列表 shall 包含 cnb.cool 的支持格式说明。
|
|
37
|
+
|
|
38
|
+
## 示例
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# 拉取 cnb.cool 上的项目
|
|
42
|
+
tcb pull https://cnb.cool/tencent/cloud/cloudbase/CloudBase-AI-ToolKit
|
|
43
|
+
|
|
44
|
+
# 拉取指定分支和子目录
|
|
45
|
+
tcb pull https://cnb.cool/shuishenhuole/learning/tree/main/examples
|
|
46
|
+
|
|
47
|
+
# 指定输出目录
|
|
48
|
+
tcb pull https://cnb.cool/username/repo --output ./my-project
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# 实施计划
|
|
2
|
+
|
|
3
|
+
## 已完成任务
|
|
4
|
+
|
|
5
|
+
- [x] 1. 更新 GitUrlInfo 接口以支持 cnb 平台
|
|
6
|
+
- 在 `GitUrlInfo` 接口中添加 `'cnb'` 平台类型
|
|
7
|
+
- 确保类型定义的完整性
|
|
8
|
+
|
|
9
|
+
- [x] 2. 实现 cnb.cool URL 识别逻辑
|
|
10
|
+
- 修改 `isGitUrl()` 方法识别 cnb.cool URLs
|
|
11
|
+
- 添加对 `cnb.cool` 域名的支持
|
|
12
|
+
|
|
13
|
+
- [x] 3. 实现 cnb.cool URL 解析逻辑
|
|
14
|
+
- 修改 `parseGitUrl()` 方法解析 cnb.cool URLs
|
|
15
|
+
- 支持基础 URL 和带分支/子目录的 URL
|
|
16
|
+
- 处理 SSH URL 中的 cnb.cool 支持
|
|
17
|
+
|
|
18
|
+
- [x] 4. 实现 cnb.cool Git URL 构建
|
|
19
|
+
- 修改 `buildGitUrl()` 方法支持 cnb 平台
|
|
20
|
+
- 构建标准的 Git URL 格式
|
|
21
|
+
|
|
22
|
+
- [x] 5. 更新命令帮助信息
|
|
23
|
+
- 更新 `tcb pull` 命令的帮助描述
|
|
24
|
+
- 添加 cnb.cool 的使用示例
|
|
25
|
+
- 更新 `tcb pull list` 的输出信息
|
|
26
|
+
|
|
27
|
+
- [x] 6. 编写单元测试
|
|
28
|
+
- 创建 `template-manager-cnb.test.ts` 测试文件
|
|
29
|
+
- 覆盖 URL 解析、验证和构建的测试用例
|
|
30
|
+
- 确保测试覆盖率达到要求
|
|
31
|
+
|
|
32
|
+
- [x] 7. 验证功能完整性
|
|
33
|
+
- 运行测试验证功能正确性
|
|
34
|
+
- 检查代码编译无错误
|
|
35
|
+
- 验证帮助信息显示正确
|
|
36
|
+
|
|
37
|
+
## 验收标准
|
|
38
|
+
|
|
39
|
+
### 功能验收标准
|
|
40
|
+
1. **URL 解析功能**
|
|
41
|
+
- [x] 能够正确解析 `https://cnb.cool/user/repo` 格式
|
|
42
|
+
- [x] 能够正确解析 `https://cnb.cool/user/repo/tree/branch/path` 格式
|
|
43
|
+
- [x] 能够正确处理 HTTP 和 HTTPS 协议
|
|
44
|
+
|
|
45
|
+
2. **Git 仓库支持**
|
|
46
|
+
- [x] 能够构建正确的 cnb.cool Git URL
|
|
47
|
+
- [x] 能够复用现有的 Git 下载逻辑
|
|
48
|
+
- [x] 支持分支和子目录拉取
|
|
49
|
+
|
|
50
|
+
3. **用户界面**
|
|
51
|
+
- [x] 命令帮助信息包含 cnb.cool 支持说明
|
|
52
|
+
- [x] `tcb pull list` 显示 cnb.cool 支持格式
|
|
53
|
+
- [x] 提供清晰的使用示例
|
|
54
|
+
|
|
55
|
+
4. **测试覆盖**
|
|
56
|
+
- [x] URL 解析测试通过
|
|
57
|
+
- [x] URL 验证测试通过
|
|
58
|
+
- [x] Git URL 构建测试通过
|
|
59
|
+
- [x] 集成测试通过
|
|
60
|
+
|
|
61
|
+
### 性能验收标准
|
|
62
|
+
- [x] 代码编译无错误
|
|
63
|
+
- [x] 测试执行时间在合理范围内
|
|
64
|
+
- [x] 不影响现有功能的性能
|
|
65
|
+
|
|
66
|
+
### 兼容性验收标准
|
|
67
|
+
- [x] 不破坏现有的 GitHub/Gitee 支持
|
|
68
|
+
- [x] 保持向后兼容性
|
|
69
|
+
- [x] API 接口保持不变
|
|
70
|
+
|
|
71
|
+
## 技术债务和风险
|
|
72
|
+
|
|
73
|
+
### 已识别的技术债务
|
|
74
|
+
1. **测试覆盖率**:当前测试主要集中在 URL 解析,缺少实际 Git 克隆的集成测试
|
|
75
|
+
2. **错误处理**:cnb.cool 特有的错误场景可能需要更细致的处理
|
|
76
|
+
|
|
77
|
+
### 风险评估
|
|
78
|
+
1. **低风险**:URL 解析逻辑相对简单,测试覆盖充分
|
|
79
|
+
2. **中风险**:实际 cnb.cool 仓库的网络访问可能有未知问题
|
|
80
|
+
3. **低风险**:复用现有 Git 逻辑,减少了新代码的复杂性
|
|
81
|
+
|
|
82
|
+
## 后续优化建议
|
|
83
|
+
|
|
84
|
+
1. **集成测试增强**
|
|
85
|
+
- 添加实际 cnb.cool 仓库的拉取测试
|
|
86
|
+
- 模拟网络错误场景的测试
|
|
87
|
+
|
|
88
|
+
2. **用户体验优化**
|
|
89
|
+
- 添加 cnb.cool 特有的错误提示
|
|
90
|
+
- 支持更多的 URL 格式变体
|
|
91
|
+
|
|
92
|
+
3. **监控和运维**
|
|
93
|
+
- 添加 cnb.cool 拉取的性能监控
|
|
94
|
+
- 记录错误日志用于问题排查
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
@@ -378,6 +378,11 @@ export declare const CLOUDBASE_PROVIDERS: readonly [{
|
|
|
378
378
|
readonly value: "deepseek";
|
|
379
379
|
readonly models: readonly ["deepseek-v3"];
|
|
380
380
|
readonly transformer: "deepseek";
|
|
381
|
+
}, {
|
|
382
|
+
readonly name: "LongCat";
|
|
383
|
+
readonly value: "longcat";
|
|
384
|
+
readonly models: readonly ["LongCat-Flash-Chat"];
|
|
385
|
+
readonly transformer: any;
|
|
381
386
|
}];
|
|
382
387
|
export declare function getDefaultConfig(agent: string): unknown;
|
|
383
388
|
export declare function getAgentConfigValidator(agent: string): (x: unknown) => {
|
|
@@ -389,6 +394,7 @@ export declare function getAgentConfigValidator(agent: string): (x: unknown) =>
|
|
|
389
394
|
export declare const BASE_URL_MODEL_MAPPING: {
|
|
390
395
|
readonly 'https://api.moonshot.cn/v1': "kimi-k2-0711-preview";
|
|
391
396
|
readonly 'https://open.bigmodel.cn/api/paas/v4': "glm-4.5";
|
|
397
|
+
readonly 'https://api.longcat.chat/openai': "LongCat-Flash-Chat";
|
|
392
398
|
};
|
|
393
399
|
export declare function getDefaultModelByBaseUrl(baseUrl: string): string;
|
|
394
400
|
export declare function getBooleanHint(defaultValue?: boolean): string;
|