@gmcb/cli 0.6.3 → 0.7.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 CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.7.0](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.5.5...@gmcb/cli@0.7.0) (2026-07-06)
7
+
8
+
9
+ ### Features
10
+
11
+ * 优化cli ([676ac43](http://10.10.10.16/caoben/front-end/commits/676ac4381ca645ef232936b86e3b77124337a03c))
12
+
13
+
14
+
15
+
16
+
17
+ ## [0.6.4](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.5.5...@gmcb/cli@0.6.4) (2026-07-06)
18
+
19
+
20
+ ### Features
21
+
22
+ * 优化cli ([676ac43](http://10.10.10.16/caoben/front-end/commits/676ac4381ca645ef232936b86e3b77124337a03c))
23
+
24
+
25
+
26
+
27
+
6
28
  ## [0.6.3](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.5.5...@gmcb/cli@0.6.3) (2026-07-06)
7
29
 
8
30
 
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
@@ -33,6 +33,7 @@ npm i @gmcb/cli -g
33
33
  | `-e, --env` | 构建环境,默认 prod |
34
34
  | `--wgt` | 构建移动应用热更新资源 |
35
35
  | `--zip` | 构建桌面应用热更新资源 |
36
+ | `--apk` | 构建 Android 应用 |
36
37
 
37
38
  使用 `--wgt` 构建移动应用热更新资源时,会先通过 vite/uni 正常构建 app,再将构建产物(`dist/build/app` 或 `unpackage/dist/build/app-plus`)打包为 `.wgt` 文件,输出路径默认为 `unpackage/release`。
38
39
 
@@ -69,6 +70,7 @@ gmcb build -p app --wgt
69
70
  | `--wgt` | 构建移动应用热更新资源 |
70
71
  | `--res` | 构建移动应用本地资源 |
71
72
  | `--zip` | 构建桌面应用热更新资源 |
73
+ | `--apk` | 构建 Android 应用 |
72
74
  | `-a, --auto` | 自动发布,跳过所有确认提示 |
73
75
 
74
76
  示例:
@@ -186,7 +186,7 @@ async function getCommands(...args) {
186
186
  }
187
187
  }
188
188
  else if (opts.compiler === 'gradlew') {
189
- commands = ['gradlew assembleRelease'];
189
+ commands = [...commands, 'gradlew assembleRelease'];
190
190
  }
191
191
  else {
192
192
  commands = [...commands, bin, 'build'];
@@ -272,7 +272,7 @@ async function fetchRemoteResources(opts) {
272
272
  const pkg = (0, fs_extra_1.readJsonSync)(utils_1.PACKAGE_PATH);
273
273
  const appId = pkg.appId;
274
274
  const result = await (0, apis_1.fetchRemoteVersionInfo)(appId);
275
- const { appName, iconUrl } = result;
275
+ const { appName, iconUrl, versionName, versionNum } = result;
276
276
  if (opts.win) {
277
277
  // Windows
278
278
  const zipUrl = result.resourcePackageUrl;
@@ -288,14 +288,11 @@ async function fetchRemoteResources(opts) {
288
288
  const zip = new adm_zip_1.default(tmpZip);
289
289
  zip.extractAllTo(rendererDir, true);
290
290
  (0, fs_extra_1.removeSync)(tmpZip);
291
- // 从目标目录读取 manifest
292
- const manifest = (0, fs_extra_1.readJsonSync)((0, path_1.join)(rendererDir, appId, 'manifest.json'));
293
- const { versionName, versionCode } = manifest;
294
291
  // 替换 package.json
295
292
  const pkgPath = (0, path_1.join)(utils_1.COMMAND_PATH, 'package.json');
296
293
  let pkgContent = (0, fs_1.readFileSync)(pkgPath, 'utf-8');
297
294
  pkgContent = pkgContent.replace(/"version":\s*"[^"]*"/, `"version": "${versionName}"`);
298
- pkgContent = pkgContent.replace(/"versionCode":\s*\d+/, `"versionCode": ${versionCode}`);
295
+ pkgContent = pkgContent.replace(/"versionCode":\s*\d+/, `"versionCode": ${versionNum}`);
299
296
  pkgContent = pkgContent.replace(/"productName":\s*"[^"]*"/, `"productName": "${appName}"`);
300
297
  (0, fs_1.writeFileSync)(pkgPath, pkgContent);
301
298
  // 下载图标
@@ -306,6 +303,9 @@ async function fetchRemoteResources(opts) {
306
303
  await (0, utils_1.png2ico)(iconPath, (0, path_1.join)(utils_1.COMMAND_PATH, 'res', 'icon.ico'));
307
304
  }
308
305
  spinner.succeed(`Windows本地资源已更新`);
306
+ if (!config_1.CONFIG_DATA.publish)
307
+ config_1.CONFIG_DATA.publish = {};
308
+ config_1.CONFIG_DATA.publish['_remoteResourceUrl'] = zipUrl;
309
309
  }
310
310
  else if (opts.compiler === 'gradlew') {
311
311
  // Android
@@ -325,7 +325,7 @@ async function fetchRemoteResources(opts) {
325
325
  (0, fs_extra_1.removeSync)(tmpWgt);
326
326
  // 从目标目录读取 manifest
327
327
  const manifest = (0, fs_extra_1.readJsonSync)((0, path_1.join)(tempDir, 'manifest.json'));
328
- const { version, id } = manifest;
328
+ const { id } = manifest;
329
329
  const assetsDir = (0, path_1.join)(appDir, id, 'www');
330
330
  // 将解压内容复制到 assetsDir,然后删除临时目录
331
331
  (0, fs_extra_1.ensureDirSync)(assetsDir);
@@ -334,8 +334,8 @@ async function fetchRemoteResources(opts) {
334
334
  // 替换 build.gradle
335
335
  const gradlePath = (0, path_1.join)(utils_1.COMMAND_PATH, 'app', 'build.gradle');
336
336
  let gradleContent = (0, fs_1.readFileSync)(gradlePath, 'utf-8');
337
- gradleContent = gradleContent.replace(/versionCode\s+\d+/, `versionCode ${version.code}`);
338
- gradleContent = gradleContent.replace(/versionName\s+"[^"]*"/, `versionName "${version.name}"`);
337
+ gradleContent = gradleContent.replace(/versionName\s+"[^"]*"/, `versionName "${versionName}"`);
338
+ gradleContent = gradleContent.replace(/versionCode\s+\d+/, `versionCode ${versionNum}`);
339
339
  (0, fs_1.writeFileSync)(gradlePath, gradleContent);
340
340
  // 替换 strings.xml
341
341
  const stringsPath = (0, path_1.join)(utils_1.COMMAND_PATH, 'app', 'src', 'main', 'res', 'values', 'strings.xml');
@@ -351,6 +351,9 @@ async function fetchRemoteResources(opts) {
351
351
  (0, fs_1.copyFileSync)(iconPath, (0, path_1.join)(drawableDir, 'push.png'));
352
352
  }
353
353
  spinner.succeed(`Android本地资源已更新`);
354
+ if (!config_1.CONFIG_DATA.publish)
355
+ config_1.CONFIG_DATA.publish = {};
356
+ config_1.CONFIG_DATA.publish['_remoteResourceUrl'] = wgtUrl;
354
357
  }
355
358
  }
356
359
  async function default_1(...args) {
@@ -377,7 +380,7 @@ async function default_1(...args) {
377
380
  if ((opts.compiler === 'electron-vite' && (opts.zip || opts.win)) ||
378
381
  (opts.compiler === 'uni' && opts.platform === 'h5' && opts.zip) ||
379
382
  (opts.compiler === 'uni' && opts.platform?.startsWith('app') && opts.wgt && !opts.pack) ||
380
- opts.compiler === 'gradlew' && opts.platform === 'app') {
383
+ opts.compiler === 'gradlew' && opts.apk) {
381
384
  await generatePackage(opts);
382
385
  }
383
386
  return commands;
@@ -12,7 +12,7 @@ async function default_1(...args) {
12
12
  const opts = args[0];
13
13
  const isPublishFlow = !!config_1.CONFIG_DATA.publish;
14
14
  const isAuto = opts.auto;
15
- const pub = { platform: 0, status: 0, updateType: 0 };
15
+ const pub = { platform: 0, status: 0, updateType: 0, updateMode: 0 };
16
16
  let install = true;
17
17
  if (!isAuto) {
18
18
  const { start } = await inquirer_1.default.prompt({
@@ -54,15 +54,36 @@ async function default_1(...args) {
54
54
  {
55
55
  type: 'list',
56
56
  name: 'updateType',
57
- message: '请选择应用更新方式',
57
+ message: '请选择应用更新类型',
58
58
  choices: [
59
59
  { name: '强制更新', value: 2 },
60
60
  { name: '提示升级', value: 1 },
61
+ { name: '静默更新', value: 3 },
61
62
  ],
62
63
  },
63
64
  ]);
64
65
  pub.updateType = updateType;
65
66
  }
67
+ // --wgt/--zip 一律热更新
68
+ // --win/--apk 一律整包更新
69
+ // --remote 则提示热更新还是整包更新
70
+ if (opts.win || opts.apk) {
71
+ pub.updateMode = 1;
72
+ if (opts.remote) {
73
+ const { updateMode } = await inquirer_1.default.prompt([
74
+ {
75
+ type: 'list',
76
+ name: 'updateMode',
77
+ message: '请选择更新方式',
78
+ choices: [
79
+ { name: '整包更新', value: 1 },
80
+ { name: '热更新', value: 2 },
81
+ ],
82
+ },
83
+ ]);
84
+ pub.updateMode = updateMode;
85
+ }
86
+ }
66
87
  }
67
88
  else {
68
89
  // pub 流程
@@ -93,7 +114,7 @@ async function default_1(...args) {
93
114
  {
94
115
  type: 'list',
95
116
  name: 'status',
96
- message: '请选择应用更新状态',
117
+ message: '请选择应用更新类型',
97
118
  choices: [
98
119
  { name: '强制更新', value: 4 },
99
120
  { name: '提示升级', value: 3 },
@@ -152,9 +173,6 @@ async function default_1(...args) {
152
173
  else {
153
174
  cmds = await (0, build_1.default)(...args);
154
175
  }
155
- if (opts.compiler === 'gradlew' || opts.remote) {
156
- return;
157
- }
158
176
  // 从 cmds 提取 buildEnv
159
177
  const buildEnv = cmds[2]?.split('=')[1];
160
178
  if (!buildEnv || !['dev', 'sit', 'uat', 'pre', 'prod'].includes(buildEnv)) {
@@ -176,6 +194,9 @@ async function default_1(...args) {
176
194
  if (pub.updateType) {
177
195
  config_1.CONFIG_DATA.publish.updateType = pub.updateType;
178
196
  }
197
+ if (pub.updateMode) {
198
+ config_1.CONFIG_DATA.publish.updateMode = pub.updateMode;
199
+ }
179
200
  }
180
201
  else {
181
202
  if (!config_1.CONFIG_DATA.pub) {
@@ -196,6 +217,11 @@ async function default_1(...args) {
196
217
  await require('../scripts/h5-exe').default();
197
218
  }
198
219
  }
220
+ else if (opts.compiler === 'gradlew') {
221
+ if (opts.apk) {
222
+ await require('../scripts/app-apk').default();
223
+ }
224
+ }
199
225
  else if (opts.compiler === 'uni') {
200
226
  if (opts.platform?.startsWith('mp')) {
201
227
  await require('../scripts/mp-weixin').default();
package/lib/apis/index.js CHANGED
@@ -207,13 +207,24 @@ async function publishVersion(params) {
207
207
  const urls = Array.isArray(remoteUrl) ? remoteUrl : [remoteUrl || ''];
208
208
  const fullUrl = urls.find((u) => !/\.zip$/i.test(u)) || '';
209
209
  const resUrl = urls.find((u) => /\.zip$/i.test(u)) || '';
210
- const fallbackFullUrl = existingVersion?.fullPackageUrl || latest?.fullPackageUrl || '';
211
- const fallbackResUrl = existingVersion?.resourcePackageUrl || latest?.resourcePackageUrl || '';
212
- await postVersion({
213
- id: versionId,
214
- fullPackageUrl: fullUrl || fallbackFullUrl,
215
- resourcePackageUrl: resUrl || fallbackResUrl,
216
- });
210
+ if (config_1.CONFIG_DATA.publish?.updateMode != null) {
211
+ const isHotUpdate = config_1.CONFIG_DATA.publish.updateMode == 2;
212
+ const hotResUrl = isHotUpdate ? (config_1.CONFIG_DATA.publish['_remoteResourceUrl'] || '') : '';
213
+ await postVersion({
214
+ id: versionId,
215
+ fullPackageUrl: fullUrl,
216
+ resourcePackageUrl: hotResUrl,
217
+ });
218
+ }
219
+ else {
220
+ const fallbackFullUrl = existingVersion?.fullPackageUrl || latest?.fullPackageUrl || '';
221
+ const fallbackResUrl = existingVersion?.resourcePackageUrl || latest?.resourcePackageUrl || '';
222
+ await postVersion({
223
+ id: versionId,
224
+ fullPackageUrl: fullUrl || fallbackFullUrl,
225
+ resourcePackageUrl: resUrl || fallbackResUrl,
226
+ });
227
+ }
217
228
  }
218
229
  catch (err) {
219
230
  console.error(err);
package/lib/bin.js CHANGED
@@ -49,6 +49,7 @@ program
49
49
  .option(...commands_1.win)
50
50
  .option(...commands_1.mac)
51
51
  .option(...commands_1.linux)
52
+ .option(...commands_1.apk)
52
53
  .option(...commands_1.remote)
53
54
  .action(build_1.default);
54
55
  program
@@ -76,6 +77,7 @@ program
76
77
  .option(...commands_1.win)
77
78
  .option(...commands_1.mac)
78
79
  .option(...commands_1.linux)
80
+ .option(...commands_1.apk)
79
81
  .option(...commands_1.auto)
80
82
  .option(...commands_1.remote)
81
83
  .action(publish_1.default);
@@ -21,6 +21,7 @@ export declare const custom: readonly ["--custom", "是否构建自定义基座"
21
21
  export declare const pack: readonly ["--pack", "是否使用hbuilderx构建应用"];
22
22
  export declare const wgt: readonly ["--wgt", "是否构建移动应用热更新资源"];
23
23
  export declare const res: readonly ["--res", "是否构建移动应用本地资源"];
24
+ export declare const apk: readonly ["--apk", "是否构建Android应用"];
24
25
  export declare const auto: readonly ["-a, --auto", "自动发布,跳过所有确认"];
25
26
  export declare const remote: readonly ["--remote", "是否从远程拉取资源构建"];
26
27
  export declare const hbuilderxCli: readonly ["--cli.hbuilderx <cli-path>", "HbuilderX Cli路径"];
@@ -53,6 +54,7 @@ export interface Options {
53
54
  win: boolean;
54
55
  mac: boolean;
55
56
  linux: boolean;
57
+ apk?: boolean;
56
58
  remote?: boolean;
57
59
  'skill.repo'?: string;
58
60
  'template.repo'?: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.templateRepo = exports.skillRepo = exports.cosSecretkey = exports.cosSecretid = exports.alipayCli = exports.weixinCli = exports.hbuilderxCli = exports.remote = exports.auto = exports.res = exports.wgt = exports.pack = 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.remote = exports.auto = exports.apk = exports.res = exports.wgt = exports.pack = 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'];
@@ -23,6 +23,7 @@ exports.custom = ['--custom', '是否构建自定义基座'];
23
23
  exports.pack = ['--pack', '是否使用hbuilderx构建应用'];
24
24
  exports.wgt = ['--wgt', '是否构建移动应用热更新资源'];
25
25
  exports.res = ['--res', '是否构建移动应用本地资源'];
26
+ exports.apk = ['--apk', '是否构建Android应用'];
26
27
  exports.auto = ['-a, --auto', '自动发布,跳过所有确认'];
27
28
  exports.remote = ['--remote', '是否从远程拉取资源构建'];
28
29
  exports.hbuilderxCli = ['--cli.hbuilderx <cli-path>', 'HbuilderX Cli路径'];
@@ -1,15 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = default_1;
4
- const utils_1 = require("../utils");
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const const_1 = require("../utils/const");
5
7
  const publish_1 = require("./publish");
6
8
  async function default_1() {
7
- const manifest = (0, utils_1.readManifest)();
9
+ const gradleContent = (0, fs_1.readFileSync)((0, path_1.join)(const_1.COMMAND_PATH, 'app', 'build.gradle'), 'utf-8');
10
+ const versionName = gradleContent.match(/versionName\s+"([^"]*)"/)?.[1];
11
+ const versionCode = gradleContent.match(/versionCode\s+(\d+)/)?.[1];
8
12
  await (0, publish_1.publish)({
9
13
  ext: 'apk',
10
14
  name: 'app-release',
11
15
  path: 'app/build/outputs/apk/release',
12
- versionName: manifest['versionName'],
13
- versionCode: manifest['versionCode'],
16
+ versionName,
17
+ versionCode: versionCode ? Number(versionCode) : undefined,
14
18
  });
15
19
  }
@@ -66,6 +66,7 @@ interface PublishConfig {
66
66
  brandId?: string;
67
67
  channel?: number;
68
68
  updateType?: number;
69
+ updateMode?: number;
69
70
  versionDesc?: string;
70
71
  publishType?: number;
71
72
  platform?: number;
@@ -14,7 +14,7 @@ export declare const DIST_PATH: string;
14
14
  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
- export declare const COMPILER_OPTIONS: readonly ["vite", "uni", "electron-vite", "gradlew"];
17
+ export declare const COMPILER_OPTIONS: string[];
18
18
  export declare const DEFAULT_SKILL_REPO = "http://10.10.10.16/caoben/project-template.git";
19
19
  export declare const DEFAULT_TEMPLATE_REPO = "http://10.10.10.16/caoben/project-template.git";
20
20
  export declare const BASE_URL: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmcb/cli",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "工茂草本前端命令行工具",
5
5
  "author": "yinjiazeng@163.com",
6
6
  "license": "MIT",
@@ -58,5 +58,6 @@
58
58
  "@types/inquirer": "^9.0.7",
59
59
  "@types/rimraf": "^4.0.5",
60
60
  "@types/user-home": "^2.0.2"
61
- }
61
+ },
62
+ "gitHead": "7aa3012c0c76701618d1e54ea9efcdcb3c3ed438"
62
63
  }
package/schema.json CHANGED
@@ -77,10 +77,14 @@
77
77
  "channel": {
78
78
  "type": "number",
79
79
  "description": "渠道类型"
80
+ },
81
+ "updateMode": {
82
+ "type": "number",
83
+ "description": "更新方式"
80
84
  },
81
85
  "updateType": {
82
86
  "type": "number",
83
- "description": "更新方式"
87
+ "description": "更新类型"
84
88
  },
85
89
  "versionDesc": {
86
90
  "type": "string",