ms-vite-plugin 1.4.15 → 1.4.17
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 +707 -9
- package/dist/mcp/doc-tools.d.ts +0 -8
- package/dist/mcp/doc-tools.js +17 -188
- package/dist/mcp/docs-service.d.ts +1 -50
- package/dist/mcp/docs-service.js +0 -105
- package/dist/mcp/httpapi-docs-service.d.ts +8 -32
- package/dist/mcp/httpapi-docs-service.js +8 -89
- package/dist/mcp/httpapi-tools.d.ts +1 -1
- package/dist/mcp/httpapi-tools.js +7 -155
- 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 +12 -4
- package/dist/mcp/tool-utils.d.ts +0 -12
- package/dist/mcp/tool-utils.js +0 -15
- package/dist/mcp/tools.js +0 -1
- package/dist/mcp/types.d.ts +0 -13
- package/dist/project.d.ts +3 -2
- package/dist/project.js +8 -2
- package/docs/AGENTS.md +54 -52
- package/docs/SKILL.md +52 -45
- 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 +58 -73
- package/package.json +1 -1
package/dist/mcp/doc-tools.d.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
/**
|
|
3
|
-
* 注册文档资源
|
|
4
|
-
* @param server MCP 服务实例
|
|
5
|
-
* @returns 无返回值
|
|
6
|
-
* @example
|
|
7
|
-
* registerDocResources(server)
|
|
8
|
-
*/
|
|
9
|
-
export declare function registerDocResources(server: McpServer): void;
|
|
10
2
|
/**
|
|
11
3
|
* 注册文档工具
|
|
12
4
|
* @param server MCP 服务实例
|
package/dist/mcp/doc-tools.js
CHANGED
|
@@ -1,105 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.registerDocResources = registerDocResources;
|
|
37
3
|
exports.registerDocTools = registerDocTools;
|
|
38
|
-
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
39
|
-
const z = __importStar(require("zod/v4"));
|
|
40
4
|
const docs_service_1 = require("./docs-service");
|
|
5
|
+
const httpapi_docs_service_1 = require("./httpapi-docs-service");
|
|
41
6
|
const tool_utils_1 = require("./tool-utils");
|
|
42
7
|
const types_1 = require("./types");
|
|
43
8
|
/**
|
|
44
|
-
*
|
|
45
|
-
* @
|
|
46
|
-
* @returns 无返回值
|
|
9
|
+
* 格式化 KuaiJS 文档路径清单
|
|
10
|
+
* @returns 返回可直接交给 AI 读取的文档路径文本
|
|
47
11
|
* @example
|
|
48
|
-
*
|
|
12
|
+
* const text = formatDocsPathsText()
|
|
49
13
|
*/
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
uri: "kuaijs://docs/current-language",
|
|
60
|
-
mimeType: "application/json",
|
|
61
|
-
text: JSON.stringify({
|
|
62
|
-
currentLanguage: language,
|
|
63
|
-
label: types_1.DOC_LANGUAGE_LABELS[language],
|
|
64
|
-
}, null, 2),
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
};
|
|
68
|
-
});
|
|
69
|
-
server.registerResource("api-doc", new mcp_js_1.ResourceTemplate("kuaijs://docs/current/{slug}", {
|
|
70
|
-
list: async () => {
|
|
71
|
-
const language = (0, docs_service_1.getCurrentDocsLanguage)();
|
|
72
|
-
const docs = await (0, docs_service_1.getApiDocsByLanguage)(language);
|
|
73
|
-
return {
|
|
74
|
-
resources: docs.map((doc) => ({
|
|
75
|
-
uri: `kuaijs://docs/current/${doc.slug}`,
|
|
76
|
-
name: doc.title,
|
|
77
|
-
description: `[${types_1.DOC_LANGUAGE_LABELS[language]}] ${doc.slug}`,
|
|
78
|
-
mimeType: "text/markdown",
|
|
79
|
-
})),
|
|
80
|
-
};
|
|
81
|
-
},
|
|
82
|
-
}), {
|
|
83
|
-
title: "KuaiJS API documents",
|
|
84
|
-
mimeType: "text/markdown",
|
|
85
|
-
}, async (_uri, variables) => {
|
|
86
|
-
const language = (0, docs_service_1.getCurrentDocsLanguage)();
|
|
87
|
-
const docs = await (0, docs_service_1.getApiDocsByLanguage)(language);
|
|
88
|
-
const slug = String(variables.slug || "");
|
|
89
|
-
const target = docs.find((doc) => doc.slug === slug);
|
|
90
|
-
if (!target) {
|
|
91
|
-
throw new Error(`文档不存在: ${slug}`);
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
contents: [
|
|
95
|
-
{
|
|
96
|
-
uri: `kuaijs://docs/current/${target.slug}`,
|
|
97
|
-
mimeType: "text/markdown",
|
|
98
|
-
text: target.content,
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
};
|
|
102
|
-
});
|
|
14
|
+
function formatDocsPathsText() {
|
|
15
|
+
const languages = ["js", "js_zh", "python"];
|
|
16
|
+
return [
|
|
17
|
+
"KuaiJS 文档路径:",
|
|
18
|
+
`docsRoot: ${(0, docs_service_1.getDocsRootDir)()}`,
|
|
19
|
+
...languages.map((language) => `${language}: ${(0, docs_service_1.getDocsDirByLanguage)(language)} (${types_1.DOC_LANGUAGE_LABELS[language]})`),
|
|
20
|
+
`httpApi: ${(0, httpapi_docs_service_1.getHttpApiDocPath)()}`,
|
|
21
|
+
"说明: 直接读取上述 markdown 路径。",
|
|
22
|
+
].join("\n");
|
|
103
23
|
}
|
|
104
24
|
/**
|
|
105
25
|
* 注册文档工具
|
|
@@ -109,102 +29,11 @@ function registerDocResources(server) {
|
|
|
109
29
|
* registerDocTools(server)
|
|
110
30
|
*/
|
|
111
31
|
function registerDocTools(server) {
|
|
112
|
-
server.registerTool("
|
|
113
|
-
title: "Get Docs
|
|
114
|
-
description: "
|
|
32
|
+
server.registerTool("get_docs_paths", {
|
|
33
|
+
title: "Get Docs Paths",
|
|
34
|
+
description: "获取 KuaiJS 本地文档路径,便于 AI 直接读取 markdown 文件而不是猜测位置。",
|
|
115
35
|
inputSchema: {},
|
|
116
36
|
}, async () => {
|
|
117
|
-
|
|
118
|
-
return (0, tool_utils_1.createTextToolResult)(`当前文档语言: ${language} (${types_1.DOC_LANGUAGE_LABELS[language]})`);
|
|
119
|
-
});
|
|
120
|
-
server.registerTool("set_docs_language", {
|
|
121
|
-
title: "Set Docs Language",
|
|
122
|
-
description: "设置当前 KuaiJS API 文档语言,影响后续文档查询与读取。",
|
|
123
|
-
inputSchema: {
|
|
124
|
-
language: z
|
|
125
|
-
.enum(["js", "js_zh", "python"])
|
|
126
|
-
.describe("文档语言:js | js_zh | python"),
|
|
127
|
-
},
|
|
128
|
-
}, async ({ language }) => {
|
|
129
|
-
const active = (0, docs_service_1.setCurrentDocsLanguage)(language);
|
|
130
|
-
const docsDir = (0, docs_service_1.getDocsDirByLanguage)(active);
|
|
131
|
-
return (0, tool_utils_1.createTextToolResult)(`文档语言已切换为 ${active} (${types_1.DOC_LANGUAGE_LABELS[active]})\n目录: ${docsDir}`);
|
|
132
|
-
});
|
|
133
|
-
server.registerTool("list_api_docs", {
|
|
134
|
-
title: "List API Docs",
|
|
135
|
-
description: "列出当前(或指定)语言下可用的 API 文档。",
|
|
136
|
-
inputSchema: {
|
|
137
|
-
language: z
|
|
138
|
-
.enum(["js", "js_zh", "python"])
|
|
139
|
-
.optional()
|
|
140
|
-
.describe("可选语言,不传则使用当前语言"),
|
|
141
|
-
},
|
|
142
|
-
}, async ({ language }) => {
|
|
143
|
-
const activeLanguage = (0, docs_service_1.resolveDocsLanguage)(language);
|
|
144
|
-
const docs = await (0, docs_service_1.getApiDocsByLanguage)(activeLanguage);
|
|
145
|
-
const lines = docs.map((doc, index) => (0, tool_utils_1.formatApiDocSummary)(activeLanguage, doc.title, doc.slug, index));
|
|
146
|
-
return (0, tool_utils_1.createTextToolResult)(lines.length === 0
|
|
147
|
-
? `当前语言 ${activeLanguage} 下没有可用文档。`
|
|
148
|
-
: [
|
|
149
|
-
`当前语言: ${activeLanguage} (${types_1.DOC_LANGUAGE_LABELS[activeLanguage]})`,
|
|
150
|
-
"",
|
|
151
|
-
...lines,
|
|
152
|
-
].join("\n"));
|
|
153
|
-
});
|
|
154
|
-
server.registerTool("search_api_docs", {
|
|
155
|
-
title: "Search API Docs",
|
|
156
|
-
description: "在当前(或指定)语言文档中按关键字搜索。",
|
|
157
|
-
inputSchema: {
|
|
158
|
-
query: z.string().min(1).describe("搜索关键字"),
|
|
159
|
-
limit: z
|
|
160
|
-
.number()
|
|
161
|
-
.int()
|
|
162
|
-
.min(1)
|
|
163
|
-
.max(20)
|
|
164
|
-
.optional()
|
|
165
|
-
.default(5)
|
|
166
|
-
.describe("返回条数上限,默认 5"),
|
|
167
|
-
language: z
|
|
168
|
-
.enum(["js", "js_zh", "python"])
|
|
169
|
-
.optional()
|
|
170
|
-
.describe("可选语言,不传则使用当前语言"),
|
|
171
|
-
},
|
|
172
|
-
}, async ({ query, limit, language }) => {
|
|
173
|
-
const activeLanguage = (0, docs_service_1.resolveDocsLanguage)(language);
|
|
174
|
-
const docs = await (0, docs_service_1.getApiDocsByLanguage)(activeLanguage);
|
|
175
|
-
const normalizedQuery = query.toLowerCase();
|
|
176
|
-
const matches = docs
|
|
177
|
-
.map((doc) => ({ doc, score: (0, docs_service_1.scoreApiDoc)(doc, normalizedQuery) }))
|
|
178
|
-
.filter((item) => item.score > 0)
|
|
179
|
-
.sort((a, b) => b.score - a.score || a.doc.slug.localeCompare(b.doc.slug))
|
|
180
|
-
.slice(0, limit)
|
|
181
|
-
.map((item) => item.doc);
|
|
182
|
-
const text = matches.length === 0
|
|
183
|
-
? `当前语言: ${activeLanguage} (${types_1.DOC_LANGUAGE_LABELS[activeLanguage]})\n未找到与 "${query}" 匹配的文档。`
|
|
184
|
-
: [
|
|
185
|
-
`当前语言: ${activeLanguage} (${types_1.DOC_LANGUAGE_LABELS[activeLanguage]})`,
|
|
186
|
-
"",
|
|
187
|
-
...matches.map((doc, index) => (0, tool_utils_1.formatApiDocSummary)(activeLanguage, doc.title, doc.slug, index)),
|
|
188
|
-
].join("\n");
|
|
189
|
-
return (0, tool_utils_1.createTextToolResult)(text);
|
|
190
|
-
});
|
|
191
|
-
server.registerTool("read_api_doc", {
|
|
192
|
-
title: "Read API Doc",
|
|
193
|
-
description: "读取当前(或指定)语言下某个文档的完整 markdown 内容。",
|
|
194
|
-
inputSchema: {
|
|
195
|
-
slug: z.string().min(1).describe("文档 slug(文件名,不含 .md)"),
|
|
196
|
-
language: z
|
|
197
|
-
.enum(["js", "js_zh", "python"])
|
|
198
|
-
.optional()
|
|
199
|
-
.describe("可选语言,不传则使用当前语言"),
|
|
200
|
-
},
|
|
201
|
-
}, async ({ slug, language }) => {
|
|
202
|
-
const activeLanguage = (0, docs_service_1.resolveDocsLanguage)(language);
|
|
203
|
-
const docs = await (0, docs_service_1.getApiDocsByLanguage)(activeLanguage);
|
|
204
|
-
const target = docs.find((doc) => doc.slug === slug);
|
|
205
|
-
if (!target) {
|
|
206
|
-
return (0, tool_utils_1.createTextToolResult)(`未找到文档 ${slug}.md(语言: ${activeLanguage})。`, true);
|
|
207
|
-
}
|
|
208
|
-
return (0, tool_utils_1.createTextToolResult)(`标题: ${target.title}\n语言: ${activeLanguage}\nURI: ${(0, docs_service_1.getDocUri)(activeLanguage, target.slug)}\n\n${target.content}`);
|
|
37
|
+
return (0, tool_utils_1.createTextToolResult)(formatDocsPathsText());
|
|
209
38
|
});
|
|
210
39
|
}
|
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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;
|
|
1
|
+
import type { ApiDocsLanguage } from "./types";
|
|
25
2
|
/**
|
|
26
3
|
* 获取 docs 根目录
|
|
27
4
|
* @returns 返回 docs 目录绝对路径
|
|
@@ -37,29 +14,3 @@ export declare function getDocsRootDir(): string;
|
|
|
37
14
|
* const dir = getDocsDirByLanguage("js_zh")
|
|
38
15
|
*/
|
|
39
16
|
export declare function getDocsDirByLanguage(language: ApiDocsLanguage): string;
|
|
40
|
-
/**
|
|
41
|
-
* 读取指定语言的 API 文档列表
|
|
42
|
-
* @param language 文档语言
|
|
43
|
-
* @returns 返回文档条目数组(按 slug 升序)
|
|
44
|
-
* @example
|
|
45
|
-
* const docs = await getApiDocsByLanguage("python")
|
|
46
|
-
*/
|
|
47
|
-
export declare function getApiDocsByLanguage(language: ApiDocsLanguage): Promise<ApiDocItem[]>;
|
|
48
|
-
/**
|
|
49
|
-
* 对文档按查询词打分,用于检索排序
|
|
50
|
-
* @param doc 文档条目
|
|
51
|
-
* @param normalizedQuery 已转小写的查询词
|
|
52
|
-
* @returns 分数,0 表示不命中
|
|
53
|
-
* @example
|
|
54
|
-
* const score = scoreApiDoc(doc, "click")
|
|
55
|
-
*/
|
|
56
|
-
export declare function scoreApiDoc(doc: ApiDocItem, normalizedQuery: string): number;
|
|
57
|
-
/**
|
|
58
|
-
* 生成文档 URI(用于资源与文本返回)
|
|
59
|
-
* @param language 文档语言
|
|
60
|
-
* @param slug 文档分类
|
|
61
|
-
* @returns 返回 MCP 资源 URI 字符串
|
|
62
|
-
* @example
|
|
63
|
-
* const uri = getDocUri("js_zh", "device")
|
|
64
|
-
*/
|
|
65
|
-
export declare function getDocUri(language: ApiDocsLanguage, slug: string): string;
|
package/dist/mcp/docs-service.js
CHANGED
|
@@ -33,50 +33,9 @@ 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
|
-
exports.getApiDocsByLanguage = getApiDocsByLanguage;
|
|
42
|
-
exports.scoreApiDoc = scoreApiDoc;
|
|
43
|
-
exports.getDocUri = getDocUri;
|
|
44
|
-
const fsExtra = __importStar(require("fs-extra"));
|
|
45
38
|
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
39
|
/**
|
|
81
40
|
* 获取 docs 根目录
|
|
82
41
|
* @returns 返回 docs 目录绝对路径
|
|
@@ -102,67 +61,3 @@ function getDocsDirByLanguage(language) {
|
|
|
102
61
|
}
|
|
103
62
|
return path.join(getDocsRootDir(), "apipython");
|
|
104
63
|
}
|
|
105
|
-
/**
|
|
106
|
-
* 读取指定语言的 API 文档列表
|
|
107
|
-
* @param language 文档语言
|
|
108
|
-
* @returns 返回文档条目数组(按 slug 升序)
|
|
109
|
-
* @example
|
|
110
|
-
* const docs = await getApiDocsByLanguage("python")
|
|
111
|
-
*/
|
|
112
|
-
async function getApiDocsByLanguage(language) {
|
|
113
|
-
const docsDir = getDocsDirByLanguage(language);
|
|
114
|
-
if (!(await fsExtra.pathExists(docsDir))) {
|
|
115
|
-
throw new Error(`文档目录不存在: ${docsDir}`);
|
|
116
|
-
}
|
|
117
|
-
const fileNames = await fsExtra.readdir(docsDir);
|
|
118
|
-
const mdFiles = fileNames
|
|
119
|
-
.filter((name) => name.toLowerCase().endsWith(".md"))
|
|
120
|
-
.sort();
|
|
121
|
-
const docs = [];
|
|
122
|
-
for (const fileName of mdFiles) {
|
|
123
|
-
const filePath = path.join(docsDir, fileName);
|
|
124
|
-
const content = await fsExtra.readFile(filePath, "utf8");
|
|
125
|
-
const slug = path.basename(fileName, ".md");
|
|
126
|
-
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
127
|
-
const title = titleMatch?.[1]?.trim() || slug;
|
|
128
|
-
docs.push({
|
|
129
|
-
slug,
|
|
130
|
-
title,
|
|
131
|
-
content,
|
|
132
|
-
filePath,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
return docs;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* 对文档按查询词打分,用于检索排序
|
|
139
|
-
* @param doc 文档条目
|
|
140
|
-
* @param normalizedQuery 已转小写的查询词
|
|
141
|
-
* @returns 分数,0 表示不命中
|
|
142
|
-
* @example
|
|
143
|
-
* const score = scoreApiDoc(doc, "click")
|
|
144
|
-
*/
|
|
145
|
-
function scoreApiDoc(doc, normalizedQuery) {
|
|
146
|
-
let score = 0;
|
|
147
|
-
if (doc.title.toLowerCase().includes(normalizedQuery)) {
|
|
148
|
-
score += 50;
|
|
149
|
-
}
|
|
150
|
-
if (doc.slug.toLowerCase().includes(normalizedQuery)) {
|
|
151
|
-
score += 40;
|
|
152
|
-
}
|
|
153
|
-
if (doc.content.toLowerCase().includes(normalizedQuery)) {
|
|
154
|
-
score += 10;
|
|
155
|
-
}
|
|
156
|
-
return score;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* 生成文档 URI(用于资源与文本返回)
|
|
160
|
-
* @param language 文档语言
|
|
161
|
-
* @param slug 文档分类
|
|
162
|
-
* @returns 返回 MCP 资源 URI 字符串
|
|
163
|
-
* @example
|
|
164
|
-
* const uri = getDocUri("js_zh", "device")
|
|
165
|
-
*/
|
|
166
|
-
function getDocUri(language, slug) {
|
|
167
|
-
return `kuaijs://docs/${language}/${slug}`;
|
|
168
|
-
}
|
|
@@ -6,39 +6,24 @@ export type HttpApiMethod = "GET" | "POST";
|
|
|
6
6
|
* HTTP API 文档条目
|
|
7
7
|
*/
|
|
8
8
|
export type HttpApiDocEntry = {
|
|
9
|
-
/** 稳定 slug,可用于读取单个接口文档 */
|
|
10
|
-
slug: string;
|
|
11
9
|
/** 接口请求方法 */
|
|
12
10
|
method: HttpApiMethod;
|
|
13
11
|
/** 接口路径 */
|
|
14
12
|
path: string;
|
|
15
13
|
/** 接口标题 */
|
|
16
14
|
title: string;
|
|
17
|
-
/** 所属一级章节 */
|
|
18
|
-
section: string;
|
|
19
15
|
/** 文档片段起始行号(1-based) */
|
|
20
16
|
startLine: number;
|
|
21
17
|
/** 文档片段结束行号(1-based) */
|
|
22
18
|
endLine: number;
|
|
23
|
-
/** 接口完整 markdown 片段 */
|
|
24
|
-
content: string;
|
|
25
19
|
};
|
|
26
20
|
/**
|
|
27
|
-
*
|
|
28
|
-
* @returns
|
|
21
|
+
* 获取 HTTP API 文档路径
|
|
22
|
+
* @returns 返回 HTTP API 文档绝对路径
|
|
29
23
|
* @example
|
|
30
|
-
* const
|
|
24
|
+
* const filePath = getHttpApiDocPath()
|
|
31
25
|
*/
|
|
32
|
-
export declare function
|
|
33
|
-
/**
|
|
34
|
-
* 根据 method/path 生成稳定 slug
|
|
35
|
-
* @param method HTTP 请求方法
|
|
36
|
-
* @param apiPath HTTP API 路径
|
|
37
|
-
* @returns 返回可用于 MCP 资源路径的 slug
|
|
38
|
-
* @example
|
|
39
|
-
* createHttpApiSlug("GET", "/api/control/click")
|
|
40
|
-
*/
|
|
41
|
-
export declare function createHttpApiSlug(method: HttpApiMethod, apiPath: string): string;
|
|
26
|
+
export declare function getHttpApiDocPath(): string;
|
|
42
27
|
/**
|
|
43
28
|
* 解析 HTTP API markdown 为接口条目
|
|
44
29
|
* @returns 返回按文档顺序排列的接口条目
|
|
@@ -47,20 +32,11 @@ export declare function createHttpApiSlug(method: HttpApiMethod, apiPath: string
|
|
|
47
32
|
*/
|
|
48
33
|
export declare function getHttpApiDocEntries(): Promise<HttpApiDocEntry[]>;
|
|
49
34
|
/**
|
|
50
|
-
*
|
|
51
|
-
* @param
|
|
52
|
-
* @param
|
|
53
|
-
* @returns 返回匹配分数,0 表示不匹配
|
|
54
|
-
* @example
|
|
55
|
-
* scoreHttpApiDocEntry(entry, "click")
|
|
56
|
-
*/
|
|
57
|
-
export declare function scoreHttpApiDocEntry(entry: HttpApiDocEntry, normalizedQuery: string): number;
|
|
58
|
-
/**
|
|
59
|
-
* 根据 slug 或 path 查找 HTTP API 文档条目
|
|
60
|
-
* @param identifier slug 或 API 路径
|
|
61
|
-
* @param method 可选 HTTP 方法,用于同路径多方法时消歧
|
|
35
|
+
* 根据 method/path 查找 HTTP API 文档条目
|
|
36
|
+
* @param apiPath API 路径
|
|
37
|
+
* @param method HTTP 方法
|
|
62
38
|
* @returns 找到时返回条目,否则返回 undefined
|
|
63
39
|
* @example
|
|
64
40
|
* const entry = await findHttpApiDocEntry("/api/control/click", "GET")
|
|
65
41
|
*/
|
|
66
|
-
export declare function findHttpApiDocEntry(
|
|
42
|
+
export declare function findHttpApiDocEntry(apiPath: string, method: HttpApiMethod): Promise<HttpApiDocEntry | undefined>;
|
|
@@ -33,16 +33,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
exports.createHttpApiSlug = createHttpApiSlug;
|
|
36
|
+
exports.getHttpApiDocPath = getHttpApiDocPath;
|
|
38
37
|
exports.getHttpApiDocEntries = getHttpApiDocEntries;
|
|
39
|
-
exports.scoreHttpApiDocEntry = scoreHttpApiDocEntry;
|
|
40
38
|
exports.findHttpApiDocEntry = findHttpApiDocEntry;
|
|
41
39
|
const fsExtra = __importStar(require("fs-extra"));
|
|
42
40
|
const path = __importStar(require("path"));
|
|
43
41
|
const HTTP_API_DOC_RELATIVE_PATH = ["docs", "httpapi", "api.md"];
|
|
44
42
|
const HTTP_API_ENDPOINT_PATTERN = /^(GET|POST)\s+(\/\S+)/;
|
|
45
|
-
const HTTP_API_SECTION_PATTERN = /^#\s+(.+)$/;
|
|
46
43
|
const HTTP_API_TITLE_PATTERN = /^##\s+(.+)$/;
|
|
47
44
|
let cachedHttpApiDocEntries = null;
|
|
48
45
|
/**
|
|
@@ -54,33 +51,6 @@ let cachedHttpApiDocEntries = null;
|
|
|
54
51
|
function getHttpApiDocPath() {
|
|
55
52
|
return path.resolve(__dirname, "..", "..", ...HTTP_API_DOC_RELATIVE_PATH);
|
|
56
53
|
}
|
|
57
|
-
/**
|
|
58
|
-
* 读取 HTTP API markdown 文档
|
|
59
|
-
* @returns 返回完整 markdown 文本
|
|
60
|
-
* @example
|
|
61
|
-
* const markdown = await readHttpApiMarkdown()
|
|
62
|
-
*/
|
|
63
|
-
async function readHttpApiMarkdown() {
|
|
64
|
-
const filePath = getHttpApiDocPath();
|
|
65
|
-
if (!(await fsExtra.pathExists(filePath))) {
|
|
66
|
-
throw new Error("HTTP API 文档不可用。");
|
|
67
|
-
}
|
|
68
|
-
return fsExtra.readFile(filePath, "utf8");
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* 根据 method/path 生成稳定 slug
|
|
72
|
-
* @param method HTTP 请求方法
|
|
73
|
-
* @param apiPath HTTP API 路径
|
|
74
|
-
* @returns 返回可用于 MCP 资源路径的 slug
|
|
75
|
-
* @example
|
|
76
|
-
* createHttpApiSlug("GET", "/api/control/click")
|
|
77
|
-
*/
|
|
78
|
-
function createHttpApiSlug(method, apiPath) {
|
|
79
|
-
return `${method.toLowerCase()}-${apiPath}`
|
|
80
|
-
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
81
|
-
.replace(/^-+|-+$/g, "")
|
|
82
|
-
.toLowerCase();
|
|
83
|
-
}
|
|
84
54
|
/**
|
|
85
55
|
* 解析 HTTP API markdown 为接口条目
|
|
86
56
|
* @returns 返回按文档顺序排列的接口条目
|
|
@@ -89,24 +59,15 @@ function createHttpApiSlug(method, apiPath) {
|
|
|
89
59
|
*/
|
|
90
60
|
async function getHttpApiDocEntries() {
|
|
91
61
|
const filePath = getHttpApiDocPath();
|
|
92
|
-
const stat = await fsExtra.stat(filePath)
|
|
93
|
-
if (!stat) {
|
|
94
|
-
throw new Error("HTTP API 文档不可用。");
|
|
95
|
-
}
|
|
62
|
+
const stat = await fsExtra.stat(filePath);
|
|
96
63
|
if (cachedHttpApiDocEntries?.mtimeMs === stat.mtimeMs) {
|
|
97
64
|
return cachedHttpApiDocEntries.entries;
|
|
98
65
|
}
|
|
99
66
|
const markdown = await fsExtra.readFile(filePath, "utf8");
|
|
100
67
|
const lines = markdown.split(/\r?\n/);
|
|
101
68
|
const entries = [];
|
|
102
|
-
let currentSection = "";
|
|
103
69
|
for (let index = 0; index < lines.length; index += 1) {
|
|
104
70
|
const line = lines[index] ?? "";
|
|
105
|
-
const sectionMatch = line.match(HTTP_API_SECTION_PATTERN);
|
|
106
|
-
if (sectionMatch) {
|
|
107
|
-
currentSection = sectionMatch[1]?.trim() ?? "";
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
71
|
const titleMatch = line.match(HTTP_API_TITLE_PATTERN);
|
|
111
72
|
if (!titleMatch) {
|
|
112
73
|
continue;
|
|
@@ -133,14 +94,11 @@ async function getHttpApiDocEntries() {
|
|
|
133
94
|
}
|
|
134
95
|
}
|
|
135
96
|
entries.push({
|
|
136
|
-
slug: createHttpApiSlug(method, apiPath),
|
|
137
97
|
method,
|
|
138
98
|
path: apiPath,
|
|
139
99
|
title,
|
|
140
|
-
section: currentSection,
|
|
141
100
|
startLine: index + 1,
|
|
142
101
|
endLine: endIndex,
|
|
143
|
-
content: lines.slice(index, endIndex).join("\n").trim(),
|
|
144
102
|
});
|
|
145
103
|
}
|
|
146
104
|
cachedHttpApiDocEntries = {
|
|
@@ -150,54 +108,15 @@ async function getHttpApiDocEntries() {
|
|
|
150
108
|
return entries;
|
|
151
109
|
}
|
|
152
110
|
/**
|
|
153
|
-
*
|
|
154
|
-
* @param
|
|
155
|
-
* @param
|
|
156
|
-
* @returns 返回匹配分数,0 表示不匹配
|
|
157
|
-
* @example
|
|
158
|
-
* scoreHttpApiDocEntry(entry, "click")
|
|
159
|
-
*/
|
|
160
|
-
function scoreHttpApiDocEntry(entry, normalizedQuery) {
|
|
161
|
-
const query = normalizedQuery.trim();
|
|
162
|
-
if (!query) {
|
|
163
|
-
return 0;
|
|
164
|
-
}
|
|
165
|
-
let score = 0;
|
|
166
|
-
if (entry.path.toLowerCase() === query) {
|
|
167
|
-
score += 100;
|
|
168
|
-
}
|
|
169
|
-
if (`${entry.method} ${entry.path}`.toLowerCase() === query) {
|
|
170
|
-
score += 120;
|
|
171
|
-
}
|
|
172
|
-
if (entry.path.toLowerCase().includes(query)) {
|
|
173
|
-
score += 60;
|
|
174
|
-
}
|
|
175
|
-
if (entry.title.toLowerCase().includes(query)) {
|
|
176
|
-
score += 50;
|
|
177
|
-
}
|
|
178
|
-
if (entry.section.toLowerCase().includes(query)) {
|
|
179
|
-
score += 20;
|
|
180
|
-
}
|
|
181
|
-
if (entry.content.toLowerCase().includes(query)) {
|
|
182
|
-
score += 10;
|
|
183
|
-
}
|
|
184
|
-
return score;
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* 根据 slug 或 path 查找 HTTP API 文档条目
|
|
188
|
-
* @param identifier slug 或 API 路径
|
|
189
|
-
* @param method 可选 HTTP 方法,用于同路径多方法时消歧
|
|
111
|
+
* 根据 method/path 查找 HTTP API 文档条目
|
|
112
|
+
* @param apiPath API 路径
|
|
113
|
+
* @param method HTTP 方法
|
|
190
114
|
* @returns 找到时返回条目,否则返回 undefined
|
|
191
115
|
* @example
|
|
192
116
|
* const entry = await findHttpApiDocEntry("/api/control/click", "GET")
|
|
193
117
|
*/
|
|
194
|
-
async function findHttpApiDocEntry(
|
|
195
|
-
const
|
|
118
|
+
async function findHttpApiDocEntry(apiPath, method) {
|
|
119
|
+
const normalizedPath = apiPath.trim();
|
|
196
120
|
const entries = await getHttpApiDocEntries();
|
|
197
|
-
return entries.find((entry) =>
|
|
198
|
-
const methodMatches = method ? entry.method === method : true;
|
|
199
|
-
return (methodMatches &&
|
|
200
|
-
(entry.slug === normalizedIdentifier ||
|
|
201
|
-
entry.path === normalizedIdentifier));
|
|
202
|
-
});
|
|
121
|
+
return entries.find((entry) => entry.method === method && entry.path === normalizedPath);
|
|
203
122
|
}
|