dsh-file-mention
繁體中文版:README.zh.md
@ file mentions + drag-and-drop file → path text for the
DeepSeek Harness (DSH) Web composer.
A DSH Web plugin that turns files in your workspace into lightweight, agent-readable
references. Pick a file from an @ menu — or drop one onto the page — and the composer
inserts an @-prefixed path as plain text; the agent then reads that path with its
own tools (read, etc.). No provider attachment mechanism is involved.
Features
@file mentions — type@and afilesgroup appears, scanned from the current session's workspace directory.- Workspace-relative by default — files inside the workspace present and insert their
relative path (concise); files reached through an explicit outside path (
/…,~/…,../…) present and insert their absolute path (more information). - Bare
@opens the menu — an empty query still lists a default set of workspace files. - Tab to accept — highlight a candidate with the arrow keys and press Tab to insert it, no mouse needed.
- Drag-and-drop files — drop any non-image file onto the page; it is uploaded to the
host and its path is inserted as
@-prefixed text. Pure-image drags pass through to the built-in image rail untouched. - All references carry
@— inserted paths are always prefixed with@to mark them as file references (@README.md,@/Users/you/project/README.md).
Installation
Requires a running DeepSeek Harness Web profile with the
@input-trigger service (ctx.inputTriggers; the plugin peer-depends ondsh-client-ui-input-trigger/dsh-client-runtime/dsh-client-locale^0.1.0-rc.7). On an older host the@/filesmenu never appears.
Install straight from GitHub — no npm publish required (the plugin is build-less, so a
git install needs no extra allowBuilds step):
dsh plugin --profile web add github:tipoLi5890/dsh-file-mention
While developing, link a local clone instead (edits take effect on restart):
dsh plugin --profile web add link:/absolute/path/to/dsh-file-mention
Verify the entry joined the profile, then restart the web server for the new Loader entry and its bundle to take effect:
dsh --profile web --dump-config # you should see a row with id: file-mention
Usage
In the composer:
| Action | Result |
|---|---|
Type @ |
Menu opens with a default workspace file list |
Type @readme |
Matches README.md; picking inserts @README.md |
Type @lib/cl |
Scoped to lib/; description shows lib, picking inserts @lib/client.js |
Type @/etc/ho |
Outside path; description shows /etc, picking inserts @/etc/hosts |
Type @~/Downloads/rep or @../sib/f |
Outside path; inserts the absolute path |
| Arrow keys + Tab | Accept the highlighted candidate without clicking |
| Drop a non-image file | Uploads and inserts @<absolute upload path> |
The path is plain text. On send, the agent resolves a relative path against its session cwd (the workspace) and reads absolute paths directly.
How it works
The package declares a dsh.bundle.patch (a self-inserting Loader entry) and a dsh.client
browser half served into the /plugins boot graph.
Host half — lib/index.js
Hand-written ESM, no build step. Registers a /api/file-mention route prefix on the
profile's web server (ctx.webServer):
GET /api/file-mention/search?base=<abs workspace dir>&q=<query>— a bounded directory scan (depth ≤ 8, ≤ 2000 entries, ≤ 50 results, ~600 ms budget; skips.git/node_modules, never follows symlinks; hidden files are included only when the query starts with.or matches).baseis the session workspace cwd (falls back to the host home). Name-only queries scan the whole workspace; path-like queries (/…,~/…,./…,../…) resolve the directory part and scan only that directory. Returns{ files: [{ name, dir, path, rel }] }—pathis always absolute,relis the workspace-relative path (ornullwhen outside), anddiris the display directory (relative inside the workspace, absolute outside).POST /api/file-mention/upload?sessionId=&name=(raw bytes body, 50 MB cap) — sanitizes the name/session id, writes collision-safely under<DSH_HOME>/uploads/<sessionId>/, returns{ path }.
Browser half — lib/client.js
Loaded in the lazy-CJS factory form the client module loader expects (no build step, no
React). Registers an @/files InputTriggerSource via ctx.inputTriggers; onPick
returns { text: "@" + path + " " } (the pipeline replaces the @query token span with
plain text). Capture-phase dragenter/dragover/drop listeners claim non-image drags,
upload each file, and insert the returned paths at the caret.
API
| Endpoint | Method | Purpose |
|---|---|---|
/api/file-mention/search |
GET |
Bounded file search for the @ menu |
/api/file-mention/upload |
POST |
Upload a dropped file and return its path |
Limitations
- Browsers do not expose a dragged file's native path, so dropped files are copied into
<DSH_HOME>/uploads/<sessionId>/and the copy's path is inserted (the agent can read it; your workspace is untouched). - The
@menu group title shows the source's raw namefiles(theinputTriggers.menulocale namespace is owned bydsh-client-ui-input-trigger). - Mixed drags (images + files) upload images as files too (inserting path text rather than going to the image rail).
- When the composer is busy/locked, the machine may reject the insertion; the plugin falls back to copying the paths to the clipboard.
- Single-file upload cap is 50 MB (host constant).
- The web server remains loopback-only and unauthenticated (same posture as the app).
License
MIT © 2026 dsh-file-mention contributors
No comments yet. Be the first to write one.