dsh-turn-navigator
v0.4.8
Published
Smoothly Turn Nav (Smoothly TN): full-history piano-key turn rail for DeepSeek Harness (dsh) web conversations — see every turn at a glance, hover to preview, click to jump anywhere, and replace the official (non-disableable) turn rail.
Maintainers
Readme
思磨力轮次胶囊条(Smoothly Turn Nav)
思磨力 · Smoothly — 品牌 · 英文名:Smoothly Turn Nav(简称 Smoothly TN)
English · 简体中文
整场会话,一眼纵览。
思磨力轮次胶囊条(Smoothly Turn Nav,简称 Smoothly TN)是 DeepSeek Harness(dsh)的外部插件,在每条会话右侧放一条钢琴键式轮次胶囊条——竖向一列小胶囊,一轮一个。它是整场会话的迷你地图:全部历史轮次一目了然(不只是当前已加载的窗口),悬停预览、点击跳转到任意轮次起点、滚动跟随高亮。它还可以取代官方内置轮次胶囊条(官方没有自己的关闭开关)。

为什么需要
默认 DSH Web UI 的官方轮次胶囊条历史上只显示当前已加载窗口内的轮次——长会话里,大部分轮次要滚动加载后才可见。从 dsh 0.1.3-alpha.1 起,官方胶囊条也通过宿主侧 turnOutline 投影补上了紧要的全会话范围与窗口外跳转,但它依然无法关闭。思磨力轮次胶囊条解决长会话问题,并且始终可替换:
- 全量历史一眼可见——所有持久化轮次以纯数据呈现,包括远在已加载窗口之外的轮次。不滚动、不加载、不等待。
- 悬停即预览——胶囊以主题色亮起并泛起波浪涟漪;DSH 风格 Tooltip 展示该轮序号、时间、提示词与回复预览(与官方一样两行内容)。提示词按序回退:journal 读到的完整首条人类消息 → 已加载窗口的主机侧有界 prompt → 宿主
turnOutline投影 → 本地化轮次标签(第 N 轮,首行);回复预览同样来自宿主投影(窗口response优先,turnOutline.response兜底,≤120 字)。机器唤醒的轮次(goal 续跑、plugin 唤醒、后台作业回报、compaction 检查点:本来就没有人类提示词)显示"轮次号 + 时间 + 回复预览",不会显示占位符或注入文本。 - 点击跳转任意轮——包括尚未加载的轮次(按需扩展窗口,带即时反馈)。
- 随时知道自己在哪——滚动时当前轮次高亮。
特性
| | |
|---|---|
| 🗺️ 全量历史迷你地图 | 所有轮次立即可见——从持久化会话日志以数据读取,打开会话零 prepend(长会话保持流畅) |
| 🎹 钢琴键设计 | 每轮一个约 3px 高的胶囊,右缘右对齐;长度自适应(上限 30vh),超出后内部滚动(滚动条隐藏) |
| 🌊 波浪悬停 | 悬停的胶囊以主题色亮起并向左加宽 150%,相邻两个加宽 125%——滑过时如波浪起伏 |
| 💬 丰富 Tooltip | 轮次序号、时间戳、提示词 + 回复预览(提示词回退链:journal 的完整首条人类消息 → 窗口的有界 prompt → 宿主 turnOutline → 本地化 第 N 轮;回复预览来自窗口/turnOutline 投影),气泡位置夹在视口内 |
| 🎯 跳转任意轮 | 精确 scrollTop 定位(不与 scrollIntoView 打架);窗口外跳转按需扩展窗口并显示"正在定位第 N 轮…"脉冲+气泡;最老轮次跳转加载到真正第一轮(hasMore = false) |
| 👁️ 滚动跟随高亮 | 阅读线所在轮次的胶囊随滚动点亮——且胶囊条自身视口会跟随当前轮次保持可见 |
| ⬆️⬇️ 滚动按钮 | 点击或悬停持续滚动;无可滚动内容时置灰 |
| 🎛️ 胶囊条模式开关 | 设置 → 通用 → 轮次导航:DSH 官方 / 思磨力轮次胶囊条(默认)/ 全部隐藏——跨刷新持久保存,官方胶囊条终于可以关掉 |
| ♿ 键盘可达 | Tab 聚焦即出预览(aria-describedby → role="tooltip"),可访问名是动作而非内容(跳转到第 N 轮 / 加载并跳转到第 N 轮),活动/加载态走 aria-current/aria-busy |
| 🔌 纯外部插件 | 不改 DSH 源码;零宿主改动;零新增依赖;不写会话内容(DOM 写入仅限注入的 style 标签、一个 body class 与一次性跳转高亮) |
与官方 DSH 轮次胶囊条对比
官方内置 TurnNavigator 没有关闭开关,始终渲染在会话视图里。下表对比对象为 dsh 0.1.3-alpha.1(当前 DSH Web 的 TurnNavigator,该版也通过自己的宿主投影恢复了全会话范围)与本插件 思磨力轮次胶囊条 v0.4.8:
| 能力 | DSH 官方胶囊条(0.1.3-alpha.1) | 思磨力轮次胶囊条(v0.4.8) |
|---|---|---|
| 显示的轮次 | 全部轮次——宿主 turnOutline 投影(0.1.3+) | 全部持久化轮次——客户端读取 journal |
| 全量历史的健壮性 | 依赖宿主 turnOutline 投影——浏览器合成会话(如 ?fixture)不驱动投影,此时退回"仅加载窗口" | 始终全量——直接读持久化日志,无需宿主投影(真实会话与 fixture 会话均已实测全量) |
| 全会话历史怎么读 | 宿主侧 turnOutline 投影,由会话视图读取(会话快照本身不带投影值) | 客户端分页读持久化日志(session/page);旧版 dsh 退回 sessions.history RPC——零宿主改动 |
| 跳转窗口外轮次 | ✅(0.1.3+ 未加载锚点按 seq 分页) | ✅ 按需扩展窗口 + "正在定位第 N 轮…"脉冲/气泡 |
| 长会话打开性能 | 读投影 | 零 prepend——纯数据、不重渲染会话流、不卡顿 |
| 滚动跟随高亮 | ✅(0.1.3+ 让 active mark 保持在胶囊条视口内,带指针守卫) | ✅(v0.4.1+ 同款指针守卫跟随) |
| 悬停预览 | prompt(1 行)+ response(≤3 行),无时间戳;无人类提示词的轮次其 prompt 行只显示轮次号 第 N 轮 | 轮次号 + 时间戳 + 提示词(journal 读到的轮次为完整首条人类消息;窗口内为主机侧有界 prompt 预览;都读不到时用 turnOutline,再回退本地化 第 N 轮)+ 回复预览(宿主投影,≤120 字,与官方同源) |
| 波浪涟漪动画 | ❌(改为固定节距 tick 加宽) | ✅ 波浪涟漪 |
| 滚动按钮(点击 / 悬停持续) | ❌(滚轮 + 渐隐) | ✅ 点击 / 悬停持续 |
| 胶囊条高度 | 动态 band(自然高…420px) | 自适应(≤30vh)+ 内部隐藏滚动条 |
| 窄窗口(<900px) | 自动隐藏 | 自动隐藏(与官方对齐) |
| 隐藏 / 切换胶囊条 | ❌ 无开关 | ✅ 设置 → 通用 → 三档;全部隐藏 两者皆隐 |
| 键盘可达 | ✅ 焦点环 + aria-current/aria-busy/aria-describedby | ✅ 同款:可访问名 = 动作(跳转到第 N 轮 / 加载并跳转到第 N 轮,未加载轮次会先翻页)+ aria-current/aria-busy,预览经 aria-describedby 指向 role="tooltip";Tab 聚焦即出预览(与官方一致,不靠鼠标) |
| 来源 | 内置、无法关闭 | 外部插件,可替换 / 可关闭 |
dsh 0.1.3 起官方胶囊条已在紧要的全会话范围与窗口外跳转上追平。思磨力轮次胶囊条仍然独占的:可以关掉它(官方关不掉)、Tooltip 带时间戳(journal 读到的轮次还给完整首条人类消息,并有与官方同源的回复预览;没有人类提示词的轮次与官方一致回退到轮次号 + 回复预览)、滚动按钮 + 波浪悬停、以及它始终是零宿主改动、不写会话内容的外部插件。在 dsh ≤ 0.1.2 上官方胶囊条更简单(仅加载窗口),思磨力轮次胶囊条填补的差距更大。
dsh 0.1.3-alpha.1 实测(2026-09-06,Playwright 直连在线 Web UI):真实 42 轮会话上两个胶囊条都显示全部 42 轮(官方走宿主投影、我们走 journal);?fixture 浏览器合成会话上官方胶囊条退化为"仅加载窗口"(24/75),而思磨力轮次胶囊条仍显示全部 75——因为我们的全量历史从不依赖宿主投影。跳转、滚动跟随高亮、模式开关、以及减法接管官方胶囊条(样式覆盖 display: none)均实测通过。
版本对照
我们的版本与 dsh 版本的对应关系:
| 思磨力轮次胶囊条 | dsh | 说明 |
|---|---|---|
| v0.1.x | dsh ≤ 0.1.1 | 通过旧版 sessions.history 浏览器→宿主 RPC 读全量历史 |
| v0.2.x – v0.4.1 | dsh 0.1.2+ | 适配 ui-chat 重构;通过 journal session/page 通道读全量历史;v0.4.1 修复真实轮次号与胶囊条视口跟随 |
| v0.4.2 | dsh 0.1.2+(含 0.1.3-alpha.1) | 对照 dsh 0.1.3 官方胶囊条更新对比与定位(见上文) |
| v0.4.3 | dsh 0.1.2+(含 0.1.3-alpha.1) | 本版:品牌命名规范化为 Smoothly(思磨力)/ Smoothly Turn Nav(Smoothly TN)/ 思磨力轮次胶囊条——技术标识符(npm 包名 dsh-turn-navigator、插件/slot ID、locale 命名空间、CSS 前缀、localStorage key)不变 |
| v0.4.4 | dsh 0.1.2+,客户端契约对照 0.1.6-alpha.2 复核 | 本版:官方胶囊条的 body class 补上 dispose(从 dsh 插件页在线停用/重载后会恢复内置胶囊条);清掉两个陈旧 inject 条目 |
| v0.4.5 | dsh 0.1.7+ | 本版:图标导入跟随 0.1.7 视觉语言改名(*Regular 笔画变体,渲染尺寸不变)——客户端半区自此要求 0.1.7;0.1.2–0.1.6 请用 v0.4.4 |
| v0.4.6 | dsh 0.1.7+ | 本版:0.1.7 下限在 package.json 里声明为对 @deepseek-ai/dsh-client-ui-conversation 的可选 peer 依赖(>=0.1.7-rc.1);带 dsh peer 校验器的宿主(0.1.7-rc.1 起)可据此拒绝加载不满足下限的插件并给出 dsh plugin allow-version 的具体解法。无行为变化;没有校验器的运行时不受影响——0.1.2–0.1.6 请用 v0.4.4 |
| v0.4.8 | dsh 0.1.7+ | 本版:Tooltip 增加回复预览(窗口 response → turnOutline.response,与官方两行内容对齐);无人类提示词的轮次不再只显示轮次号 |
| v0.4.7 | dsh 0.1.7+ | 本版:tooltip 标签不再伪造——机器唤醒的轮次在数据层保留空标签,渲染层回退本地化轮次号(与官方同语义);journal 折叠只认追加的人类消息;宿主 turnOutline 投影合并为第三个标签来源。新增行为门禁 scripts/test-turn-labels.mjs(已进 npm test/verify:all)与真机门禁 npm run verify:turn-labels |
本文 README 的对比对象为 dsh 0.1.3-alpha.1;在更旧的 dsh 上官方胶囊条更简单,思磨力轮次胶囊条的优势更大。v0.4.6 把 0.1.7 下限声明进 package.json(见上方版本对照)。dsh 的 peer 校验器自 0.1.7-rc.1 起才有,而凡是带校验器的运行时本来就满足 >=0.1.7-rc.1——所以这份声明是把下限写成机器可校验的形式,也是将来抬高下限时由宿主按 dsh plugin allow-version 拒绝加载的机制;它不是旧运行时的护栏(0.1.6 及更早、以及 0.1.7-alpha.N 都没有校验器,会照常加载本 bundle),因此 0.1.2–0.1.6 请用 v0.4.4。-rc.1 下限是刻意的:>=0.1.7 与 ^0.1.7 都不匹配 0.1.7-rc.N 运行时。
安装
dsh plugin --profile web add dsh-turn-navigator然后重启 dsh web:
dsh web使用
- 选择显示哪个胶囊条(设置 → 通用 → 轮次导航):
DSH 官方(内置 rail)、思磨力轮次胶囊条(本插件 rail——默认)、或全部隐藏。官方 rail 没有关闭开关,选择思磨力轮次胶囊条时以样式覆盖将其隐藏,我们的 rail 接管右缘居中位置。选择会跨刷新持久保存。 - 打开任意包含至少一轮已完成轮次的会话。
- 会话右侧出现一条竖向灰色胶囊列(每轮一个)。胶囊条长度自适应:轮次少则短,轮次多则达 30vh 上限后内部滚动(滚动条隐藏,无布局抖动)。
- 悬停某个胶囊:它以主题色亮起并泛起波浪、向左加宽,胶囊条左侧弹出 Tooltip(序号、时间、提示词、回复预览;没有人类提示词的轮次只显示轮次号 + 回复预览),始终完整在视口内。
- 点击某个胶囊:会话滚动到该轮起点并短暂高亮目标行;窗口外轮次会先脉冲闪烁 + 弹出"正在定位第 N 轮…"气泡,按需扩展窗口后定位。被点击的胶囊自动滚动到胶囊条中央(首尾两条除外)。
- 滚动:滚轮、上下按钮、或按住按钮持续滚动。
原理
插件注册两个加法 slot——不修改 DSH 源码:
| Slot | 作用域 | 职责 |
|------|--------|------|
| conversation.session.header.utilities | session | 悬浮轮次胶囊条(position: fixed;通过框架 useChat/useSession kit 读取实时会话快照) |
| settings.general.item | root | 设置 → 通用 的 轮次导航 模式开关 |
- 全量历史即数据:dsh 0.1.2+ 上,胶囊条通过 Typert Remote
session/page通道分页读取与官方窗口同一条持久化日志(ctx.remote.session——由基础 web 装配挂载;零宿主改动、零新增依赖);旧版 dsh 走sessions.historyRPC。每轮从turn/start/user/message/turn/end原始事件派生为纯数据。 - 按需跳转:点击窗口内轮次直接滚动;窗口外轮次通过官方会话 store 的
loadOlder()逐页扩展窗口(以权威hasMore为终止条件)直到目标进入视图——这是唯一触碰会话流的路径,且只在点击时发生。 - 精确定位:取该轮第一个 chat-node key,通过
data-chat-anchor-key找到 DOM 行,直接设置滚动容器scrollTop(比scrollIntoView更可控)。 - 取代官方胶囊条:官方 rail 位于会话滚动容器内;模式开关驱动的容器限定样式规则将其隐藏,我们的 rail 接管右缘居中位置。已在结构层面核对 dsh 0.1.3-alpha.1——
[data-conversation-scroll] nav隐藏规则依然匹配。若未来 dsh 改变该结构,最坏情况是官方 rail 重新出现(并存)——绝不会崩溃。 - 不外发数据、不写会话内容:插件从不向任何地方发送数据、从不写入会话内容,仅读取 DOM 用于定位。可见的副作用只有:注入的
style标签、tn-hide-officialbody class(dispose 时移除)、目标行上的一次性高亮 class,以及你点击窗口外轮次时才触发的按需窗口扩展。
兼容性
- DeepSeek Harness (dsh) Web 客户端(
dsh web);基于 dsh 0.1.2+ 开发与实测,并在 dsh 0.1.3-alpha.1 上复测通过(Playwright 直连实测,2026-09-06:全量历史胶囊条、跳转、跟随高亮、模式开关、官方胶囊条样式接管全部通过)。 - 需要
conversation.session.header.utilities与settings.general.itemslot 声明(当前 DSH 已包含)。 - 客户端契约已对照 dsh 0.1.6-alpha.2 复核(2026-09-22):
conversation.session.header.utilities与settings.general.item的 slot 声明、胶囊条用到的ui-primitives导出、以及它引用的--dsw-alias-*token 均仍存在。0.1.6 上的 Playwright 交互复测未重跑(2026-09-06 那次仍是最近一次交互验证)。 - 默认
思磨力轮次胶囊条模式以样式覆盖隐藏官方 rail,我们的 rail 居中接管;DSH 官方模式显示内置 rail;全部隐藏两者皆隐。900px 以下都自动隐藏。 - 与 DSH 全局面板(如看板)共存:面板接管
mainslot 条目,会话视图(连同本胶囊条)随之被换出,而不是叠在其下。 - 已知限制(DOM 兜底):当没有可读的会话存储(较旧宿主)时,胶囊条通过点击会话流自带的翻页控件来扩展窗口,而这条路径只识别该控件的中/英文案(空闲与加载中)——在第三种语言的宿主上它无法扩展窗口;主用的 journal 通道(dsh 0.1.2+)完全不读文案。
开发
pnpm typecheck— TypeScript 检查(tsdown 只转译不检查)。pnpm test— 类型检查 +scripts/test-client-dispose.mjs:在 DOM 桩里加载构建产物,断言官方胶囊条 body class 的 apply/dispose 契约。pnpm bundle— 构建模块表 client bundle 到lib/。scripts/verify-*.mjs— 针对真实dsh web的 Playwright 验收脚本(rail、全量历史 journal、模式开关、跳转、反馈、overlay、尺寸、UI)。pnpm release:check— 发布门禁(版本、tag、工作树、构建、registry)。
许可证
MIT
