@fjyueke/bify-mcp 1.0.3 → 1.0.5
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/README.md +68 -5
- package/dist/index.js +107 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,26 +9,89 @@
|
|
|
9
9
|
|
|
10
10
|
Bify 是基于 Taroify 的移动端组件库,基于 Vant 视觉规范,提供一致的 API 接口,助力开发者快速搭建小程序应用。
|
|
11
11
|
|
|
12
|
-
Bify MCP 是一项独立的 MCP(模型上下文协议)服务,旨在将 Bify 与大模型连接起来。它使大模型能够直接从文档中检索组件、API
|
|
12
|
+
Bify MCP 是一项独立的 MCP(模型上下文协议)服务,旨在将 Bify 与大模型连接起来。它使大模型能够直接从文档中检索组件、API 数据,并支持 Arco Mobile → Bify 代码转换。
|
|
13
13
|
|
|
14
14
|
- 直接使用 npx 运行
|
|
15
15
|
- 无需外部依赖,只需要 Node 环境
|
|
16
|
+
- 支持 68+ 个组件文档查询
|
|
17
|
+
- 支持 Arco Mobile 代码转换
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## 配置方式
|
|
18
20
|
|
|
19
|
-
Cursor
|
|
21
|
+
### Cursor
|
|
20
22
|
|
|
21
|
-
```
|
|
23
|
+
```json
|
|
22
24
|
{
|
|
23
25
|
"mcpServers": {
|
|
24
26
|
"@fjyueke/bify-mcp": {
|
|
25
27
|
"command": "npx",
|
|
26
28
|
"args": [
|
|
27
29
|
"-y",
|
|
28
|
-
"@fjyueke/bify-mcp"
|
|
30
|
+
"@fjyueke/bify-mcp"
|
|
29
31
|
],
|
|
30
32
|
"env": {}
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
```
|
|
37
|
+
|
|
38
|
+
### Trae
|
|
39
|
+
|
|
40
|
+
在 `.trae/skills/` 目录下创建配置文件,或在 Trae 设置中添加 MCP 服务。
|
|
41
|
+
|
|
42
|
+
### 其他支持 MCP 的 IDE
|
|
43
|
+
|
|
44
|
+
参考对应 IDE 的 MCP 配置文档,使用上述配置格式。
|
|
45
|
+
|
|
46
|
+
## 可用工具
|
|
47
|
+
|
|
48
|
+
| 工具名 | 功能 |
|
|
49
|
+
|--------|------|
|
|
50
|
+
| `list-components` | 列出所有可用的 Bify 组件 |
|
|
51
|
+
| `get-component-docs` | 获取指定组件的详细文档 |
|
|
52
|
+
| `get-component-props` | 获取指定组件的属性和 API 文档 |
|
|
53
|
+
| `list-component-example` | 获取指定组件的所有示例代码 |
|
|
54
|
+
| `convert-arco-to-bify` | 将 Arco Mobile React 代码转换为 Bify 代码 |
|
|
55
|
+
| `get-arco-conversion-help` | 获取 Arco Mobile → Bify 转换帮助信息 |
|
|
56
|
+
|
|
57
|
+
## 使用示例
|
|
58
|
+
|
|
59
|
+
### 查询组件文档
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# 列出所有组件
|
|
63
|
+
list-components
|
|
64
|
+
|
|
65
|
+
# 获取 Cell 组件文档
|
|
66
|
+
get-component-docs Cell
|
|
67
|
+
|
|
68
|
+
# 获取 Cell 组件属性
|
|
69
|
+
get-component-props Cell
|
|
70
|
+
|
|
71
|
+
# 获取 Cell 组件示例
|
|
72
|
+
list-component-example Cell
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Arco Mobile 代码转换
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 获取转换帮助
|
|
79
|
+
get-arco-conversion-help
|
|
80
|
+
|
|
81
|
+
# 转换代码
|
|
82
|
+
convert-arco-to-bify "<Cell label='标题' desc='描述' showArrow>内容</Cell>"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 版本历史
|
|
86
|
+
|
|
87
|
+
| 版本 | 日期 | 说明 |
|
|
88
|
+
|------|------|------|
|
|
89
|
+
| 1.0.3 | 2026-07-13 | 优化代码转换工具,增加 40+ 组件映射、值映射、布尔属性转换 |
|
|
90
|
+
| 1.0.2 | 2026-07-13 | 添加 Arco Mobile → Bify 代码转换功能 |
|
|
91
|
+
| 1.0.1 | 2026-07-13 | 更正包名为 bify-mcp |
|
|
92
|
+
| 1.0.0 | 2026-07-13 | 初始版本,支持 68+ 组件文档查询 |
|
|
93
|
+
|
|
94
|
+
## 相关链接
|
|
95
|
+
|
|
96
|
+
- npm 包地址:https://www.npmjs.com/package/@fjyueke/bify-mcp
|
|
97
|
+
- Bify 组件库:https://github.com/fjyueke/bify
|
package/dist/index.js
CHANGED
|
@@ -616,20 +616,36 @@ function findAllArcoComponents() {
|
|
|
616
616
|
|
|
617
617
|
// src/services/arco-converter.ts
|
|
618
618
|
async function convertArcoToBify(arcoCode) {
|
|
619
|
+
const warnings = [];
|
|
620
|
+
const suggestions = [];
|
|
621
|
+
const usedMappings = [];
|
|
619
622
|
let result = arcoCode;
|
|
620
|
-
|
|
621
|
-
result =
|
|
623
|
+
const importsResult = convertImports(result, warnings);
|
|
624
|
+
result = importsResult.code;
|
|
625
|
+
usedMappings.push(...importsResult.mappings);
|
|
626
|
+
const componentsResult = convertComponents(result, warnings, suggestions);
|
|
627
|
+
result = componentsResult.code;
|
|
628
|
+
usedMappings.push(...componentsResult.mappings);
|
|
622
629
|
result = convertIconImports(result);
|
|
623
630
|
result = fixCodeFormat(result);
|
|
624
|
-
|
|
631
|
+
const uniqueMappings = usedMappings.filter(
|
|
632
|
+
(m, index, self) => self.findIndex((t) => t.arcoName === m.arcoName) === index
|
|
633
|
+
);
|
|
634
|
+
return {
|
|
635
|
+
code: result,
|
|
636
|
+
mappings: uniqueMappings,
|
|
637
|
+
warnings,
|
|
638
|
+
suggestions
|
|
639
|
+
};
|
|
625
640
|
}
|
|
626
|
-
function convertImports(code) {
|
|
641
|
+
function convertImports(code, warnings) {
|
|
627
642
|
let result = code;
|
|
643
|
+
const usedMappings = [];
|
|
628
644
|
const arcoImportRegex = /import\s+([\s\S]*?)\s+from\s+['"]@arco-design\/mobile-react['"]/g;
|
|
629
645
|
const matches = [...code.matchAll(arcoImportRegex)];
|
|
630
646
|
const bifyCoreComponents = [];
|
|
631
647
|
const bifyIconComponents = [];
|
|
632
|
-
const
|
|
648
|
+
const unsupportedComponents = [];
|
|
633
649
|
for (const match of matches) {
|
|
634
650
|
const importContent = match[1].trim();
|
|
635
651
|
const namedImportRegex = /\{([\s\S]*?)\}/;
|
|
@@ -639,17 +655,16 @@ function convertImports(code) {
|
|
|
639
655
|
for (const component of components) {
|
|
640
656
|
const mapping = findMappingByArcoName(component);
|
|
641
657
|
if (mapping) {
|
|
658
|
+
usedMappings.push(mapping);
|
|
642
659
|
if (mapping.bifyImport === "@fjyueke/bify-icons") {
|
|
643
660
|
bifyIconComponents.push(component);
|
|
644
661
|
} else {
|
|
645
662
|
bifyCoreComponents.push(mapping.bifyName || component);
|
|
646
663
|
}
|
|
647
664
|
} else {
|
|
648
|
-
|
|
665
|
+
unsupportedComponents.push(component);
|
|
649
666
|
}
|
|
650
667
|
}
|
|
651
|
-
} else {
|
|
652
|
-
remainingComponents.push(importContent);
|
|
653
668
|
}
|
|
654
669
|
result = result.replace(match[0], "");
|
|
655
670
|
}
|
|
@@ -666,22 +681,29 @@ function convertImports(code) {
|
|
|
666
681
|
`;
|
|
667
682
|
result = iconImport + result;
|
|
668
683
|
}
|
|
669
|
-
|
|
684
|
+
if (unsupportedComponents.length > 0) {
|
|
685
|
+
warnings.push(`\u4EE5\u4E0B\u7EC4\u4EF6\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u8F6C\u6362\uFF1A${unsupportedComponents.join(", ")}`);
|
|
686
|
+
}
|
|
687
|
+
return { code: result, mappings: usedMappings };
|
|
670
688
|
}
|
|
671
|
-
function convertComponents(code) {
|
|
689
|
+
function convertComponents(code, warnings, suggestions) {
|
|
672
690
|
let result = code;
|
|
691
|
+
const usedMappings = [];
|
|
673
692
|
const arcoComponents = findAllArcoComponents();
|
|
674
693
|
for (const arcoComponent of arcoComponents) {
|
|
675
694
|
const mapping = findMappingByArcoName(arcoComponent);
|
|
676
695
|
if (!mapping || !mapping.bifyName) continue;
|
|
696
|
+
const componentPattern = new RegExp(`<${arcoComponent}`, "g");
|
|
697
|
+
if (!componentPattern.test(code)) continue;
|
|
698
|
+
usedMappings.push(mapping);
|
|
677
699
|
const bifyComponent = mapping.bifyName;
|
|
678
|
-
const
|
|
700
|
+
const selfClosingRegex = new RegExp(
|
|
679
701
|
`<${arcoComponent}([^>]*)\\/?>`,
|
|
680
702
|
"g"
|
|
681
703
|
);
|
|
682
|
-
result = result.replace(
|
|
704
|
+
result = result.replace(selfClosingRegex, (match, props) => {
|
|
683
705
|
let newProps = props;
|
|
684
|
-
newProps = applyPropMappings(newProps, mapping);
|
|
706
|
+
newProps = applyPropMappings(newProps, mapping, warnings);
|
|
685
707
|
newProps = applyValueMappings(newProps, mapping);
|
|
686
708
|
return `<${bifyComponent}${newProps}/>`;
|
|
687
709
|
});
|
|
@@ -691,15 +713,23 @@ function convertComponents(code) {
|
|
|
691
713
|
);
|
|
692
714
|
result = result.replace(closingComponentRegex, (match, props, children) => {
|
|
693
715
|
let newProps = props;
|
|
694
|
-
newProps = applyPropMappings(newProps, mapping);
|
|
716
|
+
newProps = applyPropMappings(newProps, mapping, warnings);
|
|
695
717
|
newProps = applyValueMappings(newProps, mapping);
|
|
696
718
|
return `<${bifyComponent}${newProps}>${children}</${bifyComponent}>`;
|
|
697
719
|
});
|
|
720
|
+
addSuggestions(mapping, suggestions);
|
|
698
721
|
}
|
|
699
|
-
return result;
|
|
722
|
+
return { code: result, mappings: usedMappings };
|
|
700
723
|
}
|
|
701
|
-
function applyPropMappings(props, mapping) {
|
|
724
|
+
function applyPropMappings(props, mapping, warnings) {
|
|
702
725
|
let result = props;
|
|
726
|
+
const arcoProps = props.match(/\b(\w+)=/g)?.map((p) => p.slice(0, -1)) || [];
|
|
727
|
+
const mappedProps = mapping.propMappings.map((m) => m.arcoProp);
|
|
728
|
+
for (const arcoProp of arcoProps) {
|
|
729
|
+
if (!mappedProps.includes(arcoProp) && !["className", "style", "children"].includes(arcoProp)) {
|
|
730
|
+
warnings.push(`\u7EC4\u4EF6 ${mapping.arcoName} \u7684\u5C5E\u6027 ${arcoProp} \u672A\u627E\u5230\u6620\u5C04\uFF0C\u5DF2\u4FDD\u7559\u539F\u6837`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
703
733
|
for (const propMapping of mapping.propMappings) {
|
|
704
734
|
const propRegex = new RegExp(
|
|
705
735
|
`${propMapping.arcoProp}=(["'])(.*?)\\1`,
|
|
@@ -731,7 +761,10 @@ function applyValueMappings(props, mapping) {
|
|
|
731
761
|
);
|
|
732
762
|
result = result.replace(propRegex, (match, quote, value) => {
|
|
733
763
|
const mappedValue = valueMap[value] || value;
|
|
734
|
-
|
|
764
|
+
if (mappedValue !== value) {
|
|
765
|
+
return `${propName}=${quote}${mappedValue}${quote}`;
|
|
766
|
+
}
|
|
767
|
+
return match;
|
|
735
768
|
});
|
|
736
769
|
}
|
|
737
770
|
return result;
|
|
@@ -753,6 +786,18 @@ function fixCodeFormat(code) {
|
|
|
753
786
|
result = nonEmptyLines.join("\n");
|
|
754
787
|
return result.trim();
|
|
755
788
|
}
|
|
789
|
+
function addSuggestions(mapping, suggestions) {
|
|
790
|
+
const suggestionMap = {
|
|
791
|
+
Cell: "Bify \u7684 Cell \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u5E03\u5C40\u5C5E\u6027\uFF0C\u5EFA\u8BAE\u67E5\u770B\u6587\u6863\u4E86\u89E3 align\u3001size \u7B49\u5C5E\u6027",
|
|
792
|
+
Button: "Bify \u7684 Button \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u6837\u5F0F\u53D8\u4F53\uFF0C\u5EFA\u8BAE\u67E5\u770B variant \u5C5E\u6027",
|
|
793
|
+
Dialog: "Bify \u7684 Dialog \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u4EA4\u4E92\u9009\u9879\uFF0C\u5EFA\u8BAE\u67E5\u770B closeOnClickOverlay \u7B49\u5C5E\u6027",
|
|
794
|
+
Tabs: "Bify \u7684 Tabs \u7EC4\u4EF6\u652F\u6301\u6ED1\u52A8\u5207\u6362\uFF0C\u5EFA\u8BAE\u67E5\u770B swipeable \u5C5E\u6027",
|
|
795
|
+
Field: "Bify \u7684 Field \u7EC4\u4EF6\u652F\u6301\u66F4\u591A\u9A8C\u8BC1\u5C5E\u6027\uFF0C\u5EFA\u8BAE\u67E5\u770B rules \u5C5E\u6027"
|
|
796
|
+
};
|
|
797
|
+
if (suggestionMap[mapping.arcoName]) {
|
|
798
|
+
suggestions.push(suggestionMap[mapping.arcoName]);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
756
801
|
async function getArcoConversionHelp() {
|
|
757
802
|
const availableComponents = componentMappings.filter((m) => m.bifyName).map((m) => `- ${m.arcoName} \u2192 ${m.bifyName}`).join("\n");
|
|
758
803
|
const valueMappingExamples = componentMappings.filter((m) => m.valueMappings).map((m) => {
|
|
@@ -806,9 +851,15 @@ import { Cell, CellGroup, Button } from '@fjyueke/bify-core';
|
|
|
806
851
|
| \`max\` | \`count\` | Rate \u6700\u5927\u6570\u91CF |
|
|
807
852
|
| \`percent\` | \`percentage\` | Progress \u767E\u5206\u6BD4 |
|
|
808
853
|
|
|
854
|
+
### \u6700\u4F73\u5B9E\u8DF5
|
|
855
|
+
|
|
856
|
+
1. **\u4F7F\u7528 AI \u8F85\u52A9\u8F6C\u6362**\uFF1A\u540C\u65F6\u914D\u7F6E Arco Mobile MCP \u548C Bify MCP\uFF0C\u8BA9 AI \u67E5\u8BE2\u53CC\u65B9\u6587\u6863\u540E\u518D\u8FDB\u884C\u8F6C\u6362
|
|
857
|
+
2. **\u624B\u52A8\u68C0\u67E5**\uFF1A\u8F6C\u6362\u540E\u8BF7\u68C0\u67E5\u8B66\u544A\u4FE1\u606F\uFF0C\u5904\u7406\u672A\u6620\u5C04\u7684\u5C5E\u6027
|
|
858
|
+
3. **\u53C2\u8003\u6587\u6863**\uFF1A\u4F7F\u7528 \`get-component-docs\` \u548C \`get-component-props\` \u67E5\u770B Bify \u7EC4\u4EF6\u7684\u8BE6\u7EC6\u7528\u6CD5
|
|
859
|
+
|
|
809
860
|
### \u8C03\u7528\u65B9\u5F0F
|
|
810
861
|
|
|
811
|
-
\u4F7F\u7528 \`convert-arco-to-bify\` \u5DE5\u5177\uFF0C\u4F20\u5165 Arco Mobile \u4EE3\u7801\u5373\u53EF\u83B7\u5F97\u8F6C\u6362\u540E\u7684 Bify \u4EE3\u7801\u3002`;
|
|
862
|
+
\u4F7F\u7528 \`convert-arco-to-bify\` \u5DE5\u5177\uFF0C\u4F20\u5165 Arco Mobile \u4EE3\u7801\u5373\u53EF\u83B7\u5F97\u8F6C\u6362\u540E\u7684 Bify \u4EE3\u7801\u53CA\u8BE6\u7EC6\u62A5\u544A\u3002`;
|
|
812
863
|
}
|
|
813
864
|
|
|
814
865
|
// src/tools/components.ts
|
|
@@ -880,19 +931,50 @@ function registerTifyTools(server) {
|
|
|
880
931
|
);
|
|
881
932
|
server.tool(
|
|
882
933
|
"convert-arco-to-bify",
|
|
883
|
-
"Converts Arco Mobile React code to Bify code",
|
|
934
|
+
"Converts Arco Mobile React code to Bify code with detailed report including warnings and suggestions",
|
|
884
935
|
{ arcoCode: z.string() },
|
|
885
936
|
async (args) => {
|
|
886
|
-
const
|
|
937
|
+
const result = await convertArcoToBify(args.arcoCode);
|
|
938
|
+
let report = `## \u8F6C\u6362\u7ED3\u679C
|
|
939
|
+
|
|
940
|
+
### \u8F6C\u6362\u540E\u7684\u4EE3\u7801
|
|
941
|
+
|
|
942
|
+
\`\`\`tsx
|
|
943
|
+
${result.code}
|
|
944
|
+
\`\`\``;
|
|
945
|
+
if (result.mappings.length > 0) {
|
|
946
|
+
report += `
|
|
947
|
+
|
|
948
|
+
### \u4F7F\u7528\u7684\u6620\u5C04
|
|
949
|
+
|
|
950
|
+
| Arco \u7EC4\u4EF6 | Bify \u7EC4\u4EF6 |
|
|
951
|
+
|-----------|-----------|
|
|
952
|
+
${result.mappings.map((m) => `| ${m.arcoName} | ${m.bifyName} |`).join("\n")}`;
|
|
953
|
+
}
|
|
954
|
+
if (result.warnings.length > 0) {
|
|
955
|
+
report += `
|
|
956
|
+
|
|
957
|
+
### \u26A0\uFE0F \u8B66\u544A
|
|
958
|
+
|
|
959
|
+
- ${result.warnings.join("\n- ")}`;
|
|
960
|
+
}
|
|
961
|
+
if (result.suggestions.length > 0) {
|
|
962
|
+
report += `
|
|
963
|
+
|
|
964
|
+
### \u{1F4A1} \u5EFA\u8BAE
|
|
965
|
+
|
|
966
|
+
- ${result.suggestions.join("\n- ")}`;
|
|
967
|
+
}
|
|
968
|
+
report += `
|
|
969
|
+
|
|
970
|
+
### \u8F6C\u6362\u8BF4\u660E
|
|
971
|
+
|
|
972
|
+
\u5982\u9700\u66F4\u7CBE\u786E\u7684\u8F6C\u6362\uFF0C\u5EFA\u8BAE\u540C\u65F6\u4F7F\u7528 Arco Mobile MCP \u548C Bify MCP \u67E5\u8BE2\u53CC\u65B9\u7EC4\u4EF6\u6587\u6863\u540E\u8FDB\u884C\u624B\u52A8\u8C03\u6574\u3002`;
|
|
887
973
|
return {
|
|
888
974
|
content: [
|
|
889
975
|
{
|
|
890
976
|
type: "text",
|
|
891
|
-
text:
|
|
892
|
-
|
|
893
|
-
\`\`\`tsx
|
|
894
|
-
${convertedCode}
|
|
895
|
-
\`\`\``
|
|
977
|
+
text: report
|
|
896
978
|
}
|
|
897
979
|
]
|
|
898
980
|
};
|