DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Cache Control — DeepSeek Harness 插件(DSH Plugin)
← Plugins
C

dsh-cache-control

Cache Control

会话策略八开关(设置页名称一律 2–4 字,**分区标题不带序号** —— 编号是位置属性,插一张卡就得把全部下游引用重排一遍,v1.10.2 与 v1.11.0 已为此各返工一次;指代某块请直接说名字)。**换台机器:装完必须重启 DSH Desktop;各开关与规则 override 都在 $DSH_HOME/dsh-cache-control(不随仓库走),换机后要重新打开「省缓存 / 会话守则 / ponytail / 输出形状 / 气泡置顶 / 对话页」(输出形状默认开,不用管),否则表现为「装了但什么都没发生」;「省缓存」改的是 $DSH_HOME 里的 preset 行,也要重新

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:Raylen-berry/dsh-cache-control#de473175828b86fbcacd3692ae71df523e5b687f
README兼容性版本

说明

会话策略八开关(设置页名称一律 2–4 字,**分区标题不带序号** —— 编号是位置属性,插一张卡就得把全部下游引用重排一遍,v1.10.2 与 v1.11.0 已为此各返工一次;指代某块请直接说名字)。**换台机器:装完必须重启 DSH Desktop;各开关与规则 override 都在 $DSH_HOME/dsh-cache-control(不随仓库走),换机后要重新打开「省缓存 / 会话守则 / ponytail / 输出形状 / 气泡置顶 / 对话页」(输出形状默认开,不用管),否则表现为「装了但什么都没发生」;「省缓存」改的是 $DSH_HOME 里的 preset 行,也要重新打开一次。详见 README「换台机器:可迁移性与必须手动的步骤」**。省缓存 —— 改写 standard agent preset 的 compaction-basic 参数(触发点 / 原文尾部保留百分比 / 自动压缩),只影响之后新建的会话;会话守则 —— 把插件内 session-gate.md 长期规则常驻注入 system prompt(R1 独立研判、R2 必要提问、R3 分工固定;R4 输出形状本身在同目录 shape-gate.md,只留归属声明;v1.9.2 新增 R5 编码行为四原则、v1.9.4 新增 R6 查证再下结论、v1.9.5 新增 R7 谨慎执行、v1.9.6 给 R2 补提问时机细化),对所有会话的下一个请求生效;设置页开关与按钮自 v1.9.3 起用宿主官方 primitives(软回退自带控件);ponytail —— 与会话守则同构的第二段常驻规则(v1.10.0,编码纪律:七级梯子 / YAGNI / 修根因),独立开关与独立 override 文件;输出形状(v1.12.0)—— 第三段常驻规则,**并入自原独立插件 dsh-output-shape**(段名 dsh-output-shape:output-shape → dsh-cache-control:shape-gate,order 仍 410;那个插件已下线):回复形状十条 + 六条破例,**默认开**(并入前就是默认开,升级不变行为),独立开关与 override 文件,并接手原来的两条按需技能 i-have-adhd / ponytail(技能正文直接读同一份规则文件,不占常驻 token);自动审查(v1.11.0)—— 注册**按需技能** auto-code-review,一个字都不进 system prompt:每次现向外部 ocr(alibaba/open-code-review,Apache-2.0)的 delegation mode 取「该审哪些文件 + 命中哪些规则」,判断仍由当前模型做、不需要 API key;界面显示 ocr 探测结果,未安装时如实提示,本插件不打包也不自动装它;气泡置顶 —— 钉住「已越过会话区上沿的最后一条提问」(跟着滚动换条)、气泡宽度贴住文字、复制键落在气泡右侧轨道、底衬模糊度可调;对话页 —— 会话列宽占可用宽度的 30–100%(v1.5.0 起由固定 px 改百分比,全屏/缩窗/换显示器比例都跟着走;原 dsh-bg-atelier「底图工坊 · 对话页」整节移入,启动时自动迁移旧值),另可分别隐藏会话区两竖杠(宽度把手,拖了没反应)与侧栏分隔条(v1.7.0 拆成两个开关,各带独立能力位);存储 —— 按用途统计占盘并做「移入回收」式清理(v1.8.0)。八项互相独立,chip 上四个常驻段各自可点(省缓存 / 提问 / 懒码 / 形状),自动审查、气泡置顶、对话页、存储在设置页。

兼容性与来源证明

Cache Control 以 dsh-cache-control 发布,当前版本为 1.12.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/9/20

版本

1.12.0stable
2026/9/20
1.11.1stable
2026/9/20
1.9.7stable
2026/9/20
查看其余 5 个版本收起版本
1.9.1stable
2026/9/17
1.8.0stable
2026/9/15
1.6.2stable
2026/9/14
1.5.0stable
2026/9/12
1.4.2stable
2026/9/9

相关插件

正在加载相关插件…

最新版
1.12.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/9/20
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录

相关插件

继续浏览 memory-context 分类下经过校验的插件。

Contextdsh-context用于上下文洞察和管理的 DeepSeek Harness 插件,提供上下文仪表板和上下文命令,帮助了解上下文的构成及其演变过程。Weknora@wxg-prc-cpg/dsh-weknora适用于 DeepSeek Harness (dsh) 的 WeKnora 知识检索工具:通过自有知识库进行语义搜索、文档阅读以及 RAG/代理回答。Memsearch Dsh@zilliz/memsearch-dsh适用于 DeepSeek Harness 的 MemSearch 插件:在多个代理之间共享 Markdown 记忆,支持捕获、步骤前上下文注入、记忆召回技能和技能候选审核面板。Memory@furongjun1999/dsh-memory灵枢(Lingshu·líng shū)DeepSeek Harness 插件:完整大脑——长期记忆/知识飞轮/自我认知/递归反思接入 DSH,对话自动沉淀进 md_cg 认知图(md 文档)

README

dsh-cache-control(会话策略:省缓存 / 会话守则 / ponytail / 输出形状 / 自动审查 / 气泡置顶 / 对话页 / 存储)

给 DSH Desktop(dsh 0.7.2-alpha,web profile)加八个互相独立的开关,设置页名称就叫 会话策略(4 字,八个分区标题 省缓存 / 会话守则 / ponytail / 输出形状 / 自动审查 / 气泡置顶 / 对话页 / 存储 一律 2–4 字,不带序号 —— v1.11.1 起去掉编号,理由见下面「为什么分区标题没有编号」): chip 上 省缓存 / 提问 / 懒码 / 形状 四段各自可点,自动审查、气泡置顶、对话页、存储全部走设置页。

省缓存 · 压缩策略会话守则 · 长期规则ponytail · 编码纪律输出形状 · 回复形状自动审查 · 按需技能
动的是什么standard preset 里 @deepseek-ai/dsh-compaction-basic 的 configsystem prompt 里一个常驻段(规则文本)system prompt 里的第二个常驻段(与守则同构、独立开关)system prompt 里的第三个常驻段(同上,但默认开)宿主 skills 目录里的一个条目(不进 system prompt)
生效时机之后新建的会话(preset 按组装文件 mtime 分代)所有会话的下一个 model step(含当前会话,无需重启)同「会话守则」同「会话守则」模型/用户调用技能那一刻
会被压缩冲掉吗—不会:压缩只折叠对话历史,system prompt 每请求重发同「会话守则」同「会话守则」不适用(压根不在 prompt 里)
代价无额外 token规则体积 × 每请求(含子代理/工作流子会话)约 1.3K token/请求 × 所有会话约 1.2K token/请求 × 所有会话(默认就开着)注册零 token;成本只在真调用时

「气泡置顶」与「对话页」是纯界面开关,只改样式与 CSS 变量,不动消息数据、不动宿主代码; 「存储」只做各用途占盘统计与"移入回收"式清理。 只影响 standard 之外的说明:会话守则走宿主全局提示词层,对所有 preset、子代理、workflow 子会话都生效。

「气泡置顶」与「对话页」是纯界面开关,只改样式与 CSS 变量,不动消息数据、不动宿主代码; 「存储」只做各用途占盘统计与"移入回收"式清理。 只影响 standard 之外的说明:会话守则走宿主全局提示词层,对所有 preset、子代理、workflow 子会话都生效。

为什么分区标题没有编号(v1.11.1)

编号是位置属性、名字是身份属性。把位置写进标题,代价是任何一次插入都要把全部下游引用重排一遍: v1.10.2 修的是 ponytail 曾写作 "②b" 导致页面上出现两个 ②;v1.11.0 插入「自动审查」又让后面三块全部顺延 (README、CHANGELOG、跨插件指路、测试断言各扫一遍)。v1.11.1 起标题只留名字,顺序由卡片书写顺序决定, 插一张卡只改一处。要指代某块直接说名字。

verify-gate-client.mjs 里两条断言钉住这件事:① 页面(含抽屉正文)不许出现圈符;② 八个名字必须齐全且顺序正确。 注意这里只剩行文里的列举序号不算违规 —— 断言扫的是渲染出的整页文本,所以 README/注释以外, client.js 里给用户看的字符串也不能带圈符。

省缓存 · 压缩策略

