🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI
广告☁️ 云服务器特惠阿里云首购 8 折 · 腾讯云合作特惠
DeepSeek Harness Hub
← 返回列表

Mooling0602/dsh-web-file-uploader

DeepSeek Harnessspec-screened扫描:中风险在 GitHub 查看 ↗
⚠ 装前注意

一个用于 DeepSeek Harness Web UI 的文件上传插件。它在输入框行中添加了一个

基本兼容但装前注意:未发布到 npm registry,仅可从源码安装 · 最近上游提交 2026/9/10 · 已提供中文文档

一个用于 DeepSeek Harness Web UI 的文件上传插件。

综合分
37.6
GitHub 分
37.6
用户评分
—
★ Stars
11
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add Mooling0602/dsh-web-file-uploader
未发布到 npm registry,仅可从源码安装,改用 GitHub 源安装
信任档位:已验证本站已于 4 天前真实安装成功(L4 · 真实安装)
是什么
dsh 原生插件 · ui
装得上吗
本站已真实安装成功(L4 · 真实安装,非静态推断)
安全吗
本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
还在维护吗
活跃:最近一次提交在 15 天前

档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →

🟢实装验证通过· 2026/9/21
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/21(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查⚠ 装前注意

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-web-file-uploader(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

未发布到 npm registry,仅可从源码安装

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/21 20:15:28

用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

由 DeepSeek 最新模型翻译生成
dsh-web-file-uploader

🌐 语言 · English |

一个用于 DeepSeek Harness Web UI 的文件上传插件。它在输入框行中添加了一个
DeepSeek Web 风格的 回形针附件按钮,并将所选文件上传到 DSH 主机 —— 具备
模型感知适配,使文件真正可供正在运行的模型使用,以及
内容寻址去重,使存储永远不会被重复上传所淹没。

- 仓库:https://github.com/Mooling0602/dsh-web-file-uploader

功能

- 📎 输入框工具栏中的回形针附件按钮,采用官方
附件按钮的外观(28px 圆形、--dsw-specific-selector 填充、14px
实心字形、--dsw-alias-interactive-bg-hover-solid 悬停效果),并将
回形针旋转 45° 以保留此插件长期以来的对角线样式,因此
两个按钮一眼就能区分开来。它位于官方附件按钮的正右侧,
在权限标签之前 —— 并且设置中可以选择隐藏官方按钮,让这个按钮取而代之
- 多文件选择,在输入框上方的停靠区中显示 预览式附件卡片(图片
缩略图):读取中 → 上传中 → 已保存,
带有复制路径和移除按钮
- 文件存储在 DSH 主机上,绝不仅存在于浏览器中
- 名称清理(路径分隔符、..、控制字符会被拒绝)以及
为同名但不同的文件自动添加 -1/-2 冲突后缀
- 内容寻址去重 —— 参见 去重
- UI 字符串通过应用的 locale 服务进行本地化(zh / en;遵循
dsh web 语言设置或系统默认值)

模型感知适配与附件卡片设计

上传的文件在输入框上方的停靠区中显示为 附件卡片。这些卡片是
注入的唯一依据:

| 状态 | 行为 |
|---|---|
| 卡片存在 | 只要卡片可见,文件的绝对路径就会被注入到每一条发送的用户消息中 |
| 卡片关闭(×) | 插件调用主机的 remove RPC —— 文件从待处理注册表中移除,不再被注入,并且文件保留在磁盘上,以便模型仍可从上传文件夹中重新读取它 |
| 卡片删除(🗑) | 插件调用主机的 delete RPC —— 文件被从 DSH 主机上永久删除,并且去重索引会被清理 |
| Ctrl+V 粘贴 | 粘贴的图片走原生草稿图片流程 —— 不会创建卡片,插件也从不触碰它们 |

× 和 🗑 之间的区别是有意为之:× 只是停止注入
(你可能希望模型稍后能找到该文件),而 🗑 表示你
永远不再需要该文件。删除对某个文件的最后一个引用会将其从磁盘上移除;
如果另一个活动会话仍引用同一个去重副本,则该文件会被保留,仅此会话的引用
被移除。

这是一个有意的设计决策:卡片在发送后仍然保留(不同于
(粘贴预览在发送时清除),因此由你决定文件在对话中保持“附加”状态的时长。注入对每条消息都是一次性的,注入的块会准确列出当前卡片处于打开状态的文件。

注入是模型感知的:

| 模型类型 | 图像文件(png/jpeg/webp/gif) | 其他文件 |
|---|---|---|
| 多模态(报告的 inputModalities 包含 image) | 通过附件服务使用原生 ImageBlock —— 图像是请求的一部分,就像普通附加图像一样,且没有额外的提示文本 | 路径文本块 |
| 纯文本(例如 DeepSeek V4 系列) | 路径文本块 —— 模型可以调用读取/视觉工具来检查它们 | 路径文本块 |

能力检查使用 llm.resolveModelInfo().inputModalities(缓存 10 分钟,安全的纯文本回退)。

注入的提示使用可读的、仅英文的格式(模型会读取它):

[Attached files] Some files have uploaded with this message:
- /path/to/file1.txt
- /path/to/image1.png
Read the files or use tools to analyse (like vision tools), then answer the user.

与 vision-tools 及其他插件的兼容性

- 零耦合:该插件只将绝对文件路径注入提示中。它从不调用、包装或假定任何辅助工具 —— vision-tools 或任何其他读取器只是接收路径并独立工作。
- 原生多模态路径:对于支持图像的模型,图像会作为原生 ImageBlock 注入;模型使用自己的多模态能力,不会被提示去调用外部工具。
- 非侵入式:注入仅针对真实用户消息(source.kind === 'user');引导/系统消息永远不会被触碰,并且已经带有 [Attached files] 标记的消息永远不会被注入两次(防止并发宿主实例)。通过 Ctrl+V 粘贴图像完全由产品的原生管道处理。

去重

重复上传不会淹没存储:

1. 在上传时,插件计算解码后字节的 SHA-256(动态模式通过 shell 服务管道执行 base64 -d | sha256sum;静态包使用 node:crypto)。
2. 位于 uploads/.dfu-index.json 的持久化索引将 hash → stored path 映射起来。
3. 如果相同内容再次上传(同名或不同名),现有的已存储副本会被复用 —— 不会写入新文件,不会创建 -1 后缀副本,并且响应会带有 dedup: true。
4. 上传通过 promise 队列串行化,因此并发的相同上传不会发生竞态;过期的索引条目(文件已删除)会回退到全新存储。

| 场景 | 结果 |
|---|---|
| 同一文件上传 N 次 | 磁盘上只有一份副本;所有上传都解析到同一路径 |
| 相同内容,不同文件名 | 复用第一个已存储副本 |
| 相同文件名,不同内容 | 正常的 -1 冲突处理(正确) |
| 进程重启 | 索引文件持久存在,去重继续工作 |
索引项为 hash → { path, at },其中 at 是上传时间戳
(epoch 毫秒),供下方的 TTL 清理使用。旧式 hash → path 条目会被
透明读取,并在下一次写入时升级为对象形式;不带时间戳的旧式条目
永远不会被 TTL 回收(仅在文件已不存在时被清除)。

清理与保留(TTL GC + 手动删除)

上传的文件通过两种互补方式回收:

自动 TTL 垃圾回收

每次上传、每次永久删除以及插件启动都会触发一次惰性清扫
(在成功之后)。早于 TTL 且未被任何活动会话的待处理集合引用的
文件会从磁盘中移除,其索引条目也会被删除。清扫与上传在同一串行
队列上运行,因此绝不会与进行中的写入发生竞态;无需后台任务。

- 默认 TTL:7d(7 天)。
- 保留时间单位:1s(秒)、1m(分钟)、1h(小时)、1d
(天);不带单位的纯数字按天处理(旧式行为)。
0(或空值/无效值)禁用自动 GC——只有当你显式点击 🗑 时
文件才会被移除。
- 配置位于 Settings → File uploads(原生 DSH 设置面板;
该标签页带有自己的回形针标记,因此绝不会像其他插件那样显示为
齿轮行):保留时间字段和替换官方附件按钮开关共用一个保存按钮。
静态 bundle 将两者都持久化到
~/.dsh/dsh-web-file-uploader.json({ ttl, replaceOfficial }),
并逐字段合并更新,因此保存其中一个绝不会清除另一个。环境
变量 DSH_UPLOAD_TTL(例如 DSH_UPLOAD_TTL=30m)会作为
默认值之前的回退被遵循。在动态(会话)模式下,该设置存于
内存中,覆盖在可选的 dsh-web-file-uploader 设置命名空间之上。

时间戳未知的文件(旧式索引条目)永远不会被自动移除,
从而保护迁移前已存在的上传文件不被删除。

附件按钮的位置与替换官方按钮

编辑器工具栏行显示为 [+ menu] [official attach] [permission chips]。
本插件的按钮始终可见,并放置在官方附件按钮的正右侧,
位于权限芯片之前。不会移动任何由 React 拥有的节点:shell 的插槽
包装器为 display: contents,因此 flex order 会重新排列该行——
我们的为 1,shell 在其自身附件按钮之后绘制的所有内容为 2。

| 替换官方附件按钮 | 结果 |
|---|---|
| 关闭(默认) | 两个按钮并排:先是官方直立回形针,然后是本插件的斜向回形针 |
| 开启 | 官方按钮被隐藏,本插件的按钮取而代之——该行中只有一个上传控件 |

- 保存立即生效,无需刷新,且对之后挂载的每个编辑器都生效。
- 将其关闭并保存——或禁用/卸载插件——会将官方按钮恢复为
shell 绘制时的原样:隐藏操作会写入一个内联
样式且从不分离节点,因此 React 的树保持完整。
- 当官方按钮被隐藏时,其自身的待附加轨道也无法再被触发;上传、进度和清理都归本插件所有。
- 本插件的按钮从不会因正在运行的回合而被禁用——在机器繁忙时选取的文件会在下一步被注入。
- 如果未来的外壳不再匹配,该行会完全按绘制时的样子保留,官方按钮保持可见,并且会有一条控制台警告说明原因。

两个卡片操作(回顾)

| 操作 | 宿主调用 | 磁盘上的文件 |
|---|---|---|
| × 关闭 | remove | 保留——模型可能会重新读取它 |
| 🗑 删除 | delete | 永久移除 |

关闭一个上传仍在进行中的卡片会先询问,因为字节仍在传输,而两个答案都是真实的:取消上传会中止传输并丢弃已暂存的字节(不会有任何内容落到磁盘上),而继续上传会关闭该询问并保留卡片——并且一旦完成,其引用也会保留——完整无损。两个答案都不会留下孤立的副本,而且该询问只在传输运行时出现:已完成的卡片仍然一键关闭。

delete 宿主调用会丢弃本会话的引用,检查没有其他活动会话引用同一份去重副本,然后才会取消链接该文件并清理索引。如果另一个会话仍然引用它,文件会被保留(removed: false),但本会话的卡片仍会被清除。

附件大小限制

- 没有单文件上限。 静态包在请求体到达时将其写出,同时对同一遍进行哈希;动态插件让浏览器对 File 进行切片,并在每次 RPC 调用时追加一个分块。两条路径都不会将文件保存在内存中(一次 120 MiB 的上传使进程增长  Git spec 说明:pnpm 的 git 简写形式是 github:/(例如
github:Mooling0602/dsh-web-file-uploader)。裸写的 github.com//
会被 pnpm 当作本地目录处理,并会因
“non-existent directory” 警告而失败。其他有效形式:
git+https://github.com/Mooling0602/dsh-web-file-uploader.git 或
https://github.com/Mooling0602/dsh-web-file-uploader.git。

重启 dsh web 进程并刷新页面。分发详情以及可选的 npm
发布流程(需要你的 npm 凭据)请参见
PUBLISHING.md。

更新

dsh plugin 会在 profile 目录中转发给 pnpm,因此请通过它来更新
(切勿手动编辑 ~/.dsh/profiles/web/node_modules —— 下一次 pnpm
操作会重写它):

dsh plugin --profile web update dsh-web-file-uploader
或者,如果 lockfile 固定的解析结果拒绝移动:
dsh plugin --profile web remove dsh-web-file-uploader
dsh plugin --profile web add github:Mooling0602/dsh-web-file-uploader

之后重启 dsh web 进程;所服务的 bundle URL 带有
内容哈希修订号(?rev=…),因此浏览器会在
刷新时获取新的构建。对于本地目录安装,请在重新添加之前
先在检出目录中运行 pnpm build。详情:PUBLISHING.md。

架构

Browser (Client)                          DSH host (Host)
─────────────                             ─────────────────
conversation.input.left                   harness.handle('upload-begin'/'upload-chunk'/
└ paperclip ── File (sliced) ┐              'upload-finish'/'upload-abort')  [dynamic]
│           webServer route POST /upload        [static]
▼           ┌ sandboxPolicy.resolve() → workspace root
File slices / body          ├ session cwd / DSH_HOME + /uploads/
│           ├ stage .dfu-tmp-, incremental SHA-256
▼           ├ commit: dedup → name → move → .dfu-index.json
└ base64 -d >> tmp (dynamic) / node:fs stream (static)
conversation.input.dock
└ attachment cards (persist)            harness.handle('remove', …) / remove route
└ × closes card → stop injecting     └ pending entry deleted (file kept)
└ 🗑 deletes card                  harness.handle('delete', …) / delete route
└ pending dropped → unlink + index scrub
lazy TTL sweep (upload / delete / start)
└ remove files past TTL, not in pending
agent/pre-step waterfall
├ resolveModelInfo → multimodal?
├ attachments.saveImage → ImageBlock
└ 路径文本块(仅用户消息)

为什么动态模式要经过 shell 的 base64 -d?动态沙箱禁用了 require,而 fs 服务只能写入完整的 UTF-8 文本——因此二进制数据除了通过 shell 服务的 stdin 之外,没有其他方式写入磁盘。按块追加(>>)使每条命令的大小受限于块大小,而非文件大小。静态包没有这种限制,改用 node:fs 进行流式写入。

存储位置

| 模式 | 目标位置 |
|---|---|
| 动态插件 | /uploads/(沙箱化的 shell/fs 无法离开工作区) |
| 静态包 | $DSH_HOME/uploads(默认 ~/.dsh/uploads),通过 node:fs 写入——即 dsh 数据目录 |

去重索引(uploads/.dfu-index.json)与存储的文件放在一起,映射 hash → { path, at }(参见去重和清理与保留)。

仓库结构

项目遵循单一事实来源核心 + 薄接缝架构:所有业务逻辑位于 src/core/;动态插件和静态包只是其上的薄适配器,因此只需修改一次,两端都会同步生效。

dsh-web-file-uploader/
├── src/core/
│   ├── host-core.js        # 规范主机逻辑(传输无关,依赖注入)
│   └── client-core.js      # 规范客户端逻辑(传输无关,依赖注入)
├── src/seams/
│   ├── host-dynamic.template.js     # 动态主机接缝(harness + shell/fs)
│   ├── client-dynamic.template.js   # 动态客户端接缝(host.call + React)
│   └── client-static.template.js    # 静态客户端接缝(fetch + module react)
├── src/host.js             # 生成的动态主机(内联核心)——请勿编辑
├── src/client.js           # 生成的动态客户端(内联核心)——请勿编辑
├── lib/index.js            # 静态主机接缝(导入核心;node:fs/crypto/webServer)
├── client/src/client.js    # 生成的静态客户端源码——请勿编辑
├── scripts/
│   ├── build-dynamic.mjs   # 将核心内联到接缝中 -> src/.js + client/src/client.js
│   └── build-client.mjs    # 将 client/src/client.js 包装为 lib/client.js
├── cordis.patch.yml        # dsh.bundle 补丁(profile 层行)
├── package.json            # 可发布清单(dsh.bundle + dsh.client)
├── PUBLISHING.md           # 安装与 npm 发布指南
├── README.md / README_zh_CN.md
└── LICENSE                 # MIT

如何修改代码:编辑 src/core/(或某个接缝),然后运行 pnpm build——它会重新生成动态源码(src/host.js、src/client.js)和静态客户端包(lib/client.js)。对于正在运行的动态插件,通过 cordis_define + cordis_run 重新部署重新生成的 src/host.js / src/client.js。

开发状态
- ✅ 动态插件:已在实时会话中实现并验证
- ✅ 卡片驱动注入、模型感知适配、去重、国际化 UI
- ⚠️ 静态客户端模块:由 scripts/build-client.mjs 构建,但
__ModuleLoader__ 包装器必须在分发前针对真实 Web 工具链进行验证

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入社群

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

DPharness QQ 群二维码,QQ 扫码进群
QQ 扫码进群
DPharness 飞书群二维码,飞书扫码进群
飞书扫码进群