Bundle
dsh-any-attachment
dsh bundle: attach any file type in dsh web — text-likes inline, binaries as workspace path references, rasters via the built-in pipeline
- Source
- Zenjibad
- stars
- 3 stars
- License
- MIT
- Updated
- Updated 23 hours ago
Readme
# dsh-any-attachment
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`) plugin bundle that lets the Web UI attach files of **any type** as **pathless @-mentions**: type `@` to pick a workspace file, or drop a file (or use the **+** button) to tag it into your message — the agent then reads the file itself with its own tools. Mentions carry the name only, never a path. Raster images keep flowing through the built-in image pipeline. No changes to the harness repo, and nothing is written into your workspaces.
## How mentions work
- **`@`-list**: in the composer, type `@` and a menu shows the session workspace's files, recursively and flat (`src/main.ts`, `docs/guide.md`, …). Type more to filter; pick one and a pathless `@name` chip is inserted into the draft.
- **Drop / + button**: drop a local file onto the composer (or click **+**) and it is stored privately; the draft gains an `@<stored-name>` chip — no path, no drive letter.
- Send as usual (Enter or the send button) — every mention chip resolves to its **exact file location** in the sent message (`@name (C:\...\absolute\path)`), so the agent reads the file directly instead of guessing where it lives.
- Raster images (png/jpeg/webp/gif) still route to the built-in image pipeline (vision models see them).
- Files live under `$DSH_HOME/attachments-any/` — private, never dumped into a workspace.
## Install
```sh
dsh plugin --profile web add https://github.com/Zenjibad/dsh-any-attachment
```
Restart `dsh web`, then hard-refresh the page.
## Limits
| Guard | Value |
| --- | --- |
| Max bytes per file | 25 MB |
| `@`-list depth | 4 levels below the workspace root |
| `@`-list entries | 500 (sorted, `/`-separated relative paths) |
| `@`-list exclusions | hidden (`.`-prefixed) entries and `node_modules` |
| Name | basename only; traversal, separators, drive letters rejected |
| Storage | private store under `$DSH_HOME/attachments-any`, never a workspace |
## How it works
- **Host** (`lib/`): registers an RPC channel `/attachments-any` (authority `trusted-host`, same LAN fence as `/api`). `list { sessionId }` walks the session workspace recursively and returns relative paths; `upload` validates base64/size/name, writes into the private store, and returns the stored name (deduped with `-2` suffixes). A system-prompt section tells the agent that a referenced `@name` lives at `./<name>` relative to its working directory, or in the private store otherwise.
- **Client** (`client/`): composer `+` button (`conversation.input.left`), a capture-phase drop handler, and an `@file` input-trigger source (workspace autocomplete, pathless picks). Rasters route through `createDraftImages`/`addImages`; everything else uploads via the channel and the mention `@<name>` is appended to the composer draft via `inputActions.setDraft`.
The agent reads the file at the resolved path with its own tools — no extraction, no download UI, no special send flow.
## Test
```sh
node --test
```
## License
[MIT](LICENSE)
Install
dsh plugin --profile web add github:Zenjibad/dsh-any-attachment
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-any-attachment from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.