dsh-selection-ask
English · 安装 · 使用方法 · 开发 · 故障排查 · 许可证
选中即引用,一键问 DeepSeek。
DeepSeek Harness 是一个以文本为先的终端 / agent 工作台,但「把上下文引用回对话」本该是一个手势,而不是复制粘贴的苦工。dsh-selection-ask 给 Web GUI 加上 ChatGPT 式的选区助手:在会话聊天流里选中一段文字,选区旁边就会浮出 「询问 DeepSeek」 按钮。点击它——选中文字即以 Markdown 引用(> 前缀)写入输入框,输入框自动聚焦、光标停在末尾,直接打字追问即可。
为什么选它
- 零摩擦引用 —— 你在 ChatGPT 里熟悉的那套手势,在 DeepSeek Harness 里原样拥有。
- 官方集成,不打补丁 —— 通过 harness 的
inputActions.setDraft输入机 API 写入,撤销历史、草稿持久化全部照常;不碰 DSH 内部实现,不直接改 DOM 状态。 - 一条命令安装 —— 编译好的
lib/已提交进仓库,从 GitHub 安装无需任何构建步骤。
特性
- 按钮跟随选区 —— 用
position: fixed定位到选区的屏幕坐标,自动贴边钳制,选区完全滚出视口后隐藏。 - 只引用聊天流里的文字 —— 选区必须落在聊天流容器(
[data-conversation-scroll])内;在输入框(composer)里选中文字不会触发(把草稿引用回草稿没有意义)。 - 引用感知的拼接 —— 多行选区逐行加
>前缀;草稿为空时直接替换,草稿非空时以空行隔开追加成独立段落。 - 会话级作用域 —— 切换会话自动重置按钮状态;提问 / 审批 composer 接管输入区时按钮随默认输入条一起隐藏。
环境要求
- 带
webprofile 的 DeepSeek Harness(dsh web),DSH 包版本为0.1.0-rc.6一代。 - 浏览器打开 harness GUI(默认
http://127.0.0.1:3080)。 - 从源码构建需要 Node
^22.19.0 || >=24和 pnpm;直接安装不需要(编译好的lib/已提交)。
安装
> 环境要求:DSH ≥ 0.1.5-rc.2(next 通道 / DSH Desktop 桌面版)。
>
> | 插件版本 | 适配的 DSH |
> |---|---|
> | 0.1.1 | DSH ≥ 0.1.5-rc.2 |
> | 0.1.0 | DSH 0.1.0-rc.x(dsh-client-runtime 时代) |
> 用 DSH Desktop 桌面版? 在应用内终端执行同样的命令、不用写 --profile
> (会自动指向 desktop profile)。首次安装需要重启一次;以后升级走热更新,无需重启。
第 1 步:安装包
从 npm 安装(推荐,一条命令)
dsh plugin --profile web add dsh-selection-ask
从 GitHub 安装(最新提交,无需构建)
dsh plugin --profile web add github:lzbaclz/dsh-selection-ask
想固定版本可指定 tag:dsh plugin --profile web add github:lzbaclz/dsh-selection-ask#v0.1.1
从本地克隆安装
git clone https://github.com/lzbaclz/dsh-selection-ask.git
dsh plugin --profile web add link:/绝对路径/dsh-selection-ask
第 2 步:激活
dsh plugin add 会把包自动登记进 profile 的 dsh.profile.bundles 列表,而本包自带 cordis.patch.yml,因此条目行会在启动时自动插入。下面两种激活路径二选一,绝不要同时用。
路径 A —— 重启(零 YAML 编辑;新安装推荐)
重启 dsh web(如果还没启动就正常启动)。完成——不需要改任何配置文件。
# 停掉你的 dsh web 进程,然后:
dsh web
路径 B —— 运行中的服务器热激活(不重启)
直接用 pnpm(不要用 dsh plugin,因为它会把包登记进 bundles),保持 bundles 列表不动,然后改 profile 的 patch 层——DSH 实时监听该文件并热应用:
cd ~/.dsh/profiles/web
pnpm add github:lzbaclz/dsh-selection-ask
然后打开 ~/.dsh/profiles/web/cordis.patch.yml,把 [] 替换成 insert 块——文件必须保持合法的 YAML 列表:
# 改之前:
# Your patch layer for this dsh profile, applied after every bundle layer:
# a top-level YAML array of loader patch entries (id-targeted config
# overrides, disables, and insert lists; `!!js` expressions allowed).
[]
# 改之后:
# Your patch layer for this dsh profile, applied after every bundle layer:
# a top-level YAML array of loader patch entries (id-targeted config
# overrides, disables, and insert lists; `!!js` expressions allowed).
- insert:
- id: dsh-selection-ask
name: dsh-selection-ask
config: {}
保存文件并刷新浏览器页面——插件已加载。
> ⚠️ 不要把路径 A 和路径 B 混用(比如 dsh plugin add 之后又手动加 patch 行):条目会被注册两次,dsh web 启动失败,报 duplicate loader entry id: dsh-selection-ask。
>
> ⚠️ 不要"追加" YAML 块到已有的 [] 后面——那会变成非法文件,dsh web 启动失败,报 failed to parse patches。请按上面示范把 [] 替换掉。
>
> 如果你的 profile 不叫 web,换成你的 profile 名;自定义了 harness 主目录的话,把 ~/.dsh 换成你的 $DSH_HOME。
旧版 profile(由较早版本的 dsh 创建)可能缺少 pnpm-workspace.yaml 里的 autoInstallPeers: false。补上它,pnpm 就永远不会尝试自动安装预发布版本的 peer:
packages:
- .
nodeLinker: hoisted
autoInstallPeers: false
第 3 步:验证
刷新 GUI 页面,在聊天流里选中一句话——选区旁边应浮出 「询问 DeepSeek」 按钮。点击它,文字会以引用形式进入输入框。
升级与热更新
dsh plugin --profile web add dsh-selection-ask@latest # 拉取新版本(桌面版:用应用内终端)
DSH 组合里常驻 dsh-client-hmr 链(会话实测:桌面版组合 - id: client-hmr,未禁用),
它监听已安装插件 bundle 的变化并自动重载——所以:
- 升级已装插件(同一条目、文件内容变化)→ 热更新,无需重启应用,页面通常自动生效
- 首次新增插件(名册增加条目)→ 需要重启一次 DSH 服务
插件的样式、词典、组件注册都随 fiber 生命周期清理,热重载不会残留旧代码。
使用方法
- 在会话聊天流里选中任意文字。
- 点击选区旁浮出的 「询问 DeepSeek」 按钮。
- 选中文字被引用进输入框(形如
> 选中的文字),输入框已聚焦、光标在末尾——直接输入追问并发送。
卸载
dsh plugin --profile web remove dsh-selection-ask
如果你用的是路径 B,还要把 cordis.patch.yml 里的 insert 块删掉(还原成 []),然后刷新 / 重启。
故障排查
| 症状 | 原因与解法 |
|---|---|
dsh plugin add 失败:ERR_PNPM_NO_MATCHING_VERSION,包名是 @deepseek-ai/... |
你的 profile 缺少 pnpm-workspace.yaml 里的 autoInstallPeers: false(旧版 profile),pnpm 尝试自动安装预发布版本(rc)的 peer 依赖而失败。补上这一行(见下文示例)、删掉 profile package.json dependencies 里多余的 @deepseek-ai/* 条目、删除 profile 的 pnpm-lock.yaml,然后重跑。本插件已把所有 peer 标记为 optional,因此永远不会触发自动安装。 |
dsh web 启动失败:failed to parse patches |
insert 块被追加到了文件原有的 [] 后面,YAML 变成非法。把 [] 替换成 insert 块(见路径 B)。 |
dsh web 启动失败:duplicate loader entry id: dsh-selection-ask |
插件被注册了两次——你既用了 dsh plugin add(会加 bundle)又手动加了 patch 行。删掉其中一个。 |
用 dsh plugin add 装好后刷新页面没反应 |
bundles 列表的变更在启动时才生效——重启 dsh web(路径 A),或改用热激活的路径 B。 |
| 选中文字后按钮始终不出现 | 选区不在聊天流内(试试选一条聊天消息的文字);或激活后没刷新页面;或 insert 行缺失。 |
| 按钮出现但点击无效 | 浏览器缓存了旧 bundle——强制刷新页面(Cmd/Ctrl+Shift+R)。若本地重新构建过,先 pnpm build 再重新 link:。 |
| 出现提问卡片时按钮消失 | 属预期行为:overlay 随默认输入条在接管状态下一起隐藏,接管结束后恢复。 |
dsh plugin add 失败 |
任何 pnpm 写法都支持(link:、github:、tarball URL)。检查 profile 路径是否在 ~/.dsh/profiles/ 下,以及 Node 版本。 |
开发
编译好的 lib/ 已提交,正常安装永远不需要构建。想改代码:
git clone https://github.com/lzbaclz/dsh-selection-ask.git
cd dsh-selection-ask
pnpm install
pnpm typecheck # host + client 两段 tsc,零错误
pnpm build # tsc(host) + tsc(client) + tsdown 打包
pnpm verify # 离线冒烟:manifest/exports/patch/产物形状
pnpm test:dom # 无头 DOM 测试:jsdom 里挂载真实组件,断言选区→引用→写入草稿 # 对构建产物做离线冒烟校验
src/index.ts—— host 半(空apply;它的存在是为了让服务器插件名册扫描到本包)。src/client/index.tsx—— 浏览器半:注入样式,注册进conversation.input.overlay插槽。src/client/SelectionAskButton.tsx—— 悬浮按钮组件:选区检测 / 定位 / 引用写入。src/client/quote.ts—— 纯逻辑buildQuote/appendQuote(verify离线测试的对象)。src/client/styles.ts—— 按钮样式 + HMR 安全的 `` 注入。
改完 src/ 后重新构建、重新安装(或重新 link:)包,再刷新页面即可。
原理
插件把一个组件注册进会话级插槽 conversation.input.overlay,从而获得会话输入套件(useInput、inputActions)。组件在文档层监听 selectionchange / mouseup,检测到聊天流内的有效选区后,在选区包围盒处渲染一个 position: fixed 按钮。点击时把选区转成 Markdown 引用、与当前草稿拼接,通过输入机官方写入口 inputActions.setDraft 全文写入,最后聚焦输入框 textarea。
路线图
- [x] 发布到 npm(
dsh plugin --profile web add dsh-selection-ask)—— 0.1.1 已上架。 - [ ] 可选快捷键(如 ⌘⇧Q)一键引用当前选区。
- [ ] 按钮文案 / 语言可配置。
许可证
MIT © lzbaclz
随时欢迎提 Issue 和 PR——开一个 issue 告诉我们你用这个插件做了什么。