Skip to content

Releases: fufuf-c/dsh-token

v0.9.6

Choose a tag to compare

@fufuf-c fufuf-c released this 22 Sep 11:32

主题:修 dsh 0.1.7-alpha.1 上"插件时好时坏、打开面板要等很久才出数"的根因 —— 宿主把遗留会话的 revision 换成了"文件身份 + 整库语料哈希",而本插件用 revision 当水位线,于是任一会话变动都让全部遗留会话失效、每轮整库重读。 无存储格式变更(STORE_VERSION 仍为 v8),升级不需要迁移动作;已在 0.1.7 上跑过的库第一轮就是零重读。

修复

  1. 水位线只认"本会话文件身份",不再受整库语料哈希牵连(lib/session-source.mjs)。宿主 @deepseek-ai/dsh-session-persistence-jsonl 0.1.7-alpha.1 起,list() 对 sourceVersion < 当前格式 的会话返回 <dev:ino:size:mtimeNs:ctimeNs>:<historicalCorpusRevision()>;后者是整库所有会话文件路径 + 各自 stat 身份的 sha256。旧实现在 scanStore 里直接做 wm.rev !== String(s.revision),粒度错配:
场景(70 会话 / 65 个 v3,仅改 1 个文件 mtime,内容零改动) 0.9.5 0.9.6
无变化的一轮 88 ms 88 ms
只改 1 个文件的 mtime 8 512 ms(changed=65) ~90 ms(changed=0)

而页面「进入界面时先扫描」(默认开启)意味着打开面板要等整轮扫完才出数据 —— 这正是"有时候不显示、过一会又能显示"。现在 ownRevisionToken() 只取前五段(文件身份);对新旧宿主都安全(≤0.1.6 本来就是五段,内存会话 memory:<n>:<i> 段数不足则原样返回)。

  1. 遗留会话的兄弟依赖改为精确追踪,而不是丢弃(同文件)。整库哈希原本承载的语义是"遗留会话解码时可能读兄弟文件"(宿主 prepareStoredMigration → children() 会读 origin === 'subagent' && parentSession === id 的子会话参与解码)。直接删掉这层依赖会让父会话在子会话变化后不再重折(数据静默少算)。新增 relatedFingerprints():按宿主真正读的那批文件算"父会话 id → 子会话 id+文件身份"指纹,并存入水位线的 rel 字段。于是子会话增删改只让该父会话重读,不波及别的父会话 —— 语义不弱于整库哈希,影响面从 O(全库) 收到 O(该父的子树)。

  2. 升级路径不会触发一次整库重读(同文件)。已在 0.1.7 上跑过的库里,水位线存的是六段形态(含整库哈希)。比较时对已存值与当前值都做归一化,所以升级后第一轮就是零重读,而不是把全部遗留会话判为"变了"。

  3. dsh.engines.dsh 补上 >=0.1.7-0(package.json / README.md)。按 SemVer 规则预发布不落在普通范围里:0.1.7-alpha.1 既不满足 >=0.1.5-rc.1 也不满足 >=0.1.6-0,旧声明把本插件实际支持并已在跑的 0.1.7 预发布判成不兼容(插件市场会据此显示"不兼容")。同时把 0.1.7-alpha.1 记进 compatibility.dshReleases。

测试

  1. test/v096-hostrev.test.mjs(V73–V73e)。用宿主 0.1.7 的真实 revision 形态(含"20 个会话共享同一语料哈希")锁住:任一会话变动只重读它自己;语料哈希变化本身零重读;老库六段水位线零重读;子会话变化只波及它的父;以及两个纯函数的边界。这四条行为断言在旧逻辑下实测有 4 条失败,不是事后补的空测试。

Full Changelog: v0.9.5...v0.9.6

v0.9.5

Choose a tag to compare

@fufuf-c fufuf-c released this 22 Sep 04:07

主题:补掉唯一一处"与改动量脱钩"的计算 —— 扫描收尾的聚合重建从"只要有会话变化就
整库重折"改成"只重折被改动的会话"。
无存储格式变更(STORE_VERSION 仍为 v8),
升级不需要迁移动作;重启后第一轮扫描走完整重建(与旧行为一致),之后进入增量。

