ms-vite-plugin 1.4.15 → 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.
@@ -1,4 +1,54 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export type OcrEngine = "appleocr" | "paddleocr";
3
+ export type OcrMode = "recognize" | "numbers" | "findText";
4
+ export type ScriptResultResponse = {
5
+ success?: boolean;
6
+ result?: unknown;
7
+ resultType?: string;
8
+ error?: string;
9
+ };
10
+ export type OcrRecognitionOptions = {
11
+ engine: OcrEngine;
12
+ mode: OcrMode;
13
+ input: string;
14
+ x: number;
15
+ y: number;
16
+ ex: number;
17
+ ey: number;
18
+ texts?: string[];
19
+ languages?: string[];
20
+ confidenceThreshold: number;
21
+ exactMatch: boolean;
22
+ outputPath?: string;
23
+ timeoutMs: number;
24
+ };
25
+ export type OcrRecognitionResult = {
26
+ status: number;
27
+ body: ScriptResultResponse;
28
+ text: string;
29
+ };
30
+ export declare const APPLE_OCR_LANGUAGES: readonly ["en-US", "fr-FR", "it-IT", "de-DE", "es-ES", "pt-BR", "zh-Hans", "zh-Hant"];
31
+ /**
32
+ * 格式化 OCR 工具结果
33
+ * @param response runScript 响应
34
+ * @param outputPath 可选输出文件路径
35
+ * @returns 返回 MCP 文本内容
36
+ * @example
37
+ * await formatOcrToolText({ success: true, result: [] })
38
+ */
39
+ export declare function formatOcrToolText(response: ScriptResultResponse, outputPath?: string): Promise<string>;
40
+ /**
41
+ * 在指定 HTTP 设备上执行 OCR 识别
42
+ * @param target 设备 HTTP 地址
43
+ * @param options OCR 参数
44
+ * @returns 返回 HTTP 状态码、原始结果与格式化文本
45
+ * @example
46
+ * await runOcrRecognitionOnDevice({ ip: "192.168.1.10", port: "9800" }, options)
47
+ */
48
+ export declare function runOcrRecognitionOnDevice(target: {
49
+ ip: string;
50
+ port: string;
51
+ }, options: OcrRecognitionOptions): Promise<OcrRecognitionResult>;
2
52
  /**
3
53
  * 注册 OCR MCP 工具
4
54
  * @param server MCP 服务实例
@@ -33,13 +33,16 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.APPLE_OCR_LANGUAGES = void 0;
37
+ exports.formatOcrToolText = formatOcrToolText;
38
+ exports.runOcrRecognitionOnDevice = runOcrRecognitionOnDevice;
36
39
  exports.registerOcrTools = registerOcrTools;
37
40
  const fsExtra = __importStar(require("fs-extra"));
38
41
  const os = __importStar(require("os"));
39
42
  const path = __importStar(require("path"));
40
43
  const z = __importStar(require("zod/v4"));
41
44
  const tool_utils_1 = require("./tool-utils");
42
- const APPLE_OCR_LANGUAGES = [
45
+ exports.APPLE_OCR_LANGUAGES = [
43
46
  "en-US",
44
47
  "fr-FR",
45
48
  "it-IT",
@@ -82,21 +85,22 @@ function resolveOcrOutputPath(outputPath) {
82
85
  * @param ey 区域右下角 y
83
86
  * @param texts 查找文本数组
84
87
  * @param languages 识别语言数组
88
+ * @param exactMatch 是否完整匹配文本
85
89
  * @returns 返回可交给 runScript 的 JavaScript 脚本
86
90
  * @example
87
91
  * buildAppleOcrScript("recognize", "screen", 0, 0, 0, 0)
88
92
  */
