ms-vite-plugin 1.1.4 → 1.1.6
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/mcp/tools.js +219 -26
- package/dist/project.d.ts +3 -25
- package/dist/project.js +8 -66
- package/package.json +1 -1
package/dist/mcp/tools.js
CHANGED
|
@@ -269,6 +269,57 @@ function registerDocTools(server) {
|
|
|
269
269
|
* registerRuntimeTools(server)
|
|
270
270
|
*/
|
|
271
271
|
function registerRuntimeTools(server) {
|
|
272
|
+
/**
|
|
273
|
+
* MCP 进程内当前工作目录(可通过 set_workspace 修改)
|
|
274
|
+
*/
|
|
275
|
+
let currentWorkspacePath;
|
|
276
|
+
/**
|
|
277
|
+
* 解析并记忆工作目录
|
|
278
|
+
* @param workspacePath 可选的工作目录
|
|
279
|
+
* @returns 返回本次生效的绝对路径
|
|
280
|
+
* @example
|
|
281
|
+
* const workspace = resolveWorkspacePath("/Users/demo/project")
|
|
282
|
+
*/
|
|
283
|
+
function resolveWorkspacePath(workspacePath) {
|
|
284
|
+
if (workspacePath && workspacePath.trim()) {
|
|
285
|
+
currentWorkspacePath = path.resolve(workspacePath.trim());
|
|
286
|
+
return currentWorkspacePath;
|
|
287
|
+
}
|
|
288
|
+
if (currentWorkspacePath) {
|
|
289
|
+
return currentWorkspacePath;
|
|
290
|
+
}
|
|
291
|
+
return process.cwd();
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 校验并返回有效工作目录
|
|
295
|
+
* @param workspacePath 可选工作目录
|
|
296
|
+
* @returns 返回校验通过的绝对路径
|
|
297
|
+
* @example
|
|
298
|
+
* const workspace = await ensureWorkspacePath("/Users/demo/project")
|
|
299
|
+
*/
|
|
300
|
+
async function ensureWorkspacePath(workspacePath) {
|
|
301
|
+
const workspace = resolveWorkspacePath(workspacePath);
|
|
302
|
+
await (0, project_2.ensureValidKuaiJSProject)(workspace);
|
|
303
|
+
return workspace;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 格式化日志监听结果,供 run/run_ui 结果文本复用
|
|
307
|
+
* @param result 日志监听结果
|
|
308
|
+
* @returns 返回可直接拼接到 tool 响应中的文本
|
|
309
|
+
* @example
|
|
310
|
+
* const text = formatWatchLogsResult(result)
|
|
311
|
+
*/
|
|
312
|
+
function formatWatchLogsResult(result) {
|
|
313
|
+
const logsPreview = result.logs
|
|
314
|
+
.slice(-10)
|
|
315
|
+
.map((log) => `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.message}`)
|
|
316
|
+
.join("\n");
|
|
317
|
+
return [
|
|
318
|
+
`日志监听: 收集 ${result.logs.length} 条,runtime_status ${result.runtimeStatus.length} 条`,
|
|
319
|
+
"最新日志(后10条):",
|
|
320
|
+
logsPreview || "无日志",
|
|
321
|
+
].join("\n");
|
|
322
|
+
}
|
|
272
323
|
/**
|
|
273
324
|
* 解析运行目标:
|
|
274
325
|
* - 显式 transport=ws: 强制走 ws
|
|
@@ -306,6 +357,41 @@ function registerRuntimeTools(server) {
|
|
|
306
357
|
label: `${device.ip}:${device.port}`,
|
|
307
358
|
};
|
|
308
359
|
}
|
|
360
|
+
server.registerTool("set_workspace", {
|
|
361
|
+
title: "Set Workspace",
|
|
362
|
+
description: "设置默认工作目录。后续 build/run/package/watch 等工具会优先使用该目录。",
|
|
363
|
+
inputSchema: {
|
|
364
|
+
workspacePath: z
|
|
365
|
+
.string()
|
|
366
|
+
.min(1)
|
|
367
|
+
.describe("快点JS 项目目录绝对路径(需包含 package.json 与 scripts)"),
|
|
368
|
+
},
|
|
369
|
+
}, async ({ workspacePath }) => {
|
|
370
|
+
const workspace = await ensureWorkspacePath(workspacePath);
|
|
371
|
+
return {
|
|
372
|
+
content: [
|
|
373
|
+
{
|
|
374
|
+
type: "text",
|
|
375
|
+
text: `默认工作目录已设置为: ${workspace}`,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
};
|
|
379
|
+
});
|
|
380
|
+
server.registerTool("get_workspace", {
|
|
381
|
+
title: "Get Workspace",
|
|
382
|
+
description: "查看当前 MCP 生效的工作目录。",
|
|
383
|
+
inputSchema: {},
|
|
384
|
+
}, async () => {
|
|
385
|
+
const workspace = resolveWorkspacePath();
|
|
386
|
+
return {
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: "text",
|
|
390
|
+
text: `当前工作目录: ${workspace}`,
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
};
|
|
394
|
+
});
|
|
309
395
|
server.registerTool("set_device", {
|
|
310
396
|
title: "Set Device",
|
|
311
397
|
description: "设置默认设备连接信息。首次配置后,后续 run/stop 可不再传 ip。",
|
|
@@ -523,8 +609,13 @@ function registerRuntimeTools(server) {
|
|
|
523
609
|
});
|
|
524
610
|
server.registerTool("watch_logs", {
|
|
525
611
|
title: "Watch Logs",
|
|
526
|
-
description: "通过 SSE
|
|
612
|
+
description: "通过 SSE 监听设备实时日志。首次可传 ip,也可复用 set_device 保存的默认设备。",
|
|
527
613
|
inputSchema: {
|
|
614
|
+
workspacePath: z
|
|
615
|
+
.string()
|
|
616
|
+
.min(1)
|
|
617
|
+
.optional()
|
|
618
|
+
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
528
619
|
ip: z
|
|
529
620
|
.string()
|
|
530
621
|
.min(1)
|
|
@@ -554,14 +645,10 @@ function registerRuntimeTools(server) {
|
|
|
554
645
|
.default(200)
|
|
555
646
|
.describe("最多收集日志条数,默认 200"),
|
|
556
647
|
},
|
|
557
|
-
}, async ({ ip, port, durationSeconds, maxLogs }) => {
|
|
558
|
-
await (
|
|
648
|
+
}, async ({ workspacePath, ip, port, durationSeconds, maxLogs }) => {
|
|
649
|
+
await ensureWorkspacePath(workspacePath);
|
|
559
650
|
const device = await (0, device_config_1.resolveDeviceConfig)(ip, port);
|
|
560
651
|
const result = await (0, project_1.watchDeviceLogsBySse)(device.ip, device.port, durationSeconds * 1000, maxLogs);
|
|
561
|
-
const findingsPreview = result.findings
|
|
562
|
-
.slice(0, 20)
|
|
563
|
-
.map((item, index) => `${index + 1}. [${item.severity}] ${item.rule} | ${item.log.timestamp} | ${item.log.message}`)
|
|
564
|
-
.join("\n");
|
|
565
652
|
const logsPreview = result.logs
|
|
566
653
|
.slice(-20)
|
|
567
654
|
.map((log) => `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.message}`)
|
|
@@ -573,10 +660,6 @@ function registerRuntimeTools(server) {
|
|
|
573
660
|
text: [
|
|
574
661
|
`监听目标: ${device.ip}:${device.port}`,
|
|
575
662
|
`监听时长: ${durationSeconds}s,收集日志: ${result.logs.length} 条,runtime_status: ${result.runtimeStatus.length} 条`,
|
|
576
|
-
result.summary,
|
|
577
|
-
"",
|
|
578
|
-
"异常判定(最多展示前20条):",
|
|
579
|
-
findingsPreview || "未命中异常规则",
|
|
580
663
|
"",
|
|
581
664
|
"最新日志(最多展示最后20条):",
|
|
582
665
|
logsPreview || "无日志",
|
|
@@ -589,14 +672,19 @@ function registerRuntimeTools(server) {
|
|
|
589
672
|
title: "Build Project",
|
|
590
673
|
description: "构建 KuaiJS 项目,支持开发模式与生产模式。",
|
|
591
674
|
inputSchema: {
|
|
675
|
+
workspacePath: z
|
|
676
|
+
.string()
|
|
677
|
+
.min(1)
|
|
678
|
+
.optional()
|
|
679
|
+
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
592
680
|
dev: z
|
|
593
681
|
.boolean()
|
|
594
682
|
.optional()
|
|
595
683
|
.describe("是否开发模式构建,true=开发模式,false=生产模式"),
|
|
596
684
|
},
|
|
597
|
-
}, async ({ dev }) => {
|
|
598
|
-
await (
|
|
599
|
-
await (0, build_1.buildAll)(Boolean(dev),
|
|
685
|
+
}, async ({ workspacePath, dev }) => {
|
|
686
|
+
const workspace = await ensureWorkspacePath(workspacePath);
|
|
687
|
+
await (0, build_1.buildAll)(Boolean(dev), workspace);
|
|
600
688
|
return {
|
|
601
689
|
content: [
|
|
602
690
|
{ type: "text", text: `构建完成,模式: ${dev ? "dev" : "prod"}` },
|
|
@@ -606,10 +694,16 @@ function registerRuntimeTools(server) {
|
|
|
606
694
|
server.registerTool("package_project", {
|
|
607
695
|
title: "Package Project",
|
|
608
696
|
description: "执行生产构建并加密,返回 enc.msbundle 路径。",
|
|
609
|
-
inputSchema: {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
697
|
+
inputSchema: {
|
|
698
|
+
workspacePath: z
|
|
699
|
+
.string()
|
|
700
|
+
.min(1)
|
|
701
|
+
.optional()
|
|
702
|
+
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
703
|
+
},
|
|
704
|
+
}, async ({ workspacePath }) => {
|
|
705
|
+
const workspace = await ensureWorkspacePath(workspacePath);
|
|
706
|
+
const encryptedPath = await (0, packager_1.packageProject)(workspace);
|
|
613
707
|
return {
|
|
614
708
|
content: [{ type: "text", text: `打包完成: ${encryptedPath}` }],
|
|
615
709
|
};
|
|
@@ -648,9 +742,49 @@ function registerRuntimeTools(server) {
|
|
|
648
742
|
.max(600000)
|
|
649
743
|
.optional()
|
|
650
744
|
.describe("WS 等待连接超时毫秒(transport=ws 时可选,默认 30000)"),
|
|
745
|
+
workspacePath: z
|
|
746
|
+
.string()
|
|
747
|
+
.min(1)
|
|
748
|
+
.optional()
|
|
749
|
+
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
750
|
+
watchLogs: z
|
|
751
|
+
.boolean()
|
|
752
|
+
.optional()
|
|
753
|
+
.default(true)
|
|
754
|
+
.describe("是否在运行前启动实时日志监听,默认 true"),
|
|
755
|
+
logDurationSeconds: z
|
|
756
|
+
.number()
|
|
757
|
+
.int()
|
|
758
|
+
.min(1)
|
|
759
|
+
.max(300)
|
|
760
|
+
.optional()
|
|
761
|
+
.default(20)
|
|
762
|
+
.describe("日志监听时长(秒),默认 20"),
|
|
763
|
+
logMaxLogs: z
|
|
764
|
+
.number()
|
|
765
|
+
.int()
|
|
766
|
+
.min(10)
|
|
767
|
+
.max(5000)
|
|
768
|
+
.optional()
|
|
769
|
+
.default(300)
|
|
770
|
+
.describe("日志最大收集条数,默认 300"),
|
|
651
771
|
},
|
|
652
|
-
}, async ({ transport, ip, port, wsPort, wsWaitMs }) => {
|
|
653
|
-
await (
|
|
772
|
+
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath, watchLogs, logDurationSeconds, logMaxLogs, }) => {
|
|
773
|
+
const workspace = await ensureWorkspacePath(workspacePath);
|
|
774
|
+
let logTask;
|
|
775
|
+
let logTargetText = "";
|
|
776
|
+
let logSetupWarning = "";
|
|
777
|
+
if (watchLogs) {
|
|
778
|
+
try {
|
|
779
|
+
const logDevice = await (0, device_config_1.resolveDeviceConfig)(ip, port);
|
|
780
|
+
logTargetText = `${logDevice.ip}:${logDevice.port}`;
|
|
781
|
+
// 先启动日志监听,再执行 run,确保不会错过启动期日志
|
|
782
|
+
logTask = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port, logDurationSeconds * 1000, logMaxLogs);
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
logSetupWarning = `日志监听未启动: ${error instanceof Error ? error.message : String(error)}`;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
654
788
|
const target = await resolvePreferredRuntimeTarget({
|
|
655
789
|
transport,
|
|
656
790
|
ip,
|
|
@@ -663,17 +797,24 @@ function registerRuntimeTools(server) {
|
|
|
663
797
|
transport: "ws",
|
|
664
798
|
wsPort: target.wsPort,
|
|
665
799
|
wsWaitMs: target.wsWaitMs,
|
|
800
|
+
workspacePath: workspace,
|
|
666
801
|
}
|
|
667
802
|
: {
|
|
668
803
|
ip: target.ip,
|
|
669
804
|
port: target.port,
|
|
670
805
|
transport: "http",
|
|
806
|
+
workspacePath: workspace,
|
|
671
807
|
});
|
|
808
|
+
const logSection = logTask
|
|
809
|
+
? `\n\n运行前日志监听目标: ${logTargetText}\n${formatWatchLogsResult(await logTask)}`
|
|
810
|
+
: logSetupWarning
|
|
811
|
+
? `\n\n${logSetupWarning}`
|
|
812
|
+
: "";
|
|
672
813
|
return {
|
|
673
814
|
content: [
|
|
674
815
|
{
|
|
675
816
|
type: "text",
|
|
676
|
-
text: `运行请求已发送到 ${target.label}`,
|
|
817
|
+
text: `运行请求已发送到 ${target.label}${logSection}`,
|
|
677
818
|
},
|
|
678
819
|
],
|
|
679
820
|
};
|
|
@@ -712,9 +853,49 @@ function registerRuntimeTools(server) {
|
|
|
712
853
|
.max(600000)
|
|
713
854
|
.optional()
|
|
714
855
|
.describe("WS 等待连接超时毫秒(transport=ws 时可选,默认 30000)"),
|
|
856
|
+
workspacePath: z
|
|
857
|
+
.string()
|
|
858
|
+
.min(1)
|
|
859
|
+
.optional()
|
|
860
|
+
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
861
|
+
watchLogs: z
|
|
862
|
+
.boolean()
|
|
863
|
+
.optional()
|
|
864
|
+
.default(true)
|
|
865
|
+
.describe("是否在预览前启动实时日志监听,默认 true"),
|
|
866
|
+
logDurationSeconds: z
|
|
867
|
+
.number()
|
|
868
|
+
.int()
|
|
869
|
+
.min(1)
|
|
870
|
+
.max(300)
|
|
871
|
+
.optional()
|
|
872
|
+
.default(20)
|
|
873
|
+
.describe("日志监听时长(秒),默认 20"),
|
|
874
|
+
logMaxLogs: z
|
|
875
|
+
.number()
|
|
876
|
+
.int()
|
|
877
|
+
.min(10)
|
|
878
|
+
.max(5000)
|
|
879
|
+
.optional()
|
|
880
|
+
.default(300)
|
|
881
|
+
.describe("日志最大收集条数,默认 300"),
|
|
715
882
|
},
|
|
716
|
-
}, async ({ transport, ip, port, wsPort, wsWaitMs }) => {
|
|
717
|
-
await (
|
|
883
|
+
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath, watchLogs, logDurationSeconds, logMaxLogs, }) => {
|
|
884
|
+
const workspace = await ensureWorkspacePath(workspacePath);
|
|
885
|
+
let logTask;
|
|
886
|
+
let logTargetText = "";
|
|
887
|
+
let logSetupWarning = "";
|
|
888
|
+
if (watchLogs) {
|
|
889
|
+
try {
|
|
890
|
+
const logDevice = await (0, device_config_1.resolveDeviceConfig)(ip, port);
|
|
891
|
+
logTargetText = `${logDevice.ip}:${logDevice.port}`;
|
|
892
|
+
// 先启动日志监听,再执行 run-ui,确保不会错过启动期日志
|
|
893
|
+
logTask = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port, logDurationSeconds * 1000, logMaxLogs);
|
|
894
|
+
}
|
|
895
|
+
catch (error) {
|
|
896
|
+
logSetupWarning = `日志监听未启动: ${error instanceof Error ? error.message : String(error)}`;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
718
899
|
const target = await resolvePreferredRuntimeTarget({
|
|
719
900
|
transport,
|
|
720
901
|
ip,
|
|
@@ -727,17 +908,24 @@ function registerRuntimeTools(server) {
|
|
|
727
908
|
transport: "ws",
|
|
728
909
|
wsPort: target.wsPort,
|
|
729
910
|
wsWaitMs: target.wsWaitMs,
|
|
911
|
+
workspacePath: workspace,
|
|
730
912
|
}
|
|
731
913
|
: {
|
|
732
914
|
ip: target.ip,
|
|
733
915
|
port: target.port,
|
|
734
916
|
transport: "http",
|
|
917
|
+
workspacePath: workspace,
|
|
735
918
|
});
|
|
919
|
+
const logSection = logTask
|
|
920
|
+
? `\n\n预览前日志监听目标: ${logTargetText}\n${formatWatchLogsResult(await logTask)}`
|
|
921
|
+
: logSetupWarning
|
|
922
|
+
? `\n\n${logSetupWarning}`
|
|
923
|
+
: "";
|
|
736
924
|
return {
|
|
737
925
|
content: [
|
|
738
926
|
{
|
|
739
927
|
type: "text",
|
|
740
|
-
text: `UI 预览请求已发送到 ${target.label}`,
|
|
928
|
+
text: `UI 预览请求已发送到 ${target.label}${logSection}`,
|
|
741
929
|
},
|
|
742
930
|
],
|
|
743
931
|
};
|
|
@@ -776,9 +964,14 @@ function registerRuntimeTools(server) {
|
|
|
776
964
|
.max(600000)
|
|
777
965
|
.optional()
|
|
778
966
|
.describe("WS 等待连接超时毫秒(transport=ws 时可选,默认 30000)"),
|
|
967
|
+
workspacePath: z
|
|
968
|
+
.string()
|
|
969
|
+
.min(1)
|
|
970
|
+
.optional()
|
|
971
|
+
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
779
972
|
},
|
|
780
|
-
}, async ({ transport, ip, port, wsPort, wsWaitMs }) => {
|
|
781
|
-
|
|
973
|
+
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath }) => {
|
|
974
|
+
resolveWorkspacePath(workspacePath);
|
|
782
975
|
const target = await resolvePreferredRuntimeTarget({
|
|
783
976
|
transport,
|
|
784
977
|
ip,
|
package/dist/project.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface DeviceCliOptions {
|
|
|
7
7
|
transport?: string;
|
|
8
8
|
wsPort?: string;
|
|
9
9
|
wsWaitMs?: string;
|
|
10
|
+
workspacePath?: string;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
13
|
* 设备日志条目
|
|
@@ -28,17 +29,6 @@ export interface DeviceRuntimeStatusEntry {
|
|
|
28
29
|
/** 事件时间戳(本地接收时间) */
|
|
29
30
|
timestamp: string;
|
|
30
31
|
}
|
|
31
|
-
/**
|
|
32
|
-
* 设备日志判定项
|
|
33
|
-
*/
|
|
34
|
-
export interface DeviceLogFinding {
|
|
35
|
-
/** 严重级别 */
|
|
36
|
-
severity: "error" | "warn";
|
|
37
|
-
/** 命中的判定规则 */
|
|
38
|
-
rule: string;
|
|
39
|
-
/** 证据日志 */
|
|
40
|
-
log: DeviceLogEntry;
|
|
41
|
-
}
|
|
42
32
|
/**
|
|
43
33
|
* SSE 日志监听结果
|
|
44
34
|
*/
|
|
@@ -47,10 +37,6 @@ export interface DeviceLogWatchResult {
|
|
|
47
37
|
logs: DeviceLogEntry[];
|
|
48
38
|
/** 收集到的 runtime_status 条目 */
|
|
49
39
|
runtimeStatus: DeviceRuntimeStatusEntry[];
|
|
50
|
-
/** 自动判定结果 */
|
|
51
|
-
findings: DeviceLogFinding[];
|
|
52
|
-
/** 结果摘要 */
|
|
53
|
-
summary: string;
|
|
54
40
|
}
|
|
55
41
|
/**
|
|
56
42
|
* 在设备上获取截图 JPG 二进制数据(HTTP)
|
|
@@ -79,20 +65,12 @@ export declare function getScreenshotBase64OnDevice(options: DeviceCliOptions):
|
|
|
79
65
|
*/
|
|
80
66
|
export declare function getSourceOnDevice(options: DeviceCliOptions, maxDepth?: number, timeout?: number): Promise<string>;
|
|
81
67
|
/**
|
|
82
|
-
*
|
|
83
|
-
* @param logs 待判定日志列表
|
|
84
|
-
* @returns 返回判定命中项
|
|
85
|
-
* @example
|
|
86
|
-
* const findings = analyzeDeviceLogs([{ level: "error", message: "crash", timestamp: "..." }])
|
|
87
|
-
*/
|
|
88
|
-
export declare function analyzeDeviceLogs(logs: DeviceLogEntry[]): DeviceLogFinding[];
|
|
89
|
-
/**
|
|
90
|
-
* 监听设备 SSE 日志并返回自动判定结果
|
|
68
|
+
* 监听设备 SSE 日志并返回原始结果
|
|
91
69
|
* @param ip 设备 IP 地址
|
|
92
70
|
* @param port 设备端口
|
|
93
71
|
* @param durationMs 监听时长(毫秒),默认 15000
|
|
94
72
|
* @param maxLogs 最多收集日志条数,默认 200
|
|
95
|
-
* @returns
|
|
73
|
+
* @returns 返回日志与运行状态
|
|
96
74
|
* @example
|
|
97
75
|
* const result = await watchDeviceLogsBySse("192.168.1.10", 9800, 10000, 100)
|
|
98
76
|
*/
|
package/dist/project.js
CHANGED
|
@@ -39,7 +39,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.getScreenshotOnDevice = getScreenshotOnDevice;
|
|
40
40
|
exports.getScreenshotBase64OnDevice = getScreenshotBase64OnDevice;
|
|
41
41
|
exports.getSourceOnDevice = getSourceOnDevice;
|
|
42
|
-
exports.analyzeDeviceLogs = analyzeDeviceLogs;
|
|
43
42
|
exports.watchDeviceLogsBySse = watchDeviceLogsBySse;
|
|
44
43
|
exports.runOnDevice = runOnDevice;
|
|
45
44
|
exports.runUIOnDevice = runUIOnDevice;
|
|
@@ -511,65 +510,12 @@ function normalizeLogEntry(payload) {
|
|
|
511
510
|
};
|
|
512
511
|
}
|
|
513
512
|
/**
|
|
514
|
-
*
|
|
515
|
-
* @param logs 待判定日志列表
|
|
516
|
-
* @returns 返回判定命中项
|
|
517
|
-
* @example
|
|
518
|
-
* const findings = analyzeDeviceLogs([{ level: "error", message: "crash", timestamp: "..." }])
|
|
519
|
-
*/
|
|
520
|
-
function analyzeDeviceLogs(logs) {
|
|
521
|
-
const findings = [];
|
|
522
|
-
const criticalPatterns = [
|
|
523
|
-
{ rule: "崩溃关键词", regex: /\b(crash|fatal|abort|sigabrt|segfault)\b/i },
|
|
524
|
-
{
|
|
525
|
-
rule: "异常关键词",
|
|
526
|
-
regex: /\b(exception|uncaught|assert|error:|failed|failure)\b/i,
|
|
527
|
-
},
|
|
528
|
-
{
|
|
529
|
-
rule: "内存风险关键词",
|
|
530
|
-
regex: /\b(out of memory|oom|memory leak|allocation failed)\b/i,
|
|
531
|
-
},
|
|
532
|
-
{
|
|
533
|
-
rule: "设备离线关键词",
|
|
534
|
-
regex: /\b(timeout|disconnected|connection reset|network error)\b/i,
|
|
535
|
-
},
|
|
536
|
-
];
|
|
537
|
-
for (const log of logs) {
|
|
538
|
-
const level = log.level.toLowerCase();
|
|
539
|
-
const message = log.message;
|
|
540
|
-
if (level === "error") {
|
|
541
|
-
findings.push({
|
|
542
|
-
severity: "error",
|
|
543
|
-
rule: "error 级别日志",
|
|
544
|
-
log,
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
else if (level === "warn") {
|
|
548
|
-
findings.push({
|
|
549
|
-
severity: "warn",
|
|
550
|
-
rule: "warn 级别日志",
|
|
551
|
-
log,
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
for (const pattern of criticalPatterns) {
|
|
555
|
-
if (pattern.regex.test(message)) {
|
|
556
|
-
findings.push({
|
|
557
|
-
severity: level === "error" ? "error" : "warn",
|
|
558
|
-
rule: pattern.rule,
|
|
559
|
-
log,
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
return findings;
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* 监听设备 SSE 日志并返回自动判定结果
|
|
513
|
+
* 监听设备 SSE 日志并返回原始结果
|
|
568
514
|
* @param ip 设备 IP 地址
|
|
569
515
|
* @param port 设备端口
|
|
570
516
|
* @param durationMs 监听时长(毫秒),默认 15000
|
|
571
517
|
* @param maxLogs 最多收集日志条数,默认 200
|
|
572
|
-
* @returns
|
|
518
|
+
* @returns 返回日志与运行状态
|
|
573
519
|
* @example
|
|
574
520
|
* const result = await watchDeviceLogsBySse("192.168.1.10", 9800, 10000, 100)
|
|
575
521
|
*/
|
|
@@ -657,17 +603,9 @@ async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200)
|
|
|
657
603
|
finally {
|
|
658
604
|
clearTimeout(timeoutHandle);
|
|
659
605
|
}
|
|
660
|
-
const findings = analyzeDeviceLogs(logs);
|
|
661
|
-
const errorCount = findings.filter((item) => item.severity === "error").length;
|
|
662
|
-
const warnCount = findings.filter((item) => item.severity === "warn").length;
|
|
663
|
-
const summary = findings.length === 0
|
|
664
|
-
? `日志监听完成:共 ${logs.length} 条日志,未发现明显异常。`
|
|
665
|
-
: `日志监听完成:共 ${logs.length} 条日志,发现 ${errorCount} 条 error 风险、${warnCount} 条 warn 风险。`;
|
|
666
606
|
return {
|
|
667
607
|
logs,
|
|
668
608
|
runtimeStatus,
|
|
669
|
-
findings,
|
|
670
|
-
summary,
|
|
671
609
|
};
|
|
672
610
|
}
|
|
673
611
|
/**
|
|
@@ -709,7 +647,9 @@ async function ensureWsReady(options) {
|
|
|
709
647
|
* await runOnDevice({ ip: "192.168.1.10", port: "9800", path: "./demo" })
|
|
710
648
|
*/
|
|
711
649
|
async function runOnDevice(options) {
|
|
712
|
-
const workspacePath =
|
|
650
|
+
const workspacePath = options.workspacePath
|
|
651
|
+
? path.resolve(options.workspacePath)
|
|
652
|
+
: process.cwd();
|
|
713
653
|
const transport = parseTransport(options);
|
|
714
654
|
console.log(`🔧 开始构建项目: ${workspacePath}`);
|
|
715
655
|
await runDevBuild(workspacePath);
|
|
@@ -737,7 +677,9 @@ async function runOnDevice(options) {
|
|
|
737
677
|
* await runUIOnDevice({ ip: "192.168.1.10", port: "9800", path: "./demo" })
|
|
738
678
|
*/
|
|
739
679
|
async function runUIOnDevice(options) {
|
|
740
|
-
const workspacePath =
|
|
680
|
+
const workspacePath = options.workspacePath
|
|
681
|
+
? path.resolve(options.workspacePath)
|
|
682
|
+
: process.cwd();
|
|
741
683
|
const transport = parseTransport(options);
|
|
742
684
|
console.log(`🔧 开始构建项目: ${workspacePath}`);
|
|
743
685
|
await runDevBuild(workspacePath);
|