weapp-vite 6.15.13 → 6.15.15

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/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { S as isPathInside, _ as DEFAULT_MP_PLATFORM, b as resolveMiniPlatform, c as createSharedBuildConfig, d as resolveWeappConfigFile, f as checkRuntime, g as createCjsConfigLoadError, h as parseCommentJson, l as SHARED_CHUNK_VIRTUAL_PREFIX, m as loadViteConfigFile, n as syncProjectSupportFiles, p as getProjectConfigFileName, r as syncManagedTsconfigBootstrapFiles, s as formatBytes, t as createCompilerContext, v as getDefaultIdeProjectRoot, x as shouldPassPlatformArgToIdeOpen, y as normalizeMiniPlatform } from "./createContext-CBnOZ_FN.mjs";
1
+ import { C as isPathInside, S as shouldPassPlatformArgToIdeOpen, _ as createCjsConfigLoadError, b as normalizeMiniPlatform, c as createSharedBuildConfig, f as resolveWeappConfigFile, g as parseCommentJson, h as loadViteConfigFile, l as SHARED_CHUNK_VIRTUAL_PREFIX, m as getProjectConfigFileName, n as syncProjectSupportFiles, p as checkRuntime, r as syncManagedTsconfigBootstrapFiles, s as formatBytes, t as createCompilerContext, u as resolveHmrProfileJsonPath, v as DEFAULT_MP_PLATFORM, x as resolveMiniPlatform, y as getDefaultIdeProjectRoot } from "./createContext-Bwdmz5ML.mjs";
2
2
  import { r as logger_default, t as colors } from "./logger-CgxdNjvb.mjs";
3
- import { h as VERSION } from "./file-CycxGM0E.mjs";
3
+ import { h as VERSION } from "./file-fMqSV4Z9.mjs";
4
4
  import { a as resolveWeappMcpConfig, o as startWeappViteMcpServer } from "./mcp-DRlj32v4.mjs";
5
5
  import { createRequire } from "node:module";
6
6
  import path, { posix } from "pathe";
@@ -15,14 +15,113 @@ import { execFile } from "node:child_process";
15
15
  import { Buffer } from "node:buffer";
16
16
  import { cac } from "cac";
17
17
  import { resolveCommand } from "package-manager-detector/commands";
18
+ import { RETRY_CANCEL_KEYS, RETRY_CONFIRM_KEYS, bootstrapWechatDevtoolsSettings, buildWechatIdeNpm, clearWechatIdeCache, clearWechatIdeCacheByAutomator, closeSharedMiniProgram, closeWechatIdeProject, compileWechatIdeByAutomator, connectOpenedAutomator, createSharedInputSession, dispatchWechatCliCommand, formatAutomatorLoginError, getConfig, getWechatIdeTestAccounts, getWechatIdeTicket, getWechatIdeToolInfo, isAutomatorLoginError, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, openWechatIdeProjectByHttp, parse, promptRetryKeypress, promptWechatIdeLoginRetry, quitWechatIde, refreshWechatIdeTicket, resetWechatIdeFileUtilsByHttp, runRetryableCommand, runWechatIdeEngineBuild, runWithSuspendedSharedInput, setWechatIdeTicket, startForwardConsole, takeScreenshot } from "weapp-ide-cli";
18
19
  import { promisify } from "node:util";
19
- import { bootstrapWechatDevtoolsSettings, closeSharedMiniProgram, connectOpenedAutomator, formatAutomatorLoginError, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getConfig, isAutomatorLoginError, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, parse, startForwardConsole, takeScreenshot, waitForRetryKeypress } from "weapp-ide-cli";
20
20
  import { generateJs, generateJson, generateWxml, generateWxss } from "@weapp-core/schematics";
21
21
  import { determineAgent } from "@vercel/detect-agent";
22
22
  import { initConfig } from "@weapp-core/init";
23
23
  import { createInterface } from "node:readline/promises";
24
24
  import { clearTimeout, setTimeout as setTimeout$1 } from "node:timers";
25
- import { emitKeypressEvents } from "node:readline";
25
+ //#region src/analyze/hmr.ts
26
+ function createMetricSummary(values) {
27
+ if (!values.length) return { count: 0 };
28
+ const total = values.reduce((sum, value) => sum + value, 0);
29
+ return {
30
+ count: values.length,
31
+ averageMs: total / values.length,
32
+ maxMs: Math.max(...values)
33
+ };
34
+ }
35
+ function sortCountEntries(map) {
36
+ return [...map.entries()].sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).map(([name, count]) => ({
37
+ name,
38
+ count
39
+ }));
40
+ }
41
+ function collectCounts(target, values) {
42
+ for (const value of values ?? []) {
43
+ if (!value) continue;
44
+ target.set(value, (target.get(value) ?? 0) + 1);
45
+ }
46
+ }
47
+ function isFiniteNumber$1(value) {
48
+ return typeof value === "number" && Number.isFinite(value);
49
+ }
50
+ /**
51
+ * @description 聚合 HMR JSONL profile,为命令行与后续仪表盘复用。
52
+ */
53
+ async function analyzeHmrProfile(options) {
54
+ const lines = (await fs.readFile(options.profilePath, "utf8")).split(/\r?\n/);
55
+ const samples = [];
56
+ let skippedLineCount = 0;
57
+ for (const line of lines) {
58
+ const trimmed = line.trim();
59
+ if (!trimmed) continue;
60
+ try {
61
+ const parsed = JSON.parse(trimmed);
62
+ if (!isFiniteNumber$1(parsed.totalMs)) {
63
+ skippedLineCount += 1;
64
+ continue;
65
+ }
66
+ samples.push(parsed);
67
+ } catch {
68
+ skippedLineCount += 1;
69
+ }
70
+ }
71
+ const eventCounts = /* @__PURE__ */ new Map();
72
+ const dirtyReasonCounts = /* @__PURE__ */ new Map();
73
+ const pendingReasonCounts = /* @__PURE__ */ new Map();
74
+ const totalValues = [];
75
+ const buildCoreValues = [];
76
+ const transformValues = [];
77
+ const writeValues = [];
78
+ const watchToDirtyValues = [];
79
+ const emitValues = [];
80
+ const sharedChunkValues = [];
81
+ for (const sample of samples) {
82
+ totalValues.push(sample.totalMs);
83
+ if (sample.event) eventCounts.set(sample.event, (eventCounts.get(sample.event) ?? 0) + 1);
84
+ if (isFiniteNumber$1(sample.buildCoreMs)) buildCoreValues.push(sample.buildCoreMs);
85
+ if (isFiniteNumber$1(sample.transformMs)) transformValues.push(sample.transformMs);
86
+ if (isFiniteNumber$1(sample.writeMs)) writeValues.push(sample.writeMs);
87
+ if (isFiniteNumber$1(sample.watchToDirtyMs)) watchToDirtyValues.push(sample.watchToDirtyMs);
88
+ if (isFiniteNumber$1(sample.emitMs)) emitValues.push(sample.emitMs);
89
+ if (isFiniteNumber$1(sample.sharedChunkResolveMs)) sharedChunkValues.push(sample.sharedChunkResolveMs);
90
+ collectCounts(dirtyReasonCounts, sample.dirtyReasonSummary);
91
+ collectCounts(pendingReasonCounts, sample.pendingReasonSummary);
92
+ }
93
+ const orderedByTime = [...samples].sort((left, right) => {
94
+ const leftTime = typeof left.timestamp === "string" ? Date.parse(left.timestamp) : NaN;
95
+ const rightTime = typeof right.timestamp === "string" ? Date.parse(right.timestamp) : NaN;
96
+ if (Number.isFinite(leftTime) && Number.isFinite(rightTime)) return leftTime - rightTime;
97
+ return 0;
98
+ });
99
+ const slowestSamples = [...samples].sort((left, right) => (right.totalMs ?? 0) - (left.totalMs ?? 0)).slice(0, options.topSlowest ?? 5);
100
+ return {
101
+ runtime: "mini",
102
+ kind: "hmr-profile",
103
+ generatedAt: (options.now ?? /* @__PURE__ */ new Date()).toISOString(),
104
+ profilePath: options.profilePath,
105
+ sampleCount: samples.length,
106
+ skippedLineCount,
107
+ firstTimestamp: orderedByTime[0]?.timestamp,
108
+ lastTimestamp: orderedByTime.at(-1)?.timestamp,
109
+ metrics: {
110
+ totalMs: createMetricSummary(totalValues),
111
+ buildCoreMs: createMetricSummary(buildCoreValues),
112
+ transformMs: createMetricSummary(transformValues),
113
+ writeMs: createMetricSummary(writeValues),
114
+ watchToDirtyMs: createMetricSummary(watchToDirtyValues),
115
+ emitMs: createMetricSummary(emitValues),
116
+ sharedChunkResolveMs: createMetricSummary(sharedChunkValues)
117
+ },
118
+ events: sortCountEntries(eventCounts),
119
+ dirtyReasons: sortCountEntries(dirtyReasonCounts),
120
+ pendingReasons: sortCountEntries(pendingReasonCounts),
121
+ slowestSamples
122
+ };
123
+ }
124
+ //#endregion
26
125
  //#region src/analyze/subpackages/classifier.ts
27
126
  const VIRTUAL_MODULE_INDICATOR = "\0";
28
127
  const VIRTUAL_PREFIX = `${SHARED_CHUNK_VIRTUAL_PREFIX}/`;
