weapp-ide-cli 5.1.1 → 5.1.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.
@@ -1,10 +1,10 @@
1
- import { S as validateLocaleOption, a as navigateBack, b as configureLocaleFromArgv, c as pageStack, d as remote, f as scrollTo, g as tap, i as input, l as reLaunch, m as systemInfo, o as navigateTo, p as switchTab, r as currentPage, s as pageData, t as audit, u as redirectTo, v as colors, x as i18nText, y as logger_default } from "./commands-9F3ycbXU.js";
2
- import process, { stdin, stdout } from "node:process";
1
+ import { A as createLocaleConfig, B as operatingSystemName, E as resolveCliPath, F as defaultCustomConfigFilePath, H as logger_default, I as resolvePath, M as readCustomConfig, N as removeCustomConfigKey, O as getConfiguredLocale, V as colors, _ as connectMiniProgram, a as navigateBack, b as i18nText, c as pageStack, d as remote, f as scrollTo, g as tap, i as input, j as overwriteCustomConfig, k as createCustomConfig, l as reLaunch, m as systemInfo, o as navigateTo, p as switchTab, r as currentPage, s as pageData, t as audit, u as redirectTo, x as validateLocaleOption, y as configureLocaleFromArgv, z as isOperatingSystemSupported } from "./commands-CSbpftLN.js";
3
2
  import fs from "fs-extra";
4
- import path from "pathe";
5
- import os from "node:os";
3
+ import process, { stdin, stdout } from "node:process";
6
4
  import { createInterface } from "node:readline/promises";
5
+ import { inspect } from "node:util";
7
6
  import { emitKeypressEvents } from "node:readline";
7
+ import { cac } from "cac";
8
8
  //#region src/cli/automator-argv.ts
9
9
  /**
10
10
  * @description 解析 automator 命令通用参数与位置参数。
@@ -182,7 +182,7 @@ async function runScreenshot(argv) {
182
182
  }
183
183
  const options = parseScreenshotArgs(argv);
184
184
  const isJsonOutput = argv.includes("--json");
185
- const { takeScreenshot } = await import("./commands-9F3ycbXU.js").then((n) => n.n);
185
+ const { takeScreenshot } = await import("./commands-CSbpftLN.js").then((n) => n.n);
186
186
  const result = await takeScreenshot(options);
187
187
  if (isJsonOutput) {
188
188
  console.log(JSON.stringify(result, null, 2));
@@ -192,6 +192,43 @@ async function runScreenshot(argv) {
192
192
  }
193
193
  //#endregion
194
194
  //#region src/cli/run-automator.ts
195
+ const COMMON_OPTION_DEFINITIONS = [
196
+ {
197
+ flag: "-p, --project <path>",
198
+ description: {
199
+ zh: "项目路径(默认:当前目录)",
200
+ en: "Project path (default: current directory)"
201
+ }
202
+ },
203
+ {
204
+ flag: "-t, --timeout <ms>",
205
+ description: {
206
+ zh: "连接超时时间(默认:30000)",
207
+ en: "Connection timeout (default: 30000)"
208
+ }
209
+ },
210
+ {
211
+ flag: "--json",
212
+ description: {
213
+ zh: "支持时以 JSON 输出",
214
+ en: "Output as JSON when supported"
215
+ }
216
+ },
217
+ {
218
+ flag: "--lang <lang>",
219
+ description: {
220
+ zh: "语言切换:zh | en(默认:zh)",
221
+ en: "Language: zh | en (default: zh)"
222
+ }
223
+ },
224
+ {
225
+ flag: "-h, --help",
226
+ description: {
227
+ zh: "显示命令帮助",
228
+ en: "Show command help"
229
+ }
230
+ }
231
+ ];
195
232
  const COMMON_ALLOWED_OPTIONS = new Set([
196
233
  "-p",
197
234
  "--project",
@@ -202,6 +239,27 @@ const COMMON_ALLOWED_OPTIONS = new Set([
202
239
  "-h",
203
240
  "--help"
204
241
  ]);
242
+ function createDefinition(input) {
243
+ return {
244
+ description: input.description,
245
+ usage: input.usage,
246
+ options: input.options ?? [],
247
+ allowedOptions: new Set([...COMMON_ALLOWED_OPTIONS, ...input.allowedOptions ?? []]),
248
+ handler: input.handler
249
+ };
250
+ }
251
+ function requiredPositional(value, errorMessage) {
252
+ if (!value) throw new Error(errorMessage);
253
+ return value;
254
+ }
255
+ function validateUnsupportedOptions(command, argv, allowedOptions) {
256
+ for (const token of argv) {
257
+ if (!token.startsWith("-")) continue;
258
+ const optionName = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
259
+ if (allowedOptions.has(optionName)) continue;
260
+ throw new Error(i18nText(`'${command}' 命令不支持参数 '${optionName}'`, `Command '${command}' does not support option '${optionName}'`));
261
+ }
262
+ }
205
263
  const COMMAND_DEFINITIONS = {
206
264
  "navigate": createDefinition({
207
265
  description: {
@@ -404,85 +462,26 @@ const COMMAND_DEFINITIONS = {
404
462
  })
405
463
  };
406
464
  const AUTOMATOR_COMMAND_NAMES = ["screenshot", ...Object.keys(COMMAND_DEFINITIONS)];
407
- const AUTOMATOR_COMMANDS = new Set(AUTOMATOR_COMMAND_NAMES);
465
+ const AUTOMATOR_COMMAND_SET = new Set(AUTOMATOR_COMMAND_NAMES);
408
466
  /**
409
467
  * @description 判断是否属于 automator 子命令。
410
468
  */
