dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
在 DSH Web 对话区提供一组圆形按钮,逐条跳到上一条或下一条用户消息,或直接到顶部与底部,并自动翻页加载更早历史。
English | 中文
A rail of four circular buttons for the DSH Web conversation: to top, previous user message, next user message, to bottom. It floats above the composer at the right edge of the conversation, and replaces the product's single built-in "to bottom" button.
Sibling plugins mostly draw a minimap, a table of contents, or inline anchors. This one does none of that. It steps through the conversation one user message at a time — a click lands exactly on the previous or next thing you asked — and pages older history in automatically when the target sits outside the loaded window.
Navigation targets are only user and steering entries. Tool calls, context injections, compaction markers and other process nodes are skipped, so "previous" means "my previous question", not "the previous DOM block".
# From npm
dsh plugin --profile web add dsh-conversation-jump
# From GitHub, when you want the source
dsh plugin --profile web add github:uigdwunm/dsh-conversation-jump
# From the prebuilt release tarball (nothing to build locally)
dsh plugin --profile web add https://github.com/uigdwunm/dsh-conversation-jump/releases/download/v0.1.6/dsh-conversation-jump-0.1.6.tgz
Restart dsh web afterwards.
dsh plugin is a thin forwarder to pnpm in the profile directory, so a plain registry name, a github: spec and a remote tarball URL all work. This package declares no prepare script, so no allowBuilds entry is needed for the GitHub or tarball route.
npm install
npm run build
# install into the web profile; restart dsh web afterwards
dsh plugin --profile web add file:/absolute/path/dsh-conversation-jump
A rebuild alone does not reach the running page. The profile keeps its own copy under ~/.dsh/profiles/<profile>/node_modules/, and npm run build replaces lib/client.js by rename — which breaks the hard link the install created. Re-run the dsh plugin … add file:… command after each build (or copy the built file into that package) and then reload the page.
| Capability | Behaviour |
|---|---|
| To top | Scrolls to the current top, then keeps paging older history in until the real top is reached |
| Previous | Jumps to the previous user message; if it lies beyond the loaded window, it pages older history in — as many pages as it takes — until that message is loaded |
| Next | Jumps to the next user message |
| To bottom | Goes straight to the newest position |
| Message anchor | The target message settles about 1/12 down from the top of the viewport |
| When it appears | Hidden by default; appears when the average upward scroll speed exceeds 200 px/s, hides again as soon as you scroll down yourself |
| Auto-hide | Disappears 3 s after appearing; clicking any button or hovering the rail restarts that countdown |
| Position | Aligned to the right edge of the conversation and 16 px above the composer, positioned synchronously before paint so it does not flash |
| State | Page-memory only — nothing persisted |
Button labels are Chinese (回到顶部 / 上一个 / 下一个 / 回到底部); each button carries the same text as both its title and aria-label, and the rail is a role="toolbar" labelled 会话导航.
[data-conversation-scroll], user messages are [data-chat-anchor-key] filtered by data-chat-flow-kind, and the composer seat is [data-composer-seat]. The built-in "to bottom" button is hidden by matching the stable _toBottomSlot class suffix rather than a CSS-module hash, so a DSH upgrade that rehashes class names does not break it.[data-chat-flow] — the first button that is not inside a message row and precedes the first row — clicks it, then polls the anchor count until it grows. Attempts are bounded, so a host that never grows the list cannot spin forever.加载中…), and this plugin holds the same lane while it pages. A click that arrives in that window waits for the lane and then runs instead of being dropped, and a "previous" step supersedes an in-flight "to top" jump rather than being swallowed by it.slots seat is injected. cordis-plugin-timer is host-only and absent in the web client, so the plugin declares inject: ['slots'] and uses native setTimeout / setInterval, tracking every handle so disposal cancels them.<style data-dsh-conversation-nav> node owned by the fiber, but every 100 ms sample checks the view and recreates the node when it is missing. A fiber re-apply that removes the styles (for example the dev-mode HMR driver rebuilding this plugin) therefore cannot leave the rail unstyled in the page's top-left corner with the product's own "to bottom" button reappearing while the rail is still mounted — it recovers on the next sample instead of needing a page refresh.index.mjs) is an empty apply — no host services, events, tools or storage.localStorage, IndexedDB, cookies, files or backend database.npm run build # esbuild bundles src/client.ts into lib/client.js
npm run typecheck # tsc --noEmit
npm login # requires an npm account
npm publish # prepublishOnly runs the build first
The
repositoryfield must point back at this GitHub repo.awesome-dsh-plugin's npm probe only claims a package when the package exists and itsrepositorypoints at the same repo — otherwise there is no download-count sorting and no npm install entry.
dsh-plugin topic — already set; plugin markets sync from it.data/plugins/uigdwunm__dsh-conversation-jump.yml (category ui) to awesome-dsh-plugin/awesome-dsh-plugin. That repo's READMEs are generated from the data files — do not edit them by hand.The npm name dsh-conversation-nav is taken by another author (not this repo), so this package is published as dsh-conversation-jump. Repo name and package name match.
| File | Purpose |
|---|---|
package.json | DSH bundle/client declaration, exports, metadata and build scripts |
cordis.patch.yml | Mounts the plugin into the web profile composition |
index.mjs | Host half (browser-only plugin, empty apply) |
src/client.ts | Browser-side navigation, paging, positioning and visibility policy |
build.mjs | esbuild browser build and ModuleLoader wrapper |
lib/client.js | Build output (shipped with the package) |
MIT — see LICENSE.
DSH Web 对话区的一组圆形导航按钮:回到顶部、上一条用户消息、下一条用户消息、回到底部。它悬浮在输入框上方、对话内容右缘,并替换产品自带的单个“回到底部”按钮。
同类插件大多在做缩略图(minimap)、目录(TOC)或行内锚点。本插件都不做,而是按「用户消息」这个语义单位逐条前后跳转——一次点击精确落到上一条或下一条你提过的问题,并在目标超出已加载窗口时自动翻页加载更早历史。
导航目标只包含 user 与 steering 两类条目,会跳过工具调用、上下文注入、压缩标记和其他过程节点。所以“上一条”指的是“我上一个问题”,而不是“上一个 DOM 块”。
# 从 npm 安装
dsh plugin --profile web add dsh-conversation-jump
# 从 GitHub 安装(需要源码时)
dsh plugin --profile web add github:uigdwunm/dsh-conversation-jump
# 从预构建 Release 包安装(无需本地构建)
dsh plugin --profile web add https://github.com/uigdwunm/dsh-conversation-jump/releases/download/v0.1.6/dsh-conversation-jump-0.1.6.tgz
安装后重启 dsh web 生效。
dsh plugin 只是把参数转发给 profile 目录里的 pnpm,因此「registry 包名」「github: 规格」「远程 tarball URL」三种写法都可用。本包没有声明 prepare 脚本,所以走 GitHub 或 tarball 路线都不需要额外配置 allowBuilds。
npm install
npm run build
# 安装到 web profile,重启 dsh web 后生效
dsh plugin --profile web add file:/绝对路径/dsh-conversation-jump
只重新构建不会让运行中的页面生效。 profile 在 ~/.dsh/profiles/<profile>/node_modules/ 下保存自己的一份副本,而 npm run build 是用「改名替换」的方式写 lib/client.js,会切断安装时建立的硬链接。因此每次构建后都要重新执行一次上面的 dsh plugin … add file:…(或把构建产物复制进 profile 里的那个包),再刷新页面。
| 能力 | 行为 |
|---|---|
| 回到顶部 | 先滚到当前顶部,再持续翻页加载更早历史,直到真正的顶部 |
| 上一个 | 跳到上一条用户消息;若它在已加载窗口之外,会持续翻页(需要几页就翻几页)直到该消息被加载出来 |
| 下一个 | 跳到下一条用户消息 |
| 回到底部 | 直接到最新位置 |
| 消息锚点 | 目标消息停在视口上方约 1/12 处 |
| 显示策略 | 默认隐藏;往上平均速度超过 200 px/s 时显示,读者自己往下滚动时立即隐藏 |
| 自动隐藏 | 出现后 3 秒无操作自动消失;点击任一按钮或把指针停在导航条上会重新计时 |
| 定位 | 对齐对话内容右缘、输入框上方 16 px;绘制前同步定位以避免闪动 |
| 状态 | 仅页面内存状态,不做持久化 |
[data-conversation-scroll],用户消息是 [data-chat-anchor-key] 并按 data-chat-flow-kind 过滤,输入区是 [data-composer-seat]。产品自带的“回到底部”按钮通过匹配稳定的 _toBottomSlot 类名后缀隐藏,而不是写死 CSS-module 哈希,因此 DSH 升级重新生成类名不会失效。[data-chat-flow] 中定位“加载更早”按钮(第一个不在消息行内、且位于首行之前的按钮)并点击它,然后轮询锚点数量直到增长;尝试次数有上限,宿主始终不增长列表时也不会空转。slots 一个席位。 cordis-plugin-timer 是纯 Host 服务,在 Web 端不存在,因此插件声明 inject: ['slots'] 并使用原生 setTimeout / setInterval,同时记录每个句柄以便卸载时取消。<style data-dsh-conversation-nav> 节点上,但每 100ms 采样都会检查它是否还在,缺失就重新创建。因此当 fiber 被重新 apply 而移除样式时(例如 dev 模式下 HMR 重建本插件),不会出现“导航条仍挂着却变成页面左上角的无样式按钮、产品自带『回到底部』同时回来”的状态——下一个采样周期就恢复,不需要刷新页面。index.mjs)是空的 apply——不需要 Host 服务、事件、工具或存储。localStorage、IndexedDB、Cookie、文件或后端数据库。npm run build # 用 esbuild 把 src/client.ts 打包到 lib/client.js
npm run typecheck # tsc --noEmit
npm login # 需要 npm 账号
npm publish # prepublishOnly 会先执行构建
repository字段必须指回本 GitHub 仓库。awesome-dsh-plugin 的 npm 探测只在「npm 包存在 且 其repository指向同一仓库」时才认领,否则拿不到下载量排序与 npm 安装入口。
dsh-plugin topic:已添加,各类插件市场会据此同步收录。data/plugins/uigdwunm__dsh-conversation-jump.yml 一个文件(分类 ui)。该仓库的 README 由数据文件生成,不要手工编辑。npm 上 dsh-conversation-nav 这一名称已被其他作者占用(非本仓库),因此本包发布名为 dsh-conversation-jump。仓库名与包名一致。
| 文件 | 作用 |
|---|---|
package.json | DSH bundle/client 声明、exports、元数据与构建脚本 |
cordis.patch.yml | 把插件挂进 web profile 组合 |
index.mjs | Host 半边(浏览器 UI 插件,空 apply) |
src/client.ts | 浏览器端导航、分页、定位与显示策略 |
build.mjs | esbuild 浏览器构建与 ModuleLoader 包装 |
lib/client.js | 构建产物(发布时包含) |
MIT,见 LICENSE。