设置页(设置 → “会话策略”)与对话区快捷面板里各有一条独立开关:

  • 总开关:启用 → 把下列参数写进 standard preset 的 compaction-basic 行; 关闭 → 还原首次接管前那一行块的原文(v1.6.1 起;原文存在 $DSH_HOME/dsh-cache-control/settings.json 的 compactionBackup 字段里,逐字节回写)。 没有备份可还原时(例如手工删过 settings.json)才回落到"移除受管 config、恢复 DSH 出厂默认"。
  • 只有压缩字段会碰那个文件(v1.6.1 起):enabled / triggerPct / retainPct / auto 没变时,保存设置完全不触碰 standard 组装文件 —— 只改「气泡置顶」「对话页」的外观开关不会再把你 自己写在那一行里的压缩配置抹掉(旧版每次保存都无条件重写,这是破坏性缺陷)。
  • 压缩触发点:占路由模型上下文窗口的百分比,默认 25%(deepseek-v4-flash 窗口 1,000,000 tokens ⇒ 约 250k 触发)。
  • 保留原文尾部:逐字保留最近内容的窗口百分比(必须小于触发点),默认 5%(⇒ 约 50k)。
  • 自动压缩:auto 开关;关闭后不再自动压缩与溢出恢复,仅保留手动 /compact。

会话守则 · 长期规则

插件内的 session-gate.md 就是规则本体,作为一份可长期演进的 md随包分发:

  • R1 独立研判:不默认用户是对的;命中「事实/技术错误、目标与手段冲突、与既有约束冲突、 代价不划算」四类必须指出,且反对要可核查(对象 + 理由 + 替代方案);最终裁决权在用户, 但不可逆损失(删数据、覆盖无备份、改生产、花钱、对外发布)必须先确认。
  • R2 必要提问:只有「不同理解会改变结果」且「答案查不到」时才停下来问;能查的先查; 一轮最多三问、带候选项与推荐;拿不准但可回滚就先做完再标注。v1.9.6 起补两条时机细化 (蒸自 Claude Code "Delivering work" 条款,MIT):改变方案形状的缺口问在动手前, 只影响实现细节的按默认假设做完再标注;阻塞式提问是最后手段,否则先做完不依赖答案的部分。
  • R3 分工固定:用户定目标、补真实情况、判定可用性;助手负责搜索、执行、制作、验证、交付。 交付必须可判断(改动路径 + 依据 + 未覆盖项 + 风险与回退)。
  • R5 少犯错优先(编码行为四原则):蒸馏自 multica-ai/andrej-karpathy-skills (214K★,Karpathy 诊断、Jiayuan Chang 成文,v1.9.2 起收录)——动手前说假设 / 最小实现 / 只动必须动的行 / 任务转成可验证目标。与 R1 互补:R1 管"敢反对",R5 管"少犯错"。
  • R6 查证再下结论:蒸馏自 duolahypercho/andrej-karpathy-skills 第 4 条的验证口径(v1.9.4 起收录)——先查证再断言、未验证标【假设】、完成前跑验收动作并附证据、 没跑检查就明说没跑。
  • R7 谨慎执行:蒸馏自 Claude Code 出厂条款 "Executing actions with care"(经 Piebald-AI/claude-code-system-prompts,MIT, v1.9.5 起收录)——不可逆/共享状态动作先确认、授权只按当次范围算、破坏性操作不当绕路捷径、 不认识的状态当用户半成品(能移不删)。git status 一条刻意未收:DSH 的沙箱与审批门已覆盖大半。

界面上:

  • 控件用宿主官方原子(v1.9.3):开/关行是「说明在左 + dsh-client-ui-primitives 的 Switch 在右」, 按钮走宿主 Button —— 随宿主主题与明暗自动一致。primitives 取不到时软回退到自带的 checkbox/.cc-btn, 功能两种情况完全一致(同一 require 失败只影响观感,不影响开关)。
  • 启用开关独立于省缓存开关,勾选框各管各的。chip 是固定版式的两段状态: 省缓存 [开/关] | 提问 [开/关],[开/关] 复用同一个徽标元件(.cc-badge),面板里两个分区头也用它。
  • 面板(输入框右侧)里两块用分隔线分区,可「查看规则」直接看当前生效文本。
  • 设置页里可编辑规则:写入 $DSH_HOME/dsh-cache-control/gate.md(override), 不改动插件目录里的内置 session-gate.md;点「清除自定义,回到内置」即删除 override。

实现要点(也是几条硬约束的理由):

  • 注入走 ctx.inject(['systemPrompt']) → systemPrompt.section({ name, order: 400, text }), 与 dsh-web-app 注入 app:web-surface 同一条路;text 是函数,DSH 每个 model step 重新 assemble(),所以改开关/改文本不用重启也不用新会话。拿不到 systemPrompt 服务时只 关掉会话守则,不影响压缩功能。
  • 关 = text 返回空串,renderPrompt 会丢弃空段 ⇒ 提示词里一个字都不留。
  • 文本按 mtime+size 缓存并即时重读:直接编辑 md 存盘,下一个请求就是新内容(无需重启、无需刷新页面)。
  • 注入前把成对花括号 {{ / }} 替换成全角 {{ / }}:renderPrompt 对未知变量引用是 抛错策略,用户编辑规则时写了 {{...}} 会让每次请求组装失败 —— 所以宁可改字形也不让会话挂。
  • 上限 16,384 字节(16 KB,约 6.6k tokens);超限自动截断,避免规则膨胀悄悄吃掉上下文。 (初版是 6 KB;加完 R4 输出形状一节后余量只剩 92 B,故 v1.9.0 放宽到 16 KB —— 这段文本每请求 重复计费,上限本身仍然保留,只是不再卡在刚好够用的位置。)
  • R4 输出形状不在本文件里:2026-09-16 起本文件只剩一句归属声明,真源是同目录 shape-gate.md, 由本插件作为第三段常驻规则注入(详见下面「输出形状」一节)。别在这里再抄一份,否则同一套规则会被注入两遍。 要收回原文备份:session-gate.R4-backup-2026-09-16.md。
  • 怎么知道自己的规则被砍了:/cc/gate.json 与 /cc/settings.json 内嵌的 gate 里有三个字段 —— truncated(显式布尔标记)、originalBytes(规则原文字节数)、keptBytes(实际注入 字节数,与老字段 bytes 同值)。不要用 bytes >= maxBytes 去反推"有没有截断过":截断后的 长度必然小于上限(6 KB 上限年代的实测:19,998 字节的中文规则 → 保留 5,839 字节; 10,000 字节 ASCII → 5,590 字节), 那个判据对已截断的规则恒为 false,界面于是显示"未截断";反过来原文恰好等于上限时文本原样 返回、bytes === maxBytes,它又会误报"已截断"。这正是 v1.6.2 修掉的缺陷, tools/verify-gate-truncation.mjs 就是它的回归套件(含"恰好压线"与"上限 -1"两个边界, 样本长度与期望值都相对上限生成,改动 GATE_MAX_BYTES 不会再让套件失效)。
  • 界面上被截断时显示「已截断:原 N B → 保留 M B」标签,卡片里另写一句 「你的规则被截断了:原文 N 字节,实际注入 M 字节(超出 X 字节未进入提示词)」;编辑框里草稿 超限时也会提前提示"保存后会被截断"。老客户端只读 bytes/maxBytes 照旧可用(字段只增不改)。

ponytail · 编码纪律(v1.10.0)

与「会话守则」同构的第二段常驻规则:蒸馏自 GitHub DietrichGebert/ponytail(MIT), 最懒资深工程师的七级梯子与硬约束。独立开关 ponytailEnabled(默认关),提示词段 dsh-cache-control:ponytail-gate(order 405,紧挨守则 400、在输出形状 410 之前)。 两段各读各的文件(session-gate.md / ponytail.md)、各有独立的 mtime+size 缓存,互不顶掉; 自定义覆盖走 /cc/ponytail.json(GET 预览 / PUT 写 override / 空文删回内置)。 代价:开着约 1.3K token/请求 × 所有会话(含子代理与非编码会话),正文里写明"只对编码任务生效"兜底行为。

输出形状 · 回复形状(v1.12.0,并入自 dsh-output-shape)

与上面两段同构的第三段常驻规则:蒸馏自 GitHub ayghri/i-have-adhd(MIT)的 「ADHD 友好输出」十条规则(首行给下一步 / 多步编号 / 状态复述 / 跑题后置 / 时间给量级 / 战果可见 / 报错讲因果 / 展示分组 ≤5 / 无开场白无客套)+六条破例 + 发送前自检。独立开关 shapeEnabled, 提示词段 dsh-cache-control:shape-gate(order 410,紧随 ponytail 405、plan 政策 500 之前)。

  • 默认开,与另两段相反:并入前它由独立插件 dsh-output-shape 的 bundle config 默认开启(那插件是这套规则的真源, 会话守则里的 R4 早在 2026-09-16 就摘出交给它)。合并时保持同默认 —— 否则升级即静默改变行为,用户只看到"形状规则没了"。 不想要这份 token 就去设置页或 chip 第四段关掉它。判据是 !== false(不是 === true):旧盘上没有这个键时按开处理。
  • 文件与路由:内置 shape-gate.md、override $DSH_HOME/dsh-cache-control/shape.md、 /cc/shape.json(GET 元信息 / PUT 写 override / 空文删回内置)、独立 mtime+size 缓存(三段互不顶掉)。
  • 原独立插件已下线:dsh-output-shape 从 web profile 的依赖与 bundle 列表里摘除,仓库目录归档。 段名由 dsh-output-shape:output-shape 改为 dsh-cache-control:shape-gate(段名只在运行时用,盘上没有引用,无需迁移)。
  • 它还接手了两条按需技能:i-have-adhd 与 ponytail(原来是那个插件注册的)。两条技能无开关、零常驻 token, 正文直接读本插件的规则文件(shape-gate.md / ponytail-gate.md,override 优先)—— 于是"技能里读到的规则"与 "每请求注入的规则"永远同一份,不会漂。verify-shape-gate.mjs 第 8 节把这条钉死。
  • 逃生开关沿用原名 DSH_OUTPUT_SHAPE_DISABLE=1(改名等于把别人环境里/脚本里的开关悄悄拔掉): 置 1 则无论设置如何都不注入常驻段;技能注册不受影响。界面在卡片与面板里都会写明"被环境变量强制关闭"。

