Skip to content

Releases: LoktLin/dsh-lanhu

v0.6.1

Choose a tag to compare

@LoktLin LoktLin released this 09 Oct 06:40

中文 | English

更新说明 · 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

Choose a tag to compare

@LoktLin LoktLin released this 09 Oct 04:58

中文 | English

更新说明 · 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_blocks gains 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's 480×270 to the real 1920×1080. If your pipeline treated these as empty designs, re-check it.
  • lanhu_read_blocks returns new fields: version / versionIsLatest / latestVersionAt / contrast, plus
    sourceFormat for 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/读稿.md gains a "supported and unsupported design formats" section.

Full Changelog: v0.5.4...v0.6.0

v0.5.4

Choose a tag to compare

@LoktLin LoktLin released this 08 Oct 06:32

中文 | English

更新说明 · 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 字段里补一句"这通常意味着什么、可以先做什么"。

其他变更

  • 内部重构:块类型、颜色角色、输出上限等改为集中的冻结常量,classifyBlock 只引用常量。工具可观测行为不受影响。
  • README:删去自测项数等维护者指标;把无法验证的断言改为可验证的说法("由 schema 生成,改代码时会跟着变");
    版本链接改指 Releases(不再引用 CHANGELOG.md)。

Full Changelog: v0.5.2...v0.5.4


New Features

None.

Upgrade Notes

  • ⚠️ Every tool now returns ok. Previously lanhu_list_teams / lanhu_list_designs / lanhu_read_design returned no
    ok field and success had to be inferred from other fields. Code branching on ok received undefined from these three.
  • The npm package no longer ships CHANGELOG.md (as of v0.5.4). Version history lives in git and in Releases; docs/
    and README.md are 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_designs and lanhu_read_design returned no ok field.
    This is now guaranteed at the tool success exit — all 15 tools always return ok.
  • Failures stated the cause but offered no next step:
    • A malformed id (e.g. imageId: 'not-a-uuid') used to surface the upstream code=10009:Image not exist. It is now
      caught locally and reports an actionable next step (for example, "get an imageId from lanhu_list_designs first").
    • 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 hint field explains what it
      usually means and what to try first.

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 of CHANGELOG.md.

Full Changelog: v0.5.2...v0.5.4

v0.5.2

Choose a tag to compare

@LoktLin LoktLin released this 08 Oct 05:24

中文 | English

更新说明 · 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_HINT rewritten (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 to format=full and 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 (record version) 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_designs labels its sizes "preview" (v0.5.1): the list endpoint returns thumbnail dimensions
    (187.5 vs a real 750, 480 vs 1920 — 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, and files now ships docs/ and CHANGELOG.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 12279px garbage 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/y are canvas-absolute (measured x=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
    missed renderGapDigest → 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: geometricGaps keyed "nearest per direction" by id, so when the caller
    supplied no id (or ids collided, e.g. Figma's I37: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
    existing parseRfc2822.

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): region dual 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 the v0.5.0 / v0.5.1 tags advanced accordingly.
  • Honestly recorded as still open: the flush reconciliation sample is only 3 artboards; the full 1437-artboard
    read_blocks sweep w...
Read more

v0.4.2

Choose a tag to compare

@LoktLin LoktLin released this 24 Sep 06:47

中文 | English

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.
    parseArgv had been parsing --account all 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 --alias to pick which account to operate on, a different question from which identity to use),
    and log (purely local, no network).

Improvements

  • USAGE now 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 of resolveCookie;
    undocumented it would be a silent surprise.
  • docs/CLI与开发.md gained --account and a real example (the 30005 case).

Bug Fixes

  • --account being accepted but ignored: the demo team belongs to account demo while the default is
    default-acct, so search / projects returned code=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.
  • search dropped results in its human-readable output (the worse one): cmdSearch iterated only r.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 --json showed
    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 tool lanhu_search already printed PRDs — this bug was CLI-only.)
    The rendering was extracted into a pure function searchLines(), covered by 5 assertions over its four states
    (including the "PRDs only" regression).

Chores

  • New general tripwire: every network-going cmdXxx must pass args.account to 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

Choose a tag to compare

@LoktLin LoktLin released this 24 Sep 05:08

中文 | English

四条攒着的改进。 它们不是临时起意,而是 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_designs accepts url: its parameters were projectId (required) only, while its sibling
    lanhu_list_product_documents accepted a link — so "list this project's artboards" forced the caller to
    split out the pid by hand, contradicting the plugin's own promise that tid/pid/image_id never need manual
    splitting. A project page link (the kind without image_id) now works directly — measured 252 artboards on
    one project. projectId is no longer required, but giving neither now fails loudly instead of returning an
    empty list; an explicit projectId wins.
  • order in the document list: it explains the old puzzle of "the UI shows 3, the API returns 9" — Lanhu's
    「文档」 panel sorts by order descending and is a scroll region. On the project tested order runs 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 --url and product-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: true is attached where name is produced, and all four
    heading print sites
    go through one titleName() helper — less likely to be missed than assembling strings in
    each place. Machine-readable JSON carries nameIsPath too, while name keeps 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

  • parseLanhuUrl cannot 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
    parseProjectTarget for "a project", plus a reverse assertion that parseLanhuUrl keeps requiring
    image_id
    so 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/原型样式.md gained a section on what 「路径:」 means; docs/产品文档.md documents order and withPages.

Full Changelog: v0.3.0...v0.4.0

0.2.0

Choose a tag to compare

@LoktLin LoktLin released this 24 Sep 03:48

中文 | English

补齐了产品文档(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

  • version added to lanhu_read_design / lanhu_read_blocks / lanhu_read_product_doc / lanhu_download_slices.
  • Results now carry a version field (id / requested / isLatest / count / latestId / latestAt).
  • An unknown version raises VERSION_NOT_FOUND with 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.
  • availability is always not_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
    through product_documents: a single candidate is used directly; several are disambiguated by the fact that
    pageId is stable across versions; if it still cannot decide, it fails and lists every candidate.

DDS structured data (optional, off by default)

  • lanhu_read_design gained a dds: true switch.
  • 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 returned code=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
    (and DESIGN_NOT_PROTOTYPE the 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-doc commands and a --version flag.

Bug Fixes

  • lanhu_cookie_set silently ignored account: account is 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
    account now writes to that account (~/.dsh/lanhu/cookies/<alias>), and an unknown alias fails loudly instead of
    falling back to the default file.
  • densityLimited was always []: when nothing at all could be evaluated, that read as "everything is good
    enough"
    — the exact opposite of the truth. Now null = nothing evaluated, [] = evaluated and all fine.
  • Region-mode gaps were always empty: the filter defaults disagreed with renderRegion (with only y0,y1 the
    x0/x1 bounds 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 TOOLS by tools/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.assets is a bare array of URLs (no
    render_bounds); 12 slices matched 0 layers in practice, therefore only null plus 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

Choose a tag to compare

@LoktLin LoktLin released this 23 Sep 16:29

中文 | English

首个公开发布。 本版不做新功能,只做两件事:修掉一个静默失效的真 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.mjs 24 项:生成块是否与 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 --json for machine-readable output.
  • Multiple accounts: one cookie per account. The tid in 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: region selects an area (y0,y1 or x0,y0,x1,y1); add mapBox / toBox to 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_spec drives a real browser, reads getComputedStyle and compares colour / font size / weight / family / radius field by field; lanhu_verify_blocks produces 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