DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
Q

@local/quick-reply

Quick Reply

选中任意一段文字一键引用回复;侧栏会话行也能引用该会话最后一条回答;出处带轮次或行号(都只填草稿)

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:tupi00/dsh-quick-reply#d390f291fa0728ab694e8a92e598dcb3294d6982
README兼容性版本

兼容性与来源证明

Quick Reply 以 @local/quick-reply 发布,当前版本为 1.3.1。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/20

版本

1.3.1stable
2026/10/20
1.3.0stable
2026/10/20
1.1.0stable
2026/10/20

相关插件

正在加载相关插件…

最新版
1.3.1
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/20
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 memory-context 分类下经过校验的插件。

Experimental Session Search@deepseek-ai/dsh-experimental-session-search为 Agents 提供搜索和读取当前工作区早期会话的工具。Hindsight Coding Agents@vectorize-io/hindsight-coding-agents面向编程代理的仅反思式 Hindsight 长期记忆(可插拔支持多种运行框架:opencode、……),自动在后台导入(无需设置 CLI)。Contextdsh-context用于上下文洞察和管理的 DeepSeek Harness 插件,提供上下文仪表板和上下文命令,帮助了解上下文的构成及其演变过程。Mnemondsh-mnemon面向 DeepSeek Harness 的可组合、基于视图的上下文。开箱即用的可插拔来源与策略、分层记忆和自我演进技能。

README

dsh-quick-reply · 引用回复

给 DeepSeek Harness(下称 DSH)Web 界面用的一个小插件,两个入口,都只做「引用」:

  1. 选中屏幕上任何一段文字(助手的回答、左侧会话列表里的会话标题、右侧面板里的内容),鼠标旁边会冒出一张「引用回复」小卡片。点一下,就把这段文字变成 Markdown 引用块填进草稿,不自动发送。
  2. 在左侧会话列表里把鼠标移到某个会话行上,行末会出现一个引号按钮。点一下,切到那个会话,并把它最后一条已经说完的回答引用进草稿。

没有悬浮球、没有快捷键冲突。

当前版本 1.3.1,更新记录见 CHANGELOG.md。


它解决什么问题

长对话里想追问某一句时,常见做法是把那句话复制下来、粘进输入框、手动加 >、再补出处。四步,还容易粘错。

这个插件把它压成一步:选中 → 点「引用回复」→ 草稿里出现

> 你选中的那两行文字…(略)  (引用自第7轮回答)

光标已经落在引用块下面那一行,直接写问题就行。


行为细节

  • 选中范围:助手消息里只认「起点和终点都在同一条助手消息正文里」的选区——选中你自己的提问、工具调用卡片、思考过程、系统提示,按钮都不会出现,避免引错东西。聊天区以外(左侧会话列表、右侧面板)选中的文字也可以引用,那里没有「第几轮」的概念,所以只写 > 原文,不带出处标注。输入框里选中自己打的草稿不算引用。
  • 侧栏文字本来选不中:宿主给会话行设了 user-select:none,插件把它放开成 user-select:text,才能拖选会话标题。单击行为不变(浏览器只有拖过一小段距离才算选中),行末的悬停按钮也不受影响。
  • 卡片贴着鼠标出现:位置取鼠标松开的那一点(选区焦点,正拖反拖都对),卡片右缘与字尾齐平、缩在文字下方,视线不用跳。下边放不下就翻到字的上面;贴到窗口边缘时会夹进窗口,不会被切掉。滚动聊天或缩放窗口时重新定位,跟着文字走。
  • 引用会自动截断:默认只留前 2 行 / 最多 120 字,超出部分用 …(略) 标记。原因是一整段回答塞进草稿会把输入框撑爆,也不方便接着写。原文仍然高亮着,想看全文回消息里看。
  • 带上出处:引用块最后一行的末尾跟一个 (引用自第N轮回答),同一行,不另起一段。模型看到的只是纯文本、没有消息 ID,同一句话在历史里出现两次时它会分不清——轮次号给它一个可核对的坐标。这个 N 直接读宿主写在消息外层 div 上的 data-chat-turn,和界面右侧「轮次导航」显示的第几轮是同一个数字。在代码 / diff 面板里选中时没有「第几轮」,改成写 (引用自第79行)——行号是拿选区左边那一列数出来的,数不出来就干脆不写,不编假的。
  • 光标落在引用块下一行:填完草稿后光标自动停在引用块下面的空行,直接写问题就行,不用再点一下。
  • 原文高亮:用 CSS Custom Highlight API 标记选中的原文。不改宿主 DOM,所以不会和 React 的重渲染打架;浏览器不支持时静默跳过,功能不受影响,只是少了视觉提示。
  • 引用过高亮一直留着:引用完那一段会「钉住」,之后你选别处、点别处、继续聊天都还亮着,方便回看自己引过哪些段。一个 Highlight 里装了多个 Range,所以「正在选的」和「已经引过的」可以同时亮。宿主重渲染后断开的 Range 会自动剔除;引用超过 50 段时丢掉最早的。页面刷新就清空。
  • 把引用删掉,高亮跟着消失:判断依据是「这段字还在不在输入框里」,不是「你有没有按删除键」——整段删、撤销、发送后清空,都一样处理。逐字比较会把改标点、加空格误判成删除,所以只比字(汉字、字母、数字),标点空白忽略。
  • 只填草稿,绝不发送:发不发、发什么,由你按回车决定。
  • 保留已有草稿:如果输入框里已经写了东西,引用的内容会接在后面,前面空一行。

