@neuxnet/neux-cli 0.2.6 → 0.2.8

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/README.md CHANGED
@@ -45,11 +45,10 @@ NEUX_CLI_KEY_APP_XXX=key_xxx neux debug --project ./miniapp --app-id app_xxx --s
45
45
  NEUX_CLI_KEY_APP_XXX=key_xxx neux service-preview --app-id app_xxx --server-url https://miniapp.example.com --json
46
46
  NEUX_CLI_KEY_APP_XXX=key_xxx neux submit --app-id app_xxx --server-url https://miniapp.example.com --version-id 123 --json
47
47
  NEUX_CLI_KEY_APP_XXX=key_xxx neux status --app-id app_xxx --server-url https://miniapp.example.com --json
48
- NEUX_CLI_KEY_APP_XXX=key_xxx neux meta --app-id app_xxx --server-url https://miniapp.example.com --json
49
48
  NEUX_CLI_KEY_APP_XXX=key_xxx neux audit-status --app-id app_xxx --server-url https://miniapp.example.com --version-id 123 --json
50
49
  ```
51
50
 
52
- `init` creates a minimal mini program project from scratch. In a TTY it interactively asks for the project name, App ID, Server URL, and a hidden `CLI Key`. The default Server URL is `https://demo-c.paas.superapp.neuvision.cn`. App ID and Server URL are written to the project; each App ID's CLI Key is stored in the user-level `~/.neux/config.json` and never in project files. Use `neux config set` to change the current project's CLI Key. `build` creates the client `.wgt` delivery artifact. `upload`, `debug`, `service-preview`, `submit`, `status` / `meta`, and `audit-status` use the signed service API when `--provider` is omitted. `debug-preview`, `submit-audit`, `version`, and `wgt` remain compatibility spellings for integrations that already use them. `login` is still provider-backed and unsupported by the signed service. Use `--provider local-file` or a provider module when testing adapter integrations instead of the remote service.
51
+ `init` creates a minimal mini program project from scratch. In a TTY it interactively asks for the project name, App ID, Server URL, and a hidden `CLI Key`. The default Server URL is `https://demo-c.paas.superapp.neuvision.cn`. App ID and Server URL are written to the project; each App ID's CLI Key is stored in the user-level `~/.neux/config.json` and never in project files. Use `neux config set` to change the current project's CLI Key. `build` creates the client `.wgt` delivery artifact. `upload`, `debug`, `service-preview`, `submit`, `status`, and `audit-status` use the signed service API when `--provider` is omitted. `debug-preview`, `submit-audit`, `meta`, `version`, `audit`, and `wgt` remain compatibility spellings for integrations that already use them; compatibility and legacy commands print a deprecation warning to stderr. `preview` and `web` are legacy local preview entrypoints; prefer `dev` for new scripts. `login` is provider-specific, hidden from the default root help, and unsupported by the signed service. Use `--provider local-file` or a provider module when testing adapter integrations instead of the remote service. Run `neux <command> --help` for command-specific options.
53
52
 
54
53
  The generated project also includes source-backed JSON Schemas under `.vscode/neux-json-schemas/` and registers them in `.vscode/settings.json`. Run `npm run verify:schemas` in the CLI repository to verify that the checked-in schemas and init registration remain aligned. VS Code can therefore provide completion, hover documentation, enum suggestions, and basic validation for `app.json`, page JSON files, `project.config.json`, `project.private.config.json`, and `neux.config.json`. These schemas describe fields consumed by the Neux CLI/compiler; cross-file checks such as page existence and component path resolution remain compiler/CLI validation.
55
54
 
@@ -381,7 +380,9 @@ Event names are stable: `build-start`, `build-success`, `build-error`, `ready`,
381
380
 
382
381
  ## Provider Adapters
383
382
 
384
- Provider commands first create a package artifact, then call the selected provider:
383
+ Provider commands first create a package artifact, then call the selected provider. The
384
+ default signed service does not implement `login`; the command is intentionally hidden
385
+ from the root help and is only useful when a custom provider supplies a `login` method:
385
386
 
386
387
  ```sh
387
388
  neux login --project ./miniapp --provider ./provider.mjs --json
package/README.zh-CN.md CHANGED
@@ -112,7 +112,6 @@ neux debug --page-path pages/index/index --query foo=bar
112
112
  neux upload --preview --changelog "Release notes" --channel test
113
113
  neux submit --version-id 123 --channel test
114
114
  neux status --json
115
- neux meta --json
116
115
  neux audit-status --version-id 123 --json
117
116
  ```
118
117
 
@@ -192,16 +191,22 @@ neux config set --key NEW_CLI_KEY
192
191
  | `neux upload` | 上传 signed service 体验包 |
193
192
  | `neux debug` | 上传调试预览包,并输出 deeplink 与可扫码终端二维码 |
194
193
  | `neux submit` | 提交体验版本审核 |
195
- | `neux status` / `neux meta` | 查询 signed service 版本信息 |
194
+ | `neux status` | 查询 signed service 版本信息 |
196
195
  | `neux audit-status` | 查询审核状态 |
197
196
  | `neux config doctor` | 诊断 signed service 配置 |
198
197
  | `neux config set` | 交互式修改当前项目的 CLI Key |
199
198
  | `neux update` | 检查并更新 CLI |
200
- | `neux --version` / `neux cli-version` | 查看当前安装的 CLI 版本 |
199
+ | `neux --version` | 查看当前安装的 CLI 版本 |
200
+ | `neux cli-version` | 查看详细 CLI 包信息,适合 IDE/CI |
201
201
  | `neux compile` | 仅执行内置小程序编译 |