性能

  1. 聚合收尾改为增量(lib/session-source.mjs 的收尾分支 + lib/core.mjs 的
    unfoldSessionInto / incrementalRebuildInto)。
    旧行为:dirty 为真就 rebuildAllChunked(全库) —— 代价 O(全库记录数),与"改了多少"
    完全脱钩,20 万请求的库改 1 个会话也要重折 20 万条(作者实测 447 ms)。
    新行为分三条路:

    情形 走哪条
    数据变了(会话记录被替换 / 删除 / 修剪) 增量:只重折被改动的会话
    改价格 / 高峰时段 / 保留期 整库重折(价格一改,每条记录的 cost 都过期)
    force 全量扫描 / 冷启动 / 聚合不可用 整库重折(没有"旧账"可减)

    端到端实测(真实 scanStore 路径,6 万请求 / 200 会话 / Node 24):

    场景 0.9.4 0.9.5
    无变化扫描 0.2 ms 0.2 ms
    改 2 个会话 66.6 ms(整库重折) 2.7 ms
    冷启动首扫 整库重折 整库重折(同路径)

    即"有变更的那一轮"约 25×,且库越大差距越大(O(改动量) vs O(全库))。
    两条路都会在 summary.aggMode 里如实报出 full / incremental / none,
    所以"这一轮到底重折了什么"是可观测的,不必靠计时猜。

    足量说明(别把这条读成"扫描不再花钱了")。 增量只省掉"重折"那一段;读取与
    折叠会话日志本身的开销一点没减 —— 变更的会话仍要被完整读出来并 foldSession。
    冷启动、force、以及任何改价的时刻仍是整库重折。本版没有做"日志的增量解码"。

  2. 等价性是硬门禁(test/v095-incremental.test.mjs 的 V67 / V67e)。
    增量与全量在 25 轮随机改动(追加 / 缩短 / 删除 / 新增四种混跑)后,days / months /
    逐记录派生字段与 sessions 必须逐值相同;查询与导出的 CSV 必须逐字节相同。
    一个补充口径:聚合桶里的汇总额允许 1e-9 元的浮点公差(浮点减法不可逆,实测末位
    差 ~1e-17),而四段用量与请求数是精确判定 —— 这个区别本身由 V69 锁定。

修复

  1. newRequests 统计虚高(lib/session-source.mjs)。此前是
    += 本会话全量条数,于是每次会话增长都把它整段再加一遍 —— 一个 3000 条的会话被改
    10 次就虚报 3 万。现在是净新增条数。自测统计失真比没有统计更糟:它看起来像个
    真实指标。

  2. 隔离清单在设置页从未渲染(web/src/app/80-tab-settings.js)。服务端一直把
    quarantinedCount / quarantined 放在 meta 里(README 也说"设置页可见"),
    但页面里一处都没用到 —— "有些会话统计不到"这件事对用户完全不可见。
    现在新增「数据完整性」一节:总数、每个被跳过会话的 id / 错误类型 / 命中次数 / 错误
    消息,并写明"保留上一次成功扫描的统计,不会静默清零"。超过服务端 50 条上报上限时
    显示"仅列出前 50 个 · 共 N 个"。错误消息来自宿主解码器,按外部数据处理并转义。

