weapp-vite 6.20.0 → 6.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -219,8 +219,14 @@ weapp-vite ide logs --open
219
219
  # 等价写法
220
220
  wv ide logs
221
221
  wv ide logs --open
222
+
223
+ # 检查 DevTools CLI、服务端口、登录和已打开 automator 会话
224
+ wv ide doctor
225
+ wv ide doctor --json
222
226
  ```
223
227
 
228
+ `wv open`、`wv dev -o`、`wv build -o` 和 `wv ide logs --open` 默认使用官方 CLI 打开项目,再连接 automator。需要调试旧版自动化启动链路时,可显式传入 `--ide-open-strategy automator`;项目自动信任与打开策略相互独立。
229
+
224
230
  除了日志桥接,`ide` 子命令现在也支持直接读取已打开 DevTools 会话的信息:
225
231
 
226
232
  ```sh
@@ -1,4 +1,4 @@
1
- import { n as getCompilerContext, v as getRouteRuntimeGlobalKeys } from "./createContext-CtCNbqdC.mjs";
1
+ import { n as getCompilerContext, v as getRouteRuntimeGlobalKeys } from "./createContext-DiBG4uOB.mjs";
2
2
  //#region src/auto-routes.ts
3
3
  const ROUTE_RUNTIME_OVERRIDE_KEY = Symbol.for("weapp-vite.route-runtime");
