Back to home

sharkymew

dsh-utility-tools

DSH(DeepSeek Harness)对话工具插件:拖拽任意文件进入对话 + 选中文本引用。

Stars
2
Language
JavaScript
Created
Aug 14, 2026
Updated
Aug 14, 2026

Introduction

dsh-utility-tools

DSH(DeepSeek Harness)对话工具插件:拖拽任意文件进入对话 + 选中文本引用

支持两种加载方式:静态挂载(dsh plugin add 一行命令安装,推荐)与动态加载(cordis_define,零依赖)。


功能

1. 拖拽文件附件(不限于图片)

  • 拖入任意文件到对话区域即进入附件列表:输入框上方显示「📎 附件(N)」胶囊;
  • 点击胶囊展开管理菜单:查看文件名/大小、逐个移除;
  • 发送(Enter 或发送按钮)时随消息一并提交:
    • Electron 环境:直接引用 File.path 原路径,不复制;
    • 普通浏览器:字节无损暂存到系统临时目录(macOS/Linux 用 /tmp,Windows 用每用户 %TEMP%)下的 dsh-drops/<会话id>/,消息引用绝对路径,模型可直接读取;
  • 文件内容不会出现在输入框或消息气泡里(只引用路径与大小),不污染工作目录
  • 图片拖拽仍走系统原生流程;图片与文件混拖时图片自动转交原输入栏。

2. 选中文本引用

  • 在对话中鼠标选中文字 → 选区上方弹出「引用」菜单;
  • 点击后选中文字显示在输入框上方(引用条),带「✕」取消;
  • 发送时引用以 > 引用: 块置于消息开头一并提交。

目录结构

dsh-utility-tools/
├── README.md            # 本文件(含导入指南)
├── package.json         # 包声明:dsh.bundle(自动插入 entry)+ dsh.client(静态 Client 半区)
├── cordis.patch.yml     # ★ bundle patch:`- insert:` 插入插件 entry(一行命令生效的关键)
├── LICENSE              # MIT
├── .gitignore
├── lib/                 # ★ 静态版(一行命令安装用)
│   ├── index.js         #   Host 入口(ESM,export default 插件,零依赖)
│   └── client.js        #   Client 半区(__ModuleLoader__.load 格式)
└── dynamic/             # 动态版(cordis_define 粘贴用,已验证)
    ├── host.body.js     #   code.host 函数体
    └── client.body.js   #   code.client 函数体

如何导入(给使用者)

方式 B:静态挂载(一行命令,推荐 ✅)

# 安装到 web profile(包自带 dsh.bundle,entry 自动插入插件树)
dsh plugin --profile web add dsh-utility-tools

# 重启 dsh web 生效
  • 包通过 dsh.bundle 声明(cordis.patch.yml 内的 - insert: 行)自动向插件树插入 entry,无需手动编辑任何 patch 文件
  • 安装命令等价于在 profile 目录执行 pnpm add
  • 行内 name 是模块说明符:loader 经 import(name) 加载包入口 main(Host ESM),client 模块表扫描 entry 的 dsh.client 声明并 serve ./client 导出(__ModuleLoader__ 格式);
  • Host 半区注册 HTTP 路由 /dsh-utility-tools/save,Client 半区经同源 fetch 上传附件。

方式 A:动态加载(零依赖,已验证)

git clone <本仓库地址>

dynamic/host.body.jsdynamic/client.body.js 的全文交给你的 AI:

用 cordis_define 创建插件:code.host = dynamic/host.body.js 全文,code.client = dynamic/client.body.js 全文,然后 cordis_run 运行。

在 UI 中批准运行请求即可。动态插件是 DSH 一等公民特性,进程内加载、卸载即清理。


架构说明

层面位置职责
Client UIconversation.input.dock(id file-drop-quote引用条、附件胶囊/管理菜单;document 捕获阶段监听 drop/keydown/click/mouseup 等
Client UIconversation.input.overlay(id ref-menu选区上方悬浮「引用」菜单
Client→Host 通道动态:host.call('save-dropped-file');静态:fetch('/dsh-utility-tools/save')发送时上传附件字节(base64)
Host动态:harness.handle;静态:webServer.register 路由纯 JS base64 解码 → ctx.fs 写入系统临时目录 dsh-drops/<会话id>/(平台自适应 + 重名自动加序号)→ 返回绝对路径

关键技术点

  • 字节无损:沙箱内置 atob 是 UTF-8 感知的(Buffer.from(b64).toString('utf-8')),会损坏非 ASCII 字节;Host 端使用纯 JS 手写 base64 解码器,逐字节精确还原;
  • 沙箱兼容/tmp 位于 workspace-write 策略的可写白名单(writableRoots = 工作区根 + /tmp + os.tmpdir()),模型侧工具可直接读写暂存文件;
  • 写盘兜底ctx.fs.writeText 传入 Uint8Array 时底层会在原子写盘后抛错(normalizeLineEndings 仅支持字符串),以 fs.stat 校验大小确认落盘成功;
  • 发送拦截:document 捕获阶段拦截 Enter(textarea 焦点、非 IME 组合、非 Shift)与发送按钮点击(aria-label 匹配「发送消息 / Send message」),先合并引用/附件摘要到草稿再调用 inputActions.submit(),同时跳过 / 命令流与机器忙态;
  • 深色模式:按钮使用 --dsw-alias-button-info-fill(明/暗均为蓝色底白字),避免 --dsw-alias-brand-primary 在深色下反转成近白色导致白字不可见。

已知限制

  • 普通浏览器无法获取拖入文件的真实磁盘路径(平台安全设计),只能按名称引用或暂存到系统临时目录;Electron 环境(File.path)可直引原路径;
  • 单文件上限 8MB(传输载荷约束),超出仅提示不暂存;
  • 暂存目录平台自适应:macOS/Linux 用 /tmp,Windows 优先每用户 %TEMP%C:/Users/<用户>/AppData/Local/Temp),回退 C:/Windows/Temp 等;系统重启后临时目录可能被清空;
  • 纯文本引用上限 2000 字符;
  • 附件在发送时统一暂存,移除附件不会产生任何磁盘残留;
  • 静态版 HTTP 路由仅监听回环地址且只写系统临时目录(受沙箱策略约束),已做最小暴露。

License

MIT