TableRogue
dsh-message-navigator
消息导航条 Message Navigator: DeepSeek Harness 网页聊天界面右侧的垂直消息索引(动态 Cordis 插件)
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 14, 2026
- Updated
- Aug 14, 2026
Introduction
dsh-message-navigator
消息导航条(Message Navigator) —— 一个为 DeepSeek Harness 网页聊天界面开发的动态 Cordis 插件。
在聊天内容区最右侧添加一条细长的垂直消息索引条:每条用户输入对应一个半透明圆角短横线,点击即可平滑跳转到对应消息,手动滚动时当前阅读位置对应的标记自动高亮。适合在超长对话中快速定位历史输入。
English abstract: A dynamic Cordis plugin for the DeepSeek Harness web GUI. It renders a slim vertical index strip on the right edge of the chat viewport — one marker per user input message. Click a marker to smoothly scroll to that message; the active marker follows your scroll position in real time.
效果

演示:聊天内容区最右侧的垂直消息导航条 —— 每条用户输入对应一个半透明短横线 marker,当前阅读位置对应的高亮标记,悬停显示消息预览。
聊天内容区域 消息导航条
用户消息 A ─
AI 回复 ─
用户消息 B ─
AI 回复 ─
用户消息 C ─
AI 回复 ─
用户消息 D ━ ← 当前阅读位置
AI 回复 ─
用户消息 E ─
- 每个用户输入消息(含运行中插话 steering)对应一个 marker;AI 回复不生成 marker。
- marker 为 3px 高的半透明圆角短横线,以固定 12px 间距紧凑堆叠、在导航条内垂直居中;数量多到放不下时自动等比压缩,始终保持「一条用户输入 = 一个可点击定位点」。
- 当前阅读位置对应的 marker 高亮(变宽、提亮),滚动时实时同步。
功能特性
- 点击跳转:
scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' }),消息已在视口附近时跳过动画;尊重系统prefers-reduced-motion设置;inline: 'nearest'保证不产生横向位移。 - 滚动同步:以视口 40% 高度处为「阅读线」,最接近阅读线的用户消息对应 marker 实时高亮;滚动路径为纯算术计算,零 DOM 查询、零 React re-render。
- Hover 提示:悬停显示统一尺寸(240px、1–2 行、省略号)的消息预览 tooltip,不遮挡正文。
- 动态数据:新消息、删除消息、加载历史记录、切换会话/视图时自动重建 marker;AI 流式输出不会误生成 marker。
- 稳定标识:marker 与消息通过
data-chat-flow-key(引擎上下文键,内含持久化 messageId)一一对应,不依赖 DOM 临时索引。 - 响应式:≤1100px 隐藏 tooltip,≤880px 整体隐藏组件;不压正文、不覆盖输入框、不引入横向滚动。
- 性能:几百条消息下仍流畅 —— 滚动仅 rAF 节流;位置测量批量读取并节流;MutationObserver 防抖重建;marker 用 classList 直改,不触发 React 渲染。
安装与激活
本插件是一个 Client-only 的 dsh 组合包(bundle),同时附带动态插件源码。有两种启用方式:
方式一:持久化安装(推荐,每次启动自动加载)
本包声明了 dsh.bundle(自带 patch 层)与 dsh.client(浏览器 roster)。用 dsh plugin 安装进一个 profile 后,该 profile 每次启动都会自动加载本插件,无需任何手动步骤:
# 本地 checkout 安装(开发/试用)
dsh plugin --profile web add ./dsh-message-navigator
# 或从 GitHub 直接安装(本包为纯 JS,无构建步骤,无需 allowBuilds 授权)
dsh plugin --profile web add github:TableRogue/dsh-message-navigator
安装后 dsh 会把它追加进 profile 的 dsh.profile.bundles。层顺序为:
dsh-base → dsh-web-app → dsh-message-navigator → profile 自己的 cordis.patch.yml
→ $DSH_HOME/cordis.patch.yml → --patch overlay
验证安装(打印组合树,应能看到 # == dsh-message-navigator 层):
dsh --profile web --dump-config
之后正常启动即可(dsh --profile web),聊天界面右侧自动出现导航条。卸载:
dsh plugin --profile web remove dsh-message-navigator
浏览器端代码由 client-modules 的 node 半部在启动时扫描 dsh.client 声明,并通过 /plugins/dsh-message-navigator/client.js 路由直接服务 exports["./client"] 文件——无需重建任何 Web 产物。
方式二:动态插件(临时,单次进程)
作为动态 Cordis 插件激活(Client-only,无 Host 半部),以当前 DSH 进程为生命周期,进程重启后需要重新激活:
- 复制
src/client.js中头注释以下的完整内容; - 填入
cordis_define工具的code.client字段(code.host留空),选择kind: "new"并给出 3–6 位小写字母 idPrefix; - 用返回的
pluginId/packageId调用cordis_run(mode: "run"); - 在 Run 卡片上批准激活(单勾授权当前版本,双勾授权后续版本)。
之后更新代码请使用 kind: "existing" 追加新 Package,并以 mode: "update" 切换版本。
- 复制
src/client.js中头注释以下的完整内容; - 填入
cordis_define工具的code.client字段(code.host留空),选择kind: "new"并给出 3–6 位小写字母 idPrefix; - 用返回的
pluginId/packageId调用cordis_run(mode: "run"); - 在 Run 卡片上批准激活(单勾授权当前版本,双勾授权后续版本)。
之后更新代码请使用 kind: "existing" 追加新 Package,并以 mode: "update" 切换版本。
依赖的界面契约
插件通过只读方式使用 DeepSeek Harness Web GUI 的以下稳定 DOM 锚点(与产品自身滚动记忆逻辑相同):
| 锚点 | 含义 |
|---|---|
[data-conversation-scroll] | 会话聊天滚动容器(ConversationRoot 的 scrollBody) |
[data-chat-flow-key] | 每条消息行的稳定引擎上下文键,格式 13:input-message<messageId> |
| `[data-chat-flow-kind="user" | "steering"]` |
挂载点使用 shell.overlay(加法式全框浮动层),不替换任何现有 UI。
核心数据关系
用户消息 → messageId → data-chat-flow-key → 导航 Marker → 消息行 DOM 元素(滚动目标)
定制
源码顶部常量可以直接调整:
| 常量 | 默认值 | 含义 |
|---|---|---|
STRIP_W | 20 | 导航条总宽度(含命中区) |
EDGE_GAP | 4 | 距聊天列右边缘的间隙 |
PAD | 14 | 导航条上下内边距 |
GAP | 12 | marker 默认间距(放不下时自动压缩) |
LINE_FRAC | 0.4 | 「阅读线」在视口中的高度比例 |
样式位于 src/client.js 顶部的 CSS 模板中(类名前缀 mnv-),颜色使用主题 token --dsw-alias-label-primary,自动适配亮/暗主题。
目录结构
dsh-message-navigator/
├── README.md # 本文档
├── LICENSE # MIT
├── package.json # 组合包 + client 双 manifest(dsh.bundle / dsh.client)
├── cordis.patch.yml # 组合包 patch 层:插入 browser-roster 行
├── index.js # Node(host)半部:空 apply,仅让行进入 Loader
├── docs/
│ └── screenshot.png # 演示截图
├── lib/
│ └── client.js # 浏览器半部:__ModuleLoader__ 模块(完整实现)
└── src/
└── client.js # 动态插件形态的等价源码(方式二用)
已知限制
- 依赖 DeepSeek Harness Web GUI 的 DOM 契约(
data-conversation-scroll、data-chat-flow-key/kind);产品大幅改版后可能需要同步更新选择器。 - 持久化形态为「开发 checkout 链接安装」:本地文件即运行文件,改完源码后重启 DSH 即生效。
License
MIT © 2026 TableRogue