自动审查 · 按需技能(v1.11.0)

注册宿主 skills 服务里的 auto-code-review(正文 skills/auto-code-review/SKILL.md)。 这张卡与「会话守则」「ponytail」两段的根本区别:一个字都不进 system prompt —— 注册状态零 token,正文只在模型或用户 真调用那一刻加载。开关关掉 ⇒ dispose,目录里连条目都不留。

为什么不蒸成常驻规则(这是本卡存在的理由)

上游 alibaba/open-code-review(Apache-2.0,阿里内部官方 AI 审查助手开源化)的 README 把"通用 agent + 自然语言 skill 做审查"列为反面教材:

通病机制原因
覆盖不全大 changeset 上 agent"抄近路",选择性只审几个文件
位置漂移报出的问题与实际行号/文件对不上
质量不稳自然语言 skill 难调试,prompt 微调就大幅波动

根因一句话:纯语言驱动对审查过程没有硬约束。它的解法是「确定性工程 × agent 混合」—— 选文件、分组、按文件特征匹配规则、评论定位、反思复核全部由代码保证;基准 AACR-bench (50 仓库 / 200 真实 PR / 1,505 条标注,80+ 资深工程师交叉验证)显示同模型下 F1 更高、 token 只用通用 agent 的约 1/9,而 recall 有意更低(偏精确率、压噪声)。

⇒ 抄规则文本进常驻段 = 只拿走它论证过会失败的那一半。ponytail 能常驻是因为它是风格取向 (YAGNI、梯子),没有"覆盖率""定位准确率"这类可度量指标;审查有。所以本插件不存规则正文, 每次现向 ocr 取,规则跟着上游升级、不在本仓库里腐烂。署名见 NOTICE。

三步(技能正文就是照这个契约写的,本机 v1.12.7 实测)

ocr delegate preview --format json          # 该审哪些文件(reviewable_files[] / excluded_count)
ocr delegate rule --format json <path>...   # 这些文件命中哪些规则(groups[].rule + files[])
# 然后逐组对着 diff 出结论:文件:行 + 违反哪条 + 一句为什么

范围不对时用 --from main --to feat 或 -c <commit> 重取,而不是手工挑文件。

运行期依赖(本插件不打包、不下载、不自动安装)

需要用户自行 npm install -g @alibaba-group/open-code-review(前置 Git ≥ 2.41)。 卡的第三行直接显示探测结果:装了 ⇒ ocr 已就绪:v1.12.7(<命令路径>);没装 ⇒ 黄字给安装命令。 探测不到不影响注册 —— 技能照常可用,只是跑到第一步就会停下说明,不会瞎猜。

⚠ 两个 Windows 坑(都踩过,别再改回去):

  1. execFile('…ocr.cmd') 在 Node ≥18.20/20.12/24 抛 EINVAL(CVE-2024-27980 修复),不是 ENOENT —— npm 在 Windows 上装的全局 CLI 恰恰就是 .cmd shim。所以 .cmd 那一路走 shell:true 且整条命令进 shell、不传 args(传 args + shell 会刷 DEP0190 告警)。
  2. DSH Desktop 宿主进程的 PATH 里没有 npm 全局 bin:命令行里 ocr 能跑、插件里 spawn 'ocr' 报 ENOENT。故 ocrCandidates() 显式补 %APPDATA%\npm\ocr.cmd。探测结果按 TTL 60s 记忆化, 不每次 GET 都 spawn 一遍子进程。

与会话守则 R5 / ponytail 的分工

那两个管"少写、写最小实现",这张卡管"写出来的东西对不对"。重叠处(死代码、过度抽象) 以 ponytail 的判断为准,技能正文里已写明不要重复提。

气泡置顶(纯界面,与前四块独立)

开关效果实现
pinLastUser滚动时把**已越过会话区上沿的最后一条「我的提问」**钉在顶部:往上翻会换成第 4、3 条……滚到底才钉最近那条(分节标题语义)从 [class*="_userRow"] 爬到 [data-chat-flow] 的直接子元素打 data-cc-pin + position:sticky;"钉哪一条"按 rect.top <= 滚动区上沿 + 2px 判定,scroll 触发重选;底衬画在该元素的 ::before 上(见下)
clearBubble我的气泡背景透明,露出壁纸(配合 dsh-bg-atelier)[class*="_userRow"] [class*="_bubble"]{background:transparent}
pinBlur钉顶底衬的模糊度滑杆,0–24px(0 = 只留半透明底、不模糊);小值有小数档:<3.5 按 0.1 步进(可选 1.3 / 1.5 / 1.7),≥3.5 按 0.5 步进<html style="--cc-pin-blur:Npx">,底衬规则写 backdrop-filter:blur(var(--cc-pin-blur,10px)) —— 拖滑杆只改一个变量,不重注入样式

我的提问气泡的动态贴合(v1.4.0 起始终生效,无开关;几何由 probe-userrow.mjs 用真浏览器 + 真函数源码实测):

为什么必须用 JS 量一次:块盒的宽度只跟"可用宽/上限"有关,与文字实际末端无关(inline 盒虽然贴字, 但背景逐行着色、行内 padding 只落在首末片段 ⇒ 框"超"到文字之外、文字也不垂直居中)。所以:

  • CSS 定骨架(尺寸一律 em / 宿主字号变量):userRow = display:block; position:relative; box-sizing:border-box; width:fit-content; margin-left:auto,上限 min(列宽×.55, var(--cc-user-bubble-max,41em)),右缘再留一条轨道 padding-right:var(--cc-tail-room,2.4em); bubble = 块盒 + 上下对称 padding .47em + 圆角 1.45em;图标行 position:absolute; right:.13em; left:auto; top:var(--cc-tail-y,auto) ⇒ 落在轨道里 = 气泡右侧;图标尺寸 calc(1.5em + var(--dsh-content-font-delta,0px)) 跟宿主字号走。字号变、页面缩放变,这些一起变 —— 不再有任何"某次量出来好看就钉死"的像素数。
  • JS 量一次(fitUserBubbles()):Range.getClientRects() 取逐行矩形 ⇒ ① stack.style.width = 最宽行 + 左右内边距(框贴文字;列宽变窄靠 max-width:100% 自动夹回); ② 实测图标行宽高 ⇒ 写 --cc-tail-room(轨道 = 图标行宽 + .45×图标高)与 --cc-tail-y (与最后一行同高)。变量必须写在 userRow 上:图标行是 row 的子节点,写到 userStack 上 继承不到 —— 这是复制键一度跑偏的直接原因。
  • 实测(列宽 1180、字号 15px):10 字 174px、30 字 444px、长文 579px;复制键距气泡右缘 13.1px(em 轨道,随字号缩放)且与末行同高;上下留白 8/8.1 相等;420px 窄容器不越框。
  • 两条踩过的坑(别改回去): ① 用 bubble.children.length > 0 判"含内嵌块就跳过",会把带 @路径 引用的提问(宿主渲染 成 <span>)整条漏掉 ⇒ 框宽退回"块宽 = 上限"的固定观感(就是"完全不动态"那次反馈)。现在 只跳过真的含 img/video/canvas 或某行矩形异常高(内嵌块)的气泡。 ② applyAppearance() 里任何一步抛错(例如常量改名)会连带把后面的观察器全跳过 ⇒ 被钉元素 不出现,看起来就是"模糊度失效"。现在每段各自 try/catch + warnOnce,首屏再补量两次,并在 document.fonts.ready 后清签名重算(字体切换会改行宽,一次量错会被签名锁住)。
  • 设置页「气泡置顶」卡里带一行底衬实测读数:被钉元素有/无、--cc-pin-blur、 getComputedStyle(el,'::before').backdropFilter、底衬宽、会话字号 +「重读」按钮 ⇒ 以后"看起来失效"能当场分辨是哪一种成因。
  • 只处理纯文字气泡;data-cc-fit 记签名,流式输出不会每帧重排;停用插件时 stopFitWatch() 把 stack.style.width / --cc-tail-* / data-cc-fit 全撤干净。
  • 时间戳零占位:平时 opacity:0 却仍占位 ⇒ max-width:0;padding:0;overflow:hidden, :hover 才展开(展开后的内边距也是 em)。
  • 可调点:USER_BUBBLE_MAX_EM(上限,默认 41em;测试缝 internals.setBubbleMaxEm / setBubbleMaxPx)、--cc-tail-room(轨道宽 = 复制键离框缘的距离,JS 自动量、也可手动覆盖)、 FIT_ICON_H(仅量不到图标时的兜底高度)。钉顶底衬宽度自 v1.4.2 起按这条提问的实测宽度 写入 --cc-pin-w(量不到才退回 的旧上限)。

