Skip to content

Releases

v0.4.0 — Bilingual UI and engineering

Choose a tag to compare

@LuoShanHui LuoShanHui released this 10 Nov 07:12

中文说明

Fourteen commits since v0.3.0: a fully bilingual UI, correct English plurals, client sources split into fragments, and the test suite grown from 39 to 82 checks. The engine (lib/ledger.js) and the host routes (index.js) are untouched, so the data model and cache format are unchanged and upgrading needs no cleanup of ~/.dsh/doc-ledger-*.

overview

Fully bilingual UI (zh / en)

  • Every string in the panel now lives in the dictionary: 159 keys with matching Chinese and English, covering buttons, menus, empty states, toasts, the filter row, export, the preview dialog, and every aria-label and title (previously only 3 keys existed, so an English UI still showed Chinese text).
  • Combination sentences are no longer glued from Chinese fragments; each is one full sentence with {placeholders}, so English word order is free.
  • Correct English plurals: Intl.PluralRules picks the _one / _other dictionary variant, giving 1 file / 2 files; Chinese uses the same value for both forms, so its behaviour is unchanged.
  • Evaluation-time tables (category names, sort-key labels) now store keys and resolve at render time — otherwise switching language would freeze the Chinese in place.
  • Before apply() installs the host translator the dictionary falls back to Chinese, so a raw a.b.c key is never shown to the user.

en

Client sources split into fragments

  • client.js is split into 15 named fragments under src/client/, and tools/build-client.mjs concatenates them in a fixed order with no bundler. The artifact is byte-for-byte identical before and after the split (same SHA256, no new dependencies).
  • Why not real modules: the host loads a client plugin as one factory closure whose require injects react and nothing else, so relative imports are not guaranteed. The split is for readability and testability only.
  • CI gained npm run check:client, which fails when the committed artifact drifts from the sources — no more "edited the source, forgot to rebuild".

Tests grew from 39 to 82

  • +32 client pure-function assertions: node:vm evaluates the real source fragments (not a copy of the logic), covering AND search, seven sort keys, cross-session merging, formatting, highlight range merging and dsh-resource:// address construction.
  • +159 dictionary keys verified: zh/en key sets match, no empty values or TODOs, every t() reference resolves, no dead entries, and placeholder sets agree.
  • +7 bilingual README checks: both editions have the same section count and order, link to each other, the English one carries no Chinese, and all in-page anchors resolve.
  • npm test is now 82 checks, still with zero external dependencies.

Documentation

  • A fully bilingual README: README.md (English, the default) and README.zh.md (Chinese), cross-linked at the top.
  • One shared skeleton for "Traps we hit" in both editions: host API contracts / runtime and platform / front-end rendering / caching, tests and other — each entry written as symptom → cause → fix. windowsHide and ELECTRON_RUN_AS_NODE still link to the detailed reproductions in the body.
  • docs/i18n.md rewritten to describe what shipped; docs/i18n-plan.md kept as the design record; tools/i18n-extract.mjs can recompute any remaining hard-coded strings (only the command-palette search aliases are left).
  • Added an English UI screenshot, docs/en-overview.png.

Install / upgrade

"dsh-doc-ledger": "github:LuoShanHui/dsh-doc-ledger#v0.4.0"
node <runtime>/dependencies/pnpm/bin/pnpm.mjs install `
  --config.store-dir=<pnpm-store> `
  --config.confirmModulesPurge=false

Also on npm: "dsh-doc-ledger": "0.4.0". Reload the page afterwards (the client bundle has to be re-injected).

Compatibility

  • DSH >=0.2.0-rc.1 <0.3.0-0; Node >=18; verified on Windows only.
  • The UI language follows the host's locale; when the host has no locale.getLocale(), plurals fall back to the Chinese rule (one form for every count).
  • Two host capabilities remain optional and degrade silently: uiWorkspace.openSession and sidebarRight.openResource.

Known limitations

  • Plurals use two forms (_one / _other) and do not cover languages needing few / many (Russian, Polish…). The dictionary structure already allows them; only the translations are missing.
  • The documentation (this release note, the CHANGELOG, the design records under docs/) is still mostly Chinese; the README is the one fully bilingual document.
  • Everything else is in the README's Known limitations.

Tests

npm test          # 82 checks: engine 7 + decoder 10 + routes/security 14 + cache 8 + client 36 + i18n + README 7
npm run harness   # local UI verification page; add ?locale=en for the English UI

The full change history is in CHANGELOG.md.

