ms-vite-plugin 1.1.9 → 1.1.11
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 +65 -60
- package/dist/project.d.ts +4 -3
- package/dist/project.js +23 -2
- package/package.json +1 -1
package/dist/mcp/tools.js
CHANGED
|
@@ -270,13 +270,15 @@ function registerDocTools(server) {
|
|
|
270
270
|
*/
|
|
271
271
|
function registerRuntimeTools(server) {
|
|
272
272
|
/**
|
|
273
|
-
* MCP
|
|
273
|
+
* MCP 进程内当前工作目录(仅内存态,不落盘)
|
|
274
|
+
* 说明:用于同一轮 MCP 进程内复用目录,进程重启后需由 AI 再次调用 set_workspace 设置。
|
|
274
275
|
*/
|
|
275
276
|
let currentWorkspacePath;
|
|
276
277
|
/**
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* @
|
|
278
|
+
* 解析本次调用使用的工作目录
|
|
279
|
+
* 优先级:workspacePath 参数 > set_workspace 记忆值
|
|
280
|
+
* @param workspacePath 可选工作目录
|
|
281
|
+
* @returns 返回生效的绝对路径
|
|
280
282
|
* @example
|
|
281
283
|
* const workspace = resolveWorkspacePath("/Users/demo/project")
|
|
282
284
|
*/
|
|
@@ -288,7 +290,7 @@ function registerRuntimeTools(server) {
|
|
|
288
290
|
if (currentWorkspacePath) {
|
|
289
291
|
return currentWorkspacePath;
|
|
290
292
|
}
|
|
291
|
-
|
|
293
|
+
throw new Error("未设置工作目录:请先调用 set_workspace,或在本次工具调用时传 workspacePath。");
|
|
292
294
|
}
|
|
293
295
|
/**
|
|
294
296
|
* 校验并返回有效工作目录
|
|
@@ -302,6 +304,50 @@ function registerRuntimeTools(server) {
|
|
|
302
304
|
await (0, project_2.ensureValidKuaiJSProject)(workspace);
|
|
303
305
|
return workspace;
|
|
304
306
|
}
|
|
307
|
+
server.registerTool("set_workspace", {
|
|
308
|
+
title: "Set Workspace",
|
|
309
|
+
description: "设置当前 MCP 进程内的默认工作目录。后续 build/run/package 优先使用该目录。",
|
|
310
|
+
inputSchema: {
|
|
311
|
+
workspacePath: z
|
|
312
|
+
.string()
|
|
313
|
+
.min(1)
|
|
314
|
+
.describe("快点JS 项目目录绝对路径(需包含 package.json 与 scripts)"),
|
|
315
|
+
},
|
|
316
|
+
}, async ({ workspacePath }) => {
|
|
317
|
+
const workspace = await ensureWorkspacePath(workspacePath);
|
|
318
|
+
return {
|
|
319
|
+
content: [
|
|
320
|
+
{
|
|
321
|
+
type: "text",
|
|
322
|
+
text: `默认工作目录已设置为: ${workspace}`,
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
server.registerTool("get_workspace", {
|
|
328
|
+
title: "Get Workspace",
|
|
329
|
+
description: "查看当前 MCP 进程内记忆的工作目录。",
|
|
330
|
+
inputSchema: {},
|
|
331
|
+
}, async () => {
|
|
332
|
+
if (!currentWorkspacePath) {
|
|
333
|
+
return {
|
|
334
|
+
content: [
|
|
335
|
+
{
|
|
336
|
+
type: "text",
|
|
337
|
+
text: "当前未设置工作目录,请先调用 set_workspace。",
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
content: [
|
|
344
|
+
{
|
|
345
|
+
type: "text",
|
|
346
|
+
text: `当前工作目录: ${currentWorkspacePath}`,
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
};
|
|
350
|
+
});
|
|
305
351
|
/**
|
|
306
352
|
* 格式化运行期日志结果(供 run/run_ui 直接回传)
|
|
307
353
|
* @param ip 设备 IP
|
|
@@ -381,41 +427,6 @@ function registerRuntimeTools(server) {
|
|
|
381
427
|
label: `${device.ip}:${device.port}`,
|
|
382
428
|
};
|
|
383
429
|
}
|
|
384
|
-
server.registerTool("set_workspace", {
|
|
385
|
-
title: "Set Workspace",
|
|
386
|
-
description: "设置默认工作目录。后续 build/run/package/watch 等工具会优先使用该目录。",
|
|
387
|
-
inputSchema: {
|
|
388
|
-
workspacePath: z
|
|
389
|
-
.string()
|
|
390
|
-
.min(1)
|
|
391
|
-
.describe("快点JS 项目目录绝对路径(需包含 package.json 与 scripts)"),
|
|
392
|
-
},
|
|
393
|
-
}, async ({ workspacePath }) => {
|
|
394
|
-
const workspace = await ensureWorkspacePath(workspacePath);
|
|
395
|
-
return {
|
|
396
|
-
content: [
|
|
397
|
-
{
|
|
398
|
-
type: "text",
|
|
399
|
-
text: `默认工作目录已设置为: ${workspace}`,
|
|
400
|
-
},
|
|
401
|
-
],
|
|
402
|
-
};
|
|
403
|
-
});
|
|
404
|
-
server.registerTool("get_workspace", {
|
|
405
|
-
title: "Get Workspace",
|
|
406
|
-
description: "查看当前 MCP 生效的工作目录。",
|
|
407
|
-
inputSchema: {},
|
|
408
|
-
}, async () => {
|
|
409
|
-
const workspace = resolveWorkspacePath();
|
|
410
|
-
return {
|
|
411
|
-
content: [
|
|
412
|
-
{
|
|
413
|
-
type: "text",
|
|
414
|
-
text: `当前工作目录: ${workspace}`,
|
|
415
|
-
},
|
|
416
|
-
],
|
|
417
|
-
};
|
|
418
|
-
});
|
|
419
430
|
server.registerTool("set_device", {
|
|
420
431
|
title: "Set Device",
|
|
421
432
|
description: "设置默认设备连接信息。首次配置后,后续 run/stop 可不再传 ip。",
|
|
@@ -635,11 +646,6 @@ function registerRuntimeTools(server) {
|
|
|
635
646
|
title: "Watch Logs",
|
|
636
647
|
description: "通过 SSE 监听设备实时日志。首次可传 ip,也可复用 set_device 保存的默认设备。",
|
|
637
648
|
inputSchema: {
|
|
638
|
-
workspacePath: z
|
|
639
|
-
.string()
|
|
640
|
-
.min(1)
|
|
641
|
-
.optional()
|
|
642
|
-
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
643
649
|
ip: z
|
|
644
650
|
.string()
|
|
645
651
|
.min(1)
|
|
@@ -669,8 +675,7 @@ function registerRuntimeTools(server) {
|
|
|
669
675
|
.default(200)
|
|
670
676
|
.describe("最多收集日志条数,默认 200"),
|
|
671
677
|
},
|
|
672
|
-
}, async ({
|
|
673
|
-
await ensureWorkspacePath(workspacePath);
|
|
678
|
+
}, async ({ ip, port, durationSeconds, maxLogs }) => {
|
|
674
679
|
const device = await (0, device_config_1.resolveDeviceConfig)(ip, port);
|
|
675
680
|
const result = await (0, project_1.watchDeviceLogsBySse)(device.ip, device.port, durationSeconds * 1000, maxLogs);
|
|
676
681
|
const logsPreview = result.logs
|
|
@@ -701,7 +706,7 @@ function registerRuntimeTools(server) {
|
|
|
701
706
|
.string()
|
|
702
707
|
.min(1)
|
|
703
708
|
.optional()
|
|
704
|
-
.describe("可选工作目录;不传时使用 set_workspace
|
|
709
|
+
.describe("可选工作目录;不传时使用 set_workspace 记忆值"),
|
|
705
710
|
dev: z
|
|
706
711
|
.boolean()
|
|
707
712
|
.optional()
|
|
@@ -724,7 +729,7 @@ function registerRuntimeTools(server) {
|
|
|
724
729
|
.string()
|
|
725
730
|
.min(1)
|
|
726
731
|
.optional()
|
|
727
|
-
.describe("可选工作目录;不传时使用 set_workspace
|
|
732
|
+
.describe("可选工作目录;不传时使用 set_workspace 记忆值"),
|
|
728
733
|
},
|
|
729
734
|
}, async ({ workspacePath }) => {
|
|
730
735
|
const workspace = await ensureWorkspacePath(workspacePath);
|
|
@@ -771,7 +776,7 @@ function registerRuntimeTools(server) {
|
|
|
771
776
|
.string()
|
|
772
777
|
.min(1)
|
|
773
778
|
.optional()
|
|
774
|
-
.describe("可选工作目录;不传时使用 set_workspace
|
|
779
|
+
.describe("可选工作目录;不传时使用 set_workspace 记忆值"),
|
|
775
780
|
watchLogs: z
|
|
776
781
|
.boolean()
|
|
777
782
|
.optional()
|
|
@@ -808,7 +813,7 @@ function registerRuntimeTools(server) {
|
|
|
808
813
|
logModeNotice = startBackgroundContinuousLogWatch(logDevice.ip, logDevice.port, logMaxLogs);
|
|
809
814
|
}
|
|
810
815
|
else {
|
|
811
|
-
logPromise = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port, 0, logMaxLogs, true);
|
|
816
|
+
logPromise = (0, project_1.watchDeviceLogsBySse)(logDevice.ip, logDevice.port, 0, logMaxLogs, true, true);
|
|
812
817
|
}
|
|
813
818
|
}
|
|
814
819
|
catch (error) {
|
|
@@ -838,7 +843,13 @@ function registerRuntimeTools(server) {
|
|
|
838
843
|
let logSection = "";
|
|
839
844
|
if (logPromise) {
|
|
840
845
|
const result = await logPromise;
|
|
841
|
-
|
|
846
|
+
const sections = [
|
|
847
|
+
formatRunLogSection(logDeviceIp, logDevicePort, result),
|
|
848
|
+
];
|
|
849
|
+
if (result.stopReason === "runtime_continuous") {
|
|
850
|
+
sections.push(startBackgroundContinuousLogWatch(logDeviceIp, logDevicePort, logMaxLogs));
|
|
851
|
+
}
|
|
852
|
+
logSection = `\n\n${sections.join("\n")}`;
|
|
842
853
|
}
|
|
843
854
|
else if (logModeNotice) {
|
|
844
855
|
logSection = `\n\n${logModeNotice}`;
|
|
@@ -893,7 +904,7 @@ function registerRuntimeTools(server) {
|
|
|
893
904
|
.string()
|
|
894
905
|
.min(1)
|
|
895
906
|
.optional()
|
|
896
|
-
.describe("可选工作目录;不传时使用 set_workspace
|
|
907
|
+
.describe("可选工作目录;不传时使用 set_workspace 记忆值"),
|
|
897
908
|
},
|
|
898
909
|
}, async ({ transport, ip, port, wsPort, wsWaitMs, workspacePath }) => {
|
|
899
910
|
const workspace = await ensureWorkspacePath(workspacePath);
|
|
@@ -960,14 +971,8 @@ function registerRuntimeTools(server) {
|
|
|
960
971
|
.max(600000)
|
|
961
972
|
.optional()
|
|
962
973
|
.describe("WS 等待连接超时毫秒(transport=ws 时可选,默认 30000)"),
|
|
963
|
-
workspacePath: z
|
|
964
|
-
.string()
|
|
965
|
-
.min(1)
|
|
966
|
-
.optional()
|
|
967
|
-
.describe("可选工作目录;不传时使用 set_workspace 记录值或 MCP 启动目录"),
|
|
968
974
|
},
|
|
969
|
-
}, async ({ transport, ip, port, wsPort, wsWaitMs
|
|
970
|
-
resolveWorkspacePath(workspacePath);
|
|
975
|
+
}, async ({ transport, ip, port, wsPort, wsWaitMs }) => {
|
|
971
976
|
const target = await resolvePreferredRuntimeTarget({
|
|
972
977
|
transport,
|
|
973
978
|
ip,
|
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,8 @@ 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;
|
|
544
|
+
let shouldStopReading = false;
|
|
542
545
|
const timeoutHandle = durationMs > 0
|
|
543
546
|
? setTimeout(() => {
|
|
544
547
|
stopReason = "timeout";
|
|
@@ -560,6 +563,9 @@ async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200,
|
|
|
560
563
|
const decoder = new TextDecoder("utf-8");
|
|
561
564
|
let buffer = "";
|
|
562
565
|
while (true) {
|
|
566
|
+
if (shouldStopReading) {
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
563
569
|
const { value, done } = await reader.read();
|
|
564
570
|
if (done) {
|
|
565
571
|
if (stopReason === "unknown") {
|
|
@@ -594,12 +600,24 @@ async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200,
|
|
|
594
600
|
});
|
|
595
601
|
if (parsed.isRunning === true) {
|
|
596
602
|
seenRunningStatus = true;
|
|
603
|
+
runningStatusCount += 1;
|
|
604
|
+
// 连续收到运行态,视为长期任务,single 模式可立即返回并转持续监听
|
|
605
|
+
if (stopOnRuntimeContinuous && runningStatusCount >= 2) {
|
|
606
|
+
stopReason = "runtime_continuous";
|
|
607
|
+
controller.abort();
|
|
608
|
+
shouldStopReading = true;
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
else if (parsed.isRunning === false) {
|
|
613
|
+
runningStatusCount = 0;
|
|
597
614
|
}
|
|
598
615
|
if (stopOnRuntimeStopped &&
|
|
599
616
|
seenRunningStatus &&
|
|
600
617
|
parsed.isRunning === false) {
|
|
601
618
|
stopReason = "runtime_stopped";
|
|
602
619
|
controller.abort();
|
|
620
|
+
shouldStopReading = true;
|
|
603
621
|
break;
|
|
604
622
|
}
|
|
605
623
|
}
|
|
@@ -610,6 +628,9 @@ async function watchDeviceLogsBySse(ip, port, durationMs = 15000, maxLogs = 200,
|
|
|
610
628
|
}
|
|
611
629
|
splitIndex = buffer.search(/\r?\n\r?\n/);
|
|
612
630
|
}
|
|
631
|
+
if (shouldStopReading) {
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
613
634
|
}
|
|
614
635
|
}
|
|
615
636
|
catch (error) {
|