Skip to content

Releases: bonerush/dsh-obsidian-mem

dsh-obsidian-mem v2.0.2

Choose a tag to compare

@github-actions github-actions released this 03 Nov 15:18
  • 面板 UI 两处修复:刷新图标改用 lucide rotate-cw;热力图末尾月份标签不再被裁掉。
    lib/client.js 的 ICONS.refresh 是手绘弧线(9 单位半径 + 6 单位箭头),与相邻的
    lucide rotate-ccw 不一致;现换成同表 rotate-cw(顺时针孪生,同 5 单位箭头)。
    lib/memory-panel.js 新增 HEAT_MONTH_TAIL = 24:月份行 .mem-heat-months 原先
    宽度恰为 gridWidth 且 overflow:hidden,当月份从最后一列开始时(窗口在月初结束,
    例如 2026-11-03)标签 left = gridWidth − 10,只剩 10px,而中文 "11月" / 英文
    "Nov" 约 22px,尾部被裁成 "11";现在 canvas 与月份行各预留 24px,网格列与 tooltip
    锚点几何不变(tooltip 的居中偏移由同一个 canvasWidth 推导)。
    • 证据:先红后绿——回退 lib/client.js、lib/memory-panel.js 后
      node --test test/panel-ui.test.js test/panel-client.test.js 5 项失败(新增回归
      与 4 项宽度断言);应用修复后同一命令 122/122 通过,六个 panel 测试文件
      192/192 通过。新增断言覆盖:refresh svg 的两段 path 等于 rotate-cw、末列月份
      标签 left = gridWidth − 10、月份行宽 gridWidth + 24、每个标签在行内至少留
      24px,以及以 2025-11-02(周日)开始、止于 2026-11-07 的 371 天 fixture 让
      "11月" 落在最后一列。

dsh-obsidian-mem v2.0.1

Choose a tag to compare

@github-actions github-actions released this 03 Nov 14:56
  • embedding warm 现在可中断、可恢复,并按请求耗时自适应批大小。
    lib/embedding-store.js 的 sync 每完成 8 个顶层批或距上次写盘 30s 就增量
    checkpoint,只序列化已有向量的笔记;失败时先把已嵌入的进度写盘再抛错,重跑按内容
    hash 复用,因此一次中断不再丢掉整次 warm。rank() 每次读 snapshot(),所以 warm
    进行中即可用上部分向量。新增导出纯函数 nextBatchSize(current, elapsedMs)
    (收缩到目标 2800ms、增长 +1,钳制 4–16);任何 provider-timeout 都会先把下一批
    减半再二分,避免继续硬碰 5s 上限。1404 条真实 vault 的 warm 实测超时率
    17.8%(24/135)→5.7%(18/318)、请求放大 1.22×→1.06×。

    • 证据:node --test test/embedding-store.test.js test/architecture.test.js test/hybrid-recall.test.js test/retrieval-provider.test.js 48/48;
      npm run check exit 0(pack 契约 92 entries / 82 lib modules)。
      test/architecture.test.js 的 embedding-store 预算从 370 提到 500(实测 434 行 +
      30 行注释空间)。测试覆盖超时收缩与恢复增长、checkpoint 后重跑跳过已嵌入项、首个
      checkpoint 之前中断也能保存进度、显式 batchSize 不漂移。
    • 未验证:warm 总墙钟不可与基线 489.7s 直接比较——度量时宿主 MPS 有效算力从
      ~1.5 降到 ~0.6 TFLOPS,所以只报告结构性指标;不同 Apple 芯片与内存压力下的绝对
      耗时没有测。
  • 新增本地 Qwen3-Embedding 参考服务工具包 tools/embed-server/(不随 npm 包发布)。
    用标准库 HTTP 服务实现 2.0.0 的回环 provider 契约:官方 query 指令前缀、last-token
    pooling、按文本长度排序分块、SDPA 注意力、客户端断开后中止剩余分块(修复「客户端
    5s 超时放弃的请求仍在服务端占锁与算力,导致重试级联超时」)、/health 上报
    attention/queryInstruction。含幂等的 setup.sh(uv venv、模型下载、LaunchAgent
    安装)与记录实测数字的 README。

    • 证据:分块按长度排序使代表性 16 文本载荷的 forward token 数从 6388 降到 5136
      (−19.6%,向量逐条一致);chunk 2/4/8/16 扫描决定 4;--attn 交错 A/B 中位数
      mixed16 eager 12.155s vs sdpa 11.076s、单长文本 1.144s vs 0.937s;前缀 A/B 在
      22 条 paraphrase 上 MRR 0.828(开)vs 0.773(关),30 条标题自检索 0.950 vs
      0.961,故默认开启并保留 --no-query-instruction 开关;kill -9 后 launchd
      0.27s 重新拉起、/health 5.74s 就绪,bootout 后搜索降级为
      fallback: "provider-error",bootstrap 后 2.7s 恢复且无需重新 warm。
    • 未验证:绝对耗时随宿主负载漂移较大,README 只承诺相对收益;前缀结论来自单个
      vault 的 22+30 条小样本,换 vault 需重新 A/B。

