READMESource: main@bfc8011d
dsh-x9-talkjump
DSH Web 插件:右侧「对话跳转」竖线条 —— 和 DeepSeek 网页版右侧的跳转条一样,平时完全不打扰:
- 页面右侧垂直居中显示一排横线条:每条用户提问对应一条线,默认最多显示 6 条,提问更多时用鼠标滚轮在线上滑动即可翻看;
- 鼠标悬停线条时,左侧弹出完整提问列表框(所有提问都在一个框里,单行省略显示:序号 + 内容 + 时间),框内最多同时显示 6 条,更多用滚轮在框内滑动;鼠标离开后自动收起,恢复成只有横线的状态;
- 点击线条或框内条目 → 聊天区平滑滚动到对应消息并闪烁高亮;如果目标消息还没被聊天区加载(在「加载更早」之前),插件会自动逐页加载历史再跳转,全程无需手动滚动;
- 滚动聊天区时,正在阅读的那条提问对应的线会高亮(更长、主题色);
- 界面没有任何按钮/面板常驻——不悬停时整个插件就是一列细线。
- 零运行时依赖:浏览器端只使用 DSH 平台内置的 seed 模块(react、react-dom),无需构建步骤。
- 符合 DSH 插件规范:
dsh.bundle.patch补丁层 +dsh.client客户端声明,通过dsh plugin管理生命周期。 - 在加载长对话的时候会有一点卡顿
安装
dsh plugin --profile web add github:X9wd09ncc/dsh-x9-talkjump
安装完成后重启 Web 界面(重新运行 dsh web,或刷新已打开的页面)。
本地开发调试
在插件目录里直接安装本地副本(dsh plugin 会把相对路径锚定到当前目录):
cd dsh-x9-talkjump
dsh plugin --profile web add .
dsh web
改动 client.js / index.js / cordis.patch.yml 后重启 dsh web(或刷新页面)即可生效。
卸载
dsh plugin --profile web remove dsh-x9-talkjump
相关截图
默认状态,只在页面右侧显示横线

鼠标放在横线上显示对话

文件结构
| 文件 | 作用 |
|---|---|
package.json |
dsh.bundle.patch 指向补丁层;dsh.client.platform: "web" 让 client-modules 扫描本包并服务 /plugins/dsh-x9-talkjump/client.js |
cordis.patch.yml |
补丁层:向 composition 插入一行 dsh-x9-talkjump |
index.js |
host 半边:在 webServer 上注册 GET /api/talk-jump/sessions/<id>/questions,合并 sessionPersistence.readFrom(id, 0) 的持久化全量日志 + 活跃会话内存日志(sessionQuery 兜底),过滤出追加式 user/message 事件并返回 [{seq, time, text}] |
client.js |
浏览器半边:window.__ModuleLoader__.load 工厂,导出 { apply, inject } Cordis 插件;挂载右侧竖线条导航 |
工作原理
- 全量列表(双重保证):竖线条的数据来自 host 半边提供的 HTTP 接口,不依赖聊天区懒加载窗口。
- host 接口读取的是完整日志:合并
sessionPersistence.readFrom(id, 0)(持久化全量日志,覆盖最早的历史)与活跃会话的内存日志(覆盖最新未落盘的尾巴),按 seq 去重——即使内存日志是被裁剪的窗口(头部被逐出、只保留最近若干轮),最早的提问也不会丢;接口同时保留sessionQuery作为最后的兜底。 - client 侧兜底:如果 host 接口不可用(例如 dsh 进程还在跑旧版插件),先快速重试两次(1.5s/3s),仍失败才通过
Session.loadOlder()(「加载更早」按钮背后的同一个接口)逐页把整个历史窗口加载出来,线条列表照样完整;接口恢复后自动切回并停止后台加载。打开时拉取一次,之后每 4 秒轮询 + 新提问落地时即时刷新。
- host 接口读取的是完整日志:合并
- 加载性能:所有翻页进度都用会话的同步快照(
getSnapshot().hasMore)判断,不会因 React 渲染期间的过期引用而空转;每页之间让出主线程(120ms)保证页面不冻结,40+ 轮的历史几秒内渐进加载完,期间 UI 始终可交互;点击跳转同样按同步快照推进,到目标后直接滚动,不做多余翻页。 - 线条布局:线条容器
position: fixed,右侧 10px、垂直居中(top: 50%+translateY(-50%)),最多露出 6 条(max-height),超出部分容器自身滚动(隐藏滚动条,滚轮操作);每问一条线,正常 26×4px,悬停/当前条变长变亮(36px、主题色)。 - 悬停展开框:框通过 portal 挂在
document.body(避免被线条容器的 overflow 裁剪),定位在线条左侧、垂直居中;框内一次渲染全部提问行(单行省略),max-height只露出 6 行、超出滚轮滚动;鼠标在线条与框之间移动不会误关(180ms 延迟关闭 + 框内进入取消计时),离开后收起。 - 点击跳转:目标在已加载窗口内 → 直接定位
[data-conversation-scroll]中[data-chat-anchor-key="…"]行滚动 + 闪烁;目标尚未加载 → 循环调用Session.loadOlder()(客户端 sessions 服务 binding 提供的翻页接口,正是「加载更早」按钮背后的同一个能力)直到目标进入窗口,再滚动定位。 - 阅读位置高亮:监听聊天滚动容器(rAF 节流),找到视口顶部第一条
[data-chat-flow-kind="user"]消息,按seq ↔ anchorSeq映射高亮对应线条;线条滚动条会自动把当前线滚入可视区(用户主动滚动线条后的 1.2 秒内不干预)。 - 降级:host 服务(
sessions/sessionPersistence/sessionQuery/webServer)不存在的 profile 下 host 半边自动变成 no-op,不影响启动;接口读取失败时 client 自动退回「逐页加载完整窗口」的兜底路径。 - 样式全部使用主题 token(
--dsw-alias-*),自动适配浅色/深色主题,不影响全局主题。
规范说明
dsh plugin --profile web add github:…本质是 pnpm 转发;安装后插件包因声明了dsh.bundle.patch而进入 profile 的dsh.profile.bundles补丁层列表。- host 半边是普通 Node ESM 插件:通过
ctx.get("webServer")/ctx.get("sessions")/ctx.get("sessionPersistence")/ctx.get("sessionQuery")读取服务(不带硬 inject,避免服务缺失时整机启动失败),路由注册挂在ctx.effect返回的 disposer 上。 - 浏览器端 bundle 必须调用
window.__ModuleLoader__.load({ id, factory })注册工厂,require只能解析平台 seed 词与图内条目;不要 import/require 其它插件的内部实现。 - 所有副作用(样式、插槽注册、轮询定时器、事件监听)都挂在
ctx.effect/ React effect 清理函数上,插件被移除或更新时自动清理。 - 不需要构建:
client.js直接提交到仓库,exports["./client"]指向它即可。
License
MIT
No comments yet. Be the first to write one.