@gmcb/cli 0.3.3 → 0.4.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/CHANGELOG.md +50 -41
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/lib/actions/build.js +6 -1
- package/lib/actions/config.d.ts +8 -0
- package/lib/actions/config.js +6 -0
- package/lib/actions/create.js +94 -38
- package/lib/actions/skill.d.ts +2 -0
- package/lib/actions/skill.js +220 -0
- package/lib/bin.js +12 -0
- package/lib/commands/option.d.ts +4 -0
- package/lib/commands/option.js +3 -1
- package/lib/utils/const.d.ts +2 -0
- package/lib/utils/const.js +3 -1
- package/package.json +2 -2
- package/schema.json +337 -337
package/CHANGELOG.md
CHANGED
|
@@ -1,43 +1,52 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
-
|
|
6
|
-
## [0.3.
|
|
7
|
-
|
|
8
|
-
**Note:** Version bump only for package @gmcb/cli
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [0.3.4](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.3.3...@gmcb/cli@0.3.4) (2026-04-30)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @gmcb/cli
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## [0.3.3](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.3.2...@gmcb/cli@0.3.3) (2026-04-24)
|
|
16
|
+
|
|
17
|
+
**Note:** Version bump only for package @gmcb/cli
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## [0.3.2](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.3.1...@gmcb/cli@0.3.2) (2026-04-22)
|
|
24
|
+
|
|
25
|
+
**Note:** Version bump only for package @gmcb/cli
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## [0.3.1](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.3.0...@gmcb/cli@0.3.1) (2026-04-22)
|
|
32
|
+
|
|
33
|
+
**Note:** Version bump only for package @gmcb/cli
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# [0.3.0](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.2.4...@gmcb/cli@0.3.0) (2026-04-22)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Features
|
|
43
|
+
|
|
44
|
+
* 优化使用体验 ([c82d28b](http://10.10.10.16/caoben/front-end/commits/c82d28ba920f857e5edc4865a7a88030b32230c1))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
41
50
|
|
|
42
51
|
## [0.2.4](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.2.3...@gmcb/cli@0.2.4) (2025-11-13)
|
|
43
52
|
|
|
@@ -279,4 +288,4 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|
|
279
288
|
|
|
280
289
|
## [0.0.1](http://10.10.200.92:8090/gmcb/front-end/compare/@gmcb/cli@0.1.0-alpha.0...@gmcb/cli@0.0.1) (2025-02-02)
|
|
281
290
|
|
|
282
|
-
**Note:** Version bump only for package @gmcb/cli
|
|
291
|
+
**Note:** Version bump only for package @gmcb/cli
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 aniu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -9,6 +9,36 @@ npm i @gmcb/cli -g
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## 使用
|
|
12
|
+
|
|
13
|
+
### 构建
|
|
14
|
+
|
|
12
15
|
```
|
|
13
16
|
gmcb build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 技能管理
|
|
20
|
+
|
|
21
|
+
从远程仓库同步技能到本地项目:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
gmcb skill sync
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
可选参数:
|
|
28
|
+
- `--skill.repo <repo-url>` - 指定技能仓库 Git 地址,覆盖默认配置
|
|
29
|
+
|
|
30
|
+
列出当前项目所有技能:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
gmcb skill list
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
技能仓库地址可在 `uni.build.json` 中配置:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"skill": {
|
|
41
|
+
"repo": "http://10.10.10.16/caoben/skill.git"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
14
44
|
```
|
package/lib/actions/build.js
CHANGED
|
@@ -152,7 +152,12 @@ async function getCommands(...args) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
else if (opts.compiler === 'electron-vite') {
|
|
155
|
-
commands = [
|
|
155
|
+
commands = [
|
|
156
|
+
...commands,
|
|
157
|
+
bin,
|
|
158
|
+
'build',
|
|
159
|
+
`&& cross-env CHANNEL=${String(buildEnv).startsWith('pro') ? '' : `-${buildEnv}`}`,
|
|
160
|
+
];
|
|
156
161
|
if (opts.zip) {
|
|
157
162
|
commands.push('electron-builder --dir');
|
|
158
163
|
}
|
package/lib/actions/config.d.ts
CHANGED
|
@@ -42,6 +42,12 @@ interface Mp {
|
|
|
42
42
|
privatekey?: string;
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
+
interface Skill {
|
|
46
|
+
repo?: string;
|
|
47
|
+
}
|
|
48
|
+
interface Template {
|
|
49
|
+
repo?: string;
|
|
50
|
+
}
|
|
45
51
|
interface Publish {
|
|
46
52
|
brand: string;
|
|
47
53
|
type: string;
|
|
@@ -56,6 +62,8 @@ export interface BaseConfig {
|
|
|
56
62
|
branch?: string | boolean;
|
|
57
63
|
cos?: Cos;
|
|
58
64
|
cli?: Cli;
|
|
65
|
+
skill?: Skill;
|
|
66
|
+
template?: Template;
|
|
59
67
|
}
|
|
60
68
|
export interface Config extends BaseConfig {
|
|
61
69
|
env?: string;
|
package/lib/actions/config.js
CHANGED
|
@@ -24,6 +24,12 @@ function getConfig() {
|
|
|
24
24
|
cli: {
|
|
25
25
|
hbuilderx,
|
|
26
26
|
},
|
|
27
|
+
skill: {
|
|
28
|
+
repo: utils_1.DEFAULT_SKILL_REPO,
|
|
29
|
+
},
|
|
30
|
+
template: {
|
|
31
|
+
repo: utils_1.DEFAULT_TEMPLATE_REPO,
|
|
32
|
+
},
|
|
27
33
|
}, { spaces: 2 });
|
|
28
34
|
}
|
|
29
35
|
return (0, fs_extra_1.readJsonSync)(utils_1.CONFIG_PATH, { throws: false }) || {};
|
package/lib/actions/create.js
CHANGED
|
@@ -1,66 +1,122 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.default = default_1;
|
|
7
30
|
const path_1 = require("path");
|
|
31
|
+
const fs_1 = require("fs");
|
|
8
32
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
-
const
|
|
33
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
10
34
|
const ora_1 = __importDefault(require("ora"));
|
|
11
35
|
const chalk_1 = __importDefault(require("chalk"));
|
|
36
|
+
const fsExtra = __importStar(require("fs-extra"));
|
|
37
|
+
const os_1 = __importDefault(require("os"));
|
|
12
38
|
const utils_1 = require("../utils");
|
|
13
|
-
|
|
14
|
-
if (!/https?:/.test(name)) {
|
|
15
|
-
name = `https://git.keeprisk.cn/${name}`;
|
|
16
|
-
}
|
|
17
|
-
const [url, branch = 'master'] = name.split('#');
|
|
18
|
-
const array = url.replace(/\/+$/, '').split('/');
|
|
19
|
-
const repoName = array.pop();
|
|
20
|
-
return (0, download_1.default)(`${url}/-/archive/${branch}/${repoName}-${branch}.zip`, dest, { extract: true, strip: 1 });
|
|
21
|
-
}
|
|
39
|
+
const config_1 = require("./config");
|
|
22
40
|
async function default_1(...args) {
|
|
23
41
|
const name = args[0];
|
|
24
|
-
const opts = args[
|
|
42
|
+
const opts = args[1];
|
|
25
43
|
const dest = (0, path_1.join)(utils_1.COMMAND_PATH, name);
|
|
44
|
+
const config = (0, config_1.getMergeConfig)();
|
|
45
|
+
const repoUrl = opts['template.repo'] || config.template?.repo || utils_1.DEFAULT_TEMPLATE_REPO;
|
|
46
|
+
const tempDir = (0, path_1.join)(os_1.default.tmpdir(), `gmcb-template-${Date.now()}`);
|
|
47
|
+
const spinner = (0, ora_1.default)('正在克隆模板仓库...');
|
|
48
|
+
try {
|
|
49
|
+
spinner.start();
|
|
50
|
+
await (0, simple_git_1.default)().clone(repoUrl, tempDir, ['--depth', '1']);
|
|
51
|
+
spinner.succeed('模板仓库克隆完成');
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
spinner.fail('克隆模板仓库失败:' + e.message);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const packagesDir = (0, path_1.join)(tempDir, 'packages');
|
|
58
|
+
if (!(0, fs_1.existsSync)(packagesDir)) {
|
|
59
|
+
utils_1.log.error('模板仓库中未发现 packages 目录');
|
|
60
|
+
await fsExtra.remove(tempDir);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const templates = (0, fs_1.readdirSync)(packagesDir).filter((item) => {
|
|
64
|
+
return (0, fs_1.existsSync)((0, path_1.join)(packagesDir, item));
|
|
65
|
+
});
|
|
66
|
+
if (templates.length === 0) {
|
|
67
|
+
utils_1.log.error('模板仓库 packages 目录为空,未发现任何模板');
|
|
68
|
+
await fsExtra.remove(tempDir);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
26
71
|
let { template } = opts;
|
|
27
72
|
if (!template) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
],
|
|
44
|
-
},
|
|
45
|
-
]);
|
|
46
|
-
template += res.template;
|
|
73
|
+
if (templates.length === 1) {
|
|
74
|
+
template = templates[0];
|
|
75
|
+
console.log(chalk_1.default.cyan(`使用模板: ${template}`));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const ans = await inquirer_1.default.prompt([
|
|
79
|
+
{
|
|
80
|
+
type: 'list',
|
|
81
|
+
name: 'template',
|
|
82
|
+
message: '请选择模板类型',
|
|
83
|
+
choices: templates.map((t) => ({ name: t, value: t })),
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
template = ans.template;
|
|
87
|
+
}
|
|
47
88
|
}
|
|
48
|
-
|
|
89
|
+
else {
|
|
90
|
+
if (!templates.includes(template)) {
|
|
91
|
+
utils_1.log.error(`模板 "${template}" 不存在,可用模板:${templates.join(', ')}`);
|
|
92
|
+
await fsExtra.remove(tempDir);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const templatePath = (0, path_1.join)(packagesDir, template);
|
|
97
|
+
const copySpinner = (0, ora_1.default)('正在创建项目...');
|
|
49
98
|
try {
|
|
50
|
-
|
|
51
|
-
await
|
|
52
|
-
|
|
99
|
+
copySpinner.start();
|
|
100
|
+
await fsExtra.copy(templatePath, dest);
|
|
101
|
+
const pkgPath = (0, path_1.join)(dest, 'package.json');
|
|
102
|
+
if ((0, fs_1.existsSync)(pkgPath)) {
|
|
103
|
+
const pkg = await fsExtra.readJson(pkgPath);
|
|
104
|
+
pkg.name = name;
|
|
105
|
+
await fsExtra.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
106
|
+
}
|
|
107
|
+
copySpinner.succeed('项目创建完成,请执行以下命令:');
|
|
53
108
|
const rela = (0, path_1.relative)(utils_1.COMMAND_PATH, dest);
|
|
54
109
|
if (rela) {
|
|
55
110
|
console.log(chalk_1.default.blueBright(`$ cd ${rela}`));
|
|
56
111
|
}
|
|
57
|
-
console.log(chalk_1.default.blueBright('$
|
|
58
|
-
console.log(chalk_1.default.blueBright('$ npm
|
|
112
|
+
console.log(chalk_1.default.blueBright('$ gmcb skill sync'));
|
|
113
|
+
console.log(chalk_1.default.blueBright('$ npm install'));
|
|
59
114
|
}
|
|
60
115
|
catch (e) {
|
|
61
|
-
|
|
116
|
+
copySpinner.fail('项目创建失败:' + e.message);
|
|
62
117
|
}
|
|
63
118
|
finally {
|
|
64
|
-
|
|
119
|
+
await fsExtra.remove(tempDir);
|
|
120
|
+
copySpinner.stop();
|
|
65
121
|
}
|
|
66
122
|
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.syncSkill = syncSkill;
|
|
30
|
+
exports.listSkill = listSkill;
|
|
31
|
+
const path_1 = require("path");
|
|
32
|
+
const fs_1 = require("fs");
|
|
33
|
+
const fs_2 = require("fs");
|
|
34
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
35
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
36
|
+
const ora_1 = __importDefault(require("ora"));
|
|
37
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
38
|
+
const fsExtra = __importStar(require("fs-extra"));
|
|
39
|
+
const os_1 = __importDefault(require("os"));
|
|
40
|
+
const config_1 = require("./config");
|
|
41
|
+
const utils_1 = require("../utils");
|
|
42
|
+
const ENV_MAP = {
|
|
43
|
+
default: ".agents",
|
|
44
|
+
opencode: ".opencode",
|
|
45
|
+
claude: ".claude",
|
|
46
|
+
codex: ".codex",
|
|
47
|
+
qoder: ".qoder",
|
|
48
|
+
};
|
|
49
|
+
function parseFrontmatter(content) {
|
|
50
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
51
|
+
if (!match)
|
|
52
|
+
return {};
|
|
53
|
+
const frontmatter = match[1];
|
|
54
|
+
const result = {};
|
|
55
|
+
frontmatter.split("\n").forEach((line) => {
|
|
56
|
+
const colonIndex = line.indexOf(":");
|
|
57
|
+
if (colonIndex !== -1) {
|
|
58
|
+
const key = line.substring(0, colonIndex).trim();
|
|
59
|
+
const value = line.substring(colonIndex + 1).trim();
|
|
60
|
+
result[key] = value;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return { name: result.name, description: result.description };
|
|
64
|
+
}
|
|
65
|
+
function getExistingEnvs() {
|
|
66
|
+
const result = [];
|
|
67
|
+
Object.keys(ENV_MAP).forEach((env) => {
|
|
68
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(utils_1.COMMAND_PATH, ENV_MAP[env]))) {
|
|
69
|
+
result.push(env);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function scanLocalSkills(envDir) {
|
|
75
|
+
const skillsPath = (0, path_1.join)(envDir, "skills");
|
|
76
|
+
if (!(0, fs_1.existsSync)(skillsPath))
|
|
77
|
+
return [];
|
|
78
|
+
return (0, fs_1.readdirSync)(skillsPath).filter((name) => {
|
|
79
|
+
const skillMd = (0, path_1.join)(skillsPath, name, "SKILL.md");
|
|
80
|
+
return (0, fs_1.existsSync)(skillMd);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function scanRemoteSkills(repoDir) {
|
|
84
|
+
const skills = [];
|
|
85
|
+
const skillsDir = (0, fs_1.existsSync)((0, path_1.join)(repoDir, "skills")) ? (0, path_1.join)(repoDir, "skills") : repoDir;
|
|
86
|
+
const items = (0, fs_1.readdirSync)(skillsDir);
|
|
87
|
+
items.forEach((item) => {
|
|
88
|
+
const itemPath = (0, path_1.join)(skillsDir, item);
|
|
89
|
+
const skillMd = (0, path_1.join)(itemPath, "SKILL.md");
|
|
90
|
+
if ((0, fs_1.existsSync)(skillMd)) {
|
|
91
|
+
const content = (0, fs_2.readFileSync)(skillMd, "utf-8");
|
|
92
|
+
const { name, description } = parseFrontmatter(content);
|
|
93
|
+
skills.push({
|
|
94
|
+
name: name || item,
|
|
95
|
+
description: description || "",
|
|
96
|
+
path: itemPath,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return skills;
|
|
101
|
+
}
|
|
102
|
+
async function syncSkill(...args) {
|
|
103
|
+
const opts = args[0];
|
|
104
|
+
const config = (0, config_1.getMergeConfig)();
|
|
105
|
+
const repoUrl = opts["skill.repo"] || config.skill?.repo || utils_1.DEFAULT_SKILL_REPO;
|
|
106
|
+
const tempDir = (0, path_1.join)(os_1.default.tmpdir(), `gmcb-skill-${Date.now()}`);
|
|
107
|
+
const spinner = (0, ora_1.default)("正在克隆技能仓库...");
|
|
108
|
+
try {
|
|
109
|
+
spinner.start();
|
|
110
|
+
await (0, simple_git_1.default)().clone(repoUrl, tempDir);
|
|
111
|
+
spinner.succeed("技能仓库克隆完成");
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
spinner.fail("克隆技能仓库失败:" + e.message);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const remoteSkills = scanRemoteSkills(tempDir);
|
|
118
|
+
if (remoteSkills.length === 0) {
|
|
119
|
+
utils_1.log.warning("远程仓库中未发现任何技能");
|
|
120
|
+
await fsExtra.remove(tempDir);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const existingEnvs = getExistingEnvs();
|
|
124
|
+
let selectedEnv;
|
|
125
|
+
if (existingEnvs.length === 1) {
|
|
126
|
+
selectedEnv = existingEnvs[0];
|
|
127
|
+
console.log(chalk_1.default.cyan(`使用已有环境: ${selectedEnv}`));
|
|
128
|
+
}
|
|
129
|
+
else if (existingEnvs.length === 0) {
|
|
130
|
+
const envChoices = Object.keys(ENV_MAP).map((env) => ({
|
|
131
|
+
name: env,
|
|
132
|
+
value: env,
|
|
133
|
+
}));
|
|
134
|
+
const ans = await inquirer_1.default.prompt([
|
|
135
|
+
{
|
|
136
|
+
type: "list",
|
|
137
|
+
name: "env",
|
|
138
|
+
message: "请选择目标环境",
|
|
139
|
+
choices: envChoices,
|
|
140
|
+
default: "default",
|
|
141
|
+
},
|
|
142
|
+
]);
|
|
143
|
+
selectedEnv = ans.env;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const envChoices = existingEnvs.map((env) => ({
|
|
147
|
+
name: env,
|
|
148
|
+
value: env,
|
|
149
|
+
}));
|
|
150
|
+
const ans = await inquirer_1.default.prompt([
|
|
151
|
+
{
|
|
152
|
+
type: "list",
|
|
153
|
+
name: "env",
|
|
154
|
+
message: "检测到多个环境,请选择",
|
|
155
|
+
choices: envChoices,
|
|
156
|
+
default: existingEnvs[0],
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
selectedEnv = ans.env;
|
|
160
|
+
}
|
|
161
|
+
const targetEnvDir = (0, path_1.join)(utils_1.COMMAND_PATH, ENV_MAP[selectedEnv]);
|
|
162
|
+
const localSkills = scanLocalSkills(targetEnvDir);
|
|
163
|
+
const skillChoices = remoteSkills.map((skill) => ({
|
|
164
|
+
name: `${skill.name} ${skill.description ? `- ${skill.description}` : ""}`,
|
|
165
|
+
value: skill.name,
|
|
166
|
+
checked: localSkills.includes(skill.name),
|
|
167
|
+
}));
|
|
168
|
+
const { selectedSkills } = await inquirer_1.default.prompt([
|
|
169
|
+
{
|
|
170
|
+
type: "checkbox",
|
|
171
|
+
name: "selectedSkills",
|
|
172
|
+
message: "请选择要同步的技能",
|
|
173
|
+
choices: skillChoices,
|
|
174
|
+
},
|
|
175
|
+
]);
|
|
176
|
+
if (selectedSkills.length === 0) {
|
|
177
|
+
utils_1.log.warning("未选择任何技能");
|
|
178
|
+
await fsExtra.remove(tempDir);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const skillsDir = (0, path_1.join)(targetEnvDir, "skills");
|
|
182
|
+
await fsExtra.ensureDir(skillsDir);
|
|
183
|
+
let count = 0;
|
|
184
|
+
for (const skillName of selectedSkills) {
|
|
185
|
+
const remoteSkill = remoteSkills.find((s) => s.name === skillName);
|
|
186
|
+
if (remoteSkill) {
|
|
187
|
+
const destPath = (0, path_1.join)(skillsDir, skillName);
|
|
188
|
+
await fsExtra.copy(remoteSkill.path, destPath, { overwrite: true });
|
|
189
|
+
count++;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
await fsExtra.remove(tempDir);
|
|
193
|
+
utils_1.log.success(`成功同步 ${count} 个技能到 ${ENV_MAP[selectedEnv]} 目录`);
|
|
194
|
+
}
|
|
195
|
+
async function listSkill() {
|
|
196
|
+
let hasSkills = false;
|
|
197
|
+
Object.keys(ENV_MAP).forEach((env) => {
|
|
198
|
+
const envDir = (0, path_1.join)(utils_1.COMMAND_PATH, ENV_MAP[env]);
|
|
199
|
+
const skillsPath = (0, path_1.join)(envDir, "skills");
|
|
200
|
+
if (!(0, fs_1.existsSync)(skillsPath))
|
|
201
|
+
return;
|
|
202
|
+
const skills = (0, fs_1.readdirSync)(skillsPath).filter((name) => {
|
|
203
|
+
return (0, fs_1.existsSync)((0, path_1.join)(skillsPath, name, "SKILL.md"));
|
|
204
|
+
});
|
|
205
|
+
if (skills.length === 0)
|
|
206
|
+
return;
|
|
207
|
+
hasSkills = true;
|
|
208
|
+
console.log(chalk_1.default.cyan(`\n${env} (${ENV_MAP[env]}/skills):`));
|
|
209
|
+
skills.forEach((skillName) => {
|
|
210
|
+
const skillMd = (0, path_1.join)(skillsPath, skillName, "SKILL.md");
|
|
211
|
+
const content = (0, fs_2.readFileSync)(skillMd, "utf-8");
|
|
212
|
+
const { description } = parseFrontmatter(content);
|
|
213
|
+
const desc = description ? ` - ${description}` : "";
|
|
214
|
+
console.log(` ${chalk_1.default.green("●")} ${skillName}${desc}`);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
if (!hasSkills) {
|
|
218
|
+
utils_1.log.warning("当前项目未安装任何技能");
|
|
219
|
+
}
|
|
220
|
+
}
|
package/lib/bin.js
CHANGED
|
@@ -12,6 +12,7 @@ const build_1 = __importDefault(require("./actions/build"));
|
|
|
12
12
|
const publish_1 = __importDefault(require("./actions/publish"));
|
|
13
13
|
const config_1 = __importDefault(require("./actions/config"));
|
|
14
14
|
const copy_1 = __importDefault(require("./actions/copy"));
|
|
15
|
+
const skill_1 = require("./actions/skill");
|
|
15
16
|
const commands_1 = require("./commands");
|
|
16
17
|
const utils_1 = require("./utils");
|
|
17
18
|
const program = new commander_1.default.Command();
|
|
@@ -23,6 +24,7 @@ program
|
|
|
23
24
|
.command('create <project-name>')
|
|
24
25
|
.description('创建项目框架')
|
|
25
26
|
.option(...commands_1.template)
|
|
27
|
+
.option(...commands_1.templateRepo)
|
|
26
28
|
.action(create_1.default);
|
|
27
29
|
program
|
|
28
30
|
.command('dev')
|
|
@@ -82,4 +84,14 @@ program
|
|
|
82
84
|
.option(...commands_1.cosSecretkey)
|
|
83
85
|
.option(...commands_1.branch)
|
|
84
86
|
.action(config_1.default);
|
|
87
|
+
const skillCmd = program.command('skill').description('技能管理');
|
|
88
|
+
skillCmd
|
|
89
|
+
.command('sync')
|
|
90
|
+
.description('从远程仓库同步技能到本地项目')
|
|
91
|
+
.option(...commands_1.skillRepo)
|
|
92
|
+
.action(skill_1.syncSkill);
|
|
93
|
+
skillCmd
|
|
94
|
+
.command('list')
|
|
95
|
+
.description('列出当前项目所有技能')
|
|
96
|
+
.action(skill_1.listSkill);
|
|
85
97
|
program.parse();
|
package/lib/commands/option.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare const weixinCli: readonly ["--cli.weixin <cli-path>", "微信开
|
|
|
25
25
|
export declare const alipayCli: readonly ["--cli.alipay <cli-path>", "支付宝开发者工具 Cli路径"];
|
|
26
26
|
export declare const cosSecretid: readonly ["--cos.secretid <secretid>", "设置腾讯云上传秘钥ID"];
|
|
27
27
|
export declare const cosSecretkey: readonly ["--cos.secretkey <secretkey>", "设置腾讯云上传秘钥KEY"];
|
|
28
|
+
export declare const skillRepo: readonly ["--skill.repo <repo-url>", "技能仓库 Git 地址"];
|
|
29
|
+
export declare const templateRepo: readonly ["--template.repo <repo-url>", "项目模板仓库 Git 地址"];
|
|
28
30
|
export interface Options {
|
|
29
31
|
template?: string;
|
|
30
32
|
branch?: string | boolean;
|
|
@@ -46,4 +48,6 @@ export interface Options {
|
|
|
46
48
|
win: boolean;
|
|
47
49
|
mac: boolean;
|
|
48
50
|
linux: boolean;
|
|
51
|
+
'skill.repo'?: string;
|
|
52
|
+
'template.repo'?: string;
|
|
49
53
|
}
|
package/lib/commands/option.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cosSecretkey = exports.cosSecretid = exports.alipayCli = exports.weixinCli = exports.hbuilderxCli = exports.res = exports.wgt = exports.custom = exports.zip = exports.linux = exports.mac = exports.win = exports.link = exports.path = exports.name = exports.clean = exports.ignore = exports.dest = exports.source = exports.branch = exports.env = exports.compiler = exports.project = exports.platform = exports.template = exports.version = void 0;
|
|
3
|
+
exports.templateRepo = exports.skillRepo = exports.cosSecretkey = exports.cosSecretid = exports.alipayCli = exports.weixinCli = exports.hbuilderxCli = exports.res = exports.wgt = exports.custom = exports.zip = exports.linux = exports.mac = exports.win = exports.link = exports.path = exports.name = exports.clean = exports.ignore = exports.dest = exports.source = exports.branch = exports.env = exports.compiler = exports.project = exports.platform = exports.template = exports.version = void 0;
|
|
4
4
|
exports.version = ['-v, --version', '输出版本号'];
|
|
5
5
|
exports.template = ['-t, --template <template-name>', '模版仓库名称'];
|
|
6
6
|
exports.platform = ['-p, --platform <platform-name>', '编译平台,默认h5', 'h5'];
|
|
@@ -27,3 +27,5 @@ exports.weixinCli = ['--cli.weixin <cli-path>', '微信开发者工具 Cli路径
|
|
|
27
27
|
exports.alipayCli = ['--cli.alipay <cli-path>', '支付宝开发者工具 Cli路径'];
|
|
28
28
|
exports.cosSecretid = ['--cos.secretid <secretid>', '设置腾讯云上传秘钥ID'];
|
|
29
29
|
exports.cosSecretkey = ['--cos.secretkey <secretkey>', '设置腾讯云上传秘钥KEY'];
|
|
30
|
+
exports.skillRepo = ['--skill.repo <repo-url>', '技能仓库 Git 地址'];
|
|
31
|
+
exports.templateRepo = ['--template.repo <repo-url>', '项目模板仓库 Git 地址'];
|
package/lib/utils/const.d.ts
CHANGED
|
@@ -15,3 +15,5 @@ export declare const MAINFEST_PATH: string;
|
|
|
15
15
|
export { HOME_PATH };
|
|
16
16
|
export declare const PLATFORM_OPTIONS: readonly ["h5", "mp-alipay", "mp-baidu", "mp-jd", "mp-kuaishou", "mp-qq", "mp-toutiao", "mp-weixin", "app", "app-ios", "app-android", "app-harmony", "windows", "macos", "linux"];
|
|
17
17
|
export declare const COMPILER_OPTIONS: readonly ["vite", "uni", "electron-vite"];
|
|
18
|
+
export declare const DEFAULT_SKILL_REPO = "http://10.10.10.16/caoben/project-template.git";
|
|
19
|
+
export declare const DEFAULT_TEMPLATE_REPO = "http://10.10.10.16/caoben/project-template.git";
|