weapp-ide-cli 6.2.0 → 6.3.0

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,9 +1,9 @@
1
- import { D as logger, E as colors, T as operatingSystemName, _ as readCustomConfig, a as assertWechatDevtoolsPort, b as defaultCustomConfigFilePath, d as resolveDevtoolsAutomationDefaults, f as createAutoBootstrapDevtoolsConfig, g as overwriteCustomConfig, h as createLocaleConfig, i as assertWechatDevtoolsHost, l as getConfig, m as createCustomConfig, p as createAutoTrustProjectConfig, r as resolveWechatDevtoolsTarget, u as getConfiguredLocale, v as removeCustomConfigKey, w as isOperatingSystemSupported, x as resolvePath } from "./sessionStore-zdzy2UFM.js";
2
- import { a as readManagedRecord, c as withManagedJournalLock, f as assertManagedInstallation, l as writeManagedRecord, m as sameManagedProcess, o as readManagedWechatProjectRecords, p as inspectManagedProjectHost, s as resolveManagedJournal } from "./devtoolsProjectOwnership-yDD6h0dO.js";
3
- import { _ as parseAutomatorPort, a as bootstrapWechatDevtoolsSettings, g as resolveAutomatorSessionOptions, o as detectWechatDevtoolsServicePort } from "./automator-CRpB6_pA.js";
4
- import { C as runWithSuspendedSharedInput, D as validateLocaleOption, E as i18nText, T as configureLocaleFromArgv, _ as isWechatIdeLoginRequiredError, b as promptWechatIdeLoginRetry, c as withMiniProgram$1, i as connectConsoleMiniProgram, l as runRetryableCommand, p as createWechatIdeLoginRequiredExitError, r as closeSharedMiniProgram, s as releaseSharedMiniProgram, t as acquireConsoleMiniProgram } from "./automator-session-gWEsSs_A.js";
5
- import { a as navigateBack, c as pageStack, d as remote, f as scrollTo, g as tap, i as input, l as reLaunch, m as systemInfo, n as captureScreenshotBuffer, o as navigateTo, p as switchTab, r as currentPage, s as pageData, t as audit, u as redirectTo } from "./commands-C1PF1B4P.js";
6
- import "./run-mcp-Dl_1TH1x.js";
1
+ import { A as operatingSystemName, B as removeCustomConfigKey, C as registerWechatDevtoolsInstallation, F as createAutoTrustProjectConfig, H as defaultCustomConfigFilePath, I as createCustomConfig, L as createLocaleConfig, M as logger, N as wechatDevtoolsSelectionContext, P as createAutoBootstrapDevtoolsConfig, R as overwriteCustomConfig, S as selectInstalledWechatDevtools, U as resolvePath, d as validateWechatDevtoolsSelection, f as withWechatDevtoolsSelection, j as colors, k as isOperatingSystemSupported, m as assertWechatDevtoolsPort, p as assertWechatDevtoolsHost, u as resolveWechatDevtoolsTarget, w as unregisterWechatDevtoolsInstallation, x as listWechatDevtoolsInstallations, z as readCustomConfig } from "./automatorProject-DjYLqMj6.js";
2
+ import { a as isManagedWechatProjectFullyReleased, c as resolveManagedJournal, d as assertManagedInstallation, f as inspectManagedProjectHost, l as withManagedJournalLock, o as readManagedRecord, p as sameManagedProcess, s as readManagedWechatProjectRecords, u as writeManagedRecord } from "./devtoolsProjectOwnership-BMfSAg4n.js";
3
+ import { C as isWechatIdeLoginRequiredError, E as promptWechatIdeLoginRetry, F as parseAutomatorPort, M as i18nText, N as validateLocaleOption, P as resolveAutomatorSessionOptions, a as bootstrapWechatDevtoolsSettings, j as configureLocaleFromArgv, k as runWithSuspendedSharedInput, o as detectWechatDevtoolsServicePort, y as createWechatIdeLoginRequiredExitError } from "./automator-BOe32upt.js";
4
+ import { a as connectConsoleMiniProgram, c as releaseSharedMiniProgram, i as closeSharedMiniProgram, l as withMiniProgram$1, r as closeOwnedSharedMiniProgram, t as acquireConsoleMiniProgram, u as runRetryableCommand } from "./automator-session-VOB03glx.js";
5
+ import { a as navigateBack, c as pageStack, d as remote, f as scrollTo, g as tap, i as input, l as reLaunch, m as systemInfo, n as captureScreenshotBuffer, o as navigateTo, p as switchTab, r as currentPage, s as pageData, t as audit, u as redirectTo } from "./commands-mslf7-sP.js";
6
+ import "./run-mcp-Ni139Z5C.js";
7
7
  import path from "node:path";
8
8
  import { inspect } from "node:util";
9
9
  import { withMachineE2ELease } from "@weapp-vite/devtools-runtime";
@@ -494,7 +494,7 @@ async function runScreenshot(argv) {
494
494
  }
495
495
  const options = parseScreenshotArgs(argv);
496
496
  const isJsonOutput = argv.includes("--json");
497
- const { takeScreenshot } = await import("./commands-CZVPfkE9.js");
497
+ const { takeScreenshot } = await import("./commands-DmirGBy4.js");
498
498
  const result = await takeScreenshot(options);
