Back to home@ltsone9

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

License: MIT npm version powered by dsh platform GitHub release GitHub stars

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.

  1. Get the two plugin files:

    (Also fetchable via the raw URLs: host.js and client.js.)

  2. Open any session in the DSH web UI and ask the agent to install it:

    请安装 dsh-filemenu:用 cordis_definekind: newidPrefix: file)创建插件,code.host 填入 plugin/host.js 的完整内容,code.client 填入 plugin/client.js 的完整内容,然后 cordis_runmode: run)激活。

    (Equivalent English instruction: create with cordis_definekind: new, idPrefix: file, code.host = the full content of plugin/host.js, code.client = the full content of plugin/client.js — then activate with cordis_run, mode: run.)

  3. 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.

  4. 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 the desktop profile → --profile desktop. A standalone web-server deployment runs dsh web and uses the web profile → --profile web. Check ~/.dsh/profiles/ for your active profiles.

Install steps (do these in order):

  1. Install the package into the profile: dsh plugin --profile desktop add . — this runs pnpm add in the profile directory and auto-mounts the package because its package.json declares dsh.bundle (the cordis.patch.yml row) and dsh.client (the browser half, served at /plugins/dsh-filemenu/client.js).
  2. 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).
  3. Verify — right-click a produced file / workspace row / session row in the web UI.
  4. 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-filemenu installs directly from the registry. A local checkout (add .) also works. Prerequisite: pnpm on PATH (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 archiveSession API 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/rpc route 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.0 to npm.

🖱️ Usage

Right-click the target; the menu appears exactly at the cursor.

SurfaceMenu items
Produced-file chip / inline reference / tool-card linkOpen · Open containing folder · Open in editor ▸ (detected editors) · Open with another program… · Copy path · Copy relative path
Sidebar workspace (project) rowOpen containing folder · Open · Copy path
Sidebar session rowOpen containing folder · Open · Copy path

Platform behavior:

  • Windows — "Open containing folder" opens Explorer with the file selected (explorer /select,<path>); "Open" uses Invoke-Item; "Open with another program…" opens the system dialog (rundll32 shell32.dll,OpenAs_RunDLL).
  • macOS — reveal uses open -R; open uses open.
  • 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 / actionPurposeTypical command
openOpen with the default applicationpowershell Invoke-Item / open / xdg-open
revealReveal in the OS file managerexplorer.exe /select, / open -R / xdg-open
editorsDetect installed editors + report host platformPATH resolution + install-path probes
openWithLaunch a detected editor with the file<editor-exe> <path>
openWithDialogWindows "Open With" dialogrundll32 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_SPECS table in plugin/host.js and mirror the entry in lib/index.js — each spec has commands (PATH-resolvable names), exeNames (GUI executables next to a bin/ script), and installs (absolute install paths).
  • Menu text: edit the zh / en dictionaries in plugin/client.js.
  • Theme: light mode uses harness alias tokens; dark mode colors live in MENU_CSS (data-fm-theme="dark" block) in plugin/client.js.

🚑 Troubleshooting

SymptomCheck
Right-click does nothingIs 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 outcanOpenPath = false — remote web access or a headless host cannot open paths natively.
Menu shows a red errorRead 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 emptyThe editor is not on PATH and not in a probed install location — add it to EDITOR_SPECS.
Menu does not follow the cursorUse the latest version; earlier builds were missing the position: fixed styling.

❓ FAQ

  • Is any shipped UI replaced? No. DshFileMenu only adds a shell.overlay entry; 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.js is 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

📜 License

MIT © 2026 ltsone9