Repository navigation
0.2.0
补齐了产品文档(PRD / Axure 原型)读取 —— 这是此前完全缺失的一块;另外把「代码对应的是哪一版设计稿」变成可查的事实,
并吸收了一个社区第三方项目的几段干净算法。原有 13 个工具的调用方式与返回字段都没变(新增字段一律是增量的)。
新增功能
读产品文档(PRD / 原型)—— 以前完全没有
- 新工具
lanhu_list_product_documents:列项目下的原型文档(docId / 名称 / 更新时间 / 最新版本 / 版本数 / 是否已被替换),
并附上项目名与文件夹。 - 新工具
lanhu_read_product_doc:页面树(层级 / path / 类型 / pageId)+ 指定页的正文。 - 实测某份早期项目的原型:219 个页面节点 / 183 个可读页 / 102 个版本,正文取到 35 条真实业务规则。
- 两个工具的描述都点明「这是产品文档,不是设计稿」,并与设计稿工具互相指路 —— 拿错工具的代价是白跑一次。
固定版本读取
lanhu_read_design/lanhu_read_blocks/lanhu_read_product_doc/lanhu_download_slices新增version参数。- 返回里新增
version字段(id / requested / isLatest / count / latestId / latestAt)。 - 传了具体版本而命中不了 → 明确报
VERSION_NOT_FOUND并列出可选 id,绝不静默回退到 latest。
(此前每次都读当前版本:设计稿一更新,代码与稿子就不是同一版了,而且你不会知道。)
字体需求清单(lanhu_read_design 的 format: "fonts")
- 把所有文本层按字体族聚合:字重、字号、文本层数、样例图层 id。照着这张表装字体 —— 漏装就是整页回退到系统字体。
可用性一律是not_checked:本插件不检测本机字体,不假装校验过。
几何间距(区域模式下输出)
- 只在另一轴有重叠的相邻元素之间算最近边距,x/y 各自独立,每个节点每个方向只留最近一条。
- 输出带
fromName/toName/ 重叠区间,可直接抄进 CSS —— 替代「拿相邻块坐标相减」的手工做法。
docId 失效后自动找回
- 原型被重新上传后旧 docId 会报
code=10009。现在自动用product_documents找回当前有效文档:
只有一份就直接用;多份则按pageId跨版本稳定这一特性消歧;仍定不下来就报错并列出全部候选。
DDS 结构数据(可选增强,默认关闭)
lanhu_read_design新增dds: true开关,尝试取设计稿的 DDS schema。⚠️ 这是社区实测的非官方通道(独立域名 + 独立 Cookie),随时可能失效,因此默认关、
失败只在结果里如实说明,不影响常规解析。本版实测 4 张稿都是code=10011,成功路径未获证实。
体验优化
- 网络层重试:蓝湖域名偶发超时,现在只对网络失败重试 3 次;HTTP 4xx/5xx 与业务 code 一律不重试
(否则会把「登录失效」拖成三次慢失败)。 - 拿错工具会明确报错:用设计稿解析器读原型会报
PROTOTYPE_NOT_DESIGN(反向报DESIGN_NOT_PROTOTYPE)并指路 ——
此前它会静默返回「1 层」垃圾。 - 自检从 257 项扩到 454 项,并新增两条通用绊线:
① 每个工具、每个声明参数都必须真的传给实现(83 个参数逐个查源码区间);
② README / 文档里写死的数字(工具数、自检项数)必须与真实值一致 —— 这类数字以前只会悄悄过期。 - CLI 与工具两条路对齐:新增同名命令
product-docs/product-doc与--version。
问题修复
lanhu_cookie_set传account会被静默忽略:account是给所有工具统一注入的参数,很容易被当成"支持指定账号",
结果是覆盖了默认账号的 Cookie。现在给了account就写进该账号(~/.dsh/lanhu/cookies/<alias>),
账号不存在则明确报错,绝不静默落到默认文件。- 切图的
densityLimited恒定给[]:而"一张都没配上"时它会被读成**"全部达标"**,正好是反的。
现在null= 一张都没评估,[]= 评估过且都达标。 - 区域模式的间距恒为 0 条:过滤默认值与
renderRegion不一致(只给y0,y1时x0/x1是 undefined),
会把所有元素滤掉 —— 看着像"这里确实没间距"。 - docId 消歧一度被新加的守卫打死:循环里逐个试读时吃了报错又被
catch吞掉,导致恒不命中且不报错。 - 间距列表出现「自己到自己、间距 0」:Figma 导出的 id 会重复,已补名字并剔除完全重合的重复层。
其他变更
- 工具数 13 → 15;README 的工具说明块由
tools/gen-readme-tools.mjs从代码重新生成。 - 新增文档
docs/产品文档.md(PRD 读取的用法与边界)。 - 思路吸收自社区第三方项目
dsphper/lanhu-mcp(MIT)——
独立实现,未逐行搬代码。 - 关于切图密度:实现了判定逻辑,但本通道的
tree.assets是裸 URL 数组(没有render_bounds),
实测 12 张切图配到 0 张,因此目前只输出null与原因,不产出错误的密度值;要真正用上需先有该字段。
Full Changelog: v0.1.1...v0.2.0
New Features
Reading product documents (PRD / Axure prototypes) — previously not supported at all
- New tool
lanhu_list_product_documents: lists a project's prototype documents (docId, name, updated time, latest
version, version count, whether it has been replaced), together with the project and folder names. - New tool
lanhu_read_product_doc: the page tree (level / path / type / pageId) plus the body text of one page. - Measured on a real early-stage project: 219 page nodes / 183 readable pages / 102 versions, 35 real business
rules extracted from a single page. - Both descriptions state plainly that this is a product document, not a design and point at the design tools
(and vice versa) — picking the wrong tool costs a wasted round trip.
Pinned version reads
versionadded tolanhu_read_design/lanhu_read_blocks/lanhu_read_product_doc/lanhu_download_slices.- Results now carry a
versionfield (id / requested / isLatest / count / latestId / latestAt). - An unknown version raises
VERSION_NOT_FOUNDwith the available ids listed — it never silently falls back to
latest. Previously every call read the current version, so once a design was updated your code and the artboard
were no longer the same revision, and nothing told you.
Font requirements (format: "fonts" on lanhu_read_design)
- Aggregates every text layer by font family: weights, sizes, text-layer count and sample layer ids.
Install exactly these fonts — a missing one makes the whole page fall back to a system font. availabilityis alwaysnot_checked: the plugin does not inspect local fonts and does not pretend to.
Geometric gaps (emitted in region mode)
- Measures the nearest edge distance between adjacent elements, per axis, and only when they overlap on the other
axis. One nearest gap per node per direction. - Output includes
fromName/toName/ the overlap span, so values can be copied straight into CSS — replacing the
manual "subtract the coordinates of two neighbouring blocks" routine.
Recovering a stale docId automatically
- After a prototype is re-uploaded, the old docId returns
code=10009. The plugin now looks the current document up
throughproduct_documents: a single candidate is used directly; several are disambiguated by the fact that
pageIdis stable across versions; if it still cannot decide, it fails and lists every candidate.
DDS structured data (optional, off by default)
lanhu_read_designgained adds: trueswitch.- This is a community-discovered, non-official channel (separate domain, separate cookie) that can disappear at
any time, so it is off by default, failures are reported honestly and never affect normal parsing.
All four artboards tried in this release returnedcode=10011, so the success path remains unproven.
Improvements
- Network-level retry: the Lanhu domain times out intermittently. Only network failures are retried (3 attempts);
HTTP 4xx/5xx and business error codes are not (retrying those would stretch a dead session into three slow failures). - Wrong-tool mistakes now fail loudly: feeding a prototype to the design parser raises
PROTOTYPE_NOT_DESIGN
(andDESIGN_NOT_PROTOTYPEthe other way) with a pointer to the right tool. It used to silently return "1 layer" of
garbage. - Self-check grew from 257 to 454 assertions, including two new general tripwires:
① every declared parameter of every tool must actually reach the implementation (83 parameters checked against the
source region); ② hard-coded figures in the README and docs (tool count, assertion count) must match reality —
these used to rot silently. - The CLI and the tool path are aligned: new
product-docs/product-doccommands and a--versionflag.
Bug Fixes
lanhu_cookie_setsilently ignoredaccount:accountis injected into every tool's schema, so it is easy to
assume this one supports it — the result was that the default account's cookie got overwritten. Passing
accountnow writes to that account (~/.dsh/lanhu/cookies/<alias>), and an unknown alias fails loudly instead of
falling back to the default file.densityLimitedwas always[]: when nothing at all could be evaluated, that read as "everything is good
enough" — the exact opposite of the truth. Nownull= nothing evaluated,[]= evaluated and all fine.- Region-mode gaps were always empty: the filter defaults disagreed with
renderRegion(with onlyy0,y1the
x0/x1bounds were undefined and filtered every element out), so it looked like "there really are no gaps here". - Candidate disambiguation was killed by a new guard: the retry loop swallowed the error and gave up silently,
so it never matched and never reported. - Gap output contained "self to self, distance 0": Figma-exported ids repeat; names were added and fully
coincident duplicates are now dropped.
Chores
- Tool count 13 → 15; the README's tool reference is regenerated from
TOOLSbytools/gen-readme-tools.mjs. - New
docs/产品文档.md(usage and limits of PRD reading). - Ideas absorbed from the community project
dsphper/lanhu-mcp(MIT) —
independently implemented, no code copied line by line. - On slice density: the evaluation logic exists, but this channel's
tree.assetsis a bare array of URLs (no
render_bounds); 12 slices matched 0 layers in practice, therefore onlynullplus a reason is emitted rather
than a wrong density value. It needs that field before it can do real work.
Full Changelog: v0.1.1...v0.2.0