@neuxnet/neux-cli 0.2.3

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.
Files changed (73) hide show
  1. package/README.md +438 -0
  2. package/README.zh-CN.md +554 -0
  3. package/assets/container/assets/index.css +1 -0
  4. package/assets/container/assets/index.js +137 -0
  5. package/assets/container/assets/pageFrame.css +1 -0
  6. package/assets/container/assets/pageFrame.js +56 -0
  7. package/assets/container/assets/service.js +6 -0
  8. package/assets/container/assets/vconsole.js +931 -0
  9. package/assets/container/favicon.ico +0 -0
  10. package/assets/container/images/icon-arrow.png +0 -0
  11. package/assets/container/images/mini-action-white.png +0 -0
  12. package/assets/container/images/mini-action.png +0 -0
  13. package/assets/container/images/mini-arrow-left-white.png +0 -0
  14. package/assets/container/images/mini-arrow-left.jpg +0 -0
  15. package/assets/container/images/mini-arrow-left.png +0 -0
  16. package/assets/container/images/mini-close-white.png +0 -0
  17. package/assets/container/images/mini-close.png +0 -0
  18. package/assets/container/images/more.png +0 -0
  19. package/assets/container/images/search.jpg +0 -0
  20. package/assets/container/index.html +1 -0
  21. package/assets/container/pageFrame.html +1 -0
  22. package/assets/init/tabbar/home-active.png +0 -0
  23. package/assets/init/tabbar/home.png +0 -0
  24. package/assets/init/tabbar/list-active.png +0 -0
  25. package/assets/init/tabbar/list.png +0 -0
  26. package/assets/init/types/neux-api.d.ts +1402 -0
  27. package/package.json +68 -0
  28. package/scripts/generate-init-types.js +210 -0
  29. package/scripts/sync-compiler.js +22 -0
  30. package/scripts/sync-web-container.js +34 -0
  31. package/src/bin/cli.js +646 -0
  32. package/src/core/brand.js +11 -0
  33. package/src/core/compiler.js +305 -0
  34. package/src/core/defaults.js +12 -0
  35. package/src/core/dev.js +15 -0
  36. package/src/core/errors.js +17 -0
  37. package/src/core/fs.js +66 -0
  38. package/src/core/i18n.js +37 -0
  39. package/src/core/init.js +866 -0
  40. package/src/core/lifecycle.js +32 -0
  41. package/src/core/manifest.js +72 -0
  42. package/src/core/pack.js +156 -0
  43. package/src/core/package-info.js +27 -0
  44. package/src/core/preview-server.js +123 -0
  45. package/src/core/project.js +101 -0
  46. package/src/core/prompts.js +71 -0
  47. package/src/core/proxy-security.js +141 -0
  48. package/src/core/proxy.js +156 -0
  49. package/src/core/qr.js +41 -0
  50. package/src/core/terminal-qr.js +72 -0
  51. package/src/core/update.js +278 -0
  52. package/src/core/watch.js +113 -0
  53. package/src/core/web.js +649 -0
  54. package/src/core/zip.js +120 -0
  55. package/src/index.js +20 -0
  56. package/src/providers/service-client.js +149 -0
  57. package/src/providers/service-config.js +264 -0
  58. package/src/providers/service.js +146 -0
  59. package/src/providers/upload.js +112 -0
  60. package/vendor/dimina-compiler/bin/index.cjs +265 -0
  61. package/vendor/dimina-compiler/bin/index.js +263 -0
  62. package/vendor/dimina-compiler/compatibility-B-DoZtUX.cjs +395 -0
  63. package/vendor/dimina-compiler/compatibility-Cl3-DO6V.js +366 -0
  64. package/vendor/dimina-compiler/core/logic-compiler.cjs +378 -0
  65. package/vendor/dimina-compiler/core/logic-compiler.js +374 -0
  66. package/vendor/dimina-compiler/core/style-compiler.cjs +392 -0
  67. package/vendor/dimina-compiler/core/style-compiler.js +377 -0
  68. package/vendor/dimina-compiler/core/view-compiler.cjs +1601 -0
  69. package/vendor/dimina-compiler/core/view-compiler.js +1582 -0
  70. package/vendor/dimina-compiler/index.cjs +762 -0
  71. package/vendor/dimina-compiler/index.js +751 -0
  72. package/vendor/dimina-compiler/sourcemap-BgtIgqkC.cjs +1377 -0
  73. package/vendor/dimina-compiler/sourcemap-CKjhV9h7.js +1135 -0
