ms-vite-plugin 1.1.8 → 1.1.10
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 +15 -112
- package/dist/project.d.ts +4 -3
- package/dist/project.js +14 -2
- package/package.json +1 -1
package/dist/mcp/tools.js
CHANGED
|
@@ -312,34 +312,18 @@ function registerRuntimeTools(server) {
|
|
|
312
312
|
* @example
|
|
313
313
|
* const text = formatRunLogSection("192.168.1.10", 9800, 10, result)
|
|
314
314
|
*/
|
|
315
|
-
function formatRunLogSection(ip, port,
|
|
315
|
+
function formatRunLogSection(ip, port, result) {
|
|
316
316
|
const logsPreview = result.logs
|
|
317
317
|
.slice(-20)
|
|
318
318
|
.map((log) => `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.message}`)
|
|
319
319
|
.join("\n");
|
|
320
320
|
return [
|
|
321
|
-
|
|
321
|
+
`运行日志来源: ${ip}:${port}`,
|
|
322
322
|
`结束原因: ${result.stopReason},日志: ${result.logs.length} 条,runtime_status: ${result.runtimeStatus.length} 条`,
|
|
323
323
|
"最新日志(最多展示最后20条):",
|
|
324
324
|
logsPreview || "无日志",
|
|
325
325
|
].join("\n");
|
|
326
326
|
}
|
|
327
|
-
/**
|
|
328
|
-
* 提取最后一次 runtime_status 的 isRunning 值
|
|
329
|
-
* @param result 日志监听结果
|
|
330
|
-
* @returns 返回 true/false,无法判断时返回 undefined
|
|
331
|
-
* @example
|
|
332
|
-
* const running = getLatestIsRunning(result)
|
|
333
|
-
*/
|
|
334
|
-
function getLatestIsRunning(result) {
|
|
335
|
-
for (let i = result.runtimeStatus.length - 1; i >= 0; i -= 1) {
|
|
336
|
-
const raw = result.runtimeStatus[i].raw;
|
|
337
|
-
if (typeof raw.isRunning === "boolean") {
|
|
338
|
-
return raw.isRunning;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return undefined;
|
|
342
|
-
}
|
|
343
327
|
/**
|
|
344
328
|
* 启动持续日志监听(后台,不阻塞当前 tool 返回)
|
|
345
329
|
* @param ip 设备 IP
|
|
@@ -350,7 +334,7 @@ function registerRuntimeTools(server) {
|
|
|
350
334
|
* const tip = startBackgroundContinuousLogWatch("192.168.1.10", 9800, 300)
|
|
351
335
|
*/
|
|
352
336
|
function startBackgroundContinuousLogWatch(ip, port, maxLogs) {
|
|
353
|
-
void (0, project_1.watchDeviceLogsBySse)(ip, port, 0, maxLogs
|
|
337
|
+
void (0, project_1.watchDeviceLogsBySse)(ip, port, 0, maxLogs)
|
|
354
338
|
.then((result) => {
|
|
355
339
|
console.log(`[mcp] continuous logs ${ip}:${port} ended, reason=${result.stopReason}, logs=${result.logs.length}, runtime_status=${result.runtimeStatus.length}`);
|
|
356
340
|
})
|
|
@@ -791,21 +775,13 @@ function registerRuntimeTools(server) {
|
|
|
791
775
|
watchLogs: z
|
|
792
776
|
.boolean()
|
|
793
777
|
.optional()
|
|
794
|
-
.default(
|
|
795
|
-
.describe("
|
|
778
|
+
.default(false)
|
|
779
|
+
.describe("是否在运行前启动日志监听,默认 false"),
|
|
796
780
|
logMode: z
|
|
797
|
-
.enum(["
|
|
781
|
+
.enum(["single", "continuous"])
|
|
798
782
|
.optional()
|
|
799
|
-
.default("
|
|
800
|
-
.describe("日志模式:
|
|
801
|
-
logDurationSeconds: z
|
|
802
|
-
.number()
|
|
803
|
-
.int()
|
|
804
|
-
.min(1)
|
|
805
|
-
.max(300)
|
|
806
|
-
.optional()
|
|
807
|
-
.default(10)
|
|
808
|
-
.describe("日志监听时长(秒),默认 10,用于回传 run 启动期实时输出"),
|
|
783
|
+
.default("single")
|
|
784
|
+
.describe("日志模式:single=按 runtime_status 收敛,continuous=持续监听"),
|
|
809
785
|
logMaxLogs: z
|
|
810
786
|
.number()
|
|
811
787
|
.int()
|
|
@@ -815,7 +791,7 @@ function registerRuntimeTools(server) {
|
|
|
815
791
|
.default(300)
|
|
816
792
|
.describe("日志最大收集条数,默认 300"),
|
|
817
793
|
},
|
|
818
|
-
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath, watchLogs, logMode,
|
|
794
|
+
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath, watchLogs, logMode, logMaxLogs, }) => {
|
|
819
795
|
const workspace = await ensureWorkspacePath(workspacePath);
|
|
820
796
|
let logPromise;
|
|
821
797
|
let logDeviceIp = "";
|
|
@@ -832,7 +808,7 @@ function registerRuntimeTools(server) {
|
|
|
832
808
|
logModeNotice = startBackgroundContinuousLogWatch(logDevice.ip, logDevice.port, logMaxLogs);
|
|
833
809
|
}
|
|
834
810
|
else {
|
|
835
|
-
logPromise = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port,
|
|
811
|
+
logPromise = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port, 0, logMaxLogs, true, true);
|
|
836
812
|
}
|
|
837
813
|
}
|
|
838
814
|
catch (error) {
|
|
@@ -862,14 +838,9 @@ function registerRuntimeTools(server) {
|
|
|
862
838
|
let logSection = "";
|
|
863
839
|
if (logPromise) {
|
|
864
840
|
const result = await logPromise;
|
|
865
|
-
const sections = [
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
if (logMode === "auto") {
|
|
869
|
-
const latestIsRunning = getLatestIsRunning(result);
|
|
870
|
-
if (result.stopReason === "timeout" && latestIsRunning === true) {
|
|
871
|
-
sections.push(startBackgroundContinuousLogWatch(logDeviceIp, logDevicePort, logMaxLogs));
|
|
872
|
-
}
|
|
841
|
+
const sections = [formatRunLogSection(logDeviceIp, logDevicePort, result)];
|
|
842
|
+
if (result.stopReason === "runtime_continuous") {
|
|
843
|
+
sections.push(startBackgroundContinuousLogWatch(logDeviceIp, logDevicePort, logMaxLogs));
|
|
873
844
|
}
|
|
874
845
|
logSection = `\n\n${sections.join("\n")}`;
|
|
875
846
|
}
|
|
@@ -927,57 +898,9 @@ function registerRuntimeTools(server) {
|
|
|
927
898
|
.min(1)
|
|
928
899
|
.optional()
|
|
929
900
|
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
930
|
-
watchLogs: z
|
|
931
|
-
.boolean()
|
|
932
|
-
.optional()
|
|
933
|
-
.default(true)
|
|
934
|
-
.describe("是否在预览前启动实时日志监听,默认 true"),
|
|
935
|
-
logMode: z
|
|
936
|
-
.enum(["auto", "single", "continuous"])
|
|
937
|
-
.optional()
|
|
938
|
-
.default("auto")
|
|
939
|
-
.describe("日志模式:auto=单次优先并自动判长任务,single=按 runtime_status 收敛,continuous=持续监听"),
|
|
940
|
-
logDurationSeconds: z
|
|
941
|
-
.number()
|
|
942
|
-
.int()
|
|
943
|
-
.min(1)
|
|
944
|
-
.max(300)
|
|
945
|
-
.optional()
|
|
946
|
-
.default(10)
|
|
947
|
-
.describe("日志监听时长(秒),默认 10,用于回传 run-ui 启动期实时输出"),
|
|
948
|
-
logMaxLogs: z
|
|
949
|
-
.number()
|
|
950
|
-
.int()
|
|
951
|
-
.min(10)
|
|
952
|
-
.max(5000)
|
|
953
|
-
.optional()
|
|
954
|
-
.default(300)
|
|
955
|
-
.describe("日志最大收集条数,默认 300"),
|
|
956
901
|
},
|
|
957
|
-
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath
|
|
902
|
+
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath }) => {
|
|
958
903
|
const workspace = await ensureWorkspacePath(workspacePath);
|
|
959
|
-
let logPromise;
|
|
960
|
-
let logDeviceIp = "";
|
|
961
|
-
let logDevicePort = 0;
|
|
962
|
-
let logSetupWarning = "";
|
|
963
|
-
let logModeNotice = "";
|
|
964
|
-
if (watchLogs) {
|
|
965
|
-
try {
|
|
966
|
-
const logDevice = await (0, device_config_1.resolveDeviceConfig)(ip, port);
|
|
967
|
-
// 先挂监听,再执行 run-ui,确保拿到启动期实时日志
|
|
968
|
-
logDeviceIp = logDevice.ip;
|
|
969
|
-
logDevicePort = logDevice.port;
|
|
970
|
-
if (logMode === "continuous") {
|
|
971
|
-
logModeNotice = startBackgroundContinuousLogWatch(logDevice.ip, logDevice.port, logMaxLogs);
|
|
972
|
-
}
|
|
973
|
-
else {
|
|
974
|
-
logPromise = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port, logDurationSeconds * 1000, logMaxLogs, logMode === "single" || logMode === "auto");
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
catch (error) {
|
|
978
|
-
logSetupWarning = `日志监听未启动: ${error instanceof Error ? error.message : String(error)}`;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
904
|
const target = await resolvePreferredRuntimeTarget({
|
|
982
905
|
transport,
|
|
983
906
|
ip,
|
|
@@ -998,31 +921,11 @@ function registerRuntimeTools(server) {
|
|
|
998
921
|
transport: "http",
|
|
999
922
|
workspacePath: workspace,
|
|
1000
923
|
});
|
|
1001
|
-
let logSection = "";
|
|
1002
|
-
if (logPromise) {
|
|
1003
|
-
const result = await logPromise;
|
|
1004
|
-
const sections = [
|
|
1005
|
-
formatRunLogSection(logDeviceIp, logDevicePort, logDurationSeconds, result),
|
|
1006
|
-
];
|
|
1007
|
-
if (logMode === "auto") {
|
|
1008
|
-
const latestIsRunning = getLatestIsRunning(result);
|
|
1009
|
-
if (result.stopReason === "timeout" && latestIsRunning === true) {
|
|
1010
|
-
sections.push(startBackgroundContinuousLogWatch(logDeviceIp, logDevicePort, logMaxLogs));
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
logSection = `\n\n${sections.join("\n")}`;
|
|
1014
|
-
}
|
|
1015
|
-
else if (logModeNotice) {
|
|
1016
|
-
logSection = `\n\n${logModeNotice}`;
|
|
1017
|
-
}
|
|
1018
|
-
else if (logSetupWarning) {
|
|
1019
|
-
logSection = `\n\n${logSetupWarning}`;
|
|
1020
|
-
}
|
|
1021
924
|
return {
|
|
1022
925
|
content: [
|
|
1023
926
|
{
|
|
1024
927
|
type: "text",
|
|
1025
|
-
text: `UI 预览请求已发送到 ${target.label}
|
|
928
|
+
text: `UI 预览请求已发送到 ${target.label}`,
|
|
1026
929
|
},
|
|
1027
930
|
],
|
|
1028
931
|
};
|
package/dist/project.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export interface DeviceLogWatchResult {
|
|
|
38
38
|
/** 收集到的 runtime_status 条目 */
|
|
39
39
|
runtimeStatus: DeviceRuntimeStatusEntry[];
|
|
40
40
|
/** 监听结束原因 */
|
|
41
|
-
stopReason: "timeout" | "runtime_stopped" | "stream_closed" | "manual_abort" | "unknown";
|
|
41
|
+
stopReason: "timeout" | "runtime_continuous" | "runtime_stopped" | "stream_closed" | "manual_abort" | "unknown";
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* 在设备上获取截图 JPG 二进制数据(HTTP)
|
|
@@ -73,11 +73,12 @@ export declare function getSourceOnDevice(options: DeviceCliOptions, maxDepth?:
|
|
|
73
73
|
* @param durationMs 监听时长(毫秒),默认 15000;传 0 表示不设超时,持续监听
|
|
74
74
|
* @param maxLogs 最多收集日志条数,默认 200
|
|
75
75
|
* @param stopOnRuntimeStopped 若为 true,则在运行状态从 true 回落到 false 后结束监听
|
|
76
|
+
* @param stopOnRuntimeContinuous 若为 true,则在确认持续运行态后结束监听(用于 single 模式快速返回)
|
|
76
77
|
* @returns 返回日志与运行状态
|
|
77
78
|
* @example
|
|
78
|
-
* const result = await watchDeviceLogsBySse("192.168.1.10", 9800, 30000, 300, true)
|
|
79
|
+
* const result = await watchDeviceLogsBySse("192.168.1.10", 9800, 30000, 300, true, true)
|
|
79
80
|
*/
|
|
80
|
-
export declare function watchDeviceLogsBySse(ip: string, port: number, durationMs?: number, maxLogs?: number, stopOnRuntimeStopped?: boolean): Promise<DeviceLogWatchResult>;
|
|
81
|
+
export declare function watchDeviceLogsBySse(ip: string, port: number, durationMs?: number, maxLogs?: number, stopOnRuntimeStopped?: boolean, stopOnRuntimeContinuous?: boolean): Promise<DeviceLogWatchResult>;
|
|
81
82
|
/**
|
|
82
83
|
* 在设备上运行项目(先同步后运行)
|
|
83
84
|
* @param options 命令选项
|
package/dist/project.js
CHANGED
|
@@ -516,11 +516,12 @@ function normalizeLogEntry(payload) {
|
|
|
516
516
|
* @param durationMs 监听时长(毫秒),默认 15000;传 0 表示不设超时,持续监听
|
|
517
517
|
* @param maxLogs 最多收集日志条数,默认 200
|
|
518
518
|
* @param stopOnRuntimeStopped 若为 true,则在运行状态从 true 回落到 false 后结束监听
|
|
519
|
+
* @param stopOnRuntimeContinuous 若为 true,则在确认持续运行态后结束监听(用于 single 模式快速返回)
|
|
519
520
|
* @returns 返回日志与运行状态
|
|
520
521
|
* @example
|
|
521
|
-
* const result = await watchDeviceLogsBySse("192.168.1.10", 9800, 30000, 300, true)
|
|
522
|
+
* const result = await watchDeviceLogsBySse("192.168.1.10", 9800, 30000, 300, true, true)
|
|
522
523
|
*/
|
|
523
|
-
async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200, stopOnRuntimeStopped = false) {
|
|
524
|
+
async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200, stopOnRuntimeStopped = false, stopOnRuntimeContinuous = false) {
|
|
524
525
|
if (!ip.trim()) {
|
|
525
526
|
throw new Error("监听日志失败: 设备 IP 不能为空");
|
|
526
527
|
}
|
|
@@ -539,6 +540,7 @@ async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200,
|
|
|
539
540
|
const controller = new AbortController();
|
|
540
541
|
let stopReason = "unknown";
|
|
541
542
|
let seenRunningStatus = false;
|
|
543
|
+
let runningStatusCount = 0;
|
|
542
544
|
const timeoutHandle = durationMs > 0
|
|
543
545
|
? setTimeout(() => {
|
|
544
546
|
stopReason = "timeout";
|
|
@@ -594,6 +596,16 @@ async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200,
|
|
|
594
596
|
});
|
|
595
597
|
if (parsed.isRunning === true) {
|
|
596
598
|
seenRunningStatus = true;
|
|
599
|
+
runningStatusCount += 1;
|
|
600
|
+
// 连续收到运行态,视为长期任务,single 模式可立即返回并转持续监听
|
|
601
|
+
if (stopOnRuntimeContinuous && runningStatusCount >= 2) {
|
|
602
|
+
stopReason = "runtime_continuous";
|
|
603
|
+
controller.abort();
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
else if (parsed.isRunning === false) {
|
|
608
|
+
runningStatusCount = 0;
|
|
597
609
|
}
|
|
598
610
|
if (stopOnRuntimeStopped &&
|
|
599
611
|
seenRunningStatus &&
|