给 DSH 对话页右缘加一条节点导航条,悬停看预览、点击跳转,支持滚动切换、加载更早历史和按会话精选消息。
- Language
- TypeScript
- License
- MIT
- Branch
- main
Install
$ dsh plugin --profile web add github:vlln/dsh-navbarRun the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial
一句话定位
给 DSH 对话页右缘加一条节点导航条:每条 user 消息对应一个圆点,悬停看消息预览,点击或滚动滚轮快速跳转到对应消息,并支持把某条 assistant 回复钉成「精选」方便回访。
核心能力
- 在对话区右缘渲染一条纵向节点串,每条 user 消息对应一个圆点;激活圆点(22px 品牌蓝胶囊)随当前阅读位置自动移动
- 悬停节点立即显示消息预览卡,显示对应消息气泡文本前 6 行(沿用官方 HoverCard 视觉,整条导航条含间隙都连续响应)
- 点击节点、点击导航条任意位置,或光标在导航条上滚动滚轮(阻止对话区滚动),都会平滑滚动到对应消息
- 节点超过 11 个时自动切到滑动窗口(激活 ±5),两端用更小圆点暗示还有更多;当前选中或精选的节点始终强制可见
- 顶部 ↑ 按钮在会话还有未加载的更早历史时出现:点击转发给官方「加载更早」控件,自动保持当前阅读位置;全部加载完后按钮自动隐藏
- assistant 消息操作条新增 📌 按钮(位于 copy 与 Good response 之间),点击把该回复钉为精选;对应节点变成金色细长椭圆盘,状态按会话存到浏览器本地,点击直达被精选的回复
技术实现
- 语言: TypeScript(client bundle 由 tsdown 产出 CJS,浏览器通过
window.__ModuleLoader__加载) - 关键依赖:
@deepseek-ai/cordis(peerDependency)、@deepseek-ai/dsh-client-ui-primitives、react(仅 PinAction 按钮组件使用) - 架构模式: 官方 bundle 插件形态(
dsh.bundle+ dshClient 通道)。Node half(src/index.mjs)为空apply,仅作为 bundle 挂载载体;所有行为都在浏览器端src/client/index.ts(自渲染 DOM + 官方锚点契约)。零数据通道依赖,只读官方锚点属性(data-time-hover-root、data-chat-flow、data-turn-tail、data-pending-steering)驱动,不发请求、不注册工具、不改路由 - 入口文件:
src/client/index.ts(浏览器端)、src/index.mjs(Node half 空 apply)
适用场景
对话很长、来回翻找某一条 user 消息太慢时,用右缘节点条一眼定位、直接跳过去;想标记一条关键回复以后回访,用 📌 把它钉成精选节点;历史窗口还没加载完时,用顶部 ↑ 按钮边加载边定位,不用滚回顶部。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH | >= 0.1.0-rc.5 | 通过 package.json#engines.dsh 声明;依赖官方 0806+ 在 user 行加入的 data-time-hover-root 锚点属性 |
| Node.js | >= 22.19.0 | 仅构建时需要(tsdown 打包脚本),运行时由浏览器加载 lib/client.js |
| 平台 | 跨平台 | 作为 DSH Web 端的浏览器内 UI 插件工作,操作系统无限制;不支持 DSH 桌面端(Node half 为空) |
| 原生模块 | 无 | 不引入任何原生依赖 |
| React | 18.x | client 端 PinAction 按钮组件由宿主注入 React |
安装方式
dsh plugin --profile web add github:vlln/dsh-navbar
配置项
本插件无需额外配置。无需命令行参数、无需 cordis.yml 配置、无需设置面板开关;安装重启 web profile 后自动生效。
常见问题
Q: 安装后需要手动开启吗?
A: 不需要。插件被 web profile 加载后自动在对话页生效;安装完重启 web profile 即可。在设置页「插件」面板可以停用或重新启用。
Q: 节点条在哪些页面会显示?
A: 仅在 Chat 视图(也兼容挂载的聚焦会话视图 dsh-focus-chat)的对话页显示;设置页等其他页面,以及 user 消息少于 2 条时自动隐藏。
Q: 精选消息会跨设备同步吗?
A: 不会。精选状态按会话存到浏览器 localStorage(键名 dsh-navbar:pins:<sessionId>),刷新后保留,但不跨设备、不跨浏览器同步。
Q: 节点超过 11 个时会怎样?
A: 自动切到滑动窗口:只显示当前激活附近的 11 个节点(±5),两端用更小的圆点暗示还有更多;当前选中或精选的节点始终强制显示在窗口内,不会因为窗口滑动而看不见。
Q: 顶部 ↑ 加载更早历史按钮什么时候出现?
A: 仅当当前会话还有未加载的更早消息时出现(由官方「加载更早」控件的存在判定),全部加载完后按钮自动隐藏;加载过程中按钮禁用并显示「加载中…」。
Q: 卸载插件会清除精选数据吗?
A: 不会。数据存在浏览器 localStorage,卸载插件或重启 DSH 不会自动清理;要清理就在浏览器开发者工具里删除 dsh-navbar:pins:* 开头的键。
Q: 跳转后为什么有时位置会跳动一下?
A: 插件按官方 follow 0811 之后的「读者输入账本」判定直接一步定位。0811 之前的基线版本(0808/0810)会先用 wheel 事件做兼容兜底,可能与官方流式渲染产生轻微抖动。
上手难度
入门 — 装上即用,无命令、无工具、无配置项;唯一可选交互是悬停/点击节点,或点击 📌 钉选消息。
已知问题与限制
- 仅支持 DSH Web 端,Node half 为空(
src/index.mjs仅export default function apply() {}),不提供任何宿主侧能力 - 依赖官方
data-time-hover-root行属性锚点;若官方 DOM 结构变更需同步适配(README 提到该属性自官方 0806 版本起加在 user 行上) - 跳转适配官方 follow 的读者输入判定 0811 账本机制;旧版本(0808/0810)保留 wheel dispatch 兜底
- 节点条位置紧贴对话流列右缘 + 12px,钳制在视口内;当侧边栏折叠动画或窗口宽度变化使对话流列位置剧烈变化时,可能偶发位置抖一帧(已用 ResizeObserver + rAF 节流合并)
- 「加载更早历史」按钮转发给官方
ChatView的loadOlderAnchored控件;若官方按钮结构或位置变更,本插件的定位逻辑需同步适配
中文 | English
navbar
Conversation node navigation rail: jump between user messages from the node strip on the right edge of the conversation — hover to preview, click to jump
An evenly spaced node strip along the right edge of the conversation area (one node per user message): the active pill follows your reading position, hovering shows a preview card (truncated at 6 lines), clicking smooth-scrolls with a brand-blue highlight ring, more than 11 nodes automatically switch to a sliding window, it stays invisible until hovered, and it auto-hides when there are fewer than 2 user messages. Implements the dsh-external/issues#144 spec. Form: an official bundle plugin (dsh.bundle + dshClient channel, browser-only, empty Node half), 0 patches.
Preview

