ms-vite-plugin 1.4.47 → 1.4.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.js +1 -292
- package/dist/cli.js +6 -1234
- package/dist/mcp/device-config.d.ts +0 -47
- package/dist/mcp/device-config.js +1 -183
- package/dist/mcp/device-log.d.ts +0 -8
- package/dist/mcp/device-log.js +3 -27
- package/dist/mcp/doc-tools.d.ts +0 -7
- package/dist/mcp/doc-tools.js +2 -39
- package/dist/mcp/docs-service.d.ts +0 -13
- package/dist/mcp/docs-service.js +1 -63
- package/dist/mcp/httpapi-docs-service.d.ts +0 -31
- package/dist/mcp/httpapi-docs-service.js +1 -122
- package/dist/mcp/httpapi-tools.d.ts +0 -7
- package/dist/mcp/httpapi-tools.js +4 -222
- package/dist/mcp/image-tools.d.ts +0 -62
- package/dist/mcp/image-tools.js +8 -607
- package/dist/mcp/ocr-tools.d.ts +0 -25
- package/dist/mcp/ocr-tools.js +5 -413
- package/dist/mcp/project.d.ts +0 -14
- package/dist/mcp/project.js +1 -74
- package/dist/mcp/runtime-tools.d.ts +0 -7
- package/dist/mcp/runtime-tools.js +11 -308
- package/dist/mcp/tool-utils.d.ts +0 -40
- package/dist/mcp/tool-utils.js +1 -81
- package/dist/mcp/tools.d.ts +0 -12
- package/dist/mcp/tools.js +1 -31
- package/dist/mcp/types.d.ts +0 -12
- package/dist/mcp/types.js +1 -11
- package/dist/mcp-server.js +1 -85
- package/dist/packager.d.ts +0 -7
- package/dist/packager.js +1 -125
- package/dist/project.d.ts +0 -61
- package/dist/project.js +1 -619
- package/dist/stopGuardPlugin.d.ts +0 -6
- package/dist/stopGuardPlugin.js +1 -165
- package/dist/version.d.ts +0 -10
- package/dist/version.js +1 -63
- package/dist/ws-manager.d.ts +0 -95
- package/dist/ws-manager.js +1 -392
- package/docs/api/image.md +249 -25
- package/docs/apicn/image.md +245 -19
- package/docs/apipython/image.md +238 -18
- package/package.json +3 -2
package/dist/project.js
CHANGED
|
@@ -1,619 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.getScreenshotOnDevice = getScreenshotOnDevice;
|
|
40
|
-
exports.getScreenshotBase64OnDevice = getScreenshotBase64OnDevice;
|
|
41
|
-
exports.getSourceOnDevice = getSourceOnDevice;
|
|
42
|
-
exports.getCurrentLogLinesOnDevice = getCurrentLogLinesOnDevice;
|
|
43
|
-
exports.runOnDevice = runOnDevice;
|
|
44
|
-
exports.runUIOnDevice = runUIOnDevice;
|
|
45
|
-
exports.stopOnDevice = stopOnDevice;
|
|
46
|
-
const fsExtra = __importStar(require("fs-extra"));
|
|
47
|
-
const path = __importStar(require("path"));
|
|
48
|
-
const build_1 = require("./build");
|
|
49
|
-
const crc_1 = __importDefault(require("crc"));
|
|
50
|
-
const ws_manager_1 = require("./ws-manager");
|
|
51
|
-
/**
|
|
52
|
-
* 读取并校验设备连接参数
|
|
53
|
-
* @param options 命令选项
|
|
54
|
-
* @returns 返回标准化后的设备地址信息
|
|
55
|
-
* @example
|
|
56
|
-
* parseHttpOptions({ ip: "192.168.1.10", port: "9800" })
|
|
57
|
-
*/
|
|
58
|
-
function parseHttpOptions(options) {
|
|
59
|
-
const ip = options.ip?.trim();
|
|
60
|
-
const portText = (options.port ?? "9800").trim();
|
|
61
|
-
const port = Number.parseInt(portText, 10);
|
|
62
|
-
if (!ip) {
|
|
63
|
-
throw new Error("请通过 --ip 指定设备 IP 地址");
|
|
64
|
-
}
|
|
65
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
66
|
-
throw new Error(`无效端口: ${portText}`);
|
|
67
|
-
}
|
|
68
|
-
return { ip, port };
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* 解析 WS 服务参数
|
|
72
|
-
* @param options 命令选项
|
|
73
|
-
* @returns 返回 wsPort 与等待设备连接超时时间
|
|
74
|
-
* @example
|
|
75
|
-
* parseWsOptions({ wsPort: "31111", wsWaitMs: "30000" })
|
|
76
|
-
*/
|
|
77
|
-
function parseWsOptions(options) {
|
|
78
|
-
const wsPortText = (options.wsPort ?? "31111").trim();
|
|
79
|
-
const wsWaitText = (options.wsWaitMs ?? "30000").trim();
|
|
80
|
-
const wsPort = Number.parseInt(wsPortText, 10);
|
|
81
|
-
const wsWaitMs = Number.parseInt(wsWaitText, 10);
|
|
82
|
-
if (!Number.isInteger(wsPort) || wsPort < 1 || wsPort > 65535) {
|
|
83
|
-
throw new Error(`无效 ws 端口: ${wsPortText}`);
|
|
84
|
-
}
|
|
85
|
-
if (!Number.isInteger(wsWaitMs) || wsWaitMs < 1) {
|
|
86
|
-
throw new Error(`无效 ws 等待时间: ${wsWaitText}`);
|
|
87
|
-
}
|
|
88
|
-
return { wsPort, wsWaitMs };
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* 解析传输方式
|
|
92
|
-
* @param options 命令选项
|
|
93
|
-
* @returns 返回 http 或 ws
|
|
94
|
-
* @example
|
|
95
|
-
* parseTransport({ transport: "ws" })
|
|
96
|
-
*/
|
|
97
|
-
function parseTransport(options) {
|
|
98
|
-
const transport = (options.transport ?? "http").trim().toLowerCase();
|
|
99
|
-
if (transport !== "http" && transport !== "ws") {
|
|
100
|
-
throw new Error(`无效 transport: ${transport}`);
|
|
101
|
-
}
|
|
102
|
-
return transport;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* 计算文件的 CRC32 值
|
|
106
|
-
* @param filePath 文件路径
|
|
107
|
-
* @returns CRC32 十六进制字符串(8位)
|
|
108
|
-
* @example
|
|
109
|
-
* await calculateCrc32("/tmp/a.txt")
|
|
110
|
-
*/
|
|
111
|
-
async function calculateCrc32(filePath) {
|
|
112
|
-
const fileBuffer = await fsExtra.readFile(filePath);
|
|
113
|
-
const crc32 = crc_1.default.crc32(fileBuffer);
|
|
114
|
-
return crc32.toString(16).padStart(8, "0");
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* 递归收集目录中的所有文件
|
|
118
|
-
* @param rootDir 需要遍历的根目录
|
|
119
|
-
* @param bundlePrefix 输出到设备时的目录前缀
|
|
120
|
-
* @returns 返回可同步文件列表(含 size 与 crc32)
|
|
121
|
-
* @example
|
|
122
|
-
* await collectFilesInDir("/tmp/project/ui", "ui")
|
|
123
|
-
*/
|
|
124
|
-
async function collectFilesInDir(rootDir, bundlePrefix) {
|
|
125
|
-
const files = [];
|
|
126
|
-
async function walk(dir) {
|
|
127
|
-
const entries = await fsExtra.readdir(dir, { withFileTypes: true });
|
|
128
|
-
for (const entry of entries) {
|
|
129
|
-
const fullPath = path.join(dir, entry.name);
|
|
130
|
-
if (entry.isDirectory()) {
|
|
131
|
-
await walk(fullPath);
|
|
132
|
-
}
|
|
133
|
-
else if (entry.isFile()) {
|
|
134
|
-
const relPath = path.relative(rootDir, fullPath).replace(/\\/g, "/");
|
|
135
|
-
const stat = await fsExtra.stat(fullPath);
|
|
136
|
-
files.push({
|
|
137
|
-
path: fullPath,
|
|
138
|
-
bundlePath: `${bundlePrefix}/${relPath}`,
|
|
139
|
-
size: stat.size,
|
|
140
|
-
crc32: await calculateCrc32(fullPath),
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (await fsExtra.pathExists(rootDir)) {
|
|
146
|
-
await walk(rootDir);
|
|
147
|
-
}
|
|
148
|
-
return files;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* 读取项目运行所需的元信息
|
|
152
|
-
* @param workspacePath 项目根目录
|
|
153
|
-
* @returns 返回 projectName、appVersion 与 packageJsonPath
|
|
154
|
-
* @example
|
|
155
|
-
* await getProjectMeta("/Users/demo/project")
|
|
156
|
-
*/
|
|
157
|
-
async function getProjectMeta(workspacePath) {
|
|
158
|
-
const packageJsonPath = path.join(workspacePath, "package.json");
|
|
159
|
-
const packageJson = await fsExtra.readJSON(packageJsonPath);
|
|
160
|
-
const projectName = packageJson.name;
|
|
161
|
-
const appVersion = packageJson.appVersion;
|
|
162
|
-
if (!projectName) {
|
|
163
|
-
throw new Error("请在 package.json 中添加 name 字段");
|
|
164
|
-
}
|
|
165
|
-
if (!appVersion) {
|
|
166
|
-
throw new Error("请在 package.json 中添加 appVersion 字段");
|
|
167
|
-
}
|
|
168
|
-
return { projectName, appVersion, packageJsonPath };
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* 收集运行前需要同步的文件
|
|
172
|
-
* @param workspacePath 项目根目录
|
|
173
|
-
* @returns 返回项目文件清单(含 size 与 crc32)
|
|
174
|
-
* @example
|
|
175
|
-
* await collectProjectFiles("/Users/demo/project")
|
|
176
|
-
*/
|
|
177
|
-
async function collectProjectFiles(workspacePath) {
|
|
178
|
-
let scriptPath = path.join(workspacePath, "dist", "scripts");
|
|
179
|
-
const isPy = await fsExtra.pathExists(path.join(workspacePath, "scripts", "main.py"));
|
|
180
|
-
if (isPy) {
|
|
181
|
-
scriptPath = path.join(workspacePath, "scripts");
|
|
182
|
-
}
|
|
183
|
-
const uiPath = path.join(workspacePath, "ui");
|
|
184
|
-
const resPath = path.join(workspacePath, "res");
|
|
185
|
-
const packageJsonPath = path.join(workspacePath, "package.json");
|
|
186
|
-
const files = [
|
|
187
|
-
{
|
|
188
|
-
path: packageJsonPath,
|
|
189
|
-
bundlePath: "package.json",
|
|
190
|
-
size: (await fsExtra.stat(packageJsonPath)).size,
|
|
191
|
-
crc32: await calculateCrc32(packageJsonPath),
|
|
192
|
-
},
|
|
193
|
-
];
|
|
194
|
-
const [scriptFiles, uiFiles, resFiles] = await Promise.all([
|
|
195
|
-
collectFilesInDir(scriptPath, "scripts"),
|
|
196
|
-
collectFilesInDir(uiPath, "ui"),
|
|
197
|
-
collectFilesInDir(resPath, "res"),
|
|
198
|
-
]);
|
|
199
|
-
files.push(...scriptFiles, ...uiFiles, ...resFiles);
|
|
200
|
-
return files;
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* 执行项目构建(使用 build.ts 的 dev 模式)
|
|
204
|
-
* @param workspacePath 项目根目录
|
|
205
|
-
* @returns 构建成功时返回 Promise<void>
|
|
206
|
-
* @example
|
|
207
|
-
* await runDevBuild("/Users/demo/project")
|
|
208
|
-
*/
|
|
209
|
-
async function runDevBuild(workspacePath) {
|
|
210
|
-
await (0, build_1.buildAll)(true, workspacePath);
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* 获取设备上的文件列表
|
|
214
|
-
* @param ip 设备 IP 地址
|
|
215
|
-
* @param port 设备端口
|
|
216
|
-
* @param projectName 项目名称
|
|
217
|
-
* @returns 设备当前文件信息列表
|
|
218
|
-
* @example
|
|
219
|
-
* await listDeviceFiles("192.168.1.10", 9800, "demo")
|
|
220
|
-
*/
|
|
221
|
-
async function listDeviceFiles(ip, port, projectName) {
|
|
222
|
-
const url = new URL(`http://${ip}:${port}/api/files`);
|
|
223
|
-
url.searchParams.set("projectName", projectName);
|
|
224
|
-
const response = await fetch(url.toString(), { method: "GET" });
|
|
225
|
-
if (!response.ok) {
|
|
226
|
-
throw new Error(`文件列表请求失败: ${response.statusText}`);
|
|
227
|
-
}
|
|
228
|
-
const data = (await response.json());
|
|
229
|
-
return Array.isArray(data) ? data : [];
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* 通过 WS 获取设备上的文件列表
|
|
233
|
-
* @param projectName 项目名称
|
|
234
|
-
* @returns 设备当前文件信息列表
|
|
235
|
-
* @example
|
|
236
|
-
* await listDeviceFilesByWs("demo")
|
|
237
|
-
*/
|
|
238
|
-
async function listDeviceFilesByWs(projectName) {
|
|
239
|
-
const result = await ws_manager_1.WSManager.request("files", { projectName });
|
|
240
|
-
if (!result.success) {
|
|
241
|
-
throw new Error(`文件列表请求失败: ${String(result.message ?? "unknown")}`);
|
|
242
|
-
}
|
|
243
|
-
const data = result.data;
|
|
244
|
-
return Array.isArray(data) ? data : [];
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* 将项目文件增量同步到设备
|
|
248
|
-
* @param workspacePath 项目根目录
|
|
249
|
-
* @param ip 设备 IP 地址
|
|
250
|
-
* @param port 设备端口
|
|
251
|
-
* @returns 同步完成后返回 Promise<void>
|
|
252
|
-
* @example
|
|
253
|
-
* await syncProjectToDevice("/Users/demo/project", "192.168.1.10", 9800)
|
|
254
|
-
*/
|
|
255
|
-
async function syncProjectToDevice(workspacePath, ip, port) {
|
|
256
|
-
const { projectName, appVersion } = await getProjectMeta(workspacePath);
|
|
257
|
-
console.log("🔎 正在获取设备文件列表...");
|
|
258
|
-
const deviceFiles = await listDeviceFiles(ip, port, projectName);
|
|
259
|
-
const deviceFileMap = new Map(deviceFiles.map((file) => [file.path, file]));
|
|
260
|
-
console.log("📂 正在分析项目文件...");
|
|
261
|
-
const files = await collectProjectFiles(workspacePath);
|
|
262
|
-
const filesToSync = [];
|
|
263
|
-
for (const file of files) {
|
|
264
|
-
const deviceFile = deviceFileMap.get(file.bundlePath);
|
|
265
|
-
const requireSyncFile = file.bundlePath.includes("main.js") ||
|
|
266
|
-
file.bundlePath.includes("main.py");
|
|
267
|
-
if (!deviceFile) {
|
|
268
|
-
filesToSync.push(file);
|
|
269
|
-
continue;
|
|
270
|
-
}
|
|
271
|
-
const changed = deviceFile.size !== file.size ||
|
|
272
|
-
deviceFile.crc32.toLowerCase() !== file.crc32.toLowerCase();
|
|
273
|
-
if (requireSyncFile || changed) {
|
|
274
|
-
filesToSync.push(file);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
console.log(`📦 发现 ${filesToSync.length} 个文件需要同步`);
|
|
278
|
-
if (filesToSync.length === 0) {
|
|
279
|
-
console.log("✅ 无需同步文件");
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
let syncedCount = 0;
|
|
283
|
-
for (const file of filesToSync) {
|
|
284
|
-
syncedCount += 1;
|
|
285
|
-
console.log(`⬆️ [${syncedCount}/${filesToSync.length}] 同步 ${file.bundlePath}`);
|
|
286
|
-
const binary = await fsExtra.readFile(file.path);
|
|
287
|
-
const url = new URL(`http://${ip}:${port}/debug/patchSync`);
|
|
288
|
-
url.searchParams.set("path", file.bundlePath);
|
|
289
|
-
url.searchParams.set("projectName", projectName);
|
|
290
|
-
url.searchParams.set("appVersion", appVersion);
|
|
291
|
-
const response = await fetch(url.toString(), {
|
|
292
|
-
method: "POST",
|
|
293
|
-
headers: {
|
|
294
|
-
"Content-Type": "application/octet-stream",
|
|
295
|
-
},
|
|
296
|
-
body: binary,
|
|
297
|
-
});
|
|
298
|
-
if (!response.ok) {
|
|
299
|
-
throw new Error(`同步失败: ${file.bundlePath} (状态码: ${response.status})`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
console.log(`✅ 同步完成,共 ${filesToSync.length} 个文件`);
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* 通过 WS 将项目文件增量同步到设备
|
|
306
|
-
* @param workspacePath 项目根目录
|
|
307
|
-
* @returns 同步完成后返回 Promise<void>
|
|
308
|
-
* @example
|
|
309
|
-
* await syncProjectToDeviceByWs("/Users/demo/project")
|
|
310
|
-
*/
|
|
311
|
-
async function syncProjectToDeviceByWs(workspacePath) {
|
|
312
|
-
const { projectName, appVersion } = await getProjectMeta(workspacePath);
|
|
313
|
-
console.log("🔎 正在获取设备文件列表...");
|
|
314
|
-
const deviceFiles = await listDeviceFilesByWs(projectName);
|
|
315
|
-
const deviceFileMap = new Map(deviceFiles.map((file) => [file.path, file]));
|
|
316
|
-
console.log("📂 正在分析项目文件...");
|
|
317
|
-
const files = await collectProjectFiles(workspacePath);
|
|
318
|
-
const filesToSync = [];
|
|
319
|
-
for (const file of files) {
|
|
320
|
-
const deviceFile = deviceFileMap.get(file.bundlePath);
|
|
321
|
-
const requireSyncFile = file.bundlePath.includes("main.js") ||
|
|
322
|
-
file.bundlePath.includes("main.py");
|
|
323
|
-
if (!deviceFile) {
|
|
324
|
-
filesToSync.push(file);
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
const changed = deviceFile.size !== file.size ||
|
|
328
|
-
deviceFile.crc32.toLowerCase() !== file.crc32.toLowerCase();
|
|
329
|
-
if (requireSyncFile || changed) {
|
|
330
|
-
filesToSync.push(file);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
console.log(`📦 发现 ${filesToSync.length} 个文件需要同步`);
|
|
334
|
-
if (filesToSync.length === 0) {
|
|
335
|
-
console.log("✅ 无需同步文件");
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
let syncedCount = 0;
|
|
339
|
-
for (const file of filesToSync) {
|
|
340
|
-
syncedCount += 1;
|
|
341
|
-
console.log(`⬆️ [${syncedCount}/${filesToSync.length}] 同步 ${file.bundlePath}`);
|
|
342
|
-
const binary = await fsExtra.readFile(file.path);
|
|
343
|
-
const result = await ws_manager_1.WSManager.request("patchSync", {
|
|
344
|
-
path: file.bundlePath,
|
|
345
|
-
data: binary.toString("base64"),
|
|
346
|
-
projectName,
|
|
347
|
-
appVersion,
|
|
348
|
-
});
|
|
349
|
-
if (!result.success) {
|
|
350
|
-
throw new Error(`同步失败: ${file.bundlePath} ${String(result.message ?? "")}`);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
console.log(`✅ 同步完成,共 ${filesToSync.length} 个文件`);
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* 发送设备动作请求
|
|
357
|
-
* @param action 动作名称,支持 run 与 stop
|
|
358
|
-
* @param ip 设备 IP 地址
|
|
359
|
-
* @param port 设备端口
|
|
360
|
-
* @returns 请求成功时返回 Promise<void>
|
|
361
|
-
* @example
|
|
362
|
-
* await requestDeviceAction("stop", "192.168.1.10", 9800)
|
|
363
|
-
*/
|
|
364
|
-
async function requestDeviceAction(action, ip, port) {
|
|
365
|
-
const url = `http://${ip}:${port}/api/${action}`;
|
|
366
|
-
const response = await fetch(url, { method: "GET" });
|
|
367
|
-
if (!response.ok) {
|
|
368
|
-
throw new Error(`${action} 失败,状态码: ${response.status}`);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* 在设备上获取截图 JPG 二进制数据(HTTP)
|
|
373
|
-
* @param options 命令选项(transport 仅支持 http)
|
|
374
|
-
* @returns 返回 JPG 二进制 Buffer
|
|
375
|
-
* @example
|
|
376
|
-
* const image = await getScreenshotOnDevice({ ip: "192.168.1.10", port: "9800" })
|
|
377
|
-
*/
|
|
378
|
-
async function getScreenshotOnDevice(options) {
|
|
379
|
-
const transport = parseTransport(options);
|
|
380
|
-
if (transport === "ws") {
|
|
381
|
-
await ensureWsReady(options);
|
|
382
|
-
const result = await ws_manager_1.WSManager.request("screenshot");
|
|
383
|
-
if (!result.success || typeof result.data !== "string") {
|
|
384
|
-
throw new Error(`截图失败: ${String(result.message ?? "unknown")}`);
|
|
385
|
-
}
|
|
386
|
-
return Buffer.from(result.data, "base64");
|
|
387
|
-
}
|
|
388
|
-
const { ip, port } = parseHttpOptions(options);
|
|
389
|
-
const url = `http://${ip}:${port}/api/screenshot`;
|
|
390
|
-
const response = await fetch(url, { method: "GET" });
|
|
391
|
-
if (!response.ok) {
|
|
392
|
-
throw new Error(`截图失败,状态码: ${response.status}`);
|
|
393
|
-
}
|
|
394
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
395
|
-
return Buffer.from(arrayBuffer);
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* 在设备上获取截图 Base64(HTTP)
|
|
399
|
-
* @param options 命令选项(transport 仅支持 http)
|
|
400
|
-
* @returns 返回截图 base64 字符串
|
|
401
|
-
* @example
|
|
402
|
-
* const b64 = await getScreenshotBase64OnDevice({ ip: "192.168.1.10", port: "9800" })
|
|
403
|
-
*/
|
|
404
|
-
async function getScreenshotBase64OnDevice(options) {
|
|
405
|
-
const transport = parseTransport(options);
|
|
406
|
-
if (transport === "ws") {
|
|
407
|
-
await ensureWsReady(options);
|
|
408
|
-
const result = await ws_manager_1.WSManager.request("screenshot");
|
|
409
|
-
if (!result.success || typeof result.data !== "string") {
|
|
410
|
-
throw new Error(`截图(base64)失败: ${String(result.message ?? "unknown")}`);
|
|
411
|
-
}
|
|
412
|
-
return result.data;
|
|
413
|
-
}
|
|
414
|
-
const { ip, port } = parseHttpOptions(options);
|
|
415
|
-
const url = `http://${ip}:${port}/api/screenshotBase64`;
|
|
416
|
-
const response = await fetch(url, { method: "GET" });
|
|
417
|
-
if (!response.ok) {
|
|
418
|
-
throw new Error(`截图(base64)失败,状态码: ${response.status}`);
|
|
419
|
-
}
|
|
420
|
-
const payload = (await response.json());
|
|
421
|
-
if (!payload.success || typeof payload.data !== "string") {
|
|
422
|
-
throw new Error(`截图(base64)失败: ${String(payload.message ?? "unknown")}`);
|
|
423
|
-
}
|
|
424
|
-
return payload.data;
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* 在设备上获取节点 XML(HTTP)
|
|
428
|
-
* @param options 命令选项(transport 仅支持 http)
|
|
429
|
-
* @param maxDepth 节点最大深度,默认 50
|
|
430
|
-
* @param timeout 获取节点超时秒数,默认 120
|
|
431
|
-
* @param mode 节点抓取模式,支持 1、2、3,默认 1
|
|
432
|
-
* @returns 返回 XML 字符串
|
|
433
|
-
* @example
|
|
434
|
-
* const xml = await getSourceOnDevice({ ip: "192.168.1.10", port: "9800" }, 50, 120, 1)
|
|
435
|
-
*/
|
|
436
|
-
async function getSourceOnDevice(options, maxDepth = 50, timeout = 120, mode = 1) {
|
|
437
|
-
const transport = parseTransport(options);
|
|
438
|
-
if (!Number.isInteger(maxDepth) || maxDepth < 1) {
|
|
439
|
-
throw new Error(`无效 maxDepth: ${maxDepth}`);
|
|
440
|
-
}
|
|
441
|
-
if (!Number.isInteger(timeout) || timeout < 1) {
|
|
442
|
-
throw new Error(`无效 timeout: ${timeout}`);
|
|
443
|
-
}
|
|
444
|
-
if (!Number.isInteger(mode) || (mode !== 1 && mode !== 2 && mode !== 3)) {
|
|
445
|
-
throw new Error(`无效 mode: ${mode}`);
|
|
446
|
-
}
|
|
447
|
-
if (transport === "ws") {
|
|
448
|
-
await ensureWsReady(options);
|
|
449
|
-
const result = await ws_manager_1.WSManager.request("source", {
|
|
450
|
-
max_depth: maxDepth,
|
|
451
|
-
timeout,
|
|
452
|
-
maxDepth,
|
|
453
|
-
mode,
|
|
454
|
-
});
|
|
455
|
-
if (!result.success || typeof result.data !== "string") {
|
|
456
|
-
throw new Error(`获取节点失败: ${String(result.message ?? "unknown")}`);
|
|
457
|
-
}
|
|
458
|
-
return result.data;
|
|
459
|
-
}
|
|
460
|
-
const { ip, port } = parseHttpOptions(options);
|
|
461
|
-
const url = new URL(`http://${ip}:${port}/api/source`);
|
|
462
|
-
url.searchParams.set("max_depth", String(maxDepth));
|
|
463
|
-
url.searchParams.set("timeout", String(timeout));
|
|
464
|
-
url.searchParams.set("mode", String(mode));
|
|
465
|
-
const response = await fetch(url.toString(), { method: "GET" });
|
|
466
|
-
if (!response.ok) {
|
|
467
|
-
throw new Error(`获取节点失败,状态码: ${response.status}`);
|
|
468
|
-
}
|
|
469
|
-
return response.text();
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* 在设备上获取当前日志文件最新行
|
|
473
|
-
* @param options 命令选项(仅支持 http 传输)
|
|
474
|
-
* @param count 需要读取的最新日志行数,默认 200,最大 5000
|
|
475
|
-
* @returns 返回最新日志行和是否还有更早日志
|
|
476
|
-
* @example
|
|
477
|
-
* const result = await getCurrentLogLinesOnDevice({ ip: "192.168.1.10", port: "9800" }, 200)
|
|
478
|
-
*/
|
|
479
|
-
async function getCurrentLogLinesOnDevice(options, count = 200) {
|
|
480
|
-
const transport = parseTransport(options);
|
|
481
|
-
if (transport !== "http") {
|
|
482
|
-
throw new Error("获取日志失败: 当前日志行接口仅支持 http 传输");
|
|
483
|
-
}
|
|
484
|
-
if (!Number.isInteger(count) || count < 1 || count > 5000) {
|
|
485
|
-
throw new Error(`获取日志失败: 无效 count ${count}`);
|
|
486
|
-
}
|
|
487
|
-
const { ip, port } = parseHttpOptions(options);
|
|
488
|
-
const url = new URL(`http://${ip}:${port}/logger/current/lines`);
|
|
489
|
-
url.searchParams.set("count", String(count));
|
|
490
|
-
const response = await fetch(url.toString(), { method: "GET" });
|
|
491
|
-
if (response.status === 404) {
|
|
492
|
-
return {
|
|
493
|
-
lines: [],
|
|
494
|
-
hasMore: false,
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
if (!response.ok) {
|
|
498
|
-
throw new Error(`获取日志失败,状态码: ${response.status}`);
|
|
499
|
-
}
|
|
500
|
-
const payload = (await response.json());
|
|
501
|
-
return {
|
|
502
|
-
lines: Array.isArray(payload.lines)
|
|
503
|
-
? payload.lines.map((line) => String(line))
|
|
504
|
-
: [],
|
|
505
|
-
hasMore: payload.hasMore === true,
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* 通过 WS 发送设备动作请求
|
|
510
|
-
* @param action 动作名称,支持 run、runUI、stop
|
|
511
|
-
* @returns 请求成功时返回 Promise<void>
|
|
512
|
-
* @example
|
|
513
|
-
* await requestDeviceActionByWs("run")
|
|
514
|
-
*/
|
|
515
|
-
async function requestDeviceActionByWs(action) {
|
|
516
|
-
const result = await ws_manager_1.WSManager.request(action);
|
|
517
|
-
if (!result.success) {
|
|
518
|
-
throw new Error(`${action} 失败: ${String(result.message ?? "unknown")}`);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* 确保 WS 服务可用并已连接设备
|
|
523
|
-
* @param options 命令选项
|
|
524
|
-
* @returns 返回 Promise<void>
|
|
525
|
-
* @example
|
|
526
|
-
* await ensureWsReady({ wsPort: "31111", wsWaitMs: "30000" })
|
|
527
|
-
*/
|
|
528
|
-
async function ensureWsReady(options) {
|
|
529
|
-
const { wsPort, wsWaitMs } = parseWsOptions(options);
|
|
530
|
-
const ws = ws_manager_1.WSManager.get();
|
|
531
|
-
if (!ws.isStarted()) {
|
|
532
|
-
await ws.start(wsPort);
|
|
533
|
-
}
|
|
534
|
-
if (!ws_manager_1.WSManager.isConnected()) {
|
|
535
|
-
console.log("⌛ 等待设备通过 WS 连接...");
|
|
536
|
-
await ws.waitForClient(wsWaitMs);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* 在设备上运行项目(先同步后运行)
|
|
541
|
-
* @param options 命令选项
|
|
542
|
-
* @returns 执行完成后返回 Promise<void>
|
|
543
|
-
* @example
|
|
544
|
-
* await runOnDevice({ ip: "192.168.1.10", port: "9800", path: "./demo" })
|
|
545
|
-
*/
|
|
546
|
-
async function runOnDevice(options) {
|
|
547
|
-
const workspacePath = options.workspacePath
|
|
548
|
-
? path.resolve(options.workspacePath)
|
|
549
|
-
: process.cwd();
|
|
550
|
-
const transport = parseTransport(options);
|
|
551
|
-
console.log(`🔧 开始构建项目: ${workspacePath}`);
|
|
552
|
-
await runDevBuild(workspacePath);
|
|
553
|
-
if (transport === "ws") {
|
|
554
|
-
await ensureWsReady(options);
|
|
555
|
-
console.log("📦 开始通过 WS 同步项目到设备");
|
|
556
|
-
await syncProjectToDeviceByWs(workspacePath);
|
|
557
|
-
console.log("🚀 开始通过 WS 运行项目");
|
|
558
|
-
await requestDeviceActionByWs("run");
|
|
559
|
-
console.log("✅ 运行请求已发送");
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
const { ip, port } = parseHttpOptions(options);
|
|
563
|
-
console.log(`📦 开始同步项目到设备: ${ip}:${port}`);
|
|
564
|
-
await syncProjectToDevice(workspacePath, ip, port);
|
|
565
|
-
console.log(`🚀 开始运行项目: ${ip}:${port}`);
|
|
566
|
-
await requestDeviceAction("run", ip, port);
|
|
567
|
-
console.log("✅ 运行请求已发送");
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* 在设备上预览 UI(先同步后调用 runUI)
|
|
571
|
-
* @param options 命令选项
|
|
572
|
-
* @returns 执行完成后返回 Promise<void>
|
|
573
|
-
* @example
|
|
574
|
-
* await runUIOnDevice({ ip: "192.168.1.10", port: "9800", path: "./demo" })
|
|
575
|
-
*/
|
|
576
|
-
async function runUIOnDevice(options) {
|
|
577
|
-
const workspacePath = options.workspacePath
|
|
578
|
-
? path.resolve(options.workspacePath)
|
|
579
|
-
: process.cwd();
|
|
580
|
-
const transport = parseTransport(options);
|
|
581
|
-
console.log(`🔧 开始构建项目: ${workspacePath}`);
|
|
582
|
-
await runDevBuild(workspacePath);
|
|
583
|
-
if (transport === "ws") {
|
|
584
|
-
await ensureWsReady(options);
|
|
585
|
-
console.log("📦 开始通过 WS 同步项目到设备");
|
|
586
|
-
await syncProjectToDeviceByWs(workspacePath);
|
|
587
|
-
console.log("🖼️ 开始通过 WS 预览 UI");
|
|
588
|
-
await requestDeviceActionByWs("runUI");
|
|
589
|
-
console.log("✅ UI 预览请求已发送");
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
const { ip, port } = parseHttpOptions(options);
|
|
593
|
-
console.log(`📦 开始同步项目到设备: ${ip}:${port}`);
|
|
594
|
-
await syncProjectToDevice(workspacePath, ip, port);
|
|
595
|
-
console.log(`🖼️ 开始预览 UI: ${ip}:${port}`);
|
|
596
|
-
await requestDeviceAction("runUI", ip, port);
|
|
597
|
-
console.log("✅ UI 预览请求已发送");
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* 停止设备上的项目
|
|
601
|
-
* @param options 命令选项
|
|
602
|
-
* @returns 执行完成后返回 Promise<void>
|
|
603
|
-
* @example
|
|
604
|
-
* await stopOnDevice({ ip: "192.168.1.10", port: "9800" })
|
|
605
|
-
*/
|
|
606
|
-
async function stopOnDevice(options) {
|
|
607
|
-
const transport = parseTransport(options);
|
|
608
|
-
if (transport === "ws") {
|
|
609
|
-
await ensureWsReady(options);
|
|
610
|
-
console.log("🛑 开始通过 WS 停止项目");
|
|
611
|
-
await requestDeviceActionByWs("stop");
|
|
612
|
-
console.log("✅ 停止请求已发送");
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
const { ip, port } = parseHttpOptions(options);
|
|
616
|
-
console.log(`🛑 开始停止项目: ${ip}:${port}`);
|
|
617
|
-
await requestDeviceAction("stop", ip, port);
|
|
618
|
-
console.log("✅ 停止请求已发送");
|
|
619
|
-
}
|
|
1
|
+
"use strict";var D=exports&&exports.__createBinding||(Object.create?(function(t,e,r,n){n===void 0&&(n=r);var s=Object.getOwnPropertyDescriptor(e,r);(!s||("get"in s?!e.__esModule:s.writable||s.configurable))&&(s={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,n,s)}):(function(t,e,r,n){n===void 0&&(n=r),t[n]=e[r]})),F=exports&&exports.__setModuleDefault||(Object.create?(function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}):function(t,e){t.default=e}),v=exports&&exports.__importStar||(function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var n=[];for(var s in r)Object.prototype.hasOwnProperty.call(r,s)&&(n[n.length]=s);return n},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var n=t(e),s=0;s<n.length;s++)n[s]!=="default"&&D(r,e,n[s]);return F(r,e),r}})(),I=exports&&exports.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.getScreenshotOnDevice=L,exports.getScreenshotBase64OnDevice=U,exports.getSourceOnDevice=k,exports.getCurrentLogLinesOnDevice=A,exports.runOnDevice=z,exports.runUIOnDevice=G,exports.stopOnDevice=V;const f=v(require("fs-extra")),w=v(require("path")),T=require("./build"),N=I(require("crc")),h=require("./ws-manager");function g(t){const e=t.ip?.trim(),r=(t.port??"9800").trim(),n=Number.parseInt(r,10);if(!e)throw new Error("\u8BF7\u901A\u8FC7 --ip \u6307\u5B9A\u8BBE\u5907 IP \u5730\u5740");if(!Number.isInteger(n)||n<1||n>65535)throw new Error(`\u65E0\u6548\u7AEF\u53E3: ${r}`);return{ip:e,port:n}}function q(t){const e=(t.wsPort??"31111").trim(),r=(t.wsWaitMs??"30000").trim(),n=Number.parseInt(e,10),s=Number.parseInt(r,10);if(!Number.isInteger(n)||n<1||n>65535)throw new Error(`\u65E0\u6548 ws \u7AEF\u53E3: ${e}`);if(!Number.isInteger(s)||s<1)throw new Error(`\u65E0\u6548 ws \u7B49\u5F85\u65F6\u95F4: ${r}`);return{wsPort:n,wsWaitMs:s}}function d(t){const e=(t.transport??"http").trim().toLowerCase();if(e!=="http"&&e!=="ws")throw new Error(`\u65E0\u6548 transport: ${e}`);return e}async function j(t){const e=await f.readFile(t);return N.default.crc32(e).toString(16).padStart(8,"0")}async function b(t,e){const r=[];async function n(s){const i=await f.readdir(s,{withFileTypes:!0});for(const c of i){const o=w.join(s,c.name);if(c.isDirectory())await n(o);else if(c.isFile()){const a=w.relative(t,o).replace(/\\/g,"/"),l=await f.stat(o);r.push({path:o,bundlePath:`${e}/${a}`,size:l.size,crc32:await j(o)})}}}return await f.pathExists(t)&&await n(t),r}async function E(t){const e=w.join(t,"package.json"),r=await f.readJSON(e),n=r.name,s=r.appVersion;if(!n)throw new Error("\u8BF7\u5728 package.json \u4E2D\u6DFB\u52A0 name \u5B57\u6BB5");if(!s)throw new Error("\u8BF7\u5728 package.json \u4E2D\u6DFB\u52A0 appVersion \u5B57\u6BB5");return{projectName:n,appVersion:s,packageJsonPath:e}}async function _(t){let e=w.join(t,"dist","scripts");await f.pathExists(w.join(t,"scripts","main.py"))&&(e=w.join(t,"scripts"));const n=w.join(t,"ui"),s=w.join(t,"res"),i=w.join(t,"package.json"),c=[{path:i,bundlePath:"package.json",size:(await f.stat(i)).size,crc32:await j(i)}],[o,a,l]=await Promise.all([b(e,"scripts"),b(n,"ui"),b(s,"res")]);return c.push(...o,...a,...l),c}async function O(t){await(0,T.buildAll)(!0,t)}async function B(t,e,r){const n=new URL(`http://${t}:${e}/api/files`);n.searchParams.set("projectName",r);const s=await fetch(n.toString(),{method:"GET"});if(!s.ok)throw new Error(`\u6587\u4EF6\u5217\u8868\u8BF7\u6C42\u5931\u8D25: ${s.statusText}`);const i=await s.json();return Array.isArray(i)?i:[]}async function C(t){const e=await h.WSManager.request("files",{projectName:t});if(!e.success)throw new Error(`\u6587\u4EF6\u5217\u8868\u8BF7\u6C42\u5931\u8D25: ${String(e.message??"unknown")}`);const r=e.data;return Array.isArray(r)?r:[]}async function M(t,e,r){const{projectName:n,appVersion:s}=await E(t);console.log("\u{1F50E} \u6B63\u5728\u83B7\u53D6\u8BBE\u5907\u6587\u4EF6\u5217\u8868...");const i=await B(e,r,n),c=new Map(i.map(u=>[u.path,u]));console.log("\u{1F4C2} \u6B63\u5728\u5206\u6790\u9879\u76EE\u6587\u4EF6...");const o=await _(t),a=[];for(const u of o){const p=c.get(u.bundlePath),y=u.bundlePath.includes("main.js")||u.bundlePath.includes("main.py");if(!p){a.push(u);continue}const S=p.size!==u.size||p.crc32.toLowerCase()!==u.crc32.toLowerCase();(y||S)&&a.push(u)}if(console.log(`\u{1F4E6} \u53D1\u73B0 ${a.length} \u4E2A\u6587\u4EF6\u9700\u8981\u540C\u6B65`),a.length===0){console.log("\u2705 \u65E0\u9700\u540C\u6B65\u6587\u4EF6");return}let l=0;for(const u of a){l+=1,console.log(`\u2B06\uFE0F [${l}/${a.length}] \u540C\u6B65 ${u.bundlePath}`);const p=await f.readFile(u.path),y=new URL(`http://${e}:${r}/debug/patchSync`);y.searchParams.set("path",u.bundlePath),y.searchParams.set("projectName",n),y.searchParams.set("appVersion",s);const S=await fetch(y.toString(),{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:p});if(!S.ok)throw new Error(`\u540C\u6B65\u5931\u8D25: ${u.bundlePath} (\u72B6\u6001\u7801: ${S.status})`)}console.log(`\u2705 \u540C\u6B65\u5B8C\u6210\uFF0C\u5171 ${a.length} \u4E2A\u6587\u4EF6`)}async function W(t){const{projectName:e,appVersion:r}=await E(t);console.log("\u{1F50E} \u6B63\u5728\u83B7\u53D6\u8BBE\u5907\u6587\u4EF6\u5217\u8868...");const n=await C(e),s=new Map(n.map(a=>[a.path,a]));console.log("\u{1F4C2} \u6B63\u5728\u5206\u6790\u9879\u76EE\u6587\u4EF6...");const i=await _(t),c=[];for(const a of i){const l=s.get(a.bundlePath),u=a.bundlePath.includes("main.js")||a.bundlePath.includes("main.py");if(!l){c.push(a);continue}const p=l.size!==a.size||l.crc32.toLowerCase()!==a.crc32.toLowerCase();(u||p)&&c.push(a)}if(console.log(`\u{1F4E6} \u53D1\u73B0 ${c.length} \u4E2A\u6587\u4EF6\u9700\u8981\u540C\u6B65`),c.length===0){console.log("\u2705 \u65E0\u9700\u540C\u6B65\u6587\u4EF6");return}let o=0;for(const a of c){o+=1,console.log(`\u2B06\uFE0F [${o}/${c.length}] \u540C\u6B65 ${a.bundlePath}`);const l=await f.readFile(a.path),u=await h.WSManager.request("patchSync",{path:a.bundlePath,data:l.toString("base64"),projectName:e,appVersion:r});if(!u.success)throw new Error(`\u540C\u6B65\u5931\u8D25: ${a.bundlePath} ${String(u.message??"")}`)}console.log(`\u2705 \u540C\u6B65\u5B8C\u6210\uFF0C\u5171 ${c.length} \u4E2A\u6587\u4EF6`)}async function P(t,e,r){const n=`http://${e}:${r}/api/${t}`,s=await fetch(n,{method:"GET"});if(!s.ok)throw new Error(`${t} \u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${s.status}`)}async function L(t){if(d(t)==="ws"){await $(t);const o=await h.WSManager.request("screenshot");if(!o.success||typeof o.data!="string")throw new Error(`\u622A\u56FE\u5931\u8D25: ${String(o.message??"unknown")}`);return Buffer.from(o.data,"base64")}const{ip:r,port:n}=g(t),s=`http://${r}:${n}/api/screenshot`,i=await fetch(s,{method:"GET"});if(!i.ok)throw new Error(`\u622A\u56FE\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${i.status}`);const c=await i.arrayBuffer();return Buffer.from(c)}async function U(t){if(d(t)==="ws"){await $(t);const o=await h.WSManager.request("screenshot");if(!o.success||typeof o.data!="string")throw new Error(`\u622A\u56FE(base64)\u5931\u8D25: ${String(o.message??"unknown")}`);return o.data}const{ip:r,port:n}=g(t),s=`http://${r}:${n}/api/screenshotBase64`,i=await fetch(s,{method:"GET"});if(!i.ok)throw new Error(`\u622A\u56FE(base64)\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${i.status}`);const c=await i.json();if(!c.success||typeof c.data!="string")throw new Error(`\u622A\u56FE(base64)\u5931\u8D25: ${String(c.message??"unknown")}`);return c.data}async function k(t,e=50,r=120,n=1){const s=d(t);if(!Number.isInteger(e)||e<1)throw new Error(`\u65E0\u6548 maxDepth: ${e}`);if(!Number.isInteger(r)||r<1)throw new Error(`\u65E0\u6548 timeout: ${r}`);if(!Number.isInteger(n)||n!==1&&n!==2&&n!==3)throw new Error(`\u65E0\u6548 mode: ${n}`);if(s==="ws"){await $(t);const l=await h.WSManager.request("source",{max_depth:e,timeout:r,maxDepth:e,mode:n});if(!l.success||typeof l.data!="string")throw new Error(`\u83B7\u53D6\u8282\u70B9\u5931\u8D25: ${String(l.message??"unknown")}`);return l.data}const{ip:i,port:c}=g(t),o=new URL(`http://${i}:${c}/api/source`);o.searchParams.set("max_depth",String(e)),o.searchParams.set("timeout",String(r)),o.searchParams.set("mode",String(n));const a=await fetch(o.toString(),{method:"GET"});if(!a.ok)throw new Error(`\u83B7\u53D6\u8282\u70B9\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${a.status}`);return a.text()}async function A(t,e=200){if(d(t)!=="http")throw new Error("\u83B7\u53D6\u65E5\u5FD7\u5931\u8D25: \u5F53\u524D\u65E5\u5FD7\u884C\u63A5\u53E3\u4EC5\u652F\u6301 http \u4F20\u8F93");if(!Number.isInteger(e)||e<1||e>5e3)throw new Error(`\u83B7\u53D6\u65E5\u5FD7\u5931\u8D25: \u65E0\u6548 count ${e}`);const{ip:n,port:s}=g(t),i=new URL(`http://${n}:${s}/logger/current/lines`);i.searchParams.set("count",String(e));const c=await fetch(i.toString(),{method:"GET"});if(c.status===404)return{lines:[],hasMore:!1};if(!c.ok)throw new Error(`\u83B7\u53D6\u65E5\u5FD7\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${c.status}`);const o=await c.json();return{lines:Array.isArray(o.lines)?o.lines.map(a=>String(a)):[],hasMore:o.hasMore===!0}}async function m(t){const e=await h.WSManager.request(t);if(!e.success)throw new Error(`${t} \u5931\u8D25: ${String(e.message??"unknown")}`)}async function $(t){const{wsPort:e,wsWaitMs:r}=q(t),n=h.WSManager.get();n.isStarted()||await n.start(e),h.WSManager.isConnected()||(console.log("\u231B \u7B49\u5F85\u8BBE\u5907\u901A\u8FC7 WS \u8FDE\u63A5..."),await n.waitForClient(r))}async function z(t){const e=t.workspacePath?w.resolve(t.workspacePath):process.cwd(),r=d(t);if(console.log(`\u{1F527} \u5F00\u59CB\u6784\u5EFA\u9879\u76EE: ${e}`),await O(e),r==="ws"){await $(t),console.log("\u{1F4E6} \u5F00\u59CB\u901A\u8FC7 WS \u540C\u6B65\u9879\u76EE\u5230\u8BBE\u5907"),await W(e),console.log("\u{1F680} \u5F00\u59CB\u901A\u8FC7 WS \u8FD0\u884C\u9879\u76EE"),await m("run"),console.log("\u2705 \u8FD0\u884C\u8BF7\u6C42\u5DF2\u53D1\u9001");return}const{ip:n,port:s}=g(t);console.log(`\u{1F4E6} \u5F00\u59CB\u540C\u6B65\u9879\u76EE\u5230\u8BBE\u5907: ${n}:${s}`),await M(e,n,s),console.log(`\u{1F680} \u5F00\u59CB\u8FD0\u884C\u9879\u76EE: ${n}:${s}`),await P("run",n,s),console.log("\u2705 \u8FD0\u884C\u8BF7\u6C42\u5DF2\u53D1\u9001")}async function G(t){const e=t.workspacePath?w.resolve(t.workspacePath):process.cwd(),r=d(t);if(console.log(`\u{1F527} \u5F00\u59CB\u6784\u5EFA\u9879\u76EE: ${e}`),await O(e),r==="ws"){await $(t),console.log("\u{1F4E6} \u5F00\u59CB\u901A\u8FC7 WS \u540C\u6B65\u9879\u76EE\u5230\u8BBE\u5907"),await W(e),console.log("\u{1F5BC}\uFE0F \u5F00\u59CB\u901A\u8FC7 WS \u9884\u89C8 UI"),await m("runUI"),console.log("\u2705 UI \u9884\u89C8\u8BF7\u6C42\u5DF2\u53D1\u9001");return}const{ip:n,port:s}=g(t);console.log(`\u{1F4E6} \u5F00\u59CB\u540C\u6B65\u9879\u76EE\u5230\u8BBE\u5907: ${n}:${s}`),await M(e,n,s),console.log(`\u{1F5BC}\uFE0F \u5F00\u59CB\u9884\u89C8 UI: ${n}:${s}`),await P("runUI",n,s),console.log("\u2705 UI \u9884\u89C8\u8BF7\u6C42\u5DF2\u53D1\u9001")}async function V(t){if(d(t)==="ws"){await $(t),console.log("\u{1F6D1} \u5F00\u59CB\u901A\u8FC7 WS \u505C\u6B62\u9879\u76EE"),await m("stop"),console.log("\u2705 \u505C\u6B62\u8BF7\u6C42\u5DF2\u53D1\u9001");return}const{ip:r,port:n}=g(t);console.log(`\u{1F6D1} \u5F00\u59CB\u505C\u6B62\u9879\u76EE: ${r}:${n}`),await P("stop",r,n),console.log("\u2705 \u505C\u6B62\u8BF7\u6C42\u5DF2\u53D1\u9001")}
|
|
@@ -1,8 +1,2 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
-
/**
|
|
3
|
-
* 为最终 JS chunk 的 catch 块补充停止异常转抛逻辑。
|
|
4
|
-
*
|
|
5
|
-
* 这个插件运行在 renderChunk 阶段:Vite 已经把 TS/模块语法编译成最终 JS,但尚未写入文件。
|
|
6
|
-
* 使用 MagicString 返回 sourcemap,让新增保护代码不映射到用户源码,原有代码继续保持映射。
|
|
7
|
-
*/
|
|
8
2
|
export declare function createStopGuardPlugin(): Plugin;
|