@@ -810,8 +909,42 @@ async function writeAnalyzeResult(result, outputOption, configService) {
810
909
  logger_default.success(`分析结果已写入 ${colors.green(relativeOutput)}`);
811
910
  return resolvedOutputPath;
812
911
  }
912
+ function formatMetricSummary(label, metric) {
913
+ if (!metric.count || metric.averageMs === void 0 || metric.maxMs === void 0) return;
914
+ return `${label} avg ${metric.averageMs.toFixed(2)} ms,max ${metric.maxMs.toFixed(2)} ms`;
915
+ }
916
+ function formatCountItems(items, limit = 5) {
917
+ return items.slice(0, limit).map((item) => `${item.name} x${item.count}`).join(",");
918
+ }
919
+ function printHmrProfileAnalysisSummary(result, configService) {
920
+ logger_default.success("HMR profile 分析完成");
921
+ logger_default.info(`- profile:${colors.green(configService.relativeCwd(result.profilePath))}`);
922
+ logger_default.info(`- 样本:${result.sampleCount} 条`);
923
+ if (result.firstTimestamp && result.lastTimestamp) logger_default.info(`- 时间范围:${result.firstTimestamp} -> ${result.lastTimestamp}`);
924
+ const totalSummary = formatMetricSummary("total", result.metrics.totalMs);
925
+ const watchSummary = formatMetricSummary("watch->dirty", result.metrics.watchToDirtyMs);
926
+ const emitSummary = formatMetricSummary("emit", result.metrics.emitMs);
927
+ const sharedSummary = formatMetricSummary("shared", result.metrics.sharedChunkResolveMs);
928
+ for (const summary of [
929
+ totalSummary,
930
+ watchSummary,
931
+ emitSummary,
932
+ sharedSummary
933
+ ]) if (summary) logger_default.info(`- ${summary}`);
934
+ if (result.events.length) logger_default.info(`- 事件分布:${formatCountItems(result.events)}`);
935
+ if (result.dirtyReasons.length) logger_default.info(`- 主要 dirty 原因:${formatCountItems(result.dirtyReasons)}`);
936
+ if (result.pendingReasons.length) logger_default.info(`- 主要 pending 原因:${formatCountItems(result.pendingReasons)}`);
937
+ if (result.skippedLineCount > 0) logger_default.warn(`- 跳过 ${result.skippedLineCount} 条无法解析的 profile 记录`);
938
+ if (result.slowestSamples.length) {
939
+ logger_default.info("- 最慢样本:");
940
+ for (const sample of result.slowestSamples.slice(0, 3)) {
941
+ const fileLabel = sample.file ? configService.relativeCwd(sample.file) : "(unknown)";
942
+ logger_default.info(` - ${sample.totalMs?.toFixed(2) ?? "0.00"} ms,${sample.event ?? "unknown"},${fileLabel}`);
943
+ }
944
+ }
945
+ }
813
946
  function registerAnalyzeCommand(cli) {
814
- cli.command("analyze [root]", "analyze 两端包体与源码映射").option("--json", `[boolean] 输出 JSON 结果`).option("--output <file>", `[string] 将分析结果写入指定文件(JSON)`).option("-p, --platform <platform>", `[string] target platform (weapp | h5)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).action(async (root, options) => {
947
+ cli.command("analyze [root]", "analyze 两端包体与源码映射").option("--hmr-profile [file]", `[string | boolean] 分析 HMR JSONL profile,省略值时优先读取配置,否则回退到默认路径`).option("--json", `[boolean] 输出 JSON 结果`).option("--output <file>", `[string] 将分析结果写入指定文件(JSON)`).option("-p, --platform <platform>", `[string] target platform (weapp | h5)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).action(async (root, options) => {
815
948
  filterDuplicateOptions(options);
816
949
  const configFile = resolveConfigFile(options);
817
950
  const outputJson = coerceBooleanOption(options.json);
@@ -831,6 +964,21 @@ function registerAnalyzeCommand(cli) {
831
964
  resolvedConfigPlatform: ctx.configService.platform
832
965
  });
833
966
  const outputOption = typeof options.output === "string" ? options.output.trim() : "";
967
+ if (options.hmrProfile !== void 0 && options.hmrProfile !== false) {
968
+ const profileOption = typeof options.hmrProfile === "string" && options.hmrProfile.trim() ? options.hmrProfile.trim() : ctx.configService.weappViteConfig.hmr?.profileJson;
969
+ const profilePath = resolveHmrProfileJsonPath({
970
+ cwd: ctx.configService.cwd,
971
+ option: profileOption,
972
+ fallbackToDefault: true
973
+ });
974
+ if (!profilePath) throw new Error("未找到可用的 HMR profile 文件路径");
975
+ const hmrProfileResult = await analyzeHmrProfile({ profilePath });
976
+ const writtenPath = await writeAnalyzeResult(hmrProfileResult, outputOption, ctx.configService);
977
+ if (outputJson) {
978
+ if (!writtenPath) process.stdout.write(`${JSON.stringify(hmrProfileResult, null, 2)}\n`);
979
+ } else printHmrProfileAnalysisSummary(hmrProfileResult, ctx.configService);
980
+ return;
981
+ }
834
982
  if (targets.runWeb) {
835
983
  const webResult = createWebAnalyzeResult(ctx.configService, { platform: targets.label === "web" ? "web" : "h5" });
836
984
  const writtenPath = await writeAnalyzeResult(webResult, outputOption, ctx.configService);
@@ -952,42 +1100,133 @@ function logBuildPackageSizeReport(options) {
952
1100
  }
953
1101
  }
954
1102
  //#endregion
955
- //#region src/cli/openIde.ts
956
- const execFileAsync = promisify(execFile);
957
- function shouldLogAutomatorFallbackError() {
958
- const flag = process.env.WEAPP_VITE_DEBUG_AUTOMATOR_OPEN;
959
- return flag === "1" || flag === "true";
1103
+ //#region src/cli/openIde/execute.ts
1104
+ function readArgOption(argv, ...names) {
1105
+ for (let index = 0; index < argv.length; index += 1) {
1106
+ const current = argv[index];
1107
+ if (!names.includes(current)) continue;
1108
+ const next = argv[index + 1];
1109
+ if (typeof next === "string" && !next.startsWith("-")) return next;
1110
+ }
960
1111
  }
961
- async function openWechatIdeByAutomator(projectPath) {
962
- (await launchAutomator({
963
- projectPath,
964
- trustProject: true
965
- })).disconnect();
1112
+ async function tryExecuteWechatIdeCliCommandByAutomator(argv, projectPath) {
1113
+ if (!projectPath) return false;
1114
+ const command = argv[0];
1115
+ if (!command) return false;
1116
+ if (command === "compile") {
1117
+ await compileWechatIdeByAutomator({ projectPath });
1118
+ return true;
1119
+ }
1120
+ if (command === "cache") {
1121
+ const cleanType = readArgOption(argv, "--clean", "-c");
1122
+ if (cleanType !== "compile" && cleanType !== "all") return false;
1123
+ await clearWechatIdeCacheByAutomator({
1124
+ clean: cleanType,
1125
+ projectPath
1126
+ });
1127
+ return true;
1128
+ }
1129
+ return false;
1130
+ }
1131
+ async function tryExecuteWechatIdeCliCommandByHttp(argv, projectPath) {
1132
+ const command = argv[0];
1133
+ if (!command) return false;
1134
+ if (command === "compile") {
1135
+ if (!projectPath) return false;
1136
+ await openWechatIdeProjectByHttp(projectPath);
1137
+ return true;
1138
+ }
1139
+ if (command === "reset-fileutils") {
1140
+ if (!projectPath) return false;
1141
+ await resetWechatIdeFileUtilsByHttp(projectPath);
1142
+ return true;
1143
+ }
1144
+ if (command === "engine" && argv[1] === "build") {
1145
+ const engineProjectPath = argv[2] || projectPath;
1146
+ if (!engineProjectPath) return false;
1147
+ await runWechatIdeEngineBuild(engineProjectPath, { logPath: readArgOption(argv, "--logPath", "-l") });
1148
+ return true;
1149
+ }
1150
+ return false;
1151
+ }
1152
+ async function tryExecuteWechatIdeCliCommandByHelper(argv) {
1153
+ const command = argv[0];
1154
+ if (!command) return false;
1155
+ if (command === "close") {
1156
+ await closeWechatIdeProject();
1157
+ return true;
1158
+ }
1159
+ if (command === "quit") {
1160
+ await quitWechatIde();
1161
+ return true;
1162
+ }
1163
+ if (command === "cache") {
1164
+ const cleanType = readArgOption(argv, "--clean", "-c");
1165
+ if (!cleanType) return false;
1166
+ await clearWechatIdeCache({ clean: cleanType });
1167
+ return true;
1168
+ }
1169
+ return false;
966
1170
  }
967
1171
  /**
968
- * @description 执行 IDE 打开流程,并在登录失效时允许按键重试。
1172
+ * @description 统一执行 weapp-ide-cli 命令,并在登录失效时复用同一套重试交互。
969
1173
  */
970
- async function runWechatIdeOpenWithRetry(argv) {
971
- let retrying = true;
972
- while (retrying) try {
973
- await parse(argv);
974
- return;
975
- } catch (error) {
976
- if (!isWechatIdeLoginRequiredError(error)) {
977
- logger_default.error(error);
978
- return;
1174
+ async function executeWechatIdeCliCommand(argv, options = {}) {
1175
+ const { automatorMode = "prefer", cancelLevel = "warn", httpMode = "prefer", onNonLoginError, onRetry, projectPath } = options;
1176
+ await runWithSuspendedSharedInput(async () => {
1177
+ if (httpMode !== "skip") try {
1178
+ if (await tryExecuteWechatIdeCliCommandByHttp(argv, projectPath)) return;
1179
+ } catch (error) {
1180
+ if (httpMode === "require") throw error;
979
1181
  }
980
- logger_default.error("检测到微信开发者工具登录状态失效,请先登录后重试。");
981
- logger_default.warn(formatWechatIdeLoginRequiredError(error));
982
- logger_default.info(formatRetryHotkeyPrompt());
983
- if (await waitForRetryKeypress() !== "retry") {
984
- logger_default.warn("已取消重试。完成登录后请重新执行当前命令。");
985
- retrying = false;
986
- continue;
1182
+ try {
1183
+ if (await tryExecuteWechatIdeCliCommandByAutomator(argv, projectPath)) return;
1184
+ } catch (error) {
1185
+ if (automatorMode === "require") throw error;
987
1186
  }
988
- logger_default.info(colors.bold(colors.green("正在重试连接微信开发者工具...")));
989
- }
1187
+ try {
1188
+ if (await tryExecuteWechatIdeCliCommandByHelper(argv)) return;
1189
+ } catch (error) {
1190
+ if (onNonLoginError) {
1191
+ onNonLoginError(error);
1192
+ return;
1193
+ }
1194
+ throw error;
1195
+ }
1196
+ await runRetryableCommand({
1197
+ createCancelError: () => /* @__PURE__ */ new Error("cancelled"),
1198
+ execute: async () => {
1199
+ try {
1200
+ await parse(argv);
1201
+ return null;
1202
+ } catch (error) {
1203
+ if (!isWechatIdeLoginRequiredError(error)) {
1204
+ if (onNonLoginError) {
1205
+ onNonLoginError(error);
1206
+ return null;
1207
+ }
1208
+ throw error;
1209
+ }
1210
+ return error;
1211
+ }
1212
+ },
1213
+ isRetryableResult: (result) => result !== null,
1214
+ onCancel: () => {},
1215
+ onRetry: () => {
1216
+ onRetry?.();
1217
+ },
1218
+ promptRetry: async (error) => await promptWechatIdeLoginRetry({
1219
+ cancelLevel,
1220
+ error,
1221
+ logger: logger_default
1222
+ }),
1223
+ shouldRetry: (action) => action === "retry"
1224
+ });
1225
+ });
990
1226
  }
1227
+ //#endregion
1228
+ //#region src/cli/openIde/close.ts
1229
+ const execFileAsync = promisify(execFile);
991
1230
  async function closeIdeByAppleScript() {
992
1231
  if (process.platform !== "darwin") return false;
993
1232
  const appName = process.env.WEAPP_DEVTOOLS_APP_NAME || "wechatwebdevtools";
@@ -1009,29 +1248,21 @@ async function closeIdeByProcessKill(cliPath) {
1009
1248
  }
1010
1249
  }
1011
1250
  /**
1012
- * @description 根据 mpDistRoot 推导 IDE 项目目录(目录内应包含 project/mini 配置)
1251
+ * @description 关闭微信开发者工具,并在 CLI 不可用时回退到系统级关闭。
1013
1252
  */
1014
- function resolveIdeProjectPath(mpDistRoot) {
1015
- if (!mpDistRoot || !mpDistRoot.trim()) return;
1016
- const parent = path.dirname(mpDistRoot);
1017
- if (!parent || parent === "." || parent === "/") return;
1018
- return parent;
1019
- }
1020
- /**
1021
- * @description 结合 mpDistRoot 与配置根目录解析最终 IDE 项目目录。
1022
- */
1023
- function resolveIdeProjectRoot(mpDistRoot, cwd) {
1024
- return resolveIdeProjectPath(mpDistRoot) ?? cwd;
1025
- }
1026
- async function closeIde() {
1253
+ async function closeIde$1() {
1027
1254
  const config = await getConfig();
1028
1255
  const cliPath = config.cliPath?.trim() ? config.cliPath : null;
1029
1256
  try {
1030
- await parse(["close"]);
1257
+ await closeWechatIdeProject();
1031
1258
  return true;
1032
1259
  } catch (error) {
1033
1260
  if (isWechatIdeLoginRequiredError(error)) try {
1034
- await runWechatIdeOpenWithRetry(["close"]);
1261
+ await executeWechatIdeCliCommand(["close"], {
1262
+ cancelLevel: "warn",
1263
+ onNonLoginError: (retryError) => logger_default.error(retryError),
1264
+ onRetry: () => logger_default.info("正在重试连接微信开发者工具...")
1265
+ });
1035
1266
  return true;
1036
1267
  } catch (retryError) {
1037
1268
  logger_default.error(retryError);
@@ -1051,25 +1282,36 @@ async function closeIde() {
1051
1282
  return false;
1052
1283
  }
1053
1284
  }
1285
+ //#endregion
1286
+ //#region src/cli/openIde/reuse.ts
1054
1287
  function formatReuseOpenedWechatIdePrompt() {
1055
1288
  return `目标项目已在微信开发者工具中打开,已跳过重复打开。按 ${colors.bold(colors.green("r"))} 关闭当前窗口后重新打开。`;
1056
1289
  }
1057
- /**
1058
- * @description 若当前项目已在微信开发者工具中打开且自动化可连通,则直接复用现有会话,避免重复拉起 IDE。
1059
- */
1060
- async function tryReuseOpenedWechatIde(projectPath) {
1061
- let miniProgram;
1290
+ async function openWechatIdeByAutomator(projectPath) {
1291
+ (await launchAutomator({
1292
+ projectPath,
1293
+ trustProject: true
1294
+ })).disconnect();
1295
+ }
1296
+ async function connectOpenedProject(projectPath) {
1062
1297
  try {
1063
- miniProgram = await connectOpenedAutomator({
1298
+ return await connectOpenedAutomator({
1064
1299
  projectPath,
1065
1300
  timeout: 3e3
1066
1301
  });
1067
1302
  } catch {
1068
1303
  return null;
1069
1304
  }
1305
+ }
1306
+ /**
1307
+ * @description 若当前项目已在微信开发者工具中打开且自动化可连通,则直接复用现有会话,避免重复拉起 IDE。
1308
+ */
1309
+ async function tryReuseOpenedWechatIde(projectPath, closeIde) {
1310
+ const miniProgram = await connectOpenedProject(projectPath);
1311
+ if (!miniProgram) return null;
1070
1312
  miniProgram.disconnect();
1071
1313
  logger_default.info(formatReuseOpenedWechatIdePrompt());
1072
- if (await waitForRetryKeypress() !== "retry") return {
1314
+ if (await promptRetryKeypress({ logger: logger_default }) !== "retry") return {
1073
1315
  reopened: false,
1074
1316
  reused: true
1075
1317
  };
@@ -1081,22 +1323,113 @@ async function tryReuseOpenedWechatIde(projectPath) {
1081
1323
  reused: false
1082
1324
  };
1083
1325
  }
1084
- async function reopenOpenedWechatIde(projectPath) {
1085
- let miniProgram;
1086
- try {
1087
- miniProgram = await connectOpenedAutomator({
1088
- projectPath,
1089
- timeout: 3e3
1090
- });
1091
- } catch {
1092
- return false;
1093
- }
1326
+ /**
1327
+ * @description 对已打开的目标项目执行强制重开,以刷新最新构建产物。
1328
+ */
1329
+ async function reopenOpenedWechatIde(projectPath, closeIde) {
1330
+ const miniProgram = await connectOpenedProject(projectPath);
1331
+ if (!miniProgram) return false;
1094
1332
  miniProgram.disconnect();
1095
1333
  logger_default.info("目标项目已在微信开发者工具中打开,当前命令将主动重开以刷新最新构建产物。");
1096
1334
  if (!await closeIde()) logger_default.warn("关闭当前微信开发者工具失败,仍继续尝试重新打开目标项目。");
1097
1335
  await openWechatIdeByAutomator(projectPath);
1098
1336
  return true;
1099
1337
  }
1338
+ //#endregion
1339
+ //#region src/cli/openIde/index.ts
1340
+ function shouldLogAutomatorFallbackError() {
1341
+ const flag = process.env.WEAPP_VITE_DEBUG_AUTOMATOR_OPEN;
1342
+ return flag === "1" || flag === "true";
1343
+ }
1344
+ /**
1345
+ * @description 执行 IDE 打开流程,并在登录失效时允许按键重试。
1346
+ */
1347
+ async function runWechatIdeOpenWithRetry(argv) {
1348
+ await executeWechatIdeCliCommand(argv, {
1349
+ cancelLevel: "warn",
1350
+ onNonLoginError: (error) => logger_default.error(error),
1351
+ onRetry: () => {
1352
+ logger_default.info(colors.bold(colors.green("正在重试连接微信开发者工具...")));
1353
+ }
1354
+ });
1355
+ }
1356
+ /**
1357
+ * @description 根据 mpDistRoot 推导 IDE 项目目录(目录内应包含 project/mini 配置)
1358
+ */
1359
+ function resolveIdeProjectPath(mpDistRoot) {
1360
+ if (!mpDistRoot || !mpDistRoot.trim()) return;
1361
+ const parent = path.dirname(mpDistRoot);
1362
+ if (!parent || parent === "." || parent === "/") return;
1363
+ return parent;
1364
+ }
1365
+ /**
1366
+ * @description 结合 mpDistRoot 与配置根目录解析最终 IDE 项目目录。
1367
+ */
1368
+ function resolveIdeProjectRoot(mpDistRoot, cwd) {
1369
+ return resolveIdeProjectPath(mpDistRoot) ?? cwd;
1370
+ }
1371
+ async function closeIde() {
1372
+ return await closeIde$1();
1373
+ }
1374
+ async function tryOpenWechatIdeByAutomator(projectPath, options) {
1375
+ if (options.reuseOpenedProject === false) {
1376
+ if (await reopenOpenedWechatIde(projectPath, closeIde)) return true;
1377
+ }
1378
+ const reuseResult = await tryReuseOpenedWechatIde(projectPath, closeIde);
1379
+ if (reuseResult?.reused || reuseResult?.reopened) return true;
1380
+ await openWechatIdeByAutomator(projectPath);
1381
+ return true;
1382
+ }
1383
+ /**
1384
+ * @description 打开后主动刷新微信开发者工具的项目索引,避免模拟器沿用过期 app 配置。
1385
+ */
1386
+ async function stabilizeOpenedWechatIdeProject(projectPath, servicePortEnabled) {
1387
+ if (servicePortEnabled === false) return;
1388
+ try {
1389
+ await executeWechatIdeCliCommand(["compile"], {
1390
+ httpMode: "prefer",
1391
+ onNonLoginError: (error) => logger_default.error(error),
1392
+ projectPath
1393
+ });
1394
+ await executeWechatIdeCliCommand([
1395
+ "reset-fileutils",
1396
+ "-p",
1397
+ projectPath
1398
+ ], {
1399
+ httpMode: "prefer",
1400
+ onNonLoginError: (error) => logger_default.error(error),
1401
+ projectPath
1402
+ });
1403
+ await executeWechatIdeCliCommand([
1404
+ "engine",
1405
+ "build",
1406
+ projectPath
1407
+ ], {
1408
+ httpMode: "prefer",
1409
+ onNonLoginError: (error) => logger_default.error(error),
1410
+ projectPath
1411
+ });
1412
+ try {
1413
+ await executeWechatIdeCliCommand(["compile"], {
1414
+ automatorMode: "require",
1415
+ httpMode: "skip",
1416
+ projectPath
1417
+ });
1418
+ } catch (error) {
1419
+ if (shouldLogAutomatorFallbackError()) logger_default.error(error);
1420
+ }
1421
+ } catch (error) {
1422
+ logger_default.warn("刷新微信开发者工具项目索引失败,已保留当前打开状态;如模拟器仍显示旧状态,可手动刷新一次。");
1423
+ if (shouldLogAutomatorFallbackError()) logger_default.error(error);
1424
+ }
1425
+ }
1426
+ function createIdeOpenArgv(platform, projectPath, options = {}) {
1427
+ const argv = ["open", "-p"];
1428
+ if (projectPath) argv.push(projectPath);
1429
+ if (platform === "weapp" && options.trustProject !== false) argv.push("--trust-project");
1430
+ if (platform && shouldPassPlatformArgToIdeOpen(platform)) argv.push("--platform", platform);
1431
+ return argv;
1432
+ }
1100
1433
  async function openIde(platform, projectPath, options = {}) {
1101
1434
  let bootstrapResult;
1102
1435
  if (platform === "weapp" && projectPath) try {
@@ -1110,13 +1443,10 @@ async function openIde(platform, projectPath, options = {}) {
1110
1443
  }
1111
1444
  if (platform === "weapp" && projectPath && bootstrapResult?.servicePortEnabled === false) logger_default.warn("检测到微信开发者工具服务端口当前处于关闭状态,已保留用户设置并回退到普通 open 流程。");
1112
1445
  if (platform === "weapp" && projectPath && options.trustProject !== false && bootstrapResult?.servicePortEnabled !== false) try {
1113
- if (options.reuseOpenedProject === false) {
1114
- if (await reopenOpenedWechatIde(projectPath)) return;
1446
+ if (await tryOpenWechatIdeByAutomator(projectPath, options)) {
1447
+ await stabilizeOpenedWechatIdeProject(projectPath, bootstrapResult?.servicePortEnabled);
1448
+ return;
1115
1449
  }
1116
- const reuseResult = await tryReuseOpenedWechatIde(projectPath);
1117
- if (reuseResult?.reused || reuseResult?.reopened) return;
1118
- await openWechatIdeByAutomator(projectPath);
1119
- return;
1120
1450
  } catch (error) {
1121
1451
  if (isAutomatorLoginError(error)) {
1122
1452
  logger_default.error("检测到微信开发者工具登录状态失效,请先登录后重试。");
@@ -1125,11 +1455,8 @@ async function openIde(platform, projectPath, options = {}) {
1125
1455
  logger_default.warn("通过 automator 启动微信开发者工具并自动信任项目失败,回退到普通 open 流程。");
1126
1456
  if (shouldLogAutomatorFallbackError()) logger_default.error(error);
1127
1457
  }
1128
- const argv = ["open", "-p"];
1129
- if (projectPath) argv.push(projectPath);
1130
- if (platform === "weapp" && options.trustProject !== false) argv.push("--trust-project");
1131
- if (platform && shouldPassPlatformArgToIdeOpen(platform)) argv.push("--platform", platform);
1132
- await runWechatIdeOpenWithRetry(argv);
1458
+ await runWechatIdeOpenWithRetry(createIdeOpenArgv(platform, projectPath, options));
1459
+ if (platform === "weapp" && projectPath) await stabilizeOpenedWechatIdeProject(projectPath, bootstrapResult?.servicePortEnabled);
1133
1460
  }
1134
1461
  /**
1135
1462
  * @description 解析 IDE 相关命令所需的平台、项目目录与配置上下文。
@@ -1149,6 +1476,7 @@ async function resolveIdeCommandContext(options) {
1149
1476
  platform ??= ctx.configService.platform;
1150
1477
  if (!projectPath) projectPath = resolveIdeProjectRoot(ctx.configService.mpDistRoot, ctx.configService.cwd);
1151
1478
  return {
1479
+ cwd: ctx.configService.cwd,
1152
1480
  platform,
1153
1481
  projectPath,
1154
1482
  weappViteConfig: ctx.configService.weappViteConfig,
@@ -1160,6 +1488,7 @@ async function resolveIdeCommandContext(options) {
1160
1488
  if (defaultProjectRoot) projectPath = resolveIdeProjectRoot(defaultProjectRoot, cwd);
1161
1489
  }
1162
1490
  return {
1491
+ cwd,
1163
1492
  platform,
1164
1493
  projectPath
1165
1494
  };
@@ -1586,6 +1915,79 @@ function sleep(ms) {
1586
1915
  return new Promise((resolve) => setTimeout(resolve, ms));
1587
1916
  }
1588
1917
  //#endregion
1918
+ //#region src/cli/hmrProfileSummary.ts
1919
+ function isFiniteNumber(value) {
1920
+ return typeof value === "number" && Number.isFinite(value);
1921
+ }
1922
+ function parseLatestHmrProfileSample(content) {
1923
+ const lines = content.split(/\r?\n/);
1924
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
1925
+ const trimmed = lines[index]?.trim();
1926
+ if (!trimmed) continue;
1927
+ try {
1928
+ const parsed = JSON.parse(trimmed);
1929
+ if (isFiniteNumber(parsed.totalMs)) return parsed;
1930
+ } catch {
1931
+ continue;
1932
+ }
1933
+ }
1934
+ }
1935
+ function formatPhaseHint(sample) {
1936
+ const topPhase = [
1937
+ {
1938
+ label: "build-core",
1939
+ value: sample.buildCoreMs
1940
+ },
1941
+ {
1942
+ label: "transform",
1943
+ value: sample.transformMs
1944
+ },
1945
+ {
1946
+ label: "watch->dirty",
1947
+ value: sample.watchToDirtyMs
1948
+ },
1949
+ {
1950
+ label: "emit",
1951
+ value: sample.emitMs
1952
+ },
1953
+ {
1954
+ label: "shared",
1955
+ value: sample.sharedChunkResolveMs
1956
+ },
1957
+ {
1958
+ label: "write",
1959
+ value: sample.writeMs
1960
+ }
1961
+ ].filter((phase) => isFiniteNumber(phase.value)).sort((left, right) => (right.value ?? 0) - (left.value ?? 0))[0];
1962
+ if (!topPhase || (topPhase.value ?? 0) < 5) return;
1963
+ return `${topPhase.label} ${topPhase.value.toFixed(2)} ms`;
1964
+ }
1965
+ /**
1966
+ * @description 读取最近一次 HMR profile,并格式化为 IDE 日志启动前的单行摘要。
1967
+ */
1968
+ async function readLatestHmrProfileSummary(options) {
1969
+ const profilePath = resolveHmrProfileJsonPath({
1970
+ cwd: options.cwd,
1971
+ option: options.weappViteConfig?.hmr?.profileJson
1972
+ });
1973
+ if (!profilePath) return;
1974
+ const content = await fs.readFile(profilePath, "utf8").catch(() => void 0);
1975
+ if (!content) return;
1976
+ const sample = parseLatestHmrProfileSample(content);
1977
+ if (!sample || !isFiniteNumber(sample.totalMs)) return;
1978
+ const relativeCwd = options.relativeCwd ?? ((value) => value);
1979
+ const segments = [`[hmr] 最近一次热更新 ${sample.totalMs.toFixed(2)} ms`];
1980
+ if (sample.event) segments.push(sample.event);
1981
+ if (sample.file) segments.push(relativeCwd(sample.file));
1982
+ const phaseHint = formatPhaseHint(sample);
1983
+ if (phaseHint) segments.push(`主耗时 ${phaseHint}`);
1984
+ return {
1985
+ file: sample.file,
1986
+ profilePath,
1987
+ line: segments.join(",")
1988
+ };
1989
+ }
1990
+ //#endregion
1589
1991
  //#region src/cli/commands/ide.ts
1590
1992
  async function waitForTermination(cleanup) {
1591
1993
  await new Promise((resolve) => {
@@ -1608,11 +2010,15 @@ async function waitForTermination(cleanup) {
1608
2010
  }
1609
2011
  });
1610
2012
  }
2013
+ function formatIdeOutput(data, options) {
2014
+ if (options.json) return JSON.stringify(data, null, 2);
2015
+ return JSON.stringify(data, null, 2);
2016
+ }
1611
2017
  /**
1612
2018
  * @description 执行 ide 子命令。
1613
2019
  */
1614
2020
  async function runIdeCommand(action, root, options) {
1615
- if (action !== "logs" && action !== "setup") throw new Error(`未知 ide 子命令: ${action ?? "(empty)"}`);
2021
+ if (action !== "logs" && action !== "setup" && action !== "info" && action !== "test-accounts" && action !== "ticket" && action !== "ticket:set" && action !== "ticket:refresh") throw new Error(`未知 ide 子命令: ${action ?? "(empty)"}`);
1616
2022
  filterDuplicateOptions(options);
1617
2023
  const configFile = resolveConfigFile(options);
1618
2024
  const targets = resolveRuntimeTargets(options);
@@ -1634,6 +2040,35 @@ async function runIdeCommand(action, root, options) {
1634
2040
  return;
1635
2041
  }
1636
2042
  if (options.open) await openIde(resolved.platform, resolved.projectPath, { trustProject: options.trustProject });
2043
+ if (action === "info") {
2044
+ const result = await getWechatIdeToolInfo({ projectPath: resolved.projectPath });
2045
+ logger_default.info(formatIdeOutput(result, options));
2046
+ return;
2047
+ }
2048
+ if (action === "test-accounts") {
2049
+ const result = await getWechatIdeTestAccounts({ projectPath: resolved.projectPath });
2050
+ logger_default.info(formatIdeOutput(result, options));
2051
+ return;
2052
+ }
2053
+ if (action === "ticket") {
2054
+ const result = await getWechatIdeTicket({ projectPath: resolved.projectPath });
2055
+ logger_default.info(formatIdeOutput(result, options));
2056
+ return;
2057
+ }
2058
+ if (action === "ticket:set") {
2059
+ if (!options.ticket) throw new Error("`weapp-vite ide ticket:set` 需要提供 --ticket。");
2060
+ await setWechatIdeTicket({
2061
+ projectPath: resolved.projectPath,
2062
+ ticket: options.ticket
2063
+ });
2064
+ logger_default.info(`已设置微信开发者工具 ticket:${options.ticket}`);
2065
+ return;
2066
+ }
2067
+ if (action === "ticket:refresh") {
2068
+ await refreshWechatIdeTicket({ projectPath: resolved.projectPath });
2069
+ logger_default.info("已刷新微信开发者工具 ticket。");
2070
+ return;
2071
+ }
1637
2072
  const forwardConsoleOptions = await resolveForwardConsoleOptions({
1638
2073
  ...resolved.weappViteConfig,
1639
2074
  forwardConsole: resolved.weappViteConfig?.forwardConsole === false ? { enabled: true } : {
@@ -1641,6 +2076,12 @@ async function runIdeCommand(action, root, options) {
1641
2076
  enabled: true
1642
2077
  }
1643
2078
  });
2079
+ const latestHmrSummary = await readLatestHmrProfileSummary({
2080
+ cwd: resolved.cwd ?? process.cwd(),
2081
+ relativeCwd: (value) => resolved.cwd ? value.replace(`${resolved.cwd}/`, "") : value,
2082
+ weappViteConfig: resolved.weappViteConfig
2083
+ });
2084
+ if (latestHmrSummary) logger_default.info(latestHmrSummary.line);
1644
2085
  const session = await startForwardConsoleBridge({
1645
2086
  projectPath: resolved.projectPath,
1646
2087
  agentName: void 0,
@@ -1657,7 +2098,7 @@ async function runIdeCommand(action, root, options) {
1657
2098
  * @description 注册 IDE 相关子命令。
1658
2099
  */
1659
2100
  function registerIdeCommand(cli) {
1660
- cli.command("ide [action] [root]", "forward Wechat DevTools console logs to terminal").option("-o, --open", "[boolean] open ide before attaching log bridge").option("-p, --platform <platform>", "[string] target platform (weapp | h5)").option("--project-config <path>", "[string] project config path (miniprogram only)").option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).action(async (action, root, options) => {
2101
+ cli.command("ide [action] [root]", "run Wechat DevTools utility actions and log bridge commands").option("-o, --open", "[boolean] open ide before attaching log bridge").option("-p, --platform <platform>", "[string] target platform (weapp | h5)").option("--project-config <path>", "[string] project config path (miniprogram only)").option("--ticket <value>", "[string] ticket used by `ide ticket:set`").option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).action(async (action, root, options) => {
1661
2102
  await runIdeCommand(action, root, options);
1662
2103
  });
1663
2104
  }
@@ -1979,16 +2420,18 @@ async function resolveHttpUrl(options) {
1979
2420
  }
1980
2421
  async function confirmWrite() {
1981
2422
  if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
1982
- const rl = createInterface({
1983
- input: process.stdin,
1984
- output: process.stdout
2423
+ return await runWithSuspendedSharedInput(async () => {
2424
+ const rl = createInterface({
2425
+ input: process.stdin,
2426
+ output: process.stdout
2427
+ });
2428
+ try {
2429
+ const normalized = (await rl.question("是否写入配置文件?(Y/n) ")).trim().toLowerCase();
2430
+ return normalized === "" || normalized === "y" || normalized === "yes";
2431
+ } finally {
2432
+ rl.close();
2433
+ }
1985
2434
  });
1986
- try {
1987
- const normalized = (await rl.question("是否写入配置文件?(Y/n) ")).trim().toLowerCase();
1988
- return normalized === "" || normalized === "y" || normalized === "yes";
1989
- } finally {
1990
- rl.close();
1991
- }
1992
2435
  }
1993
2436
  function resolveClientTransport(transport) {
1994
2437
  return transport === "http" ? "http" : "command";
@@ -2072,7 +2515,7 @@ function registerMcpCommand(cli) {
2072
2515
  function registerNpmCommand(cli) {
2073
2516
  cli.command("npm").alias("build:npm").alias("build-npm").action(async () => {
2074
2517
  try {
2075
- await parse(["build-npm", "-p"]);
2518
+ await buildWechatIdeNpm({ projectPath: process.cwd() });
2076
2519
  } catch (error) {
2077
2520
  logger_default.error(error);
2078
2521
  }
@@ -2085,13 +2528,19 @@ function registerOpenCommand(cli) {
2085
2528
  filterDuplicateOptions(options);
2086
2529
  const configFile = resolveConfigFile(options);
2087
2530
  const targets = resolveRuntimeTargets(options);
2088
- const { platform, projectPath, mpDistRoot } = await resolveIdeCommandContext({
2531
+ const { cwd, platform, projectPath, mpDistRoot, weappViteConfig } = await resolveIdeCommandContext({
2089
2532
  configFile,
2090
2533
  mode: options.mode ?? "development",
2091
2534
  platform: targets.mpPlatform,
2092
2535
  projectPath: root,
2093
2536
  cliPlatform: targets.rawPlatform
2094
2537
  });
2538
+ const latestHmrSummary = await readLatestHmrProfileSummary({
2539
+ cwd: cwd ?? process.cwd(),
2540
+ relativeCwd: (value) => cwd ? value.replace(`${cwd}/`, "") : value,
2541
+ weappViteConfig
2542
+ });
2543
+ if (latestHmrSummary) logger_default.info(latestHmrSummary.line);
2095
2544
  await openIde(platform, projectPath ?? resolveIdeProjectRoot(mpDistRoot, process.cwd()), { trustProject: options.trustProject });
2096
2545
  });
2097
2546
  }
@@ -2114,6 +2563,7 @@ function registerPrepareCommand(cli) {
2114
2563
  isDev: false,
2115
2564
  mode: typeof options.mode === "string" ? options.mode : "development",
2116
2565
  configFile: resolveConfigFile(options),
2566
+ configLoader: "native",
2117
2567
  syncSupportFiles: false,
2118
2568
  preloadAppEntry: false
2119
2569
  }));
@@ -2124,8 +2574,217 @@ function registerPrepareCommand(cli) {
2124
2574
  });
2125
2575
  }
2126
2576
  //#endregion
2577
+ //#region src/cli/devHotkeys/devtools.ts
2578
+ async function appendLatestHmrSummary(baseSummary, options) {
2579
+ const summary = await readLatestHmrProfileSummary({
2580
+ cwd: options.cwd,
2581
+ relativeCwd: (value) => value.replace(`${options.cwd}/`, ""),
2582
+ weappViteConfig: options.weappViteConfig
2583
+ });
2584
+ if (!summary) return baseSummary;
2585
+ return `${baseSummary};${summary.line}`;
2586
+ }
2587
+ /**
2588
+ * @description 重置当前 DevTools automator 共享会话。
2589
+ */
2590
+ async function runResetDevtoolsSessionAction(options) {
2591
+ logger_default.info("[dev action] 正在重置当前 DevTools 会话...");
2592
+ await closeSharedMiniProgram(options.projectPath);
2593
+ logger_default.success("[dev action] 当前 DevTools 会话已重置。");
2594
+ return "已重置当前 DevTools 会话";
2595
+ }
2596
+ /**
2597
+ * @description 重置共享会话并重开当前项目,以恢复 DevTools 状态。
2598
+ */
2599
+ async function runResetAndReopenDevtoolsAction(options) {
2600
+ if (!options.openIde) {
2601
+ logger_default.warn("[dev action] 当前 dev 会话未提供重新打开微信开发者工具的能力。");
2602
+ return "重置并重开微信开发者工具不可用";
2603
+ }
2604
+ logger_default.info("[dev action] 正在重置当前 DevTools 会话并重开项目...");
2605
+ await closeSharedMiniProgram(options.projectPath);
2606
+ const summary = await options.openIde();
2607
+ logger_default.success("[dev action] 当前 DevTools 会话已重置,并已重新打开项目。");
2608
+ return await appendLatestHmrSummary(summary ?? "已重置当前 DevTools 会话并重新打开项目", options);
2609
+ }
2610
+ /**
2611
+ * @description 手动触发一次当前小程序 dev 重新构建。
2612
+ */
2613
+ async function runDevRebuildAction(options) {
2614
+ if (!options.rebuild) {
2615
+ logger_default.warn("[dev action] 当前 dev 会话未提供手动重新构建能力。");
2616
+ return "手动重新构建不可用";
2617
+ }
2618
+ logger_default.info("[dev action] 正在手动重新构建当前小程序产物...");
2619
+ const summary = await options.rebuild();
2620
+ logger_default.success("[dev action] 当前小程序产物已手动重新构建。");
2621
+ return summary ?? "已手动重新构建当前小程序产物";
2622
+ }
2623
+ /**
2624
+ * @description 重新打开当前微信开发者工具项目,并主动清理共享 automator 会话。
2625
+ */
2626
+ async function runOpenIdeAction(options) {
2627
+ if (!options.openIde) {
2628
+ logger_default.warn("[dev action] 当前 dev 会话未提供重新打开微信开发者工具的能力。");
2629
+ return "重新打开微信开发者工具不可用";
2630
+ }
2631
+ logger_default.info(`[dev action] 正在重新打开微信开发者工具项目:${colors.cyan(options.projectPath)}`);
2632
+ await closeSharedMiniProgram(options.projectPath);
2633
+ const summary = await options.openIde();
2634
+ logger_default.success("[dev action] 微信开发者工具项目已重新打开。");
2635
+ return await appendLatestHmrSummary(summary ?? "已重新打开微信开发者工具项目", options);
2636
+ }
2637
+ //#endregion
2638
+ //#region src/cli/devHotkeys/screenshot.ts
2639
+ const DEV_SCREENSHOT_DIR = ".weapp-vite/dev-screenshots";
2640
+ const DEFAULT_SCREENSHOT_TIMEOUT = 3e4;
2641
+ /**
2642
+ * @description 生成开发态截图输出路径。
2643
+ */
2644
+ function resolveDevScreenshotOutputPath(cwd, now = /* @__PURE__ */ new Date()) {
2645
+ const stamp = now.toISOString().replace(/[:.]/g, "-");
2646
+ return path.join(cwd, DEV_SCREENSHOT_DIR, `screenshot-${stamp}.png`);
2647
+ }
2648
+ function formatLogPath(cwd, targetPath) {
2649
+ const relativePath = path.relative(cwd, targetPath);
2650
+ if (!relativePath || relativePath.startsWith("..")) return targetPath;
2651
+ return relativePath;
2652
+ }
2653
+ function formatResolvedScreenshotPath(cwd, fallbackPath, result) {
2654
+ return formatLogPath(cwd, result.path ?? fallbackPath);
2655
+ }
2656
+ /**
2657
+ * @description 执行当前页面截图并输出结果日志。
2658
+ */
2659
+ async function runScreenshotAction(options) {
2660
+ const outputPath = resolveDevScreenshotOutputPath(options.cwd);
2661
+ await fs$2.mkdir(path.dirname(outputPath), { recursive: true });
2662
+ logger_default.info(`[dev action] 正在截图当前页面,输出到 ${colors.cyan(formatLogPath(options.cwd, outputPath))}`);
2663
+ const result = await takeScreenshot({
2664
+ fullPage: true,
2665
+ projectPath: options.projectPath,
2666
+ sharedSession: true,
2667
+ outputPath,
2668
+ timeout: DEFAULT_SCREENSHOT_TIMEOUT
2669
+ });
2670
+ const resolvedPath = formatResolvedScreenshotPath(options.cwd, outputPath, result);
2671
+ logger_default.success(`[dev action] 当前页面截图完成:${colors.cyan(resolvedPath)}`);
2672
+ return resolvedPath;
2673
+ }
2674
+ //#endregion
2675
+ //#region src/cli/devHotkeys/actions.ts
2676
+ const DEV_HOTKEY_GROUPS = [
2677
+ {
2678
+ key: "development",
2679
+ title: "开发动作"
2680
+ },
2681
+ {
2682
+ key: "devtools",
2683
+ title: "会话动作"
2684
+ },
2685
+ {
2686
+ key: "process",
2687
+ title: "进程控制"
2688
+ },
2689
+ {
2690
+ key: "help",
2691
+ title: "帮助"
2692
+ }
2693
+ ];
2694
+ const DEV_HOTKEY_DEFINITIONS = [
2695
+ {
2696
+ description: "截图当前页面并保存到本地",
2697
+ group: "development",
2698
+ key: "s",
2699
+ label: "截图",
2700
+ pendingLabel: "正在截图当前页面",
2701
+ run: async ({ options }) => {
2702
+ return `截图已保存到 ${await runScreenshotAction(options)}`;
2703
+ }
2704
+ },
2705
+ {
2706
+ description: "手动重新构建当前小程序产物",
2707
+ group: "development",
2708
+ key: "r",
2709
+ label: "手动重新构建产物",
2710
+ pendingLabel: "正在手动重新构建当前小程序产物",
2711
+ run: async ({ options }) => {
2712
+ return await runDevRebuildAction(options);
2713
+ }
2714
+ },
2715
+ {
2716
+ description: "重置当前 DevTools automator 会话",
2717
+ group: "devtools",
2718
+ key: "c",
2719
+ label: "重置 DevTools 会话",
2720
+ pendingLabel: "正在重置当前 DevTools 会话",
2721
+ run: async ({ options }) => {
2722
+ return await runResetDevtoolsSessionAction(options);
2723
+ }
2724
+ },
2725
+ {
2726
+ description: "重置会话并重开当前微信开发者工具项目",
2727
+ group: "devtools",
2728
+ key: "C",
2729
+ label: "重置并重开项目",
2730
+ pendingLabel: "正在重置当前 DevTools 会话并重开项目",
2731
+ run: async ({ options }) => {
2732
+ return await runResetAndReopenDevtoolsAction(options);
2733
+ }
2734
+ },
2735
+ {
2736
+ description: "重新打开当前微信开发者工具项目",
2737
+ group: "devtools",
2738
+ key: "o",
2739
+ label: "重新打开微信开发者工具",
2740
+ pendingLabel: "正在重新打开微信开发者工具项目",
2741
+ run: async ({ options }) => {
2742
+ return await runOpenIdeAction(options);
2743
+ }
2744
+ },
2745
+ {
2746
+ description: "开关 MCP 服务",
2747
+ group: "devtools",
2748
+ key: "m",
2749
+ label: "MCP 切换",
2750
+ run: async ({ toggleMcp }) => {
2751
+ return await toggleMcp();
2752
+ }
2753
+ },
2754
+ {
2755
+ description: "退出当前 dev",
2756
+ group: "process",
2757
+ key: "q"
2758
+ },
2759
+ {
2760
+ description: "强制中断当前 dev",
2761
+ group: "process",
2762
+ key: "Ctrl+C"
2763
+ },
2764
+ {
2765
+ description: "暂时挂起当前 dev,恢复终端控制",
2766
+ group: "process",
2767
+ key: "Ctrl+Z"
2768
+ },
2769
+ {
2770
+ description: "重新显示这份帮助",
2771
+ group: "help",
2772
+ key: "h"
2773
+ }
2774
+ ];
2775
+ function resolveDevHotkeyRowsByGroup() {
2776
+ return DEV_HOTKEY_GROUPS.map((group) => ({
2777
+ key: group.key,
2778
+ rows: DEV_HOTKEY_DEFINITIONS.filter((action) => action.group === group.key),
2779
+ title: group.title
2780
+ }));
2781
+ }
2782
+ function resolveRunnableHotkeyDefinition(input) {
2783
+ return DEV_HOTKEY_DEFINITIONS.find((action) => action.run && action.key === input);
2784
+ }
2785
+ //#endregion
2127
2786
  //#region package.json
2128
- var version = "6.15.13";
2787
+ var version = "6.15.15";
2129
2788
  //#endregion
2130
2789
  //#region src/cli/devHotkeys/format.ts
2131
2790
  const FULLWIDTH_ASCII_START = 65281;
@@ -2143,55 +2802,45 @@ function formatFooterLine(state) {
2143
2802
  if (state.currentAction) return `执行中 ${state.currentAction}`;
2144
2803
  return "就绪 等待操作...";
2145
2804
  }
2805
+ function formatHotkeyRows(rows) {
2806
+ const key = (value) => colors.bold(colors.green(value));
2807
+ const formattedRows = rows.map((row) => ({
2808
+ description: row.description,
2809
+ key: key(row.key)
2810
+ }));
2811
+ const keyColumnWidth = Math.max(...formattedRows.map((row) => row.key.length));
2812
+ return formattedRows.map(({ key, description }) => `按 ${key.padEnd(keyColumnWidth)} ${description}`);
2813
+ }
2814
+ function formatExtraHotkeyRows(rows) {
2815
+ const key = (value) => colors.bold(colors.green(value));
2816
+ const formattedRows = rows.map(([hotkey, description]) => ({
2817
+ description,
2818
+ key: key(hotkey)
2819
+ }));
2820
+ const keyColumnWidth = Math.max(...formattedRows.map((row) => row.key.length));
2821
+ return formattedRows.map(({ key, description }) => `按 ${key.padEnd(keyColumnWidth)} ${description}`);
2822
+ }
2146
2823
  /**
2147
2824
  * @description 生成带状态的开发态快捷键帮助文本。
2148
2825
  */
2149
2826
  function formatDevHotkeyHelpWithState(state) {
2150
- const key = (value) => colors.bold(colors.green(value));
2151
- const actionRows = [{
2152
- key: key("s"),
2153
- description: "截图当前页面并保存到本地"
2154
- }, {
2155
- key: key("m"),
2156
- description: "开关 MCP 服务"
2157
- }];
2158
- const processRows = [
2159
- {
2160
- key: key("q"),
2161
- description: "退出当前 dev"
2162
- },
2163
- {
2164
- key: key("Ctrl+C"),
2165
- description: "强制中断当前 dev"
2166
- },
2167
- {
2168
- key: key("Ctrl+Z"),
2169
- description: "暂时挂起当前 dev,恢复终端控制"
2170
- }
2827
+ const sections = resolveDevHotkeyRowsByGroup().filter((section) => section.rows.length > 0).flatMap((section) => [
2828
+ "",
2829
+ section.title,
2830
+ ...formatHotkeyRows(section.rows)
2831
+ ]);
2832
+ const retrySections = [
2833
+ "",
2834
+ "登录重试",
2835
+ ...formatExtraHotkeyRows([[RETRY_CONFIRM_KEYS.join(" / "), "微信开发者工具登录失效后确认重试当前命令"], [RETRY_CANCEL_KEYS.join(" / "), "取消当前登录重试提示"]])
2171
2836
  ];
2172
- const helpRows = [{
2173
- key: key("h"),
2174
- description: "重新显示这份帮助"
2175
- }];
2176
- const keyColumnWidth = Math.max(...[
2177
- ...actionRows,
2178
- ...processRows,
2179
- ...helpRows
2180
- ].map((row) => row.key.length));
2181
- const formatRows = (rows) => rows.map(({ key, description }) => `按 ${key.padEnd(keyColumnWidth)} ${description}`);
2182
2837
  return [
2183
2838
  `${colors.bold(colors.green("DEV"))} weapp-vite v${version} ${state.projectLabel ?? "weapp"}`,
2839
+ ...sections,
2840
+ ...retrySections,
2184
2841
  "",
2185
- "快捷命令",
2186
- ...formatRows(actionRows),
2187
- "",
2188
- "进程控制",
2189
- ...formatRows(processRows),
2190
- "",
2191
- "帮助",
2192
- ...formatRows(helpRows),
2193
- "",
2194
- `当前状态:${state.currentAction ?? "等待操作"} / MCP ${formatMcpStatus(state)}`
2842
+ `当前状态:${state.currentAction ?? "等待操作"} / MCP ${formatMcpStatus(state)}`,
2843
+ ...state.lastAction ? [`最近操作:${state.lastAction}`] : []
2195
2844
  ].join("\n");
2196
2845
  }
2197
2846
  /**
@@ -2200,6 +2849,7 @@ function formatDevHotkeyHelpWithState(state) {
2200
2849
  function formatDevHotkeyHintWithState(state) {
2201
2850
  const key = (value) => colors.bold(colors.green(value));
2202
2851
  if (state.currentAction) return `${formatFooterLine(state)},按 ${key("h")} 显示帮助,按 ${key("q")} 退出`;
2852
+ if (state.lastAction) return `开发快捷键已就绪,最近操作:${state.lastAction},按 ${key("h")} 显示帮助,按 ${key("q")} 退出`;
2203
2853
  return `开发快捷键已就绪,按 ${key("h")} 显示帮助,按 ${key("q")} 退出`;
2204
2854
  }
2205
2855
  function normalizeInputChar(input) {
@@ -2252,43 +2902,6 @@ function createToggleMcpAction(options) {
2252
2902
  };
2253
2903
  }
2254
2904
  //#endregion
2255
- //#region src/cli/devHotkeys/screenshot.ts
2256
- const DEV_SCREENSHOT_DIR = ".weapp-vite/dev-screenshots";
2257
- const DEFAULT_SCREENSHOT_TIMEOUT = 3e4;
2258
- /**
2259
- * @description 生成开发态截图输出路径。
2260
- */
2261
- function resolveDevScreenshotOutputPath(cwd, now = /* @__PURE__ */ new Date()) {
2262
- const stamp = now.toISOString().replace(/[:.]/g, "-");
2263
- return path.join(cwd, DEV_SCREENSHOT_DIR, `screenshot-${stamp}.png`);
2264
- }
2265
- function formatLogPath(cwd, targetPath) {
2266
- const relativePath = path.relative(cwd, targetPath);
2267
- if (!relativePath || relativePath.startsWith("..")) return targetPath;
2268
- return relativePath;
2269
- }
2270
- function formatResolvedScreenshotPath(cwd, fallbackPath, result) {
2271
- return formatLogPath(cwd, result.path ?? fallbackPath);
2272
- }
2273
- /**
2274
- * @description 执行当前页面截图并输出结果日志。
2275
- */
2276
- async function runScreenshotAction(options) {
2277
- const outputPath = resolveDevScreenshotOutputPath(options.cwd);
2278
- await fs$2.mkdir(path.dirname(outputPath), { recursive: true });
2279
- logger_default.info(`[dev action] 正在截图当前页面,输出到 ${colors.cyan(formatLogPath(options.cwd, outputPath))}`);
2280
- const result = await takeScreenshot({
2281
- fullPage: true,
2282
- projectPath: options.projectPath,
2283
- sharedSession: true,
2284
- outputPath,
2285
- timeout: DEFAULT_SCREENSHOT_TIMEOUT
2286
- });
2287
- const resolvedPath = formatResolvedScreenshotPath(options.cwd, outputPath, result);
2288
- logger_default.success(`[dev action] 当前页面截图完成:${colors.cyan(resolvedPath)}`);
2289
- return resolvedPath;
2290
- }
2291
- //#endregion
2292
2905
  //#region src/cli/devHotkeys/index.ts
2293
2906
  function forwardSigint() {
2294
2907
  process.kill(process.pid, "SIGINT");
@@ -2301,10 +2914,6 @@ function forwardSigtstp() {
2301
2914
  */
2302
2915
  function startDevHotkeys(options) {
2303
2916
  if (options.platform !== "weapp" || !process.stdin.isTTY) return;
2304
- emitKeypressEvents(process.stdin);
2305
- const hasSetRawMode = typeof process.stdin.setRawMode === "function";
2306
- if (hasSetRawMode) process.stdin.setRawMode(true);
2307
- process.stdin.resume();
2308
2917
  let closed = false;
2309
2918
  let running = false;
2310
2919
  let mcpHandle;
@@ -2323,27 +2932,20 @@ function startDevHotkeys(options) {
2323
2932
  mcpRunning: Boolean(mcpHandle?.close),
2324
2933
  projectLabel: resolveProjectLabel(options.cwd)
2325
2934
  });
2326
- const detachTerminal = () => {
2327
- if (hasSetRawMode) process.stdin.setRawMode(false);
2328
- process.stdin.pause();
2329
- };
2330
- const attachTerminal = () => {
2331
- if (closed) return;
2332
- if (hasSetRawMode) process.stdin.setRawMode(true);
2333
- process.stdin.resume();
2334
- };
2335
- const ensureTerminalActive = () => {
2336
- if (closed) return;
2337
- if (hasSetRawMode) process.stdin.setRawMode(true);
2338
- process.stdin.resume();
2339
- };
2935
+ let inputSession = createSharedInputSession({
2936
+ onData: (chunk) => {
2937
+ onData?.(chunk);
2938
+ },
2939
+ onKeypress: (str, key) => {
2940
+ onKeypress?.(str, key);
2941
+ }
2942
+ });
2340
2943
  const close = () => {
2341
2944
  if (closed) return;
2342
2945
  closed = true;
2343
- if (onData) process.stdin.off("data", onData);
2344
- if (onKeypress) process.stdin.off("keypress", onKeypress);
2345
2946
  if (onSigcont) process.off("SIGCONT", onSigcont);
2346
- detachTerminal();
2947
+ inputSession?.close();
2948
+ inputSession = void 0;
2347
2949
  if (mcpHandle?.close) mcpHandle.close().catch((error) => {
2348
2950
  logger_default.warn(`[dev action] MCP 服务关闭失败:${error instanceof Error ? error.message : String(error)}`);
2349
2951
  });
@@ -2358,24 +2960,18 @@ function startDevHotkeys(options) {
2358
2960
  };
2359
2961
  const printHelp = () => {
2360
2962
  printPanel(formatDevHotkeyHelpWithState(getState()), true);
2361
- ensureTerminalActive();
2362
2963
  };
2363
2964
  const printHint = () => {
2364
2965
  printPanel(formatDevHotkeyHintWithState(getState()));
2365
- ensureTerminalActive();
2366
2966
  };
2367
2967
  const restore = () => {
2368
2968
  if (closed) return;
2369
- if (onData) process.stdin.off("data", onData);
2370
- if (onKeypress) process.stdin.off("keypress", onKeypress);
2371
- attachTerminal();
2372
- if (onData) process.stdin.on("data", onData);
2373
- if (onKeypress) process.stdin.on("keypress", onKeypress);
2969
+ inputSession?.resume();
2374
2970
  printHint();
2375
2971
  };
2376
2972
  const suspend = () => {
2377
2973
  lastRenderedPanel = "";
2378
- detachTerminal();
2974
+ inputSession?.suspend();
2379
2975
  forwardSigtstp();
2380
2976
  };
2381
2977
  const toggleMcp = createToggleMcpAction({
@@ -2386,6 +2982,9 @@ function startDevHotkeys(options) {
2386
2982
  mcpHandle = handle;
2387
2983
  }
2388
2984
  });
2985
+ const resolvePendingLabel = (input) => {
2986
+ if (input === "m") return mcpHandle?.close ? "正在关闭 MCP 服务" : "正在启动 MCP 服务";
2987
+ };
2389
2988
  const runAction = (label, pendingLabel, action) => {
2390
2989
  if (running) {
2391
2990
  const current = currentAction ?? "已有命令";
@@ -2427,14 +3026,13 @@ function startDevHotkeys(options) {
2427
3026
  printHelp();
2428
3027
  return;
2429
3028
  }
2430
- if (normalized === "s") {
2431
- runAction("截图", "正在截图当前页面", async () => {
2432
- return `截图已保存到 ${await runScreenshotAction(options)}`;
3029
+ const action = resolveRunnableHotkeyDefinition(normalizedInput) ?? resolveRunnableHotkeyDefinition(normalized);
3030
+ const run = action?.run;
3031
+ if (run) runAction(action.label ?? action.description, resolvePendingLabel(normalized) ?? action.pendingLabel ?? `正在执行 ${action.description}`, async () => {
3032
+ return await run({
3033
+ options,
3034
+ toggleMcp
2433
3035
  });
2434
- return;
2435
- }
2436
- if (normalized === "m") runAction("MCP 切换", mcpHandle?.close ? "正在关闭 MCP 服务" : "正在启动 MCP 服务", async () => {
2437
- return await toggleMcp();
2438
3036
  });
2439
3037
  };
2440
3038
  const handleInputOnce = (input, source) => {
@@ -2454,7 +3052,6 @@ function startDevHotkeys(options) {
2454
3052
  const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
2455
3053
  for (const char of text) handleInputOnce(char, "data");
2456
3054
  };
2457
- process.stdin.on("data", onData);
2458
3055
  onKeypress = (str, key) => {
2459
3056
  if (key?.ctrl && key.name === "c") {
2460
3057
  handleInputOnce("", "keypress");
@@ -2466,7 +3063,6 @@ function startDevHotkeys(options) {
2466
3063
  }
2467
3064
  if (typeof str === "string" && str) handleInputOnce(str, "keypress");
2468
3065
  };
2469
- process.stdin.on("keypress", onKeypress);
2470
3066
  onSigcont = () => {
2471
3067
  restore();
2472
3068
  };
@@ -2697,6 +3293,24 @@ function resolveWebHost(host) {
2697
3293
  if (typeof host === "string") return host;
2698
3294
  return String(host);
2699
3295
  }
3296
+ /**
3297
+ * @description 为 serve 模式构造统一的小程序开发动作,供热键与命令复用。
3298
+ */
3299
+ function createServeMiniProgramDevActions(options) {
3300
+ const projectPath = options.projectPath ?? options.fallbackProjectPath;
3301
+ return {
3302
+ projectPath,
3303
+ openIde: async () => {
3304
+ if (await options.tryReuseForwardConsole?.()) return "已通过控制台转发复用当前开发者工具会话";
3305
+ await options.openIde(projectPath);
3306
+ return "已重新打开微信开发者工具项目";
3307
+ },
3308
+ rebuild: async () => {
3309
+ await options.build();
3310
+ return "已手动重新构建当前小程序产物";
3311
+ }
3312
+ };
3313
+ }
2700
3314
  function waitForServeShutdownSignal() {
2701
3315
  return new Promise((resolve) => {
2702
3316
  const onSignal = () => {
@@ -2758,12 +3372,36 @@ function registerServeCommand(cli) {
2758
3372
  logRuntimeTarget(targets, { resolvedConfigPlatform: configService.platform });
2759
3373
  const enableAnalyze = Boolean(isUiEnabled(options) && targets.runMini);
2760
3374
  let analyzeHandle;
3375
+ const miniProgramDevActions = createServeMiniProgramDevActions({
3376
+ build: async () => {
3377
+ await buildService.build(options);
3378
+ },
3379
+ fallbackProjectPath: configService.cwd,
3380
+ openIde: async (projectPath) => {
3381
+ await openIde(configService.platform, projectPath, {
3382
+ reuseOpenedProject: false,
3383
+ trustProject: options.trustProject
3384
+ });
3385
+ },
3386
+ projectPath: resolveIdeProjectRoot(configService.mpDistRoot, configService.cwd),
3387
+ tryReuseForwardConsole: async () => {
3388
+ return await maybeStartForwardConsole({
3389
+ platform: configService.platform,
3390
+ mpDistRoot: configService.mpDistRoot,
3391
+ cwd: configService.cwd,
3392
+ weappViteConfig: configService.weappViteConfig
3393
+ });
3394
+ }
3395
+ });
2761
3396
  const devHotkeysSession = targets.runMini ? startDevHotkeys({
2762
3397
  cwd: configService.cwd,
2763
3398
  mcpConfig: configService.weappViteConfig?.mcp,
3399
+ openIde: miniProgramDevActions.openIde,
2764
3400
  platform: configService.platform,
2765
- projectPath: resolveIdeProjectRoot(configService.mpDistRoot, configService.cwd) ?? configService.cwd,
2766
- silentStartupHint: true
3401
+ projectPath: miniProgramDevActions.projectPath ?? configService.cwd,
3402
+ rebuild: miniProgramDevActions.rebuild,
3403
+ silentStartupHint: true,
3404
+ weappViteConfig: configService.weappViteConfig
2767
3405
  }) : void 0;
2768
3406
  try {
2769
3407
  const analyzeController = createAnalyzeController({
@@ -2824,15 +3462,7 @@ function registerServeCommand(cli) {
2824
3462
  detail: "开发服务已就绪,准备打开 IDE 项目。",
2825
3463
  tags: ["ide", "open"]
2826
3464
  }]);
2827
- if (!await maybeStartForwardConsole({
2828
- platform: configService.platform,
2829
- mpDistRoot: configService.mpDistRoot,
2830
- cwd: configService.cwd,
2831
- weappViteConfig: configService.weappViteConfig
2832
- })) await openIde(configService.platform, resolveIdeProjectRoot(configService.mpDistRoot, configService.cwd), {
2833
- reuseOpenedProject: false,
2834
- trustProject: options.trustProject
2835
- });
3465
+ await miniProgramDevActions.openIde();
2836
3466
  devHotkeysSession?.restore();
2837
3467
  }
2838
3468
  if (analyzeHandle) await analyzeController.waitForExit();
@@ -2904,18 +3534,18 @@ async function tryRunIdeCommand(argv) {
2904
3534
  if (!command) return false;
2905
3535
  if (command === "ide") {
2906
3536
  if (argv[1] === "logs") return false;
2907
- await parse(argv.slice(1));
3537
+ if (!await dispatchWechatCliCommand(argv.slice(1))) await executeWechatIdeCliCommand(argv.slice(1));
2908
3538
  return true;
2909
3539
  }
2910
3540
  if (command.startsWith("-")) return false;
2911
3541
  if (command === "help") {
2912
3542
  const target = argv[1];
2913
3543
  if (!target || WEAPP_VITE_NATIVE_COMMANDS.has(target) || !isWeappIdeTopLevelCommand(target)) return false;
2914
- await parse(argv);
3544
+ await executeWechatIdeCliCommand(argv);
2915
3545
  return true;
2916
3546
  }
2917
3547
  if (WEAPP_VITE_NATIVE_COMMANDS.has(command) || !isWeappIdeTopLevelCommand(command)) return false;
2918
- await parse(argv);
3548
+ if (!await dispatchWechatCliCommand(argv)) await executeWechatIdeCliCommand(argv);
2919
3549
  return true;
2920
3550
  }
2921
3551
  //#endregion