v0.3.0 — 交互与键盘可用性

Choose a tag to compare

@LuoShanHui LuoShanHui released this 09 Nov 08:13

自 v0.2.0 起的 10 个提交,全部是面板交互、键盘可用性、性能与工程化;数据模型与缓存格式没有变化,升级不需要清 ~/.dsh/doc-ledger-*。

overview

新增

  • 搜索支持多词 AND:空格分隔的每个词都必须命中;各词独立高亮、重叠区间合并(ord + order 只标一层),无结果时提示同时列出所有词。
  • 子代理血缘跳转:会话 payload 新增 parentSessionId,子会话卡片菜单多「跳到父会话:<标题>」,父会话卡片列出已加载的子会话(最多 5 个)。
  • 行列表 roving tabindex:每张卡只有一行可 Tab 到,卡内 ↑/↓/Home/End 逐行走;40 张卡展开时 Tab 停靠点从 400+ 降到 40。
  • 窄窗口适配:面板宽度 < 640 px 时快速查看弹窗的分裂按钮只保留程序图标(文字进 title/aria-label),文件名不再被挤成三四个字。
  • 快速查看弹窗底部路径可点击复制。
  • 「全部展开」按 8 张一批分任务:40 张卡从「2 个 85 ms 长任务(共 ~170 ms 阻塞)」变成「5 个短任务、总计 78 ms、无 >50 ms 任务」,首批 16 张在 10–30 ms 内出现;展开中按钮变「全部折叠」,点一下即中断。
  • live 会话重放下限(15 s):静默轮询在 15 秒内复用上一次折叠结果,force=1(刷新按钮)与 timing=1 仍然全量重放。
  • 私密漏洞报告:启用 Private vulnerability reporting,并加了自定义表单 .github/VULNERABILITY_REPORT.yml(强制填插件/DSH/Windows 版本、复现步骤 ≥100 字、影响面)。

工程化

  • 新增 39 项回归(npm test,零依赖):引擎 7 + 解码 10 + 宿主路由/安全 14(同源 403、台账白名单、/api/open POST-only、400/404/405、未知路由 404)+ 缓存决策 8(精确 stamp / TTL 回退 / live 重放下限)。
  • UI harness 固化进仓库:npm run harness 起一个假 cordis + 合成台账的本地页面,跑真实 client.js,不再需要登录 GUI。
  • CI:Node 18 / 20 / 22 矩阵跑语法检查 + 全部回归;actions/checkout、actions/setup-node 升到 v7(dependabot 自动 PR)。
  • 仓库工程件:CHANGELOG.md、SECURITY.md、issue 表单、dependabot.yml、.editorconfig、.gitattributes(LF 归一化)。
  • 商店素材:docs/awesome-plugin-entry.yml、docs/icon-512.png(位图,列表拒收 SVG)、docs/social-preview.png(1280×640)、screenshots.json。

安装 / 升级

已有安装改成固定新版本即可(~/.dsh/profiles/<profile>/package.json):

"dsh-doc-ledger": "github:LuoShanHui/dsh-doc-ledger#v0.3.0"
node <runtime>/dependencies/pnpm/bin/pnpm.mjs install `
  --config.store-dir=<pnpm-store> `
  --config.confirmModulesPurge=false

然后刷新页面(客户端 bundle 需要重新注入)。完整步骤见 README 的「安装(插件形态)」。

兼容性

  • DSH >=0.2.0-rc.1 <0.3.0-0;Node >=18;仅在 Windows 上验证。
  • 两个宿主能力仍是可选依赖,缺失时自动降级:uiWorkspace.openSession(无则隐藏「跳转」项)、sidebarRight.openResource(无则退回自带弹窗)。

已知限制

  • 会话目录布局是隐式契约;exists 有 20 秒缓存;shell 间接产生的文件不算「创建」;混编编码是启发式;快速查看只给前 200 KB。详见 README 的「已知限制」。

测试

npm test    # 引擎 7 + 解码 10 + 路由/安全 14 + 缓存 8 = 39 项,无外部依赖

完整变更记录见 CHANGELOG.md。

v0.2.0 — 首个公开版本

Choose a tag to compare

@LuoShanHui LuoShanHui released this 06 Nov 08:33

每个会话一份文档台账:这个会话用过哪些文档、创建 / 修改了哪些,带时间排序、类型分组、搜索、跨会话汇总,以及两种预览入口。数据全部来自 DSH 自己的会话事件日志,不需要额外索引数据库。

overview

它解决什么

