weapp-ide-cli 6.2.0 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
- import { _ as readCustomConfig, a as assertWechatDevtoolsPort, i as assertWechatDevtoolsHost, n as readPersistedAutomatorSession, r as resolveWechatDevtoolsTarget, t as persistAutomatorSession } from "./sessionStore-zdzy2UFM.js";
1
+ import { a as readPersistedAutomatorSession, i as persistAutomatorSession, j as colors, m as assertWechatDevtoolsPort, p as assertWechatDevtoolsHost, r as resolveAutomatorProjectPath, u as resolveWechatDevtoolsTarget, z as readCustomConfig } from "./automatorProject-DPU-pEF0.js";
2
2
  import path from "node:path";
3
3
  import { withMachineE2ELease } from "@weapp-vite/devtools-runtime";
4
- import { createHash } from "node:crypto";
5
4
  import fs from "node:fs/promises";
6
5
  import process from "node:process";
7
- import os from "node:os";
6
+ import { createHash } from "node:crypto";
8
7
  import { OperationLifecycle } from "@weapp-vite/miniprogram-automator/operation";
9
- //#region src/cli/automator/port.ts
8
+ import { emitKeypressEvents } from "node:readline";
9
+ // src/cli/automator/port.ts
10
10
  /** 显式端口不能被截断或作为默认值忽略,避免连接其他项目。 */
