@mijadesign/nut-mcp 1.0.0-alpha.0

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.
Files changed (58) hide show
  1. package/README.md +147 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +16 -0
  4. package/dist/services/aliases.service.d.ts +1 -0
  5. package/dist/services/aliases.service.js +19 -0
  6. package/dist/services/doc-parser.service.d.ts +3 -0
  7. package/dist/services/doc-parser.service.js +162 -0
  8. package/dist/services/index.services.d.ts +3 -0
  9. package/dist/services/index.services.js +71 -0
  10. package/dist/services/paths.service.d.ts +5 -0
  11. package/dist/services/paths.service.js +18 -0
  12. package/dist/tools/base.tool.d.ts +8 -0
  13. package/dist/tools/base.tool.js +27 -0
  14. package/dist/tools/get-component-doc.tool.d.ts +12 -0
  15. package/dist/tools/get-component-doc.tool.js +40 -0
  16. package/dist/tools/index.d.ts +4 -0
  17. package/dist/tools/index.js +4 -0
  18. package/dist/tools/list-components.tool.d.ts +8 -0
  19. package/dist/tools/list-components.tool.js +32 -0
  20. package/dist/tools/search-components.tool.d.ts +12 -0
  21. package/dist/tools/search-components.tool.js +61 -0
  22. package/dist/types/index.d.ts +33 -0
  23. package/dist/types/index.js +1 -0
  24. package/docs/docs/aliases.json +59 -0
  25. package/docs/docs/components/base/button/index.md +415 -0
  26. package/docs/docs/components/base/cell/index.md +279 -0
  27. package/docs/docs/components/base/configprovider/index.md +215 -0
  28. package/docs/docs/components/base/image/index.md +282 -0
  29. package/docs/docs/components/base/overlay/index.md +288 -0
  30. package/docs/docs/components/dentry/cascader/index.md +1080 -0
  31. package/docs/docs/components/dentry/checkbox/index.md +842 -0
  32. package/docs/docs/components/dentry/datepicker/index.md +489 -0
  33. package/docs/docs/components/dentry/form/index.md +457 -0
  34. package/docs/docs/components/dentry/input/index.md +257 -0
  35. package/docs/docs/components/dentry/picker/index.md +621 -0
  36. package/docs/docs/components/dentry/radio/index.md +364 -0
  37. package/docs/docs/components/dentry/searchbar/index.md +317 -0
  38. package/docs/docs/components/dentry/selector/index.md +295 -0
  39. package/docs/docs/components/dentry/switch/index.md +300 -0
  40. package/docs/docs/components/dentry/textarea/index.md +231 -0
  41. package/docs/docs/components/dentry/uploader/index.md +745 -0
  42. package/docs/docs/components/exhibition/collapse/index.md +339 -0
  43. package/docs/docs/components/exhibition/swiper/index.md +385 -0
  44. package/docs/docs/components/exhibition/tag/index.md +253 -0
  45. package/docs/docs/components/feedback/dialog/index.md +306 -0
  46. package/docs/docs/components/feedback/drag/index.md +164 -0
  47. package/docs/docs/components/feedback/empty/index.md +211 -0
  48. package/docs/docs/components/feedback/infiniteloading/index.md +397 -0
  49. package/docs/docs/components/feedback/noticebar/index.md +175 -0
  50. package/docs/docs/components/feedback/popup/index.md +563 -0
  51. package/docs/docs/components/feedback/pulltorefresh/index.md +254 -0
  52. package/docs/docs/components/feedback/toast/index.md +355 -0
  53. package/docs/docs/components/layout/divider/index.md +162 -0
  54. package/docs/docs/components/layout/grid/index.md +386 -0
  55. package/docs/docs/components/layout/space/index.md +196 -0
  56. package/docs/docs/components/nav/tabs/index.md +955 -0
  57. package/docs/docs/components-index.json +233 -0
  58. package/package.json +34 -0
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # Mija Design MCP
2
+
3
+ 专为 `@mijadesign/mjui-react-taro` 定制的 MCP Server,用于让 AI 编码工具按组件库文档生成代码。
4
+
5
+ 它会读取组件索引、组件 Markdown 文档和中文别名配置,提供组件列表、组件搜索、组件 API 与示例查询能力。
6
+
7
+ ## 工具列表
8
+
9
+ | 工具 | 作用 | 使用建议 |
10
+ | ------------------- | ---------------------------------------- | ------------------------------------------ |
11
+ | `list_components` | 列出全部组件,并按分组归类 | 不确定组件名时先调用 |
12
+ | `search_components` | 按关键词、中文别名、组件名、描述搜索组件 | 找到候选组件后继续调用 `get_component_doc` |
13
+ | `get_component_doc` | 获取指定组件的 props、示例、版本和说明 | 生成代码前必须调用,避免使用不存在的 prop |
14
+
15
+ ## 数据来源
16
+
17
+ 运行时依赖以下文档数据:
18
+
19
+ - `docs/docs/components-index.json`
20
+ - `docs/docs/aliases.json`
21
+ - `docs/docs/components/**/index.md`
22
+
23
+ 运行时优先读取当前包内的 `docs/docs`。未生成包内文档时,本地开发会回退读取仓库根目录的 `docs/docs`。发布前会通过 `prepare:docs` 复制一份到当前包内,发布后的 npm 包会读取包内文档。
24
+
25
+ ## 本地开发
26
+
27
+ ```bash
28
+ cd packages/mcp-mjui
29
+ npm install
30
+ npm run dev
31
+ ```
32
+
33
+ 本地 MCP 客户端配置示例:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "mija-design": {
39
+ "command": "npx",
40
+ "args": [
41
+ "tsx",
42
+ "/Users/moon/Desktop/work/frontend-mobile-core/packages/mcp-mjui/src/index.ts"
43
+ ]
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ 也可以先构建后用 Node 启动:
50
+
51
+ ```bash
52
+ cd packages/mcp-mjui
53
+ npm run prepare:docs
54
+ npm run build
55
+ npm run start
56
+ ```
57
+
58
+ 对应配置:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "mija-design": {
64
+ "command": "node",
65
+ "args": [
66
+ "/Users/moon/Desktop/work/frontend-mobile-core/packages/mcp-mjui/dist/index.js"
67
+ ]
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ ## 发布
74
+
75
+ 发布前确认包内文档和构建产物都已生成:
76
+
77
+ ```bash
78
+ cd packages/mcp-mjui
79
+ npm run prepack
80
+ npm pack --dry-run
81
+ ```
82
+
83
+ 确认 `npm pack --dry-run` 输出中包含:
84
+
85
+ - `dist/index.js`
86
+ - `dist/services/**`
87
+ - `docs/docs/components-index.json`
88
+ - `docs/docs/aliases.json`
89
+ - `docs/docs/components/**/index.md`
90
+
91
+ 发布:
92
+
93
+ ```bash
94
+ npm publish --access public
95
+ ```
96
+
97
+ ## 发布后如何使用
98
+
99
+ 发布后,在支持 MCP 的 IDE 或 AI 编码工具中添加 stdio server 配置:
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "mija-design": {
105
+ "command": "npx",
106
+ "args": ["-y", "@mijadesign/nut-mcp"]
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ 如果已经全局安装:
113
+
114
+ ```bash
115
+ npm install -g @mijadesign/nut-mcp
116
+ ```
117
+
118
+ 可配置为:
119
+
120
+ ```json
121
+ {
122
+ "mcpServers": {
123
+ "mija-design": {
124
+ "command": "mija-mcp",
125
+ "args": []
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ 客户端连接成功后,AI 工具应按这个顺序使用:
132
+
133
+ 1. 不确定组件时,调用 `search_components` 或 `list_components`。
134
+ 2. 确认组件后,调用 `get_component_doc` 获取 props 与 demos。
135
+ 3. 生成代码时只使用文档返回的 prop 和示例结构。
136
+
137
+ 示例提问:
138
+
139
+ ```text
140
+ 使用 Mija Design 的按钮和弹窗组件实现确认删除流程。生成代码前先查询组件文档。
141
+ ```
142
+
143
+ ## 维护说明
144
+
145
+ - 新增组件后,需要同步更新 `docs/docs/components-index.json`。
146
+ - 新增中文叫法或业务别名后,更新 `docs/docs/aliases.json`。
147
+ - 组件文档中的 Props 表格和示例代码会被 MCP 解析,修改 Markdown 结构时要确认 `get_component_doc` 返回正常。
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { ListComponentsTool, GetComponentDocTool, SearchComponentsTool, } from "./tools/index.js";
5
+ async function main() {
6
+ const server = new McpServer({
7
+ name: "mija-design-mcp",
8
+ version: "1.0.0",
9
+ });
10
+ // 所有 MCP 能力统一在这里注册,便于客户端从同一个 stdio 服务发现完整组件工作流。
11
+ new ListComponentsTool().register(server);
12
+ new GetComponentDocTool().register(server);
13
+ new SearchComponentsTool().register(server);
14
+ await server.connect(new StdioServerTransport());
15
+ }
16
+ main().catch(console.error);
@@ -0,0 +1 @@
1
+ export declare function loadAliases(): Promise<Record<string, string>>;
@@ -0,0 +1,19 @@
1
+ import fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { resolveDocsDir } from "./paths.service.js";
4
+ const ALIASES_FILE = path.join(resolveDocsDir(), "aliases.json");
5
+ let aliasesCache = null;
6
+ export async function loadAliases() {
7
+ if (aliasesCache !== null)
8
+ return aliasesCache;
9
+ try {
10
+ const content = await fs.readFile(ALIASES_FILE, "utf-8");
11
+ const config = JSON.parse(content);
12
+ aliasesCache = config.aliases ?? {};
13
+ }
14
+ catch (error) {
15
+ console.error("加载别名配置文件失败,将使用空别名表:", error);
16
+ aliasesCache = {};
17
+ }
18
+ return aliasesCache;
19
+ }
@@ -0,0 +1,3 @@
1
+ import { ComponentDoc, ComponentSummary } from "../types/index.js";
2
+ export declare function buildDocPathMap(): Promise<void>;
3
+ export declare function loadDoc(summary: ComponentSummary): Promise<ComponentDoc>;
@@ -0,0 +1,162 @@
1
+ import fs from "fs/promises";
2
+ import * as path from "path";
3
+ import yaml from "js-yaml";
4
+ import { resolveDocsDir } from "./paths.service.js";
5
+ const DOCS_DIR = path.join(resolveDocsDir(), "components");
6
+ const docCache = new Map();
7
+ const docPathMap = new Map();
8
+ export async function buildDocPathMap() {
9
+ if (docPathMap.size > 0)
10
+ return;
11
+ async function scan(dir) {
12
+ let entries;
13
+ try {
14
+ entries = await fs.readdir(dir, { withFileTypes: true });
15
+ }
16
+ catch {
17
+ return;
18
+ }
19
+ for (const entry of entries) {
20
+ if (!entry.isDirectory())
21
+ continue;
22
+ const full = path.join(dir, entry.name);
23
+ const mdPath = path.join(full, "index.md");
24
+ try {
25
+ await fs.access(mdPath);
26
+ docPathMap.set(entry.name.toLowerCase(), mdPath);
27
+ }
28
+ catch { }
29
+ await scan(full);
30
+ }
31
+ }
32
+ await scan(DOCS_DIR);
33
+ }
34
+ function parseFrontmatter(content) {
35
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
36
+ if (!match)
37
+ return { frontmatter: {}, body: content };
38
+ try {
39
+ const frontmatter = yaml.load(match[1]);
40
+ return { frontmatter, body: content.slice(match[0].length) };
41
+ }
42
+ catch {
43
+ return { frontmatter: {}, body: content };
44
+ }
45
+ }
46
+ function extractVersion(body, frontmatter) {
47
+ const m = body.match(/<Badge[^>]*>([^<]+)<\/Badge>/);
48
+ return m ? m[1] : (frontmatter.version ?? "");
49
+ }
50
+ function extractProps(body) {
51
+ const props = [];
52
+ const lines = body.split("\n");
53
+ let inTable = false;
54
+ const headerNames = new Set([
55
+ "参数",
56
+ "name",
57
+ "属性",
58
+ "prop",
59
+ "property",
60
+ "名称",
61
+ "方法名",
62
+ ]);
63
+ for (const line of lines) {
64
+ if (/^###\s*(Props|API|属性)/i.test(line)) {
65
+ inTable = true;
66
+ continue;
67
+ }
68
+ if (inTable && /^#{2,3}\s/.test(line) && !/Props|API|属性/i.test(line)) {
69
+ inTable = false;
70
+ continue;
71
+ }
72
+ if (inTable && line.startsWith("|") && !line.includes("---")) {
73
+ // API 表格里可能会转义联合类型分隔符,例如 `left\|right`。
74
+ // 拆分表格列前先保护这些已转义的竖线。
75
+ const ESCAPED_PIPE = "\x00";
76
+ const cols = line
77
+ .replace(/\\\|/g, ESCAPED_PIPE)
78
+ .split("|")
79
+ .map((c) => c.trim().replace(/\x00/g, "|"))
80
+ .filter(Boolean);
81
+ if (cols.length >= 3 && !headerNames.has(cols[0].toLowerCase())) {
82
+ props.push({
83
+ name: cols[0],
84
+ description: cols[1],
85
+ type: cols[2],
86
+ default: cols[3] ?? "-",
87
+ });
88
+ }
89
+ }
90
+ }
91
+ return props;
92
+ }
93
+ function extractDemos(body) {
94
+ const demos = [];
95
+ const lines = body.split("\n");
96
+ let title = "";
97
+ let code = [];
98
+ let inBlock = false;
99
+ let inDemoSection = false;
100
+ for (const line of lines) {
101
+ if (/^##\s+(示例代码|代码演示|代码示例|Examples?|Demos?)/i.test(line)) {
102
+ inDemoSection = true;
103
+ continue;
104
+ }
105
+ if (inDemoSection && !inBlock && /^##[^#]/.test(line)) {
106
+ break;
107
+ }
108
+ if (!inDemoSection)
109
+ continue;
110
+ if (/^```/.test(line)) {
111
+ if (inBlock) {
112
+ // 示例区里的每个代码块都会作为一个可直接提供给模型的示例。
113
+ if (code.length)
114
+ demos.push({ title: title || "示例", code: code.join("\n") });
115
+ code = [];
116
+ inBlock = false;
117
+ }
118
+ else {
119
+ inBlock = true;
120
+ }
121
+ continue;
122
+ }
123
+ if (inBlock) {
124
+ code.push(line);
125
+ }
126
+ else {
127
+ const m = line.match(/^###\s+(.+)/);
128
+ if (m)
129
+ title = m[1].trim();
130
+ }
131
+ }
132
+ return demos;
133
+ }
134
+ export async function loadDoc(summary) {
135
+ const key = summary.dirName.toLowerCase();
136
+ if (docCache.has(key))
137
+ return docCache.get(key);
138
+ const mdPath = docPathMap.get(key) ?? path.join(DOCS_DIR, summary.dirName, "index.md");
139
+ let content = "";
140
+ try {
141
+ content = await fs.readFile(mdPath, "utf-8");
142
+ }
143
+ catch {
144
+ const fallback = {
145
+ ...summary,
146
+ version: "",
147
+ props: [],
148
+ demos: [],
149
+ };
150
+ docCache.set(key, fallback);
151
+ return fallback;
152
+ }
153
+ const { frontmatter, body } = parseFrontmatter(content);
154
+ const doc = {
155
+ ...summary,
156
+ version: extractVersion(body, frontmatter),
157
+ props: extractProps(body),
158
+ demos: extractDemos(body),
159
+ };
160
+ docCache.set(key, doc);
161
+ return doc;
162
+ }
@@ -0,0 +1,3 @@
1
+ import { RuntimeIndex, ComponentSummary } from "../types/index.js";
2
+ export declare function getIndex(): Promise<RuntimeIndex>;
3
+ export declare function findSummary(query: string, idx: RuntimeIndex): ComponentSummary | undefined;
@@ -0,0 +1,71 @@
1
+ import fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { loadAliases } from "./aliases.service.js";
4
+ import { buildDocPathMap } from "./doc-parser.service.js";
5
+ import { resolveDocsDir } from "./paths.service.js";
6
+ const INDEX_FILE = path.join(resolveDocsDir(), "components-index.json");
7
+ let runtimeIndex = null;
8
+ function tokenize(text) {
9
+ const tokens = new Set();
10
+ const lower = text.toLowerCase();
11
+ // 英文组件名和中文描述需要不同的分词粒度。
12
+ for (const word of lower.match(/[a-z]+/g) ?? []) {
13
+ if (word.length > 1)
14
+ tokens.add(word);
15
+ }
16
+ for (const char of lower.match(/[\u4e00-\u9fa5]/g) ?? []) {
17
+ tokens.add(char);
18
+ }
19
+ return [...tokens];
20
+ }
21
+ function buildRuntimeIndex(summaries, aliases) {
22
+ const byDirName = new Map();
23
+ const byEnName = new Map();
24
+ const invertedIndex = new Map();
25
+ const aliasMap = new Map();
26
+ for (const [alias, dirName] of Object.entries(aliases)) {
27
+ aliasMap.set(alias, dirName.toLowerCase());
28
+ }
29
+ for (const s of summaries) {
30
+ const dirKey = s.dirName.toLowerCase();
31
+ byDirName.set(dirKey, s);
32
+ const enName = s.name.split(/\s+/)[0].toLowerCase();
33
+ byEnName.set(enName, s);
34
+ const fields = [s.name, s.description, s.whenToUse, s.group ?? ""].join(" ");
35
+ // 倒排索引只保存 dirName,搜索结果再回到规范的组件摘要表取详情。
36
+ for (const token of tokenize(fields)) {
37
+ if (!invertedIndex.has(token))
38
+ invertedIndex.set(token, []);
39
+ const list = invertedIndex.get(token);
40
+ if (!list.includes(s.dirName))
41
+ list.push(s.dirName);
42
+ }
43
+ }
44
+ return {
45
+ summaries,
46
+ byDirName,
47
+ byEnName,
48
+ invertedIndex,
49
+ aliasMap,
50
+ buildTime: Date.now(),
51
+ };
52
+ }
53
+ export async function getIndex() {
54
+ if (runtimeIndex)
55
+ return runtimeIndex;
56
+ const [raw, aliases] = await Promise.all([
57
+ fs.readFile(INDEX_FILE, "utf-8"),
58
+ loadAliases(),
59
+ buildDocPathMap(),
60
+ ]);
61
+ const summaries = JSON.parse(raw);
62
+ runtimeIndex = buildRuntimeIndex(summaries, aliases);
63
+ return runtimeIndex;
64
+ }
65
+ export function findSummary(query, idx) {
66
+ const q = query.toLowerCase().trim();
67
+ return (idx.byDirName.get(q) ??
68
+ idx.byEnName.get(q) ??
69
+ idx.byDirName.get(idx.aliasMap.get(query) ?? "") ??
70
+ idx.summaries.find((s) => s.name.toLowerCase().includes(q)));
71
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 同时兼容发布包和 monorepo 本地开发两种文档读取方式。
3
+ * 发布包读取 packages/mcp-mjui/docs/docs,本地 tsx 开发可回退到仓库根目录的 docs/docs。
4
+ */
5
+ export declare function resolveDocsDir(): string;
@@ -0,0 +1,18 @@
1
+ import fs from "fs";
2
+ import * as path from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = path.dirname(__filename);
6
+ // 构建后从 dist/services 回到包根目录;本地开发时从 src/services 回到包根目录。
7
+ const packageRoot = path.resolve(__dirname, "../..");
8
+ const packagedDocsDir = path.join(packageRoot, "docs/docs");
9
+ const workspaceDocsDir = path.resolve(packageRoot, "../../docs/docs");
10
+ /**
11
+ * 同时兼容发布包和 monorepo 本地开发两种文档读取方式。
12
+ * 发布包读取 packages/mcp-mjui/docs/docs,本地 tsx 开发可回退到仓库根目录的 docs/docs。
13
+ */
14
+ export function resolveDocsDir() {
15
+ if (fs.existsSync(packagedDocsDir))
16
+ return packagedDocsDir;
17
+ return workspaceDocsDir;
18
+ }
@@ -0,0 +1,8 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare abstract class BaseTool {
3
+ abstract name: string;
4
+ abstract description: string;
5
+ abstract inputSchema: any;
6
+ abstract execute(args: any): Promise<any>;
7
+ register(server: McpServer): void;
8
+ }
@@ -0,0 +1,27 @@
1
+ export class BaseTool {
2
+ register(server) {
3
+ server.registerTool(this.name, {
4
+ description: this.description,
5
+ inputSchema: this.inputSchema,
6
+ }, async (args) => {
7
+ try {
8
+ const result = await this.execute(args);
9
+ // MCP stdio 响应必须是 content blocks;工具实现只需要产出纯文本或 JSON 字符串。
10
+ return {
11
+ content: [{ type: "text", text: result }],
12
+ };
13
+ }
14
+ catch (error) {
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: error instanceof Error ? error.message : String(error),
20
+ },
21
+ ],
22
+ isError: true,
23
+ };
24
+ }
25
+ });
26
+ }
27
+ }
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ import { BaseTool } from "./base.tool.js";
3
+ export declare class GetComponentDocTool extends BaseTool {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: z.ZodObject<{
7
+ name: z.ZodString;
8
+ }, z.core.$strip>;
9
+ execute(args: {
10
+ name: string;
11
+ }): Promise<string>;
12
+ }
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { BaseTool } from "./base.tool.js";
3
+ import { getIndex, findSummary } from "../services/index.services.js";
4
+ import { loadDoc } from "../services/doc-parser.service.js";
5
+ export class GetComponentDocTool extends BaseTool {
6
+ name = "get_component_doc";
7
+ description = `获取指定组件的完整文档(props、示例代码)。
8
+
9
+ 【生成代码前必须完成】
10
+ 1. 确认已拿到 props 列表,不得使用文档外的 prop
11
+ 2. 参考 demos 中的示例代码结构
12
+ 3. 样式优先用组件 props 控制(type/size/disabled 等),其次用 CSS 变量,禁止 div+CSS 手写模拟
13
+ 4. padding/margin/font-size/color 等数值必须还原设计稿,不得使用默认猜测值
14
+ 5. 布局使用组件库 View/Flex,间距使用 spacing 系统,不硬编码`;
15
+ inputSchema = z.object({
16
+ name: z
17
+ .string()
18
+ .describe("组件名,支持英文(Button/button)、中文(按钮)、dirName(button)"),
19
+ });
20
+ async execute(args) {
21
+ const { name: query } = args;
22
+ const idx = await getIndex();
23
+ const summary = findSummary(query, idx);
24
+ if (!summary) {
25
+ throw new Error(`未找到组件"${query}",请先调用 search_components 确认组件名。`);
26
+ }
27
+ const doc = await loadDoc(summary);
28
+ return JSON.stringify({
29
+ componentName: doc.name,
30
+ dirName: doc.dirName,
31
+ group: doc.group,
32
+ version: doc.version,
33
+ description: doc.description,
34
+ whenToUse: doc.whenToUse,
35
+ importFrom: "@mijadesign/mjui-react-taro",
36
+ props: doc.props,
37
+ demos: doc.demos,
38
+ }, null, 2);
39
+ }
40
+ }
@@ -0,0 +1,4 @@
1
+ export { BaseTool } from "./base.tool.js";
2
+ export { ListComponentsTool } from "./list-components.tool.js";
3
+ export { GetComponentDocTool } from "./get-component-doc.tool.js";
4
+ export { SearchComponentsTool } from "./search-components.tool.js";
@@ -0,0 +1,4 @@
1
+ export { BaseTool } from "./base.tool.js";
2
+ export { ListComponentsTool } from "./list-components.tool.js";
3
+ export { GetComponentDocTool } from "./get-component-doc.tool.js";
4
+ export { SearchComponentsTool } from "./search-components.tool.js";
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ import { BaseTool } from "./base.tool.js";
3
+ export declare class ListComponentsTool extends BaseTool {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: z.ZodObject<{}, z.core.$strip>;
7
+ execute(_args: Record<string, unknown>): Promise<string>;
8
+ }
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ import { BaseTool } from "./base.tool.js";
3
+ import { getIndex } from "../services/index.services.js";
4
+ export class ListComponentsTool extends BaseTool {
5
+ name = "list_components";
6
+ description = "列出 Mija Design 所有组件,按分组归类输出。" +
7
+ "调用后若需生成代码,必须再调用 get_component_doc 获取完整 props 和示例,不得凭印象生成。";
8
+ inputSchema = z.object({});
9
+ async execute(_args) {
10
+ const idx = await getIndex();
11
+ const groups = new Map();
12
+ for (const s of idx.summaries) {
13
+ const g = s.group ?? "其他";
14
+ if (!groups.has(g))
15
+ groups.set(g, []);
16
+ groups.get(g).push(s);
17
+ }
18
+ const lines = [
19
+ "# Mija Design 组件索引",
20
+ "> 找到目标组件后,调用 get_component_doc 获取 props 和示例,再生成代码。",
21
+ "",
22
+ ];
23
+ for (const [group, items] of groups) {
24
+ lines.push(`## ${group}`);
25
+ for (const s of items) {
26
+ lines.push(`- **${s.name}**(${s.dirName}):${s.description}`);
27
+ }
28
+ lines.push("");
29
+ }
30
+ return lines.join("\n");
31
+ }
32
+ }
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ import { BaseTool } from "./base.tool.js";
3
+ export declare class SearchComponentsTool extends BaseTool {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: z.ZodObject<{
7
+ query: z.ZodString;
8
+ }, z.core.$strip>;
9
+ execute(args: {
10
+ query: string;
11
+ }): Promise<string>;
12
+ }