Preface

In the DSH (DeepSeek Harness) Web interface, referencing workspace files has two default ways: manually typing @ to select from the menu, or dragging files into the input box. The former is time-consuming for deep files in large repositories, while the latter directly throws an error: “Only PNG, JPG, WebP, and GIF image formats are supported” — any file or folder other than images is rejected.

dsh-paste-names fills this gap: when pasting non-image files or folders, it parses them into DSH native @path file references; when dragging, it inserts absolute path text. Below is an introduction to its functionality, principles, and installation.

What is This

dsh-paste-names is a DSH Web plugin, version 1.4.3, MIT licensed, belonging to the GitHub repository PaoMoXML/dsh-paste-names. It solves a specific problem: replacing the “only supports images” error with usable file references.

The plugin works in two collaborating halves:

  • Browser half (lib/client.js): Intercepts the input box’s paste event and global dragenter/dragover/drop events during the document capture phase, before DSH’s built-in processing. The session ID is obtained by traversing up the React fiber to the target element.
  • Host half (lib/index.js): Registers the GET /plugins/dsh-paste-names/resolve route for deep resolution, responsible for reverse-looking up files by basename.

Core Features

  • Paste non-image files/folders: Parsed into DSH native @ file references, equivalent to manual @ selection.
  • Drag and drop (added in v1.3.0): When dragging files/folders into the workspace, inserts absolute path text, separated by spaces for multiple items.
  • Multiple candidate selector (added in v1.4.0): When multiple matching files with the same name exist in the workspace, a selector pops up. After manual confirmation, insert all items.
  • Screenshots and png/jpg/webp/gif: No intervention, follows DSH’s native image attachment flow; plain text is also not intervened.
  • Trailing @ reference (v1.3.0 behavior): Does not append a trailing space. Keeps the token unclosed to trigger DSH’s native @ menu; the first choice is the exact match, and a single Enter upgrades it to a native chip.

Typical Usage

Paste

Pasted Content Result
File in workspace @relative/path/filename
Directory in workspace @dir/ (with trailing slash)
Path with spaces @"my docs/readme.md" (quoted syntax)
Failed resolution (outside workspace / no match / timeout) Fallback to inserting plain filename

Multiple items pasted are inserted separated by spaces.

Drag and Drop

Dragged Content Result
File in workspace Insert absolute path text, e.g., C:\repo\src\index.js
Folder in workspace Absolute path + trailing separator, e.g., C:\repo\docs\
Path with spaces Quoted as a whole: "C:\my docs\a.txt"
Failed resolution (outside workspace / no session) Fallback to inserting plain filename

Drag onto the input box inserts at the cursor; drag elsewhere appends to the end. Note two points: Browser drag events don’t expose absolute source file paths due to security restrictions. The plugin reverses looks up the session workspace by basename and concatenates the path, so drag-and-drop only works for items within the session workspace. Also, the insertion is absolute path text, not an @ reference.

Multiple Candidate Selection

When paste/drag items have multiple matching names in the workspace, instead of automatically taking the shortest path, a lightweight selector pops up:

  1. Each multi-matching item forms a group of candidates (≤20 items per group, shortest path first, selected by default).
  2. Click a candidate to change selection; click “Insert Selected” to insert all items at once.
  3. Pressing Esc or Cancel abandons the current insertion without writing anything.

Items with a unique match do not participate in the selector and are inserted directly. The selector follows the system light/dark theme and is positioned below the input box (moves above if the viewport is insufficient).

How It Works

Path resolution is two-level and shared by multiple items:

  1. Fast Check: DSH’s built-in remote.fileReferences @ search index. Returns in milliseconds, but the index is truncated to 10,000 BFS items; deep files in large repositories may not be covered.
  2. Deep Fallback: The host half uses node:fs to fully scan the session cwd by basename, limited to 400,000 items / 4 seconds; empirically, it takes about 1 second to scan 78k items.

Batch Interface (v1.3.0): All unmatched items are packed into a single request. The client chunks them by 40 to prevent excessively long URLs. The host half scans only once.

Deep scan results are cached by workspace root as an inverted index of “basename → path”:

  • 30s TTL + stale-while-revalidate: After expiration, the request immediately returns the old index (millisecond-level), and the background rebuilds asynchronously. Only the first request for each root waits for a full scan.
  • Concurrent build deduplication: For the same root, concurrent builds are deduplicated; only one BFS runs.
  • LRU: Caches up to 8 workspace roots to prevent unbounded memory growth in multi-session scenarios.

Resolve Route Request/Response Format:

GET /plugins/dsh-paste-names/resolve?session=<id>&n=<name>&d=<0|1>&n=<name>&d=<0|1>...
  → { ok: true, root: "<abs cwd>", results: [{ name, dir, matches: [{ path, kind }, ...] }, ...] }

Compatible with the old single-item form name=<basename>&dir=<0|1>. root=1 without n= can fetch the root directly without scanning (for drag-and-drop path concatenation); failure returns { ok: false, error: "..." }.

Installation and Enablement

Recommended installation using dsh plugin add. The package’s package.json declares dsh.bundle.patch, and dsh plugin add automatically wires it up:

dsh plugin --profile web add git+https://github.com/PaoMoXML/dsh-paste-names.git

Can also be installed manually:

  1. Clone the repository to the profile’s plugin directory:
git clone https://github.com/PaoMoXML/dsh-paste-names.git ~/.dsh/profiles/web/plugins/dsh-paste-names
  1. Add a line to dependencies in ~/.dsh/profiles/web/package.json, then run pnpm install in that directory:
"dsh-paste-names": "link:plugins/dsh-paste-names"
  1. Append to the end of ~/.dsh/profiles/web/cordis.patch.yml:
- insert:
    - id: paste-names
      name: dsh-paste-names
  1. Restart dsh web and hard refresh the page (Ctrl+Shift+R).

The plugin comes with 22 regression tests (node:test, no external dependencies), covering route contracts, concurrent BFS, paste normalization, and selector interaction. Run in the repository directory:

npm test

Applicable Scenarios and Notes

Suitable for people who frequently reference workspace files on the DSH Web端: Large repositories, deep files, multiple files with the same name requiring manual selection, and drag-and-drop scenarios are all covered. Note a few points before use:

  • Drag-and-drop only works for items within the session workspace, and it inserts absolute path text, not an @ reference.
  • The first scan of each workspace root takes about 1 second (fluctuates by repo size); subsequent 30s hits are millisecond-level cache hits; expired background rebuilds do not block.
  • Deep scan excludes .git / node_modules / target. If you need to modify EXCLUDED in lib/index.js and EXCLUDED_SEGS in lib/client.js.
  • The plugin runs with the current dsh process permissions. It is recommended to check the source code and license before installing (this project is MIT).

Conclusion

dsh-paste-names improves the daily DSH Web experience through a very small entry point: non-image files change from “error” to usable @ references or path text. Path resolution has a fast index check plus a deep scan fallback, and multi-name scenarios are handed over to manual confirmation. DSH’s philosophy is “Everything is a plugin”; such plugins that fill in the shortcomings of default behaviors are typical usage of this mechanism.

Project Homepage: https://github.com/PaoMoXML/dsh-paste-names

Community Directory Page: https://www.skillhub.cn/plugins/PaoMoXML/dsh-paste-names (The community directory is an independent site with no official affiliation to DeepSeek or Hypothesis).