文档

  1. README 修正"改外观"指引。原文让用户改 web/src/** 后跑
    node scripts/build-web.mjs,但 package.json 的 files 只发 web/index.html ——
    web/src/** 与 scripts/** 不在包里(由 V49/V50 锁定)。npm / git / tarball
    三种安装方式下照做会扑空。已写明"这条只适用于 clone 仓库"。
  2. README 规模表补三行:有变更的扫描周期已改走增量(附上表实测数据)、
    store.json 体积随会话数线性增长(它每个脏周期整体重写,本机 64 会话约 32 KB)、
    以及 aggMode 可观测。

与旧版的行为差异(需要知道的三条)

  • cost / saved 的浮点末位可能与 0.9.4 不同(聚合桶汇总额吸附到 1e-12 元网格)。
    这是为了消除增量减法的累积噪声,量级远小于任何有意义的金额;逐记录 r.cost 不受影响。
  • days / months 的键顺序变为规范序(字典序,含 models / hours 二级字典)。
    数值不变;seriesQuery 的输出字段顺序因此稳定下来。
  • aggregatesNeedRebuild 现在会拦住"有 requests 但 days 为空"这个矛盾态,
    aggregatesReady 对它返回 false。此前它被认为是自洽的(真空库确实是),而改成按需重折
    之后这个中间态会一直留着,导致每个查询都拿到一张空账。

开发期工具(不进发布包)

  • scripts/bench-incremental.mjs —— 增量 vs 全量的等价性与性能对照(固定种子,可复现)。
  • scripts/bench-scan-e2e.mjs —— 走完整 scanStore 路径的端到端对照。

Full Changelog: v0.7.1...v0.9.5

v0.7.1

Choose a tag to compare

@fufuf-c fufuf-c released this 12 Sep 05:15

主题:把"抄一份值"改成"接宿主变量"。 0.7.0 及以前,面板的字体、字号、底色都是从宿主
样式里复制出来的固定值 —— 复制值今天看着对,但用户一改设置、或宿主一换主题就静默失效,
而界面仍然"看起来正常",没人会发现。

修复

  • 会话面板不再无视「外观」里的正文字号。 面板原来写死 font:15px/1.47,全文件不引用
    --dsh-content-font-size。会话区里 chat / conversation / tool / goal / workflow-run 等
    视图全部走宿主的字号变量,只有本面板不走。现在字号接 --dsh-content-font-size、行高接
    calc(24px + var(--dsh-content-font-delta,0px)),与相邻页签同一个口径。
    (影响:把字号设成 12px 的用户,面板从 15px 变为 12px/22px。)
  • 面板底色不再与相邻页签有色差。 原来写死 #000(暗) / #f2f2f7(亮);会话根节点
    (ConversationRoot) 实际画的是 --dsw-alias-bg-base(#151517 / #fff)。
    现在底色接该 token,--d-bg 退居兜底,切页签不再看到一整块异色。
  • 字体族改接宿主钩子。 面板与仪表盘页原来各自抄了一份字体栈(且两份不同)。现在都写
    var(--dsw-font-family, <DSH 的同一串 fallback>) —— --dsw-font-family 是 DSH 留给主题
    覆写的钩子,宿主换字体时两处一起跟随。
  • 仪表盘页的「自动」主题改为跟随 DSH 外观,而不是只跟随操作系统。 该页是独立文档,
    看不到宿主 DOM 上的 data-ds-dark-theme,因此由宿主在发送页面时注入
    window.__DSH_TOKEN_THEME__(读同一个 ui-theme 设置段)。此前当用户把 DSH 钉成深色而
    系统是浅色(或反之)时,仪表盘会和外壳反着来。
  • 外观偏好纳入页面缓存键。 页面缓存原来只按 (path, mtime) 失效;只改主题设置而不动
    页面文件时,注入的旧偏好会被一直发出去。现在缓存键含偏好,改设置立即生效。
  • 主题切换的提示文案由含糊的「跟随系统」改为说明实际来源(如「跟随 DSH(深色)」)。
  • 系统深浅变化的重绘收窄:DSH 把外观钉成浅色/深色时,系统深浅与本页无关,不再触发重绘。

测试

  • 新增两条宿主适配不回退断言:面板必须接宿主字体族/正文字号/底色,且不得再用 font
    简写写死字号。这两条会在有人把绑定改回固定值时直接失败。
  • 引用闭合检查的豁免从 --dsw-* 扩展到宿主的整个命名空间(含 --dsh-*,即内容字号这类
    外壳运行参数),并在注释里写清两个前缀各自代表什么。
  • e2e 新增两条:页面必须带注入的外观偏好引导脚本(且位于 <head> 内、先于页面自身脚本);
    只改设置、不动页面文件时注入值必须立刻换新。

说明

  • 无破坏性改动:三个入口(侧边栏 / 对话区页签 / 设置页)的名称、插槽与 API 契约不变,
    store.json 结构版本不变。
  • 侧边栏入口与设置页面板本来就正确使用 --dsw-alias-*,本次未改动。

Full Changelog: v0.7.0...v0.7.1

v0.3.1

Choose a tag to compare

@fufuf-c fufuf-c released this 30 Aug 16:26

DSH 本地 Token 用量统计插件——以 Token 为第一视角:不只回答"花了多少钱、用了多少量",还回答 Token 从哪来、缓存省了多少、哪些会话在烧 Token。数据全部来自本地会话日志,零上传、无在线依赖。仪表盘为 Apple 风格四 Tab 界面,开箱即用。

亮点

  • 四段 Token 构成:未命中 / 缓存命中 / 缓存写入 / 输出
  • 缓存省钱估算:命中量 × 未命中与命中的价差(核心差异化)
  • 全局筛选贯穿所有面板:时间 + 模型多选 + 会话 + 工作目录,URL 可分享
  • 会话下钻:四联统计、逐模型构成、逐请求明细、上下文增长曲线、🔥 异常激增标记
  • 成本与预算:模型单价表(¥/M)、月度预算环形进度 + 外推月底预估 + 80%/100% 阈值变色
  • 聚合快路径查询:日/月聚合索引(复杂度 O(天数)),10 万条请求库 kpi 25ms→1ms
  • 增量扫描,空闲零写放大:未变化会话按 revision 跳过,store.json 原子写
  • 保留期可配:retention.days 修剪超龄原始记录
  • 多模型叠加趋势图 + 图例独立开关 + 24 桶小时直方图 + 12 个月活跃热力图

安装

# npm(包名 @fufuf-c/dsh-token):
dsh plugin --profile web add @fufuf-c/dsh-token
# 或 Release 预构建 tarball(更快,无需本地构建):
dsh plugin --profile web add "https://github.com/fufuf-c/dsh-token/releases/download/v0.3.1/fufuf-c-dsh-token-0.3.1.tgz"
# 装完安装依赖并重启
cd ~/.dsh/profiles/web && pnpm install
dsh web

MIT License · 零依赖 · 数据全部本地存储