底衬形态的三次选定: 2026-09-07 选半透明毛玻璃(不是实底、不是无底衬); 2026-09-07 改成圆角矩形——原先把毛玻璃铺在被钉住的整行上,而行宽 = 整个会话列宽, 于是气泡左边一大片空白也在模糊。现在:

  • 行自身只留 position:sticky,background / backdrop-filter 一律不再铺;
  • 底衬画在 ::before 上:right:-6px(右缘贴住气泡右缘,宿主 .userRow 是 align-items:flex-end 右对齐),宽度 var(--cc-pin-w, calc(min(calc(var(--dsh-chat-content-width,748px) * .55), 100%) + 12px)) —— v1.4.2 起 --cc-pin-w 由 JS 按这条提问的实测宽度写入(气泡含右侧图标轨道的像素宽 + .8em 呼吸位), 短句就是短底衬、长文就是长底衬;读不到几何时(getBoundingClientRect 拿不到正宽)退回括号里那个 "列宽 × .55 + 12px" 的旧上限兜底;
  • 长文钉顶时不再无限撑高:气泡本体 max-height:38vh + overflow-y:auto + overscroll-behavior:contain(在气泡内滚,滚到底才交还给会话流),scrollbar-width:thin;
  • border-radius:16px 圆角矩形;四周出 2–6px 呼吸位(top:-2px;bottom:-2px,不加 padding ⇒ 不挤动布局);
  • z-index:-1:被钉行有 z-index:6 自成堆叠上下文,负层因此落在"正文之上、气泡之下", backdrop-filter 采到的正是身后滚过去的正文;
  • 模糊度走 --cc-pin-blur 可调变量,默认 10px。

宽度怎么来的(v1.4.2):updatePinPlate() 在"钉住哪一条"确定后、以及每次重排(fitUserBubbles) 结束时各跑一次 —— 量被钉行里 [class*="_userRow"] 的实际像素宽,加上 根字号 × .8 当呼吸位, Math.ceil 后写进该行的 --cc-pin-w;量不到就 removeProperty,让 CSS 里的旧上限接管。

一个必须知道的真实边界:sticky 的移动量 = 父级高度 − 自身高度,所以只有当你那条提问下面 还有比它更高的内容(通常是长回答)时,钉顶才看得出来;短回答或空会话里它就像没生效。

为什么不是纯 CSS 一行:sticky 的移动量 = 父级高度 − 自身高度。真实结构(读自 dsh-client-ui-chat 的产物)是 [data-conversation-scroll] > … > [data-chat-flow] > [data-chat-flow-key] > .userRow > .userStack > .bubble, 给内层 .userRow 直接加 sticky 不会动(父级等高、没有剩余高度),所以要钉的是 [data-chat-flow] 的直接子元素(每条消息一层)。找行用 [class*="_userRow"], 定层用宿主的稳定属性 [data-chat-flow](该属性在 column 上、每条消息的 data-chat-flow-key 在其子层,均在产物里核实过);属性不在时退回"按剩余高度往上爬"的通用判据。 气泡透明只能按类名匹配,而 uSmzmW_ 这类前缀是构建哈希 ⇒ 用后缀选择器 [class*="_userRow"] [class*="_bubble"],宿主升级改名时最坏结果是这条样式不生效,不会连累其它功能。 设置页会把"钉到了哪个元素 + 共几条提问"打印出来供自检。

观察器分两条:钉顶那条只在开关打开时挂 document.body(childList + subtree,rAF 去抖),关闭即断开并清掉所有 data-cc-pin;气泡贴合那条只挂 [data-chat-flow] 容器(+ scroll / resize,90ms 去抖),负责重算框宽、 字尾位置和"钉哪一条"。插件停用/卸载时 stopFitWatch() 会撤掉观察器并清干净 stack.style.width、 --cc-tail-*、data-cc-fit 三样内联痕迹。

输入框右下角 chip 里的「开 / 关」徽标不吃背景(2026-09-07):.cc-chip .cc-badge 三条规则 把 background / border-color 都置 transparent,状态只靠文字颜色区分(开=品牌蓝、关=三级灰、 未装载=警示黄)。面板与分区头里的同名徽标保持原样(那里有底色对比的需要),所以规则限定在 .cc-chip 作用域内。

对话页(固定会话列宽,v1.3.0 从 dsh-bg-atelier 移入)

开关效果
chatWidthEnabled + chatWidth关闭 = 跟随 DSH 自适应;打开 = 把会话列宽钉在可用宽度的 30–100%(含 60/70/80/90/100 快捷键;v1.5.0 起是百分比,之前是 640–3840px)
hideResizer(v1.6.0,v1.7.0 起只管两竖杠)关闭 = 保留会话区两竖杠(宽度把手);打开 = 把它们隐藏。列宽一旦钉成固定百分比,这两条把手拖了就不再改变列宽,只剩"鼠标扫过去冒出两竖杠、拖了没反应"的误触(用户 2026-09-14 反馈)
hideDivider(v1.7.0)关闭 = 保留侧栏/详情栏分隔条;打开 = 把它隐藏。分隔条与两竖杠不同,拖它仍然有效(改侧栏宽度),所以拆成独立开关、默认不藏
  • 隐藏把手按语义识别、不按类名:宿主的类名是 CSS-module 哈希(实测 ._1tdjgG_handle / ._8JRpoa_widthHandle), DSH 一升级就变,而 cursor 含 resize 才是"这是条把手"的功能特征。两类再用宿主直接写在把手元素上的 data-width-handle 属性区分(有 = 会话区宽度把手,没有 = 框架分隔条)——数据属性不是哈希,比类名耐升级。 实现是给命中的元素分别打 data-cc-hide-resizer / data-cc-hide-divider,再由插件样式表 [data-cc-hide-*]{display:none!important} 隐藏;只认可见元素、排除自己面板内的元素, 并挂一条 MutationObserver(300ms 去抖)—— 宿主重建框架会换掉那些把手。 关掉对应开关或停用插件时把标记撤干净,不给宿主留一条看不见的把手。 两个开关各有独立能力位(resizerReady / dividerReady):旧 host 不认识某个键时只禁用那一个开关, 不连带其它。

  • 钉法:先按 [data-composer-card] 往上找到内联带 --dsh-conversation-column-width 的那个祖先 (= 会话根,宿主 publishWidths 就在它身上标定列宽),再往它身上写 --dsh-chat-content-width / --dsh-composer-card-max-width(宽 +32)/ --dsh-chat-user-width 三个变量并带 !important,绕过宿主的响应式 clamp;另有一条 :root{--dsh-chat-user-width:…!important} 兜底,覆盖 composer 还没挂上的窗口期。关闭时逐个 removeProperty + 删掉兜底样式,交回自适应。

  • 会话根随切会话/导航会重建 ⇒ 另挂一条 MutationObserver(300ms 去抖)只在开关开着时存在, 根节点一重建就把变量补写回去。

  • 滑杆拖动过程中只做即时预览(局部 state + 直接钉 CSS 变量),松手/失焦/方向键才 STORE.set → 存盘: 否则每拖一格都会把设置页整页重渲染一遍,手感发涩。

  • 与「气泡置顶」的联动:底衬宽度 v1.4.2 起跟随这条提问的实测宽度(--cc-pin-w),读不到几何时才退回 --dsh-chat-content-width × .55 的旧上限;所以这里改列宽,只在"兜底路径"下才会等比影响钉顶底衬。

  • 一次性迁移:这两项原先存在 $DSH_HOME/dsh-bg-atelier/settings.json。host 启动时若发现自家 settings.json 缺 chatWidth / chatWidthEnabled,就读底图工坊那份搬过来并写盘 (migrateFromAtelier(),日志 对话页宽度已从 dsh-bg-atelier 迁入);搬完之后自家有字段就不再读对方, 你之后改的值不会被对方旧值盖回。bg-atelier v1.3.0 起客户端不再声明这两个字段,也就不会再 PUT 回去。

存储(v1.8.0)

按用途分别统计各目录占了多少盘(会话记录 / 投影缓存 / 附件副本 / 浏览器观察窗 / 生图产物 / 费用记录 / 本插件数据),给出文件数·字节·最新最旧时间与总计。清理只收"明确可再生成"的东西, 且先给候选清单再动手、动作是移入回收而非删除;purge 才清空回收目录。 host 三条路由:GET /cc/storage、POST /cc/storage/clean、POST /cc/storage/purge。

安装

前提:DSH Desktop(dsh CLI 可用),并在装完后重启桌面应用一次。DSH 关闭状态下任选其一:

  1. 从本仓库装(推荐):
    git clone https://github.com/Raylen-berry/dsh-cache-control.git D:\dsh-plugins\dsh-cache-control
    dsh plugin --profile web add link:D:/dsh-plugins/dsh-cache-control
    
    (Linux/macOS 把路径换成自己的绝对路径即可;link: 改动即生效,便于边改边试。)
  2. 手工接线:在 profiles/web/package.json 的 dependencies 与 dsh.profile.bundles 里加 dsh-cache-control,并把 profiles/web/node_modules/dsh-cache-control 做成指向本目录的 junction / symlink。

装完后 host 半(index.js,含会话守则段注册)随 profile 装载。

⚠️ 改了 client.js 必须重启,光刷新页面没有用(我此前说过"刷新即可",那是错的)。 依据(宿主 dsh-client-modules 的产物 + 实测):插件 client 半不是按请求从磁盘读的 —— 它在 服务启动时一次性 compose 成带 rev 哈希的 combo,挂在 /plugins 前缀下、以 cache-control: public, max-age=31536000, immutable 提供。原始路径 /plugins/dsh-cache-control/client.js 实测是 404(我先前在这里写过它,是错的), 只有 compose 后的哈希 URL 才有响应。唯一能让新字节进图的入口是 rebuilt(id), 而它属于 HMR watch(需要 pnpm run dev:web 在跑)。打包运行的桌面应用没有这个 watch ⇒ 磁盘上的新 client.js 只有重启才会进组合。重启后 rev 变了、index 注入的是新 URL, 所以浏览器那份一年期 immutable 缓存不会挡住新版。