411
469
  function isAutomatorCommand(command) {
412
- return Boolean(command && AUTOMATOR_COMMANDS.has(command));
470
+ return Boolean(command && AUTOMATOR_COMMAND_SET.has(command));
413
471
  }
414
472
  /**
415
- * @description 分发 automator 子命令。
416
- */
417
- async function runAutomatorCommand(command, argv) {
418
- if (command === "screenshot") {
419
- await runScreenshot(argv);
420
- return;
421
- }
422
- const definition = COMMAND_DEFINITIONS[command];
423
- if (!definition) throw new Error(i18nText(`未知 automator 命令: ${command}`, `Unknown automator command: ${command}`));
424
- if (argv.includes("-h") || argv.includes("--help")) {
425
- printCommandHelp(command);
426
- return;
427
- }
428
- validateUnsupportedOptions(command, argv, definition.allowedOptions);
429
- const args = parseAutomatorArgs(argv);
430
- await definition.handler({
431
- argv,
432
- args
433
- });
434
- }
435
- /**
436
- * @description 获取 automator 命令帮助文本。
473
+ * @description 获取 automator 子命令帮助文本。
437
474
  */
438
475
  function getAutomatorCommandHelp(command) {
439
476
  const definition = COMMAND_DEFINITIONS[command];
440
477
  if (!definition) return;
441
- const optionLines = [
442
- ...definition.options,
443
- {
444
- flag: "-p, --project <path>",
445
- description: {
446
- zh: "项目路径(默认:当前目录)",
447
- en: "Project path (default: current directory)"
448
- }
449
- },
450
- {
451
- flag: "-t, --timeout <ms>",
452
- description: {
453
- zh: "连接超时时间(默认:30000)",
454
- en: "Connection timeout (default: 30000)"
455
- }
456
- },
457
- {
458
- flag: "--json",
459
- description: {
460
- zh: "支持时以 JSON 输出",
461
- en: "Output as JSON when supported"
462
- }
463
- },
464
- {
465
- flag: "--lang <lang>",
466
- description: {
467
- zh: "语言切换:zh | en(默认:zh)",
468
- en: "Language: zh | en (default: zh)"
469
- }
470
- },
471
- {
472
- flag: "-h, --help",
473
- description: {
474
- zh: "显示命令帮助",
475
- en: "Show command help"
476
- }
477
- }
478
- ];
479
478
  return [
480
479
  i18nText(definition.description.zh, definition.description.en),
481
480
  "",
482
481
  `Usage: ${definition.usage}`,
483
482
  "",
484
483
  i18nText("参数:", "Options:"),
485
- ...optionLines.map((option) => ` ${option.flag.padEnd(24)} ${i18nText(option.description.zh, option.description.en)}`)
484
+ ...[...definition.options, ...COMMON_OPTION_DEFINITIONS].map((option) => ` ${option.flag.padEnd(24)} ${i18nText(option.description.zh, option.description.en)}`)
486
485
  ].join("\n");
487
486
  }
488
487
  function printCommandHelp(command) {
@@ -493,28 +492,26 @@ function printCommandHelp(command) {
493
492
  }
494
493
  logger_default.warn(i18nText(`命令 ${command} 暂无帮助信息`, `No help available for command: ${command}`));
495
494
  }
