One upload button plus drag-and-drop files into the conversation as local paths: save to the project's uploads/, path text into the input box, works with any vision tool.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:a903067276-rgb/dsh-file-upload
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time. Only install sources you trust, and pin a commit (github:owner/repo#sha).
README
One upload button + drag-and-drop files straight into the conversation — a DeepSeek Harness (DSH) web plugin.
Click the 📎 upload button next to the composer (or just drag any file into the window):
the file is saved to the current project's uploads/ directory and the absolute path is
inserted into the input box as [上传文件] /path/to/uploads/xxx.png. Press send and the
model — or any attached vision tool — reads the file by path.
Vision-plugin agnostic: the message only carries a local absolute path (plain text), so
it works with dsh-vision's view_image, any other model/tool that can read local paths, or
no vision at all. It bypasses DSH's native "the current model does not support images"
rejection because no image block is ever submitted.
Screenshot

The 📎 upload button in the composer tool row; the picked file's path (blurred in the screenshot) is inserted into the input box automatically, ready to send.
Features
| Action | Effect |
|---|---|
| Click 📎 upload | System file picker (multi-select) → save → path into the input box |
| Drag a file into the window | Images & any file type are taken over (no "unsupported" toast) → save → path into the input box |
| Send the message | The model / vision tool reads the file by absolute path |
| Switch sessions | Button follows the current session; files land in that session's project uploads/ |
- Single-file limit: 25 MB (frontend) / 30 MB (backend)
- Filenames keep Chinese/space characters; a timestamp prefix avoids collisions
- Button shows busy state while uploading; failures surface as Chinese notices
Install
Official bundle install (recommended)
dsh plugin --profile web add "github:a903067276-rgb/dsh-file-upload#main"
Restart dsh web (or use scripts/restart-dsh-web.sh). Requires pnpm on PATH
(dsh plugin forwards to pnpm).
Manual mount (fallback, macOS-tested)
See docs/install.md: symlink into ~/.dsh/profiles/web/node_modules/
plus a single entry in ~/.dsh/cordis.patch.yml, then restart.
Usage
- Click 📎 and pick files, or drag files anywhere into the window.
- The input box gets
[上传文件] <absolute path>lines (your existing draft text is kept). - Press send; the model calls its vision tool on the path automatically.
Platform support
| Platform | Status |
|---|---|
| macOS | ✅ fully tested (development environment) |
| Linux | ✅ expected to work (pure Node implementation), untested |
| Windows | ⚠️ expected to work (pure Node implementation, Windows-safe filename sanitization, platform separator paths), untested |
Requirements
- DSH web (run with
dsh web) - No extra shell needed: the host half is pure Node (
node:fs), no system commands required on any platform.
How it works
- Host (
lib/index.js): one routePOST /api/file-upload/save— validates the session and size, then writes the base64 payload to<session cwd>/uploads/with pure Node (node:fs, no system command dependency, cross-platform); the returned path is built vianode:pathand follows the platform separator. - Client (
lib/client.js): registers the 📎 upload button in theconversation.input.leftseat (visually distinct from the default "+" command button); a capture-phase document listener takes over file drags before the official InputBar's bubble-phase listener (which would reject images);FileReaderreads base64, uploads it, then the path text is appended to the input draft (inputActions.setDraft). - Error boundary: a render crash degrades to a small "⚠ upload component error" chip instead of unmounting the whole composer.
Notes
- The
uploads/directory only grows; it is never cleaned automatically (we don't delete your files) — remove files manually when needed. scripts/restart-dsh-web.shrestartsdsh webgracefully (kills the port listener, waits, relaunches, health-checks); the browser auto-reconnects, no manual refresh needed.
Links
More in this category
zhu1090093659/dsh-web-ui#packages/dsh-web-ui-all★ 3649
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
omdsh-dev/DSH-better-sidebar★ 1731
Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
ccch1mneyyy/dsh-TUI★ 1646
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
omdsh-dev/dsh-at-file★ 288
Codex-style `@file` mentions: search workspace files in the composer and attach their contents to prompts.
huiliyi37/dsh-tianshu-tui★ 194
A terminal UI (TUI) for DeepSeek Harness.
Nagi-ovo/dsh-visualize★ 161
In-conversation generative UI: the model renders interactive HTML cards into the chat stream, with streaming preview and sandboxed rendering.