weapp-ide-cli 5.0.3 → 5.0.4

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
@@ -110,10 +110,27 @@ weapp config
110
110
  2. 首次运行前可通过 `weapp config` 写入 CLI 路径,也可在 CI 中直接向 `~/.weapp-ide-cli/config.json` 写入。
111
111
  3. 在自动化流程中建议加上 `--qr-output`、`--result-output` 等参数,以便收集产物或日志。
112
112
 
113
+ 推荐在 CI 或非交互脚本里显式启用非交互模式,避免登录失效时卡在按键等待:
114
+
115
+ ```sh
116
+ weapp build-npm -p --non-interactive
117
+ ```
118
+
119
+ 登录重试相关参数:
120
+
121
+ - `--non-interactive`:非交互模式,登录失效时直接失败(退出码语义保留为 `10`)。
122
+ - `--login-retry=never|once|always`:控制登录失效后的重试策略。
123
+ - `--login-retry-timeout=<ms>`:交互重试等待超时(默认 `30000`)。
124
+
125
+ 当检测到以下场景时,会自动启用非交互模式:
126
+
127
+ - `CI=true`
128
+ - `stdin` 非 TTY
129
+
113
130
  ## 常见问题
114
131
 
115
132
  - **命令执行后无反应**:请确认微信开发者工具已开启服务端口,并尝试重新登录或升级工具版本。
116
- - **提示 `需要重新登录` 或 `code: 10`**:表示微信开发者工具登录态失效。请先在工具内完成登录,再回到终端按 `r` 重试;按 `q`、`Esc` 或 `Ctrl+C` 可取消本次命令。
133
+ - **提示 `需要重新登录` 或 `code: 10`**:表示微信开发者工具登录态失效。交互模式下可按 `r` 重试,按 `q`、`Esc` 或 `Ctrl+C` 取消;非交互模式(含 CI / 非TTY)会直接失败返回非 0。
117
134
  - **提示未找到 CLI**:检查配置文件中的路径是否真实存在,可使用绝对路径避免解析误差。
118
135
  - **Linux 环境报错**:需安装社区版工具并将 `wechat-devtools-cli` 加入 `PATH`,否则只能手动指定路径。
119
136
 
@@ -328,6 +328,16 @@ function formatWechatIdeLoginRequiredError(error) {
328
328
  }
329
329
  return lines.join("\n");
330
330
  }