496
- function createDefinition(input) {
497
- const options = input.options ?? [];
498
- const allowedOptions = new Set([...COMMON_ALLOWED_OPTIONS, ...input.allowedOptions ?? []]);
499
- return {
500
- description: input.description,
501
- usage: input.usage,
502
- options,
503
- allowedOptions,
504
- handler: input.handler
505
- };
506
- }
507
- function validateUnsupportedOptions(command, argv, allowedOptions) {
508
- for (const token of argv) {
509
- if (!token.startsWith("-")) continue;
510
- const optionName = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
511
- if (allowedOptions.has(optionName)) continue;
512
- throw new Error(i18nText(`'${command}' 命令不支持参数 '${optionName}'`, `Unknown option '${optionName}' for '${command}' command`));
495
+ /**
496
+ * @description 执行 automator 子命令。
497
+ */
498
+ async function runAutomatorCommand(command, argv) {
499
+ if (command === "screenshot") {
500
+ await runScreenshot(argv);
501
+ return;
513
502
  }
514
- }
515
- function requiredPositional(value, message) {
516
- if (!value) throw new Error(message);
517
- return value;
503
+ const definition = COMMAND_DEFINITIONS[command];
504
+ if (!definition) throw new Error(i18nText(`未知 automator 命令: ${command}`, `Unknown automator command: ${command}`));
505
+ if (argv.includes("-h") || argv.includes("--help")) {
506
+ printCommandHelp(command);
507
+ return;
508
+ }
509
+ validateUnsupportedOptions(command, argv, definition.allowedOptions);
510
+ const args = parseAutomatorArgs(argv);
511
+ await definition.handler({
512
+ argv,
513
+ args
514
+ });
518
515
  }
519
516
  //#endregion
520
517
  //#region src/cli/command-catalog.ts
@@ -558,93 +555,6 @@ function isWeappIdeTopLevelCommand(command) {
558
555
  return Boolean(command && WEAPP_IDE_TOP_LEVEL_COMMAND_SET.has(command));
559
556
  }
560
557
  //#endregion
561
- //#region src/utils/path.ts
562
- /**
563
- * @description 解析为绝对路径(基于当前工作目录)
564
- */
565
- function resolvePath(filePath) {
566
- if (path.isAbsolute(filePath)) return filePath;
567
- return path.resolve(process.cwd(), filePath);
568
- }
569
- //#endregion
570
- //#region src/config/paths.ts
571
- const homedir = os.homedir();
572
- /**
573
- * @description 默认自定义配置目录
574
- */
575
- const defaultCustomConfigDirPath = path.join(homedir, ".weapp-ide-cli");
576
- /**
577
- * @description 默认自定义配置文件路径
578
- */
579
- const defaultCustomConfigFilePath = path.join(defaultCustomConfigDirPath, "config.json");
580
- //#endregion
581
- //#region src/config/custom.ts
582
- const JSON_OPTIONS = {
583
- encoding: "utf8",
584
- spaces: 2
585
- };
586
- /**
587
- * @description 写入自定义 CLI 路径配置
588
- */
589
- async function createCustomConfig(params) {
590
- const trimmedCliPath = params.cliPath.trim();
591
- if (!trimmedCliPath) throw new Error("cliPath cannot be empty");
592
- const normalizedCliPath = resolvePath(trimmedCliPath);
593
- await writeCustomConfig({ cliPath: normalizedCliPath });
594
- return normalizedCliPath;
595
- }
596
- /**
597
- * @description 写入语言配置(zh / en)。
598
- */
599
- async function createLocaleConfig(locale) {
600
- await writeCustomConfig({ locale });
601
- return locale;
602
- }
603
- /**
604
- * @description 删除指定配置项。
605
- */
606
- async function removeCustomConfigKey(key) {
607
- const currentConfig = await readCustomConfig();
608
- if (!(key in currentConfig)) return;
609
- const nextConfig = { ...currentConfig };
610
- delete nextConfig[key];
611
- await writeCustomConfig(nextConfig, { replace: true });
612
- }
613
- /**
614
- * @description 覆盖写入配置内容(会替换原内容)。
615
- */
616
- async function overwriteCustomConfig(config) {
617
- const nextConfig = {};
618
- if (typeof config.cliPath === "string" && config.cliPath.trim()) nextConfig.cliPath = resolvePath(config.cliPath.trim());
619
- if (config.locale === "zh" || config.locale === "en") nextConfig.locale = config.locale;
620
- await writeCustomConfig(nextConfig, { replace: true });
621
- }
622
- /**
623
- * @description 读取原始自定义配置。
624
- */
625
- async function readCustomConfig() {
626
- if (!await fs.pathExists(defaultCustomConfigFilePath)) return {};
627
- try {
628
- const config = await fs.readJSON(defaultCustomConfigFilePath);
629
- if (!config || typeof config !== "object") return {};
630
- const candidate = config;
631
- const next = {};
632
- if (typeof candidate.cliPath === "string" && candidate.cliPath.trim()) next.cliPath = candidate.cliPath.trim();
633
- if (candidate.locale === "zh" || candidate.locale === "en") next.locale = candidate.locale;
634
- return next;
635
- } catch {
636
- return {};
637
- }
638
- }
639
- async function writeCustomConfig(patch, options = {}) {
640
- const nextConfig = {
641
- ...options.replace ? {} : await readCustomConfig(),
642
- ...patch
643
- };
644
- await fs.ensureDir(defaultCustomConfigDirPath);
645
- await fs.writeJSON(defaultCustomConfigFilePath, nextConfig, JSON_OPTIONS);
646
- }
647
- //#endregion
648
558
  //#region src/cli/prompt.ts
649
559
  /**
650
560
  * @description 交互式提示并保存 CLI 路径
@@ -680,134 +590,6 @@ async function promptForCliPath() {
680
590
  }
681
591
  }
682
592
  //#endregion
683
- //#region src/runtime/platform.ts
684
- /**
685
- * @description 官方微信开发者工具只支持 Windows、macOS,Linux 只有社区版
686
- * https://github.com/msojocs/wechat-web-devtools-linux
687
- */
688
- const SupportedPlatformsMap = {
689
- Windows_NT: "Windows_NT",
690
- Darwin: "Darwin",
691
- Linux: "Linux"
692
- };
693
- /**
694
- * @description 判断当前系统是否支持微信开发者工具
695
- */
696
- function isOperatingSystemSupported(osName = os.type()) {
697
- return osName === SupportedPlatformsMap.Windows_NT || osName === SupportedPlatformsMap.Darwin || osName === SupportedPlatformsMap.Linux;
698
- }
699
- /**
700
- * @description 当前系统名称
701
- */
702
- const operatingSystemName = os.type();
703
- function createLinuxCliResolver() {
704
- let resolvedPath;
705
- let attempted = false;
706
- let pending = null;
707
- return async () => {
708
- if (attempted) return resolvedPath;
709
- if (!pending) pending = (async () => {
710
- try {
711
- const envPath = await getFirstBinaryPath("wechat-devtools-cli");
712
- if (envPath) resolvedPath = envPath;
713
- } catch (error) {
714
- const reason = error instanceof Error ? error.message : String(error);
715
- logger_default.warn(`获取 Linux wechat-devtools-cli 路径失败:${reason}`);
716
- } finally {
717
- attempted = true;
718
- }
719
- return resolvedPath;
720
- })();
721
- return pending;
722
- };
723
- }
724
- const linuxCliResolver = createLinuxCliResolver();
725
- const WINDOWS_DEFAULT_CLI = "C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat";
726
- const DARWIN_DEFAULT_CLI = "/Applications/wechatwebdevtools.app/Contents/MacOS/cli";
727
- const cliPathResolvers = {
728
- [SupportedPlatformsMap.Windows_NT]: async () => WINDOWS_DEFAULT_CLI,
729
- [SupportedPlatformsMap.Darwin]: async () => DARWIN_DEFAULT_CLI,
730
- [SupportedPlatformsMap.Linux]: linuxCliResolver
731
- };
732
- /**
733
- * @description 获取默认 CLI 路径(按系统)
734
- */
735
- async function getDefaultCliPath(targetOs = operatingSystemName) {
736
- if (!isOperatingSystemSupported(targetOs)) return;
737
- const resolver = cliPathResolvers[targetOs];
738
- return await resolver();
739
- }
740
- async function getFirstBinaryPath(command) {
741
- const pathDirs = (process.env.PATH || "").split(path.delimiter);
742
- for (const dir of pathDirs) {
743
- const fullPath = path.join(dir, command);
744
- try {
745
- await fs.access(fullPath, fs.constants.X_OK);
746
- return fullPath;
747
- } catch {
748
- continue;
749
- }
750
- }
751
- }
752
- //#endregion
753
- //#region src/config/resolver.ts
754
- /**
755
- * @description 读取并解析 CLI 配置(自定义优先)
756
- */
757
- async function getConfig() {
758
- if (await fs.pathExists(defaultCustomConfigFilePath)) try {
759
- const config = await fs.readJSON(defaultCustomConfigFilePath);
760
- const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
761
- const locale = config.locale === "zh" || config.locale === "en" ? config.locale : void 0;
762
- if (cliPath) {
763
- logger_default.info(`全局配置文件路径:${colors.green(defaultCustomConfigFilePath)}`);
764
- logger_default.info(`自定义 CLI 路径:${colors.green(cliPath)}`);
765
- return {
766
- cliPath,
767
- locale,
768
- source: "custom"
769
- };
770
- }
771
- logger_default.warn("自定义配置文件缺少有效的 CLI 路径,将尝试使用默认路径。");
772
- } catch (error) {
773
- const reason = error instanceof Error ? error.message : String(error);
774
- logger_default.warn(`解析自定义配置失败,将尝试使用默认路径。原因:${reason}`);
775
- }
776
- const fallbackPath = await getDefaultCliPath();
777
- if (fallbackPath) return {
778
- cliPath: fallbackPath,
779
- locale: void 0,
780
- source: "default"
781
- };
782
- return {
783
- cliPath: "",
784
- locale: void 0,
785
- source: "missing"
786
- };
787
- }
788
- /**
789
- * @description 获取用户配置的语言偏好。
790
- */
791
- async function getConfiguredLocale() {
792
- return (await readCustomConfig()).locale;
793
- }
794
- //#endregion
795
- //#region src/cli/resolver.ts
796
- /**
797
- * @description 解析 CLI 路径并校验可用性
798
- */
799
- async function resolveCliPath() {
800
- const config = await getConfig();
801
- if (!config.cliPath) return {
802
- cliPath: null,
803
- source: config.source
804
- };
805
- return {
806
- cliPath: await fs.pathExists(config.cliPath) ? config.cliPath : null,
807
- source: config.source
808
- };
809
- }
810
- //#endregion
811
593
  //#region src/cli/config-command.ts
812
594
  /**
813
595
  * @description 处理 config 子命令。
@@ -917,6 +699,123 @@ async function handleConfigCommand(argv) {
917
699
  throw new Error(i18nText("支持的 config 子命令:lang | set-lang | show | get | set | unset | doctor | import | export", "Supported config subcommands: lang | set-lang | show | get | set | unset | doctor | import | export"));
918
700
  }
919
701
  //#endregion
702
+ //#region src/cli/forwardConsole.ts
703
+ const DEFAULT_FORWARD_CONSOLE_LEVELS = [
704
+ "log",
705
+ "info",
706
+ "warn",
707
+ "error"
708
+ ];
709
+ /**
710
+ * @description 启动小程序控制台日志转发,并保持 automator 会话常驻。
711
+ */
712
+ async function startForwardConsole(options) {
713
+ const miniProgram = await connectMiniProgram(options);
714
+ const logLevels = new Set(options.logLevels?.length ? options.logLevels : DEFAULT_FORWARD_CONSOLE_LEVELS);
715
+ const logHandler = options.onLog ?? printForwardConsoleEvent;
716
+ const onConsole = (payload) => {
717
+ const event = normalizeConsoleEvent(payload);
718
+ if (!logLevels.has(event.level)) return;
719
+ logHandler(event);
720
+ };
721
+ const onException = (payload) => {
722
+ if (options.unhandledErrors === false) return;
723
+ logHandler(normalizeExceptionEvent(payload));
724
+ };
725
+ miniProgram.on("console", onConsole);
726
+ miniProgram.on("exception", onException);
727
+ options.onReady?.();
728
+ let closed = false;
729
+ return { async close() {
730
+ if (closed) return;
731
+ closed = true;
732
+ detachMiniProgramListener(miniProgram, "console", onConsole);
733
+ detachMiniProgramListener(miniProgram, "exception", onException);
734
+ await miniProgram.close();
735
+ } };
736
+ }
737
+ function detachMiniProgramListener(miniProgram, event, listener) {
738
+ if (typeof miniProgram.off === "function") miniProgram.off(event, listener);
739
+ }
740
+ function printForwardConsoleEvent(event) {
741
+ const line = `${colors.dim(`[mini:${event.level}]`)} ${event.message}`;
742
+ switch (event.level) {
743
+ case "error":
744
+ logger_default.error(line);
745
+ return;
746
+ case "warn":
747
+ logger_default.warn(line);
748
+ return;
749
+ case "info":
750
+ logger_default.info(line);
751
+ return;
752
+ default: logger_default.log(line);
753
+ }
754
+ }
755
+ function normalizeConsoleEvent(payload) {
756
+ const record = toPlainObject(payload);
757
+ return {
758
+ level: normalizeLogLevel(record.type ?? record.level ?? record.method),
759
+ message: resolveLogMessage(record, payload),
760
+ raw: payload
761
+ };
762
+ }
763
+ function normalizeExceptionEvent(payload) {
764
+ const record = toPlainObject(payload);
765
+ const error = toPlainObject(record.error);
766
+ return {
767
+ level: "error",
768
+ message: [getStringValue(error.message) ?? getStringValue(record.message), getStringValue(error.stack) ?? getStringValue(record.stack)].filter(Boolean).join("\n") || inspect(payload, {
769
+ depth: 4,
770
+ colors: false,
771
+ compact: true
772
+ }),
773
+ raw: payload
774
+ };
775
+ }
776
+ function normalizeLogLevel(value) {
777
+ const normalized = String(value ?? "log").toLowerCase();
778
+ if (normalized === "warning") return "warn";
779
+ if (normalized === "debug" || normalized === "info" || normalized === "warn" || normalized === "error") return normalized;
780
+ return "log";
781
+ }
782
+ function resolveLogMessage(record, payload) {
783
+ const text = getStringValue(record.text) ?? getStringValue(record.message);
784
+ if (text) return text;
785
+ if (Array.isArray(record.args) && record.args.length > 0) return record.args.map(formatConsoleArgument).join(" ");
786
+ if (typeof payload === "string") return payload;
787
+ return inspect(payload, {
788
+ depth: 4,
789
+ colors: false,
790
+ compact: true
791
+ });
792
+ }
793
+ function formatConsoleArgument(value) {
794
+ const record = toPlainObject(value);
795
+ const rawValue = record.value;
796
+ const description = getStringValue(record.description);
797
+ if (typeof rawValue === "string" || typeof rawValue === "number" || typeof rawValue === "boolean") return String(rawValue);
798
+ if (rawValue !== void 0) return inspect(rawValue, {
799
+ depth: 4,
800
+ colors: false,
801
+ compact: true
802
+ });
803
+ if (description) return description;
804
+ if (typeof value === "string") return value;
805
+ return inspect(value, {
806
+ depth: 4,
807
+ colors: false,
808
+ compact: true
809
+ });
810
+ }
811
+ function getStringValue(value) {
812
+ return typeof value === "string" && value.trim() ? value : void 0;
813
+ }
814
+ function toPlainObject(value) {
815
+ if (!value || typeof value !== "object") return {};
816
+ return value;
817
+ }
818
+ //#endregion
920
819
  //#region src/utils/argv.ts
921
820
  function ensurePathArgument(argv, optionIndex) {
922
821
  const paramIdx = optionIndex + 1;
@@ -1069,10 +968,9 @@ async function waitForRetryKeypress(options = {}) {
1069
968
  process.stdin.resume();
1070
969
  return new Promise((resolve) => {
1071
970
  let settled = false;
1072
- const normalizedTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e4;
1073
971
  const timeout = setTimeout(() => {
1074
972
  done("timeout");
1075
- }, normalizedTimeoutMs);
973
+ }, Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e4);
1076
974
  const cleanup = () => {
1077
975
  clearTimeout(timeout);
1078
976
  process.stdin.off("keypress", onKeypress);
@@ -1258,16 +1156,8 @@ function isNonEmptyText(value) {
1258
1156
  }
1259
1157
  //#endregion
1260
1158
  //#region src/cli/run.ts
1261
- const MINIDEV_NAMESPACE = new Set([
1262
- "alipay",
1263
- "ali",
1264
- "minidev"
1265
- ]);
1266
- const ALIPAY_PLATFORM_ALIASES = new Set([
1267
- "alipay",
1268
- "ali",
1269
- "minidev"
1270
- ]);
1159
+ const MINIDEV_NAMESPACE = new Set(MINIDEV_NAMESPACE_COMMAND_NAMES);
1160
+ const ALIPAY_PLATFORM_ALIASES = new Set(MINIDEV_NAMESPACE_COMMAND_NAMES);
1271
1161
  const ARG_TRANSFORMS = [
1272
1162
  createAlias({
1273
1163
  find: "-p",
@@ -1281,40 +1171,108 @@ const ARG_TRANSFORMS = [
1281
1171
  createPathCompat("-i")
1282
1172
  ];
1283
1173
  /**
1174
+ * @description 基于 cac 注册顶层命令,用于统一识别入口。
1175
+ */
1176
+ function createCli() {
1177
+ const cli = cac("weapp");
1178
+ cli.command("help [command]", "显示命令帮助").allowUnknownOptions();
1179
+ for (const command of WECHAT_CLI_COMMAND_NAMES) cli.command(command, "微信开发者工具官方命令透传").allowUnknownOptions();
1180
+ for (const command of MINIDEV_NAMESPACE_COMMAND_NAMES) cli.command(`${command} [...args]`, "支付宝 minidev 命令透传").allowUnknownOptions();
1181
+ cli.command(`${CONFIG_COMMAND_NAME} [...args]`, "配置 weapp-ide-cli").allowUnknownOptions();
1182
+ for (const command of [
1183
+ "screenshot",
1184
+ "navigate",
1185
+ "redirect",
1186
+ "back",
1187
+ "relaunch",
1188
+ "switch-tab",
1189
+ "page-stack",
1190
+ "current-page",
1191
+ "system-info",
1192
+ "page-data",
1193
+ "tap",
1194
+ "input",
1195
+ "scroll",
1196
+ "audit",
1197
+ "remote"
1198
+ ]) cli.command(`${command} [...args]`, "automator 增强命令").allowUnknownOptions();
1199
+ return cli;
1200
+ }
1201
+ async function handleHelpCommand(args) {
1202
+ const targetCommand = args[0];
1203
+ if (!targetCommand) {
1204
+ createCli().outputHelp();
1205
+ return;
1206
+ }
1207
+ if (targetCommand === "screenshot") {
1208
+ printScreenshotHelp();
1209
+ return;
1210
+ }
1211
+ if (isAutomatorCommand(targetCommand)) {
1212
+ const help = getAutomatorCommandHelp(targetCommand);
1213
+ if (help) {
1214
+ console.log(help);
1215
+ return;
1216
+ }
1217
+ }
1218
+ createCli().outputHelp();
1219
+ }
1220
+ async function handleMissingCliPath(source) {
1221
+ const message = source === "custom" ? i18nText("在当前自定义路径中未找到微信web开发者命令行工具,请重新指定路径。", "Cannot find Wechat Web DevTools CLI in custom path, please reconfigure it.") : i18nText(`未检测到微信web开发者命令行工具,请执行 ${colors.bold(colors.green("weapp-ide-cli config"))} 指定路径。`, `Wechat Web DevTools CLI not found, please run ${colors.bold(colors.green("weapp-ide-cli config"))} to configure it.`);
1222
+ logger_default.warn(message);
1223
+ await promptForCliPath();
1224
+ }
1225
+ /**
1226
+ * @description 判断 open 指令是否应转发到 minidev。
1227
+ */
1228
+ function shouldDelegateOpenToMinidev(argv) {
1229
+ if (argv[0] !== "open") return false;
1230
+ const platform = readOptionValue(argv, "--platform");
1231
+ if (!platform) return false;
1232
+ return ALIPAY_PLATFORM_ALIASES.has(platform.toLowerCase());
1233
+ }
1234
+ /**
1235
+ * @description 将 open 命令参数改写为 minidev ide 参数。
1236
+ */
1237
+ function createMinidevOpenArgv(argv) {
1238
+ const nextArgv = [...argv];
1239
+ nextArgv[0] = "ide";
1240
+ return removeOption(nextArgv, "--platform");
1241
+ }
1242
+ /**
1284
1243
  * @description CLI 入口解析与分发。
1285
1244
  */
1286
1245
  async function parse(argv) {
1287
1246
  validateLocaleOption(argv);
1288
1247
  configureLocaleFromArgv(argv, await getConfiguredLocale());
1289
- const command = argv[0];
1290
- if (command && MINIDEV_NAMESPACE.has(command)) {
1248
+ const cli = createCli();
1249
+ cli.parse([
1250
+ "node",
1251
+ "weapp",
1252
+ ...argv
1253
+ ], { run: false });
1254
+ const matchedCommand = cli.matchedCommandName;
1255
+ if (matchedCommand === "help") {
1256
+ await handleHelpCommand(cli.args);
1257
+ return;
1258
+ }
1259
+ if (matchedCommand && MINIDEV_NAMESPACE.has(matchedCommand)) {
1291
1260
  await runMinidev(argv.slice(1));
1292
1261
  return;
1293
1262
  }
1294
- if (command && isAutomatorCommand(command)) {
1295
- await runAutomatorCommand(command, argv.slice(1));
1263
+ if (matchedCommand === "config") {
1264
+ await handleConfigCommand(argv.slice(1));
1296
1265
  return;
1297
1266
  }
1298
- if (command === "help") {
1299
- const targetCommand = argv[1];
1300
- if (targetCommand === "screenshot") {
1301
- printScreenshotHelp();
1302
- return;
1303
- }
1304
- if (isAutomatorCommand(targetCommand)) {
1305
- await runAutomatorCommand(targetCommand, ["--help"]);
1306
- return;
1307
- }
1267
+ if (matchedCommand && isAutomatorCommand(matchedCommand)) {
1268
+ await runAutomatorCommand(matchedCommand, argv.slice(1));
1269
+ return;
1308
1270
  }
1309
1271
  const formattedArgv = transformArgv(argv, ARG_TRANSFORMS);
1310
1272
  if (shouldDelegateOpenToMinidev(formattedArgv)) {
1311
1273
  await runMinidev(createMinidevOpenArgv(formattedArgv));
1312
1274
  return;
1313
1275
  }
1314
- if (command === "config") {
1315
- await handleConfigCommand(argv.slice(1));
1316
- return;
1317
- }
1318
1276
  if (!isOperatingSystemSupported(operatingSystemName)) {
1319
1277
  logger_default.warn(i18nText(`微信web开发者工具不支持当前平台:${operatingSystemName} !`, `Wechat Web DevTools CLI is not supported on current platform: ${operatingSystemName}!`));
1320
1278
  return;
@@ -1322,29 +1280,10 @@ async function parse(argv) {
1322
1280
  validateWechatCliCommandArgs(formattedArgv);
1323
1281
  const { cliPath, source } = await resolveCliPath();
1324
1282
  if (!cliPath) {
1325
- const message = source === "custom" ? i18nText("在当前自定义路径中未找到微信web开发者命令行工具,请重新指定路径。", "Cannot find Wechat Web DevTools CLI in custom path, please reconfigure it.") : i18nText(`未检测到微信web开发者命令行工具,请执行 ${colors.bold(colors.green("weapp-ide-cli config"))} 指定路径。`, `Wechat Web DevTools CLI not found, please run ${colors.bold(colors.green("weapp-ide-cli config"))} to configure it.`);
1326
- logger_default.warn(message);
1327
- await promptForCliPath();
1283
+ await handleMissingCliPath(source);
1328
1284
  return;
1329
1285
  }
1330
1286
  await runWechatCliWithRetry(cliPath, formattedArgv);
1331
1287
  }
1332
- /**
1333
- * @description 判断 open 指令是否应分发到 minidev。
1334
- */
1335
- function shouldDelegateOpenToMinidev(argv) {
1336
- if (argv[0] !== "open") return false;
1337
- const platform = readOptionValue(argv, "--platform");
1338
- if (!platform) return false;
1339
- return ALIPAY_PLATFORM_ALIASES.has(platform.toLowerCase());
1340
- }
1341
- /**
1342
- * @description 将 open 命令参数转换为 minidev ide 参数。
1343
- */
1344
- function createMinidevOpenArgv(argv) {
1345
- const nextArgv = [...argv];
1346
- nextArgv[0] = "ide";
1347
- return removeOption(nextArgv, "--platform");
1348
- }
1349
1288
  //#endregion
1350
- export { defaultCustomConfigFilePath as A, runAutomatorCommand as B, promptForCliPath as C, readCustomConfig as D, overwriteCustomConfig as E, WECHAT_CLI_COMMAND_NAMES as F, removeOption as G, printScreenshotHelp as H, isWeappIdeTopLevelCommand as I, AUTOMATOR_COMMAND_NAMES as L, CONFIG_COMMAND_NAME as M, MINIDEV_NAMESPACE_COMMAND_NAMES as N, removeCustomConfigKey as O, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES as P, getAutomatorCommandHelp as R, operatingSystemName as S, createLocaleConfig as T, parseAutomatorArgs as U, parseScreenshotArgs as V, readOptionValue as W, getConfig as _, extractExecutionErrorText as a, getDefaultCliPath as b, isWechatIdeLoginRequiredError as c, execute as d, createAlias as f, resolveCliPath as g, handleConfigCommand as h, createWechatIdeLoginRequiredExitError as i, resolvePath as j, defaultCustomConfigDirPath as k, waitForRetryKeypress as l, transformArgv as m, validateWechatCliCommandArgs as n, formatRetryHotkeyPrompt as o, createPathCompat as p, runWechatCliWithRetry as r, formatWechatIdeLoginRequiredError as s, parse as t, runMinidev as u, getConfiguredLocale as v, createCustomConfig as w, isOperatingSystemSupported as x, SupportedPlatformsMap as y, isAutomatorCommand as z };
1289
+ export { parseAutomatorArgs as A, isWeappIdeTopLevelCommand as C, runAutomatorCommand as D, isAutomatorCommand as E, removeOption as M, parseScreenshotArgs as O, WECHAT_CLI_COMMAND_NAMES as S, getAutomatorCommandHelp as T, handleConfigCommand as _, createWechatIdeLoginRequiredExitError as a, MINIDEV_NAMESPACE_COMMAND_NAMES as b, formatWechatIdeLoginRequiredError as c, runMinidev as d, execute as f, startForwardConsole as g, transformArgv as h, runWechatCliWithRetry as i, readOptionValue as j, printScreenshotHelp as k, isWechatIdeLoginRequiredError as l, createPathCompat as m, parse as n, extractExecutionErrorText as o, createAlias as p, validateWechatCliCommandArgs as r, formatRetryHotkeyPrompt as s, createCli as t, waitForRetryKeypress as u, promptForCliPath as v, AUTOMATOR_COMMAND_NAMES as w, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES as x, CONFIG_COMMAND_NAME as y };