dsh-obsidian-mem v2.0.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 05:32
  • 破坏性变更:retrievalEngine 的默认值从 lexical 改为 hybrid。 语义检索通道
    现在默认在引擎上开启。retrievalProvider 仍然默认关闭且为空——每个字段描述的是运维
    自己的本地服务,插件不会替你凭空造一个——所以没有任何 provider 配置的默认行,读的
    仍然是原样的 lexical 路径
    :services.search 识别出「hybrid + provider 未启用」这一
    对组合并直接走 lexical 的单次查询(不是 searchHybrid 配一个缺失的 runtime,那会白付
    HYBRID_LEXICAL_LIMIT 的宽候选窗口并给数组挂上 hybrid 字段),返回值与 1.0.7 逐字节
    相同。状态不静默:search 诊断事件报的是配置要求的引擎 hybrid 加
    fallback: provider-disabled,所以运维能从诊断窗口看出「配置没有生效、为什么」。

    • 兼容性分类:retrievalEngine 是 1.0.0 起承诺的配置键之一,默认值属于该承诺的一部分,
      因此按 SemVer 走主版本号。六个 mem_* 工具名与参数、vault 协议(指针文件、frontmatter、
      skill)都没有变化。
    • 反过来,AMD 前的旧配置显式写着 retrievalEngine: lexical 或 sparse 时行为完全不变,
      升级不会改动既有行的语义。
    • 这一对默认值不再在配置加载时报错。1.0.7 里 hybrid 配未启用的 provider 会抛
      RangeError('retrievalProvider.enabled');既然它现在是出厂默认行,那个拒绝就必须撤掉,
      否则插件装不上。仍然拒绝的是「provider 打开了但不能用」:非回环 endpoint、空白 model、
      非正整数 dimensions,由 validateProviderConfig 在加载时就抛错。
    • 证据:node --test test/config.test.js test/services-hybrid.test.js test/hybrid-recall.test.js test/hybrid-search.test.js test/search-engine.test.js
      69/69 通过。test/services-hybrid.test.js 新增一条「the shipped default row reads
      lexically and says why」,钉住三件事:validateConfig({}).retrievalEngine === 'hybrid'、
      validateConfig({}).retrievalProvider.enabled === false、以及默认行的命中数组
      retrievalEngine/hybridFallback 都是 undefined(证明走的是纯 lexical 路径)、
      而诊断是 engine: 'hybrid' + fallback: 'provider-disabled'。test/config.test.js
      的默认值字面量与「hybrid 需要启用 provider」那条改成「默认这一对必须能加载」。
    • 未验证:没有 provider 的真实升级路径(从 1.0.7 装好的现有 vault 升级到 2.0.0)只做了
      离线验证,没有在真实会话里跑过一轮;「默认行逐字节等于 1.0.7」是对 searchNotes 的
      调用参数与返回数组结构做的断言,不是对真实 vault 的逐字节比对。
  • recall 闸门增加校准过的语义分支:hybrid 融合排名前三的候选,只要 dense 分数 ≥ 0.92,
    即使 token 命中数只有 1 也可通过闸门并注入摘录。
    词法闸门只认字面重叠,会把融合与
    向量都判为高信的候选拒掉;新分支只对带 semantic-score/hybrid-rank 信号的 hybrid 命中
    生效,token 分支与 lexical 默认路径完全不变。阈值按 e5-small 校准,换模型需重标。

    • 证据:同一冻结 200 条语料,接受面 +16 个 top-3 槽位、其中 9 条相关;gate pass
      24.6%→27.9%、in-gate precision 39.8%→41.8%、no-answer FPR 5.0% 不变、P@3 61.25%
      不变;指代类第一次拿到注入(8 条、5 条相关,类内精度 62.5%)。阈值敏感性:
      0.90 在 e5-small 上 gate pass 40.0% 但精度降到 36.5%,0.88 时 FPR 升到 62.5%,
      0.94 只剩 40.3% 精度且指代无新增。node --test test/prompt-recall.test.js 15/15;
      相关 8 个测试文件 156/156 通过。
    • 未验证:真实会话里这条分支的触发频次;dense-only 命中注入的摘录是正文前 160 字、
      不是查询居中的 ±60 字符窗口,生产注入文案未做 A/B。
  • 可选的 hybrid 检索引擎:FTS5 词法候选 + 本机回环 embedding 语义候选,按加权 RRF
    融合;默认关闭,关闭时读路径逐字节保持原样。
    retrievalEngine: hybrid 必须同时
    retrievalProvider.enabled: true,endpoint 只接受回环地址,model/dimensions
    决定向量文件,timeoutMs 限 50–5000,rerank 键仍保留但 hybrid 排序当前不使用
    重排。向量存 <dataRoot>/index/embeddings-<vaultHash16>-<modelHash16>-<dim>.json:
    按笔记内容哈希增量同步,损坏、维度不符或换模型时整份重建,写入原子化、无临时文件
    残留;provider 失败时回退 lexical,并在 diagnostics 的 search 事件记录 fallback。
    lib/hybrid-search.js 的 adaptive guard 在标题/短语命中或 token-hits ≥ 8 时保留
    lexical 顺序。

    • 证据:冻结 200 条语料 + 1361 条笔记快照,P@3 44.4%→61.25%、P@1 32.5%→43.1%、recall@8 53.6%→68.6%、MRR 39.2%→52.3%;五类 P@3 全部
      持平或上升(exact 96.9 持平、paraphrase 53.1→84.4、concept 37.5→59.4、
      cross-lingual 15.6→21.9、deictic 18.8→43.8);node --test test/config.test.js test/retrieval-provider.test.js test/embedding-store.test.js test/hybrid-search.test.js test/hybrid-recall.test.js test/services-hybrid.test.js 全绿。
    • 未验证:真实会话里的触发率与 900 字符注入预算;e5-base/768 没有任何报告;
      rerank 路径未接入 hybrid,rerank: true 不改变混合排序。
  • recall 增加第三态 near-miss:语义接近但没有过闸门的候选只注入一行弱提示,
    不带正文摘录。
    条件是 dense-only 候选的 semantic score ≥ 0.88 且 hybrid rank
    ≤ 3,且通过与 useful() 相同的路径/索引/热层/状态资格检查;提示恒为一颗标题行
    加一句“需要时用 mem_read 核实全文”。diagnostics 的 recall outcome 新增
    near-miss。

    • 证据:node --test test/prompt-recall.test.js test/diagnostic-codec.test.js
      24/24 通过(含“恰好一行、不含 snippet”与“0.87 或 rank 4 不注入”两条)。
    • 未验证:真实会话里 near-miss 的出现频次;语料评测只复算闸门,不回放注入文案。
  • 短追问把上一轮用户提示词作为 dense query 的上下文。 lib/hooks.js 只在会话
    状态里记住最近一次提示词(2000 码点,dense 侧再截 400),不写盘、不进日志;
    lexical 分支完全忽略它,因此关闭 provider 时行为不变。

    • 证据:test/hooks.test.js 的 “a short follow-up carries the previous prompt as
      dense context” 通过。
  • token 查询不再整表扫描 notes_fts:过滤列加一元 + 前缀、显式 bm25 列权重
    (10, 1, 4),让 SQLite 走 FTS 索引计划。
    旧的带项目/状态过滤的 FTS 查询被规划成
    MULTI-INDEX OR,随后对整个虚拟表 SCAN 计算 bm25(同一条 SQL p50 202.5ms;无过滤时
    1.82ms),是召回延迟的主因。源码校验同时按 VERIFY_CONCURRENCY = 16 分批并发,窗口
    填充集合与串行逐条一致。

    • 证据:40 条查询 lex8 p50 233.7ms→24.3ms、p95 268.9→57.5;冻结语料 lexical
      p50 22.3ms / hybrid 121.2ms;质量指标逐位不变(lexical P@3 44.375%、hybrid
      P@3 61.25%);200 条 token 查询新旧 statement 的路径列表 0 差异;test/search.test.js
      新增 EXPLAIN QUERY PLAN 断言(不含 MULTI-INDEX OR、含 notes_fts 虚拟表索引),
      改动前失败、改动后 39/39 通过。并发校验只把 lex8 p50 压到 19.0ms(n=40,单机单次)。
    • 未验证:其它 SQLite 版本的查询计划未逐个测量;并发校验在慢盘/网络盘上的收益未测。
  • recall 闸门的 token 分支从至多 4 个 token 命中提高到 6 个;标题/短语分支不变。
    旧闸门在 hybrid 候选上通过 47.1% 的 top-3 而只有 27.9% 精确率、no-answer 控制项
    32.5% 被放行;新阈值(6 个命中,floor 仍为 3–4、取二者较大)把接受面收窄到真正有
    字面证据的候选。Phase 2 只改接受/拒绝,不改排序。

    • 证据:同一语料 hybrid in-gate precision 27.9%→39.8%、no-answer FPR 32.5%→5.0%;lexical 20.1%→33.8%、50.0%→2.5%;两份报告的 P@1/P@3/
      recall@8/MRR 与各自旧闸门版本逐位相同。node --test test/prompt-recall.test.js test/architecture.test.js 全绿。
    • 延迟(2026-11-03 复测):冻结语料上 hybrid p50 从 444.6ms 降到 121.2ms,Phase 1
      验收的 350ms 绝对上限已满足;但同一轮修复把 lexical 自身从 233.4ms 降到 22.3ms,
      于是「≤ 1.5× lexical」的相对说法不再成立(hybrid 约 5.4×,差的 ~99ms 是每次查询一次
      回环 embedding 往返)。两项都记录在
      docs/validation/retrieval-latency-and-semantic-gate-2026-11-03.md;不宣称相对达标。
  • 诊断窗口补齐召回漏斗:新增 search 事件,recall 带 accepted/injected,brief 的 injected 事件带 chars。
    过去只能看到召回的结果状态,无法区分「闸门接受了几条」「最终注入了几条」「简报注入多少字符」;
    mem_search 更不产生任何事件,评估时读不到工具侧检索。现在 lib/debug.js 的事件白名单加
    search(落在 skill 与 recall 之间)、FIELDS 加两个非负整数字段;lib/services.js 的
    services.search 计时并记录 ok/failed 后原样返回或重抛;lib/prompt-recall.js 的每个
    决策携带 accepted/injected;lib/hooks.js 落库两个计数与简报字符数。事件仍然内容无涉:
    不记录 query、路径或标题。

    • 证据:node --test test/debug.test.js test/prompt-recall.test.js test/diagnostic-codec.test.js
      35/35 通过;test/tools.test.js 41/41;test/hooks.test.js 64 通过、唯一失败是
      lib/services.js 架构预算(1,920→1,968 行),预算 1,950→2,000 并注明换来的行为;
      test/architecture.test.js 8/8;完整套件 npm test:1,505 项、1,504 通过、0 失败、1 跳过(197 s)。
    • 未测:新增事件与字段尚未在真实会话的诊断窗口里采到样本(本轮改动未提交,诊断环仍是
      33 run / 3,219 events 的旧窗口);等 Phase 1 在真实会话上复核。
  • 三个模块的尺寸预算按实测抬升:lib/note-health.js 300→400、lib/vault.js 1800→1850、
    lib/curation-scan.js 1350→1450。
    分别由行内代码链接审计(344 行实测)、非 git 祖先指针
    (1,809 行实测)、deadline 先于 manifest 遍历(1,392 行实测)带来,沿用「实测 +30 向上取整
    到 50」的既有规则;理由写在 test/architecture.test.js 的预算表注释里,包括每条增长换来的
    行为,而没有新增模块或层。

    • 证据:node --test test/architecture.test.js 8/8 通过。
  • 证据(整套门禁):npm run check 退出码 0——lint、format:check、types 通过,测试套件
    1,549 项 1,548 通过 / 0 失败 / 1 跳过(161.3 s),verify-pack 与真实 tarball 校验通过
    (92 个条目 / 82 个 lib 模块)。

  • 慢模型(如 e5-base/768)首次 embedding 预热不再必然超时:超过 provider 时限的批次会
    递归二分到能在时限内返回的切片。
    默认批大小 16,1200 码点正文在 CPU 上约 5.4s/批,
    超过 timeoutMs 允许的 5000ms 上限,e5-base 因此永远 warm 不出来。
    lib/embedding-store.js 只在 provider-timeout 且切片大于 1 时二分,单条仍超时就如实
    报错,batches 只统计成功请求。

    • 证据:node --test test/embedding-store.test.js 15/15;新增「timed-out batch is
      bisected」与「timeout on a single text is reported」两条;e5-base 预嵌入 1361 条
      笔记 171 批、423s 完成,同一 harness 上 P@3 62.5%、in-gate 40.0%、FPR 2.5%。
    • 未验证:其它慢模型的实际批大小与收益未逐个测。
  • 链接目标本身引用行内代码的活链接不再被误报为 dead-wikilink。 noteLinkAudit 原来先用
    proseWithoutCode 把行内代码整段抹成空格、再从抹过的行里抽 wikilink,于是目标里带代码的
    链接会被打残成不存在的路径:真实 vault 中 Conventions/index.md:87 指向
    …/绝不替用户修改配置文件(含 `$DSH_HOME cordis.patch.yml`).md 的链接(文件存在)、
    Inbox/index.md:36 与 Decisions/index.md:40 的同形提案都是这样产生的,curation 会把它们
    当成待处理的断链。现在 lib/note-health.js 增加 proseLines()、inlineCodeSpans() 与
    insideSpans(),审计逐行扫原文、只跳过开口 [[ 落在代码 span 内的匹配,目标取原文;
    proseWithoutCode 仍只服务语言检查,输出不变。

    • 证据:node --test test/curation-scan.test.js test/lint.test.js 54/54 通过。新增用例
      「a live link whose target quotes inline code is not read as dead」在改动前失败
      (actual ['Projects/p/Conventions/含 的约定'])、改动后通过。
  • 非 git 目录树的子目录会话复用祖先指针,不再静默分裂成第二个项目。 resolveBinding
    过去只在 cwdReal 精确位置读 .obsidian-mem:在 root 做过 bind local 之后,从
    root/src 开的会话拿到 no-git-root 并提示再绑一次,照做会铸出第二个 projectId
    (实测 root 7bbe7fa3-… 与 src 19ada2c8-… 两个 id),同一目录树的记忆被拆成两半。
    现在 lib/vault.js 新增 findPointerRoot(),镜像 findGitRoot() 从 cwd 向上找最近的
    指针:最近祖先优先、不跟随 symlink、损坏的指针也采纳(目录本身就是绑定证据);无 git 根时
    resolveBinding 改用它,fork/retain 也作用于持指针的 root,损坏祖先指针报精确的
    pointer-* 而不是被吞成 no-git-root。探测只做 lstat,读路径绝不铸新指针,真正未绑定的
    目录仍照旧拒绝。

    • 证据:node --test test/binding.test.js 73/73 通过(66 条基线 + 7 条新增,新增用例中
      6 条在改动前失败);test/lint.test.js 33/33 通过。git worktree 的绑定语义未变,
      1.0.7 的两条回归保持通过。
  • 索引就地修复一条过期候选后重新应用检索过滤,被编辑出范围的来源不会再泄漏一次。
    verifyCandidate 会重新解析一条源文件已变的候选并回写,但它只重查 status,没有重放
    matchesFilters:一条被改成 superseded 的约定会在重新索引的那次搜索里仍被返回、下一次
    搜索才消失——一次性泄漏。现在候选把 plan.filters 带进校验,回写后若不匹配即返回 null;
    候选窗口本来就是用旧缓存事实选出的,这个重查补的正是那段时间差。

    • 证据:新增 test/search-source-eligibility.test.js 3 条(默认搜索不再返回改为 superseded
      的笔记、includeHistory 仍可见;type 改变后旧 type 下消失、新 type 下可见;项目移动后
      旧 scope 下消失、scope='all' 可见),改动前 3/3 失败(actual
      ['Projects/elig--5f1b2d3c/Pitfalls/race.md']),改动后通过;配套检索套件 36/36 通过,
      加 test/search-engine.test.js 47/47 通过。
  • 搜索的截断事实穿过 service 与工具边界,mem_search 现在返回 truncated、
    truncationReason、candidateWindow、rowsExamined、candidatesScored。
    索引层早就把
    这五个 non-enumerable 事实挂在命中数组上,但 lib/services.js 的 hits.map(toHitView) 与
    lib/tool-registry.js 的 { hits } 把它们丢光:被候选窗口截断的搜索看起来和完整成功一样。
    现在 lib/tool-schema.js 导出 SEARCH_FACTS 与 searchEnvelope()(以 Array.from 复制出
    干净数组,再把存在的字段放进信封——带 non-enumerable 属性的数组不是宿主 lossless-JSON
    快照接受的“未装饰”数组,直接透传会被判 returned invalid output);services.search 用
    projectHits() 让 service 边界保留这些事实,mem_search 返回信封,Codex MCP 适配器同样
    改用 searchEnvelope(),否则 JSON 序列化会静默丢弃。schema 把这五个字段列为可选,因为
    ...

Read more

dsh-obsidian-mem v1.0.7

Choose a tag to compare

@github-actions github-actions released this 02 Nov 09:33

Fixed

  • 非 git 目录 bind local 后跨会话写入不再报 no-git-root。 resolveBinding 原来在
    读指针之前就按「没有 git 根」拒绝,而 mem_write 走只读探针(mode: 'show')永远拿不到
    bind local 已写出的 .obsidian-mem,已绑定的 scratch 目录于是在后续会话永久只读。
    现在拒绝前先探测 cwdReal/.obsidian-mem:有既有指针就采纳、没有照旧拒绝;探测只采纳、
    绝不铸新指针。fork/retain 保持原 git worktree 语义。新增回归测试
    test/binding.test.js「a non-git directory with an existing pointer stays bound on the read path」。

dsh-obsidian-mem v1.0.6

Choose a tag to compare

@github-actions github-actions released this 02 Nov 04:15

Added

  • 图谱默认按记忆类型上色,采用一组莫兰迪(灰调低饱和)配色。 颜色组不再默认为空:
    决策 [type:decision] #7b8ea6、约定 [type:convention] #8ba084、踩坑
    [type:gotcha] #ab817c、文档 [type:doc] #b39b6f、术语表 [type:glossary]
    #9a8aa0。这五组是普通颜色组,查询、色块、删除与「恢复默认设置」都按既有行为处理,
    渲染器与 matches() 没有新分支;管理笔记(hub/hot/session-log/method)、未分类笔记
    和未创建目标继续用主题中性色,悬停与记忆调用仍是强调色。填充对比度按主题节点底色
    实测:深色 4.89–6.22:1、浅色 2.48–3.15:1——莫兰迪灰调在浅色下低于 WCAG 文本 4.5:1,
    类型识别同时由颜色组查询与筛选保留。色值、取色过程与中性色清单见
    docs/obsidian-graph-source.md 新增的「2026-11-01 — 按记忆类型的莫兰迪默认色组」
    一节;README 双语图谱段落同步更新。

Changed

  • 图谱设置记录版本升到 2,v1 记录整条失效一次。 v1 的默认颜色组是空列表,而读取时
    分不清「旧的空默认」与「用户把色组删光了」;不升版本,新的按类型预置会被旧记录盖住。
    升版本后旧记录回落到新默认值一次,下一次写入起按 2 保存;此后在同一版本内删空色组
    仍然是删空,刷新不会复活。

  • lib/client.js 的尺寸预算由 1700 抬到 1750 行(实测 1,711 行,按「实测 + 30 向上
    取整」的既有规则),理由写在 test/architecture.test.js 的预算表注释里:新增的是五组
    预置与其说明注释,渲染路径没有新增代码。

  • 证据:node --test test/graph-settings.test.js test/panel-client.test.js 44/44 通过
    (新增一例真实渲染 GraphCanvas、读它交给渲染器的 model.colors,钉住五个类型各自的
    颜色与 hub/untyped/unresolved 的 undefined;英文控件测试改为先断言五组预置、再断言
    新增组排在其后;graph-settings 的默认值与版本断言同步到 v2,并补「v1 记录被丢弃」
    「删空色组保持删空」两例)。完整 npm run check 退出码 0:lint、格式与类型检查通过,
    1,480 项测试 1,479 通过 / 0 失败 / 1 跳过,verify-pack 与真实 tarball 校验通过
    (89 个条目 / 79 个 lib 模块)。

Fixed

  • 图谱四个控件图标改用 Obsidian 自带的 lucide 图形,不再是手绘近似版。 18px 下四个
    按钮原来互不成比例:齿轮是 12 齿折线多边形,且 viewBox 写成 0 0 24 28,实际只画
    约 14.75×15px、位置偏下;魔杖路径的笔尖与左端压在 viewBox 边界上,描边被裁掉;复原
    箭头的箭尾是 8 单位直角,lucide 原形是 5 单位(十字本来就与 lucide x 同形,随整组
    重写、视觉不变)。现在 lib/client.js 的 ICONS 直接使用 Obsidian 桌面版图标表里的
    settings/x/wand-2/rotate-ccw 四条 path/circle 数据,icon() 支持形状列表,
    四个图标统一回到 24×24 网格;描边仍是面板既有的 1.7(与 DSH 自己的图标线宽一致,不改
    成 Obsidian 的 2)。逐项问题、提取过程与代价见 docs/obsidian-graph-source.md 新增的
    「2026-11-01 — 图谱控件图标改用 Obsidian 自带 lucide 图形」一节。

  • 证据:node --test test/panel-client.test.js 35/35 通过。新增一例从真实渲染的
    GraphView 取四个 graph-controls-button,断言 viewBox 统一 24×24、齿轮为一个 path
    加 r=3 圆、十字两条路径、魔杖八条路径、复原是弧线加 M3 3v5h5 箭头;该测试在改动前
    失败(settings draws on the 24px grid),改动后通过。另用 headless Chrome 按面板
    真实的 18px、Retina 2x、深色底渲染改动前后对照图 /tmp/icon_compare.png,4× 放大下
    折角、裁切与箭头尺寸问题消失。

  • 概览「活动热度」的日历年居中,不再在宽侧边栏里靠左。 日历是固定宽度的画布(371 天
    = 54 列 × 12px 列距 − 2px 间隙 + 14px 星期槽 = 660px),放在占满面板宽度的横向滚动框
    里;框比画布宽时块级元素默认从左边排,右侧留出一大片空白,看起来像图表被钉在一边
    (2026-11-01 用户截图)。现在 lib/client.js 的 .mem-heat-canvas 用
    margin-inline:auto 让 CSS 分配剩余空间:宽面板左右各分一半,窄面板自动外边距归零、
    保持原有的贴右可滚动行为,不引入 JS 测量。列宽/画布宽的计算同时收进
    lib/memory-panel.js 的 heatCalendar()(heatmap() 与悬停提示共用),悬停提示的
    锚点加上居中偏移,否则提示会偏到悬停格左侧。

    • 证据:node --test test/panel-ui.test.js test/panel-client.test.js 121/121 通过。
      新增一例以 800px 面板、660px 日历挂载真实 OverviewView,断言画布 width:660px、
      悬停首日 tooltip left:89px(70px 居中偏移 + 14px 星期槽 + 5px 半格);该测试在改
      动前先失败('71px' !== '89px',测试替身的滚动框不 clamp scrollLeft,修复方式见
      docs/validation/heatmap-centering-2026-11-01.md)。另用真实样式表在 headless
      Chrome 里量:1368px 面板下画布 offsetLeft 由 0 变 354px(左右自动边距各 354px);
      348px 窄面板下仍为 0,且 scrollWidth 660 > clientWidth 348 保持可横向滚动;
      对照图 /tmp/heat_center.png。

dsh-obsidian-mem v1.0.5

Choose a tag to compare

@github-actions github-actions released this 31 Oct 17:43

Fixed

  • test/pack.test.js 的 npm 可用性探针在 Windows 上必然误判,导致真实归档契约用例被跳过。
    探针直接 spawnSync('npm', ['--version']):Windows 上 npm 是 npm.cmd,无 shell 的
    spawn 报 EINVAL,于是 npm 12.0.2 已装好的本机也被判成「npm 不可用」,
    the archive this checkout really produces satisfies the contract 一直 skip ——
    而同一份解析早在 1.0.1 就改成了「用本 Node 跑 npm-cli.js」(scripts/verify-tarball.mjs),
    只是测试里另写了一份。现在探针复用已导出的 npmCommand(),并新增一条用例钉住
    「探针走本 Node 的 npm JS 入口,不 spawn .cmd」。
    • 证据:修复前整仓套件 1,475 tests / 1,440 pass / 0 fail / 35 skipped(其中一条就是它);
      修复后 test/pack.test.js 在本机 Windows 上 27/27 通过、0 skip,真实归档用例
      耗时 1.8 s 并打印 verify-tarball: OK … 89 entries, 79 lib modules。

Changed

  • Windows 兼容验证第 2 轮:全量门禁、面板布局与图谱性能在 Windows 上实测;除上面那条
    测试探针外没有发现产品缺陷。
    本机 Windows 11(10.0.26220)+ Node v24.20.0 + npm 12.0.2
    • 真实 Chrome 156.0.8078.74:
    • npm run check 全绿:1,476 tests / 1,442 pass / 0 fail / 34 skipped;
      verify-pack 与 verify-tarball 均 OK(89 entries / 79 lib modules);
      scripts/build-graph-worker.mjs --check 输出 graph worker assets: current。
    • 面板三个视图(概览 / 检索 / 健康)× 中英 × 明暗 × 300–760 px 九个宽度 × DPR
      1 / 1.25 / 1.5 / 2:432 个真实 Chrome 状态、0 布局违规 —— 无页面横向滚动、无元素
      越出视口;371 天热度图 53×7 格(10×10、列距 12)、月标签 0 重叠;KPI 宽屏单行
      space-evenly、≤559 px 2×2;構成桑基铺满实测块宽(320 px 中文 292、760 px 732,
      英文窄屏按设计横向滚动);健康卡片 figure 网格空槽 0;DPR 变化时关键盒宽差 ≤0.5 px。
      字体解析为 Segoe UI;唯一被截断的是 CSS 明写 ellipsis 的 .mem-result-title。
    • README 里「Windows 上 >2,000 节点的性能未测」换成本机实测:1,236 节点真实规模
      中位 12.8 ms/tick(p95 16.2 ms)
      ,2,500 节点 28.8 ms、4,000 节点 50.7 ms、
      6,000 节点 99.9 ms —— 与 0.4.4「为 1:1 复刻 Obsidian 付 quadtree 碰撞代价」的已知
      取舍一致,不是本轮新缺陷;中英两半同步改写,README.i18n.yaml 的 blob hash 一并重记。
    • 34 条 skip 全部是平台能力缺失或既有 opt-in(14 file symlink EPERM、10 expect/pty、
      8 NTFS mode/ACL、1 /dev/fd、1 MARKETPLACE_PROBE_LIVE),没有一条为绿而跳。
    • 证据:docs/validation/windows-compat-2026-11-01.md;测量产物在 scratch/win-round/
      (已 gitignore,不入库)。

dsh-obsidian-mem v1.0.4

Choose a tag to compare

@github-actions github-actions released this 31 Oct 16:07

Changed

  • 语言切换按钮改用翻译图标,不再印 EN/ZH。 两字母徽标读起来像「当前是什么
    语言」的状态标签,而不是「点它会切到哪一个」的动作;现在画的是常见翻译标记(文/A 组合,
    Material translate 的实心路径,16px),title 与 aria-label 仍然写明目标语言
    (英文界面 Switch to Chinese、中文界面「切换到英文」),按钮仍是 28×28 的方形热区,
    与刷新按钮同高对齐。外壳与三个视图的语言行为本身不受影响。

Fixed

  • 关键数字条的四格按内容宽度分配空白,不再等宽四等分。 等宽时每格内容各自居中,
    但读数宽窄差很大:第一条带着 120px 的折线,最后一条 "0 个" 只有 29px。实测 593px
    面板下整条墨迹左边空 25px、右边空 69px,看起来既没居中、左右空隙也不一致。改为
    display:flex; justify-content:space-evenly:每格宽度由自身内容决定,剩余空白在格间
    与两端平均分配;代价是宽布局里去掉了 1px 竖分隔线(格宽不等时它们会落在不均匀的
    位置),改由空白分组。559px 及以下仍折成 2×2 等宽网格并恢复分隔线。证据:headless
    Chrome 用真实样式实测 593px 中文左右各 46.67px、英文 35.86/35.88px;560/570/600/
    640px 四个宽度的格间距与两端空隙逐项相等(误差 <0.03px),
    scrollWidth-clientWidth 全为 0。
  • 健康页三张数字卡片的内容居中,短行不再露出灰色空格。 固定三列网格在项数不是
    3 的倍数时,空出的格子会露出网格容器的边框底色:热层数字(2 项)右侧 1 个灰块、
    今日摘要(4 项)第二行 2 个灰块。现在 figures() 把项数写进 data-columns
    (≤4 项时一项一列铺满,6 项仍是 2 行 3 列),单元格内容从左上对齐改为居中。证据:
    headless Chrome 实测三张卡片 holes 均为 0(索引 3 列×2 行、热层 2 列×1 行、摘要
    4 列×1 行),每格文字左右墨迹差 <0.03px;559px 及以下摘要的 4 列回退为 2×2。
  • 证据:DSH_HOME=$(mktemp -d) node --test test/panel-client.test.js test/panel-ui.test.js
    118/118 通过(断言更新:KPI 条含 flex/space-evenly、折线显式 120px 与
    max-width:100%、三张卡片的 data-columns 为 3/2/4、figure 单元格居中、折叠规则
    改为第 2/4 格的左边线与第 3/4 格的上边线并含 4 列→2 列回退;原有中文断言未改)。

dsh-obsidian-mem v1.0.3

Choose a tag to compare

@github-actions github-actions released this 31 Oct 13:49

Added

  • 面板内可以切换界面语言,真实浏览器默认英文。 标签条右上角新增语言按钮:英文界面
    显示 ZH(提示 Switch to Chinese),中文界面显示 EN(提示「切换到英文」)。
    点击后外壳与三个视图立即换语言,选择写入 localStorage 的
    dsh-obsidian-mem:locale,下次打开沿用。语言仍是中英两种:没有 localStorage 的
    环境(node --test、旧宿主)保持原来的 navigator 探测与中文兜底,所以既有中文断言
    不需要改写。侧栏标签页的标题与描述在插件注册时确定,切换语言后需刷新页面才更新;面板
    内部立即生效。
  • 英文界面的排版与漏翻补齐:
    • Activity 热图的星期栏在英文下留 32px(Mon/Wed/Fri 不再压住第一列色块),中文
      仍是 14px;画布宽度、月份行偏移、网格列宽与 tooltip 锚点用同一个宽度。
    • Composition 桑基按本次实际打印的英文标签测宽(Convention、Superseded 等),
      图表放进 .mem-sankey-scroll:窄面板下横向滚动看完整文字,而不是把标签截成
      Con…。中文列宽保持原来的 34/38/36/40,几何与既有断言逐字不变。
    • 健康页热层分区的三个标准区名翻成英文(强约束 → Strong constraints、进行中 →
      In progress、已完成 → Completed),与 lib/panel-copy.js 的对话框用词一致;
      用户自定义区名是数据,原样保留。

Fixed

  • 搜索框在上下空隙中垂直居中。 .mem-searchbar 的 padding 由 14/10 改为 16/8:
    加上视图区的 8px 上内边距后,搜索框上方 16px、下方 16px,不再偏上。

  • 健康页不再重复标题。 外壳的健康标签页把 onMeta 传给视图,页面不再在搜索框下面
    再印一个「健康 / Health」标题;独立渲染(无 onMeta)仍保留标题,概览页的既有门控
    行为不变。

  • 热图月份行滑到星期栏下方时不再露出半截。 星期栏的遮罩过去只和网格同高,
    横向滚动后月份标签会从 Mon/Wed/Fri 上方探出半个字。现在给 .mem-heat-weekdays
    加一个向上 14px 的同色伪元素(::before,与月份行同高),遮罩正好盖住整条月份行,
    中文标签只在星期栏右侧出现。中文 14px 与英文 32px 的星期栏通用,布局与网格尺寸未变。

  • 证据:DSH_HOME=$(mktemp -d) node --test test/panel-ui.test.js 85/85 通过(新增 4
    条:英文热图 gutter、英文桑基测宽与滚动、组合健康页的中英标题门控);同法
    test/panel-client.test.js 32/32 通过(新增 5 条:默认英文、点击切换并持久化、
    存储优先、renderer 随语言重建、居中与滚动条 CSS);test/architecture.test.js
    8/8 通过(两个越界文件的预算按实测行数 +30 向上取整后抬到 4300/1700,理由写在
    预算注释里)。中文行为与 1.0.2 逐字节一致,test/panel-ui.test.js 原有 81 条与
    test/panel-client.test.js 原有 27 条断言零改动通过(唯一调整是「只有热图横滚」的
    断言改为同时承认桑基的滚动容器)。

dsh-obsidian-mem v1.0.2

Choose a tag to compare

@github-actions github-actions released this 31 Oct 09:55

Added

  • 英文界面:面板、图谱外壳与健康操作的对话框都能按系统语言显示英文,默认仍是中文。
    只新增一份英文文案,没有引入新的运行时或开发依赖;中文文案与改动前逐字节一致,
    所以既有的中文断言不需要改写。语言解析集中在新文件 lib/locale.js:
    • 解析顺序:请求体 locale → 请求头 Accept-Language →(浏览器内)
      navigator.languages / navigator.language → 兜底 zh。显式 zh 赢过英文
      请求头;fr-FR 这类既非中英的明确偏好显示英文(界面只有两种语言,英文是唯一
      能跨语种的兜底);* 不算偏好——Node 的 fetch 默认就发
      accept-language: *,把它当成英文会让不带偏好的请求凭空变英文。
    • 面板(lib/memory-panel.js):概览 KPI、热图/流量条/树图/桑基、健康、最近
      变化、检索结果、操作单与确认/预览全部按 locale 取词;createMemoryViews({ React, locale }) 可显式传入,未传时在浏览器里按 navigator 探测;每个 POST body
      都带 locale,面板自己决定语言,不让路由被宿主浏览器的请求头改掉。
    • 外壳与图谱(lib/client.js、lib/graph-renderer.js):标签页、搜索框、错误
      与空状态、通知、图谱设置/筛选/滑块、画布 aria-label 与 worker 失败文案中英
      双语。这两个资产由路由按文件原样送出,运行时不能 import,所以语言规则在各自
      文件里内联一份;无 window 的环境(node --test)固定回中文,既有中文断言
      不变。
    • 服务端对话框(新文件 lib/panel-copy.js,lib/panel-actions.js 与
      lib/panel-route.js 接入):重试失败任务、整理热层、发布项目摘要的标题、按钮、
      字段、效果与警告按请求 locale 取英文;中文副本与改动前逐字节同一份。
    • 证据:DSH_HOME=$(mktemp -d) node --test 定向套件全绿——test/locale.test.js、
      test/panel-route.test.js、test/panel-actions.test.js、
      test/panel-client.test.js、test/graph-renderer.test.js、
      test/panel-ui.test.js;真实路由 seam 上,body 的 locale 胜过英文请求头、
      只有 Accept-Language: en-US 得英文、两者都没有得中文、只有 * 得中文。
      整仓 npm run check 全绿:1467 条测试 1466 pass / 0 fail / 1 skipped,verify-pack 与
      verify-tarball 均 OK(归档 89 entries、79 lib modules,与 AGENTS.md 记录一致)。独立
      验证(scratch/i18n-verify.md)另跑了真实路由与真实视图探针:route 导出与 HEAD 全等、
      默认中文渲染文本逐串等于 HEAD、en 三视图与预览/确认单无汉字;唯一发现的空
      "最近变化" 中文硬编码已修复并补了回归测试。
    • 未验证:真实桌面侧栏在系统语言为英文时的自动探测没有在真实 Electron 窗口里
      点过(浏览器探测只有 DOM 级测试);README 中英两半和 README.i18n.yaml 未改,
      因为用户明确说 README 已有双语、不必处理。

dsh-obsidian-mem v1.0.1

Choose a tag to compare

@github-actions github-actions released this 31 Oct 07:16

Fixed

  • CI 的浮动 node 平台不再被 npm 12 的 npm pack --json 输出形状打红。 该平台实际装的是 Node 27.0.0-alpha.0.0.0 + npm 12.1.0;npm 12 把这个输出从数组 [{…}] 改成按包名索引的对象 {"dsh-obsidian-mem": {…}},而 scripts/verify-tarball.mjs 原有的 const [packed] = JSON.parse(run.stdout) 对对象解构会抛 object is not iterable,于是 the archive this checkout really produces satisfies the contract 断言 2 !== 0、job 退出 1(run 41176291759)。这不是 1.0.0 引入的:0.4.4 的推送在同一平台上已因同一原因红(run 41093967549)。现在 parsePackReport(stdout) 同时接受数组与按包名索引的对象两种信封,并且只接受恰好一个归档记录:0 个或多个都抛出带数量的错误,不再静默挑一个;真实打包与归档检查路径不变。
    • 证据:在隔离目录安装 npm 12.1.0、用假 node 布局实测本仓库 npm pack --json 返回 isArray false、keys ["dsh-obsidian-mem"]、files 87;同一布局下 scripts/verify-tarball.mjs 输出 87 entries, 77 lib modules, every required asset present,node --test --test-name-pattern='archive this checkout' test/pack.test.js 通过;npm 11(本机默认)的同一命令与完整 npm run check 也通过。test/pack.test.js 新增两条纯函数测试:两种信封得到同一记录;0 个、2 个、缺 filename 的记录全部被拒绝。

Changed

  • README 的 DSH 支持范围改为实际支持的范围。 需求表此前只列 0.1.5-rc.2 与 0.1.7-rc.2 两个"已验证"版本,读起来像其余版本未获支持;现在写明下限 >= 0.1.5-rc.2、当前版本 0.2.1-rc.5,以及两者之间的每个版本都受支持(每个中间版本都对照插件实际使用的行内 config: 与 Cordis 接缝核查过,没有发现不兼容)。面板段落的环境同步为当前实测组合:DSH 0.2.1-rc.5 + dsh-better-sidebar 0.28.1。中英两半同改,README.i18n.yaml 的 blob hash 一并重记。