4
4
  function createGetter(resolver) {
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { C as parseCommentJson, D as isPathInside, E as shouldPassPlatformArgToIdeOpen, S as loadViteConfigFile, T as getDefaultIdeProjectRoot, _ as resolveHmrProfileJsonPath, a as formatBytes, b as checkRuntime, d as getBackendForCapability, f as resolveBackendExecution, g as SHARED_CHUNK_VIRTUAL_PREFIX, h as createSharedBuildConfig, m as syncManagedTsconfigBootstrapFiles, p as syncProjectSupportFiles, t as createCompilerContext, w as createCjsConfigLoadError, x as getProjectConfigFileName, y as resolveWeappConfigFile } from "./createContext-CtCNbqdC.mjs";
1
+ import { C as parseCommentJson, D as isPathInside, E as shouldPassPlatformArgToIdeOpen, S as loadViteConfigFile, T as getDefaultIdeProjectRoot, _ as resolveHmrProfileJsonPath, a as formatBytes, b as checkRuntime, d as getBackendForCapability, f as resolveBackendExecution, g as SHARED_CHUNK_VIRTUAL_PREFIX, h as createSharedBuildConfig, m as syncManagedTsconfigBootstrapFiles, p as syncProjectSupportFiles, t as createCompilerContext, w as createCjsConfigLoadError, x as getProjectConfigFileName, y as resolveWeappConfigFile } from "./createContext-DiBG4uOB.mjs";
2
2
  import { r as logger_default, t as colors } from "./logger-mt4mSTqV.mjs";
3
- import { h as VERSION } from "./file-NyBgGJm2.mjs";
3
+ import { h as VERSION } from "./file-DQ5FlYd5.mjs";
4
4
  import { c as startWeappViteMcpServer, l as detectAiDevelopmentEnvironment, s as resolveWeappMcpConfig } from "./mcp-BG6TliEg.mjs";
5
5
  import { createRequire } from "node:module";
6
6
  import fs from "node:fs";
@@ -15,7 +15,7 @@ import os from "node:os";
15
15
  import { execFile, spawn } from "node:child_process";
16
16
  import { Buffer } from "node:buffer";
17
17
  import { cac } from "cac";
18
- import { RETRY_CANCEL_KEYS, RETRY_CONFIRM_KEYS, bootstrapWechatDevtoolsSettings, buildWechatIdeNpm, clearWechatIdeCache, clearWechatIdeCacheByAutomator, closeSharedMiniProgram, closeWechatIdeProject, compileWechatIdeByAutomator, connectOpenedAutomator, createSharedInputSession, createWechatIdeLoginRequiredExitError, dispatchWechatCliCommand, formatAutomatorLoginError, getConfig, getWechatIdeTestAccounts, getWechatIdeTicket, getWechatIdeToolInfo, isAutomatorLoginError, isWeappIdeTopLevelCommand, isWechatIdeEngineBuildEndpointMissingError, isWechatIdeLoginRequiredError, isWechatIdeLoginRequiredExitError, launchAutomator, parse, promptRetryKeypress, promptWechatIdeLoginRetry, quitWechatIde, refreshWechatIdeTicket, resetWechatIdeFileUtilsByHttp, resolveProjectAutomatorPort, runRetryableCommand, runWechatIdeEngineBuild, runWithSuspendedSharedInput, setWechatIdeTicket, startForwardConsole, takeScreenshot } from "weapp-ide-cli";
18
+ import { RETRY_CANCEL_KEYS, RETRY_CONFIRM_KEYS, bootstrapWechatDevtoolsSettings, buildWechatIdeNpm, clearWechatIdeCache, clearWechatIdeCacheByAutomator, closeSharedMiniProgram, closeWechatIdeProject, compileWechatIdeByAutomator, connectOpenedAutomator, createSharedInputSession, createWechatIdeLoginRequiredExitError, defaultCustomConfigFilePath, detectWechatDevtoolsServicePort, dispatchWechatCliCommand, formatAutomatorLoginError, getConfig, getWechatIdeTestAccounts, getWechatIdeTicket, getWechatIdeToolInfo, isAutomatorLoginError, isWeappIdeTopLevelCommand, isWechatIdeEngineBuildEndpointMissingError, isWechatIdeLoggedIn, isWechatIdeLoginRequiredError, isWechatIdeLoginRequiredExitError, launchAutomator, parse, promptRetryKeypress, promptWechatIdeLoginRetry, quitWechatIde, refreshWechatIdeTicket, resetWechatIdeFileUtilsByHttp, resolveCliPath, resolveProjectAutomatorPort, runRetryableCommand, runWechatIdeEngineBuild, runWithSuspendedSharedInput, setWechatIdeTicket, startForwardConsole, takeScreenshot } from "weapp-ide-cli";
19
19
  import { promisify } from "node:util";
20
20
  import { brotliCompressSync, gzipSync } from "node:zlib";
21
21
  import { resolveCommand } from "package-manager-detector/commands";
@@ -251,6 +251,17 @@ async function closeIde$1() {
251
251
  //#endregion
252
252
  //#region src/cli/openIde/diagnostics.ts
253
253
  /**
254
+ * @description 将 automator 启动错误归类为用户可执行的恢复提示。
255
+ */
256
+ function formatWechatIdeAutomatorFailure(error) {
257
+ const message = error instanceof Error ? error.message : String(error);
258
+ if (/需要重新登录|need\s+re-?login|code\s*[:=]\s*10/i.test(message)) return "登录状态失效,请先登录微信开发者工具。";
259
+ if (/service port|http port|ECONNREFUSED|listen EPERM|EACCES/i.test(message)) return "服务端口不可用,请在设置 -> 安全设置中开启服务端口。";
260
+ if (/protocol method|protocol timeout|automator.*timeout|Wait timed out|websocket|ws:\/\//i.test(message)) return "自动化 websocket 或协议尚未就绪,已保留普通 CLI 打开的项目。";
261
+ if (/cliPath|not found|spawn/i.test(message)) return "微信开发者工具 CLI 路径不可用,请执行 `wv ide doctor` 检查配置。";
262
+ return "当前 DevTools 自动化能力不可用,已保留普通 CLI 打开的项目。";
263
+ }
264
+ /**
254
265
  * @description 输出微信开发者工具打开后的自助恢复步骤。
255
266
  */
256
267
  function logWechatIdeRecoveryHint(options) {
@@ -302,37 +313,50 @@ async function verifyOpenedProjectHealth(miniProgram) {
302
313
  if (typeof miniProgram.screenshot !== "function") return;
303
314
  await withTimeout(miniProgram.screenshot({ timeout: OPENED_PROJECT_HEALTH_CHECK_TIMEOUT }), OPENED_PROJECT_HEALTH_CHECK_TIMEOUT);
304
315
  }
305
- async function openWechatIdeByAutomator(projectPath) {
316
+ async function openWechatIdeByAutomator(projectPath, options = {}) {
306
317
  disconnectMiniProgram(await launchAutomator({
307
318
  persistAsDefaultSession: true,
308
- preserveProjectRoot: true,
319
+ preserveProjectRoot: options.preserveProjectRoot ?? true,
309
320
  projectPath,
310
321
  port: resolveProjectAutomatorPort(projectPath),
311
322
  timeout: OPEN_AUTOMATOR_TIMEOUT,
312
- trustProject: true
323
+ trustProject: options.trustProject !== false
313
324
  }));
314
325
  }
315
326
  async function connectOpenedProject(projectPath) {
316
- let miniProgram = null;
327
+ let miniProgram;
317
328
  try {
318
329
  miniProgram = await connectOpenedAutomator({
319
330
  projectPath,
320
331
  port: resolveProjectAutomatorPort(projectPath),
321
332
  timeout: 3e3
322
333
  });
334
+ } catch {
335
+ return { status: "not-connected" };
336
+ }
337
+ try {
323
338
  await verifyOpenedProjectHealth(miniProgram);
324
- return miniProgram;
339
+ return {
340
+ status: "connected",
341
+ miniProgram
342
+ };
325
343
  } catch {
326
- if (miniProgram) disconnectMiniProgram(miniProgram);
327
- return null;
344
+ disconnectMiniProgram(miniProgram);
345
+ return { status: "unhealthy" };
328
346
  }
329
347
  }
330
348
  /**
331
349
  * @description 若当前项目已在微信开发者工具中打开且自动化可连通,则直接复用现有会话,避免重复拉起 IDE。
332
350
  */
333
351
  async function tryReuseOpenedWechatIde(projectPath, closeIde, options = {}) {
334
- const miniProgram = await connectOpenedProject(projectPath);
335
- if (!miniProgram) return null;
352
+ const connection = await connectOpenedProject(projectPath);
353
+ if (connection.status === "unhealthy") return {
354
+ reopened: false,
355
+ reused: false,
356
+ unhealthy: true
357
+ };
358
+ if (connection.status === "not-connected") return null;
359
+ const { miniProgram } = connection;
336
360
  disconnectMiniProgram(miniProgram);
337
361
  if (options.promptReopen === false) {
338
362
  logger_default.info("目标项目已在微信开发者工具中打开,已跳过重复打开。");
@@ -348,7 +372,10 @@ async function tryReuseOpenedWechatIde(projectPath, closeIde, options = {}) {
348
372
  };
349
373
  logger_default.info(colors.bold(colors.green("正在关闭当前已打开项目,并重新拉起微信开发者工具...")));
350
374
  if (!await closeIde()) logger_default.warn("关闭当前微信开发者工具失败,仍继续尝试重新打开目标项目。");
351
- await openWechatIdeByAutomator(projectPath);
375
+ await openWechatIdeByAutomator(projectPath, {
376
+ preserveProjectRoot: options.preserveProjectRoot,
377
+ trustProject: options.trustProject
378
+ });
352
379
  return {
353
380
  reopened: true,
354
381
  reused: false
@@ -357,13 +384,14 @@ async function tryReuseOpenedWechatIde(projectPath, closeIde, options = {}) {
357
384
  /**
358
385
  * @description 对已打开的目标项目执行强制重开,以刷新最新构建产物。
359
386
  */
360
- async function reopenOpenedWechatIde(projectPath, closeIde) {
361
- const miniProgram = await connectOpenedProject(projectPath);
362
- if (!miniProgram) return false;
387
+ async function reopenOpenedWechatIde(projectPath, closeIde, options = {}) {
388
+ const connection = await connectOpenedProject(projectPath);
389
+ if (connection.status !== "connected") return false;
390
+ const { miniProgram } = connection;
363
391
  disconnectMiniProgram(miniProgram);
364
392
  logger_default.info("目标项目已在微信开发者工具中打开,当前命令将主动重开以刷新最新构建产物。");
365
393
  if (!await closeIde()) logger_default.warn("关闭当前微信开发者工具失败,仍继续尝试重新打开目标项目。");
366
- await openWechatIdeByAutomator(projectPath);
394
+ await openWechatIdeByAutomator(projectPath, options);
367
395
  return true;
368
396
  }
369
397
  //#endregion
@@ -374,6 +402,19 @@ function shouldLogAutomatorFallbackError() {
374
402
  }
375
403
  const PREPARE_AUTOMATOR_SESSION_TIMEOUT = 8e3;
376
404
  const RESET_FILEUTILS_ENV = "WEAPP_VITE_RESET_IDE_FILEUTILS";
405
+ function readProjectConfigObject(projectPath) {
406
+ try {
407
+ const raw = fs.readFileSync(path.join(projectPath, "project.config.json"), "utf8");
408
+ const value = JSON.parse(raw);
409
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
410
+ } catch {
411
+ return;
412
+ }
413
+ }
414
+ function shouldUseAutomatorProjectWrapper(projectPath) {
415
+ const projectConfig = readProjectConfigObject(projectPath);
416
+ return projectConfig?.compileType === "plugin" && typeof projectConfig.miniprogramRoot === "string" && projectConfig.miniprogramRoot.trim().length > 0;
417
+ }
377
418
  function isWechatIdeOpenRecoveryDisabled(options) {
378
419
  if (options.openRecovery === false) return true;
379
420
  const flag = process.env.WEAPP_VITE_DISABLE_IDE_OPEN_RECOVERY;
@@ -415,13 +456,25 @@ async function closeIde() {
415
456
  return await closeIde$1();
416
457
  }
417
458
  async function tryOpenWechatIdeByAutomator(projectPath, options) {
459
+ const preserveProjectRoot = !shouldUseAutomatorProjectWrapper(projectPath);
418
460
  if (options.reuseOpenedProject === false) {
419
- if (await reopenOpenedWechatIde(projectPath, closeIde)) return "reopened";
461
+ if (await reopenOpenedWechatIde(projectPath, closeIde, {
462
+ preserveProjectRoot,
463
+ trustProject: options.trustProject
464
+ })) return "reopened";
420
465
  }
421
- const reuseResult = await tryReuseOpenedWechatIde(projectPath, closeIde, { promptReopen: options.reuseOpenedProject !== true });
466
+ const reuseResult = await tryReuseOpenedWechatIde(projectPath, closeIde, {
467
+ preserveProjectRoot,
468
+ promptReopen: options.reuseOpenedProject !== true,
469
+ trustProject: options.trustProject
470
+ });
422
471
  if (reuseResult?.reused) return "reused";
423
472
  if (reuseResult?.reopened) return "reopened";
424
- await openWechatIdeByAutomator(projectPath);
473
+ if (reuseResult?.unhealthy) return "unhealthy";
474
+ await openWechatIdeByAutomator(projectPath, {
475
+ preserveProjectRoot,
476
+ trustProject: options.trustProject
477
+ });
425
478
  return "opened";
426
479
  }
427
480
  /**
@@ -444,10 +497,11 @@ function createIdeOpenArgv(platform, projectPath, options = {}) {
444
497
  return argv;
445
498
  }
446
499
  async function prepareOpenedWechatIdeAutomatorSession(projectPath, options) {
500
+ const preserveProjectRoot = !shouldUseAutomatorProjectWrapper(projectPath);
447
501
  try {
448
502
  (await launchAutomator({
449
503
  persistAsDefaultSession: true,
450
- preserveProjectRoot: true,
504
+ preserveProjectRoot,
451
505
  projectPath,
452
506
  port: resolveProjectAutomatorPort(projectPath),
453
507
  timeout: PREPARE_AUTOMATOR_SESSION_TIMEOUT,
@@ -532,7 +586,7 @@ async function stabilizeOpenedWechatIdeProject(projectPath, servicePortEnabled,
532
586
  await executeWechatIdeCliCommand(appendLoginRetryArgv(["compile"], options), {
533
587
  automatorMode: "require",
534
588
  httpMode: "skip",
535
- preserveProjectRoot: true,
589
+ preserveProjectRoot: !shouldUseAutomatorProjectWrapper(projectPath),
536
590
  projectPath
537
591
  });
538
592
  } catch (error) {
@@ -557,7 +611,7 @@ async function stabilizeOpenedWechatIdeProject(projectPath, servicePortEnabled,
557
611
  async function verifyOpenedWechatIdeProject(projectPath, servicePortEnabled, options) {
558
612
  const stabilizeResult = await stabilizeOpenedWechatIdeProject(projectPath, servicePortEnabled, options);
559
613
  if (!stabilizeResult.ok) return stabilizeResult;
560
- if (options.useAutomatorOpen === false && servicePortEnabled !== false) return await prepareOpenedWechatIdeAutomatorSession(projectPath, options);
614
+ if (options.useAutomatorOpen === false && servicePortEnabled !== false) return await connectOpenedWechatIdeAutomatorSession(projectPath);
561
615
  return stabilizeResult;
562
616
  }
563
617
  function formatWechatIdeOpenHealthReason(result) {
@@ -588,9 +642,11 @@ async function verifyAndRecoverOpenedWechatIdeProject(platform, projectPath, ser
588
642
  }
589
643
  async function openIde(platform, projectPath, options = {}) {
590
644
  let bootstrapResult;
591
- const useAutomatorOpen = options.useAutomatorOpen === true;
645
+ const openStrategy = options.openStrategy ?? (options.useAutomatorOpen === true ? "automator" : "cli");
646
+ const useAutomatorOpen = openStrategy === "automator";
592
647
  const normalizedOptions = {
593
648
  ...options,
649
+ openStrategy,
594
650
  useAutomatorOpen
595
651
  };
596
652
  if (platform === "weapp" && projectPath) try {
@@ -603,10 +659,13 @@ async function openIde(platform, projectPath, options = {}) {
603
659
  logger_default.error(error);
604
660
  }
605
661
  if (platform === "weapp" && projectPath && bootstrapResult?.servicePortEnabled === false) logWechatIdeServicePortDisabledHint(projectPath);
606
- if (platform === "weapp" && projectPath && normalizedOptions.trustProject !== false && bootstrapResult?.servicePortEnabled !== false && useAutomatorOpen) try {
662
+ if (platform === "weapp" && projectPath && bootstrapResult?.servicePortEnabled !== false && useAutomatorOpen) try {
607
663
  const openResult = await tryOpenWechatIdeByAutomator(projectPath, normalizedOptions);
608
664
  if (openResult === "reused") return;
609
- if (openResult) {
665
+ if (openResult === "unhealthy") {
666
+ logger_default.warn("已连接到目标微信开发者工具项目,但协议健康检查暂未就绪;已保留当前窗口并跳过重复启动。");
667
+ return;
668
+ } else if (openResult) {
610
669
  if (!normalizedOptions.skipPostOpenHealthCheck) await verifyAndRecoverOpenedWechatIdeProject(platform, projectPath, bootstrapResult?.servicePortEnabled, normalizedOptions);
611
670
  return;
612
671
  }
@@ -615,7 +674,7 @@ async function openIde(platform, projectPath, options = {}) {
615
674
  logger_default.error("检测到微信开发者工具登录状态失效,请先登录后重试。");
616
675
  logger_default.warn(formatAutomatorLoginError(error));
617
676
  }
618
- logger_default.warn("通过 automator 启动微信开发者工具并自动信任项目失败,回退到普通 open 流程。");
677
+ logger_default.warn(`通过 automator 启动微信开发者工具失败,回退到普通 open 流程:${formatWechatIdeAutomatorFailure(error)}`);
619
678
  if (shouldLogAutomatorFallbackError()) logger_default.error(error);
620
679
  }
621
680
  else if (platform === "weapp" && projectPath && normalizedOptions.reuseOpenedProject === false) {
@@ -2867,7 +2926,7 @@ function scheduleCompletedProductionBuildExit(options, analyzeHandle) {
2867
2926
  }, 0).unref?.();
2868
2927
  }
2869
2928
  function registerBuildCommand(cli) {
2870
- cli.command("build [root]", "build for production").option("--target <target>", `[string] transpile target (default: 'modules')`).option("--outDir <dir>", `[string] output directory (default: dist)`).option("-p, --platform <platform>", `[string] target platform (weapp | web | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--sourcemap [output]", `[boolean | "inline" | "hidden"] output source maps for build (default: false)`).option("--minify [minifier]", "[boolean | \"terser\" | \"esbuild\"] enable/disable minification, or specify minifier to use (default: esbuild)").option("--emptyOutDir", `[boolean] force empty outDir when it's outside of root`).option("-w, --watch", `[boolean] rebuilds when modules have changed on disk`).option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 输出分包分析仪表盘`, { default: false }).option("--scope <scope>", `[string] 局部构建范围,例如 main,packages/order`).action(async (root, options) => {
2929
+ cli.command("build [root]", "build for production").option("--target <target>", `[string] transpile target (default: 'modules')`).option("--outDir <dir>", `[string] output directory (default: dist)`).option("-p, --platform <platform>", `[string] target platform (weapp | web | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--sourcemap [output]", `[boolean | "inline" | "hidden"] output source maps for build (default: false)`).option("--minify [minifier]", "[boolean | \"terser\" | \"esbuild\"] enable/disable minification, or specify minifier to use (default: esbuild)").option("--emptyOutDir", `[boolean] force empty outDir when it's outside of root`).option("-w, --watch", `[boolean] rebuilds when modules have changed on disk`).option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--ide-open-strategy <strategy>", "[string] IDE open strategy (cli | automator)", { default: "cli" }).option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 输出分包分析仪表盘`, { default: false }).option("--scope <scope>", `[string] 局部构建范围,例如 main,packages/order`).action(async (root, options) => {
2871
2930
  let analyzeHandle;
2872
2931
  let ctx;
2873
2932
  let targets;
@@ -2978,7 +3037,8 @@ function registerBuildCommand(cli) {
2978
3037
  }]);
2979
3038
  await openIde(configService.platform, resolveIdeProjectPath(configService.mpDistRoot), {
2980
3039
  openRecovery: options.openRecovery,
2981
- trustProject: options.trustProject
3040
+ trustProject: options.trustProject,
3041
+ openStrategy: options.ideOpenStrategy
2982
3042
  });
2983
3043
  }
2984
3044
  if (analyzeHandle) await analyzeHandle.waitForExit();
@@ -3592,6 +3652,121 @@ async function readLatestHmrProfileSummary(options) {
3592
3652
  }
3593
3653
  //#endregion
3594
3654
  //#region src/cli/commands/ide.ts
3655
+ async function runIdeDoctor(projectPath, options) {
3656
+ const resolvedCli = await resolveCliPath();
3657
+ const servicePort = await detectWechatDevtoolsServicePort().catch((error) => ({
3658
+ servicePortEnabled: void 0,
3659
+ servicePort: void 0,
3660
+ error
3661
+ }));
3662
+ const cliCheck = resolvedCli.cliPath ? {
3663
+ status: "ok",
3664
+ value: {
3665
+ path: resolvedCli.cliPath,
3666
+ source: resolvedCli.source
3667
+ }
3668
+ } : {
3669
+ fix: "执行 `weapp config set cliPath <path-to-cli>` 配置微信开发者工具 CLI。",
3670
+ message: "未找到可用的微信开发者工具 CLI。",
3671
+ status: "failed",
3672
+ value: { source: resolvedCli.source }
3673
+ };
3674
+ const servicePortCheck = servicePort.servicePortEnabled === false ? {
3675
+ fix: "在微信开发者工具中打开:设置 -> 安全设置 -> 服务端口。",
3676
+ message: "微信开发者工具服务端口已关闭。",
3677
+ status: "failed",
3678
+ value: servicePort
3679
+ } : servicePort.error ? {
3680
+ fix: "执行 `wv ide doctor --json` 查看底层错误,并确认微信开发者工具已安装。",
3681
+ message: servicePort.error instanceof Error ? servicePort.error.message : String(servicePort.error),
3682
+ status: "warning"
3683
+ } : {
3684
+ status: servicePort.servicePortEnabled === true ? "ok" : "unknown",
3685
+ value: {
3686
+ enabled: servicePort.servicePortEnabled ?? null,
3687
+ port: servicePort.servicePort ?? null
3688
+ }
3689
+ };
3690
+ let loginCheck = {
3691
+ fix: "打开微信开发者工具完成登录后重试。",
3692
+ message: "暂未确认登录状态。",
3693
+ status: "unknown"
3694
+ };
3695
+ if (resolvedCli.cliPath) try {
3696
+ await isWechatIdeLoggedIn({
3697
+ nonInteractive: true,
3698
+ silent: true
3699
+ });
3700
+ loginCheck = {
3701
+ status: "ok",
3702
+ value: true
3703
+ };
3704
+ } catch (error) {
3705
+ loginCheck = {
3706
+ fix: "打开微信开发者工具完成登录后重试,或执行 `wv ide doctor --json` 查看 CLI 错误。",
3707
+ message: error instanceof Error ? error.message : String(error),
3708
+ status: "warning",
3709
+ value: false
3710
+ };
3711
+ }
3712
+ const projectCheck = projectPath ? {
3713
+ status: "ok",
3714
+ value: projectPath
3715
+ } : {
3716
+ fix: "在项目目录执行命令,或显式传入 `wv ide doctor <project-root>`。",
3717
+ message: "未解析到微信开发者工具项目目录。",
3718
+ status: "warning"
3719
+ };
3720
+ let automatorCheck = {
3721
+ message: projectPath ? "当前项目没有可连接的已打开 automator 会话。" : "缺少项目目录,跳过 automator 检查。",
3722
+ status: "unknown"
3723
+ };
3724
+ let toolCheck = {
3725
+ message: "当前没有可读取的 DevTools Tool.getInfo。",
3726
+ status: "unknown"
3727
+ };
3728
+ if (projectPath) try {
3729
+ const miniProgram = await connectOpenedAutomator({
3730
+ projectPath,
3731
+ port: resolveProjectAutomatorPort(projectPath),
3732
+ timeout: 3e3
3733
+ });
3734
+ automatorCheck = {
3735
+ status: "ok",
3736
+ value: true
3737
+ };
3738
+ if (typeof miniProgram.toolInfo === "function") toolCheck = {
3739
+ status: "ok",
3740
+ value: await miniProgram.toolInfo()
3741
+ };
3742
+ miniProgram.disconnect?.();
3743
+ } catch (error) {
3744
+ automatorCheck = {
3745
+ fix: "先执行 `wv open` 打开项目;若服务端口已开启,关闭多余 DevTools 窗口后重试。",
3746
+ message: error instanceof Error ? error.message : String(error),
3747
+ status: "warning"
3748
+ };
3749
+ }
3750
+ const report = {
3751
+ checks: {
3752
+ automator: automatorCheck,
3753
+ cli: cliCheck,
3754
+ login: loginCheck,
3755
+ project: projectCheck,
3756
+ servicePort: servicePortCheck,
3757
+ tool: toolCheck
3758
+ },
3759
+ configFile: defaultCustomConfigFilePath,
3760
+ nodeVersion: process.version,
3761
+ platform: process.platform,
3762
+ weappViteVersion: VERSION
3763
+ };
3764
+ const output = JSON.stringify(report, null, 2);
3765
+ if (options.json) process.stdout.write(`${output}\n`);
3766
+ else logger_default.info(output);
3767
+ if (options.strict && Object.values(report.checks).some((check) => check.status === "failed")) throw new Error("微信开发者工具环境诊断未通过,请根据 doctor 输出修复失败项后重试。");
3768
+ return report;
3769
+ }
3595
3770
  async function waitForTermination(cleanup) {
3596
3771
  await new Promise((resolve) => {
3597
3772
  const signals = ["SIGINT", "SIGTERM"];
@@ -3621,7 +3796,7 @@ function formatIdeOutput(data, options) {
3621
3796
  * @description 执行 ide 子命令。
3622
3797
  */
3623
3798
  async function runIdeCommand(action, root, options) {
3624
- if (action !== "logs" && action !== "setup" && action !== "info" && action !== "test-accounts" && action !== "ticket" && action !== "ticket:set" && action !== "ticket:refresh") throw new Error(`未知 ide 子命令: ${action ?? "(empty)"}`);
3799
+ if (action !== "logs" && action !== "setup" && action !== "info" && action !== "test-accounts" && action !== "ticket" && action !== "ticket:set" && action !== "ticket:refresh" && action !== "doctor") throw new Error(`未知 ide 子命令: ${action ?? "(empty)"}`);
3625
3800
  filterDuplicateOptions(options);
3626
3801
  const configFile = resolveConfigFile(options);
3627
3802
  const targets = resolveRuntimeTargets(options);
@@ -3634,8 +3809,12 @@ async function runIdeCommand(action, root, options) {
3634
3809
  projectPath: root,
3635
3810
  cliPlatform: targets.rawPlatform
3636
3811
  });
3637
- if (resolved.platform !== "weapp") throw new Error("`weapp-vite ide logs` 当前仅支持微信小程序平台。");
3638
- if (!resolved.projectPath) throw new Error("无法解析微信开发者工具项目目录,请显式传入 root 或检查 project.config.json。");
3812
+ if (action !== "doctor" && resolved.platform !== "weapp") throw new Error("`weapp-vite ide logs` 当前仅支持微信小程序平台。");
3813
+ if (action !== "doctor" && !resolved.projectPath) throw new Error("无法解析微信开发者工具项目目录,请显式传入 root 或检查 project.config.json。");
3814
+ if (action === "doctor") {
3815
+ await runIdeDoctor(resolved.projectPath, options);
3816
+ return;
3817
+ }
3639
3818
  if (action === "setup") {
3640
3819
  const result = await bootstrapWechatDevtoolsSettings({
3641
3820
  projectPath: resolved.projectPath,
@@ -3646,7 +3825,8 @@ async function runIdeCommand(action, root, options) {
3646
3825
  }
3647
3826
  if (options.open) await openIde(resolved.platform, resolved.projectPath, {
3648
3827
  openRecovery: options.openRecovery,
3649
- trustProject: options.trustProject
3828
+ trustProject: options.trustProject,
3829
+ openStrategy: options.ideOpenStrategy
3650
3830
  });
3651
3831
  if (action === "info") {
3652
3832
  const result = await getWechatIdeToolInfo({ projectPath: resolved.projectPath });
@@ -3707,7 +3887,7 @@ async function runIdeCommand(action, root, options) {
3707
3887
  * @description 注册 IDE 相关子命令。
3708
3888
  */
3709
3889
  function registerIdeCommand(cli) {
3710
- 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 | web)").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 }).option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").action(async (action, root, options) => {
3890
+ 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 | web)").option("--project-config <path>", "[string] project config path (miniprogram only)").option("--json", "[boolean] output the doctor report as JSON").option("--ticket <value>", "[string] ticket used by `ide ticket:set`").option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--ide-open-strategy <strategy>", "[string] IDE open strategy (cli | automator)", { default: "cli" }).option("--strict", "[boolean] fail when doctor finds blocking environment errors").option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").action(async (action, root, options) => {
3711
3891
  await runIdeCommand(action, root, options);
3712
3892
  });
3713
3893
  }
@@ -4243,7 +4423,7 @@ function applyMcpCliOptions(config, options) {
4243
4423
  //#endregion
4244
4424
  //#region src/cli/commands/open.ts
4245
4425
  function registerOpenCommand(cli) {
4246
- cli.command("open [root]").option("-p, --platform <platform>", `[string] target platform (weapp | web)`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--login-retry <mode>", "[string] login retry mode for Wechat DevTools (never | once | always)").option("--login-retry-timeout <ms>", "[number] login retry prompt timeout in milliseconds").option("--non-interactive", "[boolean] fail immediately when Wechat DevTools login has expired").option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").option("--mcp", "[boolean] auto start MCP service before opening IDE").option("--no-mcp", "[boolean] disable MCP service before opening IDE").action(async (root, options) => {
4426
+ cli.command("open [root]").option("-p, --platform <platform>", `[string] target platform (weapp | web)`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--ide-open-strategy <strategy>", "[string] IDE open strategy (cli | automator)", { default: "cli" }).option("--login-retry <mode>", "[string] login retry mode for Wechat DevTools (never | once | always)").option("--login-retry-timeout <ms>", "[number] login retry prompt timeout in milliseconds").option("--non-interactive", "[boolean] fail immediately when Wechat DevTools login has expired").option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").option("--mcp", "[boolean] auto start MCP service before opening IDE").option("--no-mcp", "[boolean] disable MCP service before opening IDE").action(async (root, options) => {
4247
4427
  filterDuplicateOptions(options);
4248
4428
  const configFile = resolveConfigFile(options);
4249
4429
  const targets = resolveRuntimeTargets(options);
@@ -4275,7 +4455,8 @@ function registerOpenCommand(cli) {
4275
4455
  loginRetryTimeout: options.loginRetryTimeout,
4276
4456
  nonInteractive: options.nonInteractive,
4277
4457
  openRecovery: options.openRecovery,
4278
- trustProject: options.trustProject
4458
+ trustProject: options.trustProject,
4459
+ openStrategy: options.ideOpenStrategy
4279
4460
  });
4280
4461
  });
4281
4462
  }
@@ -4546,7 +4727,7 @@ function resolveRunnableHotkeyDefinition(input) {
4546
4727
  }
4547
4728
  //#endregion
4548
4729
  //#region package.json
4549
- var version = "6.20.0";
4730
+ var version = "6.20.2";
4550
4731
  //#endregion
4551
4732
  //#region src/cli/devHotkeys/format.ts
4552
4733
  const FULLWIDTH_ASCII_START = 65281;
@@ -4712,6 +4893,7 @@ function startDevHotkeys(options) {
4712
4893
  let onKeypress;
4713
4894
  let onSigcont;
4714
4895
  let currentAction;
4896
+ let actionStartedAt;
4715
4897
  let lastAction;
4716
4898
  let lastRenderedPanel = "";
4717
4899
  const recentInputs = /* @__PURE__ */ new Map();
@@ -4791,10 +4973,12 @@ function startDevHotkeys(options) {
4791
4973
  const runAction = (label, pendingLabel, action) => {
4792
4974
  if (running) {
4793
4975
  const current = currentAction ?? "已有命令";
4794
- logger_default.warn(`[dev action] 当前正在${current.replace(REG_PENDING_PREFIX, "")},请稍后再试。`);
4976
+ const elapsed = actionStartedAt === void 0 ? "" : `(已运行 ${Math.max(0, Date.now() - actionStartedAt)} ms)`;
4977
+ logger_default.warn(`[dev action] 当前正在${current.replace(REG_PENDING_PREFIX, "")}${elapsed},已忽略重复请求。`);
4795
4978
  return;
4796
4979
  }
4797
4980
  running = true;
4981
+ actionStartedAt = Date.now();
4798
4982
  currentAction = pendingLabel;
4799
4983
  printHint();
4800
4984
  action().then((summary) => {
@@ -4803,6 +4987,7 @@ function startDevHotkeys(options) {
4803
4987
  logger_default.error(`[dev action] ${label}失败:${error instanceof Error ? error.message : String(error)}`);
4804
4988
  }).finally(() => {
4805
4989
  running = false;
4990
+ actionStartedAt = void 0;
4806
4991
  currentAction = void 0;
4807
4992
  if (!closed) printHint();
4808
4993
  });
@@ -4810,6 +4995,7 @@ function startDevHotkeys(options) {
4810
4995
  const runBackgroundAction = (label, pendingLabel, action) => {
4811
4996
  if (running) return;
4812
4997
  running = true;
4998
+ actionStartedAt = Date.now();
4813
4999
  currentAction = pendingLabel;
4814
5000
  action().then((summary) => {
4815
5001
  if (summary) lastAction = summary;
@@ -4817,6 +5003,7 @@ function startDevHotkeys(options) {
4817
5003
  logger_default.error(`[dev action] ${label}失败:${error instanceof Error ? error.message : String(error)}`);
4818
5004
  }).finally(() => {
4819
5005
  running = false;
5006
+ actionStartedAt = void 0;
4820
5007
  currentAction = void 0;
4821
5008
  });
4822
5009
  };
@@ -5210,7 +5397,7 @@ function writePostOpenSeparator() {
5210
5397
  process.stdout?.write?.("\n");
5211
5398
  }
5212
5399
  function registerServeCommand(cli) {
5213
- cli.command("[root]", "start dev server").alias("serve").alias("dev").option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("-p, --platform <platform>", `[string] target platform (weapp | web | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--login-retry <mode>", "[string] login retry mode for Wechat DevTools (never | once | always)").option("--login-retry-timeout <ms>", "[number] login retry prompt timeout in milliseconds").option("--non-interactive", "[boolean] fail immediately when Wechat DevTools login has expired").option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").option("--mcp", "[boolean] auto start MCP service during dev").option("--no-mcp", "[boolean] disable MCP service during dev").option("--host [host]", `[string] web dev server host`).option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 启动分包分析仪表盘 (实验特性)`, { default: false }).option("--scope <scope>", `[string] 局部构建范围,例如 main,packages/order`).action(async (root, options) => {
5400
+ cli.command("[root]", "start dev server").alias("serve").alias("dev").option("--skipNpm", `[boolean] if skip npm build`).option("-o, --open", `[boolean] open ide`).option("-p, --platform <platform>", `[string] target platform (weapp | web | all)`).option("--project-config <path>", `[string] project config path (miniprogram only)`).option("--trust-project", "[boolean] auto trust Wechat DevTools project on open", { default: true }).option("--ide-open-strategy <strategy>", "[string] IDE open strategy (cli | automator)", { default: "cli" }).option("--login-retry <mode>", "[string] login retry mode for Wechat DevTools (never | once | always)").option("--login-retry-timeout <ms>", "[number] login retry prompt timeout in milliseconds").option("--non-interactive", "[boolean] fail immediately when Wechat DevTools login has expired").option("--no-open-recovery", "[boolean] disable automatic Wechat DevTools close-and-reopen recovery").option("--mcp", "[boolean] auto start MCP service during dev").option("--no-mcp", "[boolean] disable MCP service during dev").option("--host [host]", `[string] web dev server host`).option("--ui", `[boolean] 启动调试 UI(当前提供分析视图)`, { default: false }).option("--analyze", `[boolean] 启动分包分析仪表盘 (实验特性)`, { default: false }).option("--scope <scope>", `[string] 局部构建范围,例如 main,packages/order`).action(async (root, options) => {
5214
5401
  filterDuplicateOptions(options);
5215
5402
  setCommandNodeEnv("development");
5216
5403
  const cwd = root ?? process.cwd();
@@ -5247,7 +5434,7 @@ function registerServeCommand(cli) {
5247
5434
  fallbackProjectPath: configService.cwd,
5248
5435
  openIde: async (projectPath, openOptions) => {
5249
5436
  const forceReopen = openOptions?.forceReopen === true;
5250
- const useAutomatorOpen = forceReopen || openOptions?.useAutomatorOpen === true;
5437
+ const useAutomatorOpen = openOptions?.openStrategy === "automator" || openOptions?.useAutomatorOpen === true;
5251
5438
  await openIde(configService.platform, projectPath, {
5252
5439
  loginRetry: options.loginRetry,
5253
5440
  loginRetryTimeout: options.loginRetryTimeout,
@@ -5258,6 +5445,7 @@ function registerServeCommand(cli) {
5258
5445
  skipAutomatorCompile: !forceReopen,
5259
5446
  skipPostOpenHealthCheck: true,
5260
5447
  trustProject: options.trustProject,
5448
+ openStrategy: openOptions?.openStrategy ?? options.ideOpenStrategy ?? "cli",
5261
5449
  useAutomatorOpen
5262
5450
  });
5263
5451
  writePostOpenSeparator();
@@ -5370,7 +5558,7 @@ function registerServeCommand(cli) {
5370
5558
  await miniProgramDevActions.openIde({
5371
5559
  forceOpen: true,
5372
5560
  forceReopen: false,
5373
- useAutomatorOpen: options.trustProject !== false
5561
+ openStrategy: options.ideOpenStrategy ?? "cli"
5374
5562
  });
5375
5563
  } finally {
5376
5564
  devHotkeysSession?.restore();
@@ -5445,7 +5633,7 @@ async function tryRunIdeCommand(argv) {
5445
5633
  const command = argv[0];
5446
5634
  if (!command) return false;
5447
5635
  if (command === "ide") {
5448
- if (argv[1] === "logs") return false;
5636
+ if (argv[1] === "logs" || argv[1] === "doctor" || argv[1] === "--help" || argv[1] === "-h") return false;
5449
5637
  if (!await dispatchWechatCliCommand(argv.slice(1))) await executeWechatIdeCliCommand(argv.slice(1));
5450
5638
  return true;
5451
5639
  }
@@ -410,6 +410,7 @@ interface HandleWxmlOptions {
410
410
  importMetaExtension?: string;
411
411
  removeComment?: boolean;
412
412
  transformEvent?: boolean;
413
+ transformPlatformSyntax?: boolean;
413
414
  scriptModuleExtension?: string;
414
415
  scriptModuleTag?: string;
415
416
  templateExtension?: string;
@@ -1921,6 +1922,7 @@ interface AutoImportService {
1921
1922
  reset: () => void;
1922
1923
  getVersion: () => number;
1923
1924
  runInBatch: <T>(task: () => T | Promise<T>) => Promise<T>;
1925
+ runWithoutOutputWrites: <T>(task: () => T | Promise<T>) => Promise<T>;
1924
1926
  registerPotentialComponent: (filePath: string) => Promise<void>;
1925
1927
  removePotentialComponent: (filePath: string) => void;
1926
1928
  resolve: (componentName: string, importerBaseName?: string) => AutoImportMatch | undefined;
package/dist/config.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { $n as WeappViteRuntime, Gn as applyWeappViteHostMeta, Jn as resolveWeappViteHostMeta, Kn as createWeappViteHostMeta, Un as WEAPP_VITE_HOST_NAME, Wn as WeappViteHostMeta, _ as definePageJson, a as UserConfigFnNoEnvPlain, at as WeappViteConfig, c as UserConfigFnPromise, d as Component, f as Page, g as defineComponentJson, h as defineAppJson, i as UserConfigFnNoEnv, l as defineConfig, m as Theme, n as UserConfigExport, o as UserConfigFnObject, p as Sitemap, qn as isWeappViteHost, r as UserConfigFn, s as UserConfigFnObjectPlain, t as UserConfig, u as App, v as defineSitemapJson, y as defineThemeJson } from "./config-ClSNHsDH.mjs";
1
+ import { $n as WeappViteRuntime, Gn as applyWeappViteHostMeta, Jn as resolveWeappViteHostMeta, Kn as createWeappViteHostMeta, Un as WEAPP_VITE_HOST_NAME, Wn as WeappViteHostMeta, _ as definePageJson, a as UserConfigFnNoEnvPlain, at as WeappViteConfig, c as UserConfigFnPromise, d as Component, f as Page, g as defineComponentJson, h as defineAppJson, i as UserConfigFnNoEnv, l as defineConfig, m as Theme, n as UserConfigExport, o as UserConfigFnObject, p as Sitemap, qn as isWeappViteHost, r as UserConfigFn, s as UserConfigFnObjectPlain, t as UserConfig, u as App, v as defineSitemapJson, y as defineThemeJson } from "./config-C810aRQQ.mjs";
2
2
  export { type App, type Component, type Page, type Sitemap, type Theme, UserConfig, UserConfigExport, UserConfigFn, UserConfigFnNoEnv, UserConfigFnNoEnvPlain, UserConfigFnObject, UserConfigFnObjectPlain, UserConfigFnPromise, WEAPP_VITE_HOST_NAME, type WeappViteConfig, WeappViteHostMeta, type WeappViteRuntime, applyWeappViteHostMeta, createWeappViteHostMeta, defineAppJson, defineComponentJson, defineConfig, definePageJson, defineSitemapJson, defineThemeJson, isWeappViteHost, resolveWeappViteHostMeta };