499
499
  if (isJsonOutput) {
500
500
  console.log(JSON.stringify(result, null, 2));
@@ -1055,6 +1055,7 @@ const WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES = [
1055
1055
  ...WECHAT_CLI_COMMAND_NAMES,
1056
1056
  ...AUTOMATOR_COMMAND_NAMES,
1057
1057
  ...MINIDEV_NAMESPACE_COMMAND_NAMES,
1058
+ "devtools",
1058
1059
  CONFIG_COMMAND_NAME,
1059
1060
  "mcp"
1060
1061
  ];
@@ -1066,6 +1067,91 @@ function isWeappIdeTopLevelCommand(command) {
1066
1067
  return Boolean(command && WEAPP_IDE_TOP_LEVEL_COMMAND_SET.has(command));
1067
1068
  }
1068
1069
  //#endregion
1070
+ //#region src/config/resolver.ts
1071
+ function isCustomConfigJson(value) {
1072
+ return typeof value === "object" && value !== null;
1073
+ }
1074
+ /**
1075
+ * @description 解析开发者工具自动预热相关配置的最终生效值。
1076
+ */
1077
+ function resolveDevtoolsAutomationDefaults(config) {
1078
+ return {
1079
+ autoBootstrapDevtools: config.autoBootstrapDevtools ?? true,
1080
+ autoTrustProject: config.autoTrustProject ?? false
1081
+ };
1082
+ }
1083
+ /**
1084
+ * @description 读取并解析 CLI 配置(进程选择优先,其次用户配置与平台默认)
1085
+ */
1086
+ async function getConfig() {
1087
+ const frozen = wechatDevtoolsSelectionContext.getStore();
1088
+ if (frozen) return {
1089
+ ...await readCustomConfig(),
1090
+ cliPath: frozen.cliPath,
1091
+ source: "environment"
1092
+ };
1093
+ if (process.env.WEAPP_IDE_DEVTOOLS_CHANNEL?.trim() || process.env.WEAPP_IDE_DEVTOOLS_VERSION?.trim()) {
1094
+ const target = await resolveWechatDevtoolsTarget();
1095
+ return {
1096
+ ...await readCustomConfig(),
1097
+ cliPath: target.cliPath,
1098
+ source: "environment"
1099
+ };
1100
+ }
1101
+ const selectedCliPath = process.env.WEAPP_IDE_CLI_PATH?.trim();
1102
+ if (await fs$1.pathExists(defaultCustomConfigFilePath)) try {
1103
+ const rawConfig = await fs$1.readJSON(defaultCustomConfigFilePath);
1104
+ const config = isCustomConfigJson(rawConfig) ? rawConfig : {};
1105
+ const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
1106
+ const locale = config.locale === "zh" || config.locale === "en" ? config.locale : void 0;
1107
+ const autoBootstrapDevtools = typeof config.autoBootstrapDevtools === "boolean" ? config.autoBootstrapDevtools : void 0;
1108
+ const autoTrustProject = typeof config.autoTrustProject === "boolean" ? config.autoTrustProject : void 0;
1109
+ if (selectedCliPath || cliPath) {
1110
+ logger.info(`全局配置文件路径:${colors.green(defaultCustomConfigFilePath)}`);
1111
+ logger.info(`${selectedCliPath ? "进程指定" : "自定义"} CLI 路径:${colors.green(selectedCliPath || cliPath)}`);
1112
+ return {
1113
+ cliPath: selectedCliPath || cliPath,
1114
+ locale,
1115
+ autoBootstrapDevtools,
1116
+ autoTrustProject,
1117
+ source: selectedCliPath ? "environment" : "custom"
1118
+ };
1119
+ }
1120
+ logger.warn("自定义配置文件缺少有效的 CLI 路径,将尝试使用默认路径。");
1121
+ } catch (error) {
1122
+ const reason = error instanceof Error ? error.message : String(error);
1123
+ logger.warn(`解析自定义配置失败,${selectedCliPath ? "继续使用进程指定路径" : "将尝试使用默认路径"}。原因:${reason}`);
1124
+ }
1125
+ if (selectedCliPath) return {
1126
+ cliPath: selectedCliPath,
1127
+ source: "environment"
1128
+ };
1129
+ const fallbackPath = await selectInstalledWechatDevtools().then((target) => target.cliPath, (error) => {
1130
+ if (error.code === "WECHAT_DEVTOOLS_INSTALLATION_NOT_FOUND") return;
1131
+ throw error;
1132
+ });
1133
+ if (fallbackPath) return {
1134
+ cliPath: fallbackPath,
1135
+ locale: void 0,
1136
+ autoBootstrapDevtools: void 0,
1137
+ autoTrustProject: void 0,
1138
+ source: "default"
1139
+ };
1140
+ return {
1141
+ cliPath: "",
1142
+ locale: void 0,
1143
+ autoBootstrapDevtools: void 0,
1144
+ autoTrustProject: void 0,
1145
+ source: "missing"
1146
+ };
1147
+ }
1148
+ /**
1149
+ * @description 获取用户配置的语言偏好。
1150
+ */
1151
+ async function getConfiguredLocale() {
1152
+ return (await readCustomConfig()).locale;
1153
+ }
1154
+ //#endregion
1069
1155
  //#region src/cli/prompt.ts
1070
1156
  /**
1071
1157
  * @description 交互式提示并保存 CLI 路径
@@ -1274,6 +1360,126 @@ async function handleConfigCommand(argv) {
1274
1360
  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"));
1275
1361
  }
1276
1362
  //#endregion
1363
+ //#region src/cli/devtoolsSelection.ts
1364
+ const selectionOptions$1 = /* @__PURE__ */ new Map([
1365
+ ["--cli-path", "cliPath"],
1366
+ ["--devtools-channel", "devtoolsChannel"],
1367
+ ["--devtools-version", "devtoolsVersion"]
1368
+ ]);
1369
+ const valueOptions = /* @__PURE__ */ new Set([
1370
+ "--project",
1371
+ "-p",
1372
+ "--desc",
1373
+ "-d",
1374
+ "--version",
1375
+ "-v",
1376
+ "--uv",
1377
+ "--appid",
1378
+ "--ext-appid",
1379
+ "--info-output",
1380
+ "-i",
1381
+ "--result-output",
1382
+ "-r",
1383
+ "--qr-output",
1384
+ "--qr-format",
1385
+ "--qr-size",
1386
+ "--port",
1387
+ "--timeout",
1388
+ "-t",
1389
+ "--session-id",
1390
+ "--output",
1391
+ "-o",
1392
+ "--page",
1393
+ "--lang",
1394
+ "--platform",
1395
+ "--runtime-url",
1396
+ "--login-retry",
1397
+ "--login-retry-timeout",
1398
+ "--config",
1399
+ "-c",
1400
+ "--mode",
1401
+ "-m",
1402
+ "--filter",
1403
+ "-f",
1404
+ "--base",
1405
+ "--logLevel",
1406
+ "-l",
1407
+ "--project-config",
1408
+ "--logPath",
1409
+ "--ticket",
1410
+ "--account",
1411
+ "--test-ticket",
1412
+ "--compile-condition",
1413
+ "--compile-type",
1414
+ "--clean",
1415
+ "--auto-port",
1416
+ "--auto-account",
1417
+ "--replay-config-path",
1418
+ "--key-store",
1419
+ "--key-alias",
1420
+ "--key-pass",
1421
+ "--store-pass",
1422
+ "--use-aab",
1423
+ "--resourceBundleVersion",
1424
+ "--resourceBundleDesc",
1425
+ "--isDistribute",
1426
+ "--isRemoteBuild",
1427
+ "--profilePath",
1428
+ "--certificateName",
1429
+ "--p12Path",
1430
+ "--p12Password",
1431
+ "--tpnsProfilePath",
1432
+ "--isUploadBeta",
1433
+ "--versionName",
1434
+ "--versionCode",
1435
+ "--versionDesc"
1436
+ ]);
1437
+ /** 包装参数不会透传官方 CLI,选项值和双横线后的内容保持原样。 */
1438
+ function splitWechatDevtoolsSelectionArgs(argv) {
1439
+ const selection = {};
1440
+ const args = [];
1441
+ for (let index = 0; index < argv.length; index++) {
1442
+ const token = argv[index];
1443
+ if (token === "--") {
1444
+ args.push(...argv.slice(index));
1445
+ break;
1446
+ }
1447
+ const equals = token.indexOf("=");
1448
+ const name = equals < 0 ? token : token.slice(0, equals);
1449
+ const key = selectionOptions$1.get(name);
1450
+ if (key) {
1451
+ const value = equals < 0 ? argv[++index] : token.slice(equals + 1);
1452
+ if (!value?.trim() || value.startsWith("-")) throw new Error(`${name} requires a value.`);
1453
+ if (selection[key] !== void 0 && selection[key] !== value.trim()) throw new Error(`Conflicting ${name} values in the same command.`);
1454
+ Object.assign(selection, { [key]: value.trim() });
1455
+ } else if (name === "--require-official-latest") {
1456
+ const value = equals < 0 ? "true" : token.slice(equals + 1);
1457
+ if (![
1458
+ "true",
1459
+ "false",
1460
+ "1",
1461
+ "0"
1462
+ ].includes(value)) throw new Error("--require-official-latest requires a boolean.");
1463
+ const enabled = value === "true" || value === "1";
1464
+ if (selection.requireOfficialLatest !== void 0 && selection.requireOfficialLatest !== enabled) throw new Error("Conflicting --require-official-latest values in the same command.");
1465
+ selection.requireOfficialLatest = enabled;
1466
+ } else {
1467
+ args.push(token);
1468
+ if (equals < 0 && valueOptions.has(name) && argv[index + 1] !== void 0) args.push(argv[++index]);
1469
+ }
1470
+ }
1471
+ validateWechatDevtoolsSelection(selection);
1472
+ return {
1473
+ args,
1474
+ selection
1475
+ };
1476
+ }
1477
+ /** 显式选择在任何 helper 或 CLI 回退之前固定,避免入口间选版漂移。 */
1478
+ async function withWechatDevtoolsSelectionArgs(argv, runner) {
1479
+ const { args, selection } = splitWechatDevtoolsSelectionArgs(argv);
1480
+ return Object.keys(selection).length ? await withWechatDevtoolsSelection(selection, () => runner(args)) : await runner(args);
1481
+ }
1482
+ //#endregion
1277
1483
  //#region src/cli/managedProjectGate.ts
1278
1484
  function sameTarget(first, second) {
1279
1485
  return first.installationId === second.installationId && first.cliPath === second.cliPath && first.appPath === second.appPath && first.profileDir === second.profileDir && first.version === second.version && first.channel === second.channel;
@@ -1286,7 +1492,7 @@ async function findConfirmedProject(journalPath, target, projectPath) {
1286
1492
  "unconfirmed",
1287
1493
  "closing",
1288
1494
  "failed"
1289
- ].includes(record.state))) throw new Error("Managed DevTools journal contains unresolved ownership or cleanup; refusing a project mutation.");
1495
+ ].includes(record.state) || record.state === "released" && !isManagedWechatProjectFullyReleased(record) || record.state === "borrowed" && record.snapshot?.state !== void 0 && record.snapshot.state !== "removed")) throw new Error("Managed DevTools journal contains unresolved ownership or cleanup; refusing a project mutation.");
1290
1496
  return scopeRoot === journalPath ? scopeRecords : await readManagedWechatProjectRecords(journalPath);
