dsh-verbose
Verifieddsh-verbose · v0.8.2 · MIT · Web UI
A session-header 3-dots menu: download the session log, switch each chat's transcript between Normal and Verbose, and define what Verbose expands (thinking blocks, tool calls, terminal output).
Install
dsh plugin add dsh-verbose Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Readme
dsh-verbose
English | 中文
一个 DeepSeek Harness 插件,把对话记录变成按会话阅读的形式: 会话头部的三点菜单里,下载会话日志、把每个会话单独切换为 Normal 或 Verbose,并定义 Verbose 展开哪些内容 —— 思考块、工具调用、终端输出。
一切都在浏览器里。 两个 localStorage 键 —— 一个按会话的开关,一份全局类别设置 —— 没有服务,没有遥测。

它做四件事:
- 按会话的 Normal/Verbose 开关 —— 在三点菜单里,原位替换内置的 Session log 按钮(同一位置、同一 id、
更低优先级),头部仍然只有一个三点控件。只作用于当前会话,立即生效,按会话保存在
localStorage。 - “Verbose 展开哪些内容”对话框 —— Thinking、Tool calls、Terminal output 三个全局开关,加 Turn footer 分组与 After a turn 的折叠方式。改动类别立即重新应用当前会话。
- 展开范围 —— 默认只在步骤行进入视口时展开、滚出后重新折叠,长会话不会堆出一整墙展开的步骤; 关闭则是原插件"一次性全部展开"的行为。
- 回合信息条 —— 每个回合下方的
⏱ 12.3s · 47 nodes · 9 tools · 84.2k tokens,Normal 与 Verbose 都显示,外加一个可折叠的原始回合 JSON 与复制按钮。
为什么需要它
dsh 的对话记录只有一组全局展示参数(transcriptView:compact / standard / detailed /
verbose),并没有"按会话选择"的概念。这与实际需求不符:想看多少过程 属于某一段对话,
而 verbose 到底展开什么 属于你本人。
本插件把两者拆开:
| 作用域 | 设置 | 存放位置 |
|---|---|---|
| 每个会话 | Normal 或 Verbose | localStorage,以 session id 为键 |
| 全局 | Verbose 展开哪些类别:思考、工具调用、终端输出 | localStorage,所有会话共用一份 |
两个作用域是刻意的:按会话复制类别设置只会导致漂移;而全局的 Normal/Verbose 会一次性 翻转所有对话。
你会看到什么
菜单替换内置的 Session log 按钮 —— 同一位置、同一 id、更低优先级 —— 因此头部仍然只有 一个三点控件:
- Session log —— 下载当前会话日志(宿主控制器未挂载时回退到导出 URL)。
- Transcript view → Normal / Verbose —— 只作用于当前会话,立即生效。
- Verbose settings… —— 对话框:三个类别开关、Turn footer 分组的 Turn metrics 与 Raw turn JSON,以及 After a turn 的折叠方式。类别改动立即重新应用当前会话;信息条开关为全局,下一次渲染生效。
- Compact settings… —— 仅在挂载了
context-governor时出现(见"兼容性")。
Normal 保持 dsh 原本的渲染。Verbose 采用 React 之外唯一可行的方式:找到 dsh 已渲染的每个
可展开行([data-expandable][aria-expanded]),分类后点击属于已启用类别的行,并在回答流式
生成、行被重建时持续这么做。定位依据是语义属性,绝不依赖哈希类名:
| 类别 | 管制的行 | 选择器 |
|---|---|---|
| Thinking | 推理块 | closest('[data-variant="think"]') |
| Terminal | shell 示例 | closest('[data-sample="bash"]') |
| Tool calls | 其余全部 | 默认 |
| Step groups | 回合内嵌套的 "Ran commands" 行 | [data-process-activity] |
Thinking 优先判断,因此嵌套在推理块内的工具行归为 thinking —— 外层所属类别正是你关掉的那类。
回合信息条(本次移植新增)
dsh 渲染器没有对应开关,因此这两项由本插件在 conversation.chat.turnTail 自行渲染:
- Turn metrics —— 每个回合下方的
⏱ 12.3s · 47 nodes · 9 tools · 84.2k tokens, Normal 与 Verbose 都显示。全部来自插槽交出的回合对象;缺失的字段直接省略,绝不补零。 - Raw turn JSON —— 同一对象的折叠副本与复制按钮,并限制长度,超大回合不会卡住页面。
它们刻意不作为引擎类别:引擎分类的是可展开行,而"metrics 行"并不存在 —— 把它列进类别
只会让引擎去找永远找不到的行。它们与类别同存于 dsh-verbose.categories,并通过
dsh-verbose:prefs 事件让所有已挂载的信息条与对话框保持同步。
展开范围(本次移植新增)
Only what is on screen 开关决定 Verbose 花多少力气:
- 开(默认) —— 步骤行进入视口时展开,滚出视口后重新折叠。以阅读位置为准:长会话不会 堆出一整墙展开的步骤,滚回去时又会重新展开。
- 关 —— 一次性展开所有已启用类别,即原插件的行为。
三条规则保证该模式稳定,每一条都源于一次真实故障:
- 两条边界,而非单一阈值。 行必须明显进入视口(内侧 120px)才展开,明显离开(外侧 260px)才折叠;两者之间是"什么都不做"的死区。单一阈值时,展开一行会把下一行推出边界 → 折叠 → 布局回弹 → 又符合条件,形成来回弹跳。
- 滚动停止后才折叠(最后一次滚动后 420ms),不会在滚动过程中把内容抽走。
- 本轮只要点击过,就自我抑制 320ms。 否则我们自己点击引发的 DOM 变更会立刻安排下一次 判定,使振荡自我维持,而不是一次性的。
另外两处让动作看起来是"动"而不是"坏":每轮先记录当前阅读位置的锚点行,操作后按高度差修正
scrollTop(否则在你上方展开会把整页顶下去);每行切换时加 170ms 淡入。切换会话后的第一轮
延迟一帧,因为 dsh 会在同一次提交里恢复该会话的滚动位置。
键盘焦点
dsh 自己的可展开行在点击处理里调用 focus(),而 focus 会把滚动视口移到被聚焦的元素上。由此
有两个后果:合成点击曾把焦点停在某一行上(下一次 Enter 会重新切换那一行,而不是发送消息),
而且在生成过程中,每一次新到达的工具调用都会触发一轮扫描 —— 此时点击阅读位置上方的行,会把
整段对话往上拽到那一行。
修复同时处理了因与果:在每次程序化点击期间,把该行的 focus 遮蔽为空操作,焦点不再移动,
滚动自然不发生;点击后若焦点仍有变化,再以 preventScroll 恢复。
回合结束后的处理(本次移植新增)
第三组决定已完成回答的收起方式:
| 选项 | 效果 |
|---|---|
| At answer end | 写入 dsh 自带的 collapseTiming: completion |
| On next message | 写入 dsh 自带的 collapseTiming: next-input |
| Keep expanded | 把当前会话切换为 Verbose —— "永不折叠"是每个会话的开关,而非 dsh 的全局值 |
前两项通过 ctx.configForms.get("ui-chat") 写入,与 dsh 自带设置行同一通道,因此内置渲染器
的反应与手动设置完全一致。第三项刻意复用按会话的 Verbose 开关,而不另存一个标志位:
"这个会话是否展开"若有两个真相来源,迟早会不一致,而那种不一致看起来就像其中一个的 bug。
安装
dsh plugin --profile web add dsh-verbose
dsh --profile web
本地目录:
dsh plugin --profile web add link:C:/path/to/dsh-verbose
安装后需重启宿主(bundle 行与 governor 桥都在宿主侧);仅浏览器部分改动时重新加载页面即可。
确认挂载:
dsh --profile web --dump-config | Select-String "id: verbose"
一行正确;零行表示 bundle 行未写入。
兼容性
- dsh 0.2 要求所有 strict codec 提供
create()。 原插件早于该规则,因此CG_CODEC增加了create: () => CG_CODEC.schema;缺少它时加载器会拒绝整个客户端插件,而不只是 remote。 - 插槽遮蔽是刻意的。 注册使用内置条目自己的 id(
session-log-download)并设置priority: -1;列表插槽对同一 id 只投影一个条目,优先级低者先投影 —— 这正是"替换按钮" 而不是"多出一个按钮"的原因。 context-governor可选。 宿主侧把它通过 Typert Remote 重新发布给 Compact 面板。 未挂载该插件时,桥在try内失败,各方法返回available: false,菜单自动省略该项。- dsh 0.2 对过程行做了分组。 0.1.5 给每一行都打
[data-expandable][aria-expanded]; 0.2 把一个回合的过程行合并成一个button[data-turn-process],仅 bash 工具视图仍标记自身 (data-variant="bash")。因此引擎匹配[data-turn-process][aria-expanded], [data-expandable][aria-expanded]—— 移植自 0.1.5 的 选择器在这个版本里匹配不到任何东西,表现正是"Verbose 毫无反应"。 需要知道的限制:折叠状态下组内只有一个按钮,因此单独关闭 Thinking 无法在组关闭时隐藏推理 —— 组要么展开,要么不展开。 - 存储键带插件前缀(
dsh-verbose.verbose、dsh-verbose.categories),与原来的session-view-menu并存也不会互相污染。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
条目加载失败(dsh-verbose: failed) |
apply 读取了未声明的服务 |
本插件声明 slots + remote,对照错误文本检查 |
| 出现两个三点按钮 | 另一个插件也遮蔽了 session-log-download |
只保留一个,两者 id 相同 |
| Verbose 没有反应 | 当前会话尚无任何可展开行 | 发一条消息,行会随回合出现 |
| 没有 Compact settings | 未挂载 context-governor |
属预期,该面板可选 |
| 刷新后设置丢失 | 隐私模式 / 存储被禁用 | 本插件依赖 localStorage |
开发
npm test
tests/client.test.mjs—— 用 shim 加载真实 bundle,断言决定其能否挂载的两件事:声明的服务、 插槽遮蔽(名称、内置 id、优先级、registrant);并渲染一层菜单,确认触发器存在、弹窗默认关闭。tests/classify.test.mjs—— 引擎分类规格:推理包装层、普通工具行、单元素同时带两个属性的 bash 行,以及已展开的思考块。
许可证
MIT,见 LICENSE。实现改编自 session-view-menu 1.1.0(MIT,同一作者),
按 dsh 0.2 的 codec 规则与上述命名空间做了适配。