ms-vite-plugin 1.4.14 → 1.4.16
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/cli.js +1002 -9
- package/dist/mcp/device-log.d.ts +7 -22
- package/dist/mcp/device-log.js +20 -383
- package/dist/mcp/doc-tools.d.ts +0 -8
- package/dist/mcp/doc-tools.js +40 -93
- package/dist/mcp/docs-service.d.ts +0 -23
- package/dist/mcp/docs-service.js +0 -40
- package/dist/mcp/httpapi-docs-service.d.ts +9 -0
- package/dist/mcp/httpapi-docs-service.js +3 -7
- package/dist/mcp/httpapi-tools.js +3 -1
- package/dist/mcp/image-tools.d.ts +69 -0
- package/dist/mcp/image-tools.js +163 -0
- package/dist/mcp/ocr-tools.d.ts +50 -0
- package/dist/mcp/ocr-tools.js +59 -48
- package/dist/mcp/runtime-tools.js +16 -23
- package/dist/mcp/tool-utils.d.ts +3 -2
- package/dist/mcp/tool-utils.js +9 -3
- package/dist/mcp/tools.js +0 -1
- package/dist/project.d.ts +15 -40
- package/dist/project.js +36 -186
- package/docs/AGENTS.md +46 -36
- package/docs/SKILL.md +46 -29
- package/docs/api/paddleocr.md +11 -33
- package/docs/apicn/paddleocr.md +5 -29
- package/docs/apipython/paddleocr.md +34 -55
- package/docs/mcp-agent-description.md +53 -43
- package/package.json +1 -1
package/dist/project.js
CHANGED
|
@@ -39,7 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.getScreenshotOnDevice = getScreenshotOnDevice;
|
|
40
40
|
exports.getScreenshotBase64OnDevice = getScreenshotBase64OnDevice;
|
|
41
41
|
exports.getSourceOnDevice = getSourceOnDevice;
|
|
42
|
-
exports.
|
|
42
|
+
exports.getCurrentLogLinesOnDevice = getCurrentLogLinesOnDevice;
|
|
43
43
|
exports.runOnDevice = runOnDevice;
|
|
44
44
|
exports.runUIOnDevice = runUIOnDevice;
|
|
45
45
|
exports.stopOnDevice = stopOnDevice;
|
|
@@ -428,11 +428,12 @@ async function getScreenshotBase64OnDevice(options) {
|
|
|
428
428
|
* @param options 命令选项(transport 仅支持 http)
|
|
429
429
|
* @param maxDepth 节点最大深度,默认 50
|
|
430
430
|
* @param timeout 获取节点超时秒数,默认 120
|
|
431
|
+
* @param mode 节点抓取模式,1=完整节点树,2=可见节点优化模式
|
|
431
432
|
* @returns 返回 XML 字符串
|
|
432
433
|
* @example
|
|
433
|
-
* const xml = await getSourceOnDevice({ ip: "192.168.1.10", port: "9800" }, 50, 120)
|
|
434
|
+
* const xml = await getSourceOnDevice({ ip: "192.168.1.10", port: "9800" }, 50, 120, 1)
|
|
434
435
|
*/
|
|
435
|
-
async function getSourceOnDevice(options, maxDepth = 50, timeout = 120) {
|
|
436
|
+
async function getSourceOnDevice(options, maxDepth = 50, timeout = 120, mode = 1) {
|
|
436
437
|
const transport = parseTransport(options);
|
|
437
438
|
if (!Number.isInteger(maxDepth) || maxDepth < 1) {
|
|
438
439
|
throw new Error(`无效 maxDepth: ${maxDepth}`);
|
|
@@ -440,12 +441,16 @@ async function getSourceOnDevice(options, maxDepth = 50, timeout = 120) {
|
|
|
440
441
|
if (!Number.isInteger(timeout) || timeout < 1) {
|
|
441
442
|
throw new Error(`无效 timeout: ${timeout}`);
|
|
442
443
|
}
|
|
444
|
+
if (!Number.isInteger(mode) || (mode !== 1 && mode !== 2)) {
|
|
445
|
+
throw new Error(`无效 mode: ${mode}`);
|
|
446
|
+
}
|
|
443
447
|
if (transport === "ws") {
|
|
444
448
|
await ensureWsReady(options);
|
|
445
449
|
const result = await ws_manager_1.WSManager.request("source", {
|
|
446
450
|
max_depth: maxDepth,
|
|
447
451
|
timeout,
|
|
448
452
|
maxDepth,
|
|
453
|
+
mode,
|
|
449
454
|
});
|
|
450
455
|
if (!result.success || typeof result.data !== "string") {
|
|
451
456
|
throw new Error(`获取节点失败: ${String(result.message ?? "unknown")}`);
|
|
@@ -456,6 +461,7 @@ async function getSourceOnDevice(options, maxDepth = 50, timeout = 120) {
|
|
|
456
461
|
const url = new URL(`http://${ip}:${port}/api/source`);
|
|
457
462
|
url.searchParams.set("max_depth", String(maxDepth));
|
|
458
463
|
url.searchParams.set("timeout", String(timeout));
|
|
464
|
+
url.searchParams.set("mode", String(mode));
|
|
459
465
|
const response = await fetch(url.toString(), { method: "GET" });
|
|
460
466
|
if (!response.ok) {
|
|
461
467
|
throw new Error(`获取节点失败,状态码: ${response.status}`);
|
|
@@ -463,196 +469,40 @@ async function getSourceOnDevice(options, maxDepth = 50, timeout = 120) {
|
|
|
463
469
|
return response.text();
|
|
464
470
|
}
|
|
465
471
|
/**
|
|
466
|
-
*
|
|
467
|
-
* @param
|
|
468
|
-
* @
|
|
469
|
-
* @
|
|
470
|
-
* parseSseEventBlock("event: log\ndata: {\"level\":\"info\"}")
|
|
471
|
-
*/
|
|
472
|
-
function parseSseEventBlock(rawBlock) {
|
|
473
|
-
const lines = rawBlock.split(/\r?\n/);
|
|
474
|
-
let eventName = "message";
|
|
475
|
-
const dataLines = [];
|
|
476
|
-
for (const line of lines) {
|
|
477
|
-
if (!line || line.startsWith(":")) {
|
|
478
|
-
continue;
|
|
479
|
-
}
|
|
480
|
-
if (line.startsWith("event:")) {
|
|
481
|
-
eventName = line.slice("event:".length).trim() || "message";
|
|
482
|
-
continue;
|
|
483
|
-
}
|
|
484
|
-
if (line.startsWith("data:")) {
|
|
485
|
-
dataLines.push(line.slice("data:".length).trimStart());
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
return {
|
|
489
|
-
event: eventName,
|
|
490
|
-
data: dataLines.join("\n"),
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* 将原始日志对象标准化为 DeviceLogEntry
|
|
495
|
-
* @param payload 日志原始对象
|
|
496
|
-
* @returns 返回标准化日志对象
|
|
497
|
-
* @example
|
|
498
|
-
* normalizeLogEntry({ level: "info", message: "ok", timestamp: "2026-01-01T00:00:00Z" })
|
|
499
|
-
*/
|
|
500
|
-
function normalizeLogEntry(payload) {
|
|
501
|
-
const levelText = String(payload.level ?? "info").toLowerCase();
|
|
502
|
-
const messageText = String(payload.message ?? "");
|
|
503
|
-
const timestampText = typeof payload.timestamp === "string" && payload.timestamp
|
|
504
|
-
? payload.timestamp
|
|
505
|
-
: new Date().toISOString();
|
|
506
|
-
return {
|
|
507
|
-
level: levelText,
|
|
508
|
-
message: messageText,
|
|
509
|
-
timestamp: timestampText,
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* 监听设备 SSE 日志并返回原始结果
|
|
514
|
-
* @param ip 设备 IP 地址
|
|
515
|
-
* @param port 设备端口
|
|
516
|
-
* @param durationMs 监听时长(毫秒),默认 15000;传 0 表示不设超时,持续监听
|
|
517
|
-
* @param maxLogs 最多收集日志条数,默认 200
|
|
518
|
-
* @param stopOnRuntimeStopped 若为 true,则在运行状态从 true 回落到 false 后结束监听
|
|
519
|
-
* @param stopOnRuntimeContinuous 若为 true,则在确认持续运行态后结束监听(用于 single 模式快速返回)
|
|
520
|
-
* @returns 返回日志与运行状态
|
|
472
|
+
* 在设备上获取当前日志文件最新行
|
|
473
|
+
* @param options 命令选项(仅支持 http 传输)
|
|
474
|
+
* @param count 需要读取的最新日志行数,默认 200,最大 5000
|
|
475
|
+
* @returns 返回最新日志行和是否还有更早日志
|
|
521
476
|
* @example
|
|
522
|
-
* const result = await
|
|
477
|
+
* const result = await getCurrentLogLinesOnDevice({ ip: "192.168.1.10", port: "9800" }, 200)
|
|
523
478
|
*/
|
|
524
|
-
async function
|
|
525
|
-
|
|
526
|
-
|
|
479
|
+
async function getCurrentLogLinesOnDevice(options, count = 200) {
|
|
480
|
+
const transport = parseTransport(options);
|
|
481
|
+
if (transport !== "http") {
|
|
482
|
+
throw new Error("获取日志失败: 当前日志行接口仅支持 http 传输");
|
|
527
483
|
}
|
|
528
|
-
if (!Number.isInteger(
|
|
529
|
-
throw new Error(
|
|
530
|
-
}
|
|
531
|
-
if (!Number.isInteger(durationMs) || durationMs < 0) {
|
|
532
|
-
throw new Error(`监听日志失败: 无效 durationMs ${durationMs}`);
|
|
533
|
-
}
|
|
534
|
-
if (!Number.isInteger(maxLogs) || maxLogs < 1) {
|
|
535
|
-
throw new Error(`监听日志失败: 无效 maxLogs ${maxLogs}`);
|
|
536
|
-
}
|
|
537
|
-
const url = `http://${ip}:${port}/logger/sse`;
|
|
538
|
-
const logs = [];
|
|
539
|
-
const runtimeStatus = [];
|
|
540
|
-
const controller = new AbortController();
|
|
541
|
-
let stopReason = "unknown";
|
|
542
|
-
let seenRunningStatus = false;
|
|
543
|
-
let runningStatusCount = 0;
|
|
544
|
-
let shouldStopReading = false;
|
|
545
|
-
const timeoutHandle = durationMs > 0
|
|
546
|
-
? setTimeout(() => {
|
|
547
|
-
stopReason = "timeout";
|
|
548
|
-
controller.abort();
|
|
549
|
-
}, durationMs)
|
|
550
|
-
: undefined;
|
|
551
|
-
try {
|
|
552
|
-
const response = await fetch(url, {
|
|
553
|
-
method: "GET",
|
|
554
|
-
signal: controller.signal,
|
|
555
|
-
headers: {
|
|
556
|
-
Accept: "text/event-stream",
|
|
557
|
-
},
|
|
558
|
-
});
|
|
559
|
-
if (!response.ok || !response.body) {
|
|
560
|
-
throw new Error(`监听日志失败: ${response.status} ${response.statusText || "unknown"}`);
|
|
561
|
-
}
|
|
562
|
-
const reader = response.body.getReader();
|
|
563
|
-
const decoder = new TextDecoder("utf-8");
|
|
564
|
-
let buffer = "";
|
|
565
|
-
while (true) {
|
|
566
|
-
if (shouldStopReading) {
|
|
567
|
-
break;
|
|
568
|
-
}
|
|
569
|
-
const { value, done } = await reader.read();
|
|
570
|
-
if (done) {
|
|
571
|
-
if (stopReason === "unknown") {
|
|
572
|
-
stopReason = "stream_closed";
|
|
573
|
-
}
|
|
574
|
-
break;
|
|
575
|
-
}
|
|
576
|
-
buffer += decoder.decode(value, { stream: true });
|
|
577
|
-
// SSE 事件以双换行分隔,这里逐块解析,避免半包解析错误
|
|
578
|
-
let splitIndex = buffer.search(/\r?\n\r?\n/);
|
|
579
|
-
while (splitIndex >= 0) {
|
|
580
|
-
const rawBlock = buffer.slice(0, splitIndex);
|
|
581
|
-
buffer = buffer.slice(splitIndex + (buffer[splitIndex] === "\r" ? 4 : 2));
|
|
582
|
-
const event = parseSseEventBlock(rawBlock);
|
|
583
|
-
if (event.data) {
|
|
584
|
-
try {
|
|
585
|
-
const parsed = JSON.parse(event.data);
|
|
586
|
-
if (event.event === "log") {
|
|
587
|
-
// 日志缓冲使用环形窗口,持续监听时不会无限增长
|
|
588
|
-
if (logs.length >= maxLogs) {
|
|
589
|
-
logs.shift();
|
|
590
|
-
}
|
|
591
|
-
logs.push(normalizeLogEntry(parsed));
|
|
592
|
-
}
|
|
593
|
-
else if (event.event === "runtime_status") {
|
|
594
|
-
if (runtimeStatus.length >= maxLogs) {
|
|
595
|
-
runtimeStatus.shift();
|
|
596
|
-
}
|
|
597
|
-
runtimeStatus.push({
|
|
598
|
-
raw: parsed,
|
|
599
|
-
timestamp: new Date().toISOString(),
|
|
600
|
-
});
|
|
601
|
-
if (parsed.isRunning === true) {
|
|
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;
|
|
614
|
-
}
|
|
615
|
-
if (stopOnRuntimeStopped &&
|
|
616
|
-
seenRunningStatus &&
|
|
617
|
-
parsed.isRunning === false) {
|
|
618
|
-
stopReason = "runtime_stopped";
|
|
619
|
-
controller.abort();
|
|
620
|
-
shouldStopReading = true;
|
|
621
|
-
break;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
catch {
|
|
626
|
-
// 兼容非 JSON 数据:不抛错,继续监听后续事件
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
splitIndex = buffer.search(/\r?\n\r?\n/);
|
|
630
|
-
}
|
|
631
|
-
if (shouldStopReading) {
|
|
632
|
-
break;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
484
|
+
if (!Number.isInteger(count) || count < 1 || count > 5000) {
|
|
485
|
+
throw new Error(`获取日志失败: 无效 count ${count}`);
|
|
635
486
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
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
|
+
};
|
|
646
496
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
clearTimeout(timeoutHandle);
|
|
650
|
-
}
|
|
497
|
+
if (!response.ok) {
|
|
498
|
+
throw new Error(`获取日志失败,状态码: ${response.status}`);
|
|
651
499
|
}
|
|
500
|
+
const payload = (await response.json());
|
|
652
501
|
return {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
502
|
+
lines: Array.isArray(payload.lines)
|
|
503
|
+
? payload.lines.map((line) => String(line))
|
|
504
|
+
: [],
|
|
505
|
+
hasMore: payload.hasMore === true,
|
|
656
506
|
};
|
|
657
507
|
}
|
|
658
508
|
/**
|
package/docs/AGENTS.md
CHANGED
|
@@ -36,26 +36,27 @@
|
|
|
36
36
|
|
|
37
37
|
## 文档优先
|
|
38
38
|
|
|
39
|
-
回答快点JS API
|
|
39
|
+
回答快点JS API 问题或编写脚本前,必须先查询目标语言对应的快点JS文档。
|
|
40
40
|
|
|
41
|
-
MCP
|
|
41
|
+
MCP 入口:
|
|
42
42
|
|
|
43
|
-
1. 使用 `
|
|
44
|
-
2. 使用 `search_api_docs` 搜索相关模块或 API
|
|
45
|
-
3. 使用 `read_api_doc`
|
|
43
|
+
1. 使用 `get_docs_paths` 获取本地文档路径。
|
|
44
|
+
2. 使用 `search_api_docs` 搜索相关模块或 API,按需传 `language`。
|
|
45
|
+
3. 使用 `read_api_doc` 读取完整文档,按需传 `language`。
|
|
46
46
|
4. 只依据已确认的文档内容回答或编写代码。
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
CLI 入口:
|
|
49
49
|
|
|
50
|
-
1.
|
|
51
|
-
2.
|
|
52
|
-
3.
|
|
50
|
+
1. 使用 `npx ms docs paths` 获取本地文档路径。
|
|
51
|
+
2. 使用 `npx ms docs search <query> --language js_zh|js|python` 搜索语言 API 文档。
|
|
52
|
+
3. 使用 `npx ms docs read <slug> --language js_zh|js|python` 读取完整文档。
|
|
53
|
+
4. 只使用文档中已经确认的 API。
|
|
53
54
|
|
|
54
55
|
## HTTP API 工作流
|
|
55
56
|
|
|
56
57
|
调用设备 HTTP API 前,必须先查询 HTTP API 文档。不要猜测接口路径、请求方法或参数名称。
|
|
57
58
|
|
|
58
|
-
MCP
|
|
59
|
+
MCP 入口:
|
|
59
60
|
|
|
60
61
|
1. 使用 `search_http_api_docs` 搜索目标能力、中文标题或接口路径。
|
|
61
62
|
2. 使用 `read_http_api_doc` 读取目标接口片段。
|
|
@@ -64,17 +65,19 @@ MCP 可用时:
|
|
|
64
65
|
|
|
65
66
|
`http_api_call` 只能调用 HTTP API 文档中已声明的接口,并且会校验 `docSlug`、`method`、`path` 是否匹配。
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
CLI 入口:
|
|
68
69
|
|
|
69
|
-
1.
|
|
70
|
-
2.
|
|
71
|
-
3.
|
|
70
|
+
1. 使用 `npx ms docs paths` 获取 HTTP API 文档路径。
|
|
71
|
+
2. 使用 `npx ms http-docs search <query>` 搜索目标接口。
|
|
72
|
+
3. 使用 `npx ms http-docs read <identifier> --method GET|POST` 读取目标接口片段。
|
|
73
|
+
4. 使用 `npx ms http-call -i <device-ip> --port <port> --method <method> --path <path> --doc-slug <slug>` 调用明确存在的接口。
|
|
74
|
+
5. 不要把未确认的路径当成可用接口。
|
|
72
75
|
|
|
73
76
|
## 设备与运行
|
|
74
77
|
|
|
75
78
|
设备相关操作以用户指定的设备为准。不要假设设备或工作区已经设置。
|
|
76
79
|
|
|
77
|
-
MCP
|
|
80
|
+
MCP 入口:
|
|
78
81
|
|
|
79
82
|
1. 使用 `get_device` 查看当前默认设备。
|
|
80
83
|
2. 如果未设置设备,使用 `set_device` 设置设备 IP 和端口。
|
|
@@ -84,25 +87,32 @@ MCP 可用时:
|
|
|
84
87
|
6. 使用 `stop_project` 停止当前设备上的项目。
|
|
85
88
|
7. 使用 `package_project` 执行生产打包。
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
CLI 入口可以使用:
|
|
88
91
|
|
|
89
92
|
```bash
|
|
90
93
|
npx ms --help
|
|
94
|
+
npx ms docs paths
|
|
91
95
|
npx ms run -i <device-ip> --port <port>
|
|
92
96
|
npx ms run-ui -i <device-ip> --port <port>
|
|
93
97
|
npx ms screenshot -i <device-ip> --port <port> --format file --output <path>
|
|
98
|
+
npx ms source -i <device-ip> --port <port> --mode 1 --output <path>
|
|
99
|
+
npx ms logs -i <device-ip> --port <port> --limit 200
|
|
100
|
+
npx ms ocr -i <device-ip> --port <port> --engine appleocr --mode recognize
|
|
101
|
+
npx ms screen-crop -i <device-ip> --port <port> --x <x> --y <y> --width <w> --height <h> --output <path>
|
|
102
|
+
npx ms screen-pick-color -i <device-ip> --port <port> --x <x> --y <y>
|
|
103
|
+
npx ms image-crop --image <path> --x <x> --y <y> --width <w> --height <h> --output <path>
|
|
104
|
+
npx ms image-transparent --image <path> --output <path>
|
|
94
105
|
npx ms stop -i <device-ip> --port <port>
|
|
95
106
|
npx ms package
|
|
96
107
|
```
|
|
97
108
|
|
|
98
|
-
|
|
109
|
+
`build`、`package`、`run`、`run-ui` 需要在快点JS项目根目录运行,项目根目录通常包含 `package.json` 和 `scripts/`。文档、HTTP API 查询/调用、截图、节点、日志、OCR、图片处理、停止和 WS 状态命令可以在任意目录使用。不要用未确认的通用 Node.js、浏览器或 Python 命令替代 MCP 或项目自带 `ms` CLI。
|
|
99
110
|
|
|
100
111
|
## 工具分组
|
|
101
112
|
|
|
102
113
|
### 文档
|
|
103
114
|
|
|
104
|
-
- `
|
|
105
|
-
- `get_docs_language`
|
|
115
|
+
- `get_docs_paths`
|
|
106
116
|
- `list_api_docs`
|
|
107
117
|
- `search_api_docs`
|
|
108
118
|
- `read_api_doc`
|
|
@@ -141,28 +151,28 @@ npx ms package
|
|
|
141
151
|
## 工具选择规则
|
|
142
152
|
|
|
143
153
|
- 写快点JS脚本代码:先设置或确认文档语言,再查语言 API 文档。
|
|
144
|
-
- 调设备 HTTP API:先查 HTTP API 文档,再调用 `http_api_call`
|
|
145
|
-
-
|
|
146
|
-
- 获取节点 XML
|
|
147
|
-
-
|
|
148
|
-
- 从本地图片裁切找图模板:使用 `image_crop`,输出到 `res`。
|
|
149
|
-
- 从当前设备截图裁切找图模板:使用 `screen_crop`,输出到 `res`。
|
|
150
|
-
- 从本地图片指定坐标取色:使用 `image_pick_color`。
|
|
151
|
-
- 从当前设备截图指定坐标取色:使用 `screen_pick_color`。
|
|
152
|
-
- 制作透明找图模板:使用 `image_make_transparent`,输出到 `res`。
|
|
153
|
-
- 执行 OCR 识别、数字识别或查找文字:使用 `ocr_recognize`。
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
154
|
+
- 调设备 HTTP API:先查 HTTP API 文档,再调用 `http_api_call` 或 `npx ms http-call`。
|
|
155
|
+
- 获取截图:使用 `take_screenshot` 或 `npx ms screenshot`。
|
|
156
|
+
- 获取节点 XML:使用 `get_node_source` 或 `npx ms source --mode 1`。
|
|
157
|
+
- 查看日志:使用 `get_logs` 或 `npx ms logs`。
|
|
158
|
+
- 从本地图片裁切找图模板:使用 `image_crop` 或 `npx ms image-crop`,输出到 `res`。
|
|
159
|
+
- 从当前设备截图裁切找图模板:使用 `screen_crop` 或 `npx ms screen-crop`,输出到 `res`。
|
|
160
|
+
- 从本地图片指定坐标取色:使用 `image_pick_color` 或 `npx ms image-pick-color`。
|
|
161
|
+
- 从当前设备截图指定坐标取色:使用 `screen_pick_color` 或 `npx ms screen-pick-color`。
|
|
162
|
+
- 制作透明找图模板:使用 `image_make_transparent` 或 `npx ms image-transparent`,输出到 `res`。
|
|
163
|
+
- 执行 OCR 识别、数字识别或查找文字:使用 `ocr_recognize` 或 `npx ms ocr`。
|
|
164
|
+
- 运行项目:使用 `run_project`、`run_ui_project`、`npx ms run` 或 `npx ms run-ui`。
|
|
165
|
+
- 停止项目:使用 `stop_project` 或 `npx ms stop`。
|
|
166
|
+
- 打包项目:使用 `package_project` 或 `npx ms package`。
|
|
157
167
|
|
|
158
168
|
## OCR 规则
|
|
159
169
|
|
|
160
|
-
OCR
|
|
170
|
+
OCR 识别使用 `ocr_recognize`,不要手写未确认的 OCR 调用链路。
|
|
161
171
|
|
|
162
172
|
- `ocr_recognize` 支持 `appleocr` 和 `paddleocr`。
|
|
163
173
|
- 默认使用 `appleocr`。
|
|
164
174
|
- 数字识别优先使用 `appleocr`,因为 PaddleOCR 文档未提供独立 numbers 模式。
|
|
165
|
-
-
|
|
175
|
+
- PaddleOCR 识别和查找方法会自动加载所需模型,不需要先手动调用 `loadV5`。
|
|
166
176
|
|
|
167
177
|
## 验证要求
|
|
168
178
|
|
|
@@ -170,7 +180,7 @@ OCR 没有独立 HTTP 接口,使用 `ocr_recognize` 通过 `POST /api/runScrip
|
|
|
170
180
|
|
|
171
181
|
1. 使用 MCP `run_project` 或命令 `npx ms run -i <device-ip> --port <port>` 同步并运行项目。
|
|
172
182
|
2. 使用 MCP `take_screenshot` 或命令 `npx ms screenshot ...` 获取截图。
|
|
173
|
-
3. 必要时使用 `get_logs`
|
|
183
|
+
3. 必要时使用 `get_logs` 或命令 `npx ms logs` 查看运行日志。
|
|
174
184
|
4. 在回复中说明截图或日志是否确认了预期行为。
|
|
175
185
|
|
|
176
186
|
UI 预览发起后不需要长时间等待结果,可以通过截图查看当前界面效果。
|
|
@@ -184,7 +194,7 @@ UI 预览发起后不需要长时间等待结果,可以通过截图查看当
|
|
|
184
194
|
- 不要混用 JavaScript 与 Python API。
|
|
185
195
|
- 不要把快点JS当成普通 Node.js、浏览器或通用 Python 环境。
|
|
186
196
|
- 不要对快点JS Python 脚本运行 `py_compile` 或其他 CPython 编译校验。
|
|
187
|
-
- 不要在没有查询 HTTP API 文档的情况下调用 `http_api_call` 或 `
|
|
197
|
+
- 不要在没有查询 HTTP API 文档的情况下调用 `http_api_call` 或 `ms http-call`。
|
|
188
198
|
- 不要把完整 URL 传给 `http_api_call.path`,只能传 `/api/...`、`/logger/...`、`/mirror/...` 这类相对路径。
|
|
189
199
|
- 不要调用 HTTP API 文档中未声明的接口。
|
|
190
200
|
- 不要用 `http_api_call` 替代截图落文件、节点 XML 落文件、日志缓存、项目打包和项目运行等专用工具。
|
package/docs/SKILL.md
CHANGED
|
@@ -33,22 +33,32 @@ MCP 工具和项目命令都可以使用。
|
|
|
33
33
|
|
|
34
34
|
可以使用命令的情况:
|
|
35
35
|
|
|
36
|
-
- MCP transport 断开或不可用。
|
|
37
36
|
- 用户明确要求使用命令。
|
|
38
37
|
- 需要快速验证项目本地 `ms` CLI 能力。
|
|
39
|
-
- 使用项目自带 KuaiJS CLI
|
|
38
|
+
- 使用项目自带 KuaiJS CLI 查询文档、调用已确认的 HTTP API、同步、运行、停止、截图、抓节点、查日志和 OCR。
|
|
40
39
|
|
|
41
40
|
允许的常用命令示例:
|
|
42
41
|
|
|
43
42
|
```bash
|
|
44
43
|
npx ms --help
|
|
44
|
+
npx ms docs paths
|
|
45
|
+
npx ms docs search <query> --language js_zh
|
|
46
|
+
npx ms http-docs search <query>
|
|
47
|
+
npx ms http-call -i <device-ip> --port <port> --method GET --path <path> --doc-slug <slug>
|
|
45
48
|
npx ms run -i <device-ip> --port <port>
|
|
46
49
|
npx ms run-ui -i <device-ip> --port <port>
|
|
47
50
|
npx ms screenshot -i <device-ip> --port <port> --format file --output <path>
|
|
51
|
+
npx ms source -i <device-ip> --port <port> --mode 1 --output <path>
|
|
52
|
+
npx ms logs -i <device-ip> --port <port> --limit 200
|
|
53
|
+
npx ms ocr -i <device-ip> --port <port> --engine appleocr --mode recognize
|
|
54
|
+
npx ms screen-crop -i <device-ip> --port <port> --x <x> --y <y> --width <w> --height <h> --output <path>
|
|
55
|
+
npx ms screen-pick-color -i <device-ip> --port <port> --x <x> --y <y>
|
|
56
|
+
npx ms image-crop --image <path> --x <x> --y <y> --width <w> --height <h> --output <path>
|
|
57
|
+
npx ms image-transparent --image <path> --output <path>
|
|
48
58
|
npx ms stop -i <device-ip> --port <port>
|
|
49
59
|
```
|
|
50
60
|
|
|
51
|
-
使用 `
|
|
61
|
+
使用 `ms http-call` 调用设备 HTTP API 前,必须先通过 MCP HTTP API 文档或 `ms http-docs` 确认接口存在、方法、路径、参数位置和返回结构。
|
|
52
62
|
|
|
53
63
|
## 目录职责
|
|
54
64
|
|
|
@@ -74,58 +84,66 @@ npx ms stop -i <device-ip> --port <port>
|
|
|
74
84
|
|
|
75
85
|
回答快点JS API 或编写脚本前,先确认语言并查询对应语言文档。
|
|
76
86
|
|
|
77
|
-
MCP
|
|
87
|
+
MCP 入口:
|
|
78
88
|
|
|
79
|
-
1. 使用 `
|
|
80
|
-
2. 使用 `search_api_docs` 搜索相关模块或 API
|
|
81
|
-
3. 使用 `read_api_doc`
|
|
89
|
+
1. 使用 `get_docs_paths` 获取本地文档路径。
|
|
90
|
+
2. 使用 `search_api_docs` 搜索相关模块或 API,按需传 `language`。
|
|
91
|
+
3. 使用 `read_api_doc` 读取完整文档,按需传 `language`。
|
|
82
92
|
4. 只依据已确认的文档内容回答或编写代码。
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
CLI 入口:
|
|
85
95
|
|
|
86
|
-
1.
|
|
87
|
-
2.
|
|
88
|
-
3.
|
|
96
|
+
1. 使用 `npx ms docs paths` 获取本地文档路径。
|
|
97
|
+
2. 使用 `npx ms docs search <query> --language js_zh|js|python` 搜索语言 API 文档。
|
|
98
|
+
3. 使用 `npx ms docs read <slug> --language js_zh|js|python` 读取完整文档。
|
|
99
|
+
4. 只使用文档中已经确认的 API。
|
|
89
100
|
|
|
90
101
|
## HTTP API 工作流
|
|
91
102
|
|
|
92
103
|
调用设备 HTTP API 前,必须查询 HTTP API 文档。
|
|
93
104
|
|
|
94
|
-
MCP
|
|
105
|
+
MCP 入口:
|
|
95
106
|
|
|
96
107
|
1. 使用 `search_http_api_docs` 搜索目标能力、中文标题或接口路径。
|
|
97
108
|
2. 使用 `read_http_api_doc` 读取目标接口片段。
|
|
98
109
|
3. 确认 `method`、`path`、参数位置、参数类型和返回结构。
|
|
99
110
|
4. 使用 `http_api_call` 调用接口,并传入文档返回的 `docSlug`。
|
|
100
111
|
|
|
101
|
-
|
|
112
|
+
CLI 入口:
|
|
102
113
|
|
|
103
|
-
1.
|
|
104
|
-
2.
|
|
105
|
-
3.
|
|
114
|
+
1. 使用 `npx ms docs paths` 获取 HTTP API 文档路径。
|
|
115
|
+
2. 使用 `npx ms http-docs search <query>` 搜索目标接口。
|
|
116
|
+
3. 使用 `npx ms http-docs read <identifier> --method GET|POST` 读取目标接口片段。
|
|
117
|
+
4. 使用 `npx ms http-call -i <device-ip> --port <port> --method <method> --path <path> --doc-slug <slug>` 调用明确存在的接口。
|
|
118
|
+
5. 不要把未确认的路径当成可用接口。
|
|
106
119
|
|
|
107
120
|
## 设备工作流
|
|
108
121
|
|
|
109
122
|
设备相关操作以用户指定的设备为准。不要假设设备已经设置;用户给出新设备时必须使用新设备。
|
|
110
123
|
|
|
111
|
-
MCP
|
|
124
|
+
MCP 入口:
|
|
112
125
|
|
|
113
126
|
1. 使用 `get_device` 查看当前默认设备。
|
|
114
127
|
2. 如果未设置设备,使用 `set_device` 设置设备 IP 和端口。
|
|
115
|
-
3.
|
|
116
|
-
4. 使用 `get_logs` 获取日志缓存快照。
|
|
128
|
+
3. 使用 `get_logs` 获取当前日志最新行。
|
|
117
129
|
|
|
118
|
-
|
|
130
|
+
CLI 入口:
|
|
119
131
|
|
|
120
132
|
- 用 `npx ms run -i <device-ip> --port <port>` 运行脚本。
|
|
121
133
|
- 用 `npx ms screenshot -i <device-ip> --port <port> --format file --output <path>` 截图验证。
|
|
134
|
+
- 用 `npx ms source -i <device-ip> --port <port> --mode 1 --output <path>` 获取节点 XML。
|
|
135
|
+
- 用 `npx ms logs -i <device-ip> --port <port> --limit 200` 查看当前日志。
|
|
136
|
+
- 用 `npx ms ocr -i <device-ip> --port <port> --engine appleocr --mode recognize` 执行 OCR。
|
|
137
|
+
- 用 `npx ms screen-crop` 或 `npx ms image-crop` 裁切找图模板。
|
|
138
|
+
- 用 `npx ms screen-pick-color` 或 `npx ms image-pick-color` 获取颜色。
|
|
139
|
+
- 用 `npx ms image-transparent` 制作透明找图模板。
|
|
122
140
|
- 用 `npx ms stop -i <device-ip> --port <port>` 停止项目。
|
|
123
141
|
|
|
124
142
|
UI 预览发起后不需要长时间等待结果,可以用截图查看当前界面效果。
|
|
125
143
|
|
|
126
144
|
## 项目运行工作流
|
|
127
145
|
|
|
128
|
-
MCP
|
|
146
|
+
MCP 入口:
|
|
129
147
|
|
|
130
148
|
1. 使用 `set_workspace` 设置快点JS项目根目录。
|
|
131
149
|
2. 使用 `get_workspace` 确认当前工作区。
|
|
@@ -134,20 +152,19 @@ MCP 可用时:
|
|
|
134
152
|
5. 使用 `stop_project` 停止当前设备上的项目。
|
|
135
153
|
6. 使用 `package_project` 执行生产打包。
|
|
136
154
|
|
|
137
|
-
|
|
155
|
+
CLI 入口:
|
|
138
156
|
|
|
139
|
-
1.
|
|
157
|
+
1. 使用 `npx ms --help` 确认 CLI。
|
|
140
158
|
2. 使用 `npx ms run -i <device-ip> --port <port>` 同步并运行。
|
|
141
159
|
3. 使用 `npx ms screenshot ...` 验证界面。
|
|
142
160
|
|
|
143
|
-
|
|
161
|
+
`build`、`package`、`run`、`run-ui` 需要在快点JS项目根目录运行,项目根目录必须包含 `package.json` 和 `scripts/`。文档、HTTP API 查询/调用、截图、节点、日志、OCR、图片处理、停止和 WS 状态命令可以在任意目录使用。
|
|
144
162
|
|
|
145
163
|
## 工具分组
|
|
146
164
|
|
|
147
165
|
### 文档
|
|
148
166
|
|
|
149
|
-
- `
|
|
150
|
-
- `get_docs_language`
|
|
167
|
+
- `get_docs_paths`
|
|
151
168
|
- `list_api_docs`
|
|
152
169
|
- `search_api_docs`
|
|
153
170
|
- `read_api_doc`
|
|
@@ -181,9 +198,9 @@ MCP 可用时:
|
|
|
181
198
|
|
|
182
199
|
- `http_api_call`
|
|
183
200
|
|
|
184
|
-
控制、HID、IME、镜像、配置、当前应用、运行脚本等普通设备 HTTP API 通过 `search_http_api_docs`、`read_http_api_doc` 和 `http_api_call`
|
|
201
|
+
控制、HID、IME、镜像、配置、当前应用、运行脚本等普通设备 HTTP API 通过 `search_http_api_docs`、`read_http_api_doc` 和 `http_api_call` 使用;CLI 入口使用 `ms http-docs` 和 `ms http-call`。
|
|
185
202
|
|
|
186
|
-
|
|
203
|
+
使用 `ocr_recognize` 执行 OCR 识别。`ocr_recognize` 支持 `appleocr` 和 `paddleocr`,默认 `appleocr`,识别结果坐标可直接用于点击。
|
|
187
204
|
|
|
188
205
|
图片与识别工作流:
|
|
189
206
|
|
|
@@ -204,4 +221,4 @@ OCR 没有独立 HTTP 接口,使用 `ocr_recognize` 通过 `POST /api/runScrip
|
|
|
204
221
|
|
|
205
222
|
## 文档入口
|
|
206
223
|
|
|
207
|
-
|
|
224
|
+
优先直接读取项目本地 `node_modules/ms-vite-plugin/docs/` 文档;也可以使用 MCP 文档工具或 `ms docs` / `ms http-docs` 定位具体文档。
|