package/src/bin/cli.js ADDED
@@ -0,0 +1,646 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs/promises'
4
+ import path from 'node:path'
5
+ import { spawnSync } from 'node:child_process'
6
+ import { buildProject, createLifecycleEvent, createProjectWatcher, DEFAULT_SERVER_URL, getCliPackageInfo, getCliVersion, initProject, inspectProject, maybeAutoUpdateCli, packProject, saveCliKey, startDev, startPreview, startWeb, updateCli } from '../index.js'
7
+ import { DiminaCliError, toErrorPayload } from '../core/errors.js'
8
+ import { brand } from '../core/brand.js'
9
+ import { runProviderCommand, unsupportedProviderCommand } from '../providers/upload.js'
10
+ import { resolveServiceConfig, resolveServiceConfigDiagnostics } from '../providers/service-config.js'
11
+ import { renderQrPng, renderTerminalQr } from '../core/terminal-qr.js'
12
+
13
+ const signalExitCodes = {
14
+ SIGHUP: 129,
15
+ SIGINT: 0,
16
+ SIGTERM: 143,
17
+ }
18
+
19
+ function createSessionSignalController() {
20
+ let session = null
21
+ let pendingSignal = null
22
+ let shuttingDown = false
23
+
24
+ const shutdown = signal => {
25
+ if (shuttingDown) return
26
+ if (!session) {
27
+ pendingSignal = signal
28
+ return
29
+ }
30
+
31
+ shuttingDown = true
32
+ void session.close()
33
+ .then(() => process.exit(signalExitCodes[signal] ?? 1))
34
+ .catch(error => {
35
+ console.error(error)
36
+ process.exit(1)
37
+ })
38
+ }
39
+
40
+ for (const signal of Object.keys(signalExitCodes)) {
41
+ process.once(signal, () => shutdown(signal))
42
+ }
43
+
44
+ return {
45
+ setSession(nextSession) {
46
+ session = nextSession
47
+ if (pendingSignal) shutdown(pendingSignal)
48
+ },
49
+ wait() {
50
+ return new Promise(() => {})
51
+ },
52
+ }
53
+ }
54
+ import { resolveLocale, translate } from '../core/i18n.js'
55
+ import { promptLine } from '../core/prompts.js'
56
+
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
+
142
+ function parse(argv) {
143
+ const args = [...argv]
144
+ const command = args.shift()
145
+ const options = { _: [] }
146
+
147
+ for (let i = 0; i < args.length; i++) {
148
+ const arg = args[i]
149
+ const next = () => args[++i]
150
+ if (arg === '--project' || arg === '-p') options.project = next()
151
+ else if (arg === '--out' || arg === '-o') options.out = next()
152
+ else if (arg === '--app-id') options.appId = next()
153
+ else if (arg === '--name') options.name = next()
154
+ else if (arg === '--entry-path') options.entryPath = next()
155
+ else if (arg === '--source-dir') options.sourceDir = next()
156
+ else if (arg === '--compiled-dir') options.compiledDir = next()
157
+ else if (arg === '--version-code') options.versionCode = next()
158
+ else if (arg === '--version') options.version = next()
159
+ else if (arg === '--version-name') options.versionName = next()
160
+ else if (arg === '--host') options.host = next()
161
+ else if (arg === '--port') options.port = next()
162
+ else if (arg === '--container-dir') options.containerDir = next()
163
+ else if (arg === '--compiler-module') options.compilerModule = next()
164
+ else if (arg === '--provider') options.provider = next()
165
+ else if (arg === '--provider-out') options.providerOut = next()
166
+ else if (arg === '--server-url') options.serverUrl = next()
167
+ else if (arg === '--lang' || arg === '--locale') options.lang = next()
168
+ else if (arg === '--registry') options.registry = next()
169
+ else if (arg === '--npm') options.npmCommand = next()
170
+ else if (arg === '--profile') options.profile = next()
171
+ else if (arg === '--key') options.key = next()
172
+ else if (arg === '--config') options.config = next()
173
+ else if (arg === '--desc') options.desc = next()
174
+ else if (arg === '--changelog' || arg === '--app-changelog') options.changelog = next()
175
+ else if (arg === '--channel') options.channel = next()
176
+ else if (arg === '--page-path' || arg === '--miniapp-path') options.pagePath = next()
177
+ else if (arg === '--query' || arg === '--miniapp-query') options.query = next()
178
+ else if (arg === '--scene' || arg === '--miniapp-scene') options.scene = next()
179
+ else if (arg === '--launch-from' || arg === '--miniapp-launch-from') options.launchFrom = next()
180
+ else if (arg === '--location' || arg === '--miniapp-location') options.location = next()
181
+ else if (arg === '--qr-format' || arg === '--qrcode-format') options.qrFormat = next()
182
+ else if (arg === '--qr-output' || arg === '--qrcode-output') options.qrOutput = next()
183
+ else if (arg === '--proxy') options.proxy = next()
184
+ else if (arg === '--version-id') options.versionId = next()
185
+ else if (arg === '--version-number') options.versionNumber = next()
186
+ else if (arg === '--preview') options.preview = true
187
+ else if (arg === '--submit-audit') options.submitAudit = true
188
+ else if (arg === '--auto-publish') options.autoPublish = true
189
+ else if (arg === '--auto-update') options.autoUpdate = true
190
+ else if (arg === '--no-auto-update') options.autoUpdate = false
191
+ else if (arg === '--check') options.check = true
192
+ else if (arg === '--dry-run') options.dryRun = true
193
+ else if (arg === '--copy') options.copy = true
194
+ else if (arg === '--build') options.build = true
195
+ else if (arg === '--no-build') options.build = false
196
+ else if (arg === '--no-open') options.open = false
197
+ else if (arg === '--json') options.json = true
198
+ else if (arg === '--stay') options.stay = true
199
+ else if (arg === '--watch' || arg === '-w') options.watch = true
200
+ else if (arg === '--force') options.force = true
201
+ else if (arg === '--interactive') options.interactive = true
202
+ else if (arg === '--no-interactive') options.noInteractive = true
203
+ else if (arg === '--sourcemap') options.sourcemap = true
204
+ else if (arg === '--help' || arg === '-h') options.help = true
205
+ else if (arg.startsWith('--')) {
206
+ const [key, value] = arg.slice(2).split('=')
207
+ options[key.replaceAll('-', '_')] = value ?? true
208
+ }
209
+ else options._.push(arg)
210
+ }
211
+
212
+ return { command, options }
213
+ }
214
+
215
+ function jsonSafe(value) {
216
+ if (!value || typeof value !== 'object') return value
217
+ const { close, artifact, ...rest } = value
218
+ return artifact ? { ...rest, artifact } : rest
219
+ }
220
+
221
+ function outputOptions(value) {
222
+ return typeof value === 'object' && value !== null ? value : { json: !!value }
223
+ }
224
+
225
+ function copyToClipboard(value) {
226
+ if (!value || process.platform !== 'darwin') return false
227
+ const copied = spawnSync('pbcopy', { input: String(value), encoding: 'utf8' })
228
+ return copied.status === 0
229
+ }
230
+
231
+ async function withQrOutput(result, options) {
232
+ if (!result?.qrPayload) return result
233
+ const next = { ...result }
234
+ const qrFormat = resolveQrFormat(result, options)
235
+ if (options.copy) next.copied = copyToClipboard(result.qrPayload)
236
+ const shouldWriteDefaultPng = qrFormat === 'png' && (!options.json || options.qrFormat)
237
+ const defaultPngPath = options.defaultQrOutput
238
+ || path.join(options.out || 'dist/release', `${result.command || 'preview'}-qr.png`)
239
+ const outputPath = options.qrOutput
240
+ ? path.resolve(options.qrOutput)
241
+ : (shouldWriteDefaultPng ? path.resolve(defaultPngPath) : null)
242
+ if (outputPath) {
243
+ await fs.mkdir(path.dirname(outputPath), { recursive: true })
244
+ if (qrFormat === 'png') {
245
+ await fs.writeFile(outputPath, await renderQrPng(result.qrPayload))
246
+ }
247
+ else {
248
+ const content = qrFormat === 'none'
249
+ ? `${String(result.qrPayload)}\n`
250
+ : await renderTerminalQr(result.qrPayload)
251
+ await fs.writeFile(outputPath, content)
252
+ }
253
+ next.qrOutputPath = outputPath
254
+ next.qrFormat = qrFormat
255
+ }
256
+ return next
257
+ }
258
+
259
+ function resolveQrFormat(result, options) {
260
+ const explicitFormat = options.qrFormat && normalizeQrFormat(options.qrFormat)
261
+ if (explicitFormat) return explicitFormat
262
+ if (options.qrOutput) return 'terminal'
263
+ return 'terminal'
264
+ }
265
+
266
+ function normalizeQrFormat(value) {
267
+ const qrFormat = String(value).trim().toLowerCase()
268
+ if (!['png', 'terminal', 'none'].includes(qrFormat)) {
269
+ throw new DiminaCliError('NEUX_CLI_QR_FORMAT_INVALID', `Unsupported QR output format: ${value}`, {
270
+ qrFormat: value,
271
+ supported: ['png', 'terminal', 'none'],
272
+ })
273
+ }
274
+ return qrFormat
275
+ }
276
+
277
+ async function writeResult(result, rawOptions) {
278
+ const options = outputOptions(rawOptions)
279
+ const locale = resolveLocale(options)
280
+ result = await withQrOutput(result, options)
281
+ const qrFormat = resolveQrFormat(result, options)
282
+ if (options.json) {
283
+ process.stdout.write(`${JSON.stringify(jsonSafe(result), null, 2)}\n`)
284
+ return
285
+ }
286
+ process.stdout.write(`${result.command === 'init' ? translate(locale, 'initOk') : `${result.command} ok`}\n`)
287
+ if (result.outputPath) process.stdout.write(`${translate(locale, 'outputPath')}: ${result.outputPath}\n`)
288
+ if (result.outputDir) process.stdout.write(`${translate(locale, 'outputDir')}: ${result.outputDir}\n`)
289
+ if (result.packagePath) process.stdout.write(`${translate(locale, 'packagePath')}: ${result.packagePath}\n`)
290
+ if (result.manifestPath) process.stdout.write(`manifestPath: ${result.manifestPath}\n`)
291
+ if (result.sha256) process.stdout.write(`sha256: ${result.sha256}\n`)
292
+ if (result.innerPackageName) process.stdout.write(`innerPackageName: ${result.innerPackageName}\n`)
293
+ if (result.packageName) process.stdout.write(`packageName: ${result.packageName}\n`)
294
+ if (result.packageRoot) process.stdout.write(`packageRoot: ${result.packageRoot}\n`)
295
+ if (result.currentVersion) process.stdout.write(`currentVersion: ${result.currentVersion}\n`)
296
+ if (result.latestVersion) process.stdout.write(`latestVersion: ${result.latestVersion}\n`)
297
+ if (result.updateAvailable !== undefined) process.stdout.write(`updateAvailable: ${result.updateAvailable}\n`)
298
+ if (result.installed !== undefined) process.stdout.write(`installed: ${result.installed}\n`)
299
+ if (result.target) process.stdout.write(`target: ${result.target}\n`)
300
+ if (result.registry) process.stdout.write(`registry: ${result.registry}\n`)
301
+ if (result.serverUrl) process.stdout.write(`${translate(locale, 'serverUrl')}: ${result.serverUrl}\n`)
302
+ if (result.deepLink) process.stdout.write(`deepLink: ${result.deepLink}\n`)
303
+ if (result.qrOutputPath) process.stdout.write(`qrOutputPath: ${result.qrOutputPath}\n`)
304
+ if (result.qrFormat) process.stdout.write(`qrFormat: ${result.qrFormat}\n`)
305
+ if (result.copied !== undefined) process.stdout.write(`copied: ${result.copied}\n`)
306
+ if (result.command === 'config doctor') {
307
+ process.stdout.write(`key: ${result.key?.present ? 'configured' : 'missing'}\n`)
308
+ if (result.missing?.length) process.stdout.write(`missing: ${result.missing.join(', ')}\n`)
309
+ }
310
+ if (result.qrPayload && qrFormat === 'terminal') {
311
+ process.stdout.write('\n')
312
+ process.stdout.write(await renderTerminalQr(result.qrPayload))
313
+ }
314
+ }
315
+
316
+ function formatErrorPayload(payload, locale = 'en') {
317
+ const lines = [`${payload.code}: ${payload.message}`]
318
+ const suggestions = payload.details?.suggestions
319
+ if (payload.code === 'NEUX_CLI_CONFIG_MISSING' && Array.isArray(suggestions) && suggestions.length > 0) {
320
+ lines.push('', translate(locale, 'suggestedFixes'))
321
+ for (const suggestion of suggestions) lines.push(` ${suggestion}`)
322
+ }
323
+ return `${lines.join('\n')}\n`
324
+ }
325
+
326
+ function writeJsonEvent(event, payload = {}) {
327
+ process.stdout.write(`${JSON.stringify(jsonSafe(createLifecycleEvent(event, payload)))}\n`)
328
+ }
329
+
330
+ function writeLifecycleEvent(enabled, payload) {
331
+ if (!enabled) return
332
+ process.stdout.write(`${JSON.stringify(jsonSafe(payload))}\n`)
333
+ }
334
+
335
+ async function withJsonLogRedirect(enabled, action) {
336
+ if (!enabled) return await action()
337
+
338
+ const originalWrite = process.stdout.write.bind(process.stdout)
339
+ process.stdout.write = (chunk, encoding, callback) => process.stderr.write(chunk, encoding, callback)
340
+ try {
341
+ return await action()
342
+ }
343
+ finally {
344
+ process.stdout.write = originalWrite
345
+ }
346
+ }
347
+
348
+ async function main() {
349
+ const { command, options } = parse(process.argv.slice(2))
350
+ const locale = resolveLocale(options)
351
+ if (command === '--version' || command === '-v') {
352
+ process.stdout.write(`${await getCliVersion()}\n`)
353
+ return
354
+ }
355
+ if (!command || command === '--help' || options.help) {
356
+ process.stdout.write(help(locale))
357
+ return
358
+ }
359
+ if (options.qrFormat) normalizeQrFormat(options.qrFormat)
360
+
361
+ if (command !== 'update') {
362
+ try {
363
+ await maybeAutoUpdateCli({ ...options, silent: true })
364
+ }
365
+ catch (error) {
366
+ process.stderr.write(`NEUX_CLI_AUTO_UPDATE_SKIPPED: ${error.message}\n`)
367
+ }
368
+ }
369
+
370
+ async function runCompileCommand(commandName) {
371
+ const compileOptions = { ...options, out: options.out || 'dist/build' }
372
+ if (options.watch && options.json) writeJsonEvent('build-start', { command: commandName })
373
+ let result
374
+ try {
375
+ result = await withJsonLogRedirect(options.json, () => buildProject(compileOptions))
376
+ result = { ...result, command: commandName }
377
+ }
378
+ catch (error) {
379
+ if (options.watch && options.json) {
380
+ writeJsonEvent('build-error', { command: commandName, error: toErrorPayload(error) })
381
+ process.exitCode = 1
382
+ return
383
+ }
384
+ throw error
385
+ }
386
+ if (options.watch && options.json) writeJsonEvent('build-success', result)
387
+ else await writeResult(result, options)
388
+ if (options.watch) {
389
+ let rebuilding = false
390
+ let rebuildAgain = false
391
+ const rebuild = async (event) => {
392
+ if (rebuilding) {
393
+ rebuildAgain = true
394
+ return
395
+ }
396
+ rebuilding = true
397
+ try {
398
+ if (options.json) writeJsonEvent('build-start', { command: commandName, changedPath: event?.path })
399
+ const nextResult = await withJsonLogRedirect(options.json, () => buildProject(compileOptions))
400
+ const nextCommandResult = { ...nextResult, command: commandName }
401
+ if (options.json) writeJsonEvent('build-success', nextCommandResult)
402
+ else await writeResult(nextCommandResult, options)
403
+ }
404
+ catch (error) {
405
+ const payload = toErrorPayload(error)
406
+ if (options.json) writeJsonEvent('build-error', { command: commandName, error: payload })
407
+ else process.stderr.write(`${payload.code}: ${payload.message}\n`)
408
+ }
409
+ finally {
410
+ rebuilding = false
411
+ if (rebuildAgain) {
412
+ rebuildAgain = false
413
+ await rebuild()
414
+ }
415
+ }
416
+ }
417
+ const watcher = await createProjectWatcher({
418
+ project: options.project,
419
+ ignorePaths: [result.outputPath],
420
+ onChange: rebuild,
421
+ })
422
+ process.once('SIGINT', () => {
423
+ watcher.close()
424
+ if (options.json) writeJsonEvent('close', { command: commandName })
425
+ process.exit(0)
426
+ })
427
+ return await new Promise(() => {})
428
+ }
429
+ }
430
+
431
+ async function runDeliveryBuild(commandName) {
432
+ return writeResult(await withJsonLogRedirect(options.json, () => packProject({
433
+ ...options,
434
+ command: commandName,
435
+ out: options.out || 'dist/release',
436
+ build: options.build !== false,
437
+ packageExtension: 'wgt',
438
+ })), options)
439
+ }
440
+
441
+ if (command === 'inspect') return writeResult(await withJsonLogRedirect(options.json, () => inspectProject(options)), options)
442
+ if (command === 'init') return writeResult(await initProject(options), options)
443
+ if (command === 'cli-version') {
444
+ const info = await getCliPackageInfo()
445
+ return writeResult({
446
+ ok: true,
447
+ command: 'cli-version',
448
+ packageName: info.packageName,
449
+ currentVersion: info.version,
450
+ packageRoot: info.packageRoot,
451
+ }, options)
452
+ }
453
+ if (command === 'update') {
454
+ const subcommand = options._[0]
455
+ return writeResult(await updateCli({
456
+ ...options,
457
+ check: options.check || subcommand === 'check',
458
+ dryRun: options.dryRun || options.dry_run,
459
+ }), options)
460
+ }
461
+ if (command === 'compile') return await runCompileCommand('compile')
462
+ if (command === 'build') return await runDeliveryBuild('build')
463
+ if (command === 'pack') return writeResult(await withJsonLogRedirect(options.json, () => packProject({ ...options, command: 'pack' })), options)
464
+ if (command === 'wgt') return await runDeliveryBuild('wgt')
465
+ if (command === 'preview') {
466
+ const eventStream = options.json && options.stay
467
+ const signalController = options.stay ? createSessionSignalController() : null
468
+ const session = await startPreview({
469
+ ...options,
470
+ command: 'preview',
471
+ withPackOutputRedirect: action => withJsonLogRedirect(options.json, action),
472
+ onEvent: event => {
473
+ writeLifecycleEvent(eventStream, event)
474
+ return options.onEvent?.(event)
475
+ },
476
+ })
477
+ signalController?.setSession(session)
478
+ if (!eventStream) await writeResult(session, options)
479
+ if (options.stay) {
480
+ return await signalController.wait()
481
+ }
482
+ return await session.close()
483
+ }
484
+ if (command === 'web') {
485
+ const eventStream = options.json && options.watch
486
+ let sawBuildErrorEvent = false
487
+ let session
488
+ const signalController = options.stay || options.watch || options.open !== false
489
+ ? createSessionSignalController()
490
+ : null
491
+ try {
492
+ session = await startWeb({
493
+ ...options,
494
+ withBuildOutputRedirect: action => withJsonLogRedirect(options.json, action),
495
+ onEvent: event => {
496
+ if (event.event === 'build-error') sawBuildErrorEvent = true
497
+ writeLifecycleEvent(eventStream, event)
498
+ return options.onEvent?.(event)
499
+ },
500
+ onBuildStart: payload => {
501
+ return options.onBuildStart?.(payload)
502
+ },
503
+ onRebuild: payload => {
504
+ return options.onRebuild?.(payload)
505
+ },
506
+ onBuildError: error => {
507
+ return options.onBuildError?.(error)
508
+ },
509
+ onReload: payload => {
510
+ return options.onReload?.(payload)
511
+ },
512
+ })
513
+ signalController?.setSession(session)
514
+ }
515
+ catch (error) {
516
+ if (eventStream) {
517
+ if (!sawBuildErrorEvent) writeJsonEvent('build-error', { command: 'web', error: toErrorPayload(error) })
518
+ process.exitCode = 1
519
+ return
520
+ }
521
+ throw error
522
+ }
523
+ if (!eventStream) {
524
+ await writeResult(session, options)
525
+ }
526
+ if (options.stay || options.watch || options.open !== false) {
527
+ return await signalController.wait()
528
+ }
529
+ return await session.close()
530
+ }
531
+ if (command === 'dev') {
532
+ const eventStream = !!options.json
533
+ let sawBuildErrorEvent = false
534
+ let session
535
+ const signalController = createSessionSignalController()
536
+ try {
537
+ session = await startDev({
538
+ ...options,
539
+ withBuildOutputRedirect: action => withJsonLogRedirect(options.json, action),
540
+ onEvent: event => {
541
+ if (event.event === 'build-error') sawBuildErrorEvent = true
542
+ writeLifecycleEvent(eventStream, event)
543
+ return options.onEvent?.(event)
544
+ },
545
+ onBuildStart: payload => {
546
+ return options.onBuildStart?.(payload)
547
+ },
548
+ onRebuild: payload => {
549
+ return options.onRebuild?.(payload)
550
+ },
551
+ onBuildError: error => {
552
+ return options.onBuildError?.(error)
553
+ },
554
+ onReload: payload => {
555
+ return options.onReload?.(payload)
556
+ },
557
+ })
558
+ signalController.setSession(session)
559
+ }
560
+ catch (error) {
561
+ if (eventStream) {
562
+ if (!sawBuildErrorEvent) writeJsonEvent('build-error', { command: 'dev', error: toErrorPayload(error) })
563
+ process.exitCode = 1
564
+ return
565
+ }
566
+ throw error
567
+ }
568
+ if (!eventStream) {
569
+ await writeResult(session, options)
570
+ }
571
+ return await signalController.wait()
572
+ }
573
+ if (command === 'login') {
574
+ if (!options.provider) return await unsupportedProviderCommand(command)
575
+ return writeResult(await runProviderCommand(command, options, {
576
+ project: options.project ? await inspectProject(options) : null,
577
+ }), options)
578
+ }
579
+ if (command === 'config') {
580
+ const subcommand = options._[0] || 'doctor'
581
+ if (subcommand === 'set') {
582
+ const project = await inspectProject(options)
583
+ if (!options.key && options.noInteractive === true) {
584
+ throw new DiminaCliError('NEUX_CLI_KEY_REQUIRED', 'CLI Key is required in non-interactive mode. Pass --key <key>.')
585
+ }
586
+ const key = options.key || await promptLine('CLI Key: ', { secret: true })
587
+ const result = await saveCliKey({ appId: options.appId || project.appId, key, configPath: options.config })
588
+ return writeResult({ ok: true, command: 'config set', ...result, serverUrl: project.neuxCli?.serverUrl || DEFAULT_SERVER_URL }, options)
589
+ }
590
+ if (subcommand !== 'doctor') {
591
+ throw new DiminaCliError('DIMINA_UNKNOWN_COMMAND', `Unknown config command: ${subcommand}`, { command: 'config', subcommand })
592
+ }
593
+ return writeResult(await resolveServiceConfigDiagnostics(options), options)
594
+ }
595
+ if ((command === 'audit' || command === 'submit') && (!options.provider || options.provider === 'service')) {
596
+ return writeResult(await runProviderCommand('submit-audit', options, {}), options)
597
+ }
598
+ if (command === 'status' || command === 'meta') {
599
+ return writeResult(await runProviderCommand('version', options, {}), options)
600
+ }
601
+ if (command === 'upload' || command === 'debug' || command === 'debug-preview' || command === 'audit' || command === 'submit') {
602
+ const providerCommand = command === 'debug' ? 'debug-preview' : command
603
+ const serviceProvider = !options.provider || options.provider === 'service'
604
+ const servicePackage = serviceProvider
605
+ if (servicePackage) await resolveServiceConfig(options)
606
+ const shouldBuild = servicePackage && !options.sourceDir && !options.compiledDir
607
+ ? options.build !== false
608
+ : options.build === true
609
+ const artifact = await withJsonLogRedirect(options.json, () => packProject({
610
+ ...options,
611
+ command: servicePackage ? 'wgt' : command,
612
+ out: servicePackage ? options.out || 'dist/release' : options.out,
613
+ build: shouldBuild,
614
+ packageExtension: servicePackage ? 'wgt' : undefined,
615
+ }))
616
+ const result = await runProviderCommand(providerCommand, options, {
617
+ artifact,
618
+ project: {
619
+ projectPath: artifact.projectPath,
620
+ appId: artifact.appId,
621
+ },
622
+ })
623
+ return writeResult(result, {
624
+ ...options,
625
+ defaultQrOutput: providerCommand === 'debug-preview'
626
+ ? path.join(artifact.outputDir, 'debug-preview-qr.png')
627
+ : undefined,
628
+ })
629
+ }
630
+ if (command === 'service-preview' || command === 'submit-audit' || command === 'version' || command === 'audit-status') {
631
+ return writeResult(await runProviderCommand(command, options, {}), options)
632
+ }
633
+
634
+ throw new DiminaCliError('DIMINA_UNKNOWN_COMMAND', `Unknown command: ${command}`, { command })
635
+ }
636
+
637
+ main().catch((error) => {
638
+ const payload = toErrorPayload(error)
639
+ if (process.argv.includes('--json')) {
640
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`)
641
+ }
642
+ else {
643
+ process.stderr.write(formatErrorPayload(payload, resolveLocale(parse(process.argv.slice(2)).options)))
644
+ }
645
+ process.exitCode = 1
646
+ })
@@ -0,0 +1,11 @@
1
+ export const brand = {
2
+ packageName: '@neuxnet/neux-cli',
3
+ commandName: 'neux',
4
+ serviceClientName: 'neux-cli',
5
+ displayName: 'Neux CLI',
6
+ compilerPackageName: '@dimina/compiler',
7
+ }
8
+
9
+ export function commandExample(command) {
10
+ return `${brand.commandName} ${command}`
11
+ }