89
- function buildAppleOcrScript(mode, input, x, y, ex, ey, texts, languages) {
93
+ function buildAppleOcrScript(mode, input, x, y, ex, ey, texts, languages, exactMatch = false) {
90
94
  if (mode === "findText") {
91
95
  if (!texts || texts.length === 0) {
92
96
  throw new Error("findText 模式必须传 texts。");
93
97
  }
94
- return `appleOcr.findText(${jsonLiteral(input)}, ${jsonLiteral(texts)}, ${x}, ${y}, ${ex}, ${ey}, ${jsonLiteral(languages)});`;
98
+ return `appleOcr.findTextAbs(${jsonLiteral(input)}, ${jsonLiteral(texts)}, ${x}, ${y}, ${ex}, ${ey}, ${jsonLiteral(languages)}, ${exactMatch});`;
95
99
  }
96
100
  if (mode === "numbers") {
97
- return `appleOcr.recognizeNumbers(${jsonLiteral(input)}, ${x}, ${y}, ${ex}, ${ey});`;
101
+ return `appleOcr.recognizeNumbersAbs(${jsonLiteral(input)}, ${x}, ${y}, ${ex}, ${ey});`;
98
102
  }
99
- return `appleOcr.recognize(${jsonLiteral(input)}, ${x}, ${y}, ${ex}, ${ey}, ${jsonLiteral(languages)});`;
103
+ return `appleOcr.recognizeAbs(${jsonLiteral(input)}, ${x}, ${y}, ${ex}, ${ey}, ${jsonLiteral(languages)});`;
100
104
  }
101
105
  /**
102
106
  * 构建 Paddle OCR 运行脚本
@@ -108,35 +112,22 @@ function buildAppleOcrScript(mode, input, x, y, ex, ey, texts, languages) {
108
112
  * @param ey 区域右下角 y
109
113
  * @param texts 查找文本数组
110
114
  * @param confidenceThreshold 置信度阈值
111
- * @param maxSideLen 模型最大边长
112
- * @param useGpu 是否使用 GPU
115
+ * @param exactMatch 是否完整匹配文本
113
116
  * @returns 返回可交给 runScript 的 JavaScript 脚本
114
117
  * @example
115
118
  * buildPaddleOcrScript("recognize", "screen", 0, 0, 0, 0)
116
119
  */
117
- function buildPaddleOcrScript(mode, input, x, y, ex, ey, texts, confidenceThreshold, maxSideLen, useGpu) {
120
+ function buildPaddleOcrScript(mode, input, x, y, ex, ey, texts, confidenceThreshold, exactMatch) {
118
121
  if (mode === "numbers") {
119
122
  throw new Error("PaddleOCR 文档未提供 numbers 模式,请使用 appleocr 引擎。");
120
123
  }
121
- const loadScript = `const __loaded = paddleOcr.loadV5(${maxSideLen}, ${useGpu});`;
122
- const loadFailedScript = 'let __ocrResult; if (!__loaded) { __ocrResult = { success: false, error: "PaddleOCR loadV5 failed" }; }';
123
124
  if (mode === "findText") {
124
125
  if (!texts || texts.length === 0) {
125
126
  throw new Error("findText 模式必须传 texts。");
126
127
  }
127
- return [
128
- loadScript,
129
- loadFailedScript,
130
- `if (__loaded) { __ocrResult = paddleOcr.findText(${jsonLiteral(input)}, ${jsonLiteral(texts)}, ${x}, ${y}, ${ex}, ${ey}, ${confidenceThreshold}); }`,
131
- "__ocrResult;",
132
- ].join("\n");
128
+ return `paddleOcr.findTextAbs(${jsonLiteral(input)}, ${jsonLiteral(texts)}, ${x}, ${y}, ${ex}, ${ey}, ${confidenceThreshold}, ${exactMatch});`;
133
129
  }
134
- return [
135
- loadScript,
136
- loadFailedScript,
137
- `if (__loaded) { __ocrResult = paddleOcr.recognize(${jsonLiteral(input)}, ${x}, ${y}, ${ex}, ${ey}, ${confidenceThreshold}); }`,
138
- "__ocrResult;",
139
- ].join("\n");
130
+ return `paddleOcr.recognizeAbs(${jsonLiteral(input)}, ${x}, ${y}, ${ex}, ${ey}, ${confidenceThreshold});`;
140
131
  }
141
132
  /**
142
133
  * 构建 OCR 运行脚本
@@ -150,17 +141,16 @@ function buildPaddleOcrScript(mode, input, x, y, ex, ey, texts, confidenceThresh
150
141
  * @param texts 查找文本数组
151
142
  * @param languages Apple OCR 识别语言数组
152
143
  * @param confidenceThreshold PaddleOCR 置信度阈值
153
- * @param paddleMaxSideLen PaddleOCR 模型最大边长
154
- * @param paddleUseGpu PaddleOCR 是否使用 GPU
144
+ * @param exactMatch 是否完整匹配文本
155
145
  * @returns 返回可交给 runScript 的 JavaScript 脚本
156
146
  * @example
157
147
  * buildOcrScript("appleocr", "recognize", "screen", 0, 0, 0, 0)
158
148
  */
159
- function buildOcrScript(engine, mode, input, x, y, ex, ey, texts, languages, confidenceThreshold, paddleMaxSideLen, paddleUseGpu) {
149
+ function buildOcrScript(engine, mode, input, x, y, ex, ey, texts, languages, confidenceThreshold, exactMatch) {
160
150
  if (engine === "paddleocr") {
161
- return buildPaddleOcrScript(mode, input, x, y, ex, ey, texts, confidenceThreshold, paddleMaxSideLen, paddleUseGpu);
151
+ return buildPaddleOcrScript(mode, input, x, y, ex, ey, texts, confidenceThreshold, exactMatch);
162
152
  }
163
- return buildAppleOcrScript(mode, input, x, y, ex, ey, texts, languages);
153
+ return buildAppleOcrScript(mode, input, x, y, ex, ey, texts, languages, exactMatch);
164
154
  }
165
155
  /**
166
156
  * 调用设备 runScript 接口
@@ -242,6 +232,24 @@ async function formatOcrToolText(response, outputPath) {
242
232
  responseText,
243
233
  ].join("\n");
244
234
  }
235
+ /**
236
+ * 在指定 HTTP 设备上执行 OCR 识别
237
+ * @param target 设备 HTTP 地址
238
+ * @param options OCR 参数
239
+ * @returns 返回 HTTP 状态码、原始结果与格式化文本
240
+ * @example
241
+ * await runOcrRecognitionOnDevice({ ip: "192.168.1.10", port: "9800" }, options)
242
+ */
243
+ async function runOcrRecognitionOnDevice(target, options) {
244
+ const script = buildOcrScript(options.engine, options.mode, options.input, options.x, options.y, options.ex, options.ey, options.texts, options.languages, options.confidenceThreshold, options.exactMatch);
245
+ const response = await callRunScript(target.ip, target.port, script, options.timeoutMs);
246
+ const text = await formatOcrToolText(response.body, options.outputPath);
247
+ return {
248
+ status: response.status,
249
+ body: response.body,
250
+ text,
251
+ };
252
+ }
245
253
  /**
246
254
  * 注册 OCR MCP 工具
247
255
  * @param server MCP 服务实例
@@ -252,7 +260,7 @@ async function formatOcrToolText(response, outputPath) {
252
260
  function registerOcrTools(server) {
253
261
  server.registerTool("ocr_recognize", {
254
262
  title: "OCR Recognize",
255
- description: "通过设备 POST /api/runScript 执行快点JS OCR。支持 appleocr 与 paddleocr,默认 appleocr;OCR 没有独立 HTTP 接口时使用本工具。",
263
+ description: "在当前默认设备执行 OCR。支持 appleocr 与 paddleocr,默认 appleocr;返回坐标使用绝对坐标。",
256
264
  inputSchema: {
257
265
  engine: z
258
266
  .enum(["appleocr", "paddleocr"])
@@ -291,9 +299,14 @@ function registerOcrTools(server) {
291
299
  .optional()
292
300
  .describe("findText 模式要查找的文本数组"),
293
301
  languages: z
294
- .array(z.enum(APPLE_OCR_LANGUAGES))
302
+ .array(z.enum(exports.APPLE_OCR_LANGUAGES))
295
303
  .optional()
296
304
  .describe('Apple OCR 识别语言数组,默认由运行时使用 ["zh-Hans", "en-US"]'),
305
+ exactMatch: z
306
+ .boolean()
307
+ .optional()
308
+ .default(false)
309
+ .describe("findText 模式是否要求整条识别文本完全匹配目标文本"),
297
310
  confidenceThreshold: z
298
311
  .number()
299
312
  .min(0)
@@ -301,19 +314,6 @@ function registerOcrTools(server) {
301
314
  .optional()
302
315
  .default(0.6)
303
316
  .describe("PaddleOCR 置信度阈值,默认 0.6"),
304
- paddleMaxSideLen: z
305
- .number()
306
- .int()
307
- .min(32)
308
- .max(4096)
309
- .optional()
310
- .default(640)
311
- .describe("PaddleOCR loadV5 最大边长,默认 640"),
312
- paddleUseGpu: z
313
- .boolean()
314
- .optional()
315
- .default(false)
316
- .describe("PaddleOCR loadV5 是否使用 GPU,默认 false"),
317
317
  outputPath: z
318
318
  .string()
319
319
  .min(1)
@@ -328,20 +328,31 @@ function registerOcrTools(server) {
328
328
  .default(60000)
329
329
  .describe("runScript 请求超时时间,默认 60000 毫秒"),
330
330
  },
331
- }, async ({ engine, mode, input, x, y, ex, ey, texts, languages, confidenceThreshold, paddleMaxSideLen, paddleUseGpu, outputPath, timeoutMs, }) => {
331
+ }, async ({ engine, mode, input, x, y, ex, ey, texts, languages, exactMatch, confidenceThreshold, outputPath, timeoutMs, }) => {
332
332
  const target = await (0, tool_utils_1.resolveRuntimeHttpTarget)();
333
- const script = buildOcrScript(engine, mode, input, x, y, ex, ey, texts, languages, confidenceThreshold, paddleMaxSideLen, paddleUseGpu);
334
- const response = await callRunScript(target.ip, target.port, script, timeoutMs);
335
- const text = await formatOcrToolText(response.body, outputPath);
333
+ const response = await runOcrRecognitionOnDevice(target, {
334
+ engine,
335
+ mode,
336
+ input,
337
+ x,
338
+ y,
339
+ ex,
340
+ ey,
341
+ texts,
342
+ languages,
343
+ confidenceThreshold,
344
+ exactMatch,
345
+ outputPath,
346
+ timeoutMs,
347
+ });
336
348
  return (0, tool_utils_1.createTextToolResult)([
337
- text,
349
+ response.text,
338
350
  "",
339
351
  `device: ${target.label}`,
340
352
  `engine: ${engine}`,
341
353
  `mode: ${mode}`,
342
354
  `input: ${input}`,
343
355
  `region: x=${x}, y=${y}, ex=${ex}, ey=${ey}`,
344
- `runScript: POST /api/runScript`,
345
356
  `status: ${response.status}`,
346
357
  ].join("\n"), response.body.success === false);
347
358
  });
@@ -185,7 +185,7 @@ function registerRuntimeTools(server) {
185
185
  });
186
186
  server.registerTool("get_node_source", {
187
187
  title: "Get Node Source",
188
- description: "获取当前默认设备页面节点 XML(/api/source),写入文件后返回路径,避免长文本响应被截断。",
188
+ description: "获取当前默认设备页面节点 XML,写入文件后返回路径,避免长文本响应被截断。",
189
189
  inputSchema: {
190
190
  maxDepth: z
191
191
  .number()
@@ -203,20 +203,28 @@ function registerRuntimeTools(server) {
203
203
  .optional()
204
204
  .default(120)
205
205
  .describe("设备端节点抓取超时秒数,默认 120"),
206
+ mode: z
207
+ .number()
208
+ .int()
209
+ .min(1)
210
+ .max(2)
211
+ .optional()
212
+ .default(1)
213
+ .describe("节点抓取模式:1=完整节点树,2=可见节点优化模式"),
206
214
  outputPath: z
207
215
  .string()
208
216
  .min(1)
209
217
  .optional()
210
218
  .describe("可选输出文件路径,不传则写入系统临时目录"),
211
219
  },
212
- }, async ({ maxDepth, timeout, outputPath }) => {
220
+ }, async ({ maxDepth, timeout, mode, outputPath }) => {
213
221
  const target = await (0, tool_utils_1.resolveRuntimeHttpTarget)();
214
222
  const requestOptions = (0, tool_utils_1.createRuntimeHttpRequestOptions)(target);
215
- const source = await (0, project_1.getSourceOnDevice)(requestOptions, maxDepth, timeout);
223
+ const source = await (0, project_1.getSourceOnDevice)(requestOptions, maxDepth, timeout, mode);
216
224
  const targetPath = resolveOutputPath(outputPath, "ms-mcp-node-source", "xml");
217
225
  await fsExtra.ensureDir(path.dirname(targetPath));
218
226
  await fsExtra.writeFile(targetPath, source, "utf8");
219
- return (0, tool_utils_1.createTextToolResult)(`节点获取成功: ${target.label}\nmaxDepth: ${maxDepth}\ntimeout: ${timeout}\npath: ${targetPath}\nsize: ${Buffer.byteLength(source, "utf8")} bytes`);
227
+ return (0, tool_utils_1.createTextToolResult)(`节点获取成功: ${target.label}\nmaxDepth: ${maxDepth}\ntimeout: ${timeout}\nmode: ${mode}\npath: ${targetPath}\nsize: ${Buffer.byteLength(source, "utf8")} bytes`);
220
228
  });
221
229
  server.registerTool("get_logs", {
222
230
  title: "Get Device Logs",
@@ -67,8 +67,9 @@ export declare function formatRuntimeJsonText(value: unknown): string;
67
67
  * @param title 文档标题
68
68
  * @param slug 文档 slug
69
69
  * @param index 列表序号
70
+ * @param filePath 文档文件绝对路径
70
71
  * @returns 返回用于列表展示的文本块
71
72
  * @example
72
- * formatApiDocSummary("js", "Tap", "tap", 0)
73
+ * formatApiDocSummary("js", "Tap", "tap", 0, "/tmp/tap.md")
73
74
  */
74
- export declare function formatApiDocSummary(language: ApiDocsLanguage, title: string, slug: string, index: number): string;
75
+ export declare function formatApiDocSummary(language: ApiDocsLanguage, title: string, slug: string, index: number, filePath?: string): string;
@@ -87,10 +87,16 @@ function formatRuntimeJsonText(value) {
87
87
  * @param title 文档标题
88
88
  * @param slug 文档 slug
89
89
  * @param index 列表序号
90
+ * @param filePath 文档文件绝对路径
90
91
  * @returns 返回用于列表展示的文本块
91
92
  * @example
92
- * formatApiDocSummary("js", "Tap", "tap", 0)
93
+ * formatApiDocSummary("js", "Tap", "tap", 0, "/tmp/tap.md")
93
94
  */
94
- function formatApiDocSummary(language, title, slug, index) {
95
- return `${index + 1}. ${title}\nslug: ${slug}\nuri: ${(0, docs_service_1.getDocUri)(language, slug)}`;
95
+ function formatApiDocSummary(language, title, slug, index, filePath) {
96
+ return [
97
+ `${index + 1}. ${title}`,
98
+ `slug: ${slug}`,
99
+ `uri: ${(0, docs_service_1.getDocUri)(language, slug)}`,
100
+ ...(filePath ? [`path: ${filePath}`] : []),
101
+ ].join("\n");
96
102
  }
package/dist/mcp/tools.js CHANGED
@@ -22,7 +22,6 @@ function createMcpServer() {
22
22
  name: "ms-vite-plugin-mcp",
23
23
  version: version_1.PACKAGE_VERSION,
24
24
  });
25
- (0, doc_tools_1.registerDocResources)(server);
26
25
  (0, doc_tools_1.registerDocTools)(server);
27
26
  (0, httpapi_tools_1.registerHttpApiTools)(server);
28
27
  (0, image_tools_1.registerImageTools)(server);
package/dist/project.d.ts CHANGED
@@ -39,11 +39,12 @@ export declare function getScreenshotBase64OnDevice(options: DeviceCliOptions):
39
39
  * @param options 命令选项(transport 仅支持 http)
40
40
  * @param maxDepth 节点最大深度,默认 50
41
41
  * @param timeout 获取节点超时秒数,默认 120
42
+ * @param mode 节点抓取模式,1=完整节点树,2=可见节点优化模式
42
43
  * @returns 返回 XML 字符串
43
44
  * @example
44
- * const xml = await getSourceOnDevice({ ip: "192.168.1.10", port: "9800" }, 50, 120)
45
+ * const xml = await getSourceOnDevice({ ip: "192.168.1.10", port: "9800" }, 50, 120, 1)
45
46
  */
46
- export declare function getSourceOnDevice(options: DeviceCliOptions, maxDepth?: number, timeout?: number): Promise<string>;
47
+ export declare function getSourceOnDevice(options: DeviceCliOptions, maxDepth?: number, timeout?: number, mode?: number): Promise<string>;
47
48
  /**
48
49
  * 在设备上获取当前日志文件最新行
49
50
  * @param options 命令选项(仅支持 http 传输)
package/dist/project.js CHANGED
@@ -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}`);
package/docs/AGENTS.md CHANGED
@@ -36,26 +36,27 @@
36
36
 
37
37
  ## 文档优先
38
38
 
39
- 回答快点JS API 问题或编写脚本前,必须先查询当前语言对应的快点JS文档。
39
+ 回答快点JS API 问题或编写脚本前,必须先查询目标语言对应的快点JS文档。
40
40
 
41
- MCP 可用时:
41
+ MCP 入口:
42
42
 
43
- 1. 使用 `set_docs_language` 设置语言:`js`、`js_zh` 或 `python`。
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
- MCP 不可用时:
48
+ CLI 入口:
49
49
 
50
- 1. 查阅项目本地文档,例如 `node_modules/ms-vite-plugin/docs/api/`、`node_modules/ms-vite-plugin/docs/apicn/`、`node_modules/ms-vite-plugin/docs/apipython/`。
51
- 2. 只使用文档中已经确认的 API
52
- 3. 在回复中说明使用了本地文档作为 MCP fallback。
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
- 命令 fallback 时:
68
+ CLI 入口:
68
69
 
69
- 1. 先在本地 HTTP API 文档中确认接口存在。
70
- 2. 再用 `curl` 调用明确存在的接口。
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
- 命令必须在快点JS项目根目录运行,项目根目录通常包含 `package.json` 和 `scripts/`。不要用未确认的通用 Node.js、浏览器或 Python 命令替代 MCP 或项目自带 `ms` CLI。
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
- - `set_docs_language`
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` 或已确认接口的 `curl` fallback。
145
- - 获取截图:优先使用 `take_screenshot`;命令 fallback 可用 `npx ms screenshot`。
146
- - 获取节点 XML:优先使用 `get_node_source`。
147
- - 查看日志:优先使用 `get_logs`。
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
- - 运行项目:优先使用 `run_project` 或 `run_ui_project`;命令 fallback 可用 `npx ms run` 或 `npx ms run-ui`。
155
- - 停止项目:优先使用 `stop_project`;命令 fallback 可用 `npx ms stop`。
156
- - 打包项目:优先使用 `package_project`;命令 fallback 可用 `npx ms package`。
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 没有独立 HTTP 接口,使用 `ocr_recognize` 通过 `POST /api/runScript` 执行快点JS OCR 脚本。
170
+ OCR 识别使用 `ocr_recognize`,不要手写未确认的 OCR 调用链路。
161
171
 
162
172
  - `ocr_recognize` 支持 `appleocr` 和 `paddleocr`。
163
173
  - 默认使用 `appleocr`。
164
174
  - 数字识别优先使用 `appleocr`,因为 PaddleOCR 文档未提供独立 numbers 模式。
165
- - `runScript` 的规则是最后一行表达式或变量会作为结果返回,不需要写 `return`。
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` 或日志 HTTP API 查看运行日志。
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` 或 `curl`。
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 落文件、日志缓存、项目打包和项目运行等专用工具。