11
11
  function assertAutomatorPort(port) {
12
12
  if (port !== void 0 && (typeof port !== "number" || !Number.isInteger(port) || port < 1 || port > 65535)) throw Object.assign(/* @__PURE__ */ new RangeError("Automator port must be an integer between 1 and 65535."), { code: "DEVTOOLS_INVALID_PORT" });
@@ -17,8 +17,7 @@ function parseAutomatorPort(raw) {
17
17
  assertAutomatorPort(port);
18
18
  return port;
19
19
  }
20
- //#endregion
21
- //#region src/cli/automator/context.ts
20
+ // src/cli/automator/context.ts
22
21
  /** 在连接与共享缓存入口固定安装选择;headless 不读取或修改 IDE 状态。 */
23
22
  async function resolveAutomatorSessionOptions(options) {
24
23
  assertAutomatorPort(options.port);
@@ -39,8 +38,376 @@ async function resolveAutomatorSessionOptions(options) {
39
38
  installationId: target.installationId
40
39
  };
41
40
  }
42
- //#endregion
43
- //#region src/cli/automator/errors.ts
41
+ // src/i18n.ts
42
+ let currentLocale = "zh";
43
+ /**
44
+ * @description 设置当前语言。
45
+ */
46
+ function setLocale(locale) {
47
+ currentLocale = normalizeLocale(locale);
48
+ }
49
+ /**
50
+ * @description 从 argv 和环境变量中解析语言并设置。
51
+ */
52
+ function configureLocaleFromArgv(argv, fallbackLocale) {
53
+ const localeFromArgv = readLangOption(argv);
54
+ if (localeFromArgv) {
55
+ setLocale(localeFromArgv);
56
+ return currentLocale;
57
+ }
58
+ if (fallbackLocale) {
59
+ setLocale(fallbackLocale);
60
+ return currentLocale;
61
+ }
62
+ const localeFromEnv = process.env.WEAPP_IDE_CLI_LANG || process.env.LANG;
63
+ if (localeFromEnv) {
64
+ setLocale(localeFromEnv);
65
+ return currentLocale;
66
+ }
67
+ setLocale("zh");
68
+ return currentLocale;
69
+ }
70
+ /**
71
+ * @description 根据当前语言选择文案。
72
+ */
73
+ function i18nText(zh, en) {
74
+ return currentLocale === "en" ? en : zh;
75
+ }
76
+ /**
77
+ * @description 校验 --lang 参数是否合法。
78
+ */
79
+ function validateLocaleOption(argv) {
80
+ const localeFromArgv = readLangOption(argv);
81
+ if (!localeFromArgv) return;
82
+ if (!isLocaleTokenSupported(localeFromArgv)) throw new Error(`不支持的语言: ${localeFromArgv},仅支持 zh 或 en`);
83
+ }
84
+ function normalizeLocale(raw) {
85
+ if (!raw) return "zh";
86
+ const normalized = raw.trim().toLowerCase();
87
+ if (normalized === "en" || normalized.startsWith("en_") || normalized.startsWith("en-")) return "en";
88
+ return "zh";
89
+ }
90
+ function isLocaleTokenSupported(raw) {
91
+ const normalized = raw.trim().toLowerCase();
92
+ return normalized === "zh" || normalized === "en" || normalized.startsWith("zh_") || normalized.startsWith("zh-") || normalized.startsWith("en_") || normalized.startsWith("en-");
93
+ }
94
+ function readLangOption(argv) {
95
+ for (let index = 0; index < argv.length; index += 1) {
96
+ const token = argv[index];
97
+ if (!token) continue;
98
+ if (token === "--lang") {
99
+ const value = argv[index + 1];
100
+ return typeof value === "string" ? value : void 0;
101
+ }
102
+ if (token.startsWith("--lang=")) return token.slice(7);
103
+ }
104
+ }
105
+ // src/cli/inputCoordinator.ts
106
+ const sharedSessions = /* @__PURE__ */ new Set();
107
+ const exclusiveKeypressStack = [];
108
+ const EXCLUSIVE_KEYPRESS_CARRYOVER_GUARD_MS = 500;
109
+ let initialized = false;
110
+ let rawModeEnabled = false;
111
+ let dataListenerAttached = false;
112
+ let keypressListenerAttached = false;
113
+ let lastExclusiveResolvedKeypress;
114
+ function hasInteractiveStdin() {
115
+ return Boolean(process.stdin?.isTTY);
116
+ }
117
+ function canSetRawMode() {
118
+ return typeof process.stdin?.setRawMode === "function";
119
+ }
120
+ function updateTerminalState() {
121
+ const shouldKeepInputActive = Array.from(sharedSessions).some((session) => !session.closed && !session.suspended) || exclusiveKeypressStack.length > 0;
122
+ if (canSetRawMode() && rawModeEnabled !== shouldKeepInputActive) {
123
+ process.stdin.setRawMode(shouldKeepInputActive);
124
+ rawModeEnabled = shouldKeepInputActive;
125
+ }
126
+ if (shouldKeepInputActive) {
127
+ process.stdin.resume();
128
+ return;
129
+ }
130
+ process.stdin.pause();
131
+ }
132
+ function handleData(chunk) {
133
+ if (exclusiveKeypressStack.length > 0) return;
134
+ for (const session of sharedSessions) {
135
+ if (session.closed || session.suspended || !session.options.onData) continue;
136
+ session.options.onData(chunk);
137
+ }
138
+ }
139
+ function handleKeypress(str, key) {
140
+ const activeExclusive = exclusiveKeypressStack[exclusiveKeypressStack.length - 1];
141
+ if (activeExclusive) {
142
+ const now = Date.now();
143
+ const signature = `${key?.ctrl ? "ctrl+" : ""}${key?.name ?? str}`;
144
+ if (lastExclusiveResolvedKeypress && lastExclusiveResolvedKeypress.signature === signature && now - lastExclusiveResolvedKeypress.timestamp <= EXCLUSIVE_KEYPRESS_CARRYOVER_GUARD_MS) {
145
+ lastExclusiveResolvedKeypress.timestamp = now;
146
+ return;
147
+ }
148
+ if (now < activeExclusive.ignoreUntil) return;
149
+ const nextValue = activeExclusive.onKeypress(str, key);
150
+ if (nextValue !== void 0) {
151
+ clearTimeout(activeExclusive.timeout);
152
+ exclusiveKeypressStack.pop();
153
+ lastExclusiveResolvedKeypress = {
154
+ signature,
155
+ timestamp: now
156
+ };
157
+ updateTerminalState();
158
+ activeExclusive.resolve(nextValue);
159
+ }
160
+ return;
161
+ }
162
+ for (const session of sharedSessions) {
163
+ if (session.closed || session.suspended || !session.options.onKeypress) continue;
164
+ session.options.onKeypress(str, key);
165
+ }
166
+ }
167
+ function ensureCoordinatorInitialized() {
168
+ if (initialized || !hasInteractiveStdin()) return;
169
+ emitKeypressEvents(process.stdin);
170
+ if (!dataListenerAttached) {
171
+ process.stdin.on("data", handleData);
172
+ dataListenerAttached = true;
173
+ }
174
+ if (!keypressListenerAttached) {
175
+ process.stdin.on("keypress", handleKeypress);
176
+ keypressListenerAttached = true;
177
+ }
178
+ initialized = true;
179
+ }
180
+ function createSharedInputSession(options) {
181
+ if (!hasInteractiveStdin()) return;
182
+ ensureCoordinatorInitialized();
183
+ const session = {
184
+ closed: false,
185
+ options,
186
+ suspended: false
187
+ };
188
+ sharedSessions.add(session);
189
+ updateTerminalState();
190
+ return {
191
+ close() {
192
+ if (session.closed) return;
193
+ session.closed = true;
194
+ sharedSessions.delete(session);
195
+ updateTerminalState();
196
+ },
197
+ resume() {
198
+ if (session.closed) return;
199
+ session.suspended = false;
200
+ updateTerminalState();
201
+ },
202
+ suspend() {
203
+ if (session.closed) return;
204
+ session.suspended = true;
205
+ updateTerminalState();
206
+ }
207
+ };
208
+ }
209
+ async function waitForExclusiveKeypress(options) {
210
+ options.signal?.throwIfAborted();
211
+ if (!hasInteractiveStdin()) return "timeout";
212
+ ensureCoordinatorInitialized();
213
+ return await new Promise((resolve, reject) => {
214
+ const normalizedTimeoutMs = Number.isFinite(options.timeoutMs) && options.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : 3e4;
215
+ const normalizedIgnoreInitialMs = Number.isFinite(options.ignoreInitialMs) && options.ignoreInitialMs && options.ignoreInitialMs > 0 ? options.ignoreInitialMs : 0;
216
+ let onAbort;
217
+ const record = {
218
+ ignoreUntil: Date.now() + normalizedIgnoreInitialMs,
219
+ onKeypress: options.onKeypress,
220
+ resolve: (value) => {
221
+ options.signal?.removeEventListener("abort", onAbort);
222
+ resolve(value);
223
+ },
224
+ timeout: setTimeout(() => {
225
+ const index = exclusiveKeypressStack.lastIndexOf(record);
226
+ if (index >= 0) exclusiveKeypressStack.splice(index, 1);
227
+ updateTerminalState();
228
+ record.resolve("timeout");
229
+ }, normalizedTimeoutMs)
230
+ };
231
+ onAbort = () => {
232
+ clearTimeout(record.timeout);
233
+ options.signal?.removeEventListener("abort", onAbort);
234
+ const index = exclusiveKeypressStack.indexOf(record);
235
+ if (index >= 0) exclusiveKeypressStack.splice(index, 1);
236
+ updateTerminalState();
237
+ reject(options.signal?.reason);
238
+ };
239
+ options.signal?.addEventListener("abort", onAbort, { once: true });
240
+ exclusiveKeypressStack.push(record);
241
+ updateTerminalState();
242
+ });
243
+ }
244
+ async function runWithSuspendedSharedInput(runner) {
245
+ if (!hasInteractiveStdin()) return runner();
246
+ const previousStates = /* @__PURE__ */ new Map();
247
+ for (const session of sharedSessions) {
248
+ if (session.closed) continue;
249
+ previousStates.set(session, session.suspended);
250
+ session.suspended = true;
251
+ }
252
+ if (canSetRawMode() && rawModeEnabled) {
253
+ process.stdin.setRawMode(false);
254
+ rawModeEnabled = false;
255
+ }
256
+ process.stdin.resume();
257
+ try {
258
+ return await runner();
259
+ } finally {
260
+ for (const [session, suspended] of previousStates) if (!session.closed) session.suspended = suspended;
261
+ updateTerminalState();
262
+ }
263
+ }
264
+ // src/cli/retry.ts
265
+ const RETRY_PROMPT_INITIAL_IGNORE_MS = 300;
266
+ const RETRY_CONFIRM_KEYS = ["y"];
267
+ const RETRY_CANCEL_KEYS = [
268
+ "q",
269
+ "Esc",
270
+ "Ctrl+C"
271
+ ];
272
+ const LOGIN_REQUIRED_PATTERNS = [
273
+ /code(?:\s*[:=]\s*|\s+)13\b/i,
274
+ /需要重新登录/,
275
+ /need\s+re-?login/i,
276
+ /re-?login/i,
277
+ /\blogin(?:\s+again)?\s+(?:is\s+)?required\b/i
278
+ ];
279
+ /**
280
+ * @description 提取执行错误文本,便于统一匹配与提示。
281
+ */
282
+ function extractExecutionErrorText(error) {
283
+ if (!error || typeof error !== "object") return "";
284
+ const parts = [];
285
+ const candidate = error;
286
+ for (const field of [
287
+ candidate.message,
288
+ candidate.shortMessage,
289
+ candidate.stderr,
290
+ candidate.stdout
291
+ ]) if (typeof field === "string" && field.trim()) parts.push(field);
292
+ return parts.join("\n");
293
+ }
294
+ function extractLoginRequiredMessage$1(text) {
295
+ if (!text) return "";
296
+ if (/需要重新登录/.test(text)) return "需要重新登录";
297
+ const englishMatch = text.match(/need\s+re-?login|re-?login/i);
298
+ if (englishMatch?.[0]) return englishMatch[0].toLowerCase();
299
+ const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find((line) => Boolean(line) && !line.startsWith("at "));
300
+ if (!firstLine) return "";
301
+ return firstLine.replace(/^\[error\]\s*/i, "").replace(/^error\s*:\s*/i, "").slice(0, 120);
302
+ }
303
+ /**
304
+ * @description 判断是否为微信开发者工具登录失效错误。
305
+ */
306
+ function isWechatIdeLoginRequiredError(error) {
307
+ const text = extractExecutionErrorText(error);
308
+ if (!text) return false;
309
+ return LOGIN_REQUIRED_PATTERNS.some((pattern) => pattern.test(text));
310
+ }
311
+ /**
312
+ * @description 将登录失效错误格式化为更易读的摘要。
313
+ */
314
+ function formatWechatIdeLoginRequiredError(error) {
315
+ const text = extractExecutionErrorText(error);
316
+ const code = text.match(/code\s*[:=]\s*(\d+)/i)?.[1];
317
+ const message = extractLoginRequiredMessage$1(text);
318
+ const lines = ["微信开发者工具返回登录错误:"];
319
+ if (code) lines.push(`- code: ${code}`);
320
+ if (message) lines.push(`- message: ${message}`);
321
+ if (!code && !message) lines.push("- message: 需要重新登录");
322
+ return lines.join("\n");
323
+ }
324
+ /**
325
+ * @description 创建登录失效专用错误,并携带退出码语义。
326
+ */
327
+ function createWechatIdeLoginRequiredExitError(error, reason) {
328
+ const summary = formatWechatIdeLoginRequiredError(error);
329
+ const message = reason ? `${reason}\n${summary}` : summary;
330
+ const loginError = new Error(message, { cause: error });
331
+ loginError.name = "WechatIdeLoginRequiredError";
332
+ loginError.code = 10;
333
+ loginError.exitCode = 10;
334
+ return loginError;
335
+ }
336
+ /**
337
+ * @description 判断错误是否为登录失效专用退出错误。
338
+ */
339
+ function isWechatIdeLoginRequiredExitError(error) {
340
+ if (!error || typeof error !== "object") return false;
341
+ const candidate = error;
342
+ return candidate.name === "WechatIdeLoginRequiredError" || (candidate.code === 10 || candidate.exitCode === 10) && isWechatIdeLoginRequiredError(error);
343
+ }
344
+ /**
345
+ * @description 交互等待用户按 y 重试,按 q 或 Ctrl+C 取消。
346
+ */
347
+ async function waitForRetryKeypress(options = {}) {
348
+ const { timeoutMs = 3e4 } = options;
349
+ if (!process.stdin.isTTY) return "cancel";
350
+ return await waitForExclusiveKeypress({
351
+ signal: options.signal,
352
+ ignoreInitialMs: 300,
353
+ onKeypress: (_str, key) => {
354
+ if (!key) return;
355
+ if (key.ctrl && key.name === "c") return "cancel";
356
+ if (key.name === "y") return "retry";
357
+ if (key.name === "q" || key.name === "escape") return "cancel";
358
+ },
359
+ timeoutMs
360
+ });
361
+ }
362
+ function highlightHotkey(key) {
363
+ return colors.bold(colors.green(key));
364
+ }
365
+ /**
366
+ * @description 生成重试按键提示,并高亮关键热键。
367
+ */
368
+ function formatRetryHotkeyPrompt(timeoutMs = 3e4) {
369
+ const highlight = (key) => highlightHotkey(key);
370
+ const timeoutSeconds = Math.max(1, Math.ceil(timeoutMs / 1e3));
371
+ const confirmKeys = RETRY_CONFIRM_KEYS.map(highlight).join(" / ");
372
+ const cancelKeys = RETRY_CANCEL_KEYS.map(highlight).join(" / ");
373
+ return i18nText(`按 ${confirmKeys} 重试,按 ${cancelKeys} 退出(${timeoutSeconds}s 内无输入将自动失败)。`, `Press ${confirmKeys} to retry, ${cancelKeys} to cancel (auto fail in ${timeoutSeconds}s).`);
374
+ }
375
+ /**
376
+ * @description 输出重试热键提示,并独占等待当前提示对应的按键输入。
377
+ */
378
+ async function promptRetryKeypress(options) {
379
+ const { logger, timeoutMs = 3e4 } = options;
380
+ logger.info(formatRetryHotkeyPrompt(timeoutMs));
381
+ return await waitForRetryKeypress({
382
+ timeoutMs,
383
+ signal: options.signal
384
+ });
385
+ }
386
+ /**
387
+ * @description 统一处理微信开发者工具登录失效场景下的提示与重试交互。
388
+ */
389
+ async function promptWechatIdeLoginRetry(options) {
390
+ const { allowRetry = true, cancelLevel = "info", error, logger, promptOpenIdeLogin = false, retryTimeoutMs = 3e4 } = options;
391
+ logger.error(i18nText("检测到微信开发者工具登录状态失效,请先登录后重试。", "Wechat DevTools login has expired. Please login and retry."));
392
+ if (promptOpenIdeLogin) logger.warn(i18nText("请先打开微信开发者工具完成登录。", "Please open Wechat DevTools and complete login first."));
393
+ logger.warn(formatWechatIdeLoginRequiredError(error));
394
+ if (!allowRetry) return "cancel";
395
+ const action = await promptRetryKeypress({
396
+ logger,
397
+ timeoutMs: retryTimeoutMs,
398
+ signal: options.signal
399
+ });
400
+ if (action === "timeout") {
401
+ logger.error(i18nText(`等待登录重试输入超时(${retryTimeoutMs}ms),已自动取消。`, `Retry prompt timed out (${retryTimeoutMs}ms), canceled automatically.`));
402
+ return "cancel";
403
+ }
404
+ if (action !== "retry") {
405
+ logger[cancelLevel](i18nText("已取消重试。完成登录后请重新执行当前命令。", "Retry canceled. Please run the command again after login."));
406
+ return "cancel";
407
+ }
408
+ return "retry";
409
+ }
410
+ // src/cli/automator/errors.ts
44
411
  const ERROR_STACK_PREFIX_RE = /^at /;
45
412
  const ERROR_PREFIX_RE = /^\[error\]\s*/i;
46
413
  const ERROR_LABEL_PREFIX_RE = /^error\s*:\s*/i;
@@ -63,12 +430,6 @@ const DEVTOOLS_INFRA_ERROR_PATTERNS = [
63
430
  /ECONNREFUSED/i,
64
431
  /connect ECONNREFUSED/i
65
432
  ];
66
- const DEVTOOLS_LOGIN_REQUIRED_PATTERNS = [
67
- /code\s*[:=]\s*10/i,
68
- /需要重新登录/,
69
- /need\s+re-?login/i,
70
- /re-?login/i
71
- ];
72
433
  /**
73
434
  * @description 从错误对象中提取可读文本。
74
435
  */
@@ -146,9 +507,7 @@ function getAutomatorProtocolTimeoutMethod(error) {
146
507
  * @description 判断错误是否属于开发者工具登录失效。
147
508
  */
148
509
  function isAutomatorLoginError(error) {
149
- const text = extractErrorText(error);
150
- if (!text) return false;
151
- return DEVTOOLS_LOGIN_REQUIRED_PATTERNS.some((pattern) => pattern.test(text));
510
+ return isWechatIdeLoginRequiredError(error);
152
511
  }
153
512
  /**
154
513
  * @description 格式化开发者工具登录失效错误,便于终端展示。
@@ -163,126 +522,7 @@ function formatAutomatorLoginError(error) {
163
522
  if (!code && !message) lines.push("- message: 需要重新登录");
164
523
  return lines.join("\n");
165
524
  }
166
- //#endregion
167
- //#region src/cli/automatorProject.ts
168
- const WRAPPER_ROOT = path.join(os.tmpdir(), "weapp-ide-cli-automator-projects");
169
- function normalizeProjectRelativeRoot(rawRoot) {
170
- if (typeof rawRoot !== "string") return;
171
- const normalized = rawRoot.trim().replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/+$/, "");
172
- if (!normalized || normalized === ".") return;
173
- if (normalized.split("/").includes("..")) return;
174
- return normalized;
175
- }
176
- async function pathExists(filePath) {
177
- try {
178
- await fs.access(filePath);
179
- return true;
180
- } catch {
181
- return false;
182
- }
183
- }
184
- async function readJsonObject$1(filePath) {
185
- try {
186
- const raw = await fs.readFile(filePath, "utf8");
187
- const value = JSON.parse(raw);
188
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
189
- } catch {
190
- return;
191
- }
192
- }
193
- async function writeJsonObject$1(filePath, value) {
194
- await fs.mkdir(path.dirname(filePath), { recursive: true });
195
- await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
196
- }
197
- async function copyProjectRoot(sourceProjectPath, wrapperProjectPath, relativeRoot) {
198
- const sourcePath = path.join(sourceProjectPath, relativeRoot);
199
- if (!await pathExists(sourcePath)) return;
200
- await fs.cp(sourcePath, path.join(wrapperProjectPath, relativeRoot), {
201
- dereference: true,
202
- force: true,
203
- recursive: true
204
- });
205
- }
206
- function createWrapperProjectConfig(source, patch) {
207
- const { miniprogramRoot: _miniprogramRoot, qcloudRoot: _qcloudRoot, srcMiniprogramRoot: _srcMiniprogramRoot, ...rest } = source;
208
- const sourceSetting = source.setting && typeof source.setting === "object" ? source.setting : {};
209
- const patchSetting = patch.setting && typeof patch.setting === "object" ? patch.setting : {};
210
- return {
211
- ...rest,
212
- ...patch,
213
- setting: {
214
- ...sourceSetting,
215
- ...patchSetting,
216
- packNpmManually: false,
217
- packNpmRelationList: []
218
- }
219
- };
220
- }
221
- async function ensureWrapperAppConfig(wrapperProjectPath) {
222
- const appConfigPath = path.join(wrapperProjectPath, "app.json");
223
- const appConfig = await readJsonObject$1(appConfigPath);
224
- if (!appConfig) return;
225
- await writeJsonObject$1(appConfigPath, {
226
- ...appConfig,
227
- subPackages: Array.isArray(appConfig.subPackages) ? appConfig.subPackages : []
228
- });
229
- }
230
- /**
231
- * @description 为 DevTools automator 准备稳定的小程序根目录,避免打开瞬间跨 miniprogramRoot 读取 app.json 抖动。
232
- */
233
- async function resolveAutomatorProjectPath(projectPath) {
234
- const sourceProjectPath = path.resolve(projectPath);
235
- const projectConfig = await readJsonObject$1(path.join(sourceProjectPath, "project.config.json"));
236
- const miniprogramRoot = normalizeProjectRelativeRoot(projectConfig?.miniprogramRoot);
237
- if (!miniprogramRoot) return {
238
- projectPath: sourceProjectPath,
239
- sourceProjectPath
240
- };
241
- const sourceProjectConfig = projectConfig ?? {};
242
- const distRoot = path.join(sourceProjectPath, miniprogramRoot);
243
- if (!await pathExists(path.join(distRoot, "app.json"))) return {
244
- projectPath: sourceProjectPath,
245
- sourceProjectPath
246
- };
247
- const wrapperHash = createHash("sha1").update(sourceProjectPath).update("\0").update(path.resolve(distRoot)).digest("hex").slice(0, 16);
248
- const wrapperProjectPath = path.join(WRAPPER_ROOT, wrapperHash);
249
- await fs.rm(wrapperProjectPath, {
250
- recursive: true,
251
- force: true
252
- });
253
- await fs.mkdir(wrapperProjectPath, { recursive: true });
254
- await fs.cp(distRoot, wrapperProjectPath, {
255
- dereference: true,
256
- force: true,
257
- recursive: true
258
- });
259
- const pluginRoot = normalizeProjectRelativeRoot(sourceProjectConfig.pluginRoot);
260
- if (pluginRoot) await copyProjectRoot(sourceProjectPath, wrapperProjectPath, pluginRoot);
261
- const rootPatch = {
262
- compileType: sourceProjectConfig.compileType === "plugin" ? "plugin" : "miniprogram",
263
- miniprogramRoot: "./",
264
- srcMiniprogramRoot: "./"
265
- };
266
- const projectPrivateConfig = await readJsonObject$1(path.join(sourceProjectPath, "project.private.config.json")) ?? {};
267
- await writeJsonObject$1(path.join(wrapperProjectPath, "project.config.json"), createWrapperProjectConfig(sourceProjectConfig, {
268
- ...projectPrivateConfig,
269
- ...rootPatch
270
- }));
271
- await fs.rm(path.join(wrapperProjectPath, "project.private.config.json"), { force: true });
272
- await ensureWrapperAppConfig(wrapperProjectPath);
273
- return {
274
- cleanup: async () => {
275
- await fs.rm(wrapperProjectPath, {
276
- recursive: true,
277
- force: true
278
- });
279
- },
280
- projectPath: wrapperProjectPath,
281
- sourceProjectPath
282
- };
283
- }
284
- //#endregion
285
- //#region src/cli/wechatDevtoolsSettings.ts
525
+ // src/cli/wechatDevtoolsSettings.ts
286
526
  function createStorageHash(key) {
287
527
  return createHash("md5").update(key).digest("hex");
288
528
  }
@@ -383,8 +623,7 @@ async function bootstrapWechatDevtoolsSettings(options = {}) {
383
623
  trustedProjectCount: trusted ? 1 : 0
384
624
  };
385
625
  }
386
- //#endregion
387
- //#region src/cli/automator.ts
626
+ // src/cli/automator.ts
388
627
  const PROJECT_AUTOMATOR_PORT_BASE = 9620;
389
628
  const PROJECT_AUTOMATOR_PORT_RANGE = 2e3;
390
629
  /**
@@ -420,25 +659,26 @@ async function launchSelectedAutomator(options) {
420
659
  const launcher = new Launcher();
421
660
  let lastError = null;
422
661
  let bootstrapResult;
423
- const resolvedProject = options.preserveProjectRoot ? {
424
- projectPath: path.resolve(projectPath),
425
- sourceProjectPath: path.resolve(projectPath)
426
- } : await scope.step(() => resolveAutomatorProjectPath(projectPath), { stage: "project" });
427
- if (process.env.WEAPP_IDE_MANAGED_PROJECT_JOURNAL) {
428
- const { launchManagedAutomator } = await import("./managed-Sq8y8FzP.js");
662
+ if (process.env["WEAPP_IDE_MANAGED_PROJECT_JOURNAL"]?.trim()) {
663
+ const { launchManagedAutomator } = await import("./managed-hSCZXTon.js");
429
664
  managedLaunch = launchManagedAutomator({
430
665
  launcher,
431
666
  scope,
432
667
  target,
433
- projectPath: resolvedProject.projectPath,
668
+ projectPath: path.resolve(projectPath),
434
669
  sourceProjectPath: projectPath,
435
- port: port ?? resolveProjectAutomatorPort(resolvedProject.projectPath),
670
+ port: port ?? resolveProjectAutomatorPort(projectPath),
436
671
  sessionId,
437
672
  trustProject: resolvedTrustProject,
438
- persistAsDefaultSession: options.persistAsDefaultSession
673
+ persistAsDefaultSession: options.persistAsDefaultSession,
674
+ preserveProjectRoot: options.preserveProjectRoot
439
675
  });
440
676
  return await managedLaunch;
441
677
  }
678
+ const resolvedProject = options.preserveProjectRoot ? {
679
+ projectPath: path.resolve(projectPath),
680
+ sourceProjectPath: path.resolve(projectPath)
681
+ } : await scope.step(() => resolveAutomatorProjectPath(projectPath), { stage: "project" });
442
682
  if (config.autoBootstrapDevtools !== false) bootstrapResult = await scope.step(() => bootstrapWechatDevtoolsSettings({
443
683
  target,
444
684
  projectPath: resolvedProject.projectPath,
@@ -563,14 +803,13 @@ async function connectOpenedAutomator(options) {
563
803
  }), {
564
804
  stage: "connect",
565
805
  disposeLate: (program) => {
566
- if (program && typeof program === "object" && "disconnect" in program && typeof program.disconnect === "function") program.disconnect();
806
+ if (program && typeof program === "object" && "disconnect" in program && typeof program.disconnect === "function") return program.disconnect();
567
807
  }
568
808
  });
569
809
  if (process.env.WEAPP_IDE_MANAGED_PROJECT_JOURNAL) miniProgram.close = async () => {
570
- miniProgram.disconnect();
810
+ await miniProgram.disconnect();
571
811
  };
572
812
  return miniProgram;
573
813
  });
574
814
  }
575
- //#endregion
576
- export { parseAutomatorPort as _, bootstrapWechatDevtoolsSettings as a, getAutomatorProtocolTimeoutMethod as c, isAutomatorProtocolTimeoutError as d, isAutomatorWsConnectError as f, resolveAutomatorSessionOptions as g, isRetryableAutomatorLaunchError as h, resolveProjectAutomatorPort as i, isAutomatorLoginError as l, isDevtoolsHttpPortError as m, launchAutomator as n, detectWechatDevtoolsServicePort as o, isDevtoolsExtensionContextInvalidatedError as p, persistOpenedAutomatorSession as r, formatAutomatorLoginError as s, connectOpenedAutomator as t, isAutomatorPortInUseError as u };
815
+ export { waitForExclusiveKeypress as A, isWechatIdeLoginRequiredError as C, waitForRetryKeypress as D, promptWechatIdeLoginRetry as E, parseAutomatorPort as F, i18nText as M, validateLocaleOption as N, createSharedInputSession as O, resolveAutomatorSessionOptions as P, formatWechatIdeLoginRequiredError as S, promptRetryKeypress as T, RETRY_CONFIRM_KEYS as _, bootstrapWechatDevtoolsSettings as a, extractExecutionErrorText as b, getAutomatorProtocolTimeoutMethod as c, isAutomatorProtocolTimeoutError as d, isAutomatorWsConnectError as f, RETRY_CANCEL_KEYS as g, isRetryableAutomatorLaunchError as h, resolveProjectAutomatorPort as i, configureLocaleFromArgv as j, runWithSuspendedSharedInput as k, isAutomatorLoginError as l, isDevtoolsHttpPortError as m, launchAutomator as n, detectWechatDevtoolsServicePort as o, isDevtoolsExtensionContextInvalidatedError as p, persistOpenedAutomatorSession as r, formatAutomatorLoginError as s, connectOpenedAutomator as t, isAutomatorPortInUseError as u, RETRY_PROMPT_INITIAL_IGNORE_MS as v, isWechatIdeLoginRequiredExitError as w, formatRetryHotkeyPrompt as x, createWechatIdeLoginRequiredExitError as y };