1291
1497
  })).filter((record) => record.state !== "released" && record.projectPath === projectPath && sameTarget(record.target, target));
1292
1498
  for (const record of matching) try {
@@ -1319,8 +1525,8 @@ async function ensureManagedWechatProject(target, projectPath, options = {}) {
1319
1525
  await assertManagedInstallation(target);
1320
1526
  options.signal?.throwIfAborted();
1321
1527
  if (existing) return existing;
1322
- const { launchAutomator } = await import("./automator-BkZZsGtn.js");
1323
- (await launchAutomator({
1528
+ const { launchAutomator } = await import("./automator-VSjgHujY.js");
1529
+ await (await launchAutomator({
1324
1530
  target,
1325
1531
  cliPath: target.cliPath,
1326
1532
  projectPath: resolvedProjectPath,
@@ -1699,6 +1905,30 @@ async function prepareAcceptanceProject(projectPath, signal, options = {}) {
1699
1905
  });
1700
1906
  }
1701
1907
  //#endregion
1908
+ //#region src/cli/forwardConsole/refresh.ts
1909
+ /** 刷新已有项目的日志开关,并保留日志启用与连接释放的独立错误。 */
1910
+ async function refreshOpenedMiniProgramConsoleLog(options, enableLog) {
1911
+ const miniProgram = await connectConsoleMiniProgram({
1912
+ ...options,
1913
+ openedOnly: true
1914
+ });
1915
+ let failure;
1916
+ let failed = false;
1917
+ try {
1918
+ await enableLog(miniProgram);
1919
+ } catch (error) {
1920
+ failed = true;
1921
+ failure = error;
1922
+ }
1923
+ try {
1924
+ await miniProgram.disconnect();
1925
+ } catch (cleanupError) {
1926
+ if (failed) throw new AggregateError([failure, cleanupError], "Console log refresh and connection cleanup failed", { cause: failure });
1927
+ throw cleanupError;
1928
+ }
1929
+ if (failed) throw failure;
1930
+ }
1931
+ //#endregion
1702
1932
  //#region src/cli/forwardConsole.ts
1703
1933
  const DEFAULT_FORWARD_CONSOLE_LEVELS = [
1704
1934
  "log",
@@ -1842,29 +2072,28 @@ async function acquireForwardConsoleMiniProgram(options) {
1842
2072
  return miniProgram;
1843
2073
  } catch (error) {
1844
2074
  lastError = error;
1845
- if (miniProgram) releaseSharedMiniProgram(options.projectPath, options.sessionId || options.port, options);
1846
- await closeSharedMiniProgram(options.projectPath, options.sessionId || options.port, options);
2075
+ const cleanupErrors = [];
2076
+ if (miniProgram) try {
2077
+ await releaseSharedMiniProgram(options.projectPath, options.sessionId || options.port, options);
2078
+ } catch (cleanupError) {
2079
+ cleanupErrors.push(cleanupError);
2080
+ }
2081
+ try {
2082
+ await closeSharedMiniProgram(options.projectPath, options.sessionId || options.port, options);
2083
+ } catch (cleanupError) {
2084
+ cleanupErrors.push(cleanupError);
2085
+ }
2086
+ if (cleanupErrors.length) throw new AggregateError([error, ...cleanupErrors], "Forward console setup and connection cleanup failed", { cause: error });
1847
2087
  if (attempt < ENABLE_LOG_RETRY_TIMES) await sleep(ENABLE_LOG_RETRY_DELAY_MS);
1848
2088
  }
1849
2089
  }
1850
2090
  throw lastError instanceof Error ? lastError : new Error(String(lastError));
1851
2091
  }
1852
- async function refreshOpenedMiniProgramConsoleLog(options) {
1853
- const miniProgram = await connectConsoleMiniProgram({
1854
- ...options,
1855
- openedOnly: true
1856
- });
1857
- try {
1858
- await enableMiniProgramConsoleLog(miniProgram);
1859
- } finally {
1860
- miniProgram.disconnect();
1861
- }
1862
- }
1863
2092
  function startEnableLogRefresh(miniProgram, options, refreshOpenedSession) {
1864
2093
  if (typeof miniProgram.enableLog !== "function") return;
1865
2094
  const timer = setInterval(() => {
1866
2095
  miniProgram.enableLog(ENABLE_LOG_TIMEOUT_MS).catch(() => {});
1867
- if (refreshOpenedSession) refreshOpenedMiniProgramConsoleLog(options).catch(() => {});
2096
+ if (refreshOpenedSession) refreshOpenedMiniProgramConsoleLog(options, enableMiniProgramConsoleLog).catch(() => {});
1868
2097
  }, ENABLE_LOG_REFRESH_INTERVAL_MS);
1869
2098
  return () => {
1870
2099
  clearInterval(timer);
@@ -1900,8 +2129,10 @@ async function startForwardConsole(options) {
1900
2129
  let stopEnableLogRefresh;
1901
2130
  let auxiliaryMiniProgram;
1902
2131
  let auxiliaryTimer;
1903
- const closeSession = async () => {
1904
- if (closed) return;
2132
+ let closing;
2133
+ let sharedReleased = false;
2134
+ const closeSession = () => {
2135
+ if (closing) return closing;
1905
2136
  closed = true;
1906
2137
  if (auxiliaryTimer) {
1907
2138
  clearTimeout(auxiliaryTimer);
@@ -1911,13 +2142,33 @@ async function startForwardConsole(options) {
1911
2142
  stopEnableLogRefresh = void 0;
1912
2143
  detachMiniProgramListener(miniProgram, "console", onConsole);
1913
2144
  detachMiniProgramListener(miniProgram, "exception", onException);
1914
- if (auxiliaryMiniProgram) {
1915
- detachMiniProgramListener(auxiliaryMiniProgram, "console", onConsole);
1916
- detachMiniProgramListener(auxiliaryMiniProgram, "exception", onException);
1917
- auxiliaryMiniProgram.disconnect();
1918
- auxiliaryMiniProgram = void 0;
1919
- }
1920
- if (usesSharedSession) releaseSharedMiniProgram(options.projectPath, options.sessionId || options.port, options);
2145
+ closing = (async () => {
2146
+ const errors = [];
2147
+ if (auxiliaryMiniProgram) {
2148
+ detachMiniProgramListener(auxiliaryMiniProgram, "console", onConsole);
2149
+ detachMiniProgramListener(auxiliaryMiniProgram, "exception", onException);
2150
+ try {
2151
+ await auxiliaryMiniProgram.disconnect();
2152
+ auxiliaryMiniProgram = void 0;
2153
+ } catch (error) {
2154
+ errors.push(error);
2155
+ }
2156
+ }
2157
+ if (usesSharedSession) try {
2158
+ if (!sharedReleased) {
2159
+ sharedReleased = true;
2160
+ await releaseSharedMiniProgram(options.projectPath, options.sessionId || options.port, options);
2161
+ }
2162
+ await closeOwnedSharedMiniProgram(options, miniProgram);
2163
+ } catch (error) {
2164
+ errors.push(error);
2165
+ }
2166
+ if (errors.length) throw new AggregateError(errors, "Forward console session cleanup failed");
2167
+ })().catch((error) => {
2168
+ closing = void 0;
2169
+ throw error;
2170
+ });
2171
+ return closing;
1921
2172
  };
1922
2173
  miniProgram.on("console", onConsole);
1923
2174
  miniProgram.on("exception", onException);
@@ -1929,7 +2180,7 @@ async function startForwardConsole(options) {
1929
2180
  openedOnly: true
1930
2181
  });
1931
2182
  if (closed) {
1932
- openedMiniProgram.disconnect();
2183
+ await openedMiniProgram.disconnect();
1933
2184
  return;
1934
2185
  }
1935
2186
  auxiliaryMiniProgram = openedMiniProgram;
@@ -2077,6 +2328,22 @@ async function runMinidev(argv) {
2077
2328
  }
2078
2329
  }
2079
2330
  //#endregion
2331
+ //#region src/cli/devtools.ts
2332
+ /** 本地安装管理不启动 IDE,不更改账号或默认 CLI 配置。 */
2333
+ async function handleDevtoolsCommand(argv) {
2334
+ const [action = "list", cliPath] = argv;
2335
+ if (action === "list") {
2336
+ const installations = await listWechatDevtoolsInstallations();
2337
+ if (argv.includes("--json")) console.log(JSON.stringify({ installations }, null, 2));
2338
+ else for (const entry of installations) console.log(entry.target ? `${entry.target.channel ?? "unknown"}@${entry.target.version ?? "unknown"}\n CLI: ${entry.cliPath}\n installation: ${entry.target.installationId}\n profile: ${entry.target.profileDir}` : `unavailable: ${entry.cliPath}\n ${entry.error}`);
2339
+ return;
2340
+ }
2341
+ if (action !== "add" && action !== "remove") throw new Error("Use weapp devtools list [--json] | add <path-to-cli> | remove <path-to-cli>.");
2342
+ if (!cliPath || argv.length !== 2) throw new Error(`weapp devtools ${action} requires one CLI path.`);
2343
+ if (action === "add") console.log(JSON.stringify(await registerWechatDevtoolsInstallation(cliPath), null, 2));
2344
+ else await unregisterWechatDevtoolsInstallation(cliPath);
2345
+ }
2346
+ //#endregion
2080
2347
  //#region src/cli/run-login-config.ts
2081
2348
  function normalizeLoginRetryMode(value, nonInteractive) {
2082
2349
  if (value && value !== "never" && value !== "once" && value !== "always") throw new Error(i18nText(`不支持的 --login-retry 值: ${value}(仅支持 never/once/always)`, `Invalid --login-retry value: ${value} (supported: never/once/always)`));
@@ -2274,6 +2541,7 @@ async function resolveWechatCliCommandTarget(options = {}) {
2274
2541
  logger.warn(i18nText(`微信web开发者工具不支持当前平台:${operatingSystemName} !`, `Wechat Web DevTools CLI is not supported on current platform: ${operatingSystemName}!`));
2275
2542
  return;
2276
2543
  }
2544
+ if (options.cliPath || options.devtoolsChannel || options.devtoolsVersion || options.requireOfficialLatest) return await resolveWechatDevtoolsTarget(options);
2277
2545
  let target = options.target;
2278
2546
  if (!target) {
2279
2547
  const { cliPath, source } = await resolveCliPath();
@@ -2393,6 +2661,20 @@ function validateWechatCliCommandArgs(argv) {
2393
2661
  }
2394
2662
  //#endregion
2395
2663
  //#region src/cli/wechat-commands.ts
2664
+ function selectionOptions(options) {
2665
+ return Object.fromEntries([
2666
+ "cliPath",
2667
+ "target",
2668
+ "devtoolsChannel",
2669
+ "devtoolsVersion",
2670
+ "requireOfficialLatest"
2671
+ ].filter((key) => options[key] !== void 0).map((key) => [key, options[key]]));
2672
+ }
2673
+ async function runSelectedCommand(argv, options) {
2674
+ const selection = selectionOptions(options);
2675
+ if (Object.keys(selection).length) await runWechatCliCommand(argv, selection);
2676
+ else await runWechatCliCommand(argv);
2677
+ }
2396
2678
  const DEVTOOLS_SHUTDOWN_TIMEOUT_MS = 1e4;
2397
2679
  function appendProjectLocatorArgv(argv, options) {
2398
2680
  if (options.projectPath) argv.push("--project", path.resolve(options.projectPath));
@@ -2418,7 +2700,7 @@ async function openSelectedWechatIde(options, target) {
2418
2700
  /** 打开与兼容回退在同一机器租约内沿用固定安装,禁止重新选择宿主。 */
2419
2701
  async function openWechatIde(options = {}) {
2420
2702
  return await withMachineE2ELease(async () => {
2421
- const target = await resolveWechatCliCommandTarget();
2703
+ const target = await resolveWechatCliCommandTarget(options);
2422
2704
  if (target) {
2423
2705
  if (process.env["WEAPP_IDE_MANAGED_PROJECT_JOURNAL"]?.trim()) {
2424
2706
  if (!options.projectPath) throw new Error("Managed DevTools open requires an explicit project path; no project was opened.");
@@ -2438,7 +2720,7 @@ async function loginWechatIde(options = {}) {
2438
2720
  if (options.qrOutput) argv.push("--qr-output", path.resolve(options.qrOutput));
2439
2721
  if (options.qrSize) argv.push("--qr-size", options.qrSize);
2440
2722
  if (options.resultOutput) argv.push("--result-output", path.resolve(options.resultOutput));
2441
- await runWechatCliCommand(argv);
2723
+ await runSelectedCommand(argv, options);
2442
2724
  }
2443
2725
  /**
2444
2726
  * @description 调用微信开发者工具 islogin 命令。
@@ -2446,8 +2728,11 @@ async function loginWechatIde(options = {}) {
2446
2728
  async function isWechatIdeLoggedIn(options = {}) {
2447
2729
  const argv = ["islogin"];
2448
2730
  if (options.nonInteractive) argv.push("--non-interactive");
2449
- if (options.silent) await runWechatCliCommand(argv, { silent: true });
2450
- else await runWechatCliCommand(argv);
2731
+ if (options.silent) await runWechatCliCommand(argv, {
2732
+ ...selectionOptions(options),
2733
+ silent: true
2734
+ });
2735
+ else await runSelectedCommand(argv, options);
2451
2736
  }
2452
2737
  /**
2453
2738
  * @description 调用微信开发者工具 build-npm 命令。
@@ -2459,7 +2744,7 @@ async function buildWechatIdeNpm(options = {}) {
2459
2744
  path.resolve(options.projectPath ?? process.cwd())
2460
2745
  ];
2461
2746
  if (options.compileType) argv.push("--compile-type", options.compileType);
2462
- await runWechatCliCommand(argv);
2747
+ await runSelectedCommand(argv, options);
2463
2748
  }
2464
2749
  /**
2465
2750
  * @description 调用微信开发者工具 preview 命令。
@@ -2472,7 +2757,7 @@ async function previewWechatIde(options = {}) {
2472
2757
  if (options.qrSize) argv.push("--qr-size", options.qrSize);
2473
2758
  if (options.infoOutput) argv.push("--info-output", path.resolve(options.infoOutput));
2474
2759
  if (options.compileCondition) argv.push("--compile-condition", options.compileCondition);
2475
- await runWechatCliCommand(argv);
2760
+ await runSelectedCommand(argv, options);
2476
2761
  }
2477
2762
  /**
2478
2763
  * @description 调用微信开发者工具 auto-preview 命令。
@@ -2482,7 +2767,7 @@ async function autoPreviewWechatIde(options = {}) {
2482
2767
  appendProjectLocatorArgv(argv, options);
2483
2768
  if (options.infoOutput) argv.push("--info-output", path.resolve(options.infoOutput));
2484
2769
  if (options.compileCondition) argv.push("--compile-condition", options.compileCondition);
2485
- await runWechatCliCommand(argv);
2770
+ await runSelectedCommand(argv, options);
2486
2771
  }
2487
2772
  /**
2488
2773
  * @description 调用微信开发者工具 auto 命令。
@@ -2495,7 +2780,7 @@ async function autoWechatIde(options = {}) {
2495
2780
  if (options.testTicket) argv.push("--test-ticket", options.testTicket);
2496
2781
  if (options.ticket) argv.push("--ticket", options.ticket);
2497
2782
  if (options.trustProject) argv.push("--trust-project");
2498
- await runWechatCliCommand(argv);
2783
+ await runSelectedCommand(argv, options);
2499
2784
  }
2500
2785
  /**
2501
2786
  * @description 调用微信开发者工具 auto-replay 命令。
@@ -2510,7 +2795,7 @@ async function autoReplayWechatIde(options = {}) {
2510
2795
  if (options.testTicket) argv.push("--test-ticket", options.testTicket);
2511
2796
  if (options.ticket) argv.push("--ticket", options.ticket);
2512
2797
  if (options.trustProject) argv.push("--trust-project");
2513
- await runWechatCliCommand(argv);
2798
+ await runSelectedCommand(argv, options);
2514
2799
  }
2515
2800
  /**
2516
2801
  * @description 调用微信开发者工具 upload 命令。
@@ -2520,7 +2805,7 @@ async function uploadWechatIde(options) {
2520
2805
  appendProjectLocatorArgv(argv, options);
2521
2806
  argv.push("--version", options.version, "--desc", options.desc);
2522
2807
  if (options.infoOutput) argv.push("--info-output", path.resolve(options.infoOutput));
2523
- await runWechatCliCommand(argv);
2808
+ await runSelectedCommand(argv, options);
2524
2809
  }
2525
2810
  /**
2526
2811
  * @description 调用微信开发者工具 close 命令。
@@ -2530,45 +2815,50 @@ async function closeWechatIdeProject(options = {}) {
2530
2815
  if (options.cliPath !== void 0 && !options.cliPath.trim()) throw new Error("The explicit close cliPath must not be empty.");
2531
2816
  const argv = ["close"];
2532
2817
  appendProjectLocatorArgv(argv, options);
2533
- const target = options.target || options.cliPath ? await resolveWechatDevtoolsTarget({
2534
- target: options.target,
2535
- cliPath: options.cliPath
2536
- }) : void 0;
2818
+ const target = options.target || options.cliPath || options.devtoolsChannel || options.devtoolsVersion ? await resolveWechatDevtoolsTarget(selectionOptions(options)) : void 0;
2537
2819
  await runWechatCliCommand(argv, {
2538
- ...target ? { target } : {},
2820
+ ...target ? { target } : selectionOptions(options),
2539
2821
  timeout: DEVTOOLS_SHUTDOWN_TIMEOUT_MS
2540
2822
  });
2541
2823
  }
2542
2824
  /**
2543
2825
  * @description 调用微信开发者工具 quit 命令。
2544
2826
  */
2545
- async function quitWechatIde() {
2546
- await runWechatCliCommand(["quit"], { timeout: DEVTOOLS_SHUTDOWN_TIMEOUT_MS });
2827
+ async function quitWechatIde(options = {}) {
2828
+ await runWechatCliCommand(["quit"], {
2829
+ ...selectionOptions(options),
2830
+ timeout: DEVTOOLS_SHUTDOWN_TIMEOUT_MS
2831
+ });
2547
2832
  }
2548
2833
  /**
2549
2834
  * @description 调用微信开发者工具 cache 命令。
2550
2835
  */
2551
2836
  async function clearWechatIdeCache(options) {
2552
- await runWechatCliCommand([
2837
+ await runSelectedCommand([
2553
2838
  "cache",
2554
2839
  "--clean",
2555
2840
  options.clean
2556
- ]);
2841
+ ], options);
2557
2842
  }
2558
2843
  /**
2559
2844
  * @description 调用微信开发者工具 open-other 命令。
2560
2845
  */
2561
- async function openWechatIdeOtherProject(_options = {}) {
2562
- await runWechatCliCommand(["open-other"]);
2846
+ async function openWechatIdeOtherProject(options = {}) {
2847
+ await runSelectedCommand(["open-other"], options);
2563
2848
  }
2564
2849
  /**
2565
2850
  * @description 通过微信开发者工具 HTTP 服务端口重置指定项目的 fileutils 状态。
2566
2851
  */
2567
2852
  async function resetWechatIdeFileUtils(options) {
2568
- await resetWechatIdeFileUtilsByHttp(path.resolve(options.projectPath));
2853
+ const selection = selectionOptions(options);
2854
+ if (Object.keys(selection).length) await resetWechatIdeFileUtilsByHttp(path.resolve(options.projectPath), selection);
2855
+ else await resetWechatIdeFileUtilsByHttp(path.resolve(options.projectPath));
2569
2856
  }
2570
2857
  function createAutomatorSessionOptions(options) {
2571
2858
  return {
2859
+ cliPath: options.cliPath,
2860
+ target: options.target,
2861
+ ...selectionOptions(options),
2572
2862
  ...options.port ? { port: options.port } : {},
2573
2863
  preferOpenedSession: options.preferOpenedSession ?? true,
2574
2864
  preserveProjectRoot: options.preserveProjectRoot,
@@ -2656,7 +2946,7 @@ async function buildWechatIdeApk(options) {
2656
2946
  if (options.isUploadResourceBundle) argv.push("--isUploadResourceBundle");
2657
2947
  if (options.resourceBundleVersion) argv.push("--resourceBundleVersion", options.resourceBundleVersion);
2658
2948
  if (options.resourceBundleDesc) argv.push("--resourceBundleDesc", options.resourceBundleDesc);
2659
- await runWechatCliCommand(argv);
2949
+ await runSelectedCommand(argv, options);
2660
2950
  }
2661
2951
  /**
2662
2952
  * @description 调用微信开发者工具 build-ipa 命令。
@@ -2682,7 +2972,7 @@ async function buildWechatIdeIpa(options) {
2682
2972
  if (options.versionName) argv.push("--versionName", options.versionName);
2683
2973
  if (options.versionCode !== void 0) argv.push("--versionCode", String(options.versionCode));
2684
2974
  if (options.versionDesc) argv.push("--versionDesc", options.versionDesc);
2685
- await runWechatCliCommand(argv);
2975
+ await runSelectedCommand(argv, options);
2686
2976
  }
2687
2977
  //#endregion
2688
2978
  //#region src/cli/wechat-dispatch.ts
@@ -2898,6 +3188,11 @@ function createCli() {
2898
3188
  cli.command("help [command]", "显示命令帮助").allowUnknownOptions();
2899
3189
  for (const command of WECHAT_CLI_COMMAND_NAMES) cli.command(command, "微信开发者工具官方命令透传").allowUnknownOptions();
2900
3190
  for (const command of MINIDEV_NAMESPACE_COMMAND_NAMES) cli.command(`${command} [...args]`, "支付宝 minidev 命令透传").allowUnknownOptions();
3191
+ cli.command("devtools [...args]", "管理本机多版本开发者工具").allowUnknownOptions();
3192
+ cli.option("--devtools-channel <channel>", "选择 stable | rc | nightly");
3193
+ cli.option("--devtools-version <version>", "固定开发者工具产品版本");
3194
+ cli.option("--cli-path <path>", "固定开发者工具 CLI 安装路径");
3195
+ cli.option("--require-official-latest", "要求匹配所选渠道的官方最新版本");
2901
3196
  cli.command(`${CONFIG_COMMAND_NAME} [...args]`, "配置 weapp-ide-cli").allowUnknownOptions();
2902
3197
  cli.command(`mcp [...args]`, "启动 weapp-ide-cli MCP 服务").allowUnknownOptions();
2903
3198
  for (const command of AUTOMATOR_COMMAND_NAMES) cli.command(`${command} [...args]`, "automator 增强命令").allowUnknownOptions();
@@ -2946,7 +3241,7 @@ function createMinidevOpenArgv(argv) {
2946
3241
  /**
2947
3242
  * @description CLI 入口解析与分发。
2948
3243
  */
2949
- async function parse(argv) {
3244
+ async function parseSelected(argv) {
2950
3245
  validateLocaleOption(argv);
2951
3246
  configureLocaleFromArgv(argv, await getConfiguredLocale());
2952
3247
  const cli = createCli();
@@ -2968,12 +3263,16 @@ async function parse(argv) {
2968
3263
  await runMinidev(argv.slice(1));
2969
3264
  return;
2970
3265
  }
3266
+ if (matchedCommand === "devtools") {
3267
+ await handleDevtoolsCommand(argv.slice(1));
3268
+ return;
3269
+ }
2971
3270
  if (matchedCommand === "config") {
2972
3271
  await handleConfigCommand(argv.slice(1));
2973
3272
  return;
2974
3273
  }
2975
3274
  if (matchedCommand === "mcp") {
2976
- const { runMcpCommand } = await import("./run-mcp-CPv8cesh.js");
3275
+ const { runMcpCommand } = await import("./run-mcp-83-VKZVA.js");
2977
3276
  await runMcpCommand(argv.slice(1));
2978
3277
  return;
2979
3278
  }
@@ -2990,5 +3289,17 @@ async function parse(argv) {
2990
3289
  if (await dispatchWechatCliCommand(formattedArgv)) return;
2991
3290
  await runWechatCliCommand(formattedArgv);
2992
3291
  }
3292
+ /** 在分发前剥离公共选择参数并固定本次安装。 */
3293
+ async function parse(argv) {
3294
+ if ([
3295
+ "help",
3296
+ "config",
3297
+ "devtools",
3298
+ "alipay",
3299
+ "ali",
3300
+ "minidev"
3301
+ ].includes(argv[0] ?? "") || argv.includes("--help") || argv.includes("-h")) return await parseSelected(argv);
3302
+ return await withWechatDevtoolsSelectionArgs(argv, parseSelected);
3303
+ }
2993
3304
  //#endregion
2994
- export { MINIDEV_NAMESPACE_COMMAND_NAMES as $, queryWechatIdeLogin as A, WECHAT_DEVTOOLS_ENGINE_BUILD_STATUSES as B, refreshWechatIdeTicket as C, validateWechatCliCommandArgs as D, uploadWechatIde as E, startForwardConsole as F, startWechatIdeEngineBuildByHttp as G, pollWechatIdeEngineBuildResultByHttp as H, isWechatIdeEngineBuildEndpointMissingError as I, handleConfigCommand as J, getRuntimeWechatDevtoolsServicePort as K, prepareAcceptanceProject as L, createAlias as M, createPathCompat as N, runWechatCliWithRetry as O, transformArgv as P, MCP_COMMAND_NAME as Q, runWechatIdeEngineBuild as R, quitWechatIde as S, setWechatIdeTicket as T, requestWechatDevtoolsHttp as U, openWechatIdeProjectByHttp as V, resetWechatIdeFileUtilsByHttp as W, promptForCliPath as X, resolveCliPath as Y, CONFIG_COMMAND_NAME as Z, isWechatIdeLoggedIn as _, autoReplayWechatIde as a, isAutomatorCommand as at, openWechatIdeOtherProject as b, buildWechatIdeIpa as c, printScreenshotHelp as ct, clearWechatIdeCacheByAutomator as d, parseAutomatorArgs as dt, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES as et, closeWechatIdeProject as f, readBooleanOption as ft, getWechatIdeToolInfo as g, getWechatIdeTicket as h, autoPreviewWechatIde as i, getAutomatorCommandHelp as it, execute as j, runMinidev as k, buildWechatIdeNpm as l, parseCompareArgs as lt, getWechatIdeTestAccounts as m, removeOption as mt, parse as n, isWeappIdeTopLevelCommand as nt, autoWechatIde as o, runAutomatorCommand as ot, compileWechatIdeByAutomator as p, readOptionValue as pt, setRuntimeWechatDevtoolsServicePort as q, dispatchWechatCliCommand as r, AUTOMATOR_COMMAND_NAMES as rt, buildWechatIdeApk as s, parseScreenshotArgs as st, createCli as t, WECHAT_CLI_COMMAND_NAMES as tt, clearWechatIdeCache as u, printCompareHelp as ut, loginWechatIde as v, resetWechatIdeFileUtils as w, previewWechatIde as x, openWechatIde as y, runWechatIdeEngineBuildByHttp as z };
3305
+ export { getConfig as $, queryWechatIdeLogin as A, WECHAT_DEVTOOLS_ENGINE_BUILD_STATUSES as B, refreshWechatIdeTicket as C, validateWechatCliCommandArgs as D, uploadWechatIde as E, startForwardConsole as F, startWechatIdeEngineBuildByHttp as G, pollWechatIdeEngineBuildResultByHttp as H, isWechatIdeEngineBuildEndpointMissingError as I, splitWechatDevtoolsSelectionArgs as J, getRuntimeWechatDevtoolsServicePort as K, prepareAcceptanceProject as L, createAlias as M, createPathCompat as N, runWechatCliWithRetry as O, transformArgv as P, promptForCliPath as Q, runWechatIdeEngineBuild as R, quitWechatIde as S, setWechatIdeTicket as T, requestWechatDevtoolsHttp as U, openWechatIdeProjectByHttp as V, resetWechatIdeFileUtilsByHttp as W, handleConfigCommand as X, withWechatDevtoolsSelectionArgs as Y, resolveCliPath as Z, isWechatIdeLoggedIn as _, readBooleanOption as _t, autoReplayWechatIde as a, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES as at, openWechatIdeOtherProject as b, buildWechatIdeIpa as c, AUTOMATOR_COMMAND_NAMES as ct, clearWechatIdeCacheByAutomator as d, runAutomatorCommand as dt, getConfiguredLocale as et, closeWechatIdeProject as f, parseScreenshotArgs as ft, getWechatIdeToolInfo as g, parseAutomatorArgs as gt, getWechatIdeTicket as h, printCompareHelp as ht, autoPreviewWechatIde as i, MINIDEV_NAMESPACE_COMMAND_NAMES as it, execute as j, runMinidev as k, buildWechatIdeNpm as l, getAutomatorCommandHelp as lt, getWechatIdeTestAccounts as m, parseCompareArgs as mt, parse as n, CONFIG_COMMAND_NAME as nt, autoWechatIde as o, WECHAT_CLI_COMMAND_NAMES as ot, compileWechatIdeByAutomator as p, printScreenshotHelp as pt, setRuntimeWechatDevtoolsServicePort as q, dispatchWechatCliCommand as r, MCP_COMMAND_NAME as rt, buildWechatIdeApk as s, isWeappIdeTopLevelCommand as st, createCli as t, resolveDevtoolsAutomationDefaults as tt, clearWechatIdeCache as u, isAutomatorCommand as ut, loginWechatIde as v, readOptionValue as vt, resetWechatIdeFileUtils as w, previewWechatIde as x, openWechatIde as y, removeOption as yt, runWechatIdeEngineBuildByHttp as z };