lanhu-design-mcp 0.2.1 → 0.3.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/README.md +60 -426
- package/dist/index.js +25 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
# lanhu-design-mcp
|
|
2
2
|
|
|
3
3
|
零依赖 stdio MCP server,让任意支持 MCP 的 coding Agent(Claude Code / Cursor / Trae /
|
|
4
|
-
opencode
|
|
4
|
+
opencode)直接读蓝湖设计稿做开发与验收:
|
|
5
5
|
|
|
6
|
-
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
- **下载切图**:`lanhu_download_slices` 把设计稿切图素材拉到本地 assets,供开发引用。
|
|
11
|
-
- **视觉理解 + 验收**:`lanhu_fetch_design` 在配置了视觉模型时**默认自动**理解设计稿封面图(返回 `visionAnalysis`),无需每次手带 `analyze`;`lanhu_verify_render` /
|
|
12
|
-
`vision_defect_check` / `vision_e2e_triage` 做渲染对比、UI 缺陷检测、E2E 失败归因。
|
|
6
|
+
- **结构化图层树**:官方 API(Cookie 直调)取 x/y/宽高/色值/字号/圆角(含逐角)/描边/阴影/文本,精确数值来自结构化数据,**不靠视觉模型 OCR 截图小字**;
|
|
7
|
+
- **团队目录导航**:团队 → 项目 → 分组(需求)→ 设计稿完整层级,一次拉取、按需下钻;
|
|
8
|
+
- **切图下载**:单稿或分组批量,三层去重 + 字节级验真,直接落盘本地 assets;
|
|
9
|
+
- **视觉理解与验收**:配置视觉模型后自动理解封面图语义(`visionAnalysis`),另有渲染对比、UI 缺陷检测、E2E 失败归因。
|
|
13
10
|
|
|
14
|
-
TypeScript
|
|
15
|
-
你自己的 coding Agent 就是流水线里的"代码生成引擎"——本 MCP 只负责"读设计"和"做验收"。
|
|
11
|
+
TypeScript + 官方 MCP SDK。你的 coding Agent 就是流水线里的"代码生成引擎"——本 MCP 只负责"读设计"和"做验收"。
|
|
16
12
|
|
|
17
13
|
## 环境要求
|
|
18
14
|
|
|
@@ -21,42 +17,24 @@ TypeScript 实现,基于官方 MCP SDK(`@modelcontextprotocol/sdk` + `zod`
|
|
|
21
17
|
## 安装 & 构建
|
|
22
18
|
|
|
23
19
|
```bash
|
|
24
|
-
npm install
|
|
25
|
-
npm run build # tsc 编译到 dist/
|
|
20
|
+
npm install && npm run build # esbuild 打包为单文件 dist/index.js
|
|
26
21
|
```
|
|
27
22
|
|
|
28
23
|
## 快速开始
|
|
29
24
|
|
|
30
|
-
### 1.
|
|
25
|
+
### 1. 蓝湖 Cookie
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
- **推荐**:Windows 双击 `lanhu-login.bat`(或 `npm run login`),浏览器登录后回终端按 Enter,cookie 自动写入 `.mcp-local/lanhu.cookie`(已 gitignore);
|
|
28
|
+
- **手动**:F12 → Network → 任意请求复制 `Cookie` 头整串,写入同一文件;
|
|
29
|
+
- 过期后重跑一次登录脚本即可,AI 检测到 401 时会提示你。
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
### 2. 视觉模型(analyze / 验收需要)
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
**命令行登录**:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
npm i playwright # 仅 lanhu-login.mjs 需要
|
|
43
|
-
npx playwright install chromium
|
|
44
|
-
node lanhu-login.mjs
|
|
45
|
-
# → 弹出浏览器手动登录蓝湖,回终端按 Enter,把 cookie 串写入 .mcp-local/lanhu.cookie(已 gitignore)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**cookie 过期后**:重新跑一次上面的 `lanhu-login.bat` 或 `node lanhu-login.mjs` 即可。AI 检测到过期时会提示你。
|
|
49
|
-
|
|
50
|
-
### 2. 配置视觉模型(analyze / 验收需要)
|
|
51
|
-
|
|
52
|
-
配置 `VLM_API_KEY`(视觉模型 Key),可选 `VLM_MODEL`。
|
|
53
|
-
|
|
54
|
-
配好后 `lanhu_fetch_design` 会**默认带上视觉理解**(`analyze` 自动为 `true`);想省掉这次视觉调用传 `analyze:false`,或设 `LANHU_AUTO_ANALYZE=0` 全局关闭。
|
|
33
|
+
配置 `VLM_API_KEY`,可选 `VLM_BASE_URL` / `VLM_MODEL`(任何 OpenAI 兼容端点均可,默认 DeepSeek)。
|
|
34
|
+
配好后 `lanhu_fetch_design` **默认自动返回视觉理解**;想跳过传 `analyze:false`,或设 `LANHU_AUTO_ANALYZE=0` 全局关闭。
|
|
55
35
|
|
|
56
36
|
### 3. 接入 Agent(项目根 `.mcp.json`)
|
|
57
37
|
|
|
58
|
-
**npm 包(推荐,免 clone 免构建)**:
|
|
59
|
-
|
|
60
38
|
```json
|
|
61
39
|
{
|
|
62
40
|
"mcpServers": {
|
|
@@ -65,7 +43,7 @@ node lanhu-login.mjs
|
|
|
65
43
|
"args": ["-y", "lanhu-design-mcp"],
|
|
66
44
|
"env": {
|
|
67
45
|
"VLM_API_KEY": "your-api-key",
|
|
68
|
-
"VLM_BASE_URL": "https://api.
|
|
46
|
+
"VLM_BASE_URL": "https://api.deepseek.com",
|
|
69
47
|
"LANHU_COOKIE_FILE": "./.mcp-local/lanhu.cookie"
|
|
70
48
|
}
|
|
71
49
|
}
|
|
@@ -73,412 +51,68 @@ node lanhu-login.mjs
|
|
|
73
51
|
}
|
|
74
52
|
```
|
|
75
53
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```json
|
|
79
|
-
{
|
|
80
|
-
"mcpServers": {
|
|
81
|
-
"lanhu-design-mcp": {
|
|
82
|
-
"command": "node",
|
|
83
|
-
"args": ["/绝对路径/mcp-design-toolbox/lanhu-design-mcp/dist/index.js"],
|
|
84
|
-
"env": {
|
|
85
|
-
"VLM_API_KEY": "your-api-key",
|
|
86
|
-
"LANHU_COOKIE_FILE": "./.mcp-local/lanhu.cookie"
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
`LANHU_COOKIE_FILE` 指向本地 cookie 文件(内容为完整 cookie 串,已 gitignore);
|
|
94
|
-
`VLM_API_KEY` 也可从 shell 环境变量展开。两者都不入库。
|
|
54
|
+
源码开发时改为 `node` + `dist/index.js` 绝对路径。Cursor(`.cursor/mcp.json`)/ Trae / opencode 配置字段一致。
|
|
95
55
|
|
|
96
56
|
## 工具一览
|
|
97
57
|
|
|
98
|
-
| 工具 |
|
|
99
|
-
|
|
100
|
-
| `lanhu_check_auth` | 探活 cookie
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `lanhu_download_slices` |
|
|
106
|
-
| `lanhu_verify_spec` |
|
|
107
|
-
| `lanhu_verify_render` | 渲染页 vs
|
|
108
|
-
| `vision_defect_check` | 整页/局部 UI 缺陷检测(12
|
|
109
|
-
| `vision_e2e_triage` | E2E
|
|
110
|
-
|
|
111
|
-
## 使用示例
|
|
112
|
-
|
|
113
|
-
> 示例中的 `cookie` 参数均可省略——省略时走环境变量 `LANHU_COOKIE` 或 `LANHU_COOKIE_FILE` 指定的文件。
|
|
114
|
-
|
|
115
|
-
### cookie 过期怎么办(AI 判断流程)
|
|
116
|
-
|
|
117
|
-
任何蓝湖工具报 `HTTP 401` 或返回异常空数据时,AI 会先调 `lanhu_check_auth` 探活来区分原因:
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
lanhu_check_auth({})
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
- 返回 `{ ok:true, teamCount, teams }` → cookie 仍有效,刚才的 401 是**无权访问该资源**(稿没对你分享)。重新登录无效,需联系设计者开权限。
|
|
124
|
-
- 返回 `{ ok:false, reason:"cookie_expired", hint:"..." }` → cookie 确实过期。提示用户运行**`lanhu-login.bat`**或 `npm run login` 续期。
|
|
125
|
-
- `reason:"http_xxx"` → 蓝湖其它 HTTP 错误,稍后重试或检查网络。
|
|
126
|
-
- `reason:"network_error"` → 网络不通。
|
|
127
|
-
|
|
128
|
-
> 401 不一定是 cookie 过期:全局接口 401 多半是 cookie 问题;单个稿 401 而 `check_auth` 通过,则是权限问题。`check_auth` 让 AI 不再一刀切误报过期。
|
|
129
|
-
|
|
130
|
-
### 读单个设计稿
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
lanhu_fetch_design({
|
|
134
|
-
mode: "api", // 默认,官方 Cookie 接口
|
|
135
|
-
url: "https://lanhuapp.com/web/#/item/project/detailDetach?pid=xxx&image_id=yyy"
|
|
136
|
-
})
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
返回 `{ name, viewport, layers(精确坐标/色值/字号/文本), meta }`。
|
|
140
|
-
layers 已清洗:过滤无样式纯容器层(实测省 20-30% 体积),每层带 `parentPath`(有语义的父容器名链)保分组语义;`meta.payloadBytes/droppedLayerCount` 报告数据体积与过滤量。
|
|
141
|
-
二次清洗(面向输出形态):alpha=1 颜色缩写为 hex;自动生成名(矩形/编组N/Rectangle 9943…)不输出(切图层豁免——名字是下载句柄);空壳层剔除(仅透明度/仅圆角、无填充描边的层不渲染任何东西);完全在画布外的层、逐字段一致的堆叠副本、同几何的重复切图标记(编组+子层各标一次,保留 type=image 的)剔除;被上方不透明纯色矩形完整遮挡的层剔除;可见面积占比过低(默认 <25%,只露出窄条)的矩形剔除;碎片装饰带剔除(同一容器内一排首尾相接的微小矢量段——高≤8/宽≤24/成带/宽度参差,等宽等距的分段与孤立小点保留);「备份/backup」命名的备用层整棵子树剔除;布尔运算节点(Subtract/Union 等)的操作数子层折叠(操作数从不独立渲染,只留带真实填充的布尔节点)。各规则计数见 `meta.droppedLayerCount / dedupedLayerCount / outsideCanvasLayerCount / occludedLayerCount / sliverLayerCount / fragmentLayerCount / backupLayerCount / booleanOperandLayerCount`。切图 CDN URL 不随稿返回(按名下载走 `lanhu_download_slices` 的 `sliceNames`)。返回体为紧凑 JSON。
|
|
142
|
-
|
|
143
|
-
### 读 + 视觉理解设计稿(双重验证)
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
lanhu_fetch_design({
|
|
147
|
-
mode: "api",
|
|
148
|
-
url: "https://lanhuapp.com/web/#/item/project/detailDetach?pid=xxx&image_id=yyy",
|
|
149
|
-
analyze: true // 下载封面图 → 喂给视觉模型 → 返回 visionAnalysis 文字描述
|
|
150
|
-
})
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
**`analyze` 默认自动开启**:已配置视觉模型(模型名 + `VLM_API_KEY`)时,不传 `analyze` 也等价于 `analyze: true`;
|
|
154
|
-
未配置视觉能力时默认 `false`。显式传 `true`/`false` 始终优先于自动判断。
|
|
155
|
-
想保留图层树、跳过视觉调用,显式传 `analyze: false`,或设 `LANHU_AUTO_ANALYZE=0` 全局关闭自动分析。
|
|
156
|
-
`analyzeFocus` 可注入调用方关注点/业务背景(如「重点分析签到奖励领取规则」),视觉模型会将其融入分析但不改变 JSON 结构——同一张稿、不同关注点会得到不同侧重的分析结果。
|
|
157
|
-
|
|
158
|
-
`analyze` 会返回 `visionAnalysis`(纯语义理解:page_type/版面区块/组件清单(position 用档位词+区块名)/视觉叠放层级/imagery(每张背景图的内容+与文字的关系+真伪占位)/氛围/动效暗示;精确数值一律不输出,由 layers 提供),**封面图 base64 不进上下文**,
|
|
159
|
-
只在 server 内部喂给视觉模型——且喂前已压到 **1x JPEG**(4x 封面 1.6MB → 约 100KB 内)。
|
|
160
|
-
视觉分析失败(模型超时/鉴权失败/无封面图)不再让整次读稿失败,而是原样返回图层树并附 `visionError` 字段说明原因。
|
|
161
|
-
`lanhu_verify_render` / `vision_defect_check` / `vision_e2e_triage` 的入参截图也会在 server 端统一压到最长边 1568 再发模型。
|
|
162
|
-
结合图层树的精确数值做双重验证。
|
|
163
|
-
|
|
164
|
-
### 设计稿验收(lanhu_verify_spec)
|
|
165
|
-
|
|
166
|
-
替代人工走查的主手段:**不靠模型看图,靠数值比对**。
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
lanhu_verify_spec({
|
|
170
|
-
designUrl: "https://lanhuapp.com/web/#/item/project/detailDetach?pid=xxx&image_id=yyy",
|
|
171
|
-
pageUrl: "http://localhost:5173/task-center",
|
|
172
|
-
waitFor: ".task-list" // 等接口数据渲染完再采,可选
|
|
173
|
-
})
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
流程:设计稿图层树取**期望值** → Playwright 打开页面采 `getComputedStyle` 取**实际值** → 逐字段 diff → 输出偏差清单。
|
|
177
|
-
比对字段:`x / y / width / height`(容差 1px)、`color / fill`(通道差 ≤2 且 alpha 差 ≤0.02)、`fontSize`(容差 0.5)、`fontWeight`、`lineHeight`(容差 1px)、`text`。
|
|
178
|
-
偏差按 `minor / major / critical` 分级,带 `delta`。
|
|
179
|
-
|
|
180
|
-
**H5 webview 验收口径**(内嵌 Android/iOS webview 的移动端项目):
|
|
181
|
-
- **宽度严格、高度宽松**:`x` / 非文本层 `width` 严比对;`y` / `height` 因状态栏占位与内容动态渲染,整体偏移属预期,差异一律降 `minor`。
|
|
182
|
-
- **状态栏不渲染**:设计稿顶部状态栏层(命名或顶部整条几何特征)比对前剔除;页面整体竖直偏移 `dy` 回 `offset` 字段并标注为预期,不报缺陷。
|
|
183
|
-
- **文案语义接近即可**:文本差异默认降 `minor`(warning);配了视觉模型时批量做语义等价判定,仅当确为不同含义才升 `major`。
|
|
184
|
-
- **前置去噪**:`opacity=0`、零尺寸、蒙版/标注/备份组(`*备份`)/占位/切图导出件等无效图层比对前剔除,不污染匹配与未匹配统计。
|
|
185
|
-
- **_fill 在父级背景实现_**:页面叶子节点背景透明时向上回退 3 级祖先背景色;命中即跳过;叶子全透明仍未命中则封顶 `major`,不刷 critical。
|
|
186
|
-
|
|
187
|
-
**元素匹配打分**:文案精确相等 > 纯几何 IoU ≥0.5。
|
|
188
|
-
统一候选池 + **全局贪心**分配,不按图层顺序逐个挑——顺序贪心在重复 key 下会先到先得、整队错位。
|
|
189
|
-
不依赖任何 DOM 标注属性,开发无需在页面写 `data-design`;密集/重叠区域的归属歧义由「样式清单比对」安全网兜底(见下)。
|
|
190
|
-
|
|
191
|
-
**整体偏移估算**(页面与设计稿常差一个状态栏高度,不校正会让所有 IoU 归零):
|
|
192
|
-
用**真实位置匹配对**(IoU≥0.5,与文案/语言无关)RANSAC 反推整体偏移 → 再用校正后的偏移重跑几何轮补齐漏配。
|
|
193
|
-
不依赖文案锚点,故设计稿与页面语言不同(简/繁/英)也能估准(实测 EN/ZH 均收敛到 dx≈0, dy≈-35)。
|
|
194
|
-
|
|
195
|
-
**样式清单比对(永远在线的安全网,无需任何标注)**:
|
|
196
|
-
不做元素配对,只比「设计稿文字样式集合」vs「页面文字样式集合」,元组 = `fontSize / 字重 / 色值`。
|
|
197
|
-
它**不比文案**,因此跨语言、跨迭代文案差异都不会让它失盲——是逐元素配对的主信号兜底,也是开发无需在页面写标注属性的前提下仍能发现样式漂移的抓手。
|
|
198
|
-
结果落在返回的 `inventory` 字段:`missingOnPage`(设计稿有、页面无 → 元素缺失/样式被覆盖)与
|
|
199
|
-
`notInDesign`(页面有、设计稿无 → 样式漂移/硬编码),每项附示例图层名/选择器便于定位。
|
|
200
|
-
> 实测(任务中心稿,零标注):`inventory` 以 7 类差异定位到真缺陷集群——任务名 `<p>` 被 `:last-child` 误伤(`10px/700` 共 16 处)、
|
|
201
|
-
> Go/Claim 按钮字号漂移(`14px→12px` 共 7 处);而配对模式同条件下输出 55 条偏差,信噪比显著提升。
|
|
202
|
-
|
|
203
|
-
> 注意:**纯几何匹配对同尺寸重叠的大矩形区分力弱**(如白色卡片矩形易误配到相邻橙色进度条)。
|
|
204
|
-
> 这类归属歧义不靠 DOM 标注解决,而是交给「样式清单比对」安全网按样式集合兜底——它不做几何匹配,天然不受大矩形误配影响。
|
|
205
|
-
|
|
206
|
-
> 真实项目实测(任务中心线上稿 375×1078 / 339 层 vs 本地 dev 页面):
|
|
207
|
-
> 去噪+宽松化后 EN 偏差 50 条(critical 6)、ZH 26 条(critical 3);抓到 1 类真缺陷并定位根因——
|
|
208
|
-
> 任务名 `<p>` 被 `p:last-child` 降级规则误伤(期望 14px/700/#232129,实际 10px/400/#262529,7 个任务项全中)。
|
|
209
|
-
> 前提是设计稿与页面**同语言、同迭代**;跨语言/跨迭代时文本对不上,偏差里大部分是噪音(已降级为 warning)。
|
|
210
|
-
|
|
211
|
-
当前为最小可用版本:只跑默认态、按设计稿 viewport 单一视口、不评分。
|
|
212
|
-
|
|
213
|
-
### 列账号所属团队(多团队发现)
|
|
214
|
-
|
|
215
|
-
```
|
|
216
|
-
lanhu_list_teams({})
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
返回 `{ teamCount, teams: [{ teamId, name, role, isOwner, memberNum }] }`。
|
|
220
|
-
多团队时先列团队,拿 `teamId` 传给 `lanhu_list_directory`;省略敏感字段(phone/company/tax_id_no 等)。
|
|
221
|
-
|
|
222
|
-
### 列项目分组(团队目录定位)
|
|
223
|
-
|
|
224
|
-
团队定位优先级:`url`(提 tid,最准)> `teamId`(来自 list_teams)。两者都没有则报错。
|
|
225
|
-
|
|
226
|
-
```
|
|
227
|
-
// 有蓝湖链接——直接传 url,从 tid 定位团队(最准,推荐)
|
|
228
|
-
lanhu_list_directory({
|
|
229
|
-
url: "https://lanhuapp.com/web/#/item/project/detailDetach?pid=xxx&image_id=yyy&tid=zzz"
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
// 没链接——先 lanhu_list_teams 拿 teamId
|
|
233
|
-
lanhu_list_directory({
|
|
234
|
-
teamId: "21e6d63c-..."
|
|
235
|
-
})
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
返回 `{ teamId, projectCount, sectorCount, directory: [{ project, projectId, sectors: [{ name, designCount }] }] }`。
|
|
239
|
-
|
|
240
|
-
### 按分组看稿目录(完成某个需求)
|
|
241
|
-
|
|
242
|
-
```
|
|
243
|
-
lanhu_read_sector({
|
|
244
|
-
url: "https://lanhuapp.com/web/#/item/project/detailDetach?pid=xxx&image_id=yyy",
|
|
245
|
-
sector: "会员体系" // 分组名,从 lanhu_list_directory 看到
|
|
246
|
-
})
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
返回 `{ sector, designCount, designs: [{ image_id, name, viewport, layerCount }] }`——只含稿目录(稿名/尺寸/层数),**不含图层树**。全量 layers 实测 26 稿约 395KB,会撑爆 Agent 上下文,故故意不返回;按稿名挑出要实现的目标后,用 `lanhu_fetch_design` 逐张读图层树。
|
|
250
|
-
|
|
251
|
-
### 不知道蓝湖链接,按活动名找分组(一页目录)
|
|
252
|
-
|
|
253
|
-
当你说"帮我看看节日活动页有几个设计稿"时,AI 无需你给链接,一次拉全团队目录直接定位:
|
|
254
|
-
|
|
255
|
-
```
|
|
256
|
-
// 需先 lanhu_list_teams 拿 teamId(或传任意该团队蓝湖链接的 url)
|
|
257
|
-
lanhu_list_directory({ teamId: "21e6d63c-..." })
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
返回一张完整目录(约 1.6k tokens,并行拉取约 2 秒):
|
|
261
|
-
|
|
262
|
-
```js
|
|
263
|
-
{
|
|
264
|
-
teamId, projectCount: 8, sectorCount: 163,
|
|
265
|
-
directory: [
|
|
266
|
-
{ project: "示例项目 H5/Web",
|
|
267
|
-
projectId: "d290f1ee-6c54-4b01-90e6-d701748f0851",
|
|
268
|
-
sectors: [
|
|
269
|
-
{ name: "会员体系", designCount: 18 },
|
|
270
|
-
{ name: "节日活动页", designCount: 5 },
|
|
271
|
-
// ...
|
|
272
|
-
] },
|
|
273
|
-
// ...更多项目
|
|
274
|
-
]
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
AI 在这份目录里按分组名匹配"节日活动页" → 拿到所在项目的 `projectId` →
|
|
279
|
-
传给 `lanhu_read_sector({ url: projectId, sector: "节日活动页" })` 读稿。
|
|
280
|
-
没匹配上则如实回答未找到,或问用户补充。
|
|
281
|
-
|
|
282
|
-
> `lanhu_read_sector` 的 `url` 参数同时接受**蓝湖链接**和**项目 UUID**(来自 `lanhu_list_directory` 的 `projectId`)。
|
|
283
|
-
> `lanhu_list_directory` 的 `team_id` 两级定位:`url` 入参提取的 tid > `teamId` 入参。两者都没有则报错(实测 `tenantId=0` 返回空目录而非默认团队,不能兜底)。有链接传 `url` 最准;没链接用 `lanhu_list_teams` 拿 `teamId`。
|
|
284
|
-
> 只到分组层(含 designCount),不展开设计稿名——保持轻量;稿名在读 sector 时才按需拉。
|
|
285
|
-
|
|
286
|
-
### 下载切图到本地项目(开发引用素材)
|
|
287
|
-
|
|
288
|
-
实现某个设计稿时,把稿里标记导出的切图(icon/图/头像框等)拉到本地 assets。两种范围、三层去重:
|
|
289
|
-
|
|
290
|
-
**单稿下载**:
|
|
291
|
-
|
|
292
|
-
```
|
|
293
|
-
lanhu_download_slices({
|
|
294
|
-
url: "https://lanhuapp.com/web/#/item/project/detailDetach?pid=xxx&image_id=yyy",
|
|
295
|
-
outputPath: "src/assets/masked-ball/"
|
|
296
|
-
})
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
**分组批量下载**(跨稿去重,公共 icon 只下一次):
|
|
300
|
-
|
|
301
|
-
```
|
|
302
|
-
lanhu_download_slices({
|
|
303
|
-
url: "b54e3d95-...", // 项目 UUID 或该分组任一稿链接
|
|
304
|
-
sector: "会员体系", // 分组名(从 lanhu_list_directory 看到)
|
|
305
|
-
outputPath: "src/assets/membership/"
|
|
306
|
-
})
|
|
307
|
-
```
|
|
308
|
-
拉该分组所有稿的切图合并去重。实测 20 稿 194 切图 → URL 去重后 133 张,省 61 张重复。
|
|
309
|
-
|
|
310
|
-
**只下指定切图**(sliceNames 过滤):
|
|
311
|
-
|
|
312
|
-
```
|
|
313
|
-
lanhu_download_slices({
|
|
314
|
-
url: "...",
|
|
315
|
-
outputPath: "...",
|
|
316
|
-
sliceNames: ["关闭icon", "返回btn"] // 只下这几个名字的切图
|
|
317
|
-
})
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
返回:
|
|
321
|
-
```js
|
|
322
|
-
{
|
|
323
|
-
scope: "会员体系", // 单稿=稿名,分组=分组名
|
|
324
|
-
outputDir: "/abs/.../src/assets/membership",
|
|
325
|
-
downloaded: 133, // 实际下载张数
|
|
326
|
-
skipped: { dup: 61, exist: 0 }, // URL 去重跳过 / 本地已存在跳过
|
|
327
|
-
failed: [], // 下载失败明细(不再静默跳过)
|
|
328
|
-
slices: [{ name, file, bytes, w, h }] // 全部已落盘+已存在的切片
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
三层去重(默认全开,可独立开关):
|
|
333
|
-
1. **URL 去重** —— 蓝湖切图 URL 按图内容 hash 命名,同 URL = 同图,只下一次(解决跨稿+稿内重复)
|
|
334
|
-
2. **skipExisting** —— 本地已存在同名文件就跳过(`skipExisting:false` 可强制重下;默认 true)
|
|
335
|
-
3. **sliceNames** —— 只下指定名字的切图(同名不同 URL 都下,因为它们是不同的图)
|
|
336
|
-
|
|
337
|
-
文件名为「图层名 + 短 hash + 扩展名」(清洗非法字符 `/ \ : * ? " < > |`、防重名),AI 拿到 `file` 路径即可在代码里引用。切图来自蓝湖公开 CDN,无需 cookie 即可下载。
|
|
338
|
-
|
|
339
|
-
> **关于倍率/平台**:蓝湖客户端可按 `@2x/@3x` 或安卓 `mipmap-xxxhdpi` 选倍率,但官方 API 返回的切图 URL 是单一默认值(安卓端最高分辨率 xxxhdpi/4x)。本工具**下载时自动压缩到 2x**(按设计尺寸 ×2 resize + PNG 调色板压缩,实测 138KB → 24KB),H5 用 CSS 控制显示尺寸。返回的 `slices[].w/h` 仍是设计坐标,落盘像素 = w×2 / h×2。
|
|
340
|
-
|
|
341
|
-
**存量 4x 图批量压缩**(对之前下载的旧目录):
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
node scripts/compress-images.mjs src/assets/xxx/ [--factor 0.5] [--dry-run]
|
|
345
|
-
```
|
|
58
|
+
| 工具 | 用途 |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `lanhu_check_auth` | 探活 cookie,区分"已过期"与"该资源无权限" |
|
|
61
|
+
| `lanhu_list_teams` | 列账号加入的全部团队(多团队发现) |
|
|
62
|
+
| `lanhu_list_directory` | 一次拉团队目录(项目 → 分组,无需链接) |
|
|
63
|
+
| `lanhu_read_sector` | 按分组列稿目录(稿名/尺寸/层数,不含图层树) |
|
|
64
|
+
| `lanhu_fetch_design` | 读单稿结构化图层树 + 视觉语义理解 |
|
|
65
|
+
| `lanhu_download_slices` | 切图下载到本地 assets(单稿 / 分组批量) |
|
|
66
|
+
| `lanhu_verify_spec` | 设计稿验收:图层树期望值 ↔ 页面计算样式逐字段 diff |
|
|
67
|
+
| `lanhu_verify_render` | 渲染页 vs 设计稿语义对比(主观线索) |
|
|
68
|
+
| `vision_defect_check` | 整页/局部 UI 缺陷检测(12 类) |
|
|
69
|
+
| `vision_e2e_triage` | E2E 失败截图 + DOM 归因 |
|
|
346
70
|
|
|
347
|
-
|
|
71
|
+
工具入参 schema 自描述,Agent 在工具列表里即可看到完整入参说明。
|
|
348
72
|
|
|
349
|
-
|
|
73
|
+
## 验收口径(H5 webview 项目)
|
|
350
74
|
|
|
351
|
-
|
|
352
|
-
vision_defect_check({ imagePath: "渲染页截图.png", language: "zh-CN" })
|
|
353
|
-
lanhu_verify_render({ actualImagePath: "渲染页.png", designImagePath: "设计稿.png" })
|
|
354
|
-
vision_e2e_triage({ screenshotPath: "失败截图.png", domSnapshot: "<DOM>", errorText: "<报错>" })
|
|
355
|
-
```
|
|
75
|
+
`lanhu_verify_spec` 验收 webview 内嵌页时,以下差异属预期,会自动降级:
|
|
356
76
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
| `mock` | 内置示例图层树 | 无 |
|
|
363
|
-
|
|
364
|
-
官方 `api` 模式直调蓝湖数据接口拿 `detail.url` 封面图(完整设计稿截图)+ 标注 JSON,
|
|
365
|
-
不走前端渲染画布,稳、快、准。已移除 `scrape`(playwright 爬取)模式——蓝湖前端鉴权 + 阿里云风控
|
|
366
|
-
让浏览器拦截路径不可靠,官方 API 才是正路。
|
|
77
|
+
- **宽度严格、高度宽松**:`x` / 非文本层 `width` 严比;`y` / `height` 因状态栏与动态渲染整体偏移,降 `minor`;
|
|
78
|
+
- **状态栏不渲染**:稿顶状态栏层比对前剔除,整体竖直偏移记入 `offset`,不报缺陷;
|
|
79
|
+
- **文案语义接近即可**:文本差异降 `minor`;配视觉模型时做语义等价判定,确为不同含义才升 `major`;
|
|
80
|
+
- **前置去噪**:`opacity=0`、零尺寸、蒙版/标注/备份组、占位切图等无效层不参与比对;
|
|
81
|
+
- **背景回退**:叶子节点背景透明时向上回退 3 级祖先背景色,未命中封顶 `major`。
|
|
367
82
|
|
|
368
83
|
## 环境变量
|
|
369
84
|
|
|
370
85
|
| 变量 | 必填 | 默认 | 说明 |
|
|
371
86
|
|---|---|---|---|
|
|
372
|
-
| `VLM_API_KEY` | analyze/验收时必填 | — | 视觉模型 Key |
|
|
373
|
-
| `VLM_BASE_URL` | 否 | `https://api.deepseek.com` |
|
|
87
|
+
| `VLM_API_KEY` | analyze/验收时必填 | — | 视觉模型 Key(须为对应平台签发,如 api.deepseek.com 需 DeepSeek key) |
|
|
88
|
+
| `VLM_BASE_URL` | 否 | `https://api.deepseek.com` | 任意 OpenAI 兼容端点 |
|
|
374
89
|
| `VLM_MODEL` | 否 | `deepseek-v4-flash-vision-exp` | 视觉模型名 |
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
377
|
-
| `LANHU_VISION_MAX_EDGE` | 否 | `1568` |
|
|
378
|
-
| `LANHU_VISION_CACHE` | 否 | `1` | 设 `0` 关闭视觉结果缓存(`LANHU_VISION_CACHE_DIR`
|
|
379
|
-
| `
|
|
380
|
-
| `VISION_USE_V1` | 否 | — |
|
|
381
|
-
| `
|
|
382
|
-
| `
|
|
383
|
-
| `
|
|
384
|
-
| `
|
|
385
|
-
| `
|
|
386
|
-
| `
|
|
387
|
-
| `
|
|
90
|
+
| `LANHU_VISION_MAX_TOKENS` | 否 | `8192` | 输出上限(GLM 系模型因 thinking 计入预算,分支内默认 `16384`;设太小 JSON 会被半截截断) |
|
|
91
|
+
| `LANHU_VISION_TIMEOUT_MS` | 否 | `120000` | 单次视觉请求超时(毫秒) |
|
|
92
|
+
| `LANHU_VISION_MAX_EDGE` | 否 | `1568` | 入参图压缩最长边 |
|
|
93
|
+
| `LANHU_VISION_CACHE` | 否 | `1` | 设 `0` 关闭视觉结果缓存(`LANHU_VISION_CACHE_DIR` 可改目录) |
|
|
94
|
+
| `LANHU_AUTO_ANALYZE` | 否 | — | 设 `0` 关闭 fetch_design 自动视觉分析(视觉模型配齐时默认自动开) |
|
|
95
|
+
| `VISION_USE_V1` | 否 | — | 设 `0` 切到端点原生 `/chat/completions` |
|
|
96
|
+
| `LANHU_COOKIE` | api 模式必填(与 `LANHU_COOKIE_FILE` 二选一) | — | 蓝湖 Cookie 串(F12 复制) |
|
|
97
|
+
| `LANHU_COOKIE_FILE` | 同上 | — | cookie 文件路径;`lanhu-login.bat` 续期时自动写入 |
|
|
98
|
+
| `LANHU_MOCK` | 否 | — | 设 `1` 时 fetch_design 返回内置示例(无需联网) |
|
|
99
|
+
| `LANHU_SLICE_CONCURRENCY` | 否 | `6` | 切图下载并发数 |
|
|
100
|
+
| `LANHU_ALLOWED_ASSET_HOSTS` | 否 | — | 切图主机白名单追加项(逗号分隔),默认仅放行蓝湖/阿里云系 |
|
|
101
|
+
| `LANHU_MIN_VISIBLE_FRACTION` | 否 | `0.25` | 出画窄条剔除阈值,设 `0` 关闭 |
|
|
102
|
+
| `LANHU_PRUNE_OCCLUDED` | 否 | `1` | 设 `0` 关闭遮挡剔除 |
|
|
103
|
+
| `LANHU_PRUNE_FRAGMENTS` | 否 | `1` | 设 `0` 关闭碎片装饰带剔除 |
|
|
388
104
|
|
|
389
105
|
> cookie 解析优先级:**工具入参 `cookie` > 环境变量 `LANHU_COOKIE` > 文件 `LANHU_COOKIE_FILE`**。
|
|
390
|
-
> ⚠️
|
|
391
|
-
|
|
392
|
-
## DeepSeek 视觉接入规范(已对齐)
|
|
393
|
-
|
|
394
|
-
按 [图像理解](https://api-docs.deepseek.com/zh-cn/guides/vision) 与 [JSON Output](https://api-docs.deepseek.com/zh-cn/guides/json_mode) 文档实现:
|
|
395
|
-
|
|
396
|
-
| 规范要求 | 实现 |
|
|
397
|
-
|---|---|
|
|
398
|
-
| 模型名 `deepseek-v4-flash-vision-exp`(唯一支持图片的实验模型) | 默认模型名;其它模型传图会 400 |
|
|
399
|
-
| 图片只能出现在 `user` 消息 | 只发 `user` 消息,`image_url` 块、`detail` 放在 `image_url` 对象内 |
|
|
400
|
-
| 单图 ≤ 32 MiB、请求体 ≤ 48 MiB | 发请求前按 base64 长度预估拦截,超限直接报可读错误(不浪费一次调用) |
|
|
401
|
-
| JSON Output 要求 prompt 含小写 `json` 字样 + 给出 JSON 样例 | `callVision` 自动校验并补齐;四个工具的 prompt 都自带 JSON 结构样例 |
|
|
402
|
-
| JSON Output 必须设 `max_tokens` 防截断 | 默认 4096,`LANHU_VISION_MAX_TOKENS` 可调 |
|
|
403
|
-
| JSON Output 有概率返回空 content(官方已知问题) | 最多 3 次尝试 + 退避重试 |
|
|
404
|
-
| 图片进模型前被缩到约 800×800 等效像素、每张封顶 384 token | 送图前先压到 `LANHU_VISION_MAX_EDGE`(默认 1568,DeepSeek 场景建议 1024) |
|
|
405
|
-
|
|
406
|
-
两个自适应降级(避免实验性模型/代理差异直接把调用打死):
|
|
407
|
-
|
|
408
|
-
- HTTP 404 → 自动在 `/v1/chat/completions` 与 `/chat/completions` 之间切换一次;
|
|
409
|
-
- HTTP 400 且错误指向 `response_format` → 剥掉 JSON Output,退回纯提示词约束再解析。
|
|
106
|
+
> ⚠️ 若设过 `LANHU_COOKIE` 环境变量,它会压制文件内容——登录脚本续期后新 cookie 写入了文件,但旧环境变量仍生效,会持续 401;需删除/更新该环境变量。
|
|
410
107
|
|
|
411
|
-
|
|
108
|
+
## 部署
|
|
412
109
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
npm run typecheck # tsc --noEmit,类型检查
|
|
417
|
-
npm run dev # tsx 直接跑 src/index.ts(开发模式,无需先 build)
|
|
418
|
-
npm run build # tsc 编译到 dist/
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
## 三种部署 / 分发方式
|
|
422
|
-
|
|
423
|
-
### 方式 A:拷贝即用(最简单,推荐给同事)
|
|
424
|
-
把整个 `lanhu-design-mcp/` 目录发给对方,对方 `npm install && npm run build` 后,
|
|
425
|
-
用绝对或相对路径指到 `dist/index.js` 即可。
|
|
426
|
-
|
|
427
|
-
### 方式 B:npm 全局安装 / npx
|
|
428
|
-
```bash
|
|
429
|
-
npm i -g lanhu-design-mcp # 发布后;或本地:npm link
|
|
430
|
-
lanhu-design-mcp # 等价于 node dist/index.js
|
|
431
|
-
# 或一次性:npx -p lanhu-design-mcp lanhu-design-mcp
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### 方式 C:Docker(团队统一运行时,可选)
|
|
435
|
-
```dockerfile
|
|
436
|
-
FROM node:18-alpine
|
|
437
|
-
WORKDIR /app
|
|
438
|
-
COPY . .
|
|
439
|
-
RUN npm install && npm run build
|
|
440
|
-
CMD ["node", "dist/index.js"]
|
|
441
|
-
```
|
|
442
|
-
构建:`docker build -t lanhu-design-mcp .`,运行时通过 `-e VLM_API_KEY=...` 注入密钥。
|
|
443
|
-
|
|
444
|
-
## 接入各 coding Agent
|
|
445
|
-
|
|
446
|
-
所有 Agent 都接受同一份 MCP 配置。把上面「快速开始」的 `.mcp.json` 内容写进项目根
|
|
447
|
-
(Claude Code / Cursor / Trae / opencode 通用;Cursor 用 `.cursor/mcp.json`,opencode 用
|
|
448
|
-
`.opencode/mcp.json`,字段一致)。
|
|
449
|
-
|
|
450
|
-
- **Claude Code**:`~/.claude.json` 或项目 `.mcp.json`;可用 `settings.json` 的
|
|
451
|
-
`PostToolUse` Hook 做到"改完 `.vue` 自动截屏 → `vision_defect_check` 验收"。
|
|
452
|
-
- **opencode**:`.opencode/mcp.json` + `hooks` 同样支持自动验收闭环。
|
|
453
|
-
- **Cursor**:`.cursor/mcp.json`;无原生 Hook,靠 `Rules`(`.cursor/rules`)让 Agent
|
|
454
|
-
主动调工具,验收门禁放 CI 更稳。
|
|
455
|
-
- **Trae**:`.trae/mcp.json`;无原生 Hook,靠 `AGENTS`/规则 + SOLO 模式驱动。
|
|
456
|
-
|
|
457
|
-
## 给 Agent 的提示词骨架(建议写进 CLAUDE.md / AGENTS.md)
|
|
458
|
-
|
|
459
|
-
```
|
|
460
|
-
你可用 lanhu-vision MCP:
|
|
461
|
-
0. 多团队先 `lanhu_list_teams` 列出账号加入的全部团队,拿 `teamId`;单团队可跳过直接进 1。
|
|
462
|
-
1. 不知道蓝湖链接时,lanhu_list_directory 一次拉全团队目录(项目→分组),
|
|
463
|
-
在里面按分组名匹配用户说的活动 → 拿到 projectId 传给 lanhu_read_sector。
|
|
464
|
-
没匹配则如实回答未找到或问用户。无需让用户补链接,无需自己下钻。
|
|
465
|
-
2. 有链接或项目 UUID 时,lanhu_read_sector({url: 链接或UUID, sector: 分组名}) 看该分组的稿目录(稿名/尺寸/层数,不含图层树),按稿名挑出要实现的目标。
|
|
466
|
-
3. 实现单个 UI 前用 lanhu_fetch_design 逐张读目标稿的结构化图层树(一次只读当前要实现的那 1 张,不要批量读;色值/字号从数据取,不要靠截图 OCR 小字);
|
|
467
|
-
配了视觉模型时会自带 visionAnalysis(版面/组件的文字理解),想省掉这次视觉调用就传 analyze:false。
|
|
468
|
-
4. 需要切图素材时 lanhu_download_slices 下载到项目 assets 目录,代码里引用返回的 file 路径。
|
|
469
|
-
5. 实现后把渲染页截图传给 lanhu_verify_render 做对比,或 vision_defect_check 做缺陷检测。
|
|
470
|
-
6. E2E 失败时把截图+DOM 传给 vision_e2e_triage 拿根因。
|
|
471
|
-
7. 任何蓝湖工具报 HTTP 401 或返回异常空数据时,先调 lanhu_check_auth 探活:
|
|
472
|
-
- ok:true → cookie 有效,是那个资源无权访问,提示用户联系设计者开权限(不要让用户重新登录)。
|
|
473
|
-
- ok:false(reason=cookie_expired) → 真过期,提示用户双击 `lanhu-login.bat` 或跑 npm run login 续期,完成后重试。
|
|
474
|
-
- ok:false(reason=network_error) → 网络问题,稍后重试。
|
|
475
|
-
不要在没探活前就断定 cookie 过期——单资源 401 多半是权限问题,重新登录无效。
|
|
476
|
-
视觉模型的结论只当线索,涉及钱/权限/用户数据的流程必须人审。
|
|
477
|
-
```
|
|
110
|
+
- **拷贝即用**:整个目录发给对方,`npm install && npm run build` 后指向 `dist/index.js`;
|
|
111
|
+
- **npm**:`npm i -g lanhu-design-mcp`,或一次性 `npx -y lanhu-design-mcp`;
|
|
112
|
+
- **Docker**:`node:18-alpine` 内 build,运行时 `-e` 注入密钥。
|
|
478
113
|
|
|
479
114
|
## 红线(务必遵守)
|
|
480
115
|
|
|
481
|
-
-
|
|
482
|
-
-
|
|
483
|
-
|
|
484
|
-
- 视觉模型判断只当线索;**钱 / 权限 / 用户数据相关流程必须人审或留 fallback**。
|
|
116
|
+
- **蓝湖小字(色值、字号、间距)只从 `lanhu_fetch_design` 结构化数据取,绝不靠视觉模型 OCR 截图**——图片压缩后 10px 小字/密集文本必读错;
|
|
117
|
+
- 视觉模型结论只当线索;**钱 / 权限 / 用户数据相关流程必须人审**;
|
|
118
|
+
- 没调 `lanhu_check_auth` 探活前不断定 cookie 过期——单资源 401 多半是权限问题,重新登录无效。
|