前言¶
在 DSH(DeepSeek Harness)Web 界面里引用工作区文件,默认只有两条路:手动输入 @ 从菜单逐级挑选,或者把文件拖进输入框。前者在大仓库里找深层文件很费时,后者会直接报「仅支持 PNG、JPG、WebP、GIF 格式的图片」——除图片外的任何文件、文件夹都不收。
dsh-paste-names 补的就是这个缺口:粘贴非图片文件或文件夹时,解析成 DSH 原生 @path 文件引用;拖放时,插入绝对路径文本。下面介绍它的功能、原理与安装方式。
这是什么¶
dsh-paste-names 是一个 DSH Web 端插件,当前版本 1.4.3,MIT 许可证,仓库归属 GitHub 的 PaoMoXML/dsh-paste-names。它解决的问题很具体:把「仅支持图片」的报错替换为可用的文件引用。
插件分两半协作:
- 浏览器半(
lib/client.js):在 document 捕获阶段拦截输入框的paste事件与全局dragenter/dragover/drop事件,先于 DSH 自带处理。会话 id 通过目标元素沿 React fiber 上溯取得。 - 宿主半(
lib/index.js):注册GET /plugins/dsh-paste-names/resolve深度解析路由,负责按 basename 反查文件。
核心功能¶
- 粘贴非图片文件/文件夹:解析为 DSH 原生 @ 文件引用,与手动 @ 选择等价;
- 拖放(v1.3.0 新增):拖入工作区内文件/文件夹时插入绝对路径文本,多条目以空格分隔;
- 多候选人工选择器(v1.4.0 新增):工作区内存在多个同名匹配时弹出选择器,人工确认后再插入;
- 截图与 png / jpg / webp / gif 不干预,走 DSH 原生图片附件流程;纯文本也不干预;
- 末位 @ 引用不补尾随空格(v1.3.0 行为):保持 token 未闭合,唤出 DSH 原生 @ 菜单,首选即精确匹配,一次回车即可升级为原生 chip。
典型用法¶
粘贴¶
| 粘贴内容 | 结果 |
|---|---|
| 工作区内的文件 | @相对/路径/文件名 |
| 工作区内的目录 | @目录/(带尾斜杠) |
| 含空格的路径 | @"my docs/readme.md" 引号语法 |
| 解析失败(工作区外 / 无匹配 / 超时) | 回退插入纯文件名 |
多条目粘贴以空格分隔插入。
拖放¶
| 拖入内容 | 结果 |
|---|---|
| 工作区内的文件 | 插入绝对路径文本,如 C:\repo\src\index.js |
| 工作区内的文件夹 | 绝对路径 + 尾分隔符,如 C:\repo\docs\ |
| 含空格的路径 | 整体加引号:"C:\my docs\a.txt" |
| 解析失败(工作区外 / 无会话) | 回退插入纯文件名 |
拖到输入框上插在光标处,拖到界面其他位置追加到末尾。注意两点:浏览器拖放事件出于安全限制不暴露源文件绝对路径,插件按 basename 反查会话工作区后拼接路径,因此拖放只对会话工作区内的条目有效;且插入的是绝对路径文本,不是 @ 引用。
多候选选择¶
粘贴/拖放的条目在工作区内存在多个同名匹配时,不再自动取最短路径,而是弹出轻量选择器:
- 每个多匹配条目一组候选(每组 ≤20 条,最短路径优先,默认选中首选);
- 点击候选改选,点「插入所选」一次性插入全部条目;
- 按 Esc 或取消则放弃本次插入,不写入任何内容。
唯一匹配的条目不参与选择器,仍直接插入。选择器跟随系统深浅色主题,定位在输入框下方(视口不足时移到上方)。
工作原理¶
路径解析分两级,多条目共享:
- 快查:DSH 自带
remote.fileReferences@ 搜索索引,毫秒级返回,但索引有 10,000 条 BFS 截断,大仓库深层文件覆盖不到; - 深度兜底:宿主半用
node:fs按 basename 全量扫描会话 cwd,上限 400,000 条 / 4 秒,实测约 1 秒扫完 78k 条目。
批量接口(v1.3.0):全部未命中条目打包成一次请求,客户端按每批 40 条分块防 URL 超长,宿主半只扫一次。
深扫结果以「basename → 路径」倒排索引按工作区根缓存:
- 30s TTL + stale-while-revalidate:过期后请求立即返回旧索引(毫秒级),后台异步重建;只有每个根的首次请求才等待完整扫描;
- 同一根的并发构建去重,只跑一次 BFS;
- LRU 最多缓存 8 个工作区根,防止多会话场景内存无界增长。
resolve 路由的请求与响应格式:
GET /plugins/dsh-paste-names/resolve?session=<id>&n=<name>&d=<0|1>&n=<name>&d=<0|1>...
→ { ok: true, root: "<abs cwd>", results: [{ name, dir, matches: [{ path, kind }, ...] }, ...] }
兼容旧单条形式 name=<basename>&dir=<0|1>;root=1 且不带 n= 可免扫描直接取根(供拖放拼接绝对路径);失败返回 { ok: false, error: "..." }。
安装与启用¶
推荐用 dsh plugin add 安装。包的 package.json 声明了 dsh.bundle.patch,dsh plugin add 会自动接线:
dsh plugin --profile web add git+https://github.com/PaoMoXML/dsh-paste-names.git
也可以手动安装:
- 克隆仓库到 profile 的插件目录:
git clone https://github.com/PaoMoXML/dsh-paste-names.git ~/.dsh/profiles/web/plugins/dsh-paste-names
- 在
~/.dsh/profiles/web/package.json的dependencies里加一行,然后在该目录执行pnpm install:
"dsh-paste-names": "link:plugins/dsh-paste-names"
- 在
~/.dsh/profiles/web/cordis.patch.yml末尾追加:
- insert:
- id: paste-names
name: dsh-paste-names
- 重启
dsh web并硬刷新页面(Ctrl+Shift+R)。
插件自带 22 个回归测试(node:test,无外部依赖),覆盖路由契约、并发 BFS、粘贴归一与选择器交互,可在仓库目录下运行:
npm test
适用场景与注意¶
适合在 DSH Web 端频繁引用工作区文件的人:大仓库深层文件、同名文件多需要人工挑选、习惯拖放操作的场景都能覆盖。使用前留意几点:
- 拖放只对会话工作区内的条目有效,且插入的是绝对路径文本,不是 @ 引用;
- 深度解析每个工作区根首次扫描约 1 秒(按仓库规模浮动),之后 30s 内为毫秒级缓存命中,过期后台重建不阻塞;
- 深扫排除
.git/node_modules/target,如需增删改lib/index.js的EXCLUDED与lib/client.js的EXCLUDED_SEGS; - 插件以当前 dsh 进程权限运行,安装前建议检查源码与许可证(本项目为 MIT)。
结尾¶
dsh-paste-names 用一个很小的切入点改善了 DSH Web 端的日常体验:非图片文件从「报错」变成可用的 @ 引用或路径文本,路径解析有索引快查加深扫兜底,多同名场景交给人工确认。DSH 的理念是「一切皆插件」,这类补足默认行为短板的插件正是这套机制的典型用法。
项目主页:https://github.com/PaoMoXML/dsh-paste-names
社区目录页:https://www.skillhub.cn/plugins/PaoMoXML/dsh-paste-names (社区目录为独立站点,与 DeepSeek / 幻方无官方从属关系)