@gmcb/cli 0.6.3 → 0.7.1

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,36 @@
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.1](http://10.10.10.16/caoben/front-end/compare/@gmcb/cli@0.7.0...@gmcb/cli@0.7.1) (2026-07-06)
7
+
8
+ **Note:** Version bump only for package @gmcb/cli
9
+
10
+
11
+
12
+
13
+
14
+ # [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)
15
+
16
+
17
+ ### Features
18
+
19
+ * 优化cli ([676ac43](http://10.10.10.16/caoben/front-end/commits/676ac4381ca645ef232936b86e3b77124337a03c))
20
+
21
+
22
+
23
+
24
+
25
+ ## [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)
26
+
27
+
28
+ ### Features
29
+
30
+ * 优化cli ([676ac43](http://10.10.10.16/caoben/front-end/commits/676ac4381ca645ef232936b86e3b77124337a03c))
31
+
32
+
33
+
34
+
35
+
6
36
  ## [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
37
 
8
38
 
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,13 @@ 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, versionDesc } = result;
276
+ if (!config_1.CONFIG_DATA.publish) {
277
+ config_1.CONFIG_DATA.publish = {};
278
+ }
279
+ if (versionDesc && !config_1.CONFIG_DATA.publish.versionDesc) {
280
+ config_1.CONFIG_DATA.publish.versionDesc = versionDesc;
281
+ }
276
282
  if (opts.win) {
277
283
  // Windows
278
284
  const zipUrl = result.resourcePackageUrl;
@@ -288,14 +294,11 @@ async function fetchRemoteResources(opts) {
288
294
  const zip = new adm_zip_1.default(tmpZip);
289
295
  zip.extractAllTo(rendererDir, true);
290
296
  (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
297
  // 替换 package.json
295
298
  const pkgPath = (0, path_1.join)(utils_1.COMMAND_PATH, 'package.json');
296
299
  let pkgContent = (0, fs_1.readFileSync)(pkgPath, 'utf-8');
297
300
  pkgContent = pkgContent.replace(/"version":\s*"[^"]*"/, `"version": "${versionName}"`);
298
- pkgContent = pkgContent.replace(/"versionCode":\s*\d+/, `"versionCode": ${versionCode}`);
301
+ pkgContent = pkgContent.replace(/"versionCode":\s*\d+/, `"versionCode": ${versionNum}`);
299
302
  pkgContent = pkgContent.replace(/"productName":\s*"[^"]*"/, `"productName": "${appName}"`);
300
303
  (0, fs_1.writeFileSync)(pkgPath, pkgContent);
301
304
  // 下载图标
@@ -305,6 +308,7 @@ async function fetchRemoteResources(opts) {
305
308
  await downloadFile(iconUrl, iconPath);
306
309
  await (0, utils_1.png2ico)(iconPath, (0, path_1.join)(utils_1.COMMAND_PATH, 'res', 'icon.ico'));
307
310
  }
311
+ config_1.CONFIG_DATA.publish['_remoteResourceUrl'] = zipUrl;
308
312
  spinner.succeed(`Windows本地资源已更新`);
309
313
  }
310
314
  else if (opts.compiler === 'gradlew') {
@@ -325,7 +329,7 @@ async function fetchRemoteResources(opts) {
325
329
  (0, fs_extra_1.removeSync)(tmpWgt);
326
330
  // 从目标目录读取 manifest
327
331
  const manifest = (0, fs_extra_1.readJsonSync)((0, path_1.join)(tempDir, 'manifest.json'));
328
- const { version, id } = manifest;
332
+ const { id } = manifest;
329
333
  const assetsDir = (0, path_1.join)(appDir, id, 'www');
330
334
  // 将解压内容复制到 assetsDir,然后删除临时目录
331
335
  (0, fs_extra_1.ensureDirSync)(assetsDir);
@@ -334,8 +338,8 @@ async function fetchRemoteResources(opts) {
334
338
  // 替换 build.gradle
335
339
  const gradlePath = (0, path_1.join)(utils_1.COMMAND_PATH, 'app', 'build.gradle');
336
340
  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}"`);
341
+ gradleContent = gradleContent.replace(/versionName\s+"[^"]*"/, `versionName "${versionName}"`);
342
+ gradleContent = gradleContent.replace(/versionCode\s+\d+/, `versionCode ${versionNum}`);
339
343
  (0, fs_1.writeFileSync)(gradlePath, gradleContent);
340
344
  // 替换 strings.xml
341
345
  const stringsPath = (0, path_1.join)(utils_1.COMMAND_PATH, 'app', 'src', 'main', 'res', 'values', 'strings.xml');
@@ -350,6 +354,7 @@ async function fetchRemoteResources(opts) {
350
354
  await downloadFile(iconUrl, iconPath);
351
355
  (0, fs_1.copyFileSync)(iconPath, (0, path_1.join)(drawableDir, 'push.png'));
352
356
  }
357
+ config_1.CONFIG_DATA.publish['_remoteResourceUrl'] = wgtUrl;
353
358
  spinner.succeed(`Android本地资源已更新`);
354
359
  }
355
360
  }
@@ -377,7 +382,7 @@ async function default_1(...args) {
377
382
  if ((opts.compiler === 'electron-vite' && (opts.zip || opts.win)) ||
378
383
  (opts.compiler === 'uni' && opts.platform === 'h5' && opts.zip) ||
379
384
  (opts.compiler === 'uni' && opts.platform?.startsWith('app') && opts.wgt && !opts.pack) ||
380
- opts.compiler === 'gradlew' && opts.platform === 'app') {
385
+ opts.compiler === 'gradlew' && opts.apk) {
381
386
  await generatePackage(opts);
382
387
  }
383
388
  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.1",
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": "62531cd8ffc2d51d9f160e751fabc12f6b33d89a"
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",