331
+ function createWechatIdeLoginRequiredExitError(error, reason) {
332
+ const summary = formatWechatIdeLoginRequiredError(error);
333
+ const message = reason ? `${reason}
334
+ ${summary}` : summary;
335
+ const loginError = new Error(message);
336
+ loginError.name = "WechatIdeLoginRequiredError";
337
+ loginError.code = 10;
338
+ loginError.exitCode = 10;
339
+ return loginError;
340
+ }
331
341
  function extractLoginRequiredMessage(text) {
332
342
  if (!text) {
333
343
  return "";
@@ -345,9 +355,10 @@ function extractLoginRequiredMessage(text) {
345
355
  }
346
356
  return firstLine.replace(/^\[error\]\s*/i, "").replace(/^error\s*:\s*/i, "").slice(0, 120);
347
357
  }
348
- async function waitForRetryKeypress() {
358
+ async function waitForRetryKeypress(options = {}) {
359
+ const { timeoutMs = 3e4 } = options;
349
360
  if (!process5.stdin.isTTY) {
350
- return false;
361
+ return "cancel";
351
362
  }
352
363
  emitKeypressEvents(process5.stdin);
353
364
  const hasSetRawMode = typeof process5.stdin.setRawMode === "function";
@@ -356,7 +367,13 @@ async function waitForRetryKeypress() {
356
367
  }
357
368
  process5.stdin.resume();
358
369
  return new Promise((resolve) => {
370
+ let settled = false;
371
+ const normalizedTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e4;
372
+ const timeout = setTimeout(() => {
373
+ done("timeout");
374
+ }, normalizedTimeoutMs);
359
375
  const cleanup = () => {
376
+ clearTimeout(timeout);
360
377
  process5.stdin.off("keypress", onKeypress);
361
378
  if (hasSetRawMode) {
362
379
  process5.stdin.setRawMode(false);
@@ -364,6 +381,10 @@ async function waitForRetryKeypress() {
364
381
  process5.stdin.pause();
365
382
  };
366
383
  const done = (value) => {
384
+ if (settled) {
385
+ return;
386
+ }
387
+ settled = true;
367
388
  cleanup();
368
389
  resolve(value);
369
390
  };
@@ -372,23 +393,24 @@ async function waitForRetryKeypress() {
372
393
  return;
373
394
  }
374
395
  if (key.ctrl && key.name === "c") {
375
- done(false);
396
+ done("cancel");
376
397
  return;
377
398
  }
378
399
  if (key.name === "r") {
379
- done(true);
400
+ done("retry");
380
401
  return;
381
402
  }
382
403
  if (key.name === "q" || key.name === "escape") {
383
- done(false);
404
+ done("cancel");
384
405
  }
385
406
  };
386
407
  process5.stdin.on("keypress", onKeypress);
387
408
  });
388
409
  }
389
- function formatRetryHotkeyPrompt() {
410
+ function formatRetryHotkeyPrompt(timeoutMs = 3e4) {
390
411
  const highlight = (key) => highlightHotkey(key);
391
- return `\u6309 ${highlight("r")} \u91CD\u8BD5\uFF0C\u6309 ${highlight("q")} / ${highlight("Esc")} / ${highlight("Ctrl+C")} \u9000\u51FA\u3002`;
412
+ const timeoutSeconds = Math.max(1, Math.ceil(timeoutMs / 1e3));
413
+ return `\u6309 ${highlight("r")} \u91CD\u8BD5\uFF0C\u6309 ${highlight("q")} / ${highlight("Esc")} / ${highlight("Ctrl+C")} \u9000\u51FA\uFF08${timeoutSeconds}s \u5185\u65E0\u8F93\u5165\u5C06\u81EA\u52A8\u5931\u8D25\uFF09\u3002`;
392
414
  }
393
415
  function highlightHotkey(key) {
394
416
  return colors.bold(colors.green(key));
@@ -398,6 +420,9 @@ function highlightHotkey(key) {
398
420
  import process6 from "process";
399
421
  var MINIDEV_NAMESPACE = /* @__PURE__ */ new Set(["alipay", "ali", "minidev"]);
400
422
  var ALIPAY_PLATFORM_ALIASES = /* @__PURE__ */ new Set(["alipay", "ali", "minidev"]);
423
+ function isStdinInteractive() {
424
+ return Boolean(process6.stdin && process6.stdin.isTTY);
425
+ }
401
426
  var ARG_TRANSFORMS = [
402
427
  createAlias({ find: "-p", replacement: "--project" }),
403
428
  createPathCompat("--result-output"),
@@ -414,8 +439,10 @@ async function parse(argv) {
414
439
  return;
415
440
  }
416
441
  const formattedArgv = transformArgv(argv, ARG_TRANSFORMS);
417
- if (shouldDelegateOpenToMinidev(formattedArgv)) {
418
- await runMinidev(createMinidevOpenArgv(formattedArgv));
442
+ const loginRetryOptions = resolveLoginRetryOptions(formattedArgv);
443
+ const runtimeArgv = stripLoginRetryControlFlags(formattedArgv);
444
+ if (shouldDelegateOpenToMinidev(runtimeArgv)) {
445
+ await runMinidev(createMinidevOpenArgv(runtimeArgv));
419
446
  return;
420
447
  }
421
448
  if (!isOperatingSystemSupported(operatingSystemName)) {
@@ -433,11 +460,11 @@ async function parse(argv) {
433
460
  await promptForCliPath();
434
461
  return;
435
462
  }
436
- await runWechatCliWithRetry(cliPath, formattedArgv);
463
+ await runWechatCliWithRetry(cliPath, runtimeArgv, loginRetryOptions);
437
464
  }
438
- async function runWechatCliWithRetry(cliPath, argv) {
439
- let retrying = true;
440
- while (retrying) {
465
+ async function runWechatCliWithRetry(cliPath, argv, options) {
466
+ let retryCount = 0;
467
+ while (true) {
441
468
  try {
442
469
  const result = await execute(cliPath, argv, {
443
470
  pipeStdout: false,
@@ -447,31 +474,96 @@ async function runWechatCliWithRetry(cliPath, argv) {
447
474
  flushExecutionOutput(result);
448
475
  return;
449
476
  }
450
- retrying = await promptLoginRetry(result);
451
- if (retrying) {
477
+ const action = await promptLoginRetry(result, options, retryCount);
478
+ if (action === "retry") {
479
+ retryCount += 1;
452
480
  logger_default.info("\u6B63\u5728\u91CD\u8BD5\u8FDE\u63A5\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177...");
481
+ continue;
453
482
  }
483
+ throw createWechatIdeLoginRequiredExitError(result);
454
484
  } catch (error) {
455
485
  if (!isWechatIdeLoginRequiredError(error)) {
456
486
  throw error;
457
487
  }
458
- retrying = await promptLoginRetry(error);
459
- if (retrying) {
488
+ const action = await promptLoginRetry(error, options, retryCount);
489
+ if (action === "retry") {
490
+ retryCount += 1;
460
491
  logger_default.info("\u6B63\u5728\u91CD\u8BD5\u8FDE\u63A5\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177...");
492
+ continue;
461
493
  }
494
+ throw createWechatIdeLoginRequiredExitError(error);
462
495
  }
463
496
  }
464
497
  }
465
- async function promptLoginRetry(errorLike) {
498
+ async function promptLoginRetry(errorLike, options, retryCount) {
499
+ const {
500
+ nonInteractive,
501
+ retryMode,
502
+ retryTimeoutMs
503
+ } = options;
466
504
  logger_default.error("\u68C0\u6D4B\u5230\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u767B\u5F55\u72B6\u6001\u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u540E\u91CD\u8BD5\u3002");
467
505
  logger_default.warn("\u8BF7\u5148\u6253\u5F00\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u5B8C\u6210\u767B\u5F55\u3002");
468
506
  logger_default.warn(formatWechatIdeLoginRequiredError(errorLike));
469
- logger_default.info(formatRetryHotkeyPrompt());
470
- const shouldRetry = await waitForRetryKeypress();
471
- if (!shouldRetry) {
507
+ if (nonInteractive) {
508
+ logger_default.error("\u5F53\u524D\u4E3A\u975E\u4EA4\u4E92\u6A21\u5F0F\uFF0C\u68C0\u6D4B\u5230\u767B\u5F55\u5931\u6548\u540E\u76F4\u63A5\u5931\u8D25\u3002");
509
+ return "cancel";
510
+ }
511
+ const shouldAllowRetry = retryMode === "always" || retryMode === "once" && retryCount < 1;
512
+ if (!shouldAllowRetry) {
513
+ logger_default.info("\u5F53\u524D\u91CD\u8BD5\u7B56\u7565\u4E0D\u5141\u8BB8\u7EE7\u7EED\u91CD\u8BD5\u3002");
514
+ return "cancel";
515
+ }
516
+ logger_default.info(formatRetryHotkeyPrompt(retryTimeoutMs));
517
+ const action = await waitForRetryKeypress({ timeoutMs: retryTimeoutMs });
518
+ if (action === "timeout") {
519
+ logger_default.error(`\u7B49\u5F85\u767B\u5F55\u91CD\u8BD5\u8F93\u5165\u8D85\u65F6\uFF08${retryTimeoutMs}ms\uFF09\uFF0C\u5DF2\u81EA\u52A8\u53D6\u6D88\u3002`);
520
+ return "cancel";
521
+ }
522
+ if (action !== "retry") {
472
523
  logger_default.info("\u5DF2\u53D6\u6D88\u91CD\u8BD5\u3002\u5B8C\u6210\u767B\u5F55\u540E\u8BF7\u91CD\u65B0\u6267\u884C\u5F53\u524D\u547D\u4EE4\u3002");
524
+ return "cancel";
473
525
  }
474
- return shouldRetry;
526
+ return "retry";
527
+ }
528
+ function resolveLoginRetryOptions(argv) {
529
+ const nonInteractiveFlag = readBooleanFlag(argv, "--non-interactive");
530
+ const ciMode = process6.env.CI === "true";
531
+ const nonTtyStdin = !isStdinInteractive();
532
+ const nonInteractive = nonInteractiveFlag || ciMode || nonTtyStdin;
533
+ const retryModeRaw = readOptionValue(argv, "--login-retry");
534
+ const retryMode = normalizeLoginRetryMode(retryModeRaw, nonInteractive);
535
+ const retryTimeoutRaw = readOptionValue(argv, "--login-retry-timeout");
536
+ const retryTimeoutMs = normalizeLoginRetryTimeout(retryTimeoutRaw);
537
+ return {
538
+ nonInteractive,
539
+ retryMode,
540
+ retryTimeoutMs
541
+ };
542
+ }
543
+ function normalizeLoginRetryMode(value, nonInteractive) {
544
+ if (value === "never" || value === "once" || value === "always") {
545
+ return value;
546
+ }
547
+ return nonInteractive ? "never" : "always";
548
+ }
549
+ function normalizeLoginRetryTimeout(value) {
550
+ if (!value) {
551
+ return 3e4;
552
+ }
553
+ const parsed = Number.parseInt(value, 10);
554
+ if (!Number.isFinite(parsed) || parsed <= 0) {
555
+ return 3e4;
556
+ }
557
+ return parsed;
558
+ }
559
+ function readBooleanFlag(argv, optionName) {
560
+ return argv.includes(optionName);
561
+ }
562
+ function stripLoginRetryControlFlags(argv) {
563
+ let next = removeOption(argv, "--login-retry");
564
+ next = removeOption(next, "--login-retry-timeout");
565
+ next = removeOption(next, "--non-interactive");
566
+ return next;
475
567
  }
476
568
  function shouldDelegateOpenToMinidev(argv) {
477
569
  if (argv[0] !== "open") {
@@ -562,6 +654,7 @@ export {
562
654
  isWechatIdeLoginRequiredError,
563
655
  extractExecutionErrorText,
564
656
  formatWechatIdeLoginRequiredError,
657
+ createWechatIdeLoginRequiredExitError,
565
658
  waitForRetryKeypress,
566
659
  formatRetryHotkeyPrompt,
567
660
  parse
package/dist/cli.js CHANGED
@@ -1,11 +1,20 @@
1
1
  import {
2
2
  logger_default,
3
3
  parse
4
- } from "./chunk-A26E3I4U.js";
4
+ } from "./chunk-QTQD5BFV.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import process from "process";
8
8
  var argv = process.argv.slice(2);
9
9
  parse(argv).catch((err) => {
10
10
  logger_default.error(err);
11
+ if (typeof err?.exitCode === "number") {
12
+ process.exitCode = err.exitCode;
13
+ return;
14
+ }
15
+ if (typeof err?.code === "number") {
16
+ process.exitCode = err.code;
17
+ return;
18
+ }
19
+ process.exitCode = 1;
11
20
  });
package/dist/index.d.ts CHANGED
@@ -18,6 +18,10 @@ declare function resolveCliPath(): Promise<{
18
18
  source: ConfigSource;
19
19
  }>;
20
20
 
21
+ interface RetryKeypressOptions {
22
+ timeoutMs?: number;
23
+ }
24
+ type RetryPromptResult = 'retry' | 'cancel' | 'timeout';
21
25
  /**
22
26
  * @description 判断是否为微信开发者工具登录失效错误。
23
27
  */
@@ -30,14 +34,21 @@ declare function extractExecutionErrorText(error: unknown): string;
30
34
  * @description 将登录失效错误格式化为更易读的摘要。
31
35
  */
32
36
  declare function formatWechatIdeLoginRequiredError(error: unknown): string;
37
+ /**
38
+ * @description 创建登录失效专用错误,并携带退出码语义。
39
+ */
40
+ declare function createWechatIdeLoginRequiredExitError(error: unknown, reason?: string): Error & {
41
+ code: number;
42
+ exitCode: number;
43
+ };
33
44
  /**
34
45
  * @description 交互等待用户按键重试,按 r 重试,按 q 或 Ctrl+C 取消。
35
46
  */
36
- declare function waitForRetryKeypress(): Promise<boolean>;
47
+ declare function waitForRetryKeypress(options?: RetryKeypressOptions): Promise<RetryPromptResult>;
37
48
  /**
38
49
  * @description 生成重试按键提示,并高亮关键热键。
39
50
  */
40
- declare function formatRetryHotkeyPrompt(): string;
51
+ declare function formatRetryHotkeyPrompt(timeoutMs?: number): string;
41
52
 
42
53
  /**
43
54
  * @description CLI 入口解析与分发
@@ -144,4 +155,4 @@ declare function execute(cliPath: string, argv: string[], options?: ExecuteOptio
144
155
  */
145
156
  declare function resolvePath(filePath: string): string;
146
157
 
147
- export { type ArgvTransform, type BaseConfig, type ConfigSource, type ResolvedConfig, type SupportedPlatform, SupportedPlatformsMap, createAlias, createCustomConfig, createPathCompat, defaultCustomConfigDirPath, defaultCustomConfigFilePath, execute, extractExecutionErrorText, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getConfig, getDefaultCliPath, isOperatingSystemSupported, isWechatIdeLoginRequiredError, operatingSystemName, parse, promptForCliPath, resolveCliPath, resolvePath, runMinidev, transformArgv, waitForRetryKeypress };
158
+ export { type ArgvTransform, type BaseConfig, type ConfigSource, type ResolvedConfig, type RetryKeypressOptions, type RetryPromptResult, type SupportedPlatform, SupportedPlatformsMap, createAlias, createCustomConfig, createPathCompat, createWechatIdeLoginRequiredExitError, defaultCustomConfigDirPath, defaultCustomConfigFilePath, execute, extractExecutionErrorText, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getConfig, getDefaultCliPath, isOperatingSystemSupported, isWechatIdeLoginRequiredError, operatingSystemName, parse, promptForCliPath, resolveCliPath, resolvePath, runMinidev, transformArgv, waitForRetryKeypress };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  createAlias,
4
4
  createCustomConfig,
5
5
  createPathCompat,
6
+ createWechatIdeLoginRequiredExitError,
6
7
  defaultCustomConfigDirPath,
7
8
  defaultCustomConfigFilePath,
8
9
  execute,
@@ -21,12 +22,13 @@ import {
21
22
  runMinidev,
22
23
  transformArgv,
23
24
  waitForRetryKeypress
24
- } from "./chunk-A26E3I4U.js";
25
+ } from "./chunk-QTQD5BFV.js";
25
26
  export {
26
27
  SupportedPlatformsMap,
27
28
  createAlias,
28
29
  createCustomConfig,
29
30
  createPathCompat,
31
+ createWechatIdeLoginRequiredExitError,
30
32
  defaultCustomConfigDirPath,
31
33
  defaultCustomConfigFilePath,
32
34
  execute,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weapp-ide-cli",
3
3
  "type": "module",
4
- "version": "5.0.3",
4
+ "version": "5.0.4",
5
5
  "description": "让微信开发者工具,用起来更加方便!",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",