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.
@@ -1,27 +1,4 @@
1
1
  import type { ApiDocItem, ApiDocsLanguage } from "./types";
2
- /**
3
- * 获取当前文档语言
4
- * @returns 返回当前语言
5
- * @example
6
- * const language = getCurrentDocsLanguage()
7
- */
8
- export declare function getCurrentDocsLanguage(): ApiDocsLanguage;
9
- /**
10
- * 设置当前文档语言
11
- * @param language 目标语言
12
- * @returns 设置后的语言
13
- * @example
14
- * const language = setCurrentDocsLanguage("python")
15
- */
16
- export declare function setCurrentDocsLanguage(language: ApiDocsLanguage): ApiDocsLanguage;
17
- /**
18
- * 根据可选入参解析实际使用的文档语言
19
- * @param language 工具调用时传入的语言(可选)
20
- * @returns 返回最终生效的语言
21
- * @example
22
- * const activeLanguage = resolveDocsLanguage(undefined)
23
- */
24
- export declare function resolveDocsLanguage(language?: ApiDocsLanguage): ApiDocsLanguage;
25
2
  /**
26
3
  * 获取 docs 根目录
27
4
  * @returns 返回 docs 目录绝对路径
@@ -33,9 +33,6 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getCurrentDocsLanguage = getCurrentDocsLanguage;
37
- exports.setCurrentDocsLanguage = setCurrentDocsLanguage;
38
- exports.resolveDocsLanguage = resolveDocsLanguage;
39
36
  exports.getDocsRootDir = getDocsRootDir;
40
37
  exports.getDocsDirByLanguage = getDocsDirByLanguage;
41
38
  exports.getApiDocsByLanguage = getApiDocsByLanguage;
@@ -43,40 +40,6 @@ exports.scoreApiDoc = scoreApiDoc;
43
40
  exports.getDocUri = getDocUri;
44
41
  const fsExtra = __importStar(require("fs-extra"));
45
42
  const path = __importStar(require("path"));
46
- /**
47
- * 当前 MCP 进程默认文档语言
48
- */
49
- let currentDocsLanguage = "js_zh";
50
- /**
51
- * 获取当前文档语言
52
- * @returns 返回当前语言
53
- * @example
54
- * const language = getCurrentDocsLanguage()
55
- */
56
- function getCurrentDocsLanguage() {
57
- return currentDocsLanguage;
58
- }
59
- /**
60
- * 设置当前文档语言
61
- * @param language 目标语言
62
- * @returns 设置后的语言
63
- * @example
64
- * const language = setCurrentDocsLanguage("python")
65
- */
66
- function setCurrentDocsLanguage(language) {
67
- currentDocsLanguage = language;
68
- return currentDocsLanguage;
69
- }
70
- /**
71
- * 根据可选入参解析实际使用的文档语言
72
- * @param language 工具调用时传入的语言(可选)
73
- * @returns 返回最终生效的语言
74
- * @example
75
- * const activeLanguage = resolveDocsLanguage(undefined)
76
- */
77
- function resolveDocsLanguage(language) {
78
- return language ?? currentDocsLanguage;
79
- }
80
43
  /**
81
44
  * 获取 docs 根目录
82
45
  * @returns 返回 docs 目录绝对路径
@@ -111,9 +74,6 @@ function getDocsDirByLanguage(language) {
111
74
  */
