Repository navigation
Releases: cfanzx/dsh-compact-relay
Release list
0.5.5:已收藏星标常亮
dsh-compact-relay 0.5.5
0.5.4 的 debug 版:修用户反馈「收藏后星标自动消失」。只改客户端样式注入,收藏数据 / 后端 / 推荐逻辑零改动。测试 396 → 398 PASS。
根因
星标挂在宿主助手消息的 hover 动作行里。宿主 CSS 对 [data-actions-reveal="hover"] 的行默认 opacity:0,:hover/:focus-within 才恢复——收藏后星标仍在 DOM、aria-pressed=true,但整行透明,鼠标一移开就看不见。不是收藏丢失、也不是 0.5.4 回归。
修法
注入 CSS :has():只把「含已收藏星标的 hover 动作行」强制可见;非 hover / 非键盘焦点时,同行其它按钮与同 slot 的其它插件按钮保持隐藏且 pointer-events:none → 常亮的只有已收藏星标本身,hover/focus 时完整动作行照常出现。选择器只用稳定锚点([data-actions-reveal="hover"]、slot 名),不依赖宿主哈希类名;触屏不生效;不支持 :has() 的旧浏览器自动回退。
行为
- 已收藏消息:鼠标移开 → 金色星标常亮;hover → 复制/赞/踩/分支/用量等完整出现
- 取消收藏:立即恢复宿主原 hover 隐藏行为
- 未收藏消息:行为完全不变
npm / GitHub main f325748 + tag v0.5.5。
0.5.4:0.5.3 debug(建议候选/无正文标题/压缩后建议清理)
dsh-compact-relay 0.5.4
0.5.3 的 debug 版:只动收藏/推荐两处数据面与预览卡文案,压缩主流程零改动。测试 391 → 396 PASS。
修复
- D1 建议候选过滤工具角色:「建议先收藏」只保留用户/助手消息,工具结果的报错堆栈不再占名额(
suggestPinCandidates的 limit 先于角色过滤,工具占满时用同一函数对用户/助手事件重跑,不新写识别);已收藏列表不过滤,工具输出仍可手动收藏。 - D2 无正文标题兜底:预览收藏条目里「(无文本)」显示为「第 条」,可按序号找回;摘要的收藏目录口径不变。
- D3 压缩后清理推荐建议:收到
compaction/summary/compaction/end立即清空本会话建议、取消待跑去抖、用世代号作废在跑打分——被压走的消息不再残留在/favorite suggest与星标建议上;压缩后新回合照常产生建议。
其他
- 版本 0.5.4;npm / GitHub main
c634852+ tagv0.5.4;Mac 已同步(Win 随本版一起同步)。
0.5.3:收藏(pin 退役)+ 推荐收藏 + 预览卡补收藏
dsh-compact-relay 0.5.3
从 0.5.2(e4bd0b2)拉出的分支 fix/0.5.3。主题:收藏(pin 退役)+ 推荐收藏,外加真机验证带出的 P2 语义修正。
收藏:把「标记」和「落档」彻底分成两步
- 标记:点星 /
/favorite mark [序号]//favorite last,只写项目级 JSONL 一行{op, sessionId, seq};不依赖活 agent(归档/关闭的会话也能按 seq 标)。 - 落档:只在压缩时发生——摘要追加「收藏(本段)」目录 +
~/.dsh/dcr-favorites/snapshots/<链根id>.md快照;压缩后补标会当场写快照兜底。 - 压缩预览卡补收藏区:确认卡显示「本段 N 条 · 已收藏 M 条 · 建议补 K 条」,列出已收藏条目([用户]/[助手]+标题)与「建议先收藏」候选,每条可一键收藏(含用户发言);只提示,绝不自动收藏。
- pin 退役:压缩不再按 pin 裁剪,
/pin仅保留只读兼容。
推荐收藏
- 每条助手回复异步打分(flash/关思考/temp0,0-100,8s 超时,失败不亮);三档阈值 60/75/85(默认标准 75)+ 必亮/屏蔽词。
- 星标金色光晕 + 「推荐」标签,只点亮不自动收藏;设置页可调开关/档位/词表,并支持「试算」。
P2 语义修正
force-archive的 already 判断先于 confirmStop(已归档不带确认 → 200 already);已归档+确认时补跑 stopActivity 防漏杀。- 错误码分档:未知会话 404 / 宿主缺接缝 503 / 内部失败 500。
force-archive/recover响应改archivedCount+newlyArchived/newlyRecovered(不再回全量归档集合)。
其他
- 测试 375 → 391 PASS;契约帧新增
favorites/favoriteSuggest/ 预览favoritePreview。 - 已验证:npm
dsh-compact-relay@0.5.3,Mac 真机(压缩快照链路 / 推荐点亮 / 预览卡收藏 / UI 一致性)。
dsh-compact-relay 0.5.2 — 缓存对齐 + 强制归档 + 契约快照
0.5.2(2026-10-28)
缓存对齐:摘要/交接单调用改为沿用主请求的 reasoningEffort,不再固定 off;宿主 thinking 开关不再切断前缀缓存——隔离 A/B 命中 74.0% → 96.9%,生产真实压缩 2–5% → 99.7%。输出上限 8,192 → 16,384 兜住思考输出。
契约快照 + record 构造收口:新增 test/contract-golden.mjs(readState 帧 / 父子 record 键序 / 标题格式)与 lib/core/relay-record.js(父子写点只传语义参数,字节级不变)。
强制归档旧会话:接力条菜单新增「强制归档旧会话(会停止后台任务)」,二次确认 + 置顶确认(confirmUnpin);服务端 action:'force-archive' 必须 confirmStop:true,是唯一 stopActivity:true 调用点。默认行为不变:交接的自动归档仍不强制、不停任务。
修复:交接预览九段草稿框被 flex 压成 0 高(flexShrink:0)。
契约新增(全部 additive):readState.parentPinned、readState.capabilities.forceArchive;action:'force-archive'。
测试 340 → 375 PASS。完整变更见 CHANGELOG。
v0.4.1 — 原生压缩线显示口径统一
修复:原生压缩线显示口径不一致(设置页仍写 80%,指示灯写实际触发 67.8%)
- 现象:0.4.0 把指示灯/悬停卡改为「实际触发线」(DSH 按
min(窗口×thresholdRatio, 窗口−输出预留−headroomTokens)触发),但设置页的「作用 / 调整后 / 原生阈值」三处和「指示灯怎么看」教学卡仍按thresholdRatio显示 80% —— 同一插件两处数字互相矛盾,而且设置页那句「80%:DSH 会自己压历史」本身是错的(实际 67.8% 就压)。 - 修复:客户端抽出纯函数
nativeLineInfo()(实际线优先;给出配置阈值、实际触发点与差异原因);设置页三处 + 教学卡刻度/文案 + 指示灯悬停卡统一为「实际触发 X%(配置阈值 Y%)」,并说明「模型输出预留 + DSH 自身余量」使实际触发更早;交接提醒线上限也改用实际触发线(原按配置 80% 算,允许把交接线设在实际触发点之后、永远走不到)。 - 不改:宿主计算、触发条件、压缩/交接行为;纯显示文案与校验上限。
- 验证:Mac 真机(0.4.1 客户端):设置页与悬停卡同显 67.8%(678.5K / 1.00M,deepseek-flash),配置阈值 80% 作为注释保留;交接线上限随实际线收紧。
显示层补强(dev-god 独立审查后,同属 0.4.1)
- 关闭态空数字:
autoEnabled=false时原生线信息原本连「实际会触发多少」一起丢,设置页会出现「原生阈值 %」、确认弹层出现「容量到 %」。现在关闭态显示「配置 80%(已关闭;开启后实际触发 67.8%)」,恢复确认也用实际值。 - 差异归因:
why只在「预算分支确实更小」时才归因为输出预留/余量;modelPolicies路由覆盖改说「该模型单独配了阈值」;实际触发晚于配置阈值时不再套用「理论上限」说法(原实现会自相矛盾)。 - 交接线遗留值:设置页对「已保存交接线 > 实际触发线」给出显式提示(不静默改写);交接线输入上限与保存口径统一(按实际触发线向下取整)。服务端保存校验仍以配置阈值做上限(防呆不阻断),本版仅在 UI 收紧并提示如何调整。
- 文档口径:README badge / README.en 同步到 0.4.1 与实际触发线说明;ROADMAP 标注已失效参考仓库。
- 测试:
test/native-line.mjs新增nativeLineInfo行为回归(正常/关闭/算不出/路由覆盖/实际晚于配置五组输入,从客户端源码切出函数真跑)。
v0.4.0 — 接力质量(判断机制 / 诊断包 / 保留契约 / 账本)
小版本:接力质量——判断机制加强(cue v2 + 注入门控 + 计量)、脱敏诊断包、pin 保留契约、压缩/交接轻账本、交接预览两段可编辑、接力链元数据、原生自动压缩真实触发线;并修复 BUG-013(压缩/交接后旧 compressHint 从未失效,0.3.1 起存在)。
修复:压缩/交接后「压缩判断记录」从未失效(BUG-013,0.3.1 起存在)
- 问题(真机发现,2026-10-24):压缩/交接后旧的
compressHint本该自动失效(环上断点消失、不再抑制 cue),实际一直判定「有效」。P0-1 上线后真机诊断包里counters.cueInjected=0的直接原因就是它——旧 hint 的 ratio(26.4%)高于当前 ratio(18.5%),ratio - hint.ratio < 10%的 hint 抑制规则把 cue 全部挡掉;指示灯环上也残留旧断点(26%)。 - 根因:
lib/actions/state.js调lastCheckpointSurfaceSeq(session)时漏传第二个参数isCheckpointSource;lib/dsh/session-view.js里对undefined调用判定函数抛 TypeError,又被事件循环里的 try/catch 吞成「不是 checkpoint」→ 永远返回 -1 →checkpointSeq = undefined→compressHintIsActive(hint, undefined)恒为 true。(对照:lib/dsh/select-range.js传参正确,所以选段/不二压一直正常。) - 修复:①
state.js显式传deps.engine?.isCompactCheckpointSource;②session-view.js的lastCheckpointSurfaceIdx/lastCheckpointSurfaceSeq给isCheckpointSource加默认值engine.isCompactCheckpointSource(dsh→dsh 同层、显式传参优先;纯 node 单测不注册 DSH 包解析钩子时安全降级为「无 checkpoint」,不抛);③ 回归测试加进test/state-passive.mjs(旧 hint + 更新的 checkpoint →compressHint: null;hint 比 checkpoint 新 → 保留)。 - 影响面:只影响「判断记录新鲜度」的显示与 cue 抑制;不改压缩/交接行为、不改拒绝条件、不动 client。此 bug 自 0.3.1 起存在,随 0.4.0 修复(不回溯 0.3.6)。
P2-3 原生自动压缩「真实触发线」(按路由容量算,不再只显示窗口比例)
- 问题:指示灯一直把
compaction-basic的thresholdRatio(默认 80%)当触发线显示,但 DSH 实际按 token 数触发:thresholdTokens = floor(min(W × rate, W − 输出预留 − headroom)),触发点 =thresholdTokens / W。当路由请求给输出预留较多或headroomTokens被改过时,真实触发点会明显低于 80%(作者在 Windows 真实会话里问过「原生压缩线为什么降到了 50」)。 - 修复:新增
lib/core/native-line.js(纯函数,公式与 dsh-compaction-basic 源码一致);lib/dsh/native-compaction.js增读config.headroomTokens(默认 65536)与嵌套modelPolicies(按 provider+model 精确覆盖thresholdRatio/headroomTokens,支持列表与映射两种 YAML 写法;BUG-012 保持:嵌套值不会变成全局线);lib/dsh/pressure.js新增routeBudgetOf():输出预留 =session.requestHeader().config.maxTokens ?? 适配器 defaultMaxTokens ?? 0,窗口复用llm.resolveModelInfo缓存;readState的native新增ratio/thresholdTokens/contextWindow/reservedCompletionTokens/headroomTokens/overridden/route/unavailable(thresholdRatio仍下发生效比例,老客户端可回落;算不出时ratio=null + unavailable=原因)。 - 客户端:环上原生刻度/越线闪烁改用真实线;悬停标题显示
原生自动压缩线 X%(thresholdTokens / 窗口,provider/model,按路由覆盖);首次引导文案同步。 - 测试:
test/native-line.mjs(公式 80% vs 67.8%、边界/无预算、解析与 BUG-012 回归、路由覆盖匹配、readState 下发与老字段兼容);并入npm test。 - 不改任何触发/拒绝条件,只改「显示与数据」;版本仍 0.3.6,未发布。
P2-1 交接预览「两段可编辑」(只允许 约束 / 下一步)
- 预览接口新增
editable: { titles: ['约束','下一步'], maxChars: 4000, note, sections }与ordinal(第 N 次交接);客户端交接预览卡只给这两段 textarea(data-cr-handoff-edit),其余段只读并显示「程序生成段不可改」。 - 确认时客户端只提交「用户真的改过且非空」的段;宿主在压缩/写盘前校验:非法字段(程序生成段 / 拼错段名 / 非对象)→
code='edits'(HTTP 400,消息点名不能改的段);单段 >4000 字符拒绝(不静默截断);空值/未改回落重新生成的原文。应用方式:生成九段后覆盖这两段再渲染(composeHandoffText仍按九段固定顺序),程序段永远来自程序/模型。 - 九段结构不变;必须用户点「确认交接」才写盘(预览/校验过程不写盘)。action 路由 body 上限从 8KB 放宽到 48KB(容纳两段编辑)。
- 测试:
test/handoff-p2.mjs(白名单/空值/超长/非法字段/九段顺序/客户端入口静态守卫)+test/handoff.mjs集成(编辑后交接单落盘内容生效、程序段被拒且零副作用、空编辑回落)。
P2-2 接力链元数据补全
- relay 记录 canonical 字段补齐:
parentId/childId/ordinal/at(ms)/atIso(本地 ISO);0.3 旧字段parentSessionId/index继续写入,读侧兼容旧记录并补齐 canonical 字段。 - 链式序号:首次交接
ordinal=1;从子会话继续交接ordinal=2且parentId指向真正父会话;下一次交接标题序号改用ordinal推导。 - 交接单头新增
- 交接序号:第 N 次交接(预览草稿里也能看到);接力链视图留 0.5,不做。 - 测试:
test/handoff-p2.mjs(canonical/旧记录兼容)+test/handoff.mjs(首次 ordinal=1 + 文档头、链式第 2 次 ordinal=2 / parent 正确)。
P1-3 压缩/交接可审计流水(轻账本)+ 设置页累计数字
- 新增轻账本
~/.dsh/compact-relay-ledger.jsonl(JSONL,一行一条,schemadcr-ledger/v1):每次压缩/交接成功后追加一条——kind、本地时间、耗时 ms、压前/压后 tokens + ratio、腾出 tokens、pin 命中(inRange/total)、交接单落盘路径(仅路径)与childId;交接内部那次压缩不重复记账(一次/handoff一条)。 - 隐私:allowlist 构造,只记数值/枚举/时间/路径,不含消息原文、摘要、交接单正文、sessionId、cwd/用户名;测试用敏感 fixture 断言产物中不存在。
- 有界与降级:只保留最近 200 条(超限整文件重写为最近 200 条,tmp+rename 原子替换);文件损坏按行跳过;任何读写失败静默返回
{ok:false},绝不影响压缩/交接本体(测试覆盖:账本 record 抛错时交接仍成功;账本路径不可写时动作照常、文件损坏仍可读可写)。 - 设置页:
GET /api/compact-relay-settings(含保存/恢复默认响应)新增ledger累计字段(count/compactCount/handoffCount/freedTokens/avgDurationMs/lastAt),设置页「关于与危险操作」显示一行累计:已压缩 X 次 · 交接 Y 次 · 腾出约 Z tokens · 平均耗时 W;无记录时显示引导文案。数字与账本文件同源(测试断言相等),不做大盘。 - 新增
test/ledger.mjs(字段完整 / allowlist + 敏感 fixture / JSONL 容错 / 上限裁剪 / 不可写降级 / 设置数字一致 / 客户端累计行静态守卫)+test/handoff.mjs压缩与交接成功后的账本落盘断言 +test/plugin-load.mjs设置端点累计断言;并入npm test。 - 不改压缩引擎/拒绝条件/阈值;版本仍 0.3.6,未发布。
P1-1 压缩预览「建议锁定」提示(只提示、不自动锁)
- 预览接口新增
preview.pinSuggest = { count, items: [{seq, role, reason, snippet}] }:宿主侧纯本地启发式(lib/core/pin-suggest.js)对「本次将被压掉的历史」识别三类信号——明确要求别改(用户消息里「不要改 / 别动 / 保持原样 / 必须保留」等)、报错堆栈(异常类名 / 堆栈帧 / 堆栈 / 报错等)、关键决策(决定 / 拍板 / 采用 / 改用 / 结论等);最多 5 条、每条一句摘要 ≤60 字符、不贴全文;短句、系统消息、运行时合成的 user/message(checkpoint 等)、普通工具输出不进入候选。 - 客户端预览卡只渲染「建议锁定 N 条(先 /pin 再压)」+ 每条理由/摘要;绝不自动锁定(预览不写任何会话事件,测试断言
session.log不变)。/bc预览 message 里也带一句建议。 - 收敛实现:消息角色/摘要抽取挪到
lib/core/pin-anchors.js,/pin list、建议锁定、交接单锚点共用一份(删除actions/pin.js内私有previewOf)。
P1-2 pin 作为「保留契约」(声明与展示,不承诺第三方引擎)
- 交接单九段结构不变:锚点写进程序段「当前进度」——
- 锁定锚点(保留契约,接手者请原样保留这些消息)+ 每条seq N · 角色 · 「一句摘要(≤60 字符)」(最多列 10 条,其余提示/pin list看全)+ 一行「跨引擎压缩器是否遵守取决于其实现」。 - 压缩预览新增
preview.pinHits = { inRange, total }:inRange= 本次候选范围里被锁定保护而跳过的条数,total= 会话仍活着的锁定总数;客户端预览卡显示「pin 命中 N 条」并区分范围外锁定。 - 不回归:锁定消息仍在压缩范围之前截断(
clipRangeByPins既有逻辑),压缩后原样保留在 surface。 - 测试:新增
test/pin-contract.mjs(候选识别含反例、建议条数/上限、交接单锚点、pin 命中数、预览只读不自动锁)+test/handoff.mjsA1b 预览断言补锚点;并入npm test。 - 边界:只做「声明与展示」,不承诺其他压缩器遵守 pin;不改压缩引擎/拒绝条件/阈值;版本仍 0.3.6,未发布。
P0-1 判断机制加强(未发布,代码已落地,待 3 次真实任务验收)
- 背景(BUG-010 后续):Windows 173 个真实会话里 cue 注入 18 次、
mark_compress_point调用 0 次;Mac 仅在「脚本写完 + 真机验证通过」这种明确节点自发调用过。归因:旧 cue 的「不确定就不用调」让模型倾向保守跳过、工具描述强调拒绝风险、每轮注入变成背景噪声。 - cue 文案 v2(
lib/core/compress-cue.js):把抽象「自然节点」换成 4 个可自检的完成信号——功能已实现并验证 / 文档已交付 / 问题已定位并修复 / 准备交接;明确「不确定也建议调一次让工具判断:被拒绝不会改动历史、不影响会话」;保留「不处于阶段收尾就不用管」边界,删除「不确定就不用调」。 - 注入门控(
lib/adapters/prompt.js+lib/core/policy.js常量CUE_MIN_RATIO=0.10/CUE_MAX_RATIO=0.40/CUE_MIN_TURNS=3):只有全满足才注入——① 容量落在[max(10%, 动态最小线), min(40%, 压缩线))(到压缩线不注入,避免诱导注定被拒的调用);② 距上次注入 ≥3 轮(按 text 回调调用次数计,进程内 Map、不新增持久状态、不落盘);③ 一轮内最多一次。异常/无 agent/无缓存行为不变(返回空串)。 - 工具描述 v2(
lib/adapters/tool.js):明确「用户和模型都可以调用」;「被拒不需要致歉、不会改动历史、也不影响会话,不需要重试」;补充典型调用时机(阶段完成 / 准备交接前 / 长任务中途确认可回退点);把「不需要每个小步骤都调用」弱化为句尾的「小步骤不用调用」。 - 计量接入(
lib/dsh/diag-counters.js、lib/actions/compress-hint.js、lib/adapters/prompt.js):新增cueInjected/markCalls/markAccepted/markRejected四个计数(被拒也算调用)。只记次数与结果、不记 cue 原文/任务内容(隐私口径与 P0-2 一致);P0-2 诊断包的counters与 Markdown 直接带出这四个数 → 真实使用后看数字即可判断「标准 B:3 次真实任务 ≥2 次模型自发调用」,不用翻会话日志。 - 测试:
test/compress-cue.mjs重写覆盖 U1(文案 v2:4 信号 + 被拒无副作用 + 不含旧措辞)、U2(区间 0.08 不注入 / 0.12 注入 / 0.40、0.45 不注入 + 第 4 轮再注入)、U3(无 agent 不注入 / 同轮不重复 / 异常降级)、U6(5% 桶 / 动态最小线 / hint 抑制 / state-hub 原有断言随 v2 同步);test/smoke.mjs增 U4(markCompressHint 成功/被拒计数 + 不变式);test/plugin-load.mjs增 U5(工具描述关键词)+ cue 门控下的 20% 注入断言;test/diagnostics.mjs同步 counters 白名单/渲染。 - 范围红线(未违反):不改压缩/交接行为、不改拒绝条件(最小线 5% / 压缩线 40% 不动)、不自动动作、不动指示灯客户端、零新依赖零网络、版本号仍 0.3.6。
- 未完成(发布前):需 3 次真实长任务验证标准 B;soak 记录模板已补「判断机制读数方法」。
P0-2 诊断包最小版(已完成)
- 新增「诊断信息」入口(设置 → 压缩接力 → 帮助):【生成并预览】在本机生成一份 Markdown + JSON 诊断信息,弹层里先预览,再【复制 Markdown】/【复制 JSON】;【打开问题报告页】打开预填版本/平台短字段的 GitHub issue 页。不做任何自动上传、遥测或后台外发,也不加网络能力。
- 新增只读端点
GET /api/compact-relay-diagnostics?sessionId=:沿用宿主connection.requestRejection鉴权(401/403);只支持 GET(非 GET 405);无活动会话时state: null;返回{ok, schema, version, generatedAt, markdown, json, issueUrl},响应不含正文/堆栈(失败只回短文案)。 - 新增
lib/dsh/diag-counters.js:进程内计数/耗时/错误码(重启清零)。压缩/交接成功失败计数、最近 20 个耗时样本的 p50/p95、按(code, phase)聚合的最近 20 条错误码(只收 code/phase/at/count,不收 message),锁定动作计数。 - 新增
lib/dsh/diagnostics.js:dcr-diagnostics/v1产物构造。allowlist 逐字段取值(禁止整对象透传),产物只含数值/枚举/布尔/错误码;JSON ≤ 64KB、errors ≤ 20 条且单条 ≤ 200 字符;额外正则脱敏(GitHub token /sk-/ Bearer / cookie / 邮箱 / 绝对路径 / 内网 IP / session id 等命中替换为[REDACTED],只记数量不保留原文);issue URL 只预填短字段、长度 < 7500。 - 埋点(不改行为与文案):
actions/compact-run.js与actions/handoff.js记成功/失败/耗时/错误码;actions/pin.js只在成功锁定时计数(解锁不计)。 - 新增
lib/actions/diagnostics.js:诊断组装的动作层入口(仓库 A9 架构守卫要求 adapters 不直接 importdsh/,故组装落在 actions,HTTP 适配层只做协议转换)。 - 文档/模板:README(中英)新增「诊断信息与隐私 / Diagnostics and privacy」节;
.github/ISSUE_TEMPLATE/bug_report.yml文案对齐「生成 → 预览 → 复制」;设置页按钮只用「生成 / 预览 / 复制」,不出现「发送 / 上传 / 上报」。 - 测试:新增
test/diagnostics.mjs(T1–T9:形状白名单、敏感 fixture 脱敏、禁止字段、零网络(fetch 抛错 + 源码扫描)、URL < 7500、64KB/20 条/200 字符上限、p50/p95、计数器、文案),并入npm test;test/plugin-load.mjs增加只读端点用例(鉴权 / 405 / 白名单产物 / 无会话state=null);test/e2e/settings-ui.mjs增加诊断信息真机检查(帮助区入口按钮、点【生成并预览】后的弹层内容含dcr-diagnostics/v1与「脱敏」、不含 sessionId/绝对路径、点【复制 Markdown】必须有成功或失败反馈)。 - 版本号仍保持 0.3.6(0.4.0 未发布、不 bump);
package.json无新增依赖,capabilities未新增 network。
0.3.6(2026-10-24,原生压缩线解析作用域修复)
- 问题(BUG-012,外部用户报告,Windows / DSH 0.2.1-rc.2,真实会话
session-1f90f5ee,2026-10-23):指示灯「原生自动压缩线」(紫色刻度)从默认 80% 误显示成 50%。用户配置的compaction-basic块里只有config.modelPolicies(mac-unc/qwen35-unc-64k)写了thresholdRatio: 0.5,并没有改全局线。 - 根因:
lib/dsh/native-compaction.js的parseCompactionOverride只按「下一个顶层-条目」截断,不区分 YAML 缩进层级 ——config.modelPolicies[*].thresholdRatio被当成整个插件的全局线。 - 修复:按缩进定位
compaction-basic条目 → 它的config:直接子键,只认这一层的auto/thresholdRatio;更深嵌套层(modelPolicies[*]、多层 map/list)一律忽略。applyAutoOverride写入口径同步(只写 config 直接子键,不写进modelPolicies)。 - 边界:没有
config:/ config 为空 →found=true但无覆盖,读侧回落默认值(80%);多个compaction-basic条目取第一个;CRLF 文件解析与 apply 后都保持 CRLF;#注释与引号值兼容现有写法。 - 范围:本次只修解析作用域;「按当前模型 route 算真实触发线(deepseek-flash 67.8% / mac-unc 75%,而非窗口比例 80%)」留 0.4。
- 测试:新增
test/native-compaction.mjs(① config 直属阈值生效 ② 嵌套 modelPolicies 被忽略并回落 0.8 ③ 嵌套+直属取直属 ④ 多层嵌套 ⑤ 无 config / 无条目 ⑥ CRLF ⑦ apply 后回读且不破坏 modelPolicies ⑧ 引号/注释),并入npm test;修复前该测试在嵌套用例上失败(把 0.6 误读成全局线)。 - 测试基线:smoke 53/53、handoff 35/35、plugin-load ...
v0.3.6 — 原生压缩线解析作用域修复
补丁版:修复「原生自动压缩线」被嵌套配置误报(BUG-012)。
问题
指示灯上的「原生自动压缩线」从默认 80% 误显示成 50%。真实案例(Windows / DSH 0.2.1-rc.2):用户 profile 的 cordis.patch.yml 里,compaction-basic 块只有 config.modelPolicies(mac-unc / qwen35-unc-64k)写了 thresholdRatio: 0.5,并没有改全局线。
根因
lib/dsh/native-compaction.js 的 parseCompactionOverride 只按「下一个顶层 - 条目」截断,不区分 YAML 缩进层级 —— config.modelPolicies[*].thresholdRatio 被当成了整个插件的全局线。
修复
- 按缩进定位:
compaction-basic条目 → 它的config:直接子键,只认这一层的auto/thresholdRatio;更深嵌套层(modelPolicies[*]、多层 map/list)一律忽略。 applyAutoOverride写入口径同步:只写config:直接子键,不写进modelPolicies;无config:时补块;CRLF 保持不变。- 新增
test/native-compaction.mjs(8 组场景:直属生效 / 嵌套忽略 / 嵌套+直属 / 多层嵌套 / 无 config / 无条目 / CRLF / apply 回读 + 引号注释),并入npm test;修复前嵌套用例会失败(把 0.6 误读成全局线)。
边界
- 本次只修解析作用域。「按当前模型 route 算真实触发线(deepseek-flash 67.8% / mac-unc 75%,而非窗口比例 80%)」留 0.4。
config: {}行内 flow 写法不专门支持(与旧实现一致;实际 profile 是块式 YAML)。
测试基线
bundle --check PASS(148857 字符,本补丁不改 client)、smoke 53/53、handoff 35/35、plugin-load 14/14、contract 17/17、compact-log PASS、compress-cue PASS、state-passive PASS、native-compaction PASS、markdown-lite PASS。
升级
dsh plugin --profile desktop add dsh-compact-relay@0.3.6升级后重启 DSH 生效。0.3.4 / 0.3.5 的发布物保持原样不动。
v0.3.5 — 压缩按钮误禁修复
补丁版:修复外部用户报告的「压缩按钮灰置且提示暂无可压缩内容」。
问题
会话用量已经超过压缩线、插件也建议压缩,但指示灯菜单里的「压缩旧会话」呈灰色不可点,提示「暂无可压缩内容(会话太短,或近期会话需保留原文)」。典型场景:DSH 桌面端刚重启,会话已经加载、但还没有活的 agent(还没发过消息)。
根因
readState 允许在「没有活 agent」时退化成用已加载的 live session 测压力(所以百分比和建议是正常的),但 compactRange 只在有活 agent 时计算,返回 null;客户端把 null 统一显示成「暂无可压缩内容」并禁用按钮——把「会话未激活」误当成「没有可压缩内容」。0.3.3 / 0.3.4 均存在。
修复
- state(additive,不破坏 HTTP 契约):target(含 passivized live session)非 null 即计算
compactRange(纯显示用;预览/真正压缩仍要求活 agent);新增字段compactRangeReason,仅当范围存在且无活 agent 时为'no_agent'。 - 客户端:
reason === 'no_agent'时按钮仍禁用(预览需要活 agent,点了也执行不了),但文案改为「会话未激活:发一条消息唤醒 agent 后可压 N 条 · 约 X tokens」,悬停 title 可读;rangeInfo === null与正常可压的既有文案不变。 - 测试:新增
test/state-passive.mjs(无活 agent 的 live session 仍算出范围 + reason='no_agent';有活 agent reason=null;空会话/无会话不误报;既有 state 字段不丢),并入npm test。 - 测试基线:bundle
--checkPASS(148857 字符)、smoke 53/53、handoff 35/35、plugin-load 14/14、contract 17/17、compact-log PASS、compress-cue PASS、state-passive PASS、markdown-lite PASS。
升级
dsh plugin --profile desktop add dsh-compact-relay@0.3.5升级后重启 DSH 生效。0.3.4 的发布物(npm 0.3.4 / tag v0.3.4 / 对应 Release)保持原样不动。
dsh-compact-relay 0.3.4 — 判断机制修复 + 小 bug
dsh-compact-relay 0.3.4 — Release notes
中文(主)
更新内容(0.3.4,判断机制修复 + 小 bug)
判断机制修复(BUG-010:「适合压缩的节点」几乎不触发)
- 问题与证据:扫描 427 个真实会话(36,813 次工具调用)——0.3.1 上线后
mark_stage工具调用 0 次,compress-hint记录全库仅 1 条(开发期测试);而工具 schema 在会话日志中出现 43 次,说明工具确实进了模型上下文,只是模型从不调用。 - 根因:旧工具描述写「系统会告诉你当前容量」,但系统从未告诉模型任何容量 → 「超过最小线 / 还没到压缩线」两条条件无法判断,描述末尾的「不要凑数调用」进一步抑制调用。
- 修复:容量进入可压缩区间(最小压缩线~压缩线)时,插件通过动态 system-prompt context 主动告诉模型当前容量和区间,模型据此判断「刚完成一个自然节点」时是否记录压缩节点。为控制开销:容量按 5% 桶取整、刚记过节点且容量差 <10 个百分点时不重复提醒、异常/缺服务静默跳过。
- 工具:
mark_stage改名mark_compress_point,描述改为「它自己会做什么」:完成明确任务/阶段且认为可安全压缩旧历史时调用;工具返回当前容量并复核区间,太低/已到压缩线会被拒绝且不改历史;不确定时可以调用让工具判断。 - 清理:删除 0.3.1 遗留的死代码
core/stage.js+actions/stage.js(无任何引用)。
小 bug 修复
- BUG-005:交接单详情纯文本 → 新增轻量 Markdown 渲染(标题 / 段落 / 有序无序列表 / 粗体 / 行内代码 / 代码块 / 分隔线)。零依赖、不生成 HTML、无 XSS 面;512KB / 白名单 / 只读约束不变。
- BUG-006:交接单列表只显示最近 20 份 → 列表返回总数,底部显示「共 N 份(显示最近 20)」并提供「加载更多」(上限 50),无更多时隐藏按钮。
内部整理(0.3.3 之后的架构工作)
- 把 7 处重复实现抽取为共享模块(
core/object.js、core/tokens.js、dsh/compaction-pair.js、dsh/model-task.js、actions/support.js、actions/compact-run.js、client/15-shared.js),行为不变,node --check/ 构建产物 / 测试全部一致;client bundle 由片段重新构建。
测试
npm test 全绿:smoke 53/53、handoff 35/35、plugin-load 14/14、contract 17/17、compact-log PASS、compress-cue 3 组、markdown-lite 3 组;隔离 DSH + 干净无头 Chrome 的 e2e smoke / settings-ui 通过。
升级提示
- 升级后重启 DSH 才会加载新代码;
file:挂载的开发环境升级后需要pnpm install(本次新增了 lib 文件)。 - 设置栏保存仍然即时生效,不需要重启。
安装
dsh plugin --profile desktop add dsh-compact-relaynpm:https://www.npmjs.com/package/dsh-compact-relay | 仓库:https://github.com/cfanzx/dsh-compact-relay
English
What changed (0.3.4 — compression-point judgment fix + small bug fixes)
Compression-point judgment (BUG-010: the "suitable point to compress" rarely appeared)
- Evidence: across 427 real sessions (36,813 tool calls), the old
mark_stagetool was called 0 times after 0.3.1, and only 1compress-hintrecord existed in the whole store (a development test). The tool schema appeared 43 times in session logs — the model could see the tool, it just never called it. - Root cause: the old description promised "the system will tell you the current occupancy", but nothing ever told the model. The two conditions (above the minimum line / below the compression line) were therefore not actionable, and the "don't call just to fill a quota" wording further suppressed calls.
- Fix: when occupancy enters the compressible band (between the minimum compression line and the compression line), the plugin now proactively tells the model the current occupancy and band through a dynamic system-prompt context, so the model can decide whether to record a compression node after finishing a natural milestone. To keep the overhead low, occupancy is bucketed to 5%, the cue is suppressed for 10 percentage points after a node is recorded, and any error or missing service is silently skipped.
- Tool:
mark_stageis renamed tomark_compress_pointand its description now states what the tool does: call it after finishing a clear task/phase when the older history can safely be compressed; the tool returns the current occupancy and re-checks the band, rejects when too low or already at the compression line, and never changes history. When unsure, the model can call it and let the tool decide. - Cleanup: removed dead code left from 0.3.1 (
core/stage.js,actions/stage.js), which nothing referenced.
Small bug fixes
- BUG-005: handoff-document panel was plain text → a lightweight Markdown renderer (headings / paragraphs / ordered and unordered lists / bold / inline code / code blocks / horizontal rules). Zero dependencies, no HTML generation, no XSS surface; the 512 KB / whitelist / read-only constraints are unchanged.
- BUG-006: handoff list only showed the latest 20 → the list endpoint returns a total; the panel shows "N total (showing latest 20)" and offers "load more" (up to 50), hiding the button when there is nothing more.
Internal cleanup (architecture work after 0.3.3)
- Seven duplicated implementations were extracted into shared modules (
core/object.js,core/tokens.js,dsh/compaction-pair.js,dsh/model-task.js,actions/support.js,actions/compact-run.js,client/15-shared.js) with no behavior change; syntax checks, the built client bundle and the test suite are all consistent, and the client bundle was rebuilt from its fragments.
Tests
npm test is fully green: smoke 53/53, handoff 35/35, plugin-load 14/14, contract 17/17, compact-log PASS, compress-cue 3 groups, markdown-lite 3 groups; the isolated-DSH e2e smoke and settings-ui suites also pass on a clean headless Chrome.
Upgrade notes
- Restart DSH after upgrading to load the new code; development setups mounted via
file:also needpnpm install(new lib files were added). - Settings saved from the Settings page still take effect immediately without a restart.
Install
dsh plugin --profile desktop add dsh-compact-relaynpm: https://www.npmjs.com/package/dsh-compact-relay · Repository: https://github.com/cfanzx/dsh-compact-relay
dsh-compact-relay 0.3.3 — Windows 适配
中文(主)
更新内容(0.3.3,跨平台补丁版,运行时行为无变化)
- Windows 适配:完整测试套件(smoke 53 / handoff 35 / plugin-load 13 / contract 17 / compact-log)已在 Windows 11 + Node 24.22 实测全部通过。
- 测试跨平台修复:
handoff的「目录不可写」用例改用「普通文件当父目录」制造 ENOTDIR(Windows 没有/dev/null语义);contract的交接目录断言按path.resolve比较(Windows 上/tmp会被解析为C:\tmp)。 - 构建脚本:
scripts/build-client.mjs忽略隐藏文件与 macOS 资源分叉(._*),拷贝/打包后的源码在 Windows 上也能通过--check。 - 文档:README(中英)与 DEVELOPMENT 注明测试需要 Node 22.15+(
node:module.registerHooks);TUTORIAL 常见问题补充「headless / QQ 桥接链路不加载指示灯与命令」;ROADMAP 明确不做桥接链路接管。
安装
dsh plugin --profile desktop add dsh-compact-relayEnglish
What changed (0.3.3, cross-platform patch; no runtime behavior changes)
- Windows support: the full test suite (smoke 53 / handoff 35 / plugin-load 13 / contract 17 / compact-log) passes on Windows 11 with Node 24.22.
- Cross-platform test fixes: the "directory not writable" handoff case now uses a regular file as the parent directory to force ENOTDIR (Windows has no
/dev/nullsemantics); the contract handoff-dir assertion comparespath.resolve(...)(Windows resolves/tmptoC:\tmp). - Build script:
scripts/build-client.mjsignores hidden files and macOS AppleDouble files (._*), so copied/packed sources pass--checkon Windows as well. - Docs: README (zh/en) and DEVELOPMENT note that the test suite requires Node 22.15+ (
node:module.registerHooks); TUTORIAL FAQ now explains that headless / QQ bridge links do not load the ring or commands; ROADMAP states bridge links are out of scope.
Install
dsh plugin --profile desktop add dsh-compact-relay