Repository navigation
Releases: LoktLin/dsh-lanhu
Release list
v0.6.1
更新说明 · v0.6.1
「体检」Tab 的小改进:选稿时就能看出哪张稿值得点。
新增功能
- 「体检」Tab 的「稿」下拉现在标出每张稿有几个版本**(
名称(6 版))。
只有 1 个版本的稿会置灰、不可选,并写明"只有 1 个版本,没有可对比的" —— 以前选完项目后
无从判断哪张稿能对比,只能一张张试。 - 版本数是分批按需读取的:选中项目(或贴链接定位)后先读前 30 张,
下拉下方有进度与「继续加载」;每张稿 1 次请求,已读过的不重复读。 - 读不到版本数的稿照常可选(标"版本数未知"),不因为一次探测失败把稿禁用。
升级注意
- 工具、返回值与既有面板行为均无变化 —— 本版只新增面板的一处显示与一个新端点。
- 新增 Host 端点
GET /lanhu/versions-count?pid=&offset=&limit=(默认 30 张、上限 100)。
既有端点与所有工具输出与 v0.6.0 一致(逐字节比对过)。
问题修复
无。
Full Changelog: v0.6.0...v0.6.1
New Features
- The "Design" dropdown in the Checkup tab now shows how many versions each design has (
Name (6 versions)).
Designs with only one version are greyed out and cannot be selected, with the reason stated — previously, after
picking a project there was no way to tell which design was worth comparing. - Version counts are read in batches on demand: after selecting a project (or resolving a pasted link) the first 30 are
read, with a progress line and a "load more" button; one request per design, and nothing is read twice. - Designs whose count could not be read stay selectable (marked "count unknown") — a failed probe never disables a design.
Upgrade Notes
- Tools, return values and existing panel behaviour are unchanged — this release only adds one panel display and one endpoint.
- New host endpoint
GET /lanhu/versions-count?pid=&offset=&limit=(default 30, cap 100). Existing endpoints and all tool
output are identical to v0.6.0 (verified byte for byte).
Bug Fixes
None.
Full Changelog: v0.6.0...v0.6.1
v0.6.0
更新说明 · v0.6.0
本版新增一个面板 Tab 「体检」、两个工具,以及一项读取能力修复(Sketch 插件格式的稿子以前读不出来)。
新增功能
- 面板新增「体检」Tab —— 两个项目级功能,不用记命令:
- 变更:选一张稿、选两个版本 → 显示"这次设计改了什么"(尺寸/圆角/颜色/布局/文字/增删)。
- 一致性:扫一个项目的多张稿 → 报告设计系统漂移(同一组件多种规格、字号阶梯、色值近重复、间距、圆角)。
- 两者都是耗时操作:运行时按钮禁用并显示进度,可取消。扫描张数默认 20、硬上限 200,界面会写明"本次约 N 次请求"。
- 新工具
lanhu_diff_design—— 同一张稿两个版本的变更对比(蓝湖自身不提供版本对比)。
报告的匹配可靠度是明确的:大面积对不上时会明说"逐块对比不可靠"并拒绝出明细,而不是给你一张看着精确的表。 - 新工具
lanhu_audit_project—— 跨稿一致性审计。判据是"层名归一化后相同";
工具默认名(如Rectangle 12)一律不认并计入"未参与",命名覆盖率一并报出;命名不可靠或样本太少时拒绝出明细。 lanhu_read_blocks新增「对比度」段落 —— 文字色与其有效背景的 WCAG 对比度。
有效背景沿祖先链找最近的填充;半透明逐层合成;算不出时明说"未做对比度判断",不会假定白底。
判据:正文 ≥4.5:1、大号文字 ≥3:1;不达标会给可直接抄的色值建议。- 面板标题栏显示当前版本,npm 上有新版时多一个小圆点。
升级注意
⚠️ Sketch 插件格式(type: sketchPlugin)的稿子,输出会变 —— 以前它们返回
「共 1 块:画板 1」+ 空表(一个块都没解析出来),现在能正常解析。某项目实测 11/20 是这种格式,
例如那张稿从 1 块 → 37 块、画板尺寸从缩略图480×270→ 真实1920×1080。
如果你的流程里对这类稿做过"空稿"处理,请重新检查。lanhu_read_blocks的返回新增字段:version/versionIsLatest/latestVersionAt/contrast;
非 Figma 格式还会带sourceFormat。普通稿的返回与文本输出逐字节不变。- 读不出图层时,返回带机器可读标志:
unsupported: true+sourceFormat+code,且文本会说明
**"本次输出是空的,但不代表这张稿是空的"**与下一步 —— 不再有"看着成功其实什么都没干"的情况。 - 工具数 15 → 17。
问题修复
- Sketch 插件格式静默失败:
info[]里的图层以前完全没被解析,却返回成功形态。
现在按实测映射规则归一化后走同一条解析链(坐标/尺寸/圆角/颜色/渐变/边框/字体/切图),
与 Figma 稿共用同一套块模型。
其他变更
- 面板 Tab 名「登录态」与代码统一为「账号」。
- 新增文档:
docs/设计变更.md、docs/设计系统审计.md;docs/读稿.md增加「支持与不支持的稿件格式」。
Full Changelog: v0.5.4...v0.6.0
New Features
- New "Checkup" tab in the panel — two project-level features without memorising commands:
- Changes: pick a design and two versions → see what the design update changed (size/radius/colour/layout/text/additions/removals).
- Consistency: scan a project's designs → report design-system drift (one component with several specs, font-size ladder,
near-duplicate colours, spacing, radii). - Both are long-running: buttons disable with a progress line, and they can be cancelled. Scans default to 20 designs
with a hard cap of 200, and the UI states "about N requests this run".
- New tool
lanhu_diff_design— compare two versions of one design (Lanhu itself offers no version comparison).
Match reliability is stated explicitly: when large parts fail to match it says "block-level comparison is unreliable"
and refuses to print a detail table rather than producing a precise-looking one. - New tool
lanhu_audit_project— cross-design consistency audit. The criterion is "layer name equal after
normalisation"; tool-generated names (e.g.Rectangle 12) are never accepted and are counted as "not participating",
with naming coverage reported. When naming is unreliable or the sample is too small, no details are printed. lanhu_read_blocksgains a "Contrast" section — WCAG contrast between text colour and its effective background.
The background is found by walking up the ancestor chain to the nearest fill; translucency is composited layer by layer;
when it cannot be determined the output says "not judged" instead of assuming white.
Thresholds: body ≥4.5:1, large text ≥3:1, with ready-to-copy colour suggestions.- The panel title bar shows the current version, with a dot when npm has a newer one.
Upgrade Notes
⚠️ Output for Sketch-plugin designs (type: sketchPlugin) changes — they used to return
"1 block: artboard 1" with an empty table (nothing was parsed at all). They now parse normally. In one project
11 of 20 sampled designs were this format; a given design went from 1 block to 37, and the artboard size from the
thumbnail's480×270to the real1920×1080. If your pipeline treated these as empty designs, re-check it.lanhu_read_blocksreturns new fields:version/versionIsLatest/latestVersionAt/contrast, plus
sourceFormatfor non-Figma formats. Output for ordinary designs is byte-for-byte unchanged.- When layers cannot be read, the return carries machine-readable flags (
unsupported: true,sourceFormat,code) and the
text states "this output is empty, but that does not mean the design is empty" with a next step — no more
"looks successful but did nothing". - Tool count 15 → 17.
Bug Fixes
- Silent failure on Sketch-plugin designs: layers inside
info[]were never parsed, yet the call reported success.
They are now normalised and go through the same parsing chain (position/size/radius/colour/gradient/border/font/slices),
sharing one block model with Figma designs.
Chores
- The panel tab previously called "login state" is now "Accounts", matching the code.
- New docs:
docs/设计变更.md,docs/设计系统审计.md;docs/读稿.mdgains a "supported and unsupported design formats" section.
Full Changelog: v0.5.4...v0.6.0
v0.5.4
更新说明 · v0.5.3 → v0.5.4
新增功能
无新增功能。
升级注意
⚠️ 所有工具的返回值现在都带ok。此前lanhu_list_teams/lanhu_list_designs/lanhu_read_design三个工具
没有ok字段,只能靠别的字段推断成败。如果你的代码用ok判断成功与否,这三个工具以前拿到的是undefined。- npm 包不再包含
CHANGELOG.md(v0.5.4 起)。版本历史改由 git 与 Releases 承载;docs/与README.md照常随包发布。 - 工具的入参、返回字段语义、输出文本与 v0.5.2 一致 —— 除下面两条修复外没有行为变化。
问题修复
- 返回信封不完整:
lanhu_list_teams、lanhu_list_designs、lanhu_read_design的返回缺少ok字段。
现在在工具成功出口统一补齐 —— 全部 15 个工具都保证返回ok。 - 失败只说原因、不说下一步:
- id 格式错误(如
imageId: 'not-a-uuid')以前把上游的code=10009:Image not exist直接抛给调用方;
现在在本地就拦下,并给出可执行的下一步(例如"先用lanhu_list_designs取一个 imageId")。 - 参数不符合 schema(缺必填、类型错)以前只说"字段不合法";现在会指出怎么补齐。
- 上游错误仍原文透传,不改写、不吞 —— 只是在
hint字段里补一句"这通常意味着什么、可以先做什么"。
- id 格式错误(如
其他变更
- 内部重构:块类型、颜色角色、输出上限等改为集中的冻结常量,
classifyBlock只引用常量。工具可观测行为不受影响。 - README:删去自测项数等维护者指标;把无法验证的断言改为可验证的说法("由 schema 生成,改代码时会跟着变");
版本链接改指 Releases(不再引用CHANGELOG.md)。
Full Changelog: v0.5.2...v0.5.4
New Features
None.
Upgrade Notes
⚠️ Every tool now returnsok. Previouslylanhu_list_teams/lanhu_list_designs/lanhu_read_designreturned no
okfield and success had to be inferred from other fields. Code branching onokreceivedundefinedfrom these three.- The npm package no longer ships
CHANGELOG.md(as of v0.5.4). Version history lives in git and in Releases;docs/
andREADME.mdare still published with the package. - Parameters, return-field semantics and output text are unchanged from v0.5.2 apart from the two fixes below.
Bug Fixes
- Incomplete response envelope:
lanhu_list_teams,lanhu_list_designsandlanhu_read_designreturned nookfield.
This is now guaranteed at the tool success exit — all 15 tools always returnok. - Failures stated the cause but offered no next step:
- A malformed id (e.g.
imageId: 'not-a-uuid') used to surface the upstreamcode=10009:Image not exist. It is now
caught locally and reports an actionable next step (for example, "get an imageId fromlanhu_list_designsfirst"). - Schema rejections (missing required, wrong type) used to say only which field was invalid; they now say how to fix it.
- Upstream errors still pass through verbatim — nothing is rewritten or swallowed; a
hintfield explains what it
usually means and what to try first.
- A malformed id (e.g.
Chores
- Internal refactor: block kinds, colour roles and output limits moved into frozen central constants, and
classifyBlock
references them only. Observable tool behaviour is unchanged. - README: removed maintainer-facing counters, replaced unverifiable claims with verifiable wording ("generated from the
schema, so it follows code changes"), and pointed the version link at Releases instead ofCHANGELOG.md.
Full Changelog: v0.5.2...v0.5.4
v0.5.2
更新说明 · v0.4.4 → v0.5.2(汇总)
这一段四个版本此前都没有单独发过 Release,所以这里把它们合成一份。
只想看最新一版 → 直接看 v0.5.2;想知道这段时间到底改了什么 → 往下读。
| 版本 | 一句话 |
|---|---|
| v0.4.4 | 把 README 同步到 npm 页面(补徽章 + 安装方式) |
| v0.5.0 | 注入重写:让 AI「知道该用哪个工具」+ 结果补全(间距表 / 双单位 / rgba) |
| v0.5.1 | 修两处画板坐标系的 bug + 列表尺寸标「预览」 |
| v0.5.2 | 清理公开材料里的真实项目名(行为零变化) |
新增功能
(这一段最有价值的部分,来自 v0.5.0)
SYSTEM_HINT重写(5 行 → 21 行):给 AI 一张工具决策树 ——
还原大块布局 / 对圆角 / 查分割线 →lanhu_read_blocks;要某区域精确数值(含间距)→
region + gapMaxDistance;坐标映射到自绘坐标系 →mapBox/toBox;只要统计 →format=tokens;
改完前端要验收 →lanhu_verify_blocks。
并明确禁掉那条弯路:「别summary不够就转format=full再自己写脚本解析」。
另含换算(rpx = px × 750 ÷ 画板宽,不写死 ×2)、以稿为准(字重 400 就是 400、半透明按 alpha 别换实色、
切图块没有填充也没有圆角但尺寸要还原)、溯源(记 version)、定位(贴整条链接 + 项目档案)。- 「间距一览」段(
read_blocks末尾,可直接抄 CSS):块间最近边距 + 方向(↕/↔),
外加一类**「齐平」**(两条边重合)—— 后者是「说明块底 ≡ 头像底」那种关系,单靠间距给不出。 - 色值直出两种形式:
#574af4@10% (rgba(87, 74, 244, 0.1))—— 原串便于回查 + 可直接粘贴。 - 双单位输出:
120×152px / 240×304rpx,换算比按画板宽度算、表头写明基准。 - 尾注:
≈5.52KB;本稿 21 块+ 一行「下一步该用什么」。 - 标题行带 meta:
# 示例弹窗(375×812) |version=88e0aaa6|更新于 2026-09-17(拿不到就不打,不许编)。
体验优化
list_designs的尺寸标注为「预览」(v0.5.1):列表接口返回的是缩略图尺寸(实测187.5↔ 真实750、
480↔1920,常见 ¼)。插件内部算 rpx 一直用真实画板宽(没错),
但 AI 若拿列表尺寸自己换算会算错比例 —— 而这是实测语料里 77% 的稿都长的样子。
现在三处同时标注:列表行标(预览)+ 工具描述 +SYSTEM_HINT警告。- README 同步到 npm 页面(v0.4.4):22 条文档链接改成 GitHub 绝对地址(相对路径在 npm 上会 404)、
顶部加 npm / 许可 / Node 徽章、files带上docs/与CHANGELOG.md(文档随包走)。 - 间距段的口径(v0.5.0,按省上下文调过并写在表头):封顶 24 行 · 按距离从紧到松排 · 贴边 0px 不计入 ——
否则 610 层的大稿会出 315 条「文字碎片紧挨着」的 0px 行,把真正的竖向节奏挤出前几行。
问题修复
一处病根连续复发 —— 全都出在「坐标系混用」上(v0.5.0 与 v0.5.1):
- ⭐ 画板被当成元素:画板自己进了候选集 → 间距表冒出
12279px的垃圾数字(而该稿画板对角只有几百 px)。 - ⭐ 画板内边距跨坐标系(影响所有画板不在原点的稿):画板自身的
x/y是画布绝对坐标(实测x=14599),
而子层是画板相对坐标(x=0)—— 代码却直接相减,于是深度 1 的层内边距全成了-14599这种数。
修后与独立手算逐位一致(0/287/1705/163)。 - ⭐ 间距一览没排除画板(
depth 0):上一版只挡住了 summary 那条链,renderGapDigest这条漏了 → 在唯一收口处过滤。
代码里留了一句给后来者:「新加几何计算时先问一句:这堆元素的坐标系一致吗?」
另三个真 bug(v0.5.0 / v0.5.1):
- 间距关系被静默丢掉:
geometricGaps的「每方向只留最近一条」是按id做键的 ——
调用方不给 id(或 id 重复,如 Figma 的I37:2804;3)时所有元素挤在同一个键上,
大部分关系被丢掉(4 元素夹具本该 5 条只出 2 条,看着像「这里就这点间距」)。 - 齐平段出现「自己跟自己对齐」:真身是父子(子层是父层的
:shadow、几乎撑满)再叠一层渲染歧义
(名字截到 22 字后两个元素撞成同一前缀)→ 新增sameElement()/isAncestor()排除 + 显示名去歧义。
11 条噪声 → 6 条真关系。 - 更新时间是 RFC-2822 原文(
Thu, 17 Sep 2026)被切成残句 → 复用现成的parseRfc2822归一。
其他变更
- 验证方式(这一段的做法):① 全量真机覆盖 —— 6 团队 / 31 项目 / 1437 张设计稿 / 12 份原型;
② 修复后做了全量回归 —— 同一批稿重跑(1219 张对账),那条gap>diag(5987>551)消失、0 新增异常;
③ 三项此前未闭环的验证补齐(真机证据):region双单位在 w=1920/750/375 上给出 ×0.39 / 1:1 / ×2、
找到了原生「无填充无圆角切图块」并带反证、齐平段独立复算 漏报 0 / 多报 0。 - 自检 611 → 663 项;文档绊线 76 → 103 项(后者新增「发布说明中英分段顺序 +
---位置」的结构断言 ——
这条上线后第一条咬到的就是我自己写的错版)。 - v0.5.2 清理公开材料:全量扫期间写进注释 / 发布说明的几个真实项目名换成中性说法
(数值 / 尺寸 / 坐标 / 结论一字未改),并连同 git 历史(提交信息 + 每个提交的 tree)一起清理,
v0.5.0/v0.5.1两个 tag 同步前移。 - 如实记录的未闭环:
read_blocks全量 1437 的收尾;齐平对账样本 3 张偏小。
Full Changelog: v0.4.4...v0.5.2
Update notes · v0.4.4 → v0.5.2 (combined)
None of the four versions in this range ever got its own Release, so they are combined here.
Only interested in the newest? Read v0.5.2. Wondering what actually changed? Keep reading.
| Version | In one line |
|---|---|
| v0.4.4 | Synced the README to the npm page (badges + install instructions) |
| v0.5.0 | Injection rewritten so an AI knows which tool to reach for, plus result completion (spacing table / dual units / rgba) |
| v0.5.1 | Fixed two artboard coordinate-system bugs and labelled list sizes as "preview" |
| v0.5.2 | Removed real project names from public materials (zero behaviour change) |
New Features
What v0.5.0 brought — the most valuable part of this range:
SYSTEM_HINTrewritten (5 lines → 21): a tool decision tree — block layout / radii / dividers →
lanhu_read_blocks; a region's precise numbers (including spacing) →region + gapMaxDistance; mapping artboard
coordinates into your own system →mapBox/toBox; statistics only →format=tokens; acceptance after coding →
lanhu_verify_blocks. It also explicitly forbids the old detour: "do not fall back toformat=fulland write your
own parser." Plus unit conversion (rpx = px × 750 ÷ artboard width, never a hardcoded ×2),
follow the artboard (weight 400 is 400, keep the alpha instead of a similar solid, image blocks have neither fill
nor radius but their size still matters), provenance (recordversion) and locating (paste the whole link).- A "spacing at a glance" section (appended to
read_blocks, ready for CSS): nearest edge distance and direction
(↕/↔), plus a "flush" category (two edges coinciding) that spacing alone cannot express. - Colours in both forms:
#574af4@10% (rgba(87, 74, 244, 0.1)). - Dual units:
120×152px / 240×304rpx, derived from the artboard width with the basis stated in the header. - Footer:
≈5.52KB;本稿 21 块plus a one-line "what to use next". - Title line carries meta:
# 示例弹窗(375×812) |version=88e0aaa6|更新于 2026-09-17(omitted, never invented, when unavailable).
Improvements
list_designslabels its sizes "preview" (v0.5.1): the list endpoint returns thumbnail dimensions
(187.5vs a real750,480vs1920— commonly ¼). The plugin has always computed rpx from the real artboard
width (correct), but an AI deriving the ratio from the list would get it wrong — and that is what 77% of the
artboards in the corpus look like. Flagged in three places now.- README synced to the npm page (v0.4.4): 22 documentation links became absolute GitHub URLs (relative ones 404 on
npm), badges added, andfilesnow shipsdocs/andCHANGELOG.md. - Spacing rules (v0.5.0, tuned for context economy and stated in the header): capped at 24 rows · sorted tightest
first · flush (0px) excluded — otherwise a 610-layer artboard emits 315 zero-pixel rows and buries the real rhythm.
Bug Fixes
One root cause, recurring — mixed coordinate systems (v0.5.0 and v0.5.1):
- ⭐ The artboard was treated as an element, entering the candidate set and emitting a
12279pxgarbage distance
where the artboard's diagonal is only a few hundred pixels. - ⭐ Artboard padding spanned two coordinate systems (affects every artboard not at the origin): an artboard's own
x/yare canvas-absolute (measuredx=14599) while its children are artboard-relative (x=0) — yet the code
subtracted them directly, so every depth-1 layer's padding came out as-14599. After the fix it matches an independent
hand calculation digit for digit. - ⭐ The spacing section did not exclude the artboard (
depth 0): the previous version guarded the summary chain but
missedrenderGapDigest→ filtered at its single choke point.
A note was left in the code: "when adding geometry, first ask whether these elements share a coordinate system."
Three more real bugs (v0.5.0 / v0.5.1):
- Spacing relations were silently dropped:
geometricGapskeyed "nearest per direction" byid, so when the caller
supplied no id (or ids collided, e.g. Figma'sI37:2804;3) every element collapsed onto one key and most relations
vanished (a 4-element fixture that should yield 5 relations yielded 2 — it looks like "that is all the spacing there is"). - The flush section paired elements with their own edges: the real cause is parent/child (the child is the
parent's:shadow, nearly filling it) compounded by a rendering ambiguity (names truncated to 22 characters collide
into one prefix) →sameElement()/isAncestor()now run before any comparison, and names are disambiguated.
11 noisy rows → 6 real relations. - The updated-at value is raw RFC-2822 (
Thu, 17 Sep 2026) and was sliced into a fragment → normalised via the
existingparseRfc2822.
Chores
- How this range was verified: ① full real-machine coverage — 6 teams / 31 projects / 1437 artboards /
12 prototypes; ② a full regression after the fixes — the same artboards re-run (1219 reconciled), that
gap>diag(5987>551)anomaly gone with 0 new anomalies; ③ three previously unclosed verifications closed
(with real-machine evidence):regiondual units emit ×0.39 / 1:1 / ×2 on 1920/750/375-wide artboards, the native
"image block with neither fill nor radius" was found with a counter-proof, and the flush section reconciled
0 missed / 0 extra. - Self-check 611 → 663 assertions; doc tripwires 76 → 103 (the latter gained structural assertions for the
release-note halves and the---position — and the first mistake it caught was my own). - v0.5.2 sanitisation: several real project names written into comments and release notes during the sweep were
replaced with neutral wording (every number, dimension and conclusion untouched), and git history was cleaned too
(commit messages and every commit's tree), with thev0.5.0/v0.5.1tags advanced accordingly. - Honestly recorded as still open: the flush reconciliation sample is only 3 artboards; the full 1437-artboard
read_blockssweep w...
v0.4.2
CLI 现在能指定账号了,顺带修掉一个**"看着成功却什么都没干"。
第一条来自 0.4.1 体检时记进「已知空缺」的那条;第二条是补它的时候旁边挖出来的**,而且更糟。
新增功能
- CLI 支持
--account <别名>:目标团队不属于默认账号时给上它。
parseArgv早就把--account解析出来了,但 16 个命令里一个都没往下传(实测改动前 0 个、改动后 13 个)——
于是它们永远走默认账号。现在 13 个命令 / 15 个调用点透传。 - 三个命令不需要它,并且写了理由:
who(职责就是跨账号判定)、accounts(用--alias指定"操作哪个账号",
与"用哪个身份"语义不同)、log(纯本地不走网络)。
体验优化
USAGE写清账号优先级:--cookie>LANHU_COOKIE>--account> 默认账号 ——
也就是显式 cookie 与环境变量会盖过--account。这是在resolveCookie里挖到的,不写出来就是静默意外。docs/CLI与开发.md补了--account与真实例子(那条30005)。
问题修复
--account传下去也没用 → 现在真的有用:示例团队属demo、默认账号是default-acct→
search/projects报code=30005 用户或团队不存在,而同样的入参用工具就正常。
假账号 → 明确报错并列出已知账号,退出码 1,不静默回退默认账号。search的人读输出会丢结果(更糟的一条):cmdSearch原先只遍历r.images,
于是"命中的是 PRD / 项目而不是稿"的搜索变成零输出 + 退出码 0 ——
即本项目最忌讳的**"看着跑成功但什么都没干"。
实测搜「某大屏」命中 2 条 PRD / 0 张稿 → 人读路径什么都不打,而--json里prds:2(数据明明在,只是不打)。
现在三类结果都打** + 一行汇总;三类全空时也明说"没有匹配"。
(工具侧lanhu_search本来就会打 PRD —— 这个 bug 是 CLI 独有的。)
渲染抽成纯函数searchLines(),5 条断言直接测它的四态(含"只有 PRD"这条回归)。
其他变更
- 新增通用绊线:每个走网络的
cmdXxx都必须把args.account传给它调的核心函数 ——
源码区间 + 字符串感知扫描,带显式白名单。
工具链早就有"参数声明了但没传"的守卫,CLI 没有 —— 这个缺口正是从那道缝里活下来的。 - 写这条守卫时踩了两个"假绿",都被自己的守卫抓住:
① 括号配平从参数表的{就开始数→( args, cookie )一闭合就返回(只拿到 **41** 字符)→ **所有命令被当成"不走网络"**(是"确实检查到了、不是空跑"那条断言判红的); ② 补完后扫描名单**漏了whoIsIt/buildAccountIndex` → 白名单成了摆设(清空白名单 0 条红,是变异测试抓出来的)。
补全后清空白名单报 2 条红。 - 自检 569 → 611 项;变异测试:删掉
search的 PRD 打印 → 红 1 条;清空白名单 → 红 2 条。
Full Changelog: v0.4.1...v0.4.2
New Features
- The CLI accepts
--account <alias>: pass it whenever the target team does not belong to the default account.
parseArgvhad been parsing--accountall along, but not one of the 16 commands passed it on (measured:
0 before, 13 after) — so they always used the default account. Now 13 commands / 15 call sites forward it. - Three commands do not need it, each with a stated reason:
who(its whole job is cross-account detection),
accounts(uses--aliasto pick which account to operate on, a different question from which identity to use),
andlog(purely local, no network).
Improvements
USAGEnow documents the account precedence:--cookie>LANHU_COOKIE>--account> default account —
i.e. an explicit cookie or the environment variable overrides--account. This was dug out ofresolveCookie;
undocumented it would be a silent surprise.docs/CLI与开发.mdgained--accountand a real example (the30005case).
Bug Fixes
--accountbeing accepted but ignored: the demo team belongs to accountdemowhile the default is
default-acct, sosearch/projectsreturnedcode=30005— while the same inputs through a tool worked fine.
An unknown alias now fails loudly and lists the known accounts with exit code 1 — no silent fallback.searchdropped results in its human-readable output (the worse one):cmdSearchiterated onlyr.images,
so a search whose hits are PRDs or projects produced no output at all with exit code 0 — exactly the
"looks successful but did nothing" failure this project fights.
Measured: searching 「某大屏」 hits 2 PRDs / 0 artboards → the human path printed nothing while--jsonshowed
prds:2(the data was there, it just was not printed). Now all three kinds are printed plus a summary line,
and an all-empty result says so explicitly.
(The toollanhu_searchalready printed PRDs — this bug was CLI-only.)
The rendering was extracted into a pure functionsearchLines(), covered by 5 assertions over its four states
(including the "PRDs only" regression).
Chores
- New general tripwire: every network-going
cmdXxxmust passargs.accountto the core function it calls —
a source-region scan that is string-aware, with an explicit allowlist.
The tool layer already had a "declared but not forwarded" guard; the CLI did not — and this gap is what survived
in that seam. - Two false-greens were hit while writing that guard, and its own assertions caught both:
① the brace matcher started counting from the{of the parameter list, so( args, cookie )closed it immediately
(41 characters captured) → every command looked like it did not touch the network (caught by the
"this check really ran, it is not a no-op" assertion); ② after fixing that, the scan list missed
whoIsIt/buildAccountIndex→ the allowlist became decorative (clearing the allowlist turned 0 red — caught by
mutation testing). With both fixed, clearing the allowlist turns 2 red. - Self-check 569 → 611 assertions; mutations: removing
search's PRD printing → 1 red; clearing the allowlist → 2 red.
Full Changelog: v0.4.1...v0.4.2
0.4.0
四条攒着的改进。 它们不是临时起意,而是 0.3.0 之后主动记在「已知空缺」里、等一个真改动一起发的 ——
其中第一条既是新能力,也是一个一致性修复。
新增功能
lanhu_list_designs收url:以前入参只有projectId(必填),而它的兄弟lanhu_list_product_documents收链接 ——
于是"列出这个项目的设计稿"反而要调用方先手拆 pid,与插件对外的承诺(「链接里的 tid/pid/image_id 不用手拆」)打架。
现在项目页链接(没有image_id的那种)也能直接列出(实测某项目 252 张)。
projectId改为非必填,但两者都不给会明确报错(不许静默返回空列表);显式projectId优先。- 清单加
order:它正好解释"界面只看到 3 个、接口给 9 个"这个疑问 —— 蓝湖「文档」面板按order倒序
显示且是滚动区。实测该项目order是 10→2 连续,与界面面板顺序完全一致。 withPages(默认关):附上每份原型的页面节点数 / 可读页数。同一个项目里从 3 页到 219 页(差 20 倍),
有了它 AI 能一眼选对文档,不必逐份读一遍才发现拿错。代价 N 份 = N 次额外请求(已写进描述与文档)。- 标题标明「路径」:嵌套原型页的标题会拼成
A / B / C,看起来像"把多页合并了"(实测我自己就据此误报过一次)。
现在输出路径:A / B / C。
体验优化
- CLI 与工具两条链对齐:
designs --url、product-docs --with-pages——
这个项目有过"CLI 是对的、只有工具链断了"的前例,反过来同样得防。 - 判定放在源头:传
name时同时给nameIsPath: true,下游 4 个标题打印点统一走titleName()——
比"每处自己拼字符串"更不容易漏(第 5 个站点不会又忘)。机器读的 JSON 也带nameIsPath,
而name保持原值(展示格式不污染程序消费)。 - 单份失败不炸整张表:
withPages拉不到的文档只把该行标?并给原因。
问题修复
parseLanhuUrl不能拿来列设计稿:它面向"某一张稿",没有image_id就抛错,
而项目页链接本来就没有它(第一版真机直接撞上)。→ 新增parseProjectTarget(面向"某个项目"),
并加反向断言守住parseLanhuUrl必须继续要求image_id,不许为迁就新用法被改宽容。- 同一个 bug 出现两次:列表渲染"多一个空列"(单元格带了前导
|而行模板已收尾),
工具与 CLI 各栽一次(因为各写了一遍渲染)→ 抽成共用纯函数,并断言表头/分隔/行列数一致。 - 一条断言是瞎的:
路径:在标题行与每页标题两处都有,最初只断言了标题行 ——
把「每页标题」去掉的变异注入成功却 0 条红。拆成两条后两处各自能红。
其他变更
- 自检 530 → 564 项;变异测试 7 处全部变红,其中一条盯的是源头标记 ——
只测打印点的话,"源头忘了打标记"会让四个站点同时失灵却可能一条都不报。 - 「已知空缺」里这四条标记为 0.4.0 已做(保留记录,不删)。
docs/原型样式.md新增「标题里的『路径:』是什么意思」;docs/产品文档.md补order与withPages。
Full Changelog: v0.3.0...v0.4.0
New Features
lanhu_list_designsacceptsurl: its parameters wereprojectId(required) only, while its sibling
lanhu_list_product_documentsaccepted a link — so "list this project's artboards" forced the caller to
split out the pid by hand, contradicting the plugin's own promise thattid/pid/image_idnever need manual
splitting. A project page link (the kind withoutimage_id) now works directly — measured 252 artboards on
one project.projectIdis no longer required, but giving neither now fails loudly instead of returning an
empty list; an explicitprojectIdwins.orderin the document list: it explains the old puzzle of "the UI shows 3, the API returns 9" — Lanhu's
「文档」 panel sorts byorderdescending and is a scroll region. On the project testedorderruns 10→2 and
matches the panel exactly.withPages(off by default): adds each prototype's page node count / readable page count. Within one
project this ranges from 3 to 219 pages (a 20× spread), so an AI can pick the right document at a glance
instead of opening each one. The cost — N documents = N extra requests — is stated in the description and docs.- Headings now say 「路径」: a nested prototype page's title used to read
A / B / C, which looks like several
pages merged into one (that is exactly how the maintainer misread it once). It now reads路径:A / B / C.
Improvements
- CLI and tools are aligned again:
designs --urlandproduct-docs --with-pages. This project has been bitten
before by "the CLI was right and only the tool path was broken"; the reverse deserves the same care. - The decision lives at the source:
nameIsPath: trueis attached wherenameis produced, and all four
heading print sites go through onetitleName()helper — less likely to be missed than assembling strings in
each place. Machine-readable JSON carriesnameIsPathtoo, whilenamekeeps its raw value so display
formatting does not leak into program consumption. - One failure does not take down the table: a document whose page data cannot be fetched is marked
?with a
reason.
Bug Fixes
parseLanhuUrlcannot be used to list artboards: it targets a single artboard and throws when there is no
image_id, which project page links do not have (hit on the very first real-machine run). → added
parseProjectTargetfor "a project", plus a reverse assertion thatparseLanhuUrlkeeps requiring
image_idso it is never quietly loosened to accommodate the new use.- The same bug twice: list rendering produced one extra empty column (a cell carried a leading
|while the
row template already closed the row) — hit once in the tool and once in the CLI, because each had its own
renderer → extracted into a shared pure function with assertions on header/separator/column counts. - One assertion was blind:
路径:appears both in the title line and in each page heading, but initially only the
title line was asserted — removing it from the page heading was successfully injected yet turned 0 assertions
red. Split into two, both mutations now fail.
Chores
- Self-check 530 → 564 assertions; all 7 mutations turn red, one of them guarding the source-level flag —
testing only the print sites would let a missing source flag break all four sites without a single red. - The four items in the "known gaps" list are now marked done in 0.4.0 (the record is kept, not deleted).
docs/原型样式.mdgained a section on what 「路径:」 means;docs/产品文档.mddocumentsorderandwithPages.
Full Changelog: v0.3.0...v0.4.0
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
0.1.1
首个公开发布。 本版不做新功能,只做两件事:修掉一个静默失效的真 bug,以及把侧边面板按官方主题令牌重做一遍 ——
没有新增工具、没有改任何工具的调用方式、没有改任何已有参数的含义。
新增功能
首次发布,这里是插件现在能给 AI 的全部能力:
- 13 个原生工具:
lanhu_check_auth·lanhu_list_teams·lanhu_list_projects·lanhu_list_designs·lanhu_search·lanhu_read_design·lanhu_read_blocks·lanhu_accounts·lanhu_who·lanhu_download_slices·lanhu_verify_spec·lanhu_verify_blocks·lanhu_cookie_set。 - 侧边面板(三个 Tab:块级 / 账号 / 记录):贴一个链接就出块级清单,不用敲命令。面板与工具走同一条数据通道(Host 的
/lanhu/*路由,仅本机可访问)。 - CLI:同一套能力的命令行入口,
--json可机器读。 - 多账号:一个账号一套 Cookie。蓝湖链接里的
tid就是团队 id,而一个团队只属于一个账号 —— 所以看链接就能零请求判定该用哪个账号(实测 2–45 ms),不用问用户、也不试错。 - 区域抠图 + 坐标映射:
region按区域取值(y0,y1或x0,y0,x1,y1);再配mapBox/toBox把设计稿坐标直接映射到你自己 SVG 的 viewBox —— x/y 各自独立缩放(非等比),长宽比不同也能对上。 - 两种验收:
lanhu_verify_spec用真实浏览器取getComputedStyle逐字段比对色值 / 字号 / 字重 / 字体族 / 圆角;lanhu_verify_blocks出四态报告(✅ 完全匹配 / 🟡 容差内 / ❌ 不匹配 / ⚪ 无法比对)并给可直接抄的改法。 - 切图导出带 alpha 报告:每张图给
尺寸 / mode / alpha 范围,半透明当场告警(避免整屏发灰)。 - 英文入口 + 双语发布说明:README 顶部是
[中文](#…) | [English](#english-overview)语言锚点,并新增一屏## English overview(一句话是什么 / 30 秒上手表 / 13 个工具各一行 / 安装三要点 / 四条铁律)。英文只做导航:完整参数仍指向下面那份生成的清单,中英两侧不会各维护一份会漂移的副本。 - 「工具速查」改为从代码生成:
tools/gen-readme-tools.mjs从lib/index.js的TOOLS生成 8093 字符(13 个工具的完整说明 + 每个参数的类型 / 必填 / 取值,即 AI 在 schema 里看到的那份),并由test/readme-test.mjs逐字比对 —— 主文档不会再落后。
体验优化
面板按官方主题令牌重做了一遍。八条里三条属于"静默失效"型 —— 不报错,只是看起来怪:
- 深色主题下主按钮看不见:主按钮拿
--dsw-alias-brand-primary当品牌色做底、又写死白字。该令牌浅色下是近黑#0f1115、深色下是近白#f9fafb—— 白底白字,实测对比度 1.05:1。改用官方配对的--dsw-alias-label-primary-foreground后:浅色 18.9:1 / 深色 18.1:1。 - 三个令牌名根本不存在,一直静默走 fallback:
bg-sunken(真名bg-layer-1)、brand-bg(无此令牌)、state-warning-primary(少个ing,真名state-warn-primary)。 - 深色下面板是"中灰板":
surface用了bg-overlay,该令牌深色 =#61666b,比应用底色#151517亮 17 倍。改用官方菜单别名--dsw-specific-menu(=bg-layer-3)→ 深色#353638、浅色#ffffff。 - 浮层补上对话框语义:
role="dialog"+aria-modal+aria-label,Esc 可关,打开移焦、关闭还焦。 - 关闭按钮命中区 14×16px → 26×26px(WCAG 2.5.8 要求 ≥24×24)。
- URL 输入框不再切断链接:加
break-all+ 按内容自动增高(封顶 132px 再转滚动)。 - 双层滚动条 → 单层:面板内容区与块级列表各自滚动(实测两个滚动容器);现在内层不滚,只留一层。
- 文档改成「渐进式披露」:README 只留入口(人写部分从 10059 字符降到 8924,−11%),细节下沉成 4 篇按需加载的
docs/(读稿 / 验收 / 面板与账号 / CLI 与开发,合计 7128 字符),README 给一张「你手上在做的事 → 读哪个文件」的索引。生成块本身 8093 字符不算新增信息 —— 它就是 AI 在工具 schema 里本来就能看到的那份,只是给人类读者一份不会过时的投影。 - 危险操作:删除账号改两段式确认(首次点击只变红,实测不发写请求);「更新 Cookie」会清空上一次的 Cookie 草稿 —— 以前只预填别名,最容易让人以为串也是对的。
问题修复
lanhu_read_design有三个参数是「声明了但收不到」:limit/mapBox/toBox写在工具 schema 里,但execute从来没往readDesign传。后果全是静默的 —— 传mapBox+toBox拿到未映射的表且不报错;传limit: 900仍只回 80 层(大稿子只看得到前 80 层)。CLI 一直是对的,只有插件工具这条链断了,所以这个 bug 藏了很久:用 CLI 验证的人永远撞不到它。已补齐,并复验:limit: 3只回 3 行、mapBox+toBox真的产出「映射 x,y / 映射 w×h」列与sx/sy说明、只给一个参照框时明确报错而不是静默不映射。
其他变更
- 仓库自带自检 257 项全绿(
node test/selfcheck.mjs,纯离线、秒级;每个能力都配了正反例)。 - 新增文档绊线
test/readme-test.mjs24 项:生成块是否与TOOLS逐字一致 /docs/链接是否存在且无孤立文件 / 版本号五处是否一致 / 发布说明格式与公开纪律(不含本机绝对路径)。版本一致性以前是纯靠人核的,现在漏改一处就红。 - 插件契约自检 16 项全绿(工具形状 / 路由信封 / lossless JSON / 本机访问守卫 / 槽位注册与回收)。
- 不变的两条老规矩:Host 半边是启动快照(改
lib/index.js或lanhu.mjs要重启dsh web;只改lib/client.js刷新页面即可);面板没有的功能不代表工具没有 —— 工具 schema 才是唯一真身。 - 面板改动的验证方式说明白:用真 React + 官方
dsh-client-ui-theme的 163 个真实令牌(浅 / 深两套)离屏渲染逐项测量,面板契约由桩自检覆盖;并在真实 GUI 里点过一次 —— 重启dsh web后打开面板点「读取块级清单」,/lanhu/log记到一条新的panel:preview(ok=true),证明新客户端半边确实生效。dsh web的会话 token 只在进程内、不落盘,自动化进不去真实 GUI,所以这一步只能由人做。 - 已知空缺(不藏):
test/selfcheck.mjs的DESC_MUST只断言「工具描述里提到了某个能力」,不断言「声明的参数真的传给了实现」 —— 本版修的那个 bug 就是从这里活下来的;补这条守卫需要解析源码或给实现注入桩,不是几行能写完的。面板里还有一条死路由/lanhu/verify-blocks—— 后端与recordUsage都写好了,注释写着「面板『块级』Tab 的『与页面比对』按钮用」,但那个按钮从来没做;/lanhu/who同样没有前端入口。
Full Changelog: 首次发布,全部提交
This is the first public release. It adds no new features: it fixes one silently failing bug and rebuilds the sidebar panel against the official theme tokens — no new tools, no change to how any tool is called, no change to the meaning of any existing argument.
New Features
First release — here is everything the plugin gives an AI today:
- 13 native tools:
lanhu_check_auth·lanhu_list_teams·lanhu_list_projects·lanhu_list_designs·lanhu_search·lanhu_read_design·lanhu_read_blocks·lanhu_accounts·lanhu_who·lanhu_download_slices·lanhu_verify_spec·lanhu_verify_blocks·lanhu_cookie_set. - A sidebar panel (three tabs: blocks / accounts / log): paste a link and get the block-level list — no commands. The panel and the tools share one data channel (the Host's
/lanhu/*routes, loopback-only). - A CLI: the same capabilities from the shell, with
--jsonfor machine-readable output. - Multiple accounts: one cookie per account. The
tidin a Lanhu link is the team id, and a team belongs to exactly one account — so the link alone identifies which account to use with zero requests (measured 2–45 ms). No asking the user, no trial and error. - Region extraction + coordinate mapping:
regionselects an area (y0,y1orx0,y0,x1,y1); addmapBox/toBoxto map design coordinates straight into your own SVG's viewBox — x and y are scaled independently (non-uniform), so differing aspect ratios still line up. - Two kinds of verification:
lanhu_verify_specdrives a real browser, readsgetComputedStyleand compares colour / font size / weight / family / radius field by field;lanhu_verify_blocksproduces a four-state report (✅ exact / 🟡 within tolerance / ❌ mismatch / ⚪ not comparable) with fixes you can copy verbatim. - Slice export with an alpha report: every image reports
size / mode / alpha range, and semi-transparency is flagged on the spot (so a whole screen doesn't come out washed out). - An English entry point and bilingual release notes: the README opens with a
[中文](#…) | [English](#english-overview)anchor line and gains a one-screen## English overview(one sentence, a