dsh-filemenu
Right-click file menu for DeepSeek Harness (DSH) web UI: open, reveal in Explorer, open with editor, copy path; sidebar workspace/session menus. 对话文件右键菜单插件。
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 19, 2026
- Updated
- Aug 20, 2026
Introduction
DshFileMenu
English | 中文
Right-click context menus for the DeepSeek Harness (DSH) web UI.
Files produced in a conversation, inline file references, sidebar workspace (project) rows and session rows — open them, reveal them in the OS file manager, open them in a detected editor, or copy their paths. The menu items follow the conventions of the latest Codex desktop apps.
Built as a dynamic Cordis plugin — purely additive, never replaces a shipped UI seat, and every side effect is removed when the plugin stops.
✨ Features
- File context menu — right-click any of:
- produced-file chips in the conversation ("Produced" row),
- inline code file references in assistant messages,
- file-path links on tool cards (best effort),
- → Open · Open containing folder · Open in editor ▸ · Open with another program… · Copy path · Copy relative path
- Workspace (project) context menu — right-click a sidebar workspace row:
- Open containing folder · Open (switch to the workspace's session) · Copy path
- Session context menu — right-click a sidebar session row:
- Open containing folder · Open (switch to the session) · Rename · Fork · Archive · Copy path
- Open in editor — a submenu of editors auto-detected on the host: VS Code, Cursor, Windsurf, VSCodium, Sublime Text, Notepad++, Typora, HBuilderX, Zed, IntelliJ IDEA, WebStorm, PyCharm, Rider, CLion, Neovim, Vim, gedit.
- Open with another program… — the Windows "Open With" dialog.
- Theme aware — light mode follows the harness alias tokens; dark mode uses a near-black surface with near-white text and lines.
- Positioned exactly at the cursor — single column, edge-clamped so it never runs off the viewport; every action has an inline SVG icon.
📦 Installation
Prerequisites
- A running DeepSeek Harness web UI.
- A host OS with a native opener (Windows, macOS, or a desktop Linux). The OS-dependent menu items enable automatically when the Host reports
canOpenPath(headless Linux hosts hide them).
Option A — Quick install as a dynamic plugin (no restart)
DshFileMenu ships as a dynamic Cordis plugin: two plain-JavaScript files, one Host half and one Client half. A dynamic plugin is defined and activated inside a session and takes effect immediately.
-
Get the two plugin files:
plugin/host.js— the Host halfplugin/client.js— the Client half
-
Open any session in the DSH web UI and ask the agent to install it:
请安装 dsh-filemenu:用
cordis_define(kind: new,idPrefix: file)创建插件,code.host填入plugin/host.js的完整内容,code.client填入plugin/client.js的完整内容,然后cordis_run(mode: run)激活。(Equivalent English instruction: create with
cordis_define—kind: new,idPrefix: file,code.host= the full content ofplugin/host.js,code.client= the full content ofplugin/client.js— then activate withcordis_run,mode: run.) -
Approve the first activation. The Client half asks for authorization in the Run card — click Allow (double-check also trusts future versions). Without approval the plugin stays
awaiting-approval. -
Done. Right-click a produced file, a workspace row, or a session row to verify.
Note: dynamic plugins are process-local. After the Harness restarts you need to define and run them again (Option B makes the plugin persistent).
Option B — Persistent install (official CLI route) ✅ v1.1.5
DshFileMenu is shipped in the standard package shape (dsh.bundle / dsh.client declarations), so it can be installed as a permanent profile plugin that survives restarts:
# from the repository checkout
dsh plugin --profile <profile> add .
Which
<profile>? The DSH Desktop app runs thedesktopprofile →--profile desktop. A standalone web-server deployment runsdsh weband uses thewebprofile →--profile web. Check~/.dsh/profiles/for your active profiles.
Install steps (do these in order):
- Install the package into the profile:
dsh plugin --profile desktop add .— this runspnpm addin the profile directory and auto-mounts the package because itspackage.jsondeclaresdsh.bundle(thecordis.patch.ymlrow) anddsh.client(the browser half, served at/plugins/dsh-filemenu/client.js). - Restart the Harness service. The host composition reloads and the web shell rebuilds the client bundle. On the Desktop app, restart the app (or the backend).
- Verify — right-click a produced file / workspace row / session row in the web UI.
- Manage later with the same command:
dsh plugin --profile desktop remove dsh-filemenu,update dsh-filemenu,why dsh-filemenu(any pnpm argument is forwarded verbatim).
Published to npm (
dsh-filemenu@1.1.5) —dsh plugin --profile desktop add dsh-filemenuinstalls directly from the registry. A local checkout (add .) also works. Prerequisite:pnpmonPATH(the CLI forwards to it).
If you run the Harness from source, a patch overlay also works (see the official Your first plugin tutorial):
pnpm dsh web --patch ./cordis.patch.yml
References: official plugin docs, deepseek-harness-plugins collection, dsh-market.
🆕 Recent changes
v1.1.5
- Removed the pin/unpin conversation feature from sidebar session context menus.
v1.1.4
- Added inline SVG icons to every primary menu action and editor submenu row.
v1.1.3
- Added Rename, Fork and Archive to sidebar session context menus; archive is confirmed before the existing safe
archiveSessionAPI is called.
v1.1.2
- Expanded editor detection with Typora, HBuilderX, Zed, IntelliJ IDEA, WebStorm, PyCharm, Rider, CLion, Neovim and Vim.
- Updated both English and Chinese documentation with direct npm installation and recent-change notes.
v1.1.1
- Fixed the packaged Host startup race by declaring
inject: ['webServer']; the/dsh-filemenu/rpcroute now waits for the web server before registering. - Improved packaged RPC error reporting for HTTP errors, empty responses and invalid JSON.
v1.1.0
- Added the persistent package form with
dsh.bundle,dsh.client,cordis.patch.yml, a standard__ModuleLoader__Client bundle and Host HTTP RPC. - Published
dsh-filemenu@1.1.0to npm.
🖱️ Usage
Right-click the target; the menu appears exactly at the cursor.
| Surface | Menu items |
|---|---|
| Produced-file chip / inline reference / tool-card link | Open · Open containing folder · Open in editor ▸ (detected editors) · Open with another program… · Copy path · Copy relative path |
| Sidebar workspace (project) row | Open containing folder · Open · Copy path |
| Sidebar session row | Open containing folder · Open · Copy path |
Platform behavior:
- Windows — "Open containing folder" opens Explorer with the file selected (
explorer /select,<path>); "Open" usesInvoke-Item; "Open with another program…" opens the system dialog (rundll32 shell32.dll,OpenAs_RunDLL). - macOS — reveal uses
open -R; open usesopen. - Linux — reveal/open use
xdg-open(desktop only). - "Open with another program…" is Windows-only and hidden elsewhere.
- When the Host cannot open paths (
canOpenPath = false, e.g. remote web access or headless Linux), all OS-dependent items are disabled; copy items keep working.
⚙️ How it works
┌────────────────────────── Client (browser) ──────────────────────────┐
│ shell.overlay entry hosts the menu; document capture-phase │
│ `contextmenu` listener detects targets via stable DOM markers │
│ (data-produced-files-row / code button[title] / │
│ data-dsh-workspace-drop-target + role=treeitem rows) │
│ Targets are resolved from live sessions/workspaces snapshots. │
└───────────────┬──────────────────────────────────────────────┬────────┘
│ host.call (dynamic) / fetch (packaged RPC) │ client services
▼ ▼
┌────────────────────────── Host (Node) ────────────────────────┐
│ fs service resolves paths; subprocess service launches │
│ native commands; platform derived from processPath shape │
│ (the Host sandbox has no `process` global). │
└────────────────────────────────────────────────────────────────┘
Host RPCs:
| RPC / action | Purpose | Typical command |
|---|---|---|
open | Open with the default application | powershell Invoke-Item / open / xdg-open |
reveal | Reveal in the OS file manager | explorer.exe /select, / open -R / xdg-open |
editors | Detect installed editors + report host platform | PATH resolution + install-path probes |
openWith | Launch a detected editor with the file | <editor-exe> <path> |
openWithDialog | Windows "Open With" dialog | rundll32 shell32.dll,OpenAs_RunDLL |
The transport depends on the install form: the dynamic quick-install uses harness.handle (package-private RPC); the packaged form uses an HTTP RPC endpoint (POST /dsh-filemenu/rpc, registered on the webServer service, called with fetch). Both dispatch to the same actions above.
Editor detection resolves CLI names through subprocess.resolveExecutable (PATHEXT-aware on Windows — finds code.cmd etc.), traces a .cmd/.bat bin script back to the real GUI executable in its install directory, and probes known absolute install paths as a fallback.
🔧 Configuration
- Add a custom editor: edit the
EDITOR_SPECStable inplugin/host.jsand mirror the entry inlib/index.js— each spec hascommands(PATH-resolvable names),exeNames(GUI executables next to abin/script), andinstalls(absolute install paths). - Menu text: edit the
zh/endictionaries inplugin/client.js. - Theme: light mode uses harness alias tokens; dark mode colors live in
MENU_CSS(data-fm-theme="dark"block) inplugin/client.js.
🚑 Troubleshooting
| Symptom | Check |
|---|---|
| Right-click does nothing | Is the plugin running (cordis_inspect_self)? Was the first Client activation approved? Try refreshing the page. Target a supported surface (produced chip / inline reference / workspace row / session row). |
| OS items are grayed out | canOpenPath = false — remote web access or a headless host cannot open paths natively. |
| Menu shows a red error | Read the message shown in the menu (e.g. sessions service unavailable); upgrade to the latest version if it references old field names. |
| Editor submenu is empty | The editor is not on PATH and not in a probed install location — add it to EDITOR_SPECS. |
| Menu does not follow the cursor | Use the latest version; earlier builds were missing the position: fixed styling. |
❓ FAQ
- Is any shipped UI replaced? No. DshFileMenu only adds a
shell.overlayentry; all official slots (tool.call.toolview,conversation.chat.turnTail, the sidebar browser, …) are untouched. - Do I need to restart the Harness? No — the dynamic-plugin flow takes effect immediately and cleans up on stop.
- Why does the dynamic plugin disappear after a restart? Dynamic plugins are process-local by design. Use Option B (
dsh plugin --profile desktop add dsh-filemenu) for the persistent npm package, or re-define the dynamic copy. - Which platforms are supported? Windows is primary; macOS and Linux work where a native opener exists. "Open with another program…" is Windows-only.
- How do the sidebar rows resolve? Workspace/session targets are matched by displayed title against the live snapshots (most recent session wins on ties), constrained to the containing workspace in grouped view.
🛠️ Development
dsh-filemenu/
├── README.md English documentation
├── README.zh-CN.md 中文文档
├── LICENSE MIT license
├── package.json package metadata (dsh.bundle / dsh.client declarations)
├── cordis.patch.yml composition row inserted by `dsh plugin add`
├── lib/
│ ├── index.js Host half — persistent profile plugin (webServer RPC)
│ └── client.js Client half — standard __ModuleLoader__ web bundle
└── plugin/
├── host.js Host half — dynamic quick-install copy (code.host)
└── client.js Client half — dynamic quick-install copy (code.client)
plugin/holds the dynamic quick-install copies: plain JavaScript function bodies that return a Cordis plugin — no TypeScript, JSX, or bundler involved.lib/holds the packaged halves used by Option B.lib/client.jsis a standard web bundle (window.__ModuleLoader__.load,require('react'), manual stylesheet injection,fetch-based RPC).- Keep both in sync when changing behavior (the dynamic copy uses
harness.handle/host.call; the packaged copy uses the HTTP RPC endpoint).
Load the cordis-plugin-development skill in a DSH session for the full API surface used here (slots, harness, styles, theme).
Contributions are welcome — open an issue or a PR.
🗺️ Roadmap
- File context menu (open / reveal / editor submenu / open-with / copy paths)
- Sidebar workspace & session context menus
- Theme-aware dark/light styling
- Persistent npm-package form (Option B install via
dsh plugin add) — v1.1.0 - Publish to npm (
dsh-filemenu@1.1.5) - Screenshots & animated demo
- Detect user-selected custom editor paths from Harness settings