会话跑了很久之后,「我到底改过哪些文件」「上周那个会话看的是哪份 SQL」很难回答:日志里有 tool/call,但要一条条翻。这个插件把会话事件折叠成一张按文件聚合的清单,并按会话维度汇总。

  • 右侧 Sidebar 多一个「文档台账」tab,当前会话每 8 秒静默刷新;
  • 切到「全部会话」可以看到所有历史会话各自碰过什么,卡片式区分会话;
  • 行内直接预览 / 打开 / 定位 / 复制路径,不用离开面板。

功能

面板

  • 两种视图:当前会话(只算这一个)、全部会话(每会话一张卡片,可关掉「区分会话」合并成一张清单)。
  • 类型过滤:文档 / 表格 / 演示 / 图片 / 代码 / 网页 / 配置 / 数据 / 压缩包 / 其他,按实际分布显示数量,选择会记住;旁边是「已删除 N」临时开关。
  • 清除筛选:类型或「已删除」生效时出现,✕ 一键复位(搜索词保留),视觉上是「动作」而不是又一个 chip。
  • 搜索:文件名 / 相对路径 / 绝对路径 / 类型 / 会话标题,Ctrl/⌘+K 聚焦,150 ms 防抖,命中片段高亮。
  • 排序:每个分区独立,支持最近/首次使用、读取次数、创建/更新时间、写入次数、存在状态、类型、路径;点第二次切方向。
  • 拆分「创建 / 修改」:合并视图一键拆成「创建(n)」和「修改(仅改动)(m)」,互不重复。
  • 每行时间:建 11-03 14:20 · 改 11-04 09:12,跨年会带年份。
  • 已删除标记:磁盘上已不存在的文件变暗 + 标「已删除」,仍能读到历史记录(20 秒 exists 缓存)。
  • 长清单:分区超过 100 行先显示 100 行,「显示更多」每次 +100,不再无声截断。
  • 导出:复制 Markdown 表格 / CSV / 全部路径 / 摘要,范围是当前筛选后的清单。
  • 自动刷新:静默轮询,rev 指纹不变时完全不重渲染;快速查看打开、面板不可见、切到「全部会话」时自动暂停。
  • 状态记忆:排序、拆分、区分会话、类型过滤、会话条数上限写入 localStorage。
  • 性能取舍:卡片懒挂载(滚动到附近才建行)+「全部展开」按 8 张一批分任务,避免一次提交几千个节点。

预览

  • 默认交给 DSH 自带的文档预览:点行 → ctx.sidebarRight.openResource("dsh-resource://file/session/<id>/<path>"),由宿主分发给 8 种渲染器(text / markdown / html / image / pdf / office / excel / code),所以本插件不自带 Markdown 渲染和图片查看。
  • 快速查看(Shift+回车):插件自己的弹窗,专治「只想看原文」——
    • 编码按 BOM → 整体 UTF-8 → 按行 UTF-8/GB18030 二选一;实测老项目导出的 GB18030 SQL 从 4845 个 � 降到 0;
    • 正文上限 200 KB,被切断的多字节字符先削尾再判定;
    • 截断 / 解析失败以独立提示行显示,不混进正文;
    • 带 ETag,带 If-None-Match 的请求回 304。
  • 已删除的文件:宿主预览读不到字节,自动走弹窗并说明原因。

打开与定位

  • 打开方式:从注册表枚举这台机器为该扩展名注册过的全部程序(UserChoice → OpenWithProgids → OpenWithList → shell\open\command → 去重、去失效),默认项带标记。
  • 真实图标:从 exe 抽 ExtractAssociatedIcon 转 32×32 PNG,文件名是 sha1(exe+mtime),程序升级后自动刷新;磁盘缓存 + 内存 LRU。
  • 在资源管理器中显示:explorer.exe /select,<path>,并把窗口提到前台。
  • 选择其他程序…:走 Windows 原生「打开方式」对话框。

会话导航

在「全部会话」里右键会话卡片标题:复制会话名称 / 会话 ID,或跳转到这个会话(uiWorkspace.openSession,左侧对话区直接切过去,右边栏不动)。

静态报告(可选)

node tools/report.mjs --limit 40    # 生成 report.html,双击即可看,不需要安装插件

生成物含真实路径,已在 .gitignore 里。