侧栏引用(会话列表里那个引号按钮)

  • 引什么:那个会话最后一条已经说完的助手回答(跳过还在输出中的那一步,也跳过只有工具调用的步骤)。会话还没被回答过时,按钮点了不会有反应。
  • 先切过去:点按钮会先打开那个会话,等它的历史加载完、最后一条回答出现,再把引用填进它的草稿。所以你会看到会话切换 + 草稿里出现引用块。
  • 出处照旧:同样带 (引用自第N轮回答),光标同样落在引用块下一行。
  • 为什么是「会话内引用」而不是跨会话引用:跨会话把别的会话的回答引到当前会话,需要插件去持有并读取另一个会话的历史,代价和出错面都大得多;而「点开这个会话、引用它自己的最后一条」用的还是同一条「当前会话」路径,简单可靠。这是刻意的取舍,不是没做完。

安装

前提

  • DSH 桌面端(Electron)或 dsh web,且 Web 界面能正常打开。
  • 插件通过 DSH 的插件管理器以本地包方式安装,不需要联网。

方式一:插件管理器(推荐)

在 DSH 里让 agent 执行:

plugin_manager install_bundle  target = <本仓库的绝对路径>

装完后 重启 DSH 应用(宿主进程的模块缓存按 URL 记,重载不会重新求值),再刷新网页。

方式二:手动挂到 profile

把本目录放到任意位置,然后在 profile 的 package.json 里加一条依赖:

{
  "dependencies": {
    "@local/quick-reply": "link:<本仓库的绝对路径>"
  }
}

并把 @local/quick-reply 追加到 bundles 列表末尾,重启 DSH。

验证装好了没有

刷新页面后:

  1. 选中任意一条助手回答里的文字。鼠标旁边出现「已选中第 N 轮的文字 · 引用回复」=选区那条装好了。
  2. 拖选左侧会话列表里的会话标题。卡片上写「已选中文字」(没有轮次号)=侧栏选区也装好了。
  3. 把鼠标移到左侧会话列表的任意一行上,行末多出一个引号按钮 = 侧栏那条装好了。

没出现的话按顺序查:

  1. 打开控制台,看有没有 @local/quick-reply 相关的加载错误;
  2. 在 DSH 里查插件列表,确认它是启用状态;
  3. 确认选中的确实是助手消息正文(不是工具输出、不是思考过程、不是你自己的提问);
  4. 侧栏按钮不出现时,确认那个会话行是不是被归档/空白会话(宿主对这类行不渲染动作按钮)。

卸载

插件管理器里禁用/移除,或从 profile 的 package.json 里删掉依赖与 bundles 条目,然后重启 DSH。


技术说明

挂在哪

用三个宿主官方槽位:

  • shell.overlay —— 窗口最上层、不随聊天滚动的一块浮层。卡片本体挂这里,位置由选区坐标算出来(position: fixed)。
  • conversation.input.dock —— 输入框卡片上方那一整行。这里只挂一个「什么都不渲染」的桥组件,用来取输入框的 inputActions、当前草稿、以及当前会话的聊天快照。
  • sidebar.workspaces.session.row.action —— 会话列表每行末尾的悬停按钮位(宿主自己的「归档」「置顶」也在这一排)。这里挂侧栏那个引号按钮。

为什么要分三处:shell.overlay 和侧栏行按钮都是 root 作用域,拿不到输入框的 inputActions,也读不到聊天快照;只有 conversation.input.dock 两样都拿得到。所以那两处只负责「告诉桥要干什么」,真正的取文字和填草稿都在桥里完成。

侧栏按钮为什么要切会话:桥是跟着「当前会话」挂载的,它只能读当前会话的聊天快照。所以点侧栏按钮先切过去,等新会话的历史加载完,桥自然就能读到那条回答了。好处是不需要跨会话 retain 别人的历史,坏处是用户会看到一次会话切换——这是刻意的取舍。

文件结构

