weapp-ide-cli 5.0.4 → 5.1.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.
- package/README.md +165 -9
- package/dist/chunk-C2MXNGAM.js +1472 -0
- package/dist/chunk-NSYCXXXT.js +427 -0
- package/dist/cli.js +4 -2
- package/dist/commands-QGH4FNJB.js +34 -0
- package/dist/index.d.ts +207 -2
- package/dist/index.js +88 -2
- package/package.json +2 -1
- package/dist/chunk-QTQD5BFV.js +0 -661
|
@@ -0,0 +1,1472 @@
|
|
|
1
|
+
import {
|
|
2
|
+
audit,
|
|
3
|
+
colors,
|
|
4
|
+
configureLocaleFromArgv,
|
|
5
|
+
currentPage,
|
|
6
|
+
i18nText,
|
|
7
|
+
input,
|
|
8
|
+
logger_default,
|
|
9
|
+
navigateBack,
|
|
10
|
+
navigateTo,
|
|
11
|
+
pageData,
|
|
12
|
+
pageStack,
|
|
13
|
+
reLaunch,
|
|
14
|
+
redirectTo,
|
|
15
|
+
remote,
|
|
16
|
+
scrollTo,
|
|
17
|
+
switchTab,
|
|
18
|
+
systemInfo,
|
|
19
|
+
tap,
|
|
20
|
+
validateLocaleOption
|
|
21
|
+
} from "./chunk-NSYCXXXT.js";
|
|
22
|
+
|
|
23
|
+
// src/cli/automator-argv.ts
|
|
24
|
+
import process from "process";
|
|
25
|
+
function parseAutomatorArgs(argv) {
|
|
26
|
+
const positionals = [];
|
|
27
|
+
let projectPath = process.cwd();
|
|
28
|
+
let timeout;
|
|
29
|
+
let json = false;
|
|
30
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
31
|
+
const token = argv[index];
|
|
32
|
+
if (!token) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (token === "-p" || token === "--project") {
|
|
36
|
+
const value = argv[index + 1];
|
|
37
|
+
if (typeof value === "string" && !value.startsWith("-")) {
|
|
38
|
+
projectPath = value;
|
|
39
|
+
index += 1;
|
|
40
|
+
} else {
|
|
41
|
+
projectPath = process.cwd();
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (token.startsWith("--project=")) {
|
|
46
|
+
projectPath = token.slice("--project=".length) || process.cwd();
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (token === "-t" || token === "--timeout") {
|
|
50
|
+
const value = argv[index + 1];
|
|
51
|
+
if (typeof value === "string") {
|
|
52
|
+
timeout = parsePositiveInt(value);
|
|
53
|
+
index += 1;
|
|
54
|
+
}
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (token.startsWith("--timeout=")) {
|
|
58
|
+
timeout = parsePositiveInt(token.slice("--timeout=".length));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (token === "--json") {
|
|
62
|
+
json = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (token.startsWith("-")) {
|
|
66
|
+
const optionName = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
|
|
67
|
+
if (takesValue(optionName) && !token.includes("=")) {
|
|
68
|
+
const value = argv[index + 1];
|
|
69
|
+
if (typeof value === "string" && !value.startsWith("-")) {
|
|
70
|
+
index += 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
positionals.push(token);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
projectPath,
|
|
79
|
+
timeout,
|
|
80
|
+
json,
|
|
81
|
+
positionals
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function readOptionValue(argv, optionName) {
|
|
85
|
+
const optionWithEqual = `${optionName}=`;
|
|
86
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
87
|
+
const token = argv[index];
|
|
88
|
+
if (!token) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (token === optionName) {
|
|
92
|
+
const value = argv[index + 1];
|
|
93
|
+
if (typeof value !== "string") {
|
|
94
|
+
return void 0;
|
|
95
|
+
}
|
|
96
|
+
return value.trim();
|
|
97
|
+
}
|
|
98
|
+
if (token.startsWith(optionWithEqual)) {
|
|
99
|
+
return token.slice(optionWithEqual.length).trim();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
function removeOption(argv, optionName) {
|
|
105
|
+
const optionWithEqual = `${optionName}=`;
|
|
106
|
+
const nextArgv = [];
|
|
107
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
108
|
+
const token = argv[index];
|
|
109
|
+
if (!token) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (token === optionName) {
|
|
113
|
+
const nextToken = argv[index + 1];
|
|
114
|
+
if (takesValue(optionName) && typeof nextToken === "string" && !nextToken.startsWith("-")) {
|
|
115
|
+
index += 1;
|
|
116
|
+
}
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (token.startsWith(optionWithEqual)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
nextArgv.push(token);
|
|
123
|
+
}
|
|
124
|
+
return nextArgv;
|
|
125
|
+
}
|
|
126
|
+
function parsePositiveInt(raw) {
|
|
127
|
+
const value = Number.parseInt(raw, 10);
|
|
128
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
function takesValue(optionName) {
|
|
134
|
+
return optionName === "-p" || optionName === "--project" || optionName === "-t" || optionName === "--timeout" || optionName === "-o" || optionName === "--output" || optionName === "--page" || optionName === "--login-retry" || optionName === "--login-retry-timeout" || optionName === "--lang" || optionName === "--platform" || optionName === "--qr-output" || optionName === "-r" || optionName === "--result-output" || optionName === "--info-output" || optionName === "-i";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/cli/screenshot.ts
|
|
138
|
+
function printScreenshotHelp() {
|
|
139
|
+
console.log(i18nText(`
|
|
140
|
+
${colors.bold("Usage:")} weapp screenshot [options]
|
|
141
|
+
|
|
142
|
+
${colors.bold("\u53C2\u6570:")}
|
|
143
|
+
-p, --project <path> \u9879\u76EE\u8DEF\u5F84\uFF08\u9ED8\u8BA4\uFF1A\u5F53\u524D\u76EE\u5F55\uFF09
|
|
144
|
+
-o, --output <path> \u622A\u56FE\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84
|
|
145
|
+
--page <path> \u622A\u56FE\u524D\u5148\u8DF3\u8F6C\u9875\u9762
|
|
146
|
+
-t, --timeout <ms> \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u9ED8\u8BA4\uFF1A30000\uFF09
|
|
147
|
+
--json \u4EE5 JSON \u683C\u5F0F\u8F93\u51FA
|
|
148
|
+
--lang <lang> \u8BED\u8A00\u5207\u6362\uFF1Azh | en\uFF08\u9ED8\u8BA4\uFF1Azh\uFF09
|
|
149
|
+
-h, --help \u663E\u793A\u6B64\u5E2E\u52A9\u4FE1\u606F
|
|
150
|
+
|
|
151
|
+
${colors.bold("\u793A\u4F8B:")}
|
|
152
|
+
# \u8F93\u51FA base64 \u5230 stdout
|
|
153
|
+
weapp screenshot -p /path/to/project
|
|
154
|
+
|
|
155
|
+
# \u4FDD\u5B58\u5230\u6587\u4EF6
|
|
156
|
+
weapp screenshot -p /path/to/project -o screenshot.png
|
|
157
|
+
|
|
158
|
+
# \u5148\u8DF3\u8F6C\u9875\u9762\u518D\u622A\u56FE
|
|
159
|
+
weapp screenshot -p /path/to/project --page pages/index/index
|
|
160
|
+
|
|
161
|
+
# \u4EE5 JSON \u8F93\u51FA\u4FBF\u4E8E\u811A\u672C\u89E3\u6790
|
|
162
|
+
weapp screenshot -p /path/to/project --json
|
|
163
|
+
`, `
|
|
164
|
+
${colors.bold("Usage:")} weapp screenshot [options]
|
|
165
|
+
|
|
166
|
+
${colors.bold("Options:")}
|
|
167
|
+
-p, --project <path> Project path (default: current directory)
|
|
168
|
+
-o, --output <path> Output file path for screenshot
|
|
169
|
+
--page <path> Navigate to page before taking screenshot
|
|
170
|
+
-t, --timeout <ms> Connection timeout in milliseconds (default: 30000)
|
|
171
|
+
--json Output as JSON format
|
|
172
|
+
--lang <lang> Language: zh | en (default: zh)
|
|
173
|
+
-h, --help Show this help message
|
|
174
|
+
|
|
175
|
+
${colors.bold("Examples:")}
|
|
176
|
+
# Output base64 to stdout
|
|
177
|
+
weapp screenshot -p /path/to/project
|
|
178
|
+
|
|
179
|
+
# Save to file
|
|
180
|
+
weapp screenshot -p /path/to/project -o screenshot.png
|
|
181
|
+
|
|
182
|
+
# Navigate to page first
|
|
183
|
+
weapp screenshot -p /path/to/project --page pages/index/index
|
|
184
|
+
|
|
185
|
+
# JSON output for parsing
|
|
186
|
+
weapp screenshot -p /path/to/project --json
|
|
187
|
+
`));
|
|
188
|
+
}
|
|
189
|
+
function parseScreenshotArgs(argv) {
|
|
190
|
+
const parsed = parseAutomatorArgs(argv);
|
|
191
|
+
return {
|
|
192
|
+
projectPath: parsed.projectPath,
|
|
193
|
+
timeout: parsed.timeout,
|
|
194
|
+
outputPath: readOptionValue(argv, "-o") || readOptionValue(argv, "--output"),
|
|
195
|
+
page: readOptionValue(argv, "--page")
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
async function runScreenshot(argv) {
|
|
199
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
200
|
+
printScreenshotHelp();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const options = parseScreenshotArgs(argv);
|
|
204
|
+
const isJsonOutput = argv.includes("--json");
|
|
205
|
+
const { takeScreenshot: takeScreenshot2 } = await import("./commands-QGH4FNJB.js");
|
|
206
|
+
const result = await takeScreenshot2(options);
|
|
207
|
+
if (isJsonOutput) {
|
|
208
|
+
console.log(JSON.stringify(result, null, 2));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (result.base64) {
|
|
212
|
+
console.log(result.base64);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/cli/run-automator.ts
|
|
217
|
+
var COMMON_ALLOWED_OPTIONS = /* @__PURE__ */ new Set(["-p", "--project", "-t", "--timeout", "--json", "--lang", "-h", "--help"]);
|
|
218
|
+
var COMMAND_DEFINITIONS = {
|
|
219
|
+
"navigate": createDefinition({
|
|
220
|
+
description: { zh: "\u8DF3\u8F6C\u5230\u9875\u9762\uFF08\u4FDD\u7559\u5F53\u524D\u9875\u9762\u6808\uFF09", en: "Navigate to a page (keep current page in stack)" },
|
|
221
|
+
usage: "weapp navigate <url> -p <project-path>",
|
|
222
|
+
handler: async ({ args }) => {
|
|
223
|
+
const url = requiredPositional(
|
|
224
|
+
args.positionals[0],
|
|
225
|
+
i18nText("navigate \u547D\u4EE4\u7F3A\u5C11 URL \u53C2\u6570", "URL is required for 'navigate' command")
|
|
226
|
+
);
|
|
227
|
+
await navigateTo({ ...args, url });
|
|
228
|
+
}
|
|
229
|
+
}),
|
|
230
|
+
"redirect": createDefinition({
|
|
231
|
+
description: { zh: "\u91CD\u5B9A\u5411\u5230\u9875\u9762\uFF08\u5173\u95ED\u5F53\u524D\u9875\u9762\uFF09", en: "Redirect to a page (close current page)" },
|
|
232
|
+
usage: "weapp redirect <url> -p <project-path>",
|
|
233
|
+
handler: async ({ args }) => {
|
|
234
|
+
const url = requiredPositional(
|
|
235
|
+
args.positionals[0],
|
|
236
|
+
i18nText("redirect \u547D\u4EE4\u7F3A\u5C11 URL \u53C2\u6570", "URL is required for 'redirect' command")
|
|
237
|
+
);
|
|
238
|
+
await redirectTo({ ...args, url });
|
|
239
|
+
}
|
|
240
|
+
}),
|
|
241
|
+
"back": createDefinition({
|
|
242
|
+
description: { zh: "\u8FD4\u56DE\u4E0A\u4E00\u9875", en: "Navigate back to previous page" },
|
|
243
|
+
usage: "weapp back -p <project-path>",
|
|
244
|
+
handler: async ({ args }) => {
|
|
245
|
+
await navigateBack(args);
|
|
246
|
+
}
|
|
247
|
+
}),
|
|
248
|
+
"relaunch": createDefinition({
|
|
249
|
+
description: { zh: "\u91CD\u542F\u5230\u9875\u9762\uFF08\u5173\u95ED\u5168\u90E8\u9875\u9762\uFF09", en: "Re-launch to a page (close all pages)" },
|
|
250
|
+
usage: "weapp relaunch <url> -p <project-path>",
|
|
251
|
+
handler: async ({ args }) => {
|
|
252
|
+
const url = requiredPositional(
|
|
253
|
+
args.positionals[0],
|
|
254
|
+
i18nText("relaunch \u547D\u4EE4\u7F3A\u5C11 URL \u53C2\u6570", "URL is required for 'relaunch' command")
|
|
255
|
+
);
|
|
256
|
+
await reLaunch({ ...args, url });
|
|
257
|
+
}
|
|
258
|
+
}),
|
|
259
|
+
"switch-tab": createDefinition({
|
|
260
|
+
description: { zh: "\u5207\u6362\u5230 tabBar \u9875\u9762", en: "Switch to a tab bar page" },
|
|
261
|
+
usage: "weapp switch-tab <url> -p <project-path>",
|
|
262
|
+
handler: async ({ args }) => {
|
|
263
|
+
const url = requiredPositional(
|
|
264
|
+
args.positionals[0],
|
|
265
|
+
i18nText("switch-tab \u547D\u4EE4\u7F3A\u5C11 URL \u53C2\u6570", "URL is required for 'switch-tab' command")
|
|
266
|
+
);
|
|
267
|
+
await switchTab({ ...args, url });
|
|
268
|
+
}
|
|
269
|
+
}),
|
|
270
|
+
"page-stack": createDefinition({
|
|
271
|
+
description: { zh: "\u83B7\u53D6\u9875\u9762\u6808", en: "Get the page stack" },
|
|
272
|
+
usage: "weapp page-stack -p <project-path>",
|
|
273
|
+
handler: async ({ args }) => {
|
|
274
|
+
await pageStack(args);
|
|
275
|
+
}
|
|
276
|
+
}),
|
|
277
|
+
"current-page": createDefinition({
|
|
278
|
+
description: { zh: "\u83B7\u53D6\u5F53\u524D\u9875\u9762\u4FE1\u606F", en: "Get current page info" },
|
|
279
|
+
usage: "weapp current-page -p <project-path>",
|
|
280
|
+
handler: async ({ args }) => {
|
|
281
|
+
await currentPage(args);
|
|
282
|
+
}
|
|
283
|
+
}),
|
|
284
|
+
"system-info": createDefinition({
|
|
285
|
+
description: { zh: "\u83B7\u53D6\u7CFB\u7EDF\u4FE1\u606F", en: "Get system info" },
|
|
286
|
+
usage: "weapp system-info -p <project-path>",
|
|
287
|
+
handler: async ({ args }) => {
|
|
288
|
+
await systemInfo(args);
|
|
289
|
+
}
|
|
290
|
+
}),
|
|
291
|
+
"page-data": createDefinition({
|
|
292
|
+
description: { zh: "\u83B7\u53D6\u9875\u9762\u6570\u636E", en: "Get page data" },
|
|
293
|
+
usage: "weapp page-data [path] -p <project-path>",
|
|
294
|
+
handler: async ({ args }) => {
|
|
295
|
+
await pageData({ ...args, path: args.positionals[0] });
|
|
296
|
+
}
|
|
297
|
+
}),
|
|
298
|
+
"tap": createDefinition({
|
|
299
|
+
description: { zh: "\u70B9\u51FB\u5143\u7D20", en: "Tap an element" },
|
|
300
|
+
usage: "weapp tap <selector> -p <project-path>",
|
|
301
|
+
handler: async ({ args }) => {
|
|
302
|
+
const selector = requiredPositional(
|
|
303
|
+
args.positionals[0],
|
|
304
|
+
i18nText("tap \u547D\u4EE4\u7F3A\u5C11 selector \u53C2\u6570", "Selector is required for tap command")
|
|
305
|
+
);
|
|
306
|
+
await tap({ ...args, selector });
|
|
307
|
+
}
|
|
308
|
+
}),
|
|
309
|
+
"input": createDefinition({
|
|
310
|
+
description: { zh: "\u5411\u5143\u7D20\u8F93\u5165\u6587\u672C", en: "Input text into an element" },
|
|
311
|
+
usage: "weapp input <selector> <value> -p <project-path>",
|
|
312
|
+
handler: async ({ args }) => {
|
|
313
|
+
const errorMessage = i18nText("input \u547D\u4EE4\u7F3A\u5C11 selector \u6216 value \u53C2\u6570", "Selector and value are required for input command");
|
|
314
|
+
const selector = requiredPositional(args.positionals[0], errorMessage);
|
|
315
|
+
const value = requiredPositional(args.positionals[1], errorMessage);
|
|
316
|
+
await input({ ...args, selector, value });
|
|
317
|
+
}
|
|
318
|
+
}),
|
|
319
|
+
"scroll": createDefinition({
|
|
320
|
+
description: { zh: "\u6EDA\u52A8\u9875\u9762\u5230\u6307\u5B9A\u4F4D\u7F6E", en: "Scroll page to position" },
|
|
321
|
+
usage: "weapp scroll <scrollTop> -p <project-path>",
|
|
322
|
+
handler: async ({ args }) => {
|
|
323
|
+
const rawScrollTop = requiredPositional(
|
|
324
|
+
args.positionals[0],
|
|
325
|
+
i18nText("scroll \u547D\u4EE4\u7F3A\u5C11\u6EDA\u52A8\u4F4D\u7F6E\u53C2\u6570", "Scroll position is required for scroll command")
|
|
326
|
+
);
|
|
327
|
+
const scrollTop = Number.parseInt(rawScrollTop, 10);
|
|
328
|
+
if (!Number.isFinite(scrollTop)) {
|
|
329
|
+
throw new TypeError(i18nText(`\u65E0\u6548\u7684\u6EDA\u52A8\u4F4D\u7F6E: ${rawScrollTop}`, `Invalid scroll position: ${rawScrollTop}`));
|
|
330
|
+
}
|
|
331
|
+
await scrollTo({ ...args, scrollTop });
|
|
332
|
+
}
|
|
333
|
+
}),
|
|
334
|
+
"audit": createDefinition({
|
|
335
|
+
description: { zh: "\u6267\u884C\u4F53\u9A8C\u8BC4\u5206\u5BA1\u8BA1", en: "Run experience audit" },
|
|
336
|
+
usage: "weapp audit -p <project-path>",
|
|
337
|
+
options: [
|
|
338
|
+
{ flag: "-o, --output <path>", description: { zh: "\u5BA1\u8BA1\u62A5\u544A\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84", en: "Output file path for report" } }
|
|
339
|
+
],
|
|
340
|
+
allowedOptions: ["-o", "--output"],
|
|
341
|
+
handler: async ({ args, argv }) => {
|
|
342
|
+
const outputPath = readOptionValue(argv, "-o") || readOptionValue(argv, "--output");
|
|
343
|
+
await audit({ ...args, outputPath });
|
|
344
|
+
}
|
|
345
|
+
}),
|
|
346
|
+
"remote": createDefinition({
|
|
347
|
+
description: { zh: "\u5F00\u542F/\u5173\u95ED\u8FDC\u7A0B\u8C03\u8BD5", en: "Enable/disable remote debugging" },
|
|
348
|
+
usage: "weapp remote -p <project-path>",
|
|
349
|
+
options: [
|
|
350
|
+
{ flag: "--disable", description: { zh: "\u5173\u95ED\u8FDC\u7A0B\u8C03\u8BD5", en: "Disable remote debugging" } }
|
|
351
|
+
],
|
|
352
|
+
allowedOptions: ["--disable"],
|
|
353
|
+
handler: async ({ args, argv }) => {
|
|
354
|
+
await remote({ ...args, enable: !argv.includes("--disable") });
|
|
355
|
+
}
|
|
356
|
+
})
|
|
357
|
+
};
|
|
358
|
+
var AUTOMATOR_COMMAND_NAMES = ["screenshot", ...Object.keys(COMMAND_DEFINITIONS)];
|
|
359
|
+
var AUTOMATOR_COMMANDS = new Set(AUTOMATOR_COMMAND_NAMES);
|
|
360
|
+
function isAutomatorCommand(command) {
|
|
361
|
+
return Boolean(command && AUTOMATOR_COMMANDS.has(command));
|
|
362
|
+
}
|
|
363
|
+
async function runAutomatorCommand(command, argv) {
|
|
364
|
+
if (command === "screenshot") {
|
|
365
|
+
await runScreenshot(argv);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const definition = COMMAND_DEFINITIONS[command];
|
|
369
|
+
if (!definition) {
|
|
370
|
+
throw new Error(i18nText(`\u672A\u77E5 automator \u547D\u4EE4: ${command}`, `Unknown automator command: ${command}`));
|
|
371
|
+
}
|
|
372
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
373
|
+
printCommandHelp(command);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
validateUnsupportedOptions(command, argv, definition.allowedOptions);
|
|
377
|
+
const args = parseAutomatorArgs(argv);
|
|
378
|
+
await definition.handler({ argv, args });
|
|
379
|
+
}
|
|
380
|
+
function getAutomatorCommandHelp(command) {
|
|
381
|
+
const definition = COMMAND_DEFINITIONS[command];
|
|
382
|
+
if (!definition) {
|
|
383
|
+
return void 0;
|
|
384
|
+
}
|
|
385
|
+
const optionLines = [
|
|
386
|
+
...definition.options,
|
|
387
|
+
{ flag: "-p, --project <path>", description: { zh: "\u9879\u76EE\u8DEF\u5F84\uFF08\u9ED8\u8BA4\uFF1A\u5F53\u524D\u76EE\u5F55\uFF09", en: "Project path (default: current directory)" } },
|
|
388
|
+
{ flag: "-t, --timeout <ms>", description: { zh: "\u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u9ED8\u8BA4\uFF1A30000\uFF09", en: "Connection timeout (default: 30000)" } },
|
|
389
|
+
{ flag: "--json", description: { zh: "\u652F\u6301\u65F6\u4EE5 JSON \u8F93\u51FA", en: "Output as JSON when supported" } },
|
|
390
|
+
{ flag: "--lang <lang>", description: { zh: "\u8BED\u8A00\u5207\u6362\uFF1Azh | en\uFF08\u9ED8\u8BA4\uFF1Azh\uFF09", en: "Language: zh | en (default: zh)" } },
|
|
391
|
+
{ flag: "-h, --help", description: { zh: "\u663E\u793A\u547D\u4EE4\u5E2E\u52A9", en: "Show command help" } }
|
|
392
|
+
];
|
|
393
|
+
return [
|
|
394
|
+
i18nText(definition.description.zh, definition.description.en),
|
|
395
|
+
"",
|
|
396
|
+
`Usage: ${definition.usage}`,
|
|
397
|
+
"",
|
|
398
|
+
i18nText("\u53C2\u6570\uFF1A", "Options:"),
|
|
399
|
+
...optionLines.map((option) => ` ${option.flag.padEnd(24)} ${i18nText(option.description.zh, option.description.en)}`)
|
|
400
|
+
].join("\n");
|
|
401
|
+
}
|
|
402
|
+
function printCommandHelp(command) {
|
|
403
|
+
const help = getAutomatorCommandHelp(command);
|
|
404
|
+
if (help) {
|
|
405
|
+
console.log(help);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
logger_default.warn(i18nText(`\u547D\u4EE4 ${command} \u6682\u65E0\u5E2E\u52A9\u4FE1\u606F`, `No help available for command: ${command}`));
|
|
409
|
+
}
|
|
410
|
+
function createDefinition(input3) {
|
|
411
|
+
const options = input3.options ?? [];
|
|
412
|
+
const allowedOptions = /* @__PURE__ */ new Set([...COMMON_ALLOWED_OPTIONS, ...input3.allowedOptions ?? []]);
|
|
413
|
+
return {
|
|
414
|
+
description: input3.description,
|
|
415
|
+
usage: input3.usage,
|
|
416
|
+
options,
|
|
417
|
+
allowedOptions,
|
|
418
|
+
handler: input3.handler
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function validateUnsupportedOptions(command, argv, allowedOptions) {
|
|
422
|
+
for (const token of argv) {
|
|
423
|
+
if (!token.startsWith("-")) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
const optionName = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
|
|
427
|
+
if (allowedOptions.has(optionName)) {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
throw new Error(i18nText(
|
|
431
|
+
`'${command}' \u547D\u4EE4\u4E0D\u652F\u6301\u53C2\u6570 '${optionName}'`,
|
|
432
|
+
`Unknown option '${optionName}' for '${command}' command`
|
|
433
|
+
));
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
function requiredPositional(value, message) {
|
|
437
|
+
if (!value) {
|
|
438
|
+
throw new Error(message);
|
|
439
|
+
}
|
|
440
|
+
return value;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/cli/command-catalog.ts
|
|
444
|
+
var WECHAT_CLI_COMMAND_NAMES = [
|
|
445
|
+
"open",
|
|
446
|
+
"login",
|
|
447
|
+
"islogin",
|
|
448
|
+
"preview",
|
|
449
|
+
"auto-preview",
|
|
450
|
+
"upload",
|
|
451
|
+
"build-npm",
|
|
452
|
+
"auto",
|
|
453
|
+
"auto-replay",
|
|
454
|
+
"reset-fileutils",
|
|
455
|
+
"close",
|
|
456
|
+
"quit",
|
|
457
|
+
"cache",
|
|
458
|
+
"engine",
|
|
459
|
+
"open-other",
|
|
460
|
+
"build-ipa",
|
|
461
|
+
"build-apk",
|
|
462
|
+
"cloud"
|
|
463
|
+
];
|
|
464
|
+
var MINIDEV_NAMESPACE_COMMAND_NAMES = ["alipay", "ali", "minidev"];
|
|
465
|
+
var CONFIG_COMMAND_NAME = "config";
|
|
466
|
+
var WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES = [
|
|
467
|
+
...WECHAT_CLI_COMMAND_NAMES,
|
|
468
|
+
...AUTOMATOR_COMMAND_NAMES,
|
|
469
|
+
...MINIDEV_NAMESPACE_COMMAND_NAMES,
|
|
470
|
+
CONFIG_COMMAND_NAME
|
|
471
|
+
];
|
|
472
|
+
var WEAPP_IDE_TOP_LEVEL_COMMAND_SET = new Set(WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES);
|
|
473
|
+
function isWeappIdeTopLevelCommand(command) {
|
|
474
|
+
return Boolean(command && WEAPP_IDE_TOP_LEVEL_COMMAND_SET.has(command));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/utils/path.ts
|
|
478
|
+
import process2 from "process";
|
|
479
|
+
import path from "pathe";
|
|
480
|
+
function resolvePath(filePath) {
|
|
481
|
+
if (path.isAbsolute(filePath)) {
|
|
482
|
+
return filePath;
|
|
483
|
+
}
|
|
484
|
+
return path.resolve(process2.cwd(), filePath);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/config/paths.ts
|
|
488
|
+
import os from "os";
|
|
489
|
+
import path2 from "pathe";
|
|
490
|
+
var homedir = os.homedir();
|
|
491
|
+
var defaultCustomConfigDirPath = path2.join(homedir, ".weapp-ide-cli");
|
|
492
|
+
var defaultCustomConfigFilePath = path2.join(
|
|
493
|
+
defaultCustomConfigDirPath,
|
|
494
|
+
"config.json"
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
// src/config/custom.ts
|
|
498
|
+
import fs from "fs-extra";
|
|
499
|
+
var JSON_OPTIONS = {
|
|
500
|
+
encoding: "utf8",
|
|
501
|
+
spaces: 2
|
|
502
|
+
};
|
|
503
|
+
async function createCustomConfig(params) {
|
|
504
|
+
const trimmedCliPath = params.cliPath.trim();
|
|
505
|
+
if (!trimmedCliPath) {
|
|
506
|
+
throw new Error("cliPath cannot be empty");
|
|
507
|
+
}
|
|
508
|
+
const normalizedCliPath = resolvePath(trimmedCliPath);
|
|
509
|
+
await writeCustomConfig({
|
|
510
|
+
cliPath: normalizedCliPath
|
|
511
|
+
});
|
|
512
|
+
return normalizedCliPath;
|
|
513
|
+
}
|
|
514
|
+
async function createLocaleConfig(locale) {
|
|
515
|
+
await writeCustomConfig({ locale });
|
|
516
|
+
return locale;
|
|
517
|
+
}
|
|
518
|
+
async function removeCustomConfigKey(key) {
|
|
519
|
+
const currentConfig = await readCustomConfig();
|
|
520
|
+
if (!(key in currentConfig)) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
const nextConfig = { ...currentConfig };
|
|
524
|
+
delete nextConfig[key];
|
|
525
|
+
await writeCustomConfig(nextConfig, { replace: true });
|
|
526
|
+
}
|
|
527
|
+
async function overwriteCustomConfig(config) {
|
|
528
|
+
const nextConfig = {};
|
|
529
|
+
if (typeof config.cliPath === "string" && config.cliPath.trim()) {
|
|
530
|
+
nextConfig.cliPath = resolvePath(config.cliPath.trim());
|
|
531
|
+
}
|
|
532
|
+
if (config.locale === "zh" || config.locale === "en") {
|
|
533
|
+
nextConfig.locale = config.locale;
|
|
534
|
+
}
|
|
535
|
+
await writeCustomConfig(nextConfig, { replace: true });
|
|
536
|
+
}
|
|
537
|
+
async function readCustomConfig() {
|
|
538
|
+
if (!await fs.pathExists(defaultCustomConfigFilePath)) {
|
|
539
|
+
return {};
|
|
540
|
+
}
|
|
541
|
+
try {
|
|
542
|
+
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
543
|
+
if (!config || typeof config !== "object") {
|
|
544
|
+
return {};
|
|
545
|
+
}
|
|
546
|
+
const candidate = config;
|
|
547
|
+
const next = {};
|
|
548
|
+
if (typeof candidate.cliPath === "string" && candidate.cliPath.trim()) {
|
|
549
|
+
next.cliPath = candidate.cliPath.trim();
|
|
550
|
+
}
|
|
551
|
+
if (candidate.locale === "zh" || candidate.locale === "en") {
|
|
552
|
+
next.locale = candidate.locale;
|
|
553
|
+
}
|
|
554
|
+
return next;
|
|
555
|
+
} catch {
|
|
556
|
+
return {};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
async function writeCustomConfig(patch, options = {}) {
|
|
560
|
+
const currentConfig = options.replace ? {} : await readCustomConfig();
|
|
561
|
+
const nextConfig = { ...currentConfig, ...patch };
|
|
562
|
+
await fs.ensureDir(defaultCustomConfigDirPath);
|
|
563
|
+
await fs.writeJSON(defaultCustomConfigFilePath, nextConfig, JSON_OPTIONS);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// src/cli/prompt.ts
|
|
567
|
+
import { stdin as input2, stdout as output } from "process";
|
|
568
|
+
import { createInterface } from "readline/promises";
|
|
569
|
+
import fs2 from "fs-extra";
|
|
570
|
+
async function promptForCliPath() {
|
|
571
|
+
const rl = createInterface({ input: input2, output });
|
|
572
|
+
try {
|
|
573
|
+
logger_default.info(`\u8BF7\u8BBE\u7F6E ${colors.bold("\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177 CLI")} \u7684\u8DEF\u5F84`);
|
|
574
|
+
logger_default.info("\u63D0\u793A\uFF1A\u547D\u4EE4\u884C\u5DE5\u5177\u9ED8\u8BA4\u6240\u5728\u4F4D\u7F6E\uFF1A");
|
|
575
|
+
logger_default.info(`- MacOS: ${colors.green("<\u5B89\u88C5\u8DEF\u5F84>/Contents/MacOS/cli")}`);
|
|
576
|
+
logger_default.info(`- Windows: ${colors.green("<\u5B89\u88C5\u8DEF\u5F84>/cli.bat")}`);
|
|
577
|
+
logger_default.info(`- Linux: ${colors.green("<\u5B89\u88C5\u8DEF\u5F84>/files/bin/bin/wechat-devtools-cli")}`);
|
|
578
|
+
const cliPath = (await rl.question("\u8BF7\u8F93\u5165\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177 CLI \u8DEF\u5F84\uFF1A")).trim();
|
|
579
|
+
if (!cliPath) {
|
|
580
|
+
logger_default.error("\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u53D6\u6D88\u672C\u6B21\u914D\u7F6E\u3002");
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const normalizedPath = await createCustomConfig({ cliPath });
|
|
585
|
+
logger_default.info(`\u5168\u5C40\u914D\u7F6E\u5B58\u50A8\u4F4D\u7F6E\uFF1A${colors.green(defaultCustomConfigFilePath)}`);
|
|
586
|
+
if (!await fs2.pathExists(normalizedPath)) {
|
|
587
|
+
logger_default.warn("\u5728\u5F53\u524D\u8DEF\u5F84\u672A\u627E\u5230\u5FAE\u4FE1web\u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u786E\u8BA4\u8DEF\u5F84\u662F\u5426\u6B63\u786E\u3002");
|
|
588
|
+
}
|
|
589
|
+
return normalizedPath;
|
|
590
|
+
} catch (error) {
|
|
591
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
592
|
+
logger_default.error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25\uFF1A${reason}`);
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
} finally {
|
|
596
|
+
rl.close();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/runtime/platform.ts
|
|
601
|
+
import os2 from "os";
|
|
602
|
+
import process3 from "process";
|
|
603
|
+
import fs3 from "fs-extra";
|
|
604
|
+
import path3 from "pathe";
|
|
605
|
+
var SupportedPlatformsMap = {
|
|
606
|
+
Windows_NT: "Windows_NT",
|
|
607
|
+
Darwin: "Darwin",
|
|
608
|
+
Linux: "Linux"
|
|
609
|
+
};
|
|
610
|
+
function isOperatingSystemSupported(osName = os2.type()) {
|
|
611
|
+
return osName === SupportedPlatformsMap.Windows_NT || osName === SupportedPlatformsMap.Darwin || osName === SupportedPlatformsMap.Linux;
|
|
612
|
+
}
|
|
613
|
+
var operatingSystemName = os2.type();
|
|
614
|
+
function createLinuxCliResolver() {
|
|
615
|
+
let resolvedPath;
|
|
616
|
+
let attempted = false;
|
|
617
|
+
let pending = null;
|
|
618
|
+
return async () => {
|
|
619
|
+
if (attempted) {
|
|
620
|
+
return resolvedPath;
|
|
621
|
+
}
|
|
622
|
+
if (!pending) {
|
|
623
|
+
pending = (async () => {
|
|
624
|
+
try {
|
|
625
|
+
const envPath = await getFirstBinaryPath("wechat-devtools-cli");
|
|
626
|
+
if (envPath) {
|
|
627
|
+
resolvedPath = envPath;
|
|
628
|
+
}
|
|
629
|
+
} catch (error) {
|
|
630
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
631
|
+
logger_default.warn(`\u83B7\u53D6 Linux wechat-devtools-cli \u8DEF\u5F84\u5931\u8D25\uFF1A${reason}`);
|
|
632
|
+
} finally {
|
|
633
|
+
attempted = true;
|
|
634
|
+
}
|
|
635
|
+
return resolvedPath;
|
|
636
|
+
})();
|
|
637
|
+
}
|
|
638
|
+
return pending;
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
var linuxCliResolver = createLinuxCliResolver();
|
|
642
|
+
var WINDOWS_DEFAULT_CLI = "C:\\Program Files (x86)\\Tencent\\\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177\\cli.bat";
|
|
643
|
+
var DARWIN_DEFAULT_CLI = "/Applications/wechatwebdevtools.app/Contents/MacOS/cli";
|
|
644
|
+
var cliPathResolvers = {
|
|
645
|
+
[SupportedPlatformsMap.Windows_NT]: async () => WINDOWS_DEFAULT_CLI,
|
|
646
|
+
[SupportedPlatformsMap.Darwin]: async () => DARWIN_DEFAULT_CLI,
|
|
647
|
+
[SupportedPlatformsMap.Linux]: linuxCliResolver
|
|
648
|
+
};
|
|
649
|
+
async function getDefaultCliPath(targetOs = operatingSystemName) {
|
|
650
|
+
if (!isOperatingSystemSupported(targetOs)) {
|
|
651
|
+
return void 0;
|
|
652
|
+
}
|
|
653
|
+
const resolver = cliPathResolvers[targetOs];
|
|
654
|
+
const resolvedPath = await resolver();
|
|
655
|
+
return resolvedPath;
|
|
656
|
+
}
|
|
657
|
+
async function getFirstBinaryPath(command) {
|
|
658
|
+
const envPath = process3.env.PATH || "";
|
|
659
|
+
const pathDirs = envPath.split(path3.delimiter);
|
|
660
|
+
for (const dir of pathDirs) {
|
|
661
|
+
const fullPath = path3.join(dir, command);
|
|
662
|
+
try {
|
|
663
|
+
await fs3.access(fullPath, fs3.constants.X_OK);
|
|
664
|
+
return fullPath;
|
|
665
|
+
} catch {
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return void 0;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/config/resolver.ts
|
|
673
|
+
import fs4 from "fs-extra";
|
|
674
|
+
async function getConfig() {
|
|
675
|
+
if (await fs4.pathExists(defaultCustomConfigFilePath)) {
|
|
676
|
+
try {
|
|
677
|
+
const config = await fs4.readJSON(defaultCustomConfigFilePath);
|
|
678
|
+
const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
|
|
679
|
+
const locale = config.locale === "zh" || config.locale === "en" ? config.locale : void 0;
|
|
680
|
+
if (cliPath) {
|
|
681
|
+
logger_default.info(`\u5168\u5C40\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF1A${colors.green(defaultCustomConfigFilePath)}`);
|
|
682
|
+
logger_default.info(`\u81EA\u5B9A\u4E49 CLI \u8DEF\u5F84\uFF1A${colors.green(cliPath)}`);
|
|
683
|
+
return {
|
|
684
|
+
cliPath,
|
|
685
|
+
locale,
|
|
686
|
+
source: "custom"
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
logger_default.warn("\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u7F3A\u5C11\u6709\u6548\u7684 CLI \u8DEF\u5F84\uFF0C\u5C06\u5C1D\u8BD5\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u5F84\u3002");
|
|
690
|
+
} catch (error) {
|
|
691
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
692
|
+
logger_default.warn(`\u89E3\u6790\u81EA\u5B9A\u4E49\u914D\u7F6E\u5931\u8D25\uFF0C\u5C06\u5C1D\u8BD5\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u5F84\u3002\u539F\u56E0\uFF1A${reason}`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const fallbackPath = await getDefaultCliPath();
|
|
696
|
+
if (fallbackPath) {
|
|
697
|
+
return {
|
|
698
|
+
cliPath: fallbackPath,
|
|
699
|
+
locale: void 0,
|
|
700
|
+
source: "default"
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
return {
|
|
704
|
+
cliPath: "",
|
|
705
|
+
locale: void 0,
|
|
706
|
+
source: "missing"
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
async function getConfiguredLocale() {
|
|
710
|
+
const config = await readCustomConfig();
|
|
711
|
+
return config.locale;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// src/cli/resolver.ts
|
|
715
|
+
import fs5 from "fs-extra";
|
|
716
|
+
async function resolveCliPath() {
|
|
717
|
+
const config = await getConfig();
|
|
718
|
+
if (!config.cliPath) {
|
|
719
|
+
return { cliPath: null, source: config.source };
|
|
720
|
+
}
|
|
721
|
+
const exists = await fs5.pathExists(config.cliPath);
|
|
722
|
+
return {
|
|
723
|
+
cliPath: exists ? config.cliPath : null,
|
|
724
|
+
source: config.source
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// src/cli/config-command.ts
|
|
729
|
+
import fs6 from "fs-extra";
|
|
730
|
+
async function handleConfigCommand(argv) {
|
|
731
|
+
const action = argv[0];
|
|
732
|
+
if (!action) {
|
|
733
|
+
await promptForCliPath();
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (action === "lang" || action === "set-lang") {
|
|
737
|
+
const nextLocale = argv[1];
|
|
738
|
+
if (nextLocale !== "zh" && nextLocale !== "en") {
|
|
739
|
+
throw new Error(i18nText(
|
|
740
|
+
"\u8BF7\u4F7F\u7528 weapp config lang <zh|en> \u5207\u6362\u8BED\u8A00",
|
|
741
|
+
"Use weapp config lang <zh|en> to switch language"
|
|
742
|
+
));
|
|
743
|
+
}
|
|
744
|
+
await createLocaleConfig(nextLocale);
|
|
745
|
+
logger_default.info(i18nText(
|
|
746
|
+
`\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\uFF1A${nextLocale === "zh" ? "\u4E2D\u6587" : "\u82F1\u6587"}`,
|
|
747
|
+
`Language switched to: ${nextLocale}`
|
|
748
|
+
));
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (action === "show") {
|
|
752
|
+
const config = await readCustomConfig();
|
|
753
|
+
logger_default.info(i18nText(
|
|
754
|
+
`\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF1A${colors.green(defaultCustomConfigFilePath)}`,
|
|
755
|
+
`Config file: ${colors.green(defaultCustomConfigFilePath)}`
|
|
756
|
+
));
|
|
757
|
+
console.log(JSON.stringify(config, null, 2));
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (action === "get") {
|
|
761
|
+
const key = argv[1];
|
|
762
|
+
if (key !== "cliPath" && key !== "locale") {
|
|
763
|
+
throw new Error(i18nText(
|
|
764
|
+
"\u4EC5\u652F\u6301\u8BFB\u53D6\u914D\u7F6E\u9879\uFF1AcliPath | locale",
|
|
765
|
+
"Supported keys: cliPath | locale"
|
|
766
|
+
));
|
|
767
|
+
}
|
|
768
|
+
const config = await readCustomConfig();
|
|
769
|
+
const value = config[key];
|
|
770
|
+
if (typeof value === "string") {
|
|
771
|
+
console.log(value);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
console.log("");
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
if (action === "set") {
|
|
778
|
+
const key = argv[1];
|
|
779
|
+
const value = argv.slice(2).join(" ").trim();
|
|
780
|
+
if (!value) {
|
|
781
|
+
throw new Error(i18nText(
|
|
782
|
+
"\u8BF7\u63D0\u4F9B\u914D\u7F6E\u503C\uFF0C\u4F8B\u5982\uFF1Aweapp config set locale en",
|
|
783
|
+
"Please provide a value, e.g. weapp config set locale en"
|
|
784
|
+
));
|
|
785
|
+
}
|
|
786
|
+
if (key === "cliPath") {
|
|
787
|
+
await createCustomConfig({ cliPath: value });
|
|
788
|
+
logger_default.info(i18nText("CLI \u8DEF\u5F84\u5DF2\u66F4\u65B0\u3002", "CLI path updated."));
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (key === "locale") {
|
|
792
|
+
if (value !== "zh" && value !== "en") {
|
|
793
|
+
throw new Error(i18nText(
|
|
794
|
+
"locale \u4EC5\u652F\u6301 zh \u6216 en",
|
|
795
|
+
"locale only supports zh or en"
|
|
796
|
+
));
|
|
797
|
+
}
|
|
798
|
+
await createLocaleConfig(value);
|
|
799
|
+
logger_default.info(i18nText(
|
|
800
|
+
`\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\uFF1A${value === "zh" ? "\u4E2D\u6587" : "\u82F1\u6587"}`,
|
|
801
|
+
`Language switched to: ${value}`
|
|
802
|
+
));
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
throw new Error(i18nText(
|
|
806
|
+
"\u4EC5\u652F\u6301\u8BBE\u7F6E\u914D\u7F6E\u9879\uFF1AcliPath | locale",
|
|
807
|
+
"Supported keys for set: cliPath | locale"
|
|
808
|
+
));
|
|
809
|
+
}
|
|
810
|
+
if (action === "unset") {
|
|
811
|
+
const key = argv[1];
|
|
812
|
+
if (key !== "cliPath" && key !== "locale") {
|
|
813
|
+
throw new Error(i18nText(
|
|
814
|
+
"\u4EC5\u652F\u6301\u6E05\u9664\u914D\u7F6E\u9879\uFF1AcliPath | locale",
|
|
815
|
+
"Supported keys for unset: cliPath | locale"
|
|
816
|
+
));
|
|
817
|
+
}
|
|
818
|
+
await removeCustomConfigKey(key);
|
|
819
|
+
logger_default.info(i18nText(
|
|
820
|
+
`\u5DF2\u6E05\u9664\u914D\u7F6E\u9879\uFF1A${key}`,
|
|
821
|
+
`Config key cleared: ${key}`
|
|
822
|
+
));
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
if (action === "doctor") {
|
|
826
|
+
const rawConfig = await readCustomConfig();
|
|
827
|
+
const hasConfigFile = await fs6.pathExists(defaultCustomConfigFilePath);
|
|
828
|
+
const resolvedCli = await resolveCliPath();
|
|
829
|
+
const hasCustomCli = typeof rawConfig.cliPath === "string" && rawConfig.cliPath.length > 0;
|
|
830
|
+
const hasValidCli = Boolean(resolvedCli.cliPath);
|
|
831
|
+
const locale = rawConfig.locale ?? "zh";
|
|
832
|
+
const report = {
|
|
833
|
+
configFile: defaultCustomConfigFilePath,
|
|
834
|
+
configFileExists: hasConfigFile,
|
|
835
|
+
cliPath: rawConfig.cliPath ?? null,
|
|
836
|
+
cliPathValid: hasValidCli,
|
|
837
|
+
locale,
|
|
838
|
+
source: resolvedCli.source
|
|
839
|
+
};
|
|
840
|
+
logger_default.info(i18nText("\u914D\u7F6E\u8BCA\u65AD\u7ED3\u679C\uFF1A", "Configuration diagnostics:"));
|
|
841
|
+
console.log(JSON.stringify(report, null, 2));
|
|
842
|
+
if (!hasConfigFile) {
|
|
843
|
+
logger_default.warn(i18nText(
|
|
844
|
+
"\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF0C\u53EF\u6267\u884C weapp config \u8FDB\u884C\u521D\u59CB\u5316\u3002",
|
|
845
|
+
"Config file not found. Run `weapp config` to initialize."
|
|
846
|
+
));
|
|
847
|
+
}
|
|
848
|
+
if (hasCustomCli && !hasValidCli) {
|
|
849
|
+
logger_default.warn(i18nText(
|
|
850
|
+
"\u68C0\u6D4B\u5230\u914D\u7F6E\u7684 cliPath \u4E0D\u53EF\u7528\uFF0C\u8BF7\u6267\u884C weapp config set cliPath <path> \u4FEE\u590D\u3002",
|
|
851
|
+
"Configured cliPath is not available. Run `weapp config set cliPath <path>` to fix it."
|
|
852
|
+
));
|
|
853
|
+
}
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
if (action === "export") {
|
|
857
|
+
const outputPath = argv[1];
|
|
858
|
+
const config = await readCustomConfig();
|
|
859
|
+
if (outputPath) {
|
|
860
|
+
await fs6.writeJSON(outputPath, config, { spaces: 2, encoding: "utf8" });
|
|
861
|
+
logger_default.info(i18nText(
|
|
862
|
+
`\u914D\u7F6E\u5DF2\u5BFC\u51FA\u5230\uFF1A${colors.green(outputPath)}`,
|
|
863
|
+
`Config exported to: ${colors.green(outputPath)}`
|
|
864
|
+
));
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
console.log(JSON.stringify(config, null, 2));
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
if (action === "import") {
|
|
871
|
+
const inputPath = argv[1];
|
|
872
|
+
if (!inputPath) {
|
|
873
|
+
throw new Error(i18nText(
|
|
874
|
+
"\u8BF7\u63D0\u4F9B\u5BFC\u5165\u6587\u4EF6\u8DEF\u5F84\uFF0C\u4F8B\u5982\uFF1Aweapp config import ./weapp-config.json",
|
|
875
|
+
"Please provide import file path, e.g. weapp config import ./weapp-config.json"
|
|
876
|
+
));
|
|
877
|
+
}
|
|
878
|
+
const imported = await fs6.readJSON(inputPath);
|
|
879
|
+
if (!imported || typeof imported !== "object") {
|
|
880
|
+
throw new Error(i18nText(
|
|
881
|
+
"\u5BFC\u5165\u6587\u4EF6\u683C\u5F0F\u65E0\u6548\uFF1A\u5E94\u4E3A JSON \u5BF9\u8C61",
|
|
882
|
+
"Invalid import file format: expected a JSON object"
|
|
883
|
+
));
|
|
884
|
+
}
|
|
885
|
+
const candidate = imported;
|
|
886
|
+
const cliPath = typeof candidate.cliPath === "string" ? candidate.cliPath : void 0;
|
|
887
|
+
const locale = candidate.locale === "zh" || candidate.locale === "en" ? candidate.locale : void 0;
|
|
888
|
+
await overwriteCustomConfig({ cliPath, locale });
|
|
889
|
+
logger_default.info(i18nText(
|
|
890
|
+
`\u914D\u7F6E\u5DF2\u4ECE ${colors.green(inputPath)} \u5BFC\u5165`,
|
|
891
|
+
`Config imported from ${colors.green(inputPath)}`
|
|
892
|
+
));
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
throw new Error(i18nText(
|
|
896
|
+
"\u652F\u6301\u7684 config \u5B50\u547D\u4EE4\uFF1Alang | set-lang | show | get | set | unset | doctor | import | export",
|
|
897
|
+
"Supported config subcommands: lang | set-lang | show | get | set | unset | doctor | import | export"
|
|
898
|
+
));
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// src/utils/argv.ts
|
|
902
|
+
import process4 from "process";
|
|
903
|
+
function ensurePathArgument(argv, optionIndex) {
|
|
904
|
+
const paramIdx = optionIndex + 1;
|
|
905
|
+
const param = argv[paramIdx];
|
|
906
|
+
if (param && !param.startsWith("-")) {
|
|
907
|
+
argv[paramIdx] = resolvePath(param);
|
|
908
|
+
} else {
|
|
909
|
+
argv.splice(paramIdx, 0, process4.cwd());
|
|
910
|
+
}
|
|
911
|
+
return argv;
|
|
912
|
+
}
|
|
913
|
+
function transformArgv(argv, transforms) {
|
|
914
|
+
return transforms.reduce((current, transform) => transform(current), [
|
|
915
|
+
...argv
|
|
916
|
+
]);
|
|
917
|
+
}
|
|
918
|
+
function createAlias(entry) {
|
|
919
|
+
return (input3) => {
|
|
920
|
+
const argv = [...input3];
|
|
921
|
+
let optionIndex = argv.indexOf(entry.find);
|
|
922
|
+
if (optionIndex > -1) {
|
|
923
|
+
argv.splice(optionIndex, 1, entry.replacement);
|
|
924
|
+
} else {
|
|
925
|
+
optionIndex = argv.indexOf(entry.replacement);
|
|
926
|
+
}
|
|
927
|
+
if (optionIndex === -1) {
|
|
928
|
+
return argv;
|
|
929
|
+
}
|
|
930
|
+
return ensurePathArgument(argv, optionIndex);
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function createPathCompat(option) {
|
|
934
|
+
return (input3) => {
|
|
935
|
+
const argv = [...input3];
|
|
936
|
+
const optionIndex = argv.indexOf(option);
|
|
937
|
+
if (optionIndex === -1) {
|
|
938
|
+
return argv;
|
|
939
|
+
}
|
|
940
|
+
return ensurePathArgument(argv, optionIndex);
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// src/utils/exec.ts
|
|
945
|
+
import process5 from "process";
|
|
946
|
+
async function execute(cliPath, argv, options = {}) {
|
|
947
|
+
const {
|
|
948
|
+
pipeStdout = true,
|
|
949
|
+
pipeStderr = true
|
|
950
|
+
} = options;
|
|
951
|
+
const { execa } = await import("execa");
|
|
952
|
+
const task = execa(cliPath, argv);
|
|
953
|
+
if (pipeStdout) {
|
|
954
|
+
task?.stdout?.pipe(process5.stdout);
|
|
955
|
+
}
|
|
956
|
+
if (pipeStderr) {
|
|
957
|
+
task?.stderr?.pipe(process5.stderr);
|
|
958
|
+
}
|
|
959
|
+
return await task;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/cli/minidev.ts
|
|
963
|
+
var MINIDEV_COMMAND = "minidev";
|
|
964
|
+
function isCommandNotFound(error) {
|
|
965
|
+
return Boolean(
|
|
966
|
+
error && typeof error === "object" && "code" in error && error.code === "ENOENT"
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
async function runMinidev(argv) {
|
|
970
|
+
try {
|
|
971
|
+
await execute(MINIDEV_COMMAND, [...argv]);
|
|
972
|
+
} catch (error) {
|
|
973
|
+
if (isCommandNotFound(error)) {
|
|
974
|
+
logger_default.error("\u672A\u68C0\u6D4B\u5230\u652F\u4ED8\u5B9D\u5C0F\u7A0B\u5E8F CLI\uFF1Aminidev");
|
|
975
|
+
logger_default.warn("\u8BF7\u5148\u5B89\u88C5 minidev\uFF0C\u53EF\u4F7F\u7528\u4EE5\u4E0B\u4EFB\u4E00\u547D\u4EE4\uFF1A");
|
|
976
|
+
logger_default.info(`- ${colors.green("pnpm add -g minidev")}`);
|
|
977
|
+
logger_default.info(`- ${colors.green("npm install -g minidev")}`);
|
|
978
|
+
logger_default.info(`- ${colors.green("yarn global add minidev")}`);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
throw error;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/cli/retry.ts
|
|
986
|
+
import process6 from "process";
|
|
987
|
+
import { emitKeypressEvents } from "readline";
|
|
988
|
+
var LOGIN_REQUIRED_PATTERNS = [
|
|
989
|
+
/code\s*[:=]\s*10/i,
|
|
990
|
+
/需要重新登录/,
|
|
991
|
+
/need\s+re-?login/i,
|
|
992
|
+
/re-?login/i
|
|
993
|
+
];
|
|
994
|
+
function isWechatIdeLoginRequiredError(error) {
|
|
995
|
+
const text = extractExecutionErrorText(error);
|
|
996
|
+
if (!text) {
|
|
997
|
+
return false;
|
|
998
|
+
}
|
|
999
|
+
return LOGIN_REQUIRED_PATTERNS.some((pattern) => pattern.test(text));
|
|
1000
|
+
}
|
|
1001
|
+
function extractExecutionErrorText(error) {
|
|
1002
|
+
if (!error || typeof error !== "object") {
|
|
1003
|
+
return "";
|
|
1004
|
+
}
|
|
1005
|
+
const parts = [];
|
|
1006
|
+
const candidate = error;
|
|
1007
|
+
for (const field of [candidate.message, candidate.shortMessage, candidate.stderr, candidate.stdout]) {
|
|
1008
|
+
if (typeof field === "string" && field.trim()) {
|
|
1009
|
+
parts.push(field);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return parts.join("\n");
|
|
1013
|
+
}
|
|
1014
|
+
function formatWechatIdeLoginRequiredError(error) {
|
|
1015
|
+
const text = extractExecutionErrorText(error);
|
|
1016
|
+
const code = text.match(/code\s*[:=]\s*(\d+)/i)?.[1];
|
|
1017
|
+
const message = extractLoginRequiredMessage(text);
|
|
1018
|
+
const lines = ["\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u8FD4\u56DE\u767B\u5F55\u9519\u8BEF\uFF1A"];
|
|
1019
|
+
if (code) {
|
|
1020
|
+
lines.push(`- code: ${code}`);
|
|
1021
|
+
}
|
|
1022
|
+
if (message) {
|
|
1023
|
+
lines.push(`- message: ${message}`);
|
|
1024
|
+
}
|
|
1025
|
+
if (!code && !message) {
|
|
1026
|
+
lines.push("- message: \u9700\u8981\u91CD\u65B0\u767B\u5F55");
|
|
1027
|
+
}
|
|
1028
|
+
return lines.join("\n");
|
|
1029
|
+
}
|
|
1030
|
+
function createWechatIdeLoginRequiredExitError(error, reason) {
|
|
1031
|
+
const summary = formatWechatIdeLoginRequiredError(error);
|
|
1032
|
+
const message = reason ? `${reason}
|
|
1033
|
+
${summary}` : summary;
|
|
1034
|
+
const loginError = new Error(message);
|
|
1035
|
+
loginError.name = "WechatIdeLoginRequiredError";
|
|
1036
|
+
loginError.code = 10;
|
|
1037
|
+
loginError.exitCode = 10;
|
|
1038
|
+
return loginError;
|
|
1039
|
+
}
|
|
1040
|
+
function extractLoginRequiredMessage(text) {
|
|
1041
|
+
if (!text) {
|
|
1042
|
+
return "";
|
|
1043
|
+
}
|
|
1044
|
+
if (/需要重新登录/.test(text)) {
|
|
1045
|
+
return "\u9700\u8981\u91CD\u65B0\u767B\u5F55";
|
|
1046
|
+
}
|
|
1047
|
+
const englishMatch = text.match(/need\s+re-?login|re-?login/i);
|
|
1048
|
+
if (englishMatch?.[0]) {
|
|
1049
|
+
return englishMatch[0].toLowerCase();
|
|
1050
|
+
}
|
|
1051
|
+
const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find((line) => Boolean(line) && !line.startsWith("at "));
|
|
1052
|
+
if (!firstLine) {
|
|
1053
|
+
return "";
|
|
1054
|
+
}
|
|
1055
|
+
return firstLine.replace(/^\[error\]\s*/i, "").replace(/^error\s*:\s*/i, "").slice(0, 120);
|
|
1056
|
+
}
|
|
1057
|
+
async function waitForRetryKeypress(options = {}) {
|
|
1058
|
+
const { timeoutMs = 3e4 } = options;
|
|
1059
|
+
if (!process6.stdin.isTTY) {
|
|
1060
|
+
return "cancel";
|
|
1061
|
+
}
|
|
1062
|
+
emitKeypressEvents(process6.stdin);
|
|
1063
|
+
const hasSetRawMode = typeof process6.stdin.setRawMode === "function";
|
|
1064
|
+
if (hasSetRawMode) {
|
|
1065
|
+
process6.stdin.setRawMode(true);
|
|
1066
|
+
}
|
|
1067
|
+
process6.stdin.resume();
|
|
1068
|
+
return new Promise((resolve) => {
|
|
1069
|
+
let settled = false;
|
|
1070
|
+
const normalizedTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e4;
|
|
1071
|
+
const timeout = setTimeout(() => {
|
|
1072
|
+
done("timeout");
|
|
1073
|
+
}, normalizedTimeoutMs);
|
|
1074
|
+
const cleanup = () => {
|
|
1075
|
+
clearTimeout(timeout);
|
|
1076
|
+
process6.stdin.off("keypress", onKeypress);
|
|
1077
|
+
if (hasSetRawMode) {
|
|
1078
|
+
process6.stdin.setRawMode(false);
|
|
1079
|
+
}
|
|
1080
|
+
process6.stdin.pause();
|
|
1081
|
+
};
|
|
1082
|
+
const done = (value) => {
|
|
1083
|
+
if (settled) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
settled = true;
|
|
1087
|
+
cleanup();
|
|
1088
|
+
resolve(value);
|
|
1089
|
+
};
|
|
1090
|
+
const onKeypress = (_str, key) => {
|
|
1091
|
+
if (!key) {
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
if (key.ctrl && key.name === "c") {
|
|
1095
|
+
done("cancel");
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
if (key.name === "r") {
|
|
1099
|
+
done("retry");
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
if (key.name === "q" || key.name === "escape") {
|
|
1103
|
+
done("cancel");
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
process6.stdin.on("keypress", onKeypress);
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
function formatRetryHotkeyPrompt(timeoutMs = 3e4) {
|
|
1110
|
+
const highlight = (key) => highlightHotkey(key);
|
|
1111
|
+
const timeoutSeconds = Math.max(1, Math.ceil(timeoutMs / 1e3));
|
|
1112
|
+
return i18nText(
|
|
1113
|
+
`\u6309 ${highlight("r")} \u91CD\u8BD5\uFF0C\u6309 ${highlight("q")} / ${highlight("Esc")} / ${highlight("Ctrl+C")} \u9000\u51FA\uFF08${timeoutSeconds}s \u5185\u65E0\u8F93\u5165\u5C06\u81EA\u52A8\u5931\u8D25\uFF09\u3002`,
|
|
1114
|
+
`Press ${highlight("r")} to retry, ${highlight("q")} / ${highlight("Esc")} / ${highlight("Ctrl+C")} to cancel (auto fail in ${timeoutSeconds}s).`
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
function highlightHotkey(key) {
|
|
1118
|
+
return colors.bold(colors.green(key));
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// src/cli/run-login.ts
|
|
1122
|
+
import process7 from "process";
|
|
1123
|
+
async function runWechatCliWithRetry(cliPath, argv) {
|
|
1124
|
+
const loginRetryOptions = resolveLoginRetryOptions(argv);
|
|
1125
|
+
const runtimeArgv = stripLoginRetryControlFlags(argv);
|
|
1126
|
+
let retryCount = 0;
|
|
1127
|
+
while (true) {
|
|
1128
|
+
try {
|
|
1129
|
+
const result = await execute(cliPath, runtimeArgv, {
|
|
1130
|
+
pipeStdout: false,
|
|
1131
|
+
pipeStderr: false
|
|
1132
|
+
});
|
|
1133
|
+
if (!isWechatIdeLoginRequiredError(result)) {
|
|
1134
|
+
flushExecutionOutput(result);
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
const action = await promptLoginRetry(result, loginRetryOptions, retryCount);
|
|
1138
|
+
if (action === "retry") {
|
|
1139
|
+
retryCount += 1;
|
|
1140
|
+
logger_default.info(i18nText("\u6B63\u5728\u91CD\u8BD5\u8FDE\u63A5\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177...", "Retrying to connect Wechat DevTools..."));
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
throw createWechatIdeLoginRequiredExitError(result);
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
if (!isWechatIdeLoginRequiredError(error)) {
|
|
1146
|
+
throw error;
|
|
1147
|
+
}
|
|
1148
|
+
const action = await promptLoginRetry(error, loginRetryOptions, retryCount);
|
|
1149
|
+
if (action === "retry") {
|
|
1150
|
+
retryCount += 1;
|
|
1151
|
+
logger_default.info(i18nText("\u6B63\u5728\u91CD\u8BD5\u8FDE\u63A5\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177...", "Retrying to connect Wechat DevTools..."));
|
|
1152
|
+
continue;
|
|
1153
|
+
}
|
|
1154
|
+
throw createWechatIdeLoginRequiredExitError(error);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
function resolveLoginRetryOptions(argv) {
|
|
1159
|
+
const nonInteractiveFlag = argv.includes("--non-interactive");
|
|
1160
|
+
const ciMode = process7.env.CI === "true";
|
|
1161
|
+
const nonTtyStdin = !isStdinInteractive();
|
|
1162
|
+
const nonInteractive = nonInteractiveFlag || ciMode || nonTtyStdin;
|
|
1163
|
+
const retryModeRaw = readOptionValue(argv, "--login-retry")?.toLowerCase();
|
|
1164
|
+
const retryMode = normalizeLoginRetryMode(retryModeRaw, nonInteractive);
|
|
1165
|
+
const retryTimeoutRaw = readOptionValue(argv, "--login-retry-timeout");
|
|
1166
|
+
const retryTimeoutMs = normalizeLoginRetryTimeout(retryTimeoutRaw);
|
|
1167
|
+
return {
|
|
1168
|
+
nonInteractive,
|
|
1169
|
+
retryMode,
|
|
1170
|
+
retryTimeoutMs
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
function normalizeLoginRetryMode(value, nonInteractive) {
|
|
1174
|
+
if (value && value !== "never" && value !== "once" && value !== "always") {
|
|
1175
|
+
throw new Error(i18nText(
|
|
1176
|
+
`\u4E0D\u652F\u6301\u7684 --login-retry \u503C: ${value}\uFF08\u4EC5\u652F\u6301 never/once/always\uFF09`,
|
|
1177
|
+
`Invalid --login-retry value: ${value} (supported: never/once/always)`
|
|
1178
|
+
));
|
|
1179
|
+
}
|
|
1180
|
+
if (value === "never" || value === "once" || value === "always") {
|
|
1181
|
+
return value;
|
|
1182
|
+
}
|
|
1183
|
+
return nonInteractive ? "never" : "always";
|
|
1184
|
+
}
|
|
1185
|
+
function normalizeLoginRetryTimeout(value) {
|
|
1186
|
+
if (!value) {
|
|
1187
|
+
return 3e4;
|
|
1188
|
+
}
|
|
1189
|
+
const parsed = Number.parseInt(value, 10);
|
|
1190
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
1191
|
+
throw new Error(i18nText(
|
|
1192
|
+
`\u65E0\u6548\u7684 --login-retry-timeout \u503C: ${value}\uFF08\u5FC5\u987B\u4E3A\u6B63\u6574\u6570\uFF09`,
|
|
1193
|
+
`Invalid --login-retry-timeout value: ${value} (must be a positive integer)`
|
|
1194
|
+
));
|
|
1195
|
+
}
|
|
1196
|
+
return parsed;
|
|
1197
|
+
}
|
|
1198
|
+
function isStdinInteractive() {
|
|
1199
|
+
return Boolean(process7.stdin && process7.stdin.isTTY);
|
|
1200
|
+
}
|
|
1201
|
+
function stripLoginRetryControlFlags(argv) {
|
|
1202
|
+
let next = removeOption(argv, "--login-retry");
|
|
1203
|
+
next = removeOption(next, "--login-retry-timeout");
|
|
1204
|
+
next = removeOption(next, "--non-interactive");
|
|
1205
|
+
return next;
|
|
1206
|
+
}
|
|
1207
|
+
async function promptLoginRetry(errorLike, options, retryCount) {
|
|
1208
|
+
const { nonInteractive, retryMode, retryTimeoutMs } = options;
|
|
1209
|
+
logger_default.error(i18nText(
|
|
1210
|
+
"\u68C0\u6D4B\u5230\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u767B\u5F55\u72B6\u6001\u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u540E\u91CD\u8BD5\u3002",
|
|
1211
|
+
"Wechat DevTools login has expired. Please login and retry."
|
|
1212
|
+
));
|
|
1213
|
+
logger_default.warn(i18nText(
|
|
1214
|
+
"\u8BF7\u5148\u6253\u5F00\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u5B8C\u6210\u767B\u5F55\u3002",
|
|
1215
|
+
"Please open Wechat DevTools and complete login first."
|
|
1216
|
+
));
|
|
1217
|
+
logger_default.warn(formatWechatIdeLoginRequiredError(errorLike));
|
|
1218
|
+
if (nonInteractive) {
|
|
1219
|
+
logger_default.error(i18nText(
|
|
1220
|
+
"\u5F53\u524D\u4E3A\u975E\u4EA4\u4E92\u6A21\u5F0F\uFF0C\u68C0\u6D4B\u5230\u767B\u5F55\u5931\u6548\u540E\u76F4\u63A5\u5931\u8D25\u3002",
|
|
1221
|
+
"Non-interactive mode enabled, failing immediately on login expiration."
|
|
1222
|
+
));
|
|
1223
|
+
return "cancel";
|
|
1224
|
+
}
|
|
1225
|
+
const shouldAllowRetry = retryMode === "always" || retryMode === "once" && retryCount < 1;
|
|
1226
|
+
if (!shouldAllowRetry) {
|
|
1227
|
+
logger_default.info(i18nText("\u5F53\u524D\u91CD\u8BD5\u7B56\u7565\u4E0D\u5141\u8BB8\u7EE7\u7EED\u91CD\u8BD5\u3002", "Current retry policy does not allow further retries."));
|
|
1228
|
+
return "cancel";
|
|
1229
|
+
}
|
|
1230
|
+
logger_default.info(formatRetryHotkeyPrompt(retryTimeoutMs));
|
|
1231
|
+
const action = await waitForRetryKeypress({ timeoutMs: retryTimeoutMs });
|
|
1232
|
+
if (action === "timeout") {
|
|
1233
|
+
logger_default.error(i18nText(
|
|
1234
|
+
`\u7B49\u5F85\u767B\u5F55\u91CD\u8BD5\u8F93\u5165\u8D85\u65F6\uFF08${retryTimeoutMs}ms\uFF09\uFF0C\u5DF2\u81EA\u52A8\u53D6\u6D88\u3002`,
|
|
1235
|
+
`Retry prompt timed out (${retryTimeoutMs}ms), canceled automatically.`
|
|
1236
|
+
));
|
|
1237
|
+
return "cancel";
|
|
1238
|
+
}
|
|
1239
|
+
if (action !== "retry") {
|
|
1240
|
+
logger_default.info(i18nText(
|
|
1241
|
+
"\u5DF2\u53D6\u6D88\u91CD\u8BD5\u3002\u5B8C\u6210\u767B\u5F55\u540E\u8BF7\u91CD\u65B0\u6267\u884C\u5F53\u524D\u547D\u4EE4\u3002",
|
|
1242
|
+
"Retry canceled. Please run the command again after login."
|
|
1243
|
+
));
|
|
1244
|
+
return "cancel";
|
|
1245
|
+
}
|
|
1246
|
+
return "retry";
|
|
1247
|
+
}
|
|
1248
|
+
function flushExecutionOutput(result) {
|
|
1249
|
+
if (!result || typeof result !== "object") {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
const candidate = result;
|
|
1253
|
+
if (typeof candidate.stdout === "string" && candidate.stdout) {
|
|
1254
|
+
process7.stdout.write(candidate.stdout);
|
|
1255
|
+
}
|
|
1256
|
+
if (typeof candidate.stderr === "string" && candidate.stderr) {
|
|
1257
|
+
process7.stderr.write(candidate.stderr);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/cli/wechat-command-schema.ts
|
|
1262
|
+
function validateWechatCliCommandArgs(argv) {
|
|
1263
|
+
const command = argv[0];
|
|
1264
|
+
if (!command) {
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
validatePortOption(argv);
|
|
1268
|
+
validateExtAppidDependency(argv);
|
|
1269
|
+
if (command === "upload") {
|
|
1270
|
+
const version = readOptionValue(argv, "--version") || readOptionValue(argv, "-v");
|
|
1271
|
+
const desc = readOptionValue(argv, "--desc") || readOptionValue(argv, "-d");
|
|
1272
|
+
if (!isNonEmptyText(version) || !isNonEmptyText(desc)) {
|
|
1273
|
+
throw new Error(i18nText(
|
|
1274
|
+
"upload \u547D\u4EE4\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570\uFF1A--version/-v \u548C --desc/-d",
|
|
1275
|
+
"upload command requires both --version/-v and --desc/-d"
|
|
1276
|
+
));
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
if (command === "preview") {
|
|
1280
|
+
validateProjectLocator(command, argv);
|
|
1281
|
+
const qrFormat = readOptionValue(argv, "--qr-format") || readOptionValue(argv, "-f");
|
|
1282
|
+
if (!qrFormat) {
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
if (!["terminal", "image", "base64"].includes(qrFormat.toLowerCase())) {
|
|
1286
|
+
throw new Error(i18nText(
|
|
1287
|
+
`preview \u547D\u4EE4\u7684\u4E8C\u7EF4\u7801\u683C\u5F0F\u65E0\u6548: ${qrFormat}\uFF08\u4EC5\u652F\u6301 terminal/image/base64\uFF09`,
|
|
1288
|
+
`Invalid preview qr format: ${qrFormat} (supported: terminal/image/base64)`
|
|
1289
|
+
));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
if (command === "upload" || command === "auto" || command === "auto-preview") {
|
|
1293
|
+
validateProjectLocator(command, argv);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function validatePortOption(argv) {
|
|
1297
|
+
const port = readOptionValue(argv, "--port");
|
|
1298
|
+
if (!port) {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
const parsed = Number.parseInt(port, 10);
|
|
1302
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
1303
|
+
throw new Error(i18nText(
|
|
1304
|
+
`\u65E0\u6548\u7684 --port \u503C: ${port}\uFF08\u5FC5\u987B\u4E3A\u6B63\u6574\u6570\uFF09`,
|
|
1305
|
+
`Invalid --port value: ${port} (must be a positive integer)`
|
|
1306
|
+
));
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
function validateProjectLocator(command, argv) {
|
|
1310
|
+
const projectPath = readOptionValue(argv, "--project");
|
|
1311
|
+
const appid = readOptionValue(argv, "--appid");
|
|
1312
|
+
if (isNonEmptyText(projectPath) || isNonEmptyText(appid)) {
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
throw new Error(i18nText(
|
|
1316
|
+
`${command} \u547D\u4EE4\u9700\u8981\u63D0\u4F9B --project \u6216 --appid`,
|
|
1317
|
+
`${command} command requires --project or --appid`
|
|
1318
|
+
));
|
|
1319
|
+
}
|
|
1320
|
+
function validateExtAppidDependency(argv) {
|
|
1321
|
+
const extAppid = readOptionValue(argv, "--ext-appid");
|
|
1322
|
+
if (!isNonEmptyText(extAppid)) {
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
const projectPath = readOptionValue(argv, "--project");
|
|
1326
|
+
if (isNonEmptyText(projectPath)) {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
const appid = readOptionValue(argv, "--appid");
|
|
1330
|
+
if (isNonEmptyText(appid)) {
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
throw new Error(i18nText(
|
|
1334
|
+
"--ext-appid \u9700\u8981\u548C --appid \u4E00\u8D77\u4F7F\u7528\uFF08\u5F53\u672A\u63D0\u4F9B --project \u65F6\uFF09",
|
|
1335
|
+
"--ext-appid requires --appid when --project is not provided"
|
|
1336
|
+
));
|
|
1337
|
+
}
|
|
1338
|
+
function isNonEmptyText(value) {
|
|
1339
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// src/cli/run.ts
|
|
1343
|
+
var MINIDEV_NAMESPACE = /* @__PURE__ */ new Set(["alipay", "ali", "minidev"]);
|
|
1344
|
+
var ALIPAY_PLATFORM_ALIASES = /* @__PURE__ */ new Set(["alipay", "ali", "minidev"]);
|
|
1345
|
+
var ARG_TRANSFORMS = [
|
|
1346
|
+
createAlias({ find: "-p", replacement: "--project" }),
|
|
1347
|
+
createPathCompat("--result-output"),
|
|
1348
|
+
createPathCompat("-r"),
|
|
1349
|
+
createPathCompat("--qr-output"),
|
|
1350
|
+
createPathCompat("-o"),
|
|
1351
|
+
createPathCompat("--info-output"),
|
|
1352
|
+
createPathCompat("-i")
|
|
1353
|
+
];
|
|
1354
|
+
async function parse(argv) {
|
|
1355
|
+
validateLocaleOption(argv);
|
|
1356
|
+
const configuredLocale = await getConfiguredLocale();
|
|
1357
|
+
configureLocaleFromArgv(argv, configuredLocale);
|
|
1358
|
+
const command = argv[0];
|
|
1359
|
+
if (command && MINIDEV_NAMESPACE.has(command)) {
|
|
1360
|
+
await runMinidev(argv.slice(1));
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (command && isAutomatorCommand(command)) {
|
|
1364
|
+
await runAutomatorCommand(command, argv.slice(1));
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
if (command === "help") {
|
|
1368
|
+
const targetCommand = argv[1];
|
|
1369
|
+
if (targetCommand === "screenshot") {
|
|
1370
|
+
printScreenshotHelp();
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
if (isAutomatorCommand(targetCommand)) {
|
|
1374
|
+
await runAutomatorCommand(targetCommand, ["--help"]);
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const formattedArgv = transformArgv(argv, ARG_TRANSFORMS);
|
|
1379
|
+
if (shouldDelegateOpenToMinidev(formattedArgv)) {
|
|
1380
|
+
await runMinidev(createMinidevOpenArgv(formattedArgv));
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
if (command === "config") {
|
|
1384
|
+
await handleConfigCommand(argv.slice(1));
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
if (!isOperatingSystemSupported(operatingSystemName)) {
|
|
1388
|
+
logger_default.warn(i18nText(
|
|
1389
|
+
`\u5FAE\u4FE1web\u5F00\u53D1\u8005\u5DE5\u5177\u4E0D\u652F\u6301\u5F53\u524D\u5E73\u53F0\uFF1A${operatingSystemName} !`,
|
|
1390
|
+
`Wechat Web DevTools CLI is not supported on current platform: ${operatingSystemName}!`
|
|
1391
|
+
));
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
validateWechatCliCommandArgs(formattedArgv);
|
|
1395
|
+
const { cliPath, source } = await resolveCliPath();
|
|
1396
|
+
if (!cliPath) {
|
|
1397
|
+
const message = source === "custom" ? i18nText(
|
|
1398
|
+
"\u5728\u5F53\u524D\u81EA\u5B9A\u4E49\u8DEF\u5F84\u4E2D\u672A\u627E\u5230\u5FAE\u4FE1web\u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u91CD\u65B0\u6307\u5B9A\u8DEF\u5F84\u3002",
|
|
1399
|
+
"Cannot find Wechat Web DevTools CLI in custom path, please reconfigure it."
|
|
1400
|
+
) : i18nText(
|
|
1401
|
+
`\u672A\u68C0\u6D4B\u5230\u5FAE\u4FE1web\u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u6267\u884C ${colors.bold(colors.green("weapp-ide-cli config"))} \u6307\u5B9A\u8DEF\u5F84\u3002`,
|
|
1402
|
+
`Wechat Web DevTools CLI not found, please run ${colors.bold(colors.green("weapp-ide-cli config"))} to configure it.`
|
|
1403
|
+
);
|
|
1404
|
+
logger_default.warn(message);
|
|
1405
|
+
await promptForCliPath();
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
await runWechatCliWithRetry(cliPath, formattedArgv);
|
|
1409
|
+
}
|
|
1410
|
+
function shouldDelegateOpenToMinidev(argv) {
|
|
1411
|
+
if (argv[0] !== "open") {
|
|
1412
|
+
return false;
|
|
1413
|
+
}
|
|
1414
|
+
const platform = readOptionValue(argv, "--platform");
|
|
1415
|
+
if (!platform) {
|
|
1416
|
+
return false;
|
|
1417
|
+
}
|
|
1418
|
+
return ALIPAY_PLATFORM_ALIASES.has(platform.toLowerCase());
|
|
1419
|
+
}
|
|
1420
|
+
function createMinidevOpenArgv(argv) {
|
|
1421
|
+
const nextArgv = [...argv];
|
|
1422
|
+
nextArgv[0] = "ide";
|
|
1423
|
+
return removeOption(nextArgv, "--platform");
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
export {
|
|
1427
|
+
parseAutomatorArgs,
|
|
1428
|
+
readOptionValue,
|
|
1429
|
+
removeOption,
|
|
1430
|
+
printScreenshotHelp,
|
|
1431
|
+
parseScreenshotArgs,
|
|
1432
|
+
AUTOMATOR_COMMAND_NAMES,
|
|
1433
|
+
isAutomatorCommand,
|
|
1434
|
+
runAutomatorCommand,
|
|
1435
|
+
getAutomatorCommandHelp,
|
|
1436
|
+
WECHAT_CLI_COMMAND_NAMES,
|
|
1437
|
+
MINIDEV_NAMESPACE_COMMAND_NAMES,
|
|
1438
|
+
CONFIG_COMMAND_NAME,
|
|
1439
|
+
WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES,
|
|
1440
|
+
isWeappIdeTopLevelCommand,
|
|
1441
|
+
resolvePath,
|
|
1442
|
+
defaultCustomConfigDirPath,
|
|
1443
|
+
defaultCustomConfigFilePath,
|
|
1444
|
+
createCustomConfig,
|
|
1445
|
+
createLocaleConfig,
|
|
1446
|
+
removeCustomConfigKey,
|
|
1447
|
+
overwriteCustomConfig,
|
|
1448
|
+
readCustomConfig,
|
|
1449
|
+
promptForCliPath,
|
|
1450
|
+
SupportedPlatformsMap,
|
|
1451
|
+
isOperatingSystemSupported,
|
|
1452
|
+
operatingSystemName,
|
|
1453
|
+
getDefaultCliPath,
|
|
1454
|
+
getConfig,
|
|
1455
|
+
getConfiguredLocale,
|
|
1456
|
+
resolveCliPath,
|
|
1457
|
+
handleConfigCommand,
|
|
1458
|
+
transformArgv,
|
|
1459
|
+
createAlias,
|
|
1460
|
+
createPathCompat,
|
|
1461
|
+
execute,
|
|
1462
|
+
runMinidev,
|
|
1463
|
+
isWechatIdeLoginRequiredError,
|
|
1464
|
+
extractExecutionErrorText,
|
|
1465
|
+
formatWechatIdeLoginRequiredError,
|
|
1466
|
+
createWechatIdeLoginRequiredExitError,
|
|
1467
|
+
waitForRetryKeypress,
|
|
1468
|
+
formatRetryHotkeyPrompt,
|
|
1469
|
+
runWechatCliWithRetry,
|
|
1470
|
+
validateWechatCliCommandArgs,
|
|
1471
|
+
parse
|
|
1472
|
+
};
|