安装

  1. 在 ~/.dsh/profiles/<profile>/package.json 的 dependencies 中加入:

    "dsh-doc-ledger": "github:LuoShanHui/dsh-doc-ledger#v0.2.0"
  2. 用 DSH 运行时自带的 pnpm 安装(<runtime> 换成你的运行时目录,<pnpm-store> 用已有 store):

    node <runtime>/dependencies/pnpm/bin/pnpm.mjs install `
      --config.store-dir=<pnpm-store> `
      --config.confirmModulesPurge=false
  3. 在 ~/.dsh/profiles/<profile>/cordis.patch.yml 末尾追加:

    # dsh-doc-ledger: per-session document ledger sidebar tab
    - insert:
        - id: doc-ledger
          name: dsh-doc-ledger
          config:
            maxSessions: 40
            debug: false
  4. 刷新页面(客户端 bundle 需要重新注入),右侧 Sidebar 出现「文档台账」。

验证:GET /doc-ledger/api/all?scope=all 返回 200 且有 sessions[];GET /doc-ledger/api/all?scope=current&session=<id>&timing=1 的 data.timings.total 通常 20 ms 内。

本地目录方式(想改代码时):git clone 后把依赖写成 "dsh-doc-ledger": "file:<path>/dsh-doc-ledger",其余步骤相同。

卸载:删掉那条依赖 → 用同样参数 pnpm install → 删掉 cordis.patch.yml 里的 insert 行。

兼容性

  • DSH >=0.2.0-rc.1 <0.3.0-0(package.json 的 dsh.compatibility.dsh)。
  • Node >=18。
  • 目前只在 Windows 上验证:注册表枚举、explorer.exe、PowerShell 抽图标都是 Windows 实现。
  • 两个宿主能力是可选依赖,缺失时自动降级、不会报错:uiWorkspace.openSession(没有就不显示「跳转」项)、sidebarRight.openResource(没有就退回插件自己的弹窗)。

性能(本机实测,34–43 会话规模)

手段 效果
?scope=current&session= 只算当前会话 613 KB → 19 KB,1.7 s → 15 ms
gzip + slimFile() 全量 613 KB → 31 KB
3 秒快照缓存 + rev 指纹 重复请求/轮询 ≈ 0 成本;rev 不变时 0 次 DOM 变更
日志 size+mtime 指纹 + 每会话台账落盘 冷启动全量 8.3 s → 0.9 s,关掉的会话永不重放
「全部展开」分 8 张一批 170 ms 阻塞 → 78 ms,无 >50 ms 的长任务
图标批量抽取(一次 PowerShell 处理 N 个) 6 个图标 1288 ms → 255 ms
预览 200 KB 上限 + ETag 大文件不爆内存,未改动时 304

安全模型

插件挂在回环端口,但回环不等于安全(任何网页都能向 127.0.0.1 发请求),所以宿主侧只认三条:

  1. 同源校验:Sec-Fetch-Site: cross-site/same-site、外部 Origin/Referer、Origin: null 一律 403;
  2. 只认台账里的路径:/api/file、/api/open、/api/openwith 只接受当前台账出现过的文件,C:\Windows\win.ini 这类返回 403;/icon 只接受存在的 .exe/.ico/.lnk;
  3. 启动程序必须 POST:/api/open 拒绝 GET,<img>、链接、预取都拉不起程序。

已知限制

  • 会话目录布局是隐式契约:指纹来自 ~/.dsh/sessions/<项目>/<会话 id>/session.v4.jsonl.zstd,布局变了会自动退回 TTL 失效(功能不受影响,只是变慢)。
  • shell 间接产生的文件不算「创建」:git diff > x.diff、PowerShell 重定向、解压这类没有路径参数的写入抓不到,只会因后续被读而出现在「使用过」。
  • 整文件写入即视为创建:不读直接覆盖已存在文件时会被记为「创建」(本机用文件出生时间反查过全部 43 个会话,0 例误报)。
  • 混编编码是启发式:UTF-8 文件里若恰好一行只剩单个坏字节,可能被读成「看起来正常」的 GBK;真正解不出的字节会如实标注。
  • 快速查看只给前 200 KB:完整内容请用「侧边栏」或「打开」。
  • exists 有 20 秒缓存:刚删掉的文件最多 20 秒后才显示「已删除」。

测试

npm test    # 引擎 7 项断言 + 解码 10 项断言

引擎(lib/ledger.js)与解码(lib/preview-text.js)都是纯函数、无依赖,回归脚本不依赖 DSH 运行环境。

反馈

Bug / 需求请开 Issue,附上 DSH 版本、平台和 /doc-ledger/api/all?scope=all&timing=1 的 timings 会快很多。

MIT License · 首个公开版本,接口跟着 DSH 走