dsh-web-ui
zhu1090093659
Plugin and skin collection for DeepSeek Harness (DSH) Web UI - task board, git graph, right-side panel, remote mobile UI, pet, live token stats, and skin center.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:GLFzr/dsh-file-upload
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
把 DSH Web GUI 原版只支持图片的附件通道,扩展为任意文件上传:拖入任意文件(PDF、3MF、ZIP、Excel、代码、图片……)→ 文件上传/引用到本机中转目录 → 输入框出现一个蓝色文件 chip → agent 可以直接读取该文件。
定位说明(v2.0.0 起):本插件的本质是文件上传功能,不是"路径展示"。路径只是内部机制——agent 读取文件必须依赖磁盘路径,浏览器又拿不到(见下文"为什么必须上传"),所以插件负责把文件物化到本机、并把路径交给 agent。用户界面不再出现任何路径概念:chip 只显示文件名,用户只需知道"文件上传好了,agent 能读了"。
本仓库是持久化 profile 插件(dsh.bundle + dsh.client 双声明):按官方方式安装一次,DSH 重启后自动生效。
.b64 后缀、_1/_2 重名序号、中转目录路径——用户界面永远看不到;提交给 agent 的才是完整真实路径begin 快路径命中条件 = 同名 + 同大小 + manifest 登记的源文件修改时间与本次拖入一致——重复拖同一文件仍秒回(零上传);但编辑过且字节数没变的文件绝不误复用(v2.1.0 起,新/旧文件首次拖入都先完整上传,由 end 的 sha256 逐字节比对裁决:内容相同复用旧路径,内容不同落 _1 副本)~/.dsh-dropbox/.dsh-manifest.json(原名、源修改时间、sha256、是否自动编号副本)——清理面板的"冗余副本"标记只认清单,不会把 notes_2024.txt 这类自然命名误判为副本(v2.1.0 起)_N 副本、按大小清理、清空全部,操作前确认,避免中转目录无限膨胀这是 WebUI 与 Hermes/Codex 之类本地 CLI 的本质区别,不是本插件的缺陷:
C:\...\xxx.pdf;DSH 的 Web GUI 是一个浏览器网页,它手里的文件只是一个内存 File 对象。~/.dsh-dropbox),agent 才能访问。DataTransferItem.webkitGetAsEntry() 能探测到源文件路径——此时插件直接引用原路径,零上传、零复制。Firefox、或从非本机来源(网页、压缩包内)拖拽时拿不到路径,才必须走上传兜底。中转目录会随着使用积累文件(尤其大文件)。侧边栏底部、设置图标上方的垃圾桶图标(悬停显示"清理上传目录")打开清理浮层:
.dsh-manifest.json)里登记的自动编号副本,自然命名文件(如 notes_2024.txt)绝不会被误标_N 副本(推荐——你的电脑里已有原文件,这些副本是纯浪费).b64 是什么?(内部细节,用户无需关心)浏览器无法保证任意二进制文件的原始字节能无损地穿越 JSON/文本通道,所以回退上传的二进制文件(PDF、3MF、ZIP、图片等)落盘时以 base64 文本保存,文件名追加 .b64 作为标记——agent 看到 .b64 就知道要先解码再使用:
import base64
with open('xxx.pdf.b64') as f: raw = base64.b64decode(f.read())
with open('xxx.pdf', 'wb') as f: f.write(raw)
文本类文件(.md/.txt/.json 等)直接写原文,不会带 .b64。本机文件走原路径引用时不经过中转目录,天然没有 .b64。所有这些都是内部机制——输入框里的 chip 只显示文件名,提交给 agent 的才是完整真实路径。
# 在 deepseek-harness 仓库根目录(源码版):
pnpm dsh plugin --profile web add ./plugins/file-upload
# 或任意 dsh 安装(npx 版亦可):
dsh plugin --profile web add <本仓库路径>
dsh plugin 会 pnpm link 本包到 $DSH_HOME/profiles/web 并追加 dsh.profile.bundles。之后无论用 npx 版还是源码版启动 DSH,插件都自动加载。
验证:dsh web --dump-config 应出现 # == dsh-file-upload 层。
从旧名
dsh-drop-file-to-path升级:插件 id 与路由已更名为file-upload,重装后旧版本无需卸载(同一 bundle 行被覆盖)。
| 部件 | 位置 | 职责 |
|---|---|---|
Host 半(lib/index.js) |
宿主进程,inject: ['webServer'] |
HTTP 路由 /api/file-upload/begin\|chunk\|end\|abort\|list\|clean:分块校验、两级去重(lastModified+sha256)、manifest 清单、Origin 校验、node:fs 落盘、清理接口 |
Client 半(lib/client.js) |
浏览器(__ModuleLoader__ bundle,dsh.client 声明) |
全局拖拽监听(capture 接管)、fetch 分块上传、待机圆环、注册 trigger source、经 conversation.input.insertReference 插入文件 chip、侧边栏清理入口 |
文件引用走 composer 原生的参考引用机制(U+FFFC 占位符 + occurrence 表 + 提交时 codec 序列化):占位符在草稿里只占一个字符,因此整个引用是不可分割的整体;提交时经插件注册的 file-upload source 的 codec 把占位符展开为真实路径(含 .b64)。
篮筐宽度自适应:插件在插入前用 composer 的真实字体实测文件名宽度,算出 NBSP 空格数 pad,随 chip 一起插入(占位符 + pad 个 NBSP)。chip 单元格宽度 = 基础 1em + pad×空格宽 ≈ 文件名宽——先有文件名,后有篮筐。为此需要两处配套(都在本 DSH 发行版内):
tools/patch-chip-font.mjs 把 DshChipCell 的 U+FFFC advance 从 composer 默认 4em 改为 1em(同名字体族、后声明者生效,textarea/镜像/背板三层共享同一 advance,对齐关系不变);dsh-client-ui-conversation):occurrence 支持 pad 扩展占位区间——插入、序列化、复制/剪切投影、Backspace/Delete 整删、backdrop 渲染全部按 [offset, offset+1+pad) 整段处理。无该 composer 扩展的公开版 DSH(降级模式):pad 缺失时插件自动退回 [offset, offset+1)——chip 为固定 1em 宽(文件名按 composer 默认样式显示),提交/复制/刷新草稿全部正确,不会损坏草稿。
==,Node/Python 解码器都会在首个 == 处截断,>4MB 文件会损坏;v1.2.1 起修复)。chunk 阶段校验每块精确长度与 base64 合法性;end 阶段校验分块齐全、总量一致、解码后字节数 === 声明大小——截断/缺块/伪造数据一律拒绝,绝不落盘损坏文件。begin 快路径命中需要「同名 + 同大小 + manifest 登记的源修改时间一致」——重复拖同一文件秒回、零上传;编辑过但字节数未变的文件不会走快路径(v2.1.0 修复的误复用问题),而是完整上传后由 end 的 sha256 逐字节比对裁决:内容相同复用旧路径、不产生新副本;内容不同落 _1 副本,绝不复用错误内容。v2.1.0 之前上传的旧文件首次重拖也会走完整上传(缺 manifest 记录),由 end 哈希兜底并补登记。.dsh-manifest.json(原名、源修改时间、sha256、是否自动编号副本);清理时同步注销。清单缺失或损坏时所有行为保守化(不做快路径复用、不标冗余副本),不影响上传本身。#4d6bfe)弧线圆环,渐隐拖尾 + 光晕,0.85s/圈持续旋转。document.body,不经过 React/slot,无中间环节可吞掉它)。侧边栏脚部的垃圾桶图标(sidebar.footer.action 槽位,渲染在设置图标上方;悬停显示"清理上传目录")点击后弹出右下角清理浮层,复用同一套清理逻辑(/api/file-upload/list + /clean)。
依赖官方服务:webServer(HTTP 路由)、slots(shell.overlay + conversation.composer.dock + sidebar.footer.action)、inputTriggers(source 注册与序列化)、conversation/sessions(按 session 解析输入门面)。除上述核心 occurrence 扩展外不修改 dsh 源码。
File.lastModified ↔ manifest 登记时间,1s 容差).dsh-manifest.json 清单,冗余副本标记只认清单登记的自动编号副本,notes_2024.txt 这类自然命名不再被误标、不会被误删::::)落盘为 file 而非 ____dsh-file-upload——定位从"拖拽文件转路径"改为"任意文件上传"(把原版仅图片的附件通道扩展为任意文件);用户界面移除全部"路径"概念(ready 卡片不再显示/复制路径,提示文案统一为"接收文件");内部机制(上传、两级去重、完整性校验、待机圆环、清理入口)与 v1.4.8 完全一致node --check lib/index.js lib/client.js # 语法检查
node --test tests/host.test.mjs # 宿主行为测试(27 例:上传/完整性/两级去重/防误复用/清单/清理/跨源/安全)
CI(.github/workflows/ci.yml)在 push/PR 时自动执行以上两步。
├── lib/index.js # Host 半:HTTP 上传路由 + 校验/去重/清理 + node:fs 落盘
├── lib/client.js # Client 半:全局拖拽 + 待机圆环 + 文件 chip + 侧边栏清理入口
├── tools/patch-chip-font.mjs # 生成加宽 DshChipCell 字体的工具(改宽度后重跑)
├── tests/host.test.mjs # 宿主行为测试(node --test,免 DSH 服务器)
├── chip-cell-font.b64 # 加宽字体产物(client.js 内嵌同一份)
├── cordis.patch.yml # bundle 补丁层(insert 插件行)
├── .github/workflows/ci.yml # CI:语法检查 + 宿主测试
├── .gitignore
└── package.json # dsh.bundle.patch + dsh.client 声明
C:\Users\<用户>\.dsh-dropbox\(os.homedir() 解析;测试可用 DSH_DROPBOX_DIR 覆盖)~/.dsh-dropbox/.dsh-manifest.json(插件内部登记,勿手动编辑;删除中转文件时建议用清理面板,保证清单同步).b64 解码(agent 侧):见上文 .b64 说明end 落盘。单机单用户够用;并发多个大文件会明显吃内存(架构级优化待后续版本)。webkitGetAsEntry() 返回的真实磁盘路径,无存在性/大小校验;OneDrive 占位文件、虚拟文件系统拖入时可能得到不可读路径(此时会看到 agent 报文件不存在,建议改用"复制文件再拖")。Firefox 等拿不到路径的浏览器自动走上传兜底,无此问题。MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: drag-drop、web-ui。