112
75
  async function getApiDocsByLanguage(language) {
113
76
  const docsDir = getDocsDirByLanguage(language);
114
- if (!(await fsExtra.pathExists(docsDir))) {
115
- throw new Error(`文档目录不存在: ${docsDir}`);
116
- }
117
77
  const fileNames = await fsExtra.readdir(docsDir);
118
78
  const mdFiles = fileNames
119
79
  .filter((name) => name.toLowerCase().endsWith(".md"))
@@ -8,6 +8,8 @@ export type HttpApiMethod = "GET" | "POST";
8
8
  export type HttpApiDocEntry = {
9
9
  /** 稳定 slug,可用于读取单个接口文档 */
10
10
  slug: string;
11
+ /** HTTP API 文档绝对路径 */
12
+ filePath: string;
11
13
  /** 接口请求方法 */
12
14
  method: HttpApiMethod;
13
15
  /** 接口路径 */
@@ -23,6 +25,13 @@ export type HttpApiDocEntry = {
23
25
  /** 接口完整 markdown 片段 */
24
26
  content: string;
25
27
  };
28
+ /**
29
+ * 获取 HTTP API 文档路径
30
+ * @returns 返回 HTTP API 文档绝对路径
31
+ * @example
32
+ * const filePath = getHttpApiDocPath()
33
+ */
34
+ export declare function getHttpApiDocPath(): string;
26
35
  /**
27
36
  * 读取 HTTP API markdown 文档
28
37
  * @returns 返回完整 markdown 文本
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getHttpApiDocPath = getHttpApiDocPath;
36
37
  exports.readHttpApiMarkdown = readHttpApiMarkdown;
37
38
  exports.createHttpApiSlug = createHttpApiSlug;
38
39
  exports.getHttpApiDocEntries = getHttpApiDocEntries;
@@ -62,9 +63,6 @@ function getHttpApiDocPath() {
62
63
  */
63
64
  async function readHttpApiMarkdown() {
64
65
  const filePath = getHttpApiDocPath();
65
- if (!(await fsExtra.pathExists(filePath))) {
66
- throw new Error("HTTP API 文档不可用。");
67
- }
68
66
  return fsExtra.readFile(filePath, "utf8");
69
67
  }
70
68
  /**
@@ -89,10 +87,7 @@ function createHttpApiSlug(method, apiPath) {
89
87
  */
90
88
  async function getHttpApiDocEntries() {
91
89
  const filePath = getHttpApiDocPath();
92
- const stat = await fsExtra.stat(filePath).catch(() => null);
93
- if (!stat) {
94
- throw new Error("HTTP API 文档不可用。");
95
- }
90
+ const stat = await fsExtra.stat(filePath);
96
91
  if (cachedHttpApiDocEntries?.mtimeMs === stat.mtimeMs) {
97
92
  return cachedHttpApiDocEntries.entries;
98
93
  }
@@ -134,6 +129,7 @@ async function getHttpApiDocEntries() {
134
129
  }
135
130
  entries.push({
136
131
  slug: createHttpApiSlug(method, apiPath),
132
+ filePath,
137
133
  method,
138
134
  path: apiPath,
139
135
  title,
@@ -59,6 +59,7 @@ function formatHttpApiDocSummary(entry, index) {
59
59
  `slug: ${entry.slug}`,
60
60
  `section: ${entry.section || "未分组"}`,
61
61
  `lines: ${entry.startLine}-${entry.endLine}`,
62
+ `file: ${entry.filePath}`,
62
63
  `uri: ${HTTP_API_ENDPOINT_RESOURCE_PREFIX}/${entry.slug}`,
63
64
  ].join("\n");
64
65
  }
@@ -183,7 +184,7 @@ function registerHttpApiTools(server) {
183
184
  resources: entries.map((entry) => ({
184
185
  uri: `${HTTP_API_ENDPOINT_RESOURCE_PREFIX}/${entry.slug}`,
185
186
  name: `${entry.method} ${entry.path}`,
186
- description: `${entry.title} [${entry.section || "未分组"}]`,
187
+ description: `${entry.title} [${entry.section || "未分组"}] | file: ${entry.filePath}`,
187
188
  mimeType: "text/markdown",
188
189
  })),
189
190
  };
@@ -271,6 +272,7 @@ function registerHttpApiTools(server) {
271
272
  `slug: ${entry.slug}`,
272
273
  `section: ${entry.section || "未分组"}`,
273
274
  `lines: ${entry.startLine}-${entry.endLine}`,
275
+ `file: ${entry.filePath}`,
274
276
  "",
275
277
  entry.content,
276
278
  ].join("\n"));
@@ -1,4 +1,73 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export type ImageSampleCorner = "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
3
+ /**
4
+ * 裁切本地图片
5
+ * @param imagePath 输入图片路径
6
+ * @param x 裁切起点 x
7
+ * @param y 裁切起点 y
8
+ * @param width 裁切宽度
9
+ * @param height 裁切高度
10
+ * @param outputPath 可选输出路径
11
+ * @returns 返回操作结果文本
12
+ * @example
13
+ * await cropLocalImage("./screen.jpg", 0, 0, 100, 100)
14
+ */
15
+ export declare function cropLocalImage(imagePath: string, x: number, y: number, width: number, height: number, outputPath?: string): Promise<string>;
16
+ /**
17
+ * 裁切设备截图
18
+ * @param target 设备 HTTP 地址
19
+ * @param x 裁切起点 x
20
+ * @param y 裁切起点 y
21
+ * @param width 裁切宽度
22
+ * @param height 裁切高度
23
+ * @param outputPath 可选输出路径
24
+ * @returns 返回操作结果文本
25
+ * @example
26
+ * await cropDeviceScreen({ ip: "192.168.1.10", port: "9800", label: "192.168.1.10:9800" }, 0, 0, 100, 100)
27
+ */
28
+ export declare function cropDeviceScreen(target: {
29
+ ip: string;
30
+ port: string;
31
+ label: string;
32
+ }, x: number, y: number, width: number, height: number, outputPath?: string): Promise<string>;
33
+ /**
34
+ * 读取本地图片颜色
35
+ * @param imagePath 输入图片路径
36
+ * @param x 目标坐标 x
37
+ * @param y 目标坐标 y
38
+ * @param radius 采样半径
39
+ * @returns 返回取色结果文本
40
+ * @example
41
+ * await pickLocalImageColor("./screen.jpg", 10, 10, 0)
42
+ */
43
+ export declare function pickLocalImageColor(imagePath: string, x: number, y: number, radius: number): Promise<string>;
44
+ /**
45
+ * 读取设备截图颜色
46
+ * @param target 设备 HTTP 地址
47
+ * @param x 目标坐标 x
48
+ * @param y 目标坐标 y
49
+ * @param radius 采样半径
50
+ * @returns 返回取色结果文本
51
+ * @example
52
+ * await pickDeviceScreenColor({ ip: "192.168.1.10", port: "9800", label: "192.168.1.10:9800" }, 10, 10, 0)
53
+ */
54
+ export declare function pickDeviceScreenColor(target: {
55
+ ip: string;
56
+ port: string;
57
+ label: string;
58
+ }, x: number, y: number, radius: number): Promise<string>;
59
+ /**
60
+ * 制作本地图片透明图
61
+ * @param imagePath 输入图片路径
62
+ * @param outputPath 可选输出路径
63
+ * @param transparentColor 可选透明色
64
+ * @param sampleCorner 未传透明色时采样的角落
65
+ * @param tolerance 颜色容差
66
+ * @returns 返回操作结果文本
67
+ * @example
68
+ * await makeLocalImageTransparent("./button.png", undefined, "#ffffff", "topLeft", 24)
69
+ */
70
+ export declare function makeLocalImageTransparent(imagePath: string, outputPath: string | undefined, transparentColor: string | undefined, sampleCorner: ImageSampleCorner, tolerance: number): Promise<string>;
2
71
  /**
3
72
  * 注册图片处理 MCP 工具
4
73
  * @param server MCP 服务实例
@@ -36,6 +36,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.cropLocalImage = cropLocalImage;
40
+ exports.cropDeviceScreen = cropDeviceScreen;
41
+ exports.pickLocalImageColor = pickLocalImageColor;
42
+ exports.pickDeviceScreenColor = pickDeviceScreenColor;
43
+ exports.makeLocalImageTransparent = makeLocalImageTransparent;
39
44
  exports.registerImageTools = registerImageTools;
40
45
  const fsExtra = __importStar(require("fs-extra"));
41
46
  const os = __importStar(require("os"));
@@ -247,6 +252,164 @@ function formatPickedColorText(source, x, y, radius, imageWidth, imageHeight, co
247
252
  `rgba: ${color.r},${color.g},${color.b},${color.a}`,
248
253
  ].join("\n");
249
254
  }
255
+ /**
256
+ * 裁切本地图片
257
+ * @param imagePath 输入图片路径
258
+ * @param x 裁切起点 x
259
+ * @param y 裁切起点 y
260
+ * @param width 裁切宽度
261
+ * @param height 裁切高度
262
+ * @param outputPath 可选输出路径
263
+ * @returns 返回操作结果文本
264
+ * @example
265
+ * await cropLocalImage("./screen.jpg", 0, 0, 100, 100)
266
+ */
267
+ async function cropLocalImage(imagePath, x, y, width, height, outputPath) {
268
+ const inputPath = await resolveExistingImagePath(imagePath);
269
+ const targetPath = resolveImageOutputPath(inputPath, outputPath, "crop");
270
+ const metadata = await (0, sharp_1.default)(inputPath).metadata();
271
+ const imageWidth = metadata.width ?? 0;
272
+ const imageHeight = metadata.height ?? 0;
273
+ if (x + width > imageWidth || y + height > imageHeight) {
274
+ throw new Error(`裁切范围超出图片尺寸: image=${imageWidth}x${imageHeight}, crop=${x},${y},${width},${height}`);
275
+ }
276
+ await fsExtra.ensureDir(path.dirname(targetPath));
277
+ const info = await (0, sharp_1.default)(inputPath)
278
+ .extract({ left: x, top: y, width, height })
279
+ .png()
280
+ .toFile(targetPath);
281
+ return [
282
+ "图片裁切成功",
283
+ `input: ${inputPath}`,
284
+ `output: ${targetPath}`,
285
+ `crop: x=${x}, y=${y}, width=${width}, height=${height}`,
286
+ `size: ${info.size} bytes`,
287
+ ].join("\n");
288
+ }
289
+ /**
290
+ * 裁切设备截图
291
+ * @param target 设备 HTTP 地址
292
+ * @param x 裁切起点 x
293
+ * @param y 裁切起点 y
294
+ * @param width 裁切宽度
295
+ * @param height 裁切高度
296
+ * @param outputPath 可选输出路径
297
+ * @returns 返回操作结果文本
298
+ * @example
299
+ * await cropDeviceScreen({ ip: "192.168.1.10", port: "9800", label: "192.168.1.10:9800" }, 0, 0, 100, 100)
300
+ */
301
+ async function cropDeviceScreen(target, x, y, width, height, outputPath) {
302
+ const screenshot = await (0, project_1.getScreenshotOnDevice)({
303
+ ip: target.ip,
304
+ port: target.port,
305
+ transport: "http",
306
+ });
307
+ const metadata = await (0, sharp_1.default)(screenshot).metadata();
308
+ const imageWidth = metadata.width ?? 0;
309
+ const imageHeight = metadata.height ?? 0;
310
+ if (x + width > imageWidth || y + height > imageHeight) {
311
+ throw new Error(`裁切范围超出截图尺寸: image=${imageWidth}x${imageHeight}, crop=${x},${y},${width},${height}`);
312
+ }
313
+ const targetPath = resolveGeneratedImageOutputPath(outputPath, "ms-mcp-screen-crop", "png");
314
+ await fsExtra.ensureDir(path.dirname(targetPath));
315
+ const info = await (0, sharp_1.default)(screenshot)
316
+ .extract({ left: x, top: y, width, height })
317
+ .png()
318
+ .toFile(targetPath);
319
+ return [
320
+ "屏幕裁图成功",
321
+ `device: ${target.label}`,
322
+ `output: ${targetPath}`,
323
+ `screen: ${imageWidth}x${imageHeight}`,
324
+ `crop: x=${x}, y=${y}, width=${width}, height=${height}`,
325
+ `size: ${info.size} bytes`,
326
+ ].join("\n");
327
+ }
328
+ /**
329
+ * 读取本地图片颜色
330
+ * @param imagePath 输入图片路径
331
+ * @param x 目标坐标 x
332
+ * @param y 目标坐标 y
333
+ * @param radius 采样半径
334
+ * @returns 返回取色结果文本
335
+ * @example
336
+ * await pickLocalImageColor("./screen.jpg", 10, 10, 0)
337
+ */
338
+ async function pickLocalImageColor(imagePath, x, y, radius) {
339
+ const inputPath = await resolveExistingImagePath(imagePath);
340
+ const image = await readRgbaImage(inputPath);
341
+ const picked = pickAverageColor(image.data, image.width, image.height, x, y, radius);
342
+ return formatPickedColorText(inputPath, x, y, radius, image.width, image.height, picked.color, picked.sampleCount);
343
+ }
344
+ /**
345
+ * 读取设备截图颜色
346
+ * @param target 设备 HTTP 地址
347
+ * @param x 目标坐标 x
348
+ * @param y 目标坐标 y
349
+ * @param radius 采样半径
350
+ * @returns 返回取色结果文本
351
+ * @example
352
+ * await pickDeviceScreenColor({ ip: "192.168.1.10", port: "9800", label: "192.168.1.10:9800" }, 10, 10, 0)
353
+ */
354
+ async function pickDeviceScreenColor(target, x, y, radius) {
355
+ const screenshot = await (0, project_1.getScreenshotOnDevice)({
356
+ ip: target.ip,
357
+ port: target.port,
358
+ transport: "http",
359
+ });
360
+ const image = await readRgbaImage(screenshot);
361
+ const picked = pickAverageColor(image.data, image.width, image.height, x, y, radius);
362
+ return formatPickedColorText(target.label, x, y, radius, image.width, image.height, picked.color, picked.sampleCount);
363
+ }
364
+ /**
365
+ * 制作本地图片透明图
366
+ * @param imagePath 输入图片路径
367
+ * @param outputPath 可选输出路径
368
+ * @param transparentColor 可选透明色
369
+ * @param sampleCorner 未传透明色时采样的角落
370
+ * @param tolerance 颜色容差
371
+ * @returns 返回操作结果文本
372
+ * @example
373
+ * await makeLocalImageTransparent("./button.png", undefined, "#ffffff", "topLeft", 24)
374
+ */
375
+ async function makeLocalImageTransparent(imagePath, outputPath, transparentColor, sampleCorner, tolerance) {
376
+ const inputPath = await resolveExistingImagePath(imagePath);
377
+ const targetPath = resolveImageOutputPath(inputPath, outputPath, "transparent");
378
+ const { data, info } = await (0, sharp_1.default)(inputPath)
379
+ .ensureAlpha()
380
+ .raw()
381
+ .toBuffer({ resolveWithObject: true });
382
+ const targetColor = transparentColor
383
+ ? parseHexColor(transparentColor)
384
+ : sampleCornerColor(data, info.width, info.height, sampleCorner);
385
+ let transparentPixelCount = 0;
386
+ for (let offset = 0; offset < data.length; offset += 4) {
387
+ if (isColorMatch(data, offset, targetColor, tolerance)) {
388
+ data[offset + 3] = 0;
389
+ transparentPixelCount += 1;
390
+ }
391
+ }
392
+ await fsExtra.ensureDir(path.dirname(targetPath));
393
+ const output = await (0, sharp_1.default)(data, {
394
+ raw: {
395
+ width: info.width,
396
+ height: info.height,
397
+ channels: 4,
398
+ },
399
+ })
400
+ .png()
401
+ .toFile(targetPath);
402
+ return [
403
+ "透明图制作成功",
404
+ `input: ${inputPath}`,
405
+ `output: ${targetPath}`,
406
+ `image: ${info.width}x${info.height}`,
407
+ `transparentColor: ${formatRgbHex(targetColor)}`,
408
+ `tolerance: ${tolerance}`,
409
+ `transparentPixels: ${transparentPixelCount}`,
410
+ `size: ${output.size} bytes`,
411
+ ].join("\n");
412
+ }
250
413
  /**
251
414
  * 注册图片处理 MCP 工具
252
415
  * @param server MCP 服务实例
@@ -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 服务实例