此后:改规则 md 立即生效(host 每次组装重读磁盘);开关与滑杆改动即时写盘; 压缩参数对之后新建的会话生效;界面与 chip 的改动要重启才可见。

发布前检查(CI 与本地同一条命令)

push / PR 都会跑 .github/workflows/ci.yml,它做两件事:npm ci(只装 devDependencies)→ npm test。 本地跑的就是同一条命令:

npm install                    # 只装 devDependencies(就一个 react);CI 用 npm ci
npm test                       # = node tools/run-all.mjs
node tools/run-all.mjs --list  # 只看清单:跑哪些、以及哪些被排除、为什么

出网边界:只有 npm ci / npm install 那一步出网(按 package-lock.json 装 devDependencies)。 npm test 本身不出网 —— 不做真实下载、不调模型、不读 %APPDATA% 下的真实 preset / settings.json。

tools/run-all.mjs 把每套都跑完再汇总(不用 && 串,避免第一套一失败就看不到后面), 任一套非 0 退出 ⇒ npm test 退出码 1 ⇒ CI 变红。CI 用 Node 20/22/24 三档矩阵、windows-latest。

干净环境实测(DSH_HOME / APPDATA / LOCALAPPDATA / USERPROFILE / DSH_APP_MODULES 全指空目录, 独立下载的 node),三档(Node 20/22/24)结果一致 —— 5/5 套件通过:

套件结果
tools/verify-gate-truncation.mjs31 项通过
tools/verify-host-width.mjs全部 PASS
tools/verify-settings-payload.mjs9 项通过(v1.7.0 起含 hideDivider 对齐断言;v1.11.0 起含 reviewSkillEnabled 与"载荷锚点定位"两条)
tools/verify-panel-and-resizer.mjs25 项通过(v1.7.0 起两类把手分开关断言)
tools/verify-session-gate.mjs39 项通过(v1.9.4 起纳入;本机跑时另加真实 home 对照 3 条)

上表是 v1.9.x 那次"干净机器实测"的记录,当时确实只有 5 套。v1.10.2 起进 CI 的是 8 套: 多出 verify-ponytail-gate.mjs(23 项,v1.10.0 纳入)、verify-shape-gate.mjs (60 项,v1.12.0 纳入)与 verify-gate-client.mjs (v1.12.0 起本机 80 项 / 无真实 home 时 78 项 + SKIP,夹具化见下面那条)。

verify-panel-and-resizer.mjs 原来因为"要本机 DSH 安装目录的 node_modules/react"被排除。 现在 react 进 devDependencies,run-all.mjs 把 DSH_APP_MODULES 指向仓库自己的 node_modules/, 于是本地与 CI 都不再依赖任何人的安装路径(反向证据:把 DSH_APP_MODULES 指回空目录, 该套件立刻报 ERR_MODULE_NOT_FOUND: Cannot find module '<空目录>/react/index.js')。

verify-session-gate.mjs 被排除的原因(v1.9.4 已消除两条):① DEPLOYMENT_PERSONA TypeError ——根因是断言引用了宿主从未导出的符号名,套件在段序断言处崩、后面 20+ 条从没跑过;② 读 %APPDATA% 真实 preset/settings ——换成仓库内最小夹具 + 「真实 home 存在才比对」。它 import 的 @deepseek-ai/dsh-system-prompt 走自己 devDependencies 里那份(createRequire 从仓库 package.json 解析,版本与本安装宿主一致),所以把 DSH_APP_MODULES 指到空目录仍 39/39。

verify-gate-client.mjs 同样在 v1.10.2 挪回 CI,消除的是三条本机依赖:① preset 从 %APPDATA% 复制 ⇒ 换成与 verify-session-gate 同款的最小夹具;② 收尾"真实 settings.json/gate.md 未被改动" 两条硬读真实 home ⇒ 真实 home 不存在时 SKIP 并如实打印(v1.12.0 起本机 80 条,CI 上 78 条 + SKIP); ③ primitives 桩原来要求"能读到宿主真包源码"才装载 ⇒ 改为始终按签名复刻桩,读不到只打一行 NOTE。 react-dom 随之补进 devDependencies(钉到与 react 同版本 18.3.1,原来只有 react、server.js 靠宿主目录)。 反向证据(本轮实测):APPDATA 指空目录后跑 npm test ⇒ 8/8 套件通过,该套件 78 passed / 0 failed + SKIP; verify-session-gate 同步退化为 36 项(它自己的真实 home 对照 3 条也走 SKIP)。

未纳入 CI 的套件(原因同时写在 tools/run-all.mjs 的 EXCLUDED 里): verify-ui-appearance.mjs / verify-gate-http.mjs(要 %APPDATA% 下的真实 preset)。

verify-gate-http.mjs 本轮没有做夹具化:它先把真实 preset 复制到临时 DSH_HOME, 然后有几条断言是"逐字节比对真实 preset 有没有被本次验证改动" (fs.readFileSync(REAL_PRESET) + sha256)。换成仓库内夹具就得重写那几条的比对对象, 而那属于放宽验证口径 —— 本轮的规矩是只允许"等价或更强"的改动,所以保持排除并在此写明。

换台机器:可迁移性与必须手动的步骤

给后续在任何一台机器上接手的人或 agent:本插件装起来不需要任何手工点击, 但下面几条"换机后不生效 / 得手动做"的事,必须先看清楚,别以为"克隆下来就完事"。 (起因:用户 2026-09-12 反馈"工作电脑上传、回家发现可用性很差、必须手动操作"。)

A. 装(agent 可全自动)

git clone https://github.com/Raylen-berry/dsh-cache-control.git <你放插件的绝对路径>
dsh plugin --profile web add link:<同一个绝对路径>

link: 挂载的意义:改完即生效(开发态),不需要每次重装。

B. 必须重启 DSH Desktop(人工触发,agent 不能替你决定) client 半在服务启动时才 compose 进图(依据见上一节),所以"装完刷新页面"是没用的。 重启会掐断正在跑的会话轮次 —— 让用户自己挑时间。

C. 设置不随仓库走**(换机器后各开关全是默认关)** 所有状态都在 $DSH_HOME/dsh-cache-control/:settings.json(各开关 + 数值)、 gate.md(会话守则的自定义覆盖,可选)、ponytail.md(ponytail 的自定义覆盖,可选)、 shape.md(输出形状的自定义覆盖,可选)。 仓库里没有它们,因此换机器后要重新打开: 「省缓存」「会话守则」「ponytail」「气泡置顶」「对话页」—— 否则会表现为"插件装了但什么都没发生"。 (「自动审查」与「输出形状」按 DEFAULTS 默认开,换机器不用拨:前者只注册一个技能,ocr 没装也不报错, 只是用到时第一步会停下说明;后者是常驻规则,不想要那份 token 才需要去关。)