Features
| Feature | Description |
|---|---|
| Node navigation rail | Vertical node strip on the right edge of the conversation area, one dot node per user message |
| Follows reading position | The active pill (22px brand-blue capsule) moves with your current reading position |
| Hover preview | Hovering a node shows a message preview card (6-line truncation, matching the official HoverCard look) |
| Continuous hover | The entire rail (including the gaps between nodes) responds to hover continuously: the preview switches to the nearest node and the corresponding pill elongates (gray) to indicate the click target — no dead zones |
| Scroll-wheel switching | With the cursor over the rail, scrolling the wheel moves up/down one message (blocking conversation-area scrolling) |
| Click to jump | The whole rail is clickable (including gaps, jumping to the nearest node) plus an enlarged pill hit area — no need to precisely aim at tiny dots |
| Sliding window | When there are more than 11 nodes, only the nodes inside the window are shown (avoids overflow) |
| Load earlier history | An ↑ button pinned at the top of the rail (visible only while the conversation has older history): click to load earlier messages — it forwards to the official load-older control, so your reading position is preserved. Hovering it instantly shows a hint card in the same style as the node previews (the official HoverCard look) |
| Auto-hide | Not shown with fewer than 2 user messages or on non-conversation pages |
| Message pin | 📌 button on the assistant action bar (between copy and Good response); pinned turns render as a golden slim elliptical disc in the rail (always visible, the preview card carries a 📌 badge, clicking jumps straight to the pinned reply), persisted per session |
Zero data-channel dependencies: driven only by official anchor attributes (data-time-hover-root, on user rows since 0806) — no polling, no routing, no tools.
Installation
Recommended: one-line install from git source (build artifacts are committed, so git source does not trigger a build):
dsh plugin --profile web add "github:vlln/dsh-navbar#main" # one-line git-source install (build artifacts committed)
# or npm source: dsh plugin --profile web add @vlln/dsh-navbar@0.4.0
Or from a local directory (when you have the source): git clone, then cd dsh-navbar && dsh plugin --profile web add ..
Restart web after installing for it to take effect; you can disable/enable it in the Plugins panel on the Settings page.
Usage
Works out of the box — no commands, no tools. The node rail appears on the right edge of the conversation page (Chat view); hover for a preview, click to jump. Animations are disabled under prefers-reduced-motion.
Pin: hover an assistant message's action bar and click 📌 to pin that reply — the corresponding turn's navigation node becomes a golden slim elliptical disc (click to jump straight to that reply; the preview card shows a 📌 badge and the reply text). Pin state is saved per session in browser localStorage and survives refreshes; click again to unpin.
Load earlier history: when the open conversation still has older messages (its history window is not fully loaded), an ↑ button sits at the very top of the node rail. Click it to load the earlier messages — the rail then grows new nodes at the top. The button hides automatically once all history is loaded, and is disabled while a load is in flight. Hovering it instantly shows a hint card in the same style as the node previews (the official HoverCard look), and it reads "Loading…" while a load is in flight. The click is forwarded to the official load-older control, so your current reading position is preserved (no content jump).
Development
pnpm install
pnpm run build # tsdown: client bundle (lib/client.js)
- client:
src/client/index.ts(self-rendered DOM + official anchor contract; the pin button uses the officialconversation.chat.assistant-actionsslot, with React provided by the client runtime; ctx services accessed must be declared in the plugin object'sinject) - Node half:
src/index.mjs(empty apply, the bundle mount carrier)
License
MIT License (an example plugin in the DSH ecosystem).