202
+ | `neux pack` | 将已有编译产物打包为本地归档 |
202
203
  | `neux wgt` | `neux build` 的兼容别名 |
203
204
 
204
- 兼容命令包括 `debug-preview`、`service-preview`、`submit-audit`、`version`、`audit`、`preview`、`web`。新脚本优先使用 `build`、`dev`、`debug`、`upload`、`submit`。
205
+ `service-preview` `audit-status` 属于高级服务命令。`debug-preview`、`submit-audit`、
206
+ `meta`、`version`、`audit` 和 `wgt` 是兼容命令;`preview`、`web` 是旧版本地预览
207
+ 入口。调用兼容命令或旧版命令时,CLI 会向 stderr 输出弃用提示;新脚本优先使用
208
+ `build`、`dev`、`debug`、`upload`、`submit`、`status`。
209
+ 可使用 `neux <command> --help` 查看命令级选项。
205
210
 
206
211
  ## 更新 CLI
207
212
 
@@ -315,7 +320,6 @@ neux submit --version-id 123 --channel test
315
320
 
316
321
  ```sh
317
322
  neux status --json
318
- neux meta --json
319
323
  ```
320
324
 
321
325
  查询审核状态:
@@ -457,6 +461,8 @@ neux preview --json --stay
457
461
  ## Provider 适配器
458
462
 
459
463
  默认不传 `--provider` 时,`upload`、`debug`、`submit` 等命令使用 signed service。
464
+ 默认 signed service 不实现 `login`;`login` 不会出现在根命令帮助中,仅在自定义
465
+ Provider 实现 `login` 时才有意义。
460
466
 
461
467
  如果要测试自定义适配器,可以传入 provider 模块:
462
468
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuxnet/neux-cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Standalone CLI and Node API for Neux mini program build, pack, preview, and CI automation.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/bin/cli.js CHANGED
@@ -6,6 +6,7 @@ import { spawnSync } from 'node:child_process'
6
6
  import { buildProject, createLifecycleEvent, createProjectWatcher, DEFAULT_SERVER_URL, getCliPackageInfo, getCliVersion, initProject, inspectProject, maybeAutoUpdateCli, packProject, saveCliKey, startDev, startPreview, startWeb, updateCli } from '../index.js'
7
7
  import { DiminaCliError, toErrorPayload } from '../core/errors.js'
8
8
  import { brand } from '../core/brand.js'
9
+ import { help, rootHelp, warnIfDeprecated } from '../core/help.js'
9
10
  import { runProviderCommand, unsupportedProviderCommand } from '../providers/upload.js'
10
11
  import { resolveServiceConfig, resolveServiceConfigDiagnostics } from '../providers/service-config.js'
11
12
  import { renderQrPng, renderTerminalQr } from '../core/terminal-qr.js'