D. 「省缓存」改的是 preset,不是插件目录 它把参数写进 $DSH_HOME/profiles/**/standard/agent.yml 里 compaction-basic 那一行 (带 # managed by dsh-cache-control 标记)。换机器/换 profile 后,必须在新机器上再打开一次总开关 才会重新写进去;关闭总开关会把该文件还原成上次接管前的原文(v1.6.1 起; 备份在 $DSH_HOME/dsh-cache-control/settings.json 的 compactionBackup 里,不随仓库走, 所以换机器后新机器上关一次开关只回到它自己那份原文)。

E. 已知的宿主坑:插件会被 generation 迁移搬走(本机踩过) 部分 DSH Desktop 版本在启动时会做 installGeneration 迁移,会把 link: 挂载的插件重新 stage 一遍,期间把一个绝对路径当相对路径拼接⇒ ENOENT、迁移被 defer, profiles/web/.install-complete 永远写不出来的同时插件也可能不加载。 本机的处置是给应用 bundle 打一个本地补丁(把本插件加进 KEEP_IN_SHARED_TREE)——该补丁不在本仓库里, 它属于"每台机器各自的 DSH 应用目录"。识别方法:启动日志出现 migration deferred / could not stage,或 profiles/web/.generations-deferred.json 反复生成。 遇到就按本机 dsh-local-patches/README.md 的脚本处理(DSH 每次升级都会覆盖该补丁,升级后要重跑)。

G. 设置导出/导入(换机器一键搬配置,v1.5.0 新增)

node tools/settings.mjs export --out D:\cc-settings.json    # 旧机器
node tools/settings.mjs import D:\cc-settings.json --yes    # 新机器(覆盖前自动备份 settings.json / gate.md)

show 看当前值;不带 --yes 演练。它连 gate.md(会话守则的自定义规则)一起搬 —— 这是本插件最不该手抄的东西。导入会按与 host sanitize 同口径的规则钳制 (触发点 5–95、保留尾部 < 触发点、底衬模糊 0–24 且 1 位小数、钉顶上限 12–80vh、 对话页宽度 30–100% 且旧 px 值归一 80%),未知字段丢弃并列出来; host 读盘时还会再 sanitize 一次,所以口径即使漂了也不会写坏引擎侧。 ⚠ 导出/导入只搬 settings.json 与 gate.md:ponytail.md / shape.md 两个 override 要自己拷 (它们就在同一个目录下)。v1.12.0 修掉一处静默丢键:这个脚本的 DEFAULTS 曾经漏了 ponytailEnabled / reviewSkillEnabled,于是"导出再导入"会把这两个开关悄悄抹回默认 —— verify-settings-payload.mjs 只比对 host 与 client,管不到这个脚本,所以以后加开关记得三处都补。 ⚠ 「省缓存」不在这个文件里:它改的是 $DSH_HOME 里 standard preset 的那一行, 新机器导入后在设置页把总开关关一次再打开即可重新写入。

F. 换机后自查(30 秒)

node tools/verify-audit.mjs 2>$null; node tools/verify-host-width.mjs   # 期望全绿 / 无 FAIL
# 设置页应出现「会话策略」八个分区(标题无编号);对话页默认 80%(百分比,v1.5.0 起)

验证

回归与探针脚本都在本仓库 tools/ 下(只用于开发,不进 npm 包,见 package.json 的 files)。 分两层:逻辑回归(Node 里跑,写盘全部落在临时 home,不碰你真实的 $DSH_HOME)与 浏览器实测(无头 Chrome,把宿主产物里的真实 CSS 规则与真实类名塞进复刻约束的夹具,判定用数字不用肉眼)。

node tools/verify-session-gate.mjs    # 规则解析 / 花括号防御 / 截断 / 压缩行无回归
node tools/verify-ponytail-gate.mjs   # ponytail 段:独立开关 / 独立缓存 / 截断 / override 往返
node tools/verify-shape-gate.mjs      # 输出形状段(v1.12.0):默认开 / 逃生开关 / 三段独立 / 技能同源 / 不重复注入
node tools/verify-gate-http.mjs       # host 半真起 http 服务:路由、两开关正交、异常输入
node tools/verify-gate-client.mjs     # client 半真渲染:磁盘 → 路由 → STORE → DOM(含抽屉展开态)
node tools/verify-ui-appearance.mjs   # 外观引擎 + 置顶跟随滚动选条 + chip 点击语义 + 对话页宽度钉法
node tools/verify-host-width.mjs      # host:字段钳制 + 从底图工坊的一次性迁移(临时 DSH_HOME)
node tools/verify-gate-truncation.mjs # 规则截断:原/留长度 + 显式标记 + 边界与两个 HTTP 响应契约

「自动审查」(v1.11.0)没有独立套件,断言分挂在两处:payload 对齐(reviewSkillEnabled 必须 出现在主 PUT 载荷里 —— 这条正是 v1.6.0 hideResizer 那个"拨得动不落盘"bug 的守门人)与 client 渲染(八个分区标题名字齐全且顺序正确、页面里不许出现圈符编号)。ocr 探测本身是 子进程调用,不进套件(CI 上没有 ocr,且它属于"环境事实"而不是逻辑);改探测逻辑时手工跑一次 node -e "import('./index.js').then(h=>h.probeOcr().then(console.log))" 看结果。

浏览器侧(会往 tools/*-out/ 落 HTML/JSON/PNG,已在 .gitignore 里):

node tools/probe-userrow.mjs          # 气泡贴文字 / 复制键在气泡右侧轨道 / 上下留白对称(跑的是 client.js 里的真函数源码)
node tools/cc-appear-probe.mjs        # 钉顶底衬形态与模糊度:--dump-dom 让页面自量自报
node tools/cc-fixture.mjs             # 面板朝向与 portal:插槽/portal × 旧朝向/新朝向
node tools/cc-appear-fixture.mjs      # 同一批判定的 CDP 版

脚本里的默认路径是本机(Windows + DSH Desktop)的绝对路径,换机器用环境变量覆盖即可: DSH_CC_PLUGIN(本插件目录)、DSH_APP_MODULES(宿主 node_modules)、DSH_CHAT_BUNDLE (dsh-client-ui-chat/lib/client.js)、DSH_CC_INDEX、DSH_TOOL_HOME(临时 home)、 DSH_TOOL_OUT(夹具输出目录)、CHROME(Chrome 可执行文件)。 verify-gate-client.mjs 里对底图工坊的交叉断言在找不到对面插件时会自动 SKIP(DSH_BGA_CLIENT 可指定)。

夹具里量出来的关键数字(写在这里,下次改动好比对是否退化): 旧朝向面板可见比例 0.021(超出视口底部 411px);新朝向完整可见。 钉顶:position:sticky、top:0px、被钉元素 y:0 h:84、travelPx:676、滚动 1298px 后仍在滚动区顶; 透明:开 rgba(0, 0, 0, 0) / 关 rgb(47, 47, 52)(后者是宿主 --dsw-specific-bubble 的真值)。 底衬(2026 形态,cc-appear-probe.mjs 实量,夹具视口 1280 / 列宽 748):整行 rowBg rgba(0, 0, 0, 0) + rowBackdrop none(左侧干净);::before 底衬 v1.4.2 起按该条提问实测宽度:夹具里 411px 宽的气泡 ⇒ --cc-pin-w ≈ 423.4px (= 411 + 根字号 15 × .8,向上取整),对整行 748px ⇒ 左边留出 ~324px 不糊;短句提问则底衬跟着变短。 (v1.4.2 之前是"定长":423.4px = 748×.55 + 12,短消息时明显比气泡宽;v1.4.0 之前是 537.094px = 748×.702 + 12。) border-radius:16px; position:absolute / z-index:-1;右缘 right:-6px 与气泡右缘差 6px; --cc-pin-blur 未设 ⇒ blur(10px),设 0px ⇒ blur(0px),设 20px ⇒ blur(20px)。 注意夹具的坑:最后一条提问下面若没有长回答,sticky 没有移动量,量出来会误判成"没钉住"; --dump-dom 那条还必须给每个状态独立的 --user-data-dir,否则后启动的实例会把活儿交给 已在跑的浏览器进程、自己退出,dump 出来就是空文件。

卸载 / 回退

  1. 关闭省缓存总开关(把 standard 组装文件还原成接管前的原文 —— v1.6.1 起是逐字节还原, 不是删掉那一行);没有备份时手动删除组装文件里带 # managed by dsh-cache-control 的 config 块。 关闭会话守则开关即可让规则段消失。
  2. 在 profile 移除依赖与 bundle 项、删除 junction;或 dsh plugin --profile web remove dsh-cache-control。
  3. 重启应用。插件停用/卸载后不残留任何行为改动(gate.md override 与 settings.json 是数据,需自行删除)。

版本与变更记录

  • v1.7.0(把"隐藏拖拽条"拆成两个开关:两竖杠与侧栏分隔条分开管)

    • 起因:v1.6.0 的 hideResizer 一条开关按 cursor:*-resize 语义标记,实测会同时命中三类元素: 会话区左右两条宽度把手(._8JRpoa_widthHandle,就是"误触冒出两竖杠、拖了没反应"的那两位) 与 AppFrame 的侧栏/详情栏分隔条(._1tdjgG_handle,8px 宽)。前两位拖了确实没反应, 但分隔条是能用的(拖它会改侧栏宽度)——一个开关把死控件和活控件一起藏了(用户 2026-09-14 要求拆开)。
    • 改法:hideResizer 语义收窄为只管带 data-width-handle 属性的宽度把手(存量盘上值不动, 升级后"两竖杠仍被藏、分隔条自动回来");新增 hideDivider(默认关)管分隔条。 两类共用 cursor 含 resize 的语义识别,再用宿主写在把手元素上的 data-width-handle 数据属性区分 (它不是 CSS-module 哈希,耐升级);两套标记各一个属性(data-cc-hide-resizer / data-cc-hide-divider), 各一条 CSS,互不牵连:关一个开关不会把另一类也撤了。dividerReady 与 resizerReady 同样是 独立能力位,旧 host 重启前只禁用新开关,不影响已有的。
    • 顺带补漏:tools/settings.mjs(导出/导入)的字段名单停在 v1.4.x,hideResizer 从来不在里面 —— 导入一份开着把手隐藏的设置会被"丢弃未知字段"静默抹掉。现在 hideResizer / hideDivider 都在名单里。
    • 验证:verify-panel-and-resizer 从 19 条扩到 25 通过 / 0 失败(新增:只开一个开关时另一类 不被标记、关一个不撤另一个、能力位单独禁用、isWidthHandle 分类、setHideDivider no-op 路径); verify-settings-payload 9 通过(新增 hideDivider 载荷对齐断言);verify-host-width 全绿 (sanitize 键齐全断言扩到 hideDivider);npm test 套件 4/4 通过。
  • v1.6.2(修"截断标记判错":规则被砍了,界面却说没截断)

    • 症状:会话守则规则超过 6,144 字节时会被截断,但界面不显示"已截断",用户以为整份规则都进了 提示词 —— 实际超出部分从没被模型看到。
    • 根因:host 的截断函数只返回一个字符串,界面判断"有没有截断"是靠结果长度猜的: truncated: bytes >= GATE_MAX_BYTES。而截断后的长度必然小于上限(末尾那句省略提示算在内 也只有 5.6–6.1 KB 一档,且随原文的字节/字符比浮动)⇒ 该判据对已截断的文本恒为 false。 反方向也错:原文恰好 6,144 字节时文本原样返回、bytes === maxBytes,它又把没截断的判成截断。
    • 修法:截断函数 truncateBytes() 改为直接返回全部事实 { text, originalBytes, keptBytes, truncated },调用方一律读 truncated;gateMeta 与 PUT /cc/gate.json 的响应原样带出这三个事实(bytes/maxBytes/lines/// 等老字段一个不动,老客户端不受影响);界面标签与提示改成 「已截断:原 N B → 保留 M B」+「你的规则被截断了:原文 N 字节,实际注入 M 字节(超出 X 字节未进入提示词)」。

说明:本插件只写 $DSH_HOME/dsh-cache-control/* 与 standard preset 的 compaction-basic 行。 任何替你改动运行时开关值的行为都应算作越界——v1.1.0 曾直接写入过 gateEnabled: true,已记在此处。

说明与限制

  • 会话守则是软约束:它让规则每请求都在提示词里、且不被压缩稀释,但不产生技术硬拦截 —— 模型仍可违反。 真要拦截得走工具层/审批钩子,那是另一件事。
  • 修改点位于打包目录(app 安装的 node_modules,profile 以 junction 指向它); 若 DSH 升级重建该文件,插件启动时会自动对账并重新应用当前设置(写回标记行)。
  • 浏览器端刻意不编辑组装文本;本插件的“编辑”由其 host 进程完成,页面只有开关、滑杆与规则编辑器。
  • 数值换算显示用 ROUTED_CONTEXT_WINDOW = 1_000_000 这个常量(当前路由 qwen3.8-flash 声明的窗口 也是 1,000,000,所以对你这台机器是对的);若换到别的窗口的模型,界面上的 token 数会失真, 但引擎侧是比例式阈值,实际触发点仍按窗口同比变化。token 数为 token-meter 的估算口径。
  • v1.2.0 起 chip 固定为三段:省缓存 [开/关] | 提问 [开/关] | ▾,前两段点击即切换、 ▾ 弹滑杆与规则面板;标签不随状态改名(v1.1.0 那套"两个都开就叫会话策略"已去掉)。
  • tools/verify-session-gate.mjs 的既有失败已于 v1.9.4 修复并纳入 CI(此前记录:从宿主包取 FIRST_PARTY_SECTION_ORDER.DEPLOYMENT_PERSONA,而该导出名从未存在 ⇒ 段序断言处崩、后面 20+ 条从没跑过)。 修法见 CHANGELOG 1.9.4:段序判据改读已解析包的源码文本数值(persona=0 / plan=500), preset 依赖换成仓库内最小夹具。这段留在这里是提醒:测试脚本与宿主导出脱节时,崩在中途的套件 会伪装成"只坏了前半截" —— 排除理由里写"既有失败"之前先数一下它到底跑到了第几行。
min(列宽×.55, 上限) + .8em
text
source
enabled
  • 同类第二处:全仓库再找了一遍"靠长度/结果反推状态"的写法,结论是只有这一处是缺陷。 保留的同类写法都有正当理由,逐条记录在这里:readBody 用显式 overflow 布尔标记(正确做法); truncateBytes 里的 buf.length <= max 与界面编辑框的 draftBytes > gateMaxBytes、 tools/settings.mjs 的"导入前预警"都是输入侧判据(比的是"待处理文本自己 vs 上限", 不是在反推已经发生的截断);client.js 的 atBottom = scrollTop >= max - 1 是位置判定 (滚动几何的即时谓词),与"用产物长度推状态"不是一回事。
  • 回归:新增 tools/verify-gate-truncation.mjs(v1.6.2 时 31 通过 / 0 失败;v1.9.0 把上限 放宽到 16 KB 后,样本长度与期望值改为相对上限生成,现为 30 通过 / 0 失败 —— 本条其余 数字是当时的记录):① 超长(中文 19,998 B / ASCII 10,000 B)⇒ truncated:true 且 originalBytes/keptBytes 齐备(中文那条正好复现审计给的 5,839 B);② 恰好 6,144 B ⇒ false 且内容逐字节原样;③ 6,143 B ⇒ false;④ 空/极短 ⇒ false 且内容原样;⑤ 六种输入的"标记 / 原文长度 / 保留长度 / 实际内容"四者互相对得上(没有"标记为假 但内容变短"的样本);⑥ 老字段名齐全;⑦ 两个 HTTP 响应(GET /cc/gate.json、GET /cc/settings.json、PUT /cc/gate.json)都带标记且与文本一致;⑧ 界面接线(读标记、不自己比长度)。 另有两条照妖镜断言直接把旧判据钉死:同一个样本上断言"bytes < maxBytes 而标记为 true"与 "bytes === maxBytes 而标记为 false"。verify-gate-client.mjs 从 67 条扩到 72 条 (新增 5 条:真渲染出的 HTML 里出现「已截断:原 19998 B → 保留 5839 B」、那句人话含两个字节数、 用警示色类、数字与 host 响应一致、未截断时一个截断字样都不出现)。
  • 反向验证:把新套件用 DSH_CC_INDEX 指向 git show HEAD:index.js 那份改动前实现 ⇒ 25 失败 / 6 通过(退出码 1);指回本仓库这份 ⇒ 31 通过 / 0 失败。这证明断言真的盯着这个缺陷 而不是"假绿"。
  • 验证数字:本仓库套件全绿 —— verify-gate-client 72、verify-gate-http 43、 verify-gate-truncation 31、verify-host-width 51、verify-ui-appearance 50、 verify-panel-and-resizer 19、verify-settings-payload 8,全部 0 失败; verify-session-gate 仍为既有失败(见文末"说明与限制",与本轮无关)。
  • v1.6.1(修一个破坏性配置缺陷:保存外观开关会抹掉用户自己的压缩配置)

    • 症状:只改 ③ 气泡置顶 / ④ 对话页的任何一个外观值(钉顶、气泡透明、模糊度、宽度、 隐藏拖拽条),standard 组装文件就被重写一遍;如果当时总开关是"关",那一行块里 用户自己写的压缩配置会直接消失(回落到 DSH 出厂默认 0.8 / 0.16)。
    • 根因:保存入口 PUT /cc/settings.json 无条件 applyToStandard(settings),而 applyToStandard 在 enabled === false 时执行 spliceCompactionRow(text, null) —— 也就是"删掉那一行块里的 config"。链路与 tools/verify-host-width.mjs 里的断言一一对应。
    • 修法(三条,全部有断言):
      1. 只有压缩字段变化才碰那个文件:compactionFieldsChanged() 只看 enabled / triggerPct / retainPct / auto;外观/门禁字段的保存完全不触碰组装文件 (响应里 touched:false 即"这次没碰")。
      2. 接管前先备份、关闭时还原:首次接管时把接管前的整篇原文存进 settings.json.compactionBackup = { text, at };关闭开关时优先逐字节还原这份原文, 还原后清掉备份(下次再开 = 重新接管、重新采备份)。只有没有备份可还原时才回落到 旧的"摘掉受管 config"。受管行的识别沿用原有 # managed by dsh-cache-control 标记,没新造标记。
      3. 幂等:保留 next === text 早退 —— 重复保存同一份设置不会产生第二次写盘; 重写行块时只替换"标记 + 其后的 config 块",name: 与用户手写的注释原样保留。
    • 修的过程中被断言抓出来的两个次生问题(都已修,都有断言):
      • CRLF:原来 split('\n') 把 \r 留在行尾,config: 的整行比较会失败 ⇒ 旧 config 不被替换、 反而是又追加一份(YAML 重复键)。改成 split(/\r?\n/)。
      • 未受管时也追加:首次接管(文件里本来就有用户的 config: 块)时,旧 config 没被摘掉 ⇒ thresholdRatio 出现两次。现在"行块末尾的 config 块"一律整段替换。
    • 回归:tools/verify-host-width.mjs 从 17 条扩到 51 条(本次新增 34 条,走真 HTTP 路由, DSH_HOME 指临时目录):① 只改外观(7 个字段一次提交)⇒ 该文件哈希与 mtime 都不变; ② 改压缩字段 ⇒ 确实被改(哈希变化、thresholdRatio 只出现一次、用户注释仍在、备份 === 接管前原文); ③ 重复保存同一份设置 ⇒ changed:false + 哈希/mtime 不动;④ 关闭 ⇒ 逐字节还原、 用户原有的 0.66/0.11 回来、备份被清、再关一次不再写盘;④b 无备份回落路径; 启动对账(开关=开但文件无受管行 / 开关=关但文件有受管行)两条路径同样受这套语义约束; ⑤ sanitize 带出 compactionBackup(任何一次写盘都不许吃掉它);⑥ splice 幂等与纯函数性。
    • 验证数字:verify-host-width 51 通过 / 0 失败、verify-gate-http 43(新增 3 条: 备份===接管前原文、只动门禁的保存 touched:false、关压缩逐字节还原 + 真实 preset 逐字节未变)、 verify-gate-client 67、verify-ui-appearance 50、verify-panel-and-resizer 19, 全部 0 失败;verify-session-gate 为既有失败(见文末"说明与限制")。
  • v1.6.0(两个独立改动,同一个文件所以同一笔提交:修一个真 bug + 加一个开关)

    • 修:滑杆面板 ▾ "点不开"(用户 2026-09-14 反馈)。不是点击没接上 —— 点了 aria-expanded 会变 true、DOM 里也有 .cc-panel,但它被摆到屏幕外(实测 rect.y = 33554004、 内联 bottom: -6.71e7px)。根因是那次"一次性校正"的 effect 量纲混用:期望值写成"距视口底部的距离" (vh - c.top + 6),实测值 r.bottom 却是视口 Y 坐标,两者相减恒不为 0;而 patch 又把 dy 累加回 bottom、依赖数组里还含 pos.bottom ⇒ 每帧误差翻倍,二十来帧就发散到 -6.7e7px。 修法:定位数学抽成纯函数 computePanelPatch()(两边统一用视口 Y,一次补到位即收敛), 并加 ±400px 量级闸门 —— 任何不可信的测量只能被忽略,不可能再把面板丢出屏幕。 回归:新增 tools/verify-panel-and-resizer.mjs(19 通过 / 0 失败),把"已对齐返回 null / 有偏移一步到位 / 一步后收敛 / 离谱值被闸门挡掉 / NaN 挡掉 / 翻转分支同量纲"全部锁住。
    • 增:④ 对话页新增 hideResizer(默认关),可选隐藏 DSH 原生分栏把手,理由与实现见上面 ④ 那节。 host 侧 sanitize 只负责原样存取;client 侧用一个独立能力位 resizerReady 判断 "host 认不认识这个键",不并进 appearanceReady —— 否则旧 host 下会把已有几个外观开关一起禁用。
    • 验证:本仓库套件全绿(verify-ui-appearance 50、verify-gate-client 67、verify-gate-http 40、 verify-panel-and-resizer 19、verify-host-width 通过;verify-session-gate 是既有失败, 见文末"说明与限制")。
    • 顺带:README ④ 那节的表格还写着 640–3840px(v1.5.0 已改成百分比却没同步),一并改正。
  • v1.5.0(④ 对话页:宽度单位 px → 百分比)

    • 起因(用户 2026-09-12 原话):"改成百分比,具体的数值不仅会随着全屏或是缩小有变动, 还会因为显示器的比例出现不协调。"固定 640–3840px 在全屏/缩窗时不跟着走,换显示器比例就失配。
    • 改法:chatWidth 语义从 px 变成 30–100 的百分比,三个变量写同一个 P% —— --dsh-chat-content-width / --dsh-composer-card-max-width / --dsh-chat-user-width 都写 P%(:root 兜底那条同样写 %);滑杆 30–100、步长 1,快捷键改成 60/70/80/90/100%。
    • 真浏览器实测(本机会话区 clientWidth 1139,在真会话里量消息列与输入卡): 80% ⇒ 消息列 860px、输入卡 886px;60% ⇒ 645 / 664;100% ⇒ 1075(满宽)/ 1107。 即三个变量都是"可用内容区的 P%"(100% 时 1075 = 1139 − 两侧 32px 内边距), 而输入卡恰好 = P% ×(内容区 + 32) ⇒ 卡片永远比消息列宽 32×P 像素 —— 与 px 时代"+32px 出挑"的关系完全一致,只是整体按比例缩放。 (一度以为会"复合两次"导致卡片过窄:那是在空会话页量的,那页的 composer stack 宽度不同; 真会话里不复合。这条记在这里,免得下次又被空页面误导。)
    • 迁移:盘上的旧 px 值(>100,例如你现在的 900)不再按 px 用,一律落到默认 80% —— 900px 在本机 1139px 会话区里正好≈79%,观感等价;由 normalizeChatWidth() 在 host 与 client 两端同口径处理(sanitize / clampChatWidth), 底图工坊那次一次性迁移(migrateFromAtelier)也一并走这条口径。
    • 验证:verify-host-width.mjs 全绿(新增"60 原样 / 10→30 / 900 与 3840 旧 px → 80"四条); verify-ui-appearance.mjs 50 passed / 0 failed(新增"三个变量都是 90%"与"旧 px 1600 → 80%"); verify-gate-client.mjs 67 passed / 0 failed。
    • 顺手修了 verify-gate-client.mjs 里一条早就假失败的断言:它要求底衬规则含 width:calc(min(,而 v1.4.2 起那层已经是 width:var(--cc-pin-w, calc(min(…))) (早于本轮的单位改动,与本轮无关,只是这次跑测试才发现)。 另把 verify-host-width.mjs 里"删掉文件再看它不存在"的断言改成哨兵文件写法 —— 本机沙箱会把 fs.rmSync 拦成空操作(实测 rmSync 之后 existsSync 仍为 true), 那种写法会假失败,改成"跑完看哨兵内容有没有被改写",反而更直接地证明"不写盘"。
  • v1.4.2(钉顶底衬改"实测宽度" + 长文限高)

    • 底衬宽度不再"定长":新增 updatePinPlate(),在钉住哪一条确定后、以及每次气泡重排 (fitUserBubbles)结束时,量出被钉行里 [class*="_userRow"] 的实际像素宽 + 根字号 × .8 呼吸位,写进该行的 --cc-pin-w(短句 ⇒ 短底衬);量不到就 removeProperty, 由 CSS 里的旧上限 min(列宽×.55, 上限) + .8em 兜底。
    • 长提问钉顶不再无限撑高:气泡本体 max-height:38vh + overflow-y:auto + overscroll-behavior:contain + scrollbar-width:thin —— 超出时在气泡内滚,滚到底才交还会话流。
    • 只动 client.js 与版本号;host 半、路由、settings 字段均未变,不需要重启(客户端热更新即可)。
  • v1.4.1(根因修复 + 尺寸自适应)

    • applyAppearance 每段各自 try/catch + warnOnce:一处抛错不再连带把钉顶/贴合观察器全部 跳过(那会让"底衬模糊度"看着像失效);首屏补量两次 + document.fonts.ready 后清签名重算。
    • 气泡量测不再按 children.length 整条跳过(带 @路径 <span> 的提问曾被全漏 ⇒ 框宽退回固定 上限),改为只跳过真含 img/video/canvas 或内嵌块的气泡;轨道宽与纵向对齐改为实测图标行。
    • 尺寸全面 em 化:气泡内边距/圆角/图标尺寸/轨道宽/上限(USER_BUBBLE_MAX_EM 取代 px 常量)/ chip 徽标与标签位移一律 em 或实测值,跟随会话字号与页面缩放自适应。
    • 设置页 ③ 新增底衬实测读数自检行 +「重读」按钮;提问气泡图标区隐藏宿主 tooltip。
  • v1.4.0(改名 / 气泡微调 / 小数档)

    • 分区名改:② 门禁 → ② 会话守则(chip 工具提示、设置页、规则 md 标题同步); ③ 外观 → ③ 气泡置顶。
    • 我的提问气泡微调(始终生效):宽度上限系数 .702 → .55;上下 padding 压到 6px (行距/字号不动);时间/复制那一行从气泡下方挪到气泡文末右侧同排,放不下才换行; 钉顶底衬公式同步改用 .55(实测列宽 748 ⇒ 气泡 411px / 底衬 ~423.4px)。
    • pinBlur 支持 1 位小数:<3.5 按 0.1 步进(可到 1.3 / 1.5 / 1.7),≥3.5 按 0.5 步进; host sanitize 同口径保留 1 位小数。
  • v1.3.0(本轮四项)

    • 钉顶底衬改形态:从"铺满被钉住的整行"改为画在 ::before 上的定长圆角矩形, 整行不再有 background / backdrop-filter ⇒ 会话列左侧不再被模糊;新增 可调模糊度 pinBlur(0–24px,写在 <html> 的 --cc-pin-blur 上,拖滑杆不重注入样式)。
    • chip 的「开 / 关」徽标改纯透明:.cc-chip .cc-badge 三条规则去掉背景与描边, 状态只靠文字颜色;面板内的同名徽标不受影响。
    • 名称一律压到 2–4 字:设置页导航条目 会话策略 · 省缓存/守则 → 会话策略; 分区标题 → 省缓存 / 会话守则 / 气泡置顶 / 对话页;快捷面板分区头同步缩短。 长说明没删,都挪到各卡正文与 hover 里。
    • 接住 bg-atelier 的「对话页固定宽度」:新增 ④ 对话页卡(开关 + 640–3840px 滑杆 + 常用宽度快捷键 + 会话根重建时的补写观察器),并由 migrateFromAtelier() 在启动时 一次性把 $DSH_HOME/dsh-bg-atelier/settings.json 里的 chatWidth / chatWidthEnabled 搬进自家 settings.json(只在自家缺这两个字段时读对方,之后不再读)。
    • sanitize 新增三字段钳制:pinBlur 0–24(v1.4.0 起保留 1 位小数)、chatWidth 640–3840、chatWidthEnabled 只认 true。
    • 验证补三条:cc-appear-probe.mjs(无 CDP 的浏览器实量,本沙箱里唯一跑得通的那条)、 verify-host-width.mjs(钳制 + 迁移幂等)、verify-bga-trim.mjs(对面插件的回归)。
  • v1.2.0

    • 新增 ③ 会话区外观:pinLastUser(最近一条「我的提问」钉顶)、clearBubble(我的气泡背景透明)。 纯客户端样式 + 运行时打标记,设置项持久化在同一个 settings.json。 两项形态按用户选定实现:钉在会话滚动区顶部、钉住条目自带半透明毛玻璃底衬。 开关默认 false,不由插件替用户打开。
    • chip 改为三段可点:省缓存 [开/关] | 提问 [开/关] | ▾。点前两段直接切对应开关, ▾ 才弹滑杆与规则面板(不用进设置页);每段 hover 有独立介绍。
    • 修"点开面板看不见":旧写法 top: chip 下沿 + 6,而输入条贴在视口底部 ⇒ 面板整块开到屏幕外。 无头 Chrome 夹具实测(03-调试临时/cc-fixture.mjs,三个 variant 只动「父级」与「朝向」两个变量): 旧朝向可见比例 0.021(超出视口底部 411px);改成贴 chip 上沿 + max-height 锁进可用空间后完整可见。 同时把面板 portal 到 body(与宿主 dsh-client-ui-attachment 同源做法)——实测它不是主因: 朝向正确时留在插槽里也完整可见;portal 消除的是 contain:paint/"裁剪盒恰是包含块"这类组合。
    • 新增两道能力/状态闸:loaded(没成功读到设置就拒绝保存,防止默认值盖掉真实配置)、 gateReady / appearanceReady(旧 host 不认识的字段一律禁用对应开关,避免写盘被抹)。
    • 修 readBody 超限时 req.destroy() 打断连接的缺陷(客户端 ECONNRESET + Windows libuv 断言),改为排空后回 400。
  • v1.0.0 仅省缓存(压缩策略)单开关。