@szc-ft/mcp-szcd-client 0.23.1 → 0.25.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.
- package/agents/build.js +22 -12
- package/agents/opencode-extension/agents/szcd-component-expert.md +94 -50
- package/agents/qwen-extension/agents/szcd-component-expert.md +94 -50
- package/agents/src/szcd-component-expert.md +94 -50
- package/agents/src/tools.json +1 -1
- package/agents/szcd-component-expert.md +94 -50
- package/agents/szcd-component-expert.qoder.md +95 -51
- package/agents/szcd-component-expert.trae.md +94 -50
- package/opencode-extension/agents/szcd-component-expert.md +94 -50
- package/opencode-extension/skills/local-api-tool/SKILL.md +164 -60
- package/opencode-extension/skills/local-api-tool/scripts/extract_swagger.py +477 -0
- package/opencode-extension/skills/szcd-component-helper/SKILL.md +22 -17
- package/opencode-extension/skills/szcd-design-to-code/SKILL.md +141 -31
- package/package.json +1 -1
- package/qwen-extension/agents/szcd-component-expert.md +94 -50
- package/qwen-extension/qwen-extension.json +1 -1
- package/qwen-extension/skills/local-api-tool/SKILL.md +164 -60
- package/qwen-extension/skills/local-api-tool/scripts/extract_swagger.py +477 -0
- package/qwen-extension/skills/szcd-component-helper/SKILL.md +22 -17
- package/qwen-extension/skills/szcd-design-to-code/SKILL.md +141 -31
- package/scripts/lib/claude-code.js +1 -1
- package/scripts/lib/common.js +44 -0
- package/scripts/lib/opencode.js +1 -1
- package/scripts/lib/qoder.js +1 -1
- package/scripts/lib/trae-cli.js +1 -1
- package/scripts/lib/trae-ide.js +1 -1
- package/scripts/postinstall.js +1 -0
- package/standard-skill/local-api-tool/SKILL.md +164 -60
- package/standard-skill/local-api-tool/scripts/extract_swagger.py +477 -0
- package/standard-skill/szcd-component-helper/SKILL.md +22 -17
- package/standard-skill/szcd-design-to-code/SKILL.md +141 -31
|
@@ -57,7 +57,7 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
57
57
|
| `get_best_practices` | 获取组件使用最佳实践和常见错误修正,指定scenario可获取组合最佳实践 | 步骤4:组合最佳实践 |
|
|
58
58
|
| `get_style_injection_guide` | 查询组件样式注入方法、CSS穿透路径、优先级和反模式 | 步骤5:样式注入 |
|
|
59
59
|
| `read_file` | 读取仓库内文件(组件源码/文档),组件源码无长度限制 | 步骤6:读取源码确认 |
|
|
60
|
-
| `get_upload_endpoint` | 获取设计稿图片上传接口地址和curl命令,上传后取upload_id传给analyze_design_image | 步骤3:上传设计稿 |
|
|
60
|
+
| `get_upload_endpoint` | 获取设计稿图片上传接口地址和curl命令,上传后取upload_id传给analyze_design_image。上传最多重试3次,超过后停止并向用户说明失败原因 | 步骤3:上传设计稿 |
|
|
61
61
|
| `analyze_design_image` | 分析UI设计稿,提取Token配置、CSS覆盖样式、视觉细节,支持pixel_perfect模式 | 步骤3:分析设计稿 |
|
|
62
62
|
| `map_design_data` | 将设计稿解析结果映射为szcd组件配置,支持sketchData自动推断组件 | 步骤2.5:设计稿映射 |
|
|
63
63
|
| `assert_page_screenshot` | 对页面截图进行自然语言语义断言,返回pass/fail+原因。用于自动化测试验证布局、内容、功能 | 步骤6.5:浏览器验证结果审查 |
|
|
@@ -120,54 +120,54 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
120
120
|
|
|
121
121
|
### 步骤2.5:Sketch 文件解析(条件执行)
|
|
122
122
|
|
|
123
|
-
**当用户提供 .sketch 设计文件时**,使用 `sketch-mcp-server`(独立 MCP Server,stdio
|
|
123
|
+
**当用户提供 .sketch 设计文件时**,使用 `sketch-mcp-server`(独立 MCP Server,stdio 模式,**v1.5.0+**)解析,直接提取结构化数据,结合组件库架构推理组件方案,无需经过视觉模型和 `map_design_data`。
|
|
124
124
|
|
|
125
|
-
**核心原则**:写代码前必须先 `getMultipleNodeInfo` 拉取所有 `text
|
|
125
|
+
**核心原则**:写代码前必须先 `getMultipleNodeInfo` 拉取所有 `text`、`rectangle`、`group` 节点的完整样式 Token + 父子归属。`queryNodes.type` 接受数组(一次拿三类)、`getMultipleNodeInfo` 内部自动分片、每个节点自动返回 `parent: {id,name,type}`,禁止凭节点名猜测样式,禁止用 x 坐标判定元素归属。
|
|
126
126
|
|
|
127
|
-
**工作流(
|
|
127
|
+
**工作流(4 步,sketch-mcp-server v1.5.0+)**:
|
|
128
128
|
|
|
129
129
|
1. **加载文件**:
|
|
130
130
|
- `loadSketchByPath` 加载 .sketch 文件
|
|
131
131
|
- `listPages` 列出所有页面
|
|
132
|
-
- `
|
|
132
|
+
- `queryNodes`(pageId, type="artboard")获取画板列表
|
|
133
133
|
- 根据画板名称选择目标页面
|
|
134
134
|
|
|
135
|
-
2.
|
|
136
|
-
- `getPageStructure`(pageId
|
|
137
|
-
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
4. **批量拉取样式 Token**:
|
|
149
|
-
- `getMultipleNodeInfo`([id1, id2, ...])— 每次 ≤ 100 个节点
|
|
135
|
+
2. **获取分区结构**:
|
|
136
|
+
- `getPageStructure`(pageId, mode="tree", maxDepth=3)— 看顶层 group 分区(通常 2-5 个,对应 LeftTree区/Query+Table区/信息栏区/标题栏区)
|
|
137
|
+
- 记下每个分区根 group 的 id 和 name,后续按 `parent` 字段归属元素
|
|
138
|
+
|
|
139
|
+
3. **批量获取目标节点 ID**:
|
|
140
|
+
- 推荐:`queryNodes({ pageId, type: ["text", "rectangle", "group"], limit: 500 })` — **type 数组**一次拿三类节点的 ID
|
|
141
|
+
- 备选:`getPageStructure(pageId, mode="ids")` — 返回按类型分组的全量 ID `{ text: [...], rectangle: [...], group: [...], bitmap: [...], shapePath: [...] }`
|
|
142
|
+
- 顺手记下 bitmap/shapePath 节点列表,传给步骤 2.5.1
|
|
143
|
+
|
|
144
|
+
4. **批量拉取样式 Token + 父子归属**:
|
|
145
|
+
- `getMultipleNodeInfo`([id1, id2, ...])— 传入全部 ID,**内部自动按 100 个一批分片**,无需手动拆分
|
|
146
|
+
- **同批必须包含 text + rectangle + group 三类节点 ID**(漏 group 会丢失渐变背景/边框/阴影)
|
|
150
147
|
- 关键字段提取:
|
|
151
|
-
- 背景色:`style.fills[0].color.hex
|
|
148
|
+
- 背景色:`style.fills[0].color.hex`(含 group 容器的渐变)
|
|
152
149
|
- 文字色:`text.color`(部分版本在 `style.fills[0].color`)
|
|
153
150
|
- 字号:`style.fontSize`
|
|
154
151
|
- 字重:`style.fontWeight`
|
|
155
152
|
- 边框:`style.borders[0].color.hex` + `thickness`
|
|
153
|
+
- 阴影:`style.shadows`
|
|
154
|
+
- **父子归属**:`parent: { id, name, type }` ← v1.5.0+ 自动返回,元素归属判定唯一可信来源
|
|
156
155
|
- **禁止**逐个 `getNodeInfo` 探查
|
|
157
156
|
|
|
158
157
|
**步骤 2.5 产出物**(**只产出数据,不做组件映射**):
|
|
159
|
-
- Sketch
|
|
160
|
-
- text/rectangle 节点的完整样式 Token
|
|
158
|
+
- Sketch 顶层分区结构(步骤 2 的 tree)
|
|
159
|
+
- text/rectangle/group 节点的完整样式 Token + parent 父子关系
|
|
161
160
|
- 图表区结构规律识别结果
|
|
161
|
+
- bitmap ID 列表 + shapePath 节点名列表(传给步骤 2.5.1)
|
|
162
162
|
|
|
163
163
|
组件候选列表推理**不**在步骤 2.5 内部完成,**统一在主流程步骤 3.5 中结合步骤 1 的 `templatePatterns` 推理**。
|
|
164
164
|
|
|
165
|
-
**Sketch → szcd
|
|
165
|
+
**Sketch → szcd 工作流(v1.5.0+)**:
|
|
166
166
|
```
|
|
167
|
-
.sketch → loadSketchByPath → listPages →
|
|
168
|
-
→ getPageStructure(
|
|
169
|
-
→
|
|
170
|
-
→ getMultipleNodeInfo([
|
|
167
|
+
.sketch → loadSketchByPath → listPages → queryNodes(pageId, type="artboard")
|
|
168
|
+
→ getPageStructure(pageId, mode="tree", maxDepth=3) ← 拿分区
|
|
169
|
+
→ queryNodes(pageId, type=["text","rectangle","group"]) ← 拿全量 ID(数组类型)
|
|
170
|
+
→ getMultipleNodeInfo([全部 ID]) ← 自动分片,含 parent 字段
|
|
171
171
|
→ [进入主流程步骤 3.5 统一推理]
|
|
172
172
|
```
|
|
173
173
|
|
|
@@ -175,16 +175,17 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
175
175
|
|
|
176
176
|
| 步骤 | 第一次做错的 | 应该做的 |
|
|
177
177
|
|------|------------|---------|
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
|
|
|
178
|
+
| 分区识别 | 直接拉所有节点详情,靠 x/y 反推分区 | `getPageStructure(mode="tree", maxDepth=3)` 先看顶层 group 分布 |
|
|
179
|
+
| 节点收集 | 分两次调用 queryNodes 拿 text 和 rectangle | `queryNodes(type=["text","rectangle","group"])` 一次拿三类 |
|
|
180
|
+
| 样式提取 | 没做 | `getMultipleNodeInfo([全部 ID])` 内部自动分片,**单次调用** |
|
|
181
|
+
| 元素归属 | 凭 x/y 坐标判定("x=272 列都是同区域") | 看 `getMultipleNodeInfo` 返回的 `parent.id/name` 字段 |
|
|
182
|
+
| 颜色提取 | 跳过 group 只取 text/rectangle | 同批提交 group ID,从 `style.fills` 取渐变背景 |
|
|
182
183
|
|
|
183
|
-
|
|
184
|
+
**实战经验沉淀(重要)**:
|
|
184
185
|
|
|
185
186
|
**收获 1:首轮 `getMultipleNodeInfo` 必须全量拉取,不能挑**
|
|
186
187
|
- 错误做法:先查 7 个顶层容器,再根据需要分批补漏(结果补了 7 轮 ≈ 108 个节点)
|
|
187
|
-
- 正确做法:`
|
|
188
|
+
- 正确做法:`queryNodes(type=["text","rectangle","group"])` 一次性拿全量 ID → `getMultipleNodeInfo([全部 ID])`,**单次调用**(内部自动分片)
|
|
188
189
|
|
|
189
190
|
**收获 2:text 节点是颜色/DOM 映射的两级索引**
|
|
190
191
|
每个 text 节点同时关联两种上下文,**必须同批拉取**:
|
|
@@ -192,9 +193,28 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
192
193
|
- 所属 group 父级 rectangle 样式:`bg`、`border`、`radius`、`shadow`
|
|
193
194
|
|
|
194
195
|
错误做法:先查 text 拿自身样式 → 再根据 parent ID 单独查 rectangle(多走一步)
|
|
195
|
-
|
|
196
|
+
正确做法:用 `queryNodes(type=["text","rectangle","group"])` 一次拿三类 ID,`getMultipleNodeInfo` 返回的 `parent` 字段直接告诉你归属关系
|
|
197
|
+
|
|
198
|
+
**收获 3:元素归属必须走 group 父子关系,禁止 x 坐标平面判定**
|
|
199
|
+
|
|
200
|
+
实战教训:`'主题'text(x=272,y=149)` 被错误识别为内容区块标题,实际是左侧树标题(与树节点同 x=272 列)。同列坐标不代表同区域。
|
|
201
|
+
|
|
202
|
+
正确做法:
|
|
203
|
+
- 步骤 2 拿到完整节点树后,先识别顶层 group 分区(通常 2-5 个,对应 LeftTree区/Query+Table区/信息栏区/标题栏区)
|
|
204
|
+
- `getMultipleNodeInfo` v1.5.0+ **自动返回** `parent: { id, name, type }` 字段,按 parent 归属到具体分区
|
|
205
|
+
- "主题"这类标题文本,先看 `parent.name` 是否带 "LeftTree" / "树" / "PageContent" 等容器关键字,不要看 x 坐标
|
|
206
|
+
- 坐标仅作为同 parent 内子元素排序兜底使用
|
|
207
|
+
|
|
208
|
+
**收获 4:信息栏/卡片容器必须先取 group 再取子元素**
|
|
209
|
+
|
|
210
|
+
实战教训:仅提取 text 节点导致信息栏容器样式遗漏(渐变背景 #f3faff→#f8fdff、边框 #e9f5ff、图标编组)。
|
|
211
|
+
|
|
212
|
+
正确做法:
|
|
213
|
+
- 看到画板里有 `编组N`/`infoCard`/`statBox` 等 group 节点,必须连 group 自身和内部 rectangle 一起拉 `getMultipleNodeInfo`
|
|
214
|
+
- group 节点的 `style.fills` 才是渐变背景、`style.borders` 才是边框
|
|
215
|
+
- 子图标若为 group(rectangle + shapePath),rectangle 是圆形/方形背景,shapePath 是矢量图标
|
|
196
216
|
|
|
197
|
-
**收获
|
|
217
|
+
**收获 5:图表区样式提取有规律可循**
|
|
198
218
|
|
|
199
219
|
| 图表子元素 | 对应 Sketch 节点类型 | 关键样式字段 |
|
|
200
220
|
|---|---|---|
|
|
@@ -209,23 +229,34 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
209
229
|
|
|
210
230
|
识别出图表后,**图例色块**应归入 ECharts `legend` 配置(不要用 div 硬编码),**柱体色**映射到 `series.itemStyle.color`。
|
|
211
231
|
|
|
212
|
-
**收获
|
|
213
|
-
- `shapePath` / `shapeGroup` 在 sketch 节点中占比可能高达 46.8
|
|
214
|
-
- 解压 `.sketch
|
|
215
|
-
-
|
|
232
|
+
**收获 6:矢量图形 + 图标语义优先级(v1.5.0 已内置 compoundIcons)**
|
|
233
|
+
- `shapePath` / `shapeGroup` 在 sketch 节点中占比可能高达 46.8%,`renderNodeAsBase64` 不支持渲染
|
|
234
|
+
- 解压 `.sketch` 只能提取 `bitmap` 中内嵌的 PNG/PDF(常仅几张,通常是 Logo)
|
|
235
|
+
- **`matchIconFromName` v1.5.0+ 评分制**:每个 nodeName 返回 Top-3 候选,complex 词组合(如"文件夹+新增")自动命中 `FolderAddOutlined`(compound score 100+),不会被"新增"单独 +20 分压制
|
|
236
|
+
- 优先看 `bestMatch.source === "compound"`:表示已强映射,直接采用 `antdIcon`
|
|
237
|
+
- `unmatched`(无关键词信号,如"编组11备份")必须看节点 `parent.name` 和兄弟节点上下文兜底
|
|
216
238
|
|
|
217
|
-
|
|
218
|
-
- 大型 .sketch 文件先 `listNodesByPage(type="artboard")` 锁定目标画板,避免一次性加载整个文档
|
|
219
|
-
- `getNodesSummary` 是 token 节省关键:先按类型分组统计,再决定要查哪些节点 ID
|
|
220
|
-
- 批量 `getMultipleNodeInfo` 严格 ≤ 100 个/次,超过需分批
|
|
221
|
-
- 仅当结构化样式数据仍不足(如复杂渐变、阴影)时,才回退到 `renderNodeAsBase64` + `analyze_design_image`
|
|
222
|
-
- 如果 sketch-mcp-server 工具不可用,提示用户安装:`npm install -g sketch-mcp-server`
|
|
239
|
+
**参考表(内置 compoundIcons 已覆盖;列出供 unmatched 兜底参考)**:
|
|
223
240
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
241
|
+
| Sketch 节点上下文 | 期望 antd 图标 | 反例(不要选) |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| 文件夹+新增/添加 | `FolderAddOutlined` | PlusOutlined |
|
|
244
|
+
| 文件+新增 | `FileAddOutlined` | PlusOutlined |
|
|
245
|
+
| 用户+新增 | `UserAddOutlined` | PlusOutlined |
|
|
246
|
+
| 文件夹+打开 | `FolderOpenOutlined` | FolderOutlined |
|
|
247
|
+
| 编辑+笔 | `EditOutlined` | FormOutlined |
|
|
248
|
+
| 设置+齿轮 | `SettingOutlined` | ToolOutlined |
|
|
249
|
+
|
|
250
|
+
- **兜底方案**:① 用 `extractBitmaps` 提取的 PNG/PDF 资源;② `matchIconFromName` 的 Top-1(若 source=compound);③ unmatched 时按 parent 上下文 + 上表选 antd `@ant-design/icons` 复合图标;④ 在代码注释中标注"⚠️ 矢量图标用 antd 图标替代,原始 Sketch 为 shapePath"
|
|
251
|
+
|
|
252
|
+
**提示(sketch-mcp-server v1.5.0+)**:
|
|
253
|
+
- 大型 .sketch 文件先 `queryNodes(pageId, type="artboard")` 锁定目标画板,避免一次性加载整个文档
|
|
254
|
+
- `queryNodes(pageId, type=["text","rectangle","group"])` 一次拿三类节点 ID(type 字段支持数组),跳过 `getPageStructure(mode="ids")` 单独调用
|
|
255
|
+
- `getPageStructure(pageId, mode="tree", maxDepth=2-3)` 用于看分区层级;`mode="summary"` 用于按类型统计概况
|
|
256
|
+
- 批量 `getMultipleNodeInfo` 支持任意数量 ID(内部按 100 一批自动分片),无需手动拆分;每个节点自带 `parent: {id,name,type}` 字段,元素归属直接走 parent,禁止用 x/y 坐标
|
|
257
|
+
- `matchIconFromName` 评分制返回 Top-3 + `bestMatch.source === "compound"` 强映射,shapePath 节点优先走它
|
|
258
|
+
- 仅当结构化样式数据仍不足(如复杂渐变、阴影)时,才回退到 `renderNodeAsBase64` + `analyze_design_image`
|
|
259
|
+
- 如果 sketch-mcp-server 工具不可用,提示用户安装:`npm install -g @szc-ft/sketch-mcp-server`
|
|
229
260
|
|
|
230
261
|
### 步骤3:分析设计稿(条件执行)
|
|
231
262
|
|
|
@@ -303,6 +334,19 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
303
334
|
| 可编辑表格(单元格直接输入) | `TableOrList(componentType="EditableProTable")` | 可编辑表格特征 |
|
|
304
335
|
| 卡片列表(非表格式数据卡片) | `TableOrList(componentType="ProList")` | 卡片布局特征 |
|
|
305
336
|
|
|
337
|
+
#### ⚠️ TemplateMode 槽位传参铁律(高频踩坑)
|
|
338
|
+
|
|
339
|
+
**LeftContent / Query / PageContent 三个槽位都接收单个 ReactNode,禁止传数组**:
|
|
340
|
+
|
|
341
|
+
| ❌ 错误 | ✅ 正确 | 后果 |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| `LeftContent={[<LeftTree/>]}` | `LeftContent={<LeftTree/>}` | 数组会触发多余 tab 渲染 |
|
|
344
|
+
| `LeftContent={[<LeftTree/>, <Filter/>]}` | `LeftContent={<><LeftTree/><Filter/></>}` 或包一层 div | 同上 |
|
|
345
|
+
| `Query={[<Query/>]}` | `Query={<Query/>}` | 同上 |
|
|
346
|
+
| `PageContent={[<TableOrList/>]}` | `PageContent={<TableOrList/>}` | 同上 |
|
|
347
|
+
|
|
348
|
+
**判定方法**:Sketch 中只要某个分区是"单棵树/单个查询面板/单个表格",对应槽位就传单个组件实例。需要多个并列时用 Fragment `<>...</>` 或容器 div 包裹,**不要用数组**。
|
|
349
|
+
|
|
306
350
|
**长尾场景走语义搜索**(不进文档,避免膨胀):
|
|
307
351
|
|
|
308
352
|
*数据可视化长尾*:`Radar`(雷达图)、`Gauge`(仪表盘)、`Funnel`(漏斗图)
|
|
@@ -84,54 +84,54 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
84
84
|
|
|
85
85
|
### 步骤2.5:Sketch 文件解析(条件执行)
|
|
86
86
|
|
|
87
|
-
**当用户提供 .sketch 设计文件时**,使用 `sketch-mcp-server`(独立 MCP Server,stdio
|
|
87
|
+
**当用户提供 .sketch 设计文件时**,使用 `sketch-mcp-server`(独立 MCP Server,stdio 模式,**v1.5.0+**)解析,直接提取结构化数据,结合组件库架构推理组件方案,无需经过视觉模型和 `mcp__szcd-component-helper__map_design_data`。
|
|
88
88
|
|
|
89
|
-
**核心原则**:写代码前必须先 `getMultipleNodeInfo` 拉取所有 `text
|
|
89
|
+
**核心原则**:写代码前必须先 `getMultipleNodeInfo` 拉取所有 `text`、`rectangle`、`group` 节点的完整样式 Token + 父子归属。`queryNodes.type` 接受数组(一次拿三类)、`getMultipleNodeInfo` 内部自动分片、每个节点自动返回 `parent: {id,name,type}`,禁止凭节点名猜测样式,禁止用 x 坐标判定元素归属。
|
|
90
90
|
|
|
91
|
-
**工作流(
|
|
91
|
+
**工作流(4 步,sketch-mcp-server v1.5.0+)**:
|
|
92
92
|
|
|
93
93
|
1. **加载文件**:
|
|
94
94
|
- `loadSketchByPath` 加载 .sketch 文件
|
|
95
95
|
- `listPages` 列出所有页面
|
|
96
|
-
- `
|
|
96
|
+
- `queryNodes`(pageId, type="artboard")获取画板列表
|
|
97
97
|
- 根据画板名称选择目标页面
|
|
98
98
|
|
|
99
|
-
2.
|
|
100
|
-
- `getPageStructure`(pageId
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
-
|
|
111
|
-
|
|
112
|
-
4. **批量拉取样式 Token**:
|
|
113
|
-
- `getMultipleNodeInfo`([id1, id2, ...])— 每次 ≤ 100 个节点
|
|
99
|
+
2. **获取分区结构**:
|
|
100
|
+
- `getPageStructure`(pageId, mode="tree", maxDepth=3)— 看顶层 group 分区(通常 2-5 个,对应 LeftTree区/Query+Table区/信息栏区/标题栏区)
|
|
101
|
+
- 记下每个分区根 group 的 id 和 name,后续按 `parent` 字段归属元素
|
|
102
|
+
|
|
103
|
+
3. **批量获取目标节点 ID**:
|
|
104
|
+
- 推荐:`queryNodes({ pageId, type: ["text", "rectangle", "group"], limit: 500 })` — **type 数组**一次拿三类节点的 ID
|
|
105
|
+
- 备选:`getPageStructure(pageId, mode="ids")` — 返回按类型分组的全量 ID `{ text: [...], rectangle: [...], group: [...], bitmap: [...], shapePath: [...] }`
|
|
106
|
+
- 顺手记下 bitmap/shapePath 节点列表,传给步骤 2.5.1
|
|
107
|
+
|
|
108
|
+
4. **批量拉取样式 Token + 父子归属**:
|
|
109
|
+
- `getMultipleNodeInfo`([id1, id2, ...])— 传入全部 ID,**内部自动按 100 个一批分片**,无需手动拆分
|
|
110
|
+
- **同批必须包含 text + rectangle + group 三类节点 ID**(漏 group 会丢失渐变背景/边框/阴影)
|
|
114
111
|
- 关键字段提取:
|
|
115
|
-
- 背景色:`style.fills[0].color.hex
|
|
112
|
+
- 背景色:`style.fills[0].color.hex`(含 group 容器的渐变)
|
|
116
113
|
- 文字色:`text.color`(部分版本在 `style.fills[0].color`)
|
|
117
114
|
- 字号:`style.fontSize`
|
|
118
115
|
- 字重:`style.fontWeight`
|
|
119
116
|
- 边框:`style.borders[0].color.hex` + `thickness`
|
|
117
|
+
- 阴影:`style.shadows`
|
|
118
|
+
- **父子归属**:`parent: { id, name, type }` ← v1.5.0+ 自动返回,元素归属判定唯一可信来源
|
|
120
119
|
- **禁止**逐个 `getNodeInfo` 探查
|
|
121
120
|
|
|
122
121
|
**步骤 2.5 产出物**(**只产出数据,不做组件映射**):
|
|
123
|
-
- Sketch
|
|
124
|
-
- text/rectangle 节点的完整样式 Token
|
|
122
|
+
- Sketch 顶层分区结构(步骤 2 的 tree)
|
|
123
|
+
- text/rectangle/group 节点的完整样式 Token + parent 父子关系
|
|
125
124
|
- 图表区结构规律识别结果
|
|
125
|
+
- bitmap ID 列表 + shapePath 节点名列表(传给步骤 2.5.1)
|
|
126
126
|
|
|
127
127
|
组件候选列表推理**不**在步骤 2.5 内部完成,**统一在主流程步骤 3.5 中结合步骤 1 的 `templatePatterns` 推理**。
|
|
128
128
|
|
|
129
|
-
**Sketch → szcd
|
|
129
|
+
**Sketch → szcd 工作流(v1.5.0+)**:
|
|
130
130
|
```
|
|
131
|
-
.sketch → loadSketchByPath → listPages →
|
|
132
|
-
→ getPageStructure(
|
|
133
|
-
→
|
|
134
|
-
→ getMultipleNodeInfo([
|
|
131
|
+
.sketch → loadSketchByPath → listPages → queryNodes(pageId, type="artboard")
|
|
132
|
+
→ getPageStructure(pageId, mode="tree", maxDepth=3) ← 拿分区
|
|
133
|
+
→ queryNodes(pageId, type=["text","rectangle","group"]) ← 拿全量 ID(数组类型)
|
|
134
|
+
→ getMultipleNodeInfo([全部 ID]) ← 自动分片,含 parent 字段
|
|
135
135
|
→ [进入主流程步骤 3.5 统一推理]
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -139,16 +139,17 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
139
139
|
|
|
140
140
|
| 步骤 | 第一次做错的 | 应该做的 |
|
|
141
141
|
|------|------------|---------|
|
|
142
|
-
|
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
|
|
|
142
|
+
| 分区识别 | 直接拉所有节点详情,靠 x/y 反推分区 | `getPageStructure(mode="tree", maxDepth=3)` 先看顶层 group 分布 |
|
|
143
|
+
| 节点收集 | 分两次调用 queryNodes 拿 text 和 rectangle | `queryNodes(type=["text","rectangle","group"])` 一次拿三类 |
|
|
144
|
+
| 样式提取 | 没做 | `getMultipleNodeInfo([全部 ID])` 内部自动分片,**单次调用** |
|
|
145
|
+
| 元素归属 | 凭 x/y 坐标判定("x=272 列都是同区域") | 看 `getMultipleNodeInfo` 返回的 `parent.id/name` 字段 |
|
|
146
|
+
| 颜色提取 | 跳过 group 只取 text/rectangle | 同批提交 group ID,从 `style.fills` 取渐变背景 |
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
**实战经验沉淀(重要)**:
|
|
148
149
|
|
|
149
150
|
**收获 1:首轮 `getMultipleNodeInfo` 必须全量拉取,不能挑**
|
|
150
151
|
- 错误做法:先查 7 个顶层容器,再根据需要分批补漏(结果补了 7 轮 ≈ 108 个节点)
|
|
151
|
-
- 正确做法:`
|
|
152
|
+
- 正确做法:`queryNodes(type=["text","rectangle","group"])` 一次性拿全量 ID → `getMultipleNodeInfo([全部 ID])`,**单次调用**(内部自动分片)
|
|
152
153
|
|
|
153
154
|
**收获 2:text 节点是颜色/DOM 映射的两级索引**
|
|
154
155
|
每个 text 节点同时关联两种上下文,**必须同批拉取**:
|
|
@@ -156,9 +157,28 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
156
157
|
- 所属 group 父级 rectangle 样式:`bg`、`border`、`radius`、`shadow`
|
|
157
158
|
|
|
158
159
|
错误做法:先查 text 拿自身样式 → 再根据 parent ID 单独查 rectangle(多走一步)
|
|
159
|
-
|
|
160
|
+
正确做法:用 `queryNodes(type=["text","rectangle","group"])` 一次拿三类 ID,`getMultipleNodeInfo` 返回的 `parent` 字段直接告诉你归属关系
|
|
161
|
+
|
|
162
|
+
**收获 3:元素归属必须走 group 父子关系,禁止 x 坐标平面判定**
|
|
163
|
+
|
|
164
|
+
实战教训:`'主题'text(x=272,y=149)` 被错误识别为内容区块标题,实际是左侧树标题(与树节点同 x=272 列)。同列坐标不代表同区域。
|
|
165
|
+
|
|
166
|
+
正确做法:
|
|
167
|
+
- 步骤 2 拿到完整节点树后,先识别顶层 group 分区(通常 2-5 个,对应 LeftTree区/Query+Table区/信息栏区/标题栏区)
|
|
168
|
+
- `getMultipleNodeInfo` v1.5.0+ **自动返回** `parent: { id, name, type }` 字段,按 parent 归属到具体分区
|
|
169
|
+
- "主题"这类标题文本,先看 `parent.name` 是否带 "LeftTree" / "树" / "PageContent" 等容器关键字,不要看 x 坐标
|
|
170
|
+
- 坐标仅作为同 parent 内子元素排序兜底使用
|
|
171
|
+
|
|
172
|
+
**收获 4:信息栏/卡片容器必须先取 group 再取子元素**
|
|
173
|
+
|
|
174
|
+
实战教训:仅提取 text 节点导致信息栏容器样式遗漏(渐变背景 #f3faff→#f8fdff、边框 #e9f5ff、图标编组)。
|
|
175
|
+
|
|
176
|
+
正确做法:
|
|
177
|
+
- 看到画板里有 `编组N`/`infoCard`/`statBox` 等 group 节点,必须连 group 自身和内部 rectangle 一起拉 `getMultipleNodeInfo`
|
|
178
|
+
- group 节点的 `style.fills` 才是渐变背景、`style.borders` 才是边框
|
|
179
|
+
- 子图标若为 group(rectangle + shapePath),rectangle 是圆形/方形背景,shapePath 是矢量图标
|
|
160
180
|
|
|
161
|
-
**收获
|
|
181
|
+
**收获 5:图表区样式提取有规律可循**
|
|
162
182
|
|
|
163
183
|
| 图表子元素 | 对应 Sketch 节点类型 | 关键样式字段 |
|
|
164
184
|
|---|---|---|
|
|
@@ -173,23 +193,34 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
173
193
|
|
|
174
194
|
识别出图表后,**图例色块**应归入 ECharts `legend` 配置(不要用 div 硬编码),**柱体色**映射到 `series.itemStyle.color`。
|
|
175
195
|
|
|
176
|
-
**收获
|
|
177
|
-
- `shapePath` / `shapeGroup` 在 sketch 节点中占比可能高达 46.8
|
|
178
|
-
- 解压 `.sketch
|
|
179
|
-
-
|
|
196
|
+
**收获 6:矢量图形 + 图标语义优先级(v1.5.0 已内置 compoundIcons)**
|
|
197
|
+
- `shapePath` / `shapeGroup` 在 sketch 节点中占比可能高达 46.8%,`renderNodeAsBase64` 不支持渲染
|
|
198
|
+
- 解压 `.sketch` 只能提取 `bitmap` 中内嵌的 PNG/PDF(常仅几张,通常是 Logo)
|
|
199
|
+
- **`matchIconFromName` v1.5.0+ 评分制**:每个 nodeName 返回 Top-3 候选,complex 词组合(如"文件夹+新增")自动命中 `FolderAddOutlined`(compound score 100+),不会被"新增"单独 +20 分压制
|
|
200
|
+
- 优先看 `bestMatch.source === "compound"`:表示已强映射,直接采用 `antdIcon`
|
|
201
|
+
- `unmatched`(无关键词信号,如"编组11备份")必须看节点 `parent.name` 和兄弟节点上下文兜底
|
|
180
202
|
|
|
181
|
-
|
|
182
|
-
- 大型 .sketch 文件先 `listNodesByPage(type="artboard")` 锁定目标画板,避免一次性加载整个文档
|
|
183
|
-
- `getNodesSummary` 是 token 节省关键:先按类型分组统计,再决定要查哪些节点 ID
|
|
184
|
-
- 批量 `getMultipleNodeInfo` 严格 ≤ 100 个/次,超过需分批
|
|
185
|
-
- 仅当结构化样式数据仍不足(如复杂渐变、阴影)时,才回退到 `renderNodeAsBase64` + `mcp__szcd-component-helper__analyze_design_image`
|
|
186
|
-
- 如果 sketch-mcp-server 工具不可用,提示用户安装:`npm install -g sketch-mcp-server`
|
|
203
|
+
**参考表(内置 compoundIcons 已覆盖;列出供 unmatched 兜底参考)**:
|
|
187
204
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
205
|
+
| Sketch 节点上下文 | 期望 antd 图标 | 反例(不要选) |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| 文件夹+新增/添加 | `FolderAddOutlined` | PlusOutlined |
|
|
208
|
+
| 文件+新增 | `FileAddOutlined` | PlusOutlined |
|
|
209
|
+
| 用户+新增 | `UserAddOutlined` | PlusOutlined |
|
|
210
|
+
| 文件夹+打开 | `FolderOpenOutlined` | FolderOutlined |
|
|
211
|
+
| 编辑+笔 | `EditOutlined` | FormOutlined |
|
|
212
|
+
| 设置+齿轮 | `SettingOutlined` | ToolOutlined |
|
|
213
|
+
|
|
214
|
+
- **兜底方案**:① 用 `extractBitmaps` 提取的 PNG/PDF 资源;② `matchIconFromName` 的 Top-1(若 source=compound);③ unmatched 时按 parent 上下文 + 上表选 antd `@ant-design/icons` 复合图标;④ 在代码注释中标注"⚠️ 矢量图标用 antd 图标替代,原始 Sketch 为 shapePath"
|
|
215
|
+
|
|
216
|
+
**提示(sketch-mcp-server v1.5.0+)**:
|
|
217
|
+
- 大型 .sketch 文件先 `queryNodes(pageId, type="artboard")` 锁定目标画板,避免一次性加载整个文档
|
|
218
|
+
- `queryNodes(pageId, type=["text","rectangle","group"])` 一次拿三类节点 ID(type 字段支持数组),跳过 `getPageStructure(mode="ids")` 单独调用
|
|
219
|
+
- `getPageStructure(pageId, mode="tree", maxDepth=2-3)` 用于看分区层级;`mode="summary"` 用于按类型统计概况
|
|
220
|
+
- 批量 `getMultipleNodeInfo` 支持任意数量 ID(内部按 100 一批自动分片),无需手动拆分;每个节点自带 `parent: {id,name,type}` 字段,元素归属直接走 parent,禁止用 x/y 坐标
|
|
221
|
+
- `matchIconFromName` 评分制返回 Top-3 + `bestMatch.source === "compound"` 强映射,shapePath 节点优先走它
|
|
222
|
+
- 仅当结构化样式数据仍不足(如复杂渐变、阴影)时,才回退到 `renderNodeAsBase64` + `mcp__szcd-component-helper__analyze_design_image`
|
|
223
|
+
- 如果 sketch-mcp-server 工具不可用,提示用户安装:`npm install -g @szc-ft/sketch-mcp-server`
|
|
193
224
|
|
|
194
225
|
### 步骤3:分析设计稿(条件执行)
|
|
195
226
|
|
|
@@ -266,6 +297,19 @@ Ant Design → ProComponents → Cover 层 → Wrapper 层 → ProPackages →
|
|
|
266
297
|
| 可编辑表格(单元格直接输入) | `TableOrList(componentType="EditableProTable")` | 可编辑表格特征 |
|
|
267
298
|
| 卡片列表(非表格式数据卡片) | `TableOrList(componentType="ProList")` | 卡片布局特征 |
|
|
268
299
|
|
|
300
|
+
#### ⚠️ TemplateMode 槽位传参铁律(高频踩坑)
|
|
301
|
+
|
|
302
|
+
**LeftContent / Query / PageContent 三个槽位都接收单个 ReactNode,禁止传数组**:
|
|
303
|
+
|
|
304
|
+
| ❌ 错误 | ✅ 正确 | 后果 |
|
|
305
|
+
|---|---|---|
|
|
306
|
+
| `LeftContent={[<LeftTree/>]}` | `LeftContent={<LeftTree/>}` | 数组会触发多余 tab 渲染 |
|
|
307
|
+
| `LeftContent={[<LeftTree/>, <Filter/>]}` | `LeftContent={<><LeftTree/><Filter/></>}` 或包一层 div | 同上 |
|
|
308
|
+
| `Query={[<Query/>]}` | `Query={<Query/>}` | 同上 |
|
|
309
|
+
| `PageContent={[<TableOrList/>]}` | `PageContent={<TableOrList/>}` | 同上 |
|
|
310
|
+
|
|
311
|
+
**判定方法**:Sketch 中只要某个分区是"单棵树/单个查询面板/单个表格",对应槽位就传单个组件实例。需要多个并列时用 Fragment `<>...</>` 或容器 div 包裹,**不要用数组**。
|
|
312
|
+
|
|
269
313
|
**长尾场景走语义搜索**(不进文档,避免膨胀):
|
|
270
314
|
|
|
271
315
|
*数据可视化长尾*:`Radar`(雷达图)、`Gauge`(仪表盘)、`Funnel`(漏斗图)
|