QuickReply/
├── package.json        # 包元数据 + dsh.client 声明(平台、注入依赖)
├── cordis.patch.yml    # Cordis 加载补丁:insert 一个 id=quick-reply 的插件
├── index.js            # Host 半边(空实现;本插件纯客户端,留入口给以后扩展)
├── client.js           # 浏览器半边:全部逻辑都在这里
├── locale/zh.json      # 插件列表里的标题与描述
├── locale/en.json
├── icon.svg
└── test/helpers.test.mjs  # 纯函数单测(不启浏览器)

关键实现点

  • 宿主插槽 props:dock 条目能拿到 inputActions(setDraft / submit 等)与当前草稿,所以填草稿走的是宿主自己的草稿接口,不是去模拟键盘。
  • 为什么要缓存选区:点击按钮的 mousedown 会把页面选区清空,所以插件在 selectionchange 里先把「选中了哪段、属于第几轮、在屏幕哪个位置」记下来(用 requestAnimationFrame 合帧,拖选时不会疯狂重渲染),点按钮时用的是缓存。
  • 怎么判断「这段文字能不能引」:看选区的起点和终点落在哪个容器里。两端都在同一条 [data-chat-flow-kind="assistant-step"] 里 → 能引,带轮次号;两端都不在聊天流里(侧栏、右侧面板)→ 也能引,但没轮次号;一头在里一头在外 → 跨区选择,不认。另外两端都在 [data-composer-card] 或 contenteditable 里(= 用户在选自己打的草稿)→ 不认。
  • 位置在渲染后用 useLayoutEffect 算:卡片宽度要先量出来才能决定水平对齐(右缘贴字尾);layoutEffect 在浏览器绘制前跑完,用户看不到跳一下。位置没算好前先放 left:-9999px,避免在左上角闪一下。
  • 锚点取选区焦点而不是 range 末尾:选区分方向,从下往上拖选时 range 的终点在文档里是上面那行。取 selection.focusNode / focusOffset 处收一个零宽 Range,才是鼠标松开的那一点。
  • 按钮上 onMouseDown: preventDefault():同样是为了保住选区,避免卡片在按下的瞬间自己消失。
  • 填完把光标送到末尾:focus() 的默认落点不保证在末尾,所以用 Selection API 把 range 收拢到 contenteditable 的末尾。
  • 样式自己插 <style> 标签:装进 profile 的普通插件拿不到动态插件沙箱里的 styles 服务,宿主自带的客户端插件也是自己插 style 标签的。颜色一律用 --dsw-alias-* 设计令牌,跟随主题。
  • 侧栏按钮和桥之间靠一个小 store 通知:两者不在同一棵 React 树里,侧栏按钮只能把「要引用哪个会话」写进模块级的 pendingQuoteStore;桥订阅它,被通知后重渲染、等目标会话的最后一条回答出现再填草稿。用普通变量的话桥的依赖项没变、effect 不会重跑,点了就像没反应。
  • 挑「最后一条回答」时跳过 status === 'running' 的步骤:那一步还在往外吐字,引一半会被截断,模型看到的是半句话。
  • useChat 缺失时用空壳 hook 顶上:React 要求每次渲染 hook 数量一致,props.useChat ? props.useChat(x) : null 会让两边 hook 数不同、整棵组件炸掉,所以空壳也要调一次 useSyncExternalStore。
  • 不用 require 引 DSH 客户端包:插件只依赖宿主注入的 ctx、React,符合宿主对插件的要求。

开发

# 纯函数单测(不需要浏览器)
node test/helpers.test.mjs

# 语法检查
node --check client.js
node --check index.js

test/helpers.test.mjs 会用标记 // >>>PURE-HELPERS 从 client.js 里把纯函数抠出来跑,所以那几个函数里不能出现 DOM / React 调用。


已知限制

限制说明
只引用助手正文选中你自己的提问、工具输出、思考过程不会出现按钮。这是有意的。
侧栏只引「最后一条已结束的回答」不提供「选第几条」的入口;想引中间某条,打开那个会话手动选中即可。
侧栏引用会切会话点按钮会先打开那个会话。这是为了复用「当前会话」路径,避免跨会话读历史。
引用永远截断目前没有「引用全文」入口。需要整段时手动选中复制。
依赖宿主 DOM 语义属性选区判定依赖 [data-chat-flow-kind="assistant-step"] 和 [data-chat-turn]。宿主改版时插件最多失效(按钮不出现),不会弄坏聊天。
位置由 JS 算卡片用 position: fixed 跟随选区坐标,不是宿主分配的布局空间。滚动/缩放时会重算,但如果宿主在浮层里加了 transform 容器,定位可能偏移。
没有配置项截断行数/字数写死在 client.js 顶部(QUOTE_MAX_LINES / QUOTE_MAX_CHARS),改完需重新加载插件。
仅 Web 界面宿主声明 platform: "web"。

许可

MIT