dsh-paste-names:让 DSH Web 输入框支持粘贴与拖放非图片文件

前言

在 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 反查会话工作区后拼接路径,因此拖放只对会话工作区内的条目有效;且插入的是绝对路径文本,不是 @ 引用。

多候选选择

粘贴/拖放的条目在工作区内存在多个同名匹配时,不再自动取最短路径,而是弹出轻量选择器:

  1. 每个多匹配条目一组候选(每组 ≤20 条,最短路径优先,默认选中首选);
  2. 点击候选改选,点「插入所选」一次性插入全部条目;
  3. 按 Esc 或取消则放弃本次插入,不写入任何内容。

唯一匹配的条目不参与选择器,仍直接插入。选择器跟随系统深浅色主题,定位在输入框下方(视口不足时移到上方)。

工作原理

路径解析分两级,多条目共享:

  1. 快查:DSH 自带 remote.fileReferences @ 搜索索引,毫秒级返回,但索引有 10,000 条 BFS 截断,大仓库深层文件覆盖不到;
  2. 深度兜底:宿主半用 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.patchdsh plugin add 会自动接线:

dsh plugin --profile web add git+https://github.com/PaoMoXML/dsh-paste-names.git

也可以手动安装:

  1. 克隆仓库到 profile 的插件目录:
git clone https://github.com/PaoMoXML/dsh-paste-names.git ~/.dsh/profiles/web/plugins/dsh-paste-names
  1. ~/.dsh/profiles/web/package.jsondependencies 里加一行,然后在该目录执行 pnpm install
"dsh-paste-names": "link:plugins/dsh-paste-names"
  1. ~/.dsh/profiles/web/cordis.patch.yml 末尾追加:
- insert:
    - id: paste-names
      name: dsh-paste-names
  1. 重启 dsh web 并硬刷新页面(Ctrl+Shift+R)。

插件自带 22 个回归测试(node:test,无外部依赖),覆盖路由契约、并发 BFS、粘贴归一与选择器交互,可在仓库目录下运行:

npm test

适用场景与注意

适合在 DSH Web 端频繁引用工作区文件的人:大仓库深层文件、同名文件多需要人工挑选、习惯拖放操作的场景都能覆盖。使用前留意几点:

  • 拖放只对会话工作区内的条目有效,且插入的是绝对路径文本,不是 @ 引用;
  • 深度解析每个工作区根首次扫描约 1 秒(按仓库规模浮动),之后 30s 内为毫秒级缓存命中,过期后台重建不阻塞;
  • 深扫排除 .git / node_modules / target,如需增删改 lib/index.jsEXCLUDEDlib/client.jsEXCLUDED_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 / 幻方无官方从属关系)

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye