选中聊天文字后悬停批注或引用,随消息发送
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/12 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add jabingu/dsh-selection-group该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · ui
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 23 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
发起外部网络请求
查看扫描证据(共 2 处,展示前 2 条)
- 发起网络请求client.js:4319
const response = await awaitSidechatOperation(window.fetch(hostRoute(SIDECHAT_ROUTE), { - 发起网络请求src/toolbar.js:866
const response = await awaitSidechatOperation(window.fetch(hostRoute(SIDECHAT_ROUTE), {
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 选中文字悬停操作
- 批注与引用合并
- 随消息发送
划词工具栏(dsh-selection-group)—— 一个悬停工具栏,处理 DeepSeek Harness 里选中的文本:批注 + 引用合在一个框里,不依赖任何上游插件。
README
由 DeepSeek 最新模型翻译生成dsh-selection-group
Selection Toolbar —— 插件面板里显示的名字(包名、插件 id、仓库名都是 dsh-selection-group;标识名用 kebab-case,面板名给人读,二者分工不同)。
English summary — A DSH client plugin that gives text selection in the chat one hover toolbar with two actions (annotate + quote). It is a merged build: both upstream plugins are vendored byte-for-byte and patched at build time, so it depends on neither of them being installed. client.js is generated from vendor/ + src/ and verified by the test suite (npm test).
English README → README.en.md
展开完整文档(README 剩余 1 节)
dsh-selection-group
Selection Toolbar —— 插件面板里显示的名字(包名、插件 id、仓库名都是 dsh-selection-group;标识名用 kebab-case,面板名给人读,二者分工不同)。
English summary — A DSH client plugin that gives text selection in the chat one hover toolbar with two actions (annotate + quote). It is a merged build: both upstream plugins are vendored byte-for-byte and patched at build time, so it depends on neither of them being installed. client.js is generated from vendor/ + src/ and verified by the test suite (npm test).
English README → README.en.md
MIT licensed. The vendored plugins are MIT too — see THIRD_PARTY_NOTICES.md for their licences and every deliberate deviation from upstream, with reasons.
一个悬停框,两个动作。 选中文字后出现的同一个框里有两段:
┌──────────────────────────┐
│ + 批注 │ ❐ 引用 │ ← 定位在选区上方 └──────────────────────────┘
- + 批注:对选中的文字写批注,随消息发送,模型按编号逐条回应(上游 @changfenhuang/dsh-annotation)。
- ❐ 引用:把选中文字以 DSH 原生引用 chip 追加到输入框(上游 dsh-quote-followup)。
它不依赖那两个插件:两者的浏览器端代码被逐字内联进本包;两者都可以保持停用或直接卸载。
架构(一个框 + 注入的动作,而不是搬运两个框)
| | 做法 |
| 唯一的悬停框 | annotation 的工具条。构建期补丁让它为每个注入的动作渲染一个按钮(window.__DSH_SELECTION_GROUP_ACTIONS__)。 |
| 第二个动作 | 一个 ❐ 引用 按钮,它的 run() 只是点击 dsh-quote-followup 自己的按钮。那个插件完全保持上游实现(选区跟踪、原生 chip 插入、失败提示),只是它的浮动按钮在共享框出现时被隐藏。 |
| 隐藏是同回合的 | 选中文字的那一刻(selectionchange 内,同步)就给 打上 data-dsh-selection-group-bar,独立按钮一帧都不会露——否则它会先在自己的位置闪一下(独立按钮是即时的,共享框要等批注约 120ms 的 settle)。若共享框在 300ms 宽限内没出现(例如跨消息选区被上游拒绝),标记释放,独立按钮回来,引用照旧可用。 |
| 不搬 DOM | 没有任何节点的重新父级化或移动,没有容器、没有定位接管、没有帧调度。(test/contract.test.mjs 断言 glue 里不存在 insertBefore / appendChild(quote…)。) |
版本沿革
| 版本 | 做法 | 结果 |
| 0.2.0 | DOM 适配层:把两个插件各自的悬浮按钮搬进一个容器 | 依赖两个插件都启用 |
| 1.0.0 | 内联合并 + 归位层(仍是"搬 DOM") | 自包含,但仍受 DOM 搬运与调度影响 |
| 1.1.0 | 一个悬停框 + 补丁注入第二个动作 | 无搬运、无容器、无调度器,改动面最小 |
| 1.2.x | 立即出框、引用点完收框、ctx.effect 与热插拔修复 | 与选区同时出现,不再残留框 |
| 1.3.x(当前) | 拖拽感知绘制、事件驱动标记、可观测的自我修复 | 拖选不闪,空闲 ~18 次 DOM 查询/秒 |
安装 / 升级
包名与安装槽没变(desktop profile 里以 link: 安装且已在 dsh.profile.bundles 中启用),所以:
1. 完全退出 DeepSeek Harness(Cmd+Q)再打开。
2. dsh-quote-followup、@changfenhuang/dsh-annotation 继续保持停用或直接卸载。⚠️ 不要重新启用:内联副本与上游使用相同的元素 id(dsh-quote-followup-btn),同时存在会互相抢 DOM。
安装后在插件面板里显示为 Selection Toolbar。
从零安装(新机器):
设置 → 插件 → 安装,粘贴本仓库的绝对路径(示例): ~/path/to/dsh-selection-group
或:
"/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" \
plugin --profile desktop add \
"link:$PWD" # 在仓库根目录执行
结构
| 路径 | 说明 |
| client.js | 生成物,勿手改。由 scripts/build.mjs 从下面几份输入生成 |
| vendor/dsh-annotation.client.js | @changfenhuang/dsh-annotation v1.4.11 浏览器半区,逐字拷贝(MIT) |
| vendor/dsh-quote-followup.client.js | dsh-quote-followup v0.2.10 浏览器半区,逐字拷贝(MIT) |
| vendor/manifest.json | 两个 vendor 文件的版本、许可与 sha256(构建时强校验) |
| patches/.json | 对上游的有意偏离(见下),构建时套用;vendor/ 仍与上游逐字节一致 |
| src/toolbar.js | 本项目唯一自研部分:发布动作 hook、条件隐藏独立按钮、诊断 |
| scripts/build.mjs | 合并构建:套补丁 → 剥离 __ModuleLoader__ 包装 → 内联工厂体 → 拼接 glue |
| lib/index.js / cordis.patch.yml | Node 半区空实现 / bundle patch |
| icon.svg + locale/{en,zh}.json | 插件面板显示用的图标与本地化名称/简介(meta.title / meta.description;en.json 是读取器要求的锚点,exports 里必须导出 ./locale/.json 才解析得到) |
| THIRD_PARTY_NOTICES.md | 第三方许可与偏离清单 |
对上游的有意偏离
patches/ 里每条都写了 why。test/vendor.test.mjs 断言:锚点在上游文件里恰好命中一次、替换文本尚未存在于上游、确实进入产物,且产物里不再残留上游原文。
| 补丁 | 上游 | 现在 | 为什么 |
| accept-any-conversation-row(annotation) | 只对助手消息里的选区提供工具条 | 会话区内的任意消息行(用户 / steering / 工具步)都可;跨多条消息仍拒绝 | 让两个动作对同一个选区都可用 |
| settle-120ms(annotation) | 选中稳定后等 250ms 才画工具条 | 120ms(仅用于"再校验 + 用最终摘录重绘一次") | 缩短错位 |
| immediate-toolbar(annotation) | 工具条在 settle 之后才画出来 | 在 selectionchange 当回合就画;拖选过程中只移动不重建;settle 只在最后校验并用最终摘录重绘一次 | 让「批注 + 引用」随选区立即出现,而不是延迟 120ms |
| resync-excerpt-on-click(annotation) | enterEditing 用 settle 时存下的摘录 | 点击时从实时选区重取摘录 | 框出得比 settle 早,否则拖选刚结束就点「批注」会批到旧文本 |
| expose-close-hook(annotation) | 收框函数 closeToolbar 是内部闭包 | 把它发布成 window.__DSH_SELECTION_GROUP_CLOSE__ | 让「引用」点完也收框(点「批注」会切到编辑卡片所以框本就消失;而选区被清空时它不会自动收框) |
| bar-extra-actions(annotation) | 工具条只有一个「批注」按钮 | 额外渲染 glue 注入的动作按钮(带 data-dsh-selection-group-action) | 这就是"合并"本身 |
| mousedown-tolerates-merged-trigger(quote) | 指针按在非本按钮上就丢弃待引用摘录 | 容忍标记为 data-dsh-selection-group-action 的按钮 | 否则按下注入的「引用」按钮会在 click 之前清掉摘录 |
行为与边界
- 引用走的是上游路径:点击注入按钮 → 触发 quote 自己的按钮 click → 它经官方 session facade 做原生 chip 插入(conversation.input.for(scope).insertReference),失败时仍弹它自己的提示。
- 改动面最小:除"隐藏独立按钮"这一条 CSS 和上述 9 处补丁外,两个插件的代码与行为不变。
- 不依赖 requestAnimationFrame:批注用 rAF 做标记重排/卡片定位/发送后聚焦;本包启动时探测 rAF 是否真的触发,若证实不触发(某些 Electron 视图会如此)就给整页垫一个定时器实现,记入诊断 rafShimmed。
- 已知行为:点「批注」→ 框换成编辑卡片;点「引用」→ 引用插入输入框后框同样收起(两者行为一致)。选区消失或点框外时整框收起,独立按钮随之恢复。
- 失败不静默:若引用没能插入(没有输入框、输入框被锁、摘录确实已经失效),上游插件会弹出原因提示,且框保持打开让你重新选择重试——不会出现"点了没反应、框还消失了"。
- 框在屏上时摘录不会莫名丢失:上游在"选区失效"(文本变空、矩形测不到 —— 流式输出时聊天区重渲染就会这样)或"任何滚动"时会丢弃待引用摘录,而批注的框此时不会关,于是你按「引用」就会撞上"摘录已保留,请选中原文重试"。本包打了补丁:只要合并工具条还在接管(标记在),上述两种情形都不丢弃摘录;Escape、点框外、独立模式下的滚动仍按上游语义处理。
- 编辑卡片期间也隐藏独立按钮:批注的框换成编辑卡片后,独立「引用」按钮不再冒出来压住卡片。
- 开销:工具栏是事件驱动的——selectionchange 当回合打标记,MutationObserver(body / head / annotation host,childList)跟随框与编辑卡片的出现与消失,宽限期用一次性 timeout,1 秒的定时器只做兜底(自愈 + 采样)。实测完全空闲时:诊断全量期间 ~18 次 DOM 查询/秒(原来是 ~110),过期/关闭后 ~8 次/秒且零写盘。若还想更省,把 TICK_MS/SAMPLE_MS 调大即可。
- 更新日志:见 CHANGELOG.md。
- 显示时机:按住鼠标期间不出框(拖拽每一帧都会触发 selectionchange,且跨消息边界那一帧上游会收框,于是会闪),松开鼠标的那一回合立刻出框——pointerup 会补发一次 selectionchange,所以既没有闪烁,也不用等上游的 120ms settle。按住期间独立「引用」按钮同样保持隐藏:共享框既然要等松手,宽限期就不能成为它的理由,否则你按住停顿超过 300ms 就会看到那颗孤立的引用按钮。非拖拽路径(双击选词、键盘选择、程序化选择)依旧当回合出框。
- 不含任何网络请求、文件写入或主机权限。
排障(自证诊断,不用开控制台)
诊断默认只跑 3 分钟。 它会包装 console.warn/error、监听 window 错误并每秒采样,对排查刚启动时的问题很值;长期挂在别人的页面上则不合适。
| 想要 | 做法(在插件加载前设置) |
| 一直开着 | window.__DSH_SELECTION_GROUP_DIAGNOSTICS__ = true |
| 完全关掉(不挂钩子、不写盘、不采样) | window.__DSH_SELECTION_GROUP_DIAGNOSTICS__ = false |
| 改过期时长(毫秒) | window.__DSH_SELECTION_GROUP_DIAGNOSTICS_TTL_MS__ = 600000 |
过期(或关闭)时:console 与错误监听被还原、采样与写盘停止,并写入最后一份快照(含 diagnosticsMode: "expired"、diagnosticsExpiredAt);window.__DSH_SELECTION_GROUP__ 里那些事件驱动的轻量字段(applied / barUp / cardUp / quoteButtonHidden / diagnosticsMode)继续可用。工具栏功能不受影响——标记、观察者、动作 hook、拖拽跟踪,以及 rAF 兜底垫片(那是正确性修复,不是诊断)都不随开关关闭。
实测空闲开销:全量运行时 ~18 次 DOM 查询/秒(有写盘);过期或关闭后 ~8 次/秒、零写盘(剩下的是标记与自愈的功能下限,1 秒一次)。
诊断同时挂在 window.__DSH_SELECTION_GROUP__ 并写进 localStorage['dsh-selection-group.diagnostics'](Electron 把它落在磁盘上,可直接读):
applied / mountedAt / tick / barUp / cardUp / extraButtons / actionsInstalled / quoteButtonHidden / stylePresent / hookPresent / selection{state,rowKind,rowTurn,inTranscript} / consoleTail / lastWindowError / lastError / visibility / docHidden / rafFired / rafShimmed / topLevel / href / frames / transcripts / flowRows / turnRows / context / vendoredMount / disposedAt
| 症状 | 先看 |
| 一个框都不出现 | vendoredMount.annotation 是否 mounted (with disposer);consoleTail / lastWindowError |
| 框出现但只有一个按钮 | extraButtons 是否为 1;actionsInstalled;consoleTail 里是否有 [annotation] … |
| 两个框同时出现 | barUp / cardUp / quoteButtonHidden(选中同回合打标记,MutationObserver 跟随框的出现/消失);stylePresent / hookPresent |
| 批注不出 | selection.rowKind / inTranscript;transcripts 是否 > 0(确认插件与 UI 在同一文档) |
开发者工具在这个应用里是 F12(Mac 上若被系统占用用 Fn+F12)。
开发与测试
npm install # 只有一个开发依赖:jsdom
npm run build # 重新生成 client.js
npm test # 51 项
| 测试文件 | 覆盖 |
| test/toolbar.test.mjs(30) | 动作 hook 与条件隐藏;一个框里两个按钮;点击「引用」真的走通 quote 的原生插入(断言官方 facade 收到一次 insertReference 且带选中文字);有框时隐藏 / 无框时恢复;用户消息里也成立;rAF 垫片;拖拽门控;热插拔;诊断的三种模式(默认过期 / 强制开启 / 完全关闭)与镜像快照 |
| test/integration.test.mjs(3) | 真实挂载合并 bundle:两个内联插件都创建 UI、glue 发布动作、不移动任何 DOM、无运行期上游引用 |
| test/vendor.test.mjs(6) | vendor 哈希/许可、内联体 = vendor + 已声明补丁、每处偏离的锚点/理由/是否落盘、无上游引用、构建可复现 |
| test/manifest.test.mjs(5)+ test/contract.test.mjs(3) | 包形状、面板本地化元数据与内联代码/glue 的 DOM 契约 |
更新上游版本
1. 新版 client.js 放进 vendor/,同步更新同名 LICENSE.。
2. 更新 vendor/manifest.json 的 version 与 sha256(shasum -a 256 vendor/<file>)。
3. node scripts/build.mjs —— 若上游动过被补丁锚定的代码,这一步会直接报错并指出是哪个补丁,照 patches/.json 的新上下文改锚点。
4. node --test test/*.test.mjs。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
jabingu/dsh-selection-group
选中聊天文字后悬停批注或引用,随消息发送
相关插件 · UI / 主题
破甲增强版JeffKeeping/dsh-purge-plus
dsh-purge 的非官方分支fork:适配 DeepSeek Harness 0.2.1-rc.2、破甲内核…
★ 387已汉化DeepSeek 客户端
71.9
无代码业务系统平台nocobase/nocobase
NocoBase 是什么
★ 24,804已汉化DSH
71.8
1Panel 服务器面板1Panel-dev/1Panel
全球 250 万+ 自托管用户共同喜爱。
★ 37,350已汉化DSH
71.5
工作状态行动态ccch1mneyyy/working-activity
作者:chimney@ccch1mneyyy。社区项目,非 DeepSeek 官方项目。
★ 664已汉化DSH
71.2
多模型配置管家farion1231/cc-switch
跨平台桌面一体化助手,支持 Claude Code、Codex、OpenCode、DeepSeek Harness 等工具,唯一官网 ccswitch.io
★ 151,506已汉化DSH
71.1
AI 矢量设计工具ZSeven-W/openpencil
全球首个 AI 原生开源矢量设计工具。
★ 7,027已汉化DSH
71.1
这是你的仓库?认领条目