dsh-quick-toc
English | 中文
DeepSeek Harness(DSH)对话大纲插件:把 AI 回复中的 Markdown 标题(H1–H6)提取成可导航的大纲——侧边面板与全屏幕布两种大纲视图,按对话回合分组、覆盖整段会话(含尚未加载进窗口的回合),支持标题/全文/跨会话三档检索、悬停预览、多种跳转(点标题、点组头、跳到本节末尾),阅读位置自动跟随并可记住。
功能
- 按回合分组 —— 每条用户消息 + 其后续 AI 回复为一组,组头显示回合时间与首行预览,点击跳到该回合模型回答的开头
- 覆盖整段会话 —— 未加载进对话窗口的回合也在列表里(带「未加载」标记与预览);点击即加载该回合并跳过去
- 失败回合的报错 —— 请求超时 / 上游报错这类没有回复的回合显示
请求失败 与报错原文,点击跳到对话中的报错位置
- 全屏「幕布」 —— 对话顶边标签条里的液滴把手(或面板标题栏的「幕布」圆钮)把大纲铺成整幅宽度落下:没有遮罩、不压暗对话,字号与行距都放大,每行三段(层级徽标 / 标题 / 该节正文开头),搜索栏从右侧推进来;点条目、Esc 或 ✕ 收起。它与停靠面板共用同一份列表,滚动位置、搜索、键盘光标全部延续
- 跳到本节末尾 —— 悬停标题行 / 组头 / 结果行,右端渐显一枚圆钮,点击跳到该节内容结束处;组头这颗跳到整轮对话的末尾
- 跨会话检索 —— 搜索范围第三档「会话」用宿主的全文索引搜其他会话的消息正文,点结果切过去并继续查找;已归档 / 子会话 / 不在列表里的会话会被略过并计数
- 只看提问 —— 一键把大纲折成「每轮只留时间与你的提问首行」
- 记住阅读位置 —— 重新打开会话回到上次读到的那一轮(半小时内有效;可在设置里关掉)
- 键盘导航 —— ↑/↓ 移动光标、Enter 跳转、Home / End 到首尾、Esc 收起;光标位置有屏幕阅读器播报
- 中英双语 —— 界面语言可设为跟随宿主、中文或 English;中文时间戳用
昨天 / 前天,英文昨天用 yesterday、更早用 YY-MM-DD HH:MM 日期
- 插件配置卡片 —— 设置 → 插件 → 插件配置里的「对话大纲」卡片:语言、默认停靠边缘、显示的标题层级、收起把手的位置、记住阅读位置、模糊搜索、悬停预览与诊断开关;改过的字段标「已自定义」并可单独重置(改回默认值时标记自动消失),卡片与面板实时同步
- 回合时间带日期 —— 昨天
昨天 15:04、前天 前天 15:04、更早 25-09-11 15:04,跨天的会话里时间不再重影
- 标题行副标题 —— 每行标题下方显示该节正文的第一句,同名标题一眼可辨
- 悬停预览 —— 悬停标题行显示该节开头、回合时间与层级路径
- 搜索 —— 标题 / 全文两种范围,结果列表点击定位并高亮,
n/N 回车逐处跳,Esc 关闭
- 搜索容错 —— 大小写、全角半角、连续空白自动视为同一匹配;「模糊」开关可放宽到关键字中间夹字
- 对话内高亮 —— 命中的关键字在对话中高亮,当前命中单独标亮
- 组头吸顶 —— 滚动大纲时,当前回合的组头固定在面板顶部
- 层级筛选 —— 标题栏的圆形层级按钮弹出 H1–H6 开关,任意组合显示
- 自动跟随 —— 滚动对话时正在阅读的回合自动点亮(封闭蓝框),大纲自动跟随
- 跳转 —— 点击标题跳到对话中该标题的位置,滚动动画交给浏览器自己的平滑滚动(按真实时间推进,60Hz 与 240Hz 屏幕上时长一致);飞行中目标被宿主翻页挪动时会重新瞄准、动画被宿主滚动打断时会重新发起,跨页远跳不会半途停下;若某个浏览器把平滑滚动直接执行成瞬移,插件改为自己逐帧绘制。面板与对话双向定位
- 回到底部 —— 往上翻远之后,列表右下角的浮动按钮一步回到最新一条(不在底部时出现、到底后消失)
- 回到我离开的位置 —— 关闭面板或幕布时记住列表顶部那一行(两者各记各的、互不覆盖),下次打开时列表右上角出现向上的浮动按钮,一步回到那一行的原位置;用过一次或自己滚回该处就渐隐并忘掉,直到下次关闭再记。同一规则下,打开面板或幕布时正在阅读的那一行会落在列表顶部(读的就在最新几轮时列表已经到底,那一行自然停在底部)
- 可停靠、可缩放 —— 拖顶部横条移动,◀ / ▶ 切换左右停靠,拖边缘调宽高(尺寸没有上限,最窄可到 120px),收起后成为边缘把手(停在什么高度由设置里的「把手位置」决定);位置与尺寸按浏览器记住(顶边距、宽度、高度只通过拖拽调整)
- 面板缩放 —— 设置里的滑块把内容(文字、图标、按钮及其间距)在 50%–200% 之间按 5% 一档缩放,面板本身的尺寸不变;拖动滑块时只移动读数,松手才写入设置。面板变窄时顶栏四颗按钮保持一行:先挤掉中间的空白,挤满后整行可横向滚动(在顶栏上滚滚轮即可),此时顶部的灰色拖拽横条渐隐消失
- 分页 —— 默认显示最近的若干组,向上滚动既展开索引也加载更早的对话
- 边界提示 —— 滚到最早或最新再继续滚动时,面板底部短暂提示
- Markdown 感知 —— 标题中的行内标记会被剥离;围栏代码块里的
# 行不算标题
- 主题适配 —— 深色 / 浅色主题自适应;仅对话视图显示,切到其他视图渐隐
- 对话中没有标题也没有可识别时间时面板自动隐藏
兼容性
| 插件版本 | 支持的 DSH 版本 |
|---|
| 0.7.x(最新,0.7.1) | 0.1.5-rc.1、0.1.5-rc.2 |
| 0.6.x(0.6.3) | 0.1.5-rc.1、0.1.5-rc.2 |
| 0.5.x(0.5.1) | 0.1.5-rc.1、0.1.5-rc.2 |
| 0.4.x(0.4.1) | 0.1.5-rc.1、0.1.5-rc.2 |
| 0.3.x(0.3.3) | 0.1.5-rc.1 |
| 0.2.x(0.2.2) | = 0.1.2-rc.1 |
每个大版本只列该系列最新的一个补丁版本(新功能引入的缺陷都在其后的补丁里修掉了,所以同一个大版本内直接用最新补丁即可;旧补丁仍可继续用,插件不破坏既有接口)。
engines.dsh 下限为 0.1.5-rc.1(>=,该版本起插件改用会话级槽位注入的宿主接口)。0.7.1 在 0.1.5-rc.2 上实测通过(「回到我离开的位置」浮动按钮、面板与幕布分别记录的离开位置、打开时落在正在阅读的那一行、以及在底部关闭再打开不出按钮都逐项确认);0.7.0 在同一版本上实测通过(全屏幕布与液滴把手、跳到本节末尾、跨会话检索、键盘导航、只看提问、记住阅读位置都在真实浏览器里逐项跑过;面板缩放、尺寸的落盘与读回、收起把手的位置等既有能力此前已实测);0.1.5-rc.1 上实测了插件加载与客户端模块下发(宿主启动无报错、--dump-config 里有 quick-toc 条目、客户端组合包 URL 里列出 dsh-quick-toc/client.js,取回的下发内容包含本版新增的幕布把手、跳到本节末尾与阅读位置等标记),它依赖的宿主接口——turnOutline 投影、会话级槽位的 useProjection、客户端 sessions 服务与 loadThrough 跳转加载器(0.5.0 起)、失败回合所用的 turn-error 节点(0.5.1 起)、以及 0.6.0 新增的宿主 settings 服务(installSection)、客户端 settingsScope 与 settings.plugin.item 配置卡片槽位、以及 0.7.0 跨会话检索所用的客户端 sessions.search——在 0.1.5-rc.1 与 0.1.5-rc.2 的安装包中逐个核对存在(这些宿主包的代码在两版之间逐字节相同,dsh-client-ui-chat 仅差一条与本插件无关的 CSS 声明;search 所在的 dsh-api-session-controller 两版逐字节相同,含「一次最多 20 条、片段上限 240 字符」的同一套上限),因此两版都声明兼容。更早或更新的 DSH 版本未经验证,不作声明;在更早的 DSH 上可安装的最新插件版本是 0.3.2。安装或更新时,DSH 市场会依据 package.json 中的 engines.dsh、dsh.compatibility.dshReleases 与 peerDependencies 做宿主兼容预检。
安装
通过 DSH CLI 安装:
dsh plugin --profile web add dsh-quick-toc
也可以从 GitHub 安装:
dsh plugin --profile web add github:LyaxZ/dsh-quick-toc
或以本地目录安装:
dsh plugin --profile web add <插件目录路径>
安装后重启 DSH 并打开 Web UI。面板默认收起:点对话区边缘的把手展开面板,或点对话顶边标签条里的液滴把手直接把大纲铺成整幅宽度落下。
使用
- 跳转:点击大纲标题或组头跳到对应位置;带「未加载」标记的条目会先把该回合加载进来再跳;失败回合点报错行跳到对话中的报错位置
- 搜索:放大镜打开搜索框,输入后点结果定位并高亮,回车逐处跳,Esc 关闭
- 搜索容错:全角/半角、大小写、空格差异会自动匹配;需要更宽松时点搜索框右侧的「模糊」开关
- 层级筛选:点标题栏的圆形层级按钮弹出 H1–H6 开关,选择显示的层级
- 移动与停靠:拖顶部横条移动,◀ / ▶ 切换左右停靠
- 调整大小:拖右边缘、下边缘或右下角(没有上限,最窄到 120px;面板过窄时顶栏可横向滚动)
- 加载更早:在大纲中向上滚动(既展开索引,也加载更早的对话)
- 幕布:点对话顶边标签条里的液滴把手(或面板标题栏的「幕布」圆钮)展开全屏大纲;点任意条目、按 Esc 或点右上角的 ✕ 收起
- 跳到本节末尾:悬停标题行 / 组头 / 结果行,点右端出现的圆钮
- 跨会话检索:搜索框右侧的范围按钮点两下切到「会话」,用宿主的全文索引搜其他会话;点结果切到那个会话并继续查找
- 键盘:面板打开后 ↑/↓ 移动光标、Enter 跳转、Home / End 到首尾、Esc 收起;搜索框里 ↑/↓ 在命中之间切换
- 只看提问:标题栏的语音气泡按钮把大纲折成每轮的时间 + 你的提问首行
- 回到底部:翻远了之后点列表右下角的浮动按钮回到最新一条
- 回到我离开的位置:关掉面板或幕布时它记住你当时看的那一行;下次打开时右上角的浮动按钮一步带你回去
- 阅读位置:滚动对话,正在阅读的回合会以蓝框标出;大纲会自动跟随
- 设置:在 设置 → 插件 → 插件配置 里展开「对话大纲」卡片,可改语言、默认停靠边缘、面板缩放(50%–200% 滑块,5% 一档)、收起把手的位置(0%–100% 滑块,1% 一档;0% 在最下、100% 在最上,默认 50% 居中)、显示的标题层级、记住阅读位置与模糊/悬停/诊断开关;改过的字段可单独重置(改回默认值时标记自动消失)。卡片与面板实时同步,不需要刷新;偏好保存在 DSH 的设置里,跟随配置走
诊断
面板挂载时默认不打印任何日志。需要排查宿主能力时,在 设置 → 插件 → 插件配置 里展开「对话大纲」卡片、勾选「在控制台打印诊断日志」——打开后当下就会打印一行(无需刷新):
[dsh-quick-toc] panel mounted · turnOutline=… · jumpLoader=… · lang=… · prefs=…
turnOutline 缺失说明宿主没有该投影,jumpLoader 的分阶段措辞(no-sessions-service / no-binding-api / no-binding-for-session / no-loadThrough / binding-threw)可直接定位跳转桥断在哪一环。
开发
lib/client.js —— 全部 UI 逻辑(浏览器端)
lib/index.js —— 宿主半:注册 dsh-quick-toc 设置命名空间(schemastery schema,含取值范围校验),让偏好进入 DSH 的设置文档并提供插件配置卡片的入口
cordis.patch.yml —— loader patch(符合官方 bundle 规范)
- 面板注册进会话级
conversation.input.overlay 槽以取得会话级 hook(useChat、useSession、sessionId 等),面板本体通过 createPortal 渲染到 document.body 成为固定浮层;对话数据来自 props.useChat(ChatSnapshot.order 与 nodes,节点形状:kind: user/assistant-step、location.turn、data.blocks)
- 「未加载回合」能力依赖宿主的两样东西:
turnOutline 投影(整段会话的回合索引,每条含 turn/start 的 seq)与会话跳转加载器(客户端 sessions 服务的 binding(sessionId).session.loadThrough(seq),通过客户端 ctx 的 ctx.get("sessions") 免声明查找取得)。两者各自独立降级:没有投影时只列已加载回合,没有加载器时未加载条目只展示、不跳转,面板其余功能不受影响。
- 失败回合的报错行读的是宿主的
turn-error 会话节点(宿主在 turn/end 的原因为 error 时发布,含 message 与可选的 code);宿主不提供该节点时只是不显示这一行,其余功能不受影响。
- 界面文字来自
lib/client.js 顶部的一张字符串表(DICTS,中英各一份),语言设置决定用哪一份:跟随宿主 时优先问宿主的翻译函数(ctx.locale.bind("dsh-quick-toc"),注册的表就来自 DICTS),拿不到才回退到内置表。中英两份表的键必须对齐(仅 time.beforeYesterday(前天)是中文独有——英文对更早的时间直接用日期;time.yesterday 两语言都有,英文作 yesterday)。
- 偏好存储分两层,由一个模块级 store 统一读出:宿主设置文档(
ctx.settingsScope.bind({ namespace: "dsh-quick-toc" }),语言/停靠边/层级/缩放/把手位置/记住阅读位置/模糊/悬停/诊断九项,回环页面上是权威层)与 localStorage(镜像 + 顶边距/宽度/高度三项的正式存储——它们描述"这一块屏幕",按浏览器保存)。写入按字段路由:宿主字段走 scope.mutate(本地同步折叠、宿主应答后对账),其余写 localStorage;写入的值若正好是该字段的默认值,则改为把用户层里的这一项删掉(等同于"未自定义")。非回环页面 DSH 将设置标记为只读,此时这九项偏好退回本地镜像,行为与 0.5.x 一致;0.5.x 留下的本地值会在宿主层首次应答时导入一次(仅当用户层为空)。
- 幕布与停靠面板共用同一份列表 DOM:幕布只是把面板本体搬进一个从标签条下沿落下的整宽容器(面板在幕布态换一套几何:相对定位、宽高 100%、不套用面板缩放),容器本身常驻挂载、收起时是一个 0×0 的直通盒,所以开关幕布不会重建列表、也不会丢掉滚动位置。跨会话检索走客户端
ctx.get("sessions") 的 search(query, signal)(走宿主的会话全文索引,一次最多 20 条);每个会话的阅读位置存在浏览器本地(dsh-quick-toc.readPos.v1,半小时内有效)。
- 插件配置卡片注册进
settings.plugin.item 槽(key 为插件命名空间;该槽按宿主实际提供的命名空间派发,宿主半未加载时卡片自然不出现,面板不受影响);卡片与面板共享上面那个 store,因此两边实时互通。
- 修改
lib/client.js 后刷新页面即可看到变化(客户端模块按内容哈希发版,DSH 的客户端 HMR 也会推送重载);改 lib/index.js(宿主半)需重启 DSH
License
MIT © 2026 LyaxZ