v0.1.4
dsh-diff-stat v0.1.4
Sixth release. The collapsed row's file link now fits like the stock client — shrink-to-fit with a real ellipsis (the old rule pinned the path box at 340px, and its
display: inline-flexsilently disabledtext-overflow, so truncation was always a hard clip). A multi-pass third-party review then hardened the unsafe edges: undo now judges create-vs-overwrite on turn-start existence snapshots (session-scoped, full-tree, truncated-reads-unverified), the inline badge and the diff window share one arithmetic, PTC dispatch records route to their turn reliably, and the committed lib builds byte-stable on any machine.
Install / 安装
# from npm / 从 npm 安装
dsh plugin --profile web add dsh-diff-stat
# or from GitHub / 或从 GitHub 安装
dsh plugin --profile web add github:HaoyueQin/dsh-diff-statUninstall:
dsh plugin --profile web remove dsh-diff-statHighlights / 亮点
- Undo is snapshot-guarded end to end: the host captures a turn-start file-existence snapshot (existence only, never bytes) with session-scoped keys
(cwd, session, turn)— two sessions can share one workspace and turn numbers restart per session. The capture walks the full tree (node_modules/.gitskipped, the 100k-file cap the only bound) and is idempotent per turn (a window reload re-running the start match no longer re-captures at a later time). Anything truncated or unlistable reads unverified, never create — undo can no longer delete a file that pre-existed the turn. Reads are capped:files.readtakes only the display head, undo refuses files beyond a 32 MiB gate, oversized request bodies answer 413 exactly once, and concurrent history replays merge per key. - Badge and window share one arithmetic: a terminator-only change (
"a\n"→"a") is line-equal under the LCS yet rendered as a lone gap row with+0 −0— it now counts one deletion plus one addition in both the badge and the window, and the detector bails above the alignment budget so neither drifts. An empty creation (write ''to a new file) counts one added line instead of+0 −0. LCS results are memoized per side pair (the badge and the window align the same hunk up to four times at the 1200-line budget), and paths merge on a normalized key (\\and./forms collapse into one row, first-seen spelling kept for display). - PTC / Code Dispatch routing: wire dispatch records carry no turn coordinate — the accumulator now learns
rootCallId → Turnfrom tool/call matches and routes each record to its turn; the fold seeds from the engine-routed Context id (the runtime Location index resolves a window-start record tosession, so Location alone had nothing to say exactly when it mattered). The dead string-arguments branch is removed — both supported kernel generations carryargumentsas an object, and its hunks double-counted with the chat-tree join — dispatch records now contribute PTC evidence only, and the root learn-table evicts LRU instead of clearing every mapping at the cap. - The row file link fits like stock alpha.2:
.linkFitreduces to the single overrideflex: 0 1 auto— width = min(content, free line width), a real ellipsis when the line runs out, the+N −Mbadge stays adjacent, and the click target still ends where the path text ends (the row's empty remainder stays the expand/collapse toggle).
Fixes / 修复
- Accessible summary card header: the header becomes a
divwith button semantics — the undo button inside the old<button>header was invalid nested-button HTML that broke screen readers and keyboard navigation. - Context boost anchors only on a unique fragment: with duplicated content (a snippet copied across a template) the boosted builder wrapped the wrong region; a fragment appearing more than once now stays unboosted.
- Glass bridge validated before invoke: any window code could dispatch a same-named event or clobber the global — a partial shape threw on
.versionfar from the source while the old bridge stayed un-cleaned (silent glass failure). The global and event detail now pass a structural guard first. - Hardened host calls:
fetchWithTimeoutkeeps the module-owned timeout over any caller signal, and a failed host probe retries on the next call (host routes appear on hot reload). The file peek stores error message keys, so a locale switch re-renders in the new language; duplicated implementations and dead CSS dropped.
Infrastructure / 基建
- Byte-stable committed lib: bundled
node_modulesmodules carried ABSOLUTE//#regionpaths of the build machine, so a rebuild on any other checkout differed byte-for-byte — breaking the committed-lib contract and the CI lib-diff gate. ArenderChunkpass now normalizes region labels under the project root (verified: zero absolute paths remain); committed artifacts rebuilt. - CI / release guards: branch/path filters with superseded-run cancellation; the release workflow asserts the pushed tag matches
package.jsonversion; the tarball is picked with an exactly-one regex that now admits dotted prerelease segments (and would otherwise mis-pick0.10.xover0.9.x); CI paths gainlib/**. - Packaging hygiene:
dsh-atomic-writejoins peerDependencies (the host half imports it and the bundle externals it — a harness without it crashed instead of degrading);enginesdeclares the node floor;.gitattributespins committed lib bundles as binary so the byte-stable diff survives Windows checkouts. - Tests: new assertion blocks cover the pagination-boundary dispatch routing and fold, the create/overwrite classifier, the unique-fragment anchor, path-key merging, and terminator-only arithmetic — including skipped directories (both separators, several depths), empty creations,
.git-safe classification (.gitignoreas a filename stays create), truncated snapshots, and over-budget terminators. - Docs: the supported harness matrix extends to
0.1.2-alpha.2(slot contracts, wire meta, and session events re-verified item by item); READMEs gain hand-drawn SMIL banner and demo SVGs, the GitStock activity chart, and a sync with the fenced API surface.
Full Changelog: v0.1.3...v0.1.4
中文说明
第六个版本。两条主线:行内文件链接截断修复与多轮第三方评审驱动的安全加固。
链接修复:折叠行上的路径链接曾同时踩两个坑——flex: none 配 max-width: 340px 定宽帽(340px 是早期 badge 置行尾时代的遗留,布局改造后未清理),宽度恒为 min(内容, 340px),窗口再宽也截断;display: inline-flex 又使按钮成为 flex 容器,text-overflow 为非继承属性、不作用于匿名 flex item,省略号从未渲染过,一直是硬裁切。现 .linkFit 收敛为单条 flex: 0 1 auto,对齐 stock alpha.2 上游的 shrink-to-fit 设计:宽度 = min(内容宽, 剩余行宽),窄行让位给 +N −M 徽标并出真省略号,点击目标止于路径文本,行剩余区域仍归展开切换。
undo 撤销守卫:此前 undo 以「wire 记录无旧文本」判定 create 并直接删除,多轮评审发现一串可误删既有文件的路径——回合起点快照(仅存在性、绝不落字节)成为判定基准:键升级为会话级(双会话共享工作区、回合号各自重起时不再串档);捕获遍历全树(跳过 node_modules/.git,仅受 10 万文件上限约束)且按回合幂等(窗口重载重放 start 匹配不再二次捕获);凡截断、目录不可列、junction/symlink 项一律降级为 unverified,绝不判 create——undo 从此不可能删除回合前就存在的文件。读取侧同步设限:files.read 只读展示头部、undo 拒绝 32 MiB 以上文件、超限请求体精确应答一次 413、并发历史重放按键合并。
徽标与算术统一 / PTC 路由:行尾仅换行符变化("a\n" → "a")在 LCS 下行等价,曾渲染为 +0 −0 的孤立空隙行,现徽标与窗口一致计为 +1 −1;空文件创建(write '')计一行新增;LCS 按侧对记忆化;路径按归一化键合并(\\ 与 ./ 形态收敛为一行)。PTC 子调用记录按 rootCallId 归位到所属回合,fold 以引擎路由的 Context id 播种(分页窗口从中途开始也能认领轮末卡);死代码 string-args 分支移除(其 hunk 会与工具树 join 重复计数),学习表改 LRU 淘汰。
基建:提交 lib 实现字节稳定(bundle 内 region 标签由构建机绝对路径归一化为项目相对路径,跨机器重建逐字节一致,CI 的 lib-diff 门禁恢复意义);CI/发版增加守卫(tag 与 package.json 版本一致性断言、tarball 恰一匹配正则支持 prerelease、分支/路径过滤与超驰取消);dsh-atomic-write 补进 peerDependencies、engines 声明 node 下限、.gitattributes 将提交 lib 钉为 binary;对齐器新增多组断言(路由/fold、create-overwrite 分类、唯一片段锚定、路径合并、terminator 算术、.git/node_modules 分类、截断快照、超预算 terminator);README 文档面更新(支持矩阵延展至 0.1.2-alpha.2、SMIL banner 与演示 SVG、GitStock 活跃图、围栏 API 同步)。
验证:pnpm typecheck、pnpm check:align、pnpm build 全绿;发布 tag 经 CI 校验「tag 名 == package.json 版本」与「lib 零漂移」后自动出包。