@@ -54,90 +55,6 @@ function createSessionSignalController() {
54
55
  import { resolveLocale, translate } from '../core/i18n.js'
55
56
  import { promptLine } from '../core/prompts.js'
56
57
 
57
- function help(locale = 'en') {
58
- return `${translate(locale, 'usage')}: ${brand.commandName} <command> [options]
59
-
60
- ${translate(locale, 'commands')}:
61
- init Create a new mini program project
62
- inspect Read mini program metadata
63
- dev Compile, open the H5 container, watch files, and live reload
64
- build Build and create a client .wgt package in dist/release/
65
- upload Upload a signed service trial package
66
- debug Upload a signed debug preview package and print a QR code
67
- submit Submit a signed service trial version for audit
68
- status Query signed service version information
69
- meta Alias of status for signed service version metadata
70
- config Diagnose signed service configuration
71
- update Check for or install a newer CLI version
72
- cli-version Show the installed CLI version
73
- compile Compile a mini program with ${brand.compilerPackageName}
74
- wgt Alias of build for compatibility
75
- preview Legacy local static preview server
76
- web Legacy H5 container command; prefer dev
77
- login Reserved provider-backed login command (unsupported by signed service)
78
- debug-preview Upload a signed debug preview package and print a QR code
79
- service-preview Generate signed service trial preview information
80
- submit-audit Submit a signed service trial version for audit
81
- version Query signed service version information
82
- audit-status Query signed service audit status
83
- audit Alias of submit-audit for provider integrations
84
-
85
- ${translate(locale, 'commonOptions')}:
86
- --project <path> Mini program project path, defaults to current directory
87
- --out <path> Output directory, defaults to dist/<command>
88
- --app-id <id> Override project app id
89
- --name <name> Project name for init or metadata override
90
- --entry-path <path> Override entry path
91
- --source-dir <path> Already-produced mini app output directory for packaging
92
- --compiled-dir <path> Alias of --source-dir
93
- --version-code <n> Package version code
94
- --version <version> Package/service version
95
- --version-name <name> Package version name
96
- --host <host> Preview host
97
- --port <port> Preview port, use 0 for a random free port
98
- --container-dir <path> Web container dist directory
99
- --compiler-module <path> Use a local compiler module instead of ${brand.compilerPackageName}
100
- --provider <module> Provider module or "local-file" for provider commands
101
- --provider-out <path> Output directory for provider-generated records
102
- --server-url <url> Signed service base URL
103
- --profile <name> User-level service profile name
104
- --key <key> Signed service key (prefer NEUX_CLI_KEY in CI)
105
- --config <path> User-level CLI config path, defaults to ~/.neux/config.json
106
- --registry <url> npm registry for CLI self-update
107
- --check Check updates without installing
108
- --dry-run Check update/install intent without installing
109
- --auto-update Enable automatic CLI update for this run
110
- --no-auto-update Disable automatic CLI update for this run
111
- --desc <text> Upload description
112
- --changelog <text> Upload changelog, also used as description fallback
113
- --channel <channel> Service channel for preview/upload/audit
114
- --page-path <path> Debug/preview launch page path
115
- --query <query> Debug/preview launch query string
116
- --scene <scene> Debug/preview launch scene
117
- --launch-from <source> Debug/preview launch source
118
- --location <location> Debug/preview launch location
119
- --qr-format <format> QR output format: png, terminal, or none
120
- --qr-output <path> Write QR output to a file
121
- --copy Copy deeplink/QR payload to clipboard when supported
122
- --proxy <url> Proxy hint for service/provider integrations
123
- --preview Return trial preview during upload
124
- --submit-audit Submit trial version after upload
125
- --auto-publish Ask audit service to publish automatically when supported
126
- --version-id <id> Service version id
127
- --version-number <v> Service version number
128
- --build Build before pack/preview
129
- --no-open Do not open the browser automatically
130
- --json Print machine-readable JSON
131
- --lang <locale> Output language: en or zh-CN
132
- --interactive Enable interactive prompts
133
- --no-interactive Disable interactive prompts
134
- --stay Keep preview/web server running
135
- --watch, -w Rebuild on project file changes
136
- --force Allow init to write into a non-empty directory
137
- --version, -v Show CLI version
138
- --help Show help
139
- `
140
- }
141
58
 
142
59
  function parse(argv) {
143
60
  const args = [...argv]
@@ -365,9 +282,13 @@ async function main() {
365
282
  return
366
283
  }
367
284
  if (!command || command === '--help' || options.help) {
368
- process.stdout.write(help(locale))
285
+ const subcommand = command === 'config' ? options._[0] : undefined
286
+ process.stdout.write(command === '--help' || !command
287
+ ? rootHelp(locale)
288
+ : help(locale, command, subcommand))
369
289
  return
370
290
  }
291
+ warnIfDeprecated(command, locale)
371
292
  if (options.qrFormat) normalizeQrFormat(options.qrFormat)
372
293
 
373
294
  if (command !== 'update') {
@@ -0,0 +1,507 @@
1
+ import { brand } from './brand.js'
2
+ import { translate } from './i18n.js'
3
+
4
+ const commandGroups = [
5
+ {
6
+ title: 'Core commands',
7
+ commands: [
8
+ ['init', 'Create a new mini program project'],
9
+ ['inspect', 'Inspect project metadata and diagnostics'],
10
+ ['dev', 'Start local development with H5 preview and live reload'],
11
+ ['build', 'Build a client .wgt package'],
12
+ ['upload', 'Upload a signed service trial package'],
13
+ ['debug', 'Upload a debug package and print a QR code'],
14
+ ['submit', 'Submit a signed service trial version for audit'],
15
+ ['status', 'Query signed service version information'],
16
+ ['config', 'Diagnose or update signed service configuration'],
17
+ ['update', 'Check for or install a newer CLI version'],
18
+ ],
19
+ },
20
+ {
21
+ title: 'Advanced commands',
22
+ commands: [
23
+ ['compile', 'Compile without creating a delivery package'],
24
+ ['pack', 'Package an existing compiled output'],
25
+ ['service-preview', 'Generate signed service trial preview information'],
26
+ ['audit-status', 'Query signed service audit status'],
27
+ ['cli-version', 'Show detailed CLI package information'],
28
+ ],
29
+ },
30
+ {
31
+ title: 'Compatibility aliases',
32
+ commands: [
33
+ ['wgt', 'Alias of build'],
34
+ ['meta', 'Alias of status'],
35
+ ['version', 'Alias of status'],
36
+ ['debug-preview', 'Compatibility spelling for debug'],
37
+ ['submit-audit', 'Compatibility spelling for submit'],
38
+ ['audit', 'Provider/service compatibility command'],
39
+ ],
40
+ },
41
+ {
42
+ title: 'Legacy commands',
43
+ commands: [
44
+ ['preview', 'Legacy local static preview server'],
45
+ ['web', 'Legacy H5 container command; prefer dev'],
46
+ ],
47
+ },
48
+ ]
49
+
50
+ const commonHelp = ` --project <path> Project path, defaults to current directory
51
+ --out <path> Output directory; see <command> --help for defaults
52
+ --json Print machine-readable JSON
53
+ --lang <locale> Output language: en or zh-CN
54
+ --help Show command help
55
+ --version, -v Show CLI version`
56
+
57
+ const helpTranslations = new Map([
58
+ ['Core commands:', '核心命令:'],
59
+ ['Advanced commands:', '高级命令:'],
60
+ ['Provider commands:', 'Provider 命令:'],
61
+ ['Compatibility aliases:', '兼容别名:'],
62
+ ['Legacy commands:', '旧版命令:'],
63
+ ['Create a new mini program project', '创建新的小程序项目'],
64
+ ['Inspect project metadata and diagnostics', '检查项目元数据和诊断信息'],
65
+ ['Inspect project metadata and configuration diagnostics.', '检查项目元数据和配置诊断信息。'],
66
+ ['Start local development with H5 preview and live reload', '启动本地开发、H5 预览和热更新'],
67
+ ['Start local development with the H5 container and live reload.', '启动本地开发、H5 容器和热更新。'],
68
+ ['Build a client .wgt package', '构建客户端 `.wgt` 交付包'],
69
+ ['Upload a signed service trial package', '上传 signed service 体验包'],
70
+ ['Upload a debug package and print a QR code', '上传调试包并输出二维码'],
71
+ ['Submit a signed service trial version for audit', '提交 signed service 体验版本审核'],
72
+ ['Query signed service version information', '查询 signed service 版本信息'],
73
+ ['Diagnose or update signed service configuration', '诊断或更新 signed service 配置'],
74
+ ['Diagnose signed service configuration', '诊断 signed service 配置'],
75
+ ['Check for or install a newer CLI version', '检查或安装新版 CLI'],
76
+ ['Provider-specific authentication', 'Provider 专属认证'],
77
+ ['Alias of build', 'build 的别名'],
78
+ ['Alias of status', 'status 的别名'],
79
+ ['Compatibility spelling for debug', 'debug 的兼容写法'],
80
+ ['Compatibility spelling for submit', 'submit 的兼容写法'],
81
+ ['Provider/service compatibility command', 'Provider/service 兼容命令'],
82
+ ['Legacy local static preview server', '旧版本地静态预览服务器'],
83
+ ['Legacy H5 container command; prefer dev', '旧版 H5 容器命令;建议使用 dev'],
84
+ ['Project path, defaults to current directory', '项目路径,默认当前目录'],
85
+ ['Output directory; see <command> --help for defaults', '输出目录;默认值请查看 <command> --help'],
86
+ ['Output language: en or zh-CN', '输出语言:en 或 zh-CN'],
87
+ ['Show command help', '显示命令帮助'],
88
+ ['Show CLI version', '显示 CLI 版本'],
89
+ ['Create a new mini program project.', '创建新的小程序项目。'],
90
+ ['Inspect project metadata and diagnostics.', '检查项目元数据和诊断信息。'],
91
+ ['Start local development with H5 preview and live reload.', '启动本地开发、H5 预览和热更新。'],
92
+ ['Build a client .wgt delivery package.', '构建客户端 `.wgt` 交付包。'],
93
+ ['Build and upload a signed service trial package.', '构建并上传 signed service 体验包。'],
94
+ ['Build and upload a signed debug preview package.', '构建并上传 signed service 调试预览包。'],
95
+ ['Submit a signed service trial version for audit.', '提交 signed service 体验版本审核。'],
96
+ ['Query signed service version information.', '查询 signed service 版本信息。'],
97
+ ['Diagnose or update signed service configuration', '诊断或更新 signed service 配置'],
98
+ ['Check for or install a newer CLI version.', '检查或安装新版 CLI。'],
99
+ ['Compile without creating a delivery package', '仅编译,不创建交付包'],
100
+ ['Compile a mini program without creating a delivery package.', '仅编译小程序,不创建交付包。'],
101
+ ['Package an existing compiled output', '将已有编译产物打包'],
102
+ ['Package an existing compiled output as a local archive.', '将已有编译产物打包为本地归档。'],
103
+ ['Generate signed service trial preview information.', '生成 signed service 体验预览信息。'],
104
+ ['Query signed service audit status.', '查询 signed service 审核状态。'],
105
+ ['Show detailed CLI package information.', '显示详细的 CLI 包信息。'],
106
+ ['Provider-specific authentication.', 'Provider 专属认证。'],
107
+ ['The default signed service does not implement login.', '默认 signed service 不支持 login。'],
108
+ ['Provider-specific authentication. The default signed service does not implement login.', 'Provider 专属认证。默认 signed service 不支持 login。'],
109
+ ['Create a new mini program project.', '创建新的小程序项目。'],
110
+ ['Alias of build', 'build 的别名'],
111
+ ['Alias of status', 'status 的别名'],
112
+ ['Compatibility spelling for debug', 'debug 的兼容写法'],
113
+ ['Compatibility spelling for submit', 'submit 的兼容写法'],
114
+ ['Provider/service compatibility command', 'Provider/service 兼容命令'],
115
+ ['Legacy local static preview server', '旧版本地静态预览服务器'],
116
+ ['Legacy H5 container command; prefer dev', '旧版 H5 容器命令;建议使用 dev'],
117
+ ['Usage:', '用法:'],
118
+ ['Options:', '选项:'],
119
+ ['Subcommands:', '子命令:'],
120
+ ['Run "neux config <subcommand> --help" for subcommand options.', '运行 "neux config <subcommand> --help" 查看子命令选项。'],
121
+ ['Initial app id', '初始 App ID'],
122
+ ['Initial project name', '初始项目名称'],
123
+ ['Signed service base URL', 'signed service 基础地址'],
124
+ ['Initial CLI key', '初始 CLI Key'],
125
+ ['Allow writing into a non-empty directory', '允许写入非空目录'],
126
+ ['Disable interactive prompts', '禁用交互式询问'],
127
+ ['Print machine-readable JSON', '输出机器可读 JSON'],
128
+ ['Project path', '项目路径'],
129
+ ['Mini program project path', '小程序项目路径'],
130
+ ['Output directory, defaults to dist/dev', '输出目录,默认是 dist/dev'],
131
+ ['Output directory, defaults to dist/release', '输出目录,默认是 dist/release'],
132
+ ['Output directory, defaults to dist/build', '输出目录,默认是 dist/build'],
133
+ ['Output directory, defaults to dist/pack', '输出目录,默认是 dist/pack'],
134
+ ['Output directory, defaults to dist/preview', '输出目录,默认是 dist/preview'],
135
+ ['Output directory, defaults to dist/web', '输出目录,默认是 dist/web'],
136
+ ['Preview host', '预览主机'],
137
+ ['Preview port, use 0 for a random free port', '预览端口,使用 0 随机分配空闲端口'],
138
+ ['Preview port', '预览端口'],
139
+ ['Web container dist directory', 'Web 容器 dist 目录'],
140
+ ['Use a local compiler module', '使用本地编译器模块'],
141
+ ['Do not open the browser automatically', '不要自动打开浏览器'],
142
+ ['Print lifecycle events as JSON Lines', '以 JSON Lines 输出生命周期事件'],
143
+ ['Package version name', '包版本名称'],
144
+ ['Package version code', '包版本 code'],
145
+ ['Alias of --version-name', '--version-name 的别名'],
146
+ ['Package an existing compiled output', '打包已有编译产物'],
147
+ ['Alias of --source-dir', '--source-dir 的别名'],
148
+ ['Override project app id', '覆盖项目 App ID'],
149
+ ['User-level service profile name', '用户级服务 profile 名称'],
150
+ ['Signed service key', 'signed service Key'],
151
+ ['Return trial preview information', '返回体验预览信息'],
152
+ ['Submit the trial version after upload', '上传后提交体验版本审核'],
153
+ ['Upload changelog', '上传变更说明'],
154
+ ['Service channel', '服务通道'],
155
+ ['Provider module or "local-file"', 'Provider 模块或 "local-file"'],
156
+ ['Build before upload', '上传前先构建'],
157
+ ['Launch page path', '启动页面路径'],
158
+ ['Launch query string', '启动 query 字符串'],
159
+ ['Launch scene', '启动场景'],
160
+ ['Launch source', '启动来源'],
161
+ ['Launch location', '启动位置'],
162
+ ['QR output: png, terminal, or none', '二维码输出格式:png、terminal 或 none'],
163
+ ['Write QR output to a file', '将二维码输出到文件'],
164
+ ['Copy the deeplink when supported', '在支持时复制 deeplink'],
165
+ ['Service version id', '服务版本 ID'],
166
+ ['Service version number', '服务版本号'],
167
+ ['Ask the audit service to publish automatically', '请求审核服务自动发布'],
168
+ ['Provider module', 'Provider 模块'],
169
+ ['Save the current project\'s CLI key in the user-level CLI config.', '将当前项目的 CLI Key 保存到用户级 CLI 配置。'],
170
+ ['User-level CLI config path', '用户级 CLI 配置路径'],
171
+ ['Diagnose signed service configuration without exposing key values.', '诊断 signed service 配置,不暴露 Key 内容。'],
172
+ ['Check updates without installing', '只检查更新,不安装'],
173
+ ['Check update/install intent without installing', '检查更新/安装意图,不安装'],
174
+ ['npm registry for the update', '更新使用的 npm registry'],
175
+ ['npm executable to use', '使用的 npm 可执行文件'],
176
+ ['Compatibility alias: use "neux build" instead.', '兼容别名:请改用 "neux build"。'],
177
+ ['Compatibility alias: use "neux status" instead.', '兼容别名:请改用 "neux status"。'],
178
+ ['Compatibility alias: use "neux debug" instead.', '兼容别名:请改用 "neux debug"。'],
179
+ ['Compatibility alias: use "neux submit" instead.', '兼容别名:请改用 "neux submit"。'],
180
+ ['Provider/service compatibility command. Use "neux submit" for the signed service.', 'Provider/service 兼容命令。signed service 请使用 "neux submit"。'],
181
+ ['Legacy local static preview server. Prefer "neux dev".', '旧版本地静态预览服务器。建议使用 "neux dev"。'],
182
+ ['Legacy H5 container command. Prefer "neux dev".', '旧版 H5 容器命令。建议使用 "neux dev"。'],
183
+ ['This command is legacy; use `neux dev` for the local H5 workflow.', '该命令已是旧版入口;本地 H5 工作流请使用 `neux dev`。'],
184
+ ['This command is legacy; use `neux dev` instead.', '该命令已是旧版入口;请使用 `neux dev`。'],
185
+ ['Common options:', '通用选项:'],
186
+ ['通用选项:', '通用选项:'],
187
+ ['Generate signed service trial preview information', '生成 signed service 体验预览信息'],
188
+ ['Query signed service audit status', '查询 signed service 审核状态'],
189
+ ['Show detailed CLI package information', '显示详细的 CLI 包信息'],
190
+ ['Save the current project\'s CLI key', '保存当前项目的 CLI Key'],
191
+ ['Run "neux <command> --help" for command-specific options.', '运行 "neux <command> --help" 查看命令级选项。'],
192
+ ])
193
+
194
+ function localizeHelpText(locale, text) {
195
+ if (String(locale).toLowerCase() !== 'zh-cn') return text
196
+ let localized = text
197
+ const translations = [...helpTranslations].sort(([left], [right]) => right.length - left.length)
198
+ for (const [source, target] of translations) localized = localized.replaceAll(source, target)
199
+ return localized
200
+ }
201
+
202
+ const commandHelp = {
203
+ init: `Usage: ${brand.commandName} init <dir> [options]
204
+
205
+ Create a new mini program project.
206
+
207
+ Options:
208
+ --app-id <id> Initial app id
209
+ --name <name> Initial project name
210
+ --server-url <url> Signed service base URL
211
+ --key <key> Initial CLI key
212
+ --force Allow writing into a non-empty directory
213
+ --no-interactive Disable interactive prompts
214
+ --json Print machine-readable JSON`,
215
+ inspect: `Usage: ${brand.commandName} inspect [options]
216
+
217
+ Inspect project metadata and configuration diagnostics.
218
+
219
+ Options:
220
+ --project <path> Project path
221
+ --json Print machine-readable JSON`,
222
+ dev: `Usage: ${brand.commandName} dev [options]
223
+
224
+ Start local development with the H5 container and live reload.
225
+
226
+ Options:
227
+ --project <path> Mini program project path
228
+ --out <path> Output directory, defaults to dist/dev
229
+ --host <host> Preview host
230
+ --port <port> Preview port, use 0 for a random free port
231
+ --container-dir <path> Web container dist directory
232
+ --compiler-module <path> Use a local compiler module
233
+ --no-open Do not open the browser automatically
234
+ --json Print lifecycle events as JSON Lines`,
235
+ build: `Usage: ${brand.commandName} build [options]
236
+
237
+ Build a client .wgt delivery package.
238
+
239
+ Options:
240
+ --project <path> Mini program project path
241
+ --out <path> Output directory, defaults to dist/release
242
+ --version-name <name> Package version name
243
+ --version-code <n> Package version code
244
+ --version <version> Alias of --version-name
245
+ --source-dir <path> Package an existing compiled output
246
+ --compiled-dir <path> Alias of --source-dir
247
+ --compiler-module <path> Use a local compiler module
248
+ --json Print machine-readable JSON`,
249
+ upload: `Usage: ${brand.commandName} upload [options]
250
+
251
+ Build and upload a signed service trial package.
252
+
253
+ Options:
254
+ --project <path> Mini program project path
255
+ --out <path> Output directory, defaults to dist/release
256
+ --server-url <url> Signed service base URL
257
+ --app-id <id> Override project app id
258
+ --profile <name> User-level service profile name
259
+ --key <key> Signed service key
260
+ --version-name <name> Package version name
261
+ --version-code <n> Package version code
262
+ --preview Return trial preview information
263
+ --submit-audit Submit the trial version after upload
264
+ --changelog <text> Upload changelog
265
+ --channel <channel> Service channel
266
+ --provider <module> Provider module or "local-file"
267
+ --build Build before upload
268
+ --json Print machine-readable JSON`,
269
+ debug: `Usage: ${brand.commandName} debug [options]
270
+
271
+ Build and upload a signed debug preview package.
272
+
273
+ Options:
274
+ --project <path> Mini program project path
275
+ --server-url <url> Signed service base URL
276
+ --app-id <id> Override project app id
277
+ --profile <name> User-level service profile name
278
+ --key <key> Signed service key
279
+ --page-path <path> Launch page path
280
+ --query <query> Launch query string
281
+ --scene <scene> Launch scene
282
+ --launch-from <source> Launch source
283
+ --location <location> Launch location
284
+ --qr-format <format> QR output: png, terminal, or none
285
+ --qr-output <path> Write QR output to a file
286
+ --copy Copy the deeplink when supported
287
+ --json Print machine-readable JSON`,
288
+ submit: `Usage: ${brand.commandName} submit [options]
289
+
290
+ Submit a signed service trial version for audit.
291
+
292
+ Options:
293
+ --server-url <url> Signed service base URL
294
+ --app-id <id> Override project app id
295
+ --profile <name> User-level service profile name
296
+ --key <key> Signed service key
297
+ --version-id <id> Service version id
298
+ --version-number <v> Service version number
299
+ --channel <channel> Service channel
300
+ --auto-publish Ask the audit service to publish automatically
301
+ --provider <module> Provider module
302
+ --json Print machine-readable JSON`,
303
+ status: `Usage: ${brand.commandName} status [options]
304
+
305
+ Query signed service version information.
306
+
307
+ Options:
308
+ --server-url <url> Signed service base URL
309
+ --app-id <id> Override project app id
310
+ --profile <name> User-level service profile name
311
+ --key <key> Signed service key
312
+ --provider <module> Provider module
313
+ --json Print machine-readable JSON`,
314
+ config: `Usage: ${brand.commandName} config <subcommand> [options]
315
+
316
+ Subcommands:
317
+ doctor Diagnose signed service configuration
318
+ set Save the current project's CLI key
319
+
320
+ Run "${brand.commandName} config <subcommand> --help" for subcommand options.`,
321
+ 'config set': `Usage: ${brand.commandName} config set [options]
322
+
323
+ Save the current project's CLI key in the user-level CLI config.
324
+
325
+ Options:
326
+ --project <path> Mini program project path
327
+ --app-id <id> Override project app id
328
+ --key <key> CLI key
329
+ --config <path> User-level CLI config path
330
+ --no-interactive Disable interactive prompts
331
+ --json Print machine-readable JSON`,
332
+ 'config doctor': `Usage: ${brand.commandName} config doctor [options]
333
+
334
+ Diagnose signed service configuration without exposing key values.
335
+
336
+ Options:
337
+ --project <path> Mini program project path
338
+ --server-url <url> Signed service base URL
339
+ --app-id <id> Override project app id
340
+ --profile <name> User-level service profile name
341
+ --key <key> Signed service key
342
+ --config <path> User-level CLI config path
343
+ --json Print machine-readable JSON`,
344
+ update: `Usage: ${brand.commandName} update [check] [options]
345
+
346
+ Check for or install a newer CLI version.
347
+
348
+ Options:
349
+ --check Check updates without installing
350
+ --dry-run Check update/install intent without installing
351
+ --registry <url> npm registry for the update
352
+ --npm <command> npm executable to use
353
+ --json Print machine-readable JSON`,
354
+ compile: `Usage: ${brand.commandName} compile [options]
355
+
356
+ Compile a mini program without creating a delivery package.
357
+
358
+ Options:
359
+ --project <path> Mini program project path
360
+ --out <path> Output directory, defaults to dist/build
361
+ --compiler-module <path> Use a local compiler module
362
+ --watch, -w Rebuild on project file changes
363
+ --json Print machine-readable JSON`,
364
+ pack: `Usage: ${brand.commandName} pack [options]
365
+
366
+ Package an existing compiled output as a local archive.
367
+
368
+ Options:
369
+ --project <path> Mini program project path
370
+ --out <path> Output directory, defaults to dist/pack
371
+ --source-dir <path> Already-produced mini app output directory
372
+ --compiled-dir <path> Alias of --source-dir
373
+ --version-name <name> Package version name
374
+ --version-code <n> Package version code
375
+ --json Print machine-readable JSON`,
376
+ 'service-preview': `Usage: ${brand.commandName} service-preview [options]
377
+
378
+ Generate signed service trial preview information.
379
+
380
+ Options:
381
+ --server-url <url> Signed service base URL
382
+ --app-id <id> Override project app id
383
+ --profile <name> User-level service profile name
384
+ --key <key> Signed service key
385
+ --version-id <id> Service version id
386
+ --version-number <v> Service version number
387
+ --provider <module> Provider module
388
+ --json Print machine-readable JSON`,
389
+ 'audit-status': `Usage: ${brand.commandName} audit-status [options]
390
+
391
+ Query signed service audit status.
392
+
393
+ Options:
394
+ --server-url <url> Signed service base URL
395
+ --app-id <id> Override project app id
396
+ --profile <name> User-level service profile name
397
+ --key <key> Signed service key
398
+ --version-id <id> Service version id
399
+ --provider <module> Provider module
400
+ --json Print machine-readable JSON`,
401
+ 'cli-version': `Usage: ${brand.commandName} cli-version [options]
402
+
403
+ Show detailed CLI package information.
404
+
405
+ Options:
406
+ --json Print machine-readable JSON`,
407
+ }
408
+
409
+ for (const [alias, target] of Object.entries({
410
+ wgt: 'build',
411
+ meta: 'status',
412
+ version: 'status',
413
+ 'debug-preview': 'debug',
414
+ 'submit-audit': 'submit',
415
+ })) {
416
+ commandHelp[alias] = `${commandHelp[target]}\n\nCompatibility alias: use "${brand.commandName} ${target}" instead.`
417
+ }
418
+
419
+ commandHelp.audit = `Usage: ${brand.commandName} audit [options]
420
+
421
+ Provider/service compatibility command. Use "${brand.commandName} submit" for the signed service.
422
+
423
+ Options:
424
+ --provider <module> Provider module
425
+ --version-id <id> Service version id
426
+ --version-number <v> Service version number
427
+ --json Print machine-readable JSON`
428
+
429
+ commandHelp.preview = `Usage: ${brand.commandName} preview [options]
430
+
431
+ Legacy local static preview server. Prefer "${brand.commandName} dev".
432
+
433
+ Options:
434
+ --project <path> Mini program project path
435
+ --out <path> Output directory, defaults to dist/preview
436
+ --host <host> Preview host
437
+ --port <port> Preview port
438
+ --stay Keep the preview server running
439
+ --json Print machine-readable JSON`
440
+
441
+ commandHelp.web = `Usage: ${brand.commandName} web [options]
442
+
443
+ Legacy H5 container command. Prefer "${brand.commandName} dev".
444
+
445
+ Options:
446
+ --project <path> Mini program project path
447
+ --out <path> Output directory, defaults to dist/web
448
+ --host <host> Preview host
449
+ --port <port> Preview port
450
+ --watch, -w Rebuild on project file changes
451
+ --no-open Do not open the browser automatically
452
+ --json Print lifecycle events as JSON Lines`
453
+
454
+ commandHelp.login = `Usage: ${brand.commandName} login [options]
455
+
456
+ Provider-specific authentication. The default signed service does not implement login.
457
+
458
+ Options:
459
+ --provider <module> Provider module
460
+ --project <path> Mini program project path
461
+ --json Print machine-readable JSON`
462
+
463
+ const deprecatedCommands = {
464
+ wgt: 'Use `neux build` instead.',
465
+ meta: 'Use `neux status` instead.',
466
+ version: 'Use `neux status` instead.',
467
+ 'debug-preview': 'Use `neux debug` instead.',
468
+ 'submit-audit': 'Use `neux submit` instead.',
469
+ audit: 'Use `neux submit` for the signed service.',
470
+ preview: 'This command is legacy; use `neux dev` for the local H5 workflow.',
471
+ web: 'This command is legacy; use `neux dev` instead.',
472
+ }
473
+
474
+ function formatCommandGroup(group) {
475
+ const width = Math.max(...group.commands.map(([name]) => name.length))
476
+ return `${group.title}:\n${group.commands
477
+ .map(([name, description]) => ` ${name.padEnd(width + 2)}${description}`)
478
+ .join('\n')}`
479
+ }
480
+
481
+ export function rootHelp(locale = 'en') {
482
+ const content = `${translate(locale, 'usage')}: ${brand.commandName} <command> [options]
483
+
484
+ ${commandGroups.map(formatCommandGroup).join('\n\n')}
485
+
486
+ ${translate(locale, 'commonOptions')}:
487
+ ${commonHelp}
488
+
489
+ Run "${brand.commandName} <command> --help" for command-specific options.
490
+ `
491
+ return localizeHelpText(locale, content)
492
+ }
493
+
494
+ export function help(locale = 'en', command, subcommand) {
495
+ const target = subcommand ? `${command} ${subcommand}` : command
496
+ const output = commandHelp[target] || commandHelp[command] || rootHelp(locale)
497
+ if (!commandHelp[target] && !commandHelp[command]) return output
498
+ const localized = localizeHelpText(locale, output)
499
+ return localized.endsWith('\n') ? localized : `${localized}\n`
500
+ }
501
+
502
+ export function warnIfDeprecated(command, locale = 'en') {
503
+ const message = deprecatedCommands[command]
504
+ if (!message) return
505
+ const warning = localizeHelpText(locale, `Warning: \`${brand.commandName} ${command}\` is deprecated. ${message}\n`)
506
+ process.stderr.write(warning)
507
+ }
package/src/core/web.js CHANGED
@@ -192,6 +192,10 @@ export function liveReloadScript() {
192
192
  return `<script>
193
193
  (() => {
194
194
  const source = new EventSource('/__dimina_live_reload');
195
+ let hotUpdateQueue = Promise.resolve();
196
+ let hotUpdateRecoveryTimer = null;
197
+ let hotUpdateRecoveryActive = false;
198
+ let reloadRequested = false;
195
199
  const refreshStylesheets = (doc, timestamp) => {
196
200
  if (!doc) return;
197
201
  for (const link of doc.querySelectorAll('link[rel="stylesheet"][href]')) {
@@ -209,36 +213,66 @@ export function liveReloadScript() {
209
213
  } catch {}
210
214
  }
211
215
  };
216
+ const requestReload = () => {
217
+ if (reloadRequested) return;
218
+ reloadRequested = true;
219
+ window.location.reload();
220
+ };
221
+ const armHotUpdateRecovery = () => {
222
+ hotUpdateRecoveryActive = true;
223
+ clearTimeout(hotUpdateRecoveryTimer);
224
+ hotUpdateRecoveryTimer = setTimeout(() => {
225
+ hotUpdateRecoveryActive = false;
226
+ }, 2000);
227
+ };
228
+ const isDomPatchError = (value) => {
229
+ const message = value?.message || value?.reason?.message || value?.reason || value;
230
+ return /(?:insertBefore|appendChild|removeChild|parentNode)/.test(String(message || ''));
231
+ };
232
+ const recoverFromAsyncHotUpdateError = (event) => {
233
+ if (hotUpdateRecoveryActive && isDomPatchError(event?.error || event)) {
234
+ requestReload();
235
+ }
236
+ };
237
+ window.addEventListener('error', recoverFromAsyncHotUpdateError);
238
+ window.addEventListener('unhandledrejection', recoverFromAsyncHotUpdateError);
212
239
  const applyHotUpdate = (handler, payload) => {
240
+ armHotUpdateRecovery();
213
241
  try {
214
242
  if (typeof handler !== 'function') {
215
- window.location.reload();
243
+ requestReload();
216
244
  return;
217
245
  }
218
246
  const result = handler(payload);
219
247
  if (result && typeof result.then === 'function') {
220
- result.then((handled) => {
221
- if (handled === false || handled == null) window.location.reload();
222
- }).catch(() => window.location.reload());
223
- return;
248
+ return result.then((handled) => {
249
+ if (handled === false || handled == null) requestReload();
250
+ }).catch(() => requestReload());
224
251
  }
225
252
  if (result === false || result == null) {
226
- window.location.reload();
253
+ requestReload();
227
254
  }
255
+ return result;
228
256
  } catch {
229
- window.location.reload();
257
+ requestReload();
230
258
  }
231
259
  };
260
+ const enqueueHotUpdate = (handler, payload) => {
261
+ hotUpdateQueue = hotUpdateQueue
262
+ .then(() => applyHotUpdate(handler, payload))
263
+ .catch(() => requestReload());
264
+ return hotUpdateQueue;
265
+ };
232
266
  source.addEventListener('style-update', refreshAllStylesheets);
233
267
  source.addEventListener('view-update', (event) => {
234
268
  const payload = JSON.parse(event.data || '{}');
235
- applyHotUpdate(window.__diminaHotUpdateView, payload);
269
+ enqueueHotUpdate(window.__diminaHotUpdateView, payload);
236
270
  });
237
271
  source.addEventListener('logic-update', (event) => {
238
272
  const payload = JSON.parse(event.data || '{}');
239
- applyHotUpdate(window.__diminaHotUpdateLogic, payload);
273
+ enqueueHotUpdate(window.__diminaHotUpdateLogic, payload);
240
274
  });
241
- source.addEventListener('reload', () => location.reload());
275
+ source.addEventListener('reload', requestReload);
242
276
  })();
243
277
  </script>`
244
278
  }