dsh-menu — DeepSeek Harness 插件(当前:工作区文件右键菜单)
为 DeepSeek Harness Web 客户端侧边栏的「工作区文件」树添加自定义右键菜单,替代浏览器默认菜单。 纯前端 + Host 路由实现,无第三方依赖、无构建步骤。项目名为
dsh-menu,后续可在此基础上扩展更多菜单。
已发布到 npm,一行命令装好(装完重启宿主进程 + 浏览器硬刷新):
dsh plugin --profile web add dsh-menu
| 深色模式 | 浅色模式 |
|---|---|
![]() |
![]() |
右键「工作区文件」中的任意行 → 自定义菜单(新建文件夹 / 重命名 / 在文件管理器中显示 / 在浏览器中打开 / 在 VS Code 中打开 / 复制文件路径 / 下载文件夹 / 删除)
✨ 功能特性
右键「工作区文件」任意文件 / 文件夹行,弹出自定义菜单(顺序即菜单顺序):
| # | 菜单项 | 说明 |
|---|---|---|
| 1 | 新建文件夹 | 内联输入框;目录行在其内部创建,文件行在其父目录创建 |
| 2 | 重命名 | 内联输入框,可编辑当前文件名 |
| 3 | 在文件管理器中显示 | 调用官方 remote 服务,在资源管理器中定位该文件 |
| 4 | 在浏览器中打开 | 文件原样返回内容;目录渲染为可浏览的 HTML 列表 |
| 5 | 在 VS Code 中打开 | 自动解析本机 VS Code 并打开文件/目录 |
| 6 | 复制文件路径 | 复制工作区路径到剪贴板 |
| 7 | 下载文件夹 / 下载文件 | 目录打包为流式 ZIP 下载;文件直接下载 |
| 8 | 删除(红色) | 危险项红色标注,点击后二次确认 |
交互细节
- 🪟 毛玻璃卡片:半透明主题色底 +
backdrop-filter: blur(18px) saturate(140%) - ⌨️ 内联表单:重命名 / 新建文件夹复用同一输入体验,支持中文输入法组合输入(composition 感知,避免回车打断候选词)、
Enter提交、Esc取消 - ⚠️ 删除二次确认:点击「删除」切换到确认面板,取消或再次确认
- 🔔 结果 toast:成功 / 失败提示,数秒后自动消失
- 🖱️ 点击外部、
Esc、滚动、窗口缩放都会自动关闭菜单 - 🌐 中英双语:
zh/en两套文案,跟随界面语言
📦 目录结构
dsh-menu/
├── index.js # Host 半区:全部文件系统操作路由(约 743 行)
├── client.js # Client 半区:右键菜单 UI(约 680 行)
├── package.json # 包元信息 + dsh.bundle / dsh.client 声明
├── cordis.patch.yml # 把插件并入 Harness profile 的补丁
├── screenshot-dark.png # 深色模式效果图
├── screenshot-light.png # 浅色模式效果图
└── README.md # 本文档
🧩 工作原理
- Client 半区(
client.js)在文档捕获阶段拦截contextmenu事件,命中[data-files-entry]树行后preventDefault掉浏览器默认菜单,改弹自定义菜单(挂载在shell.overlay槽位,是一个独立 overlay 组件)。 - Host 半区(
index.js)通过connection.fetch.register注册一组/api/workspace-files-menu/*路由,所有文件系统操作(重命名 / 建目录 / 删除 / 打开 / 下载)都由 Host 执行,Client 只发 JSON。 - 客户端不依赖任何 Harness Client 包:状态用自实现的 observable store +
React.useSyncExternalStore,样式只用官方主题 CSS token(--dsw-alias-*)。 - 按钮式「在文件管理器中显示」走官方
remote.session.openWorkspacePath({ action: "reveal" }),其余操作走自建路由。
Host 路由一览
错误响应统一为 { ok: false, error: { code, message } }。
| 路由 | 方法 | 参数 | 行为 |
|---|---|---|---|
/api/workspace-files-menu/rename |
POST | { sessionId, path, name } |
重命名文件或目录(仅改名,不移动) |
/api/workspace-files-menu/mkdir |
POST | { sessionId, path, name } |
在 path(必须是目录)内新建文件夹 |
/api/workspace-files-menu/delete |
POST | { sessionId, path } |
删除文件或目录(递归) |
/api/workspace-files-menu/open-app |
POST | { sessionId, path, app: "vscode" } |
在外部应用中打开;当前支持 vscode |
/api/workspace-files-menu/open |
GET | ?sessionId=&path= |
浏览器打开:文件返回内容,目录返回 HTML 列表 |
/api/workspace-files-menu/download |
GET | ?sessionId=&path= |
文件直接下载;目录流式打包 ZIP 下载 |
主要状态码:200 成功;400 非法参数 / 非法文件名 / 父级不是目录;403 目标在工作区之外(含删除根、越界穿越);404 目标不存在;409 重名冲突(rename 到已存在名 / 已存在同名新目录)。
📥 安装
前置:已部署并运行 DeepSeek Harness(含 Web GUI);宿主进程可直接运行 Node.js 与 pnpm。
方式 A:从 npm 安装(推荐)
dsh plugin --profile web add dsh-menu
方式 B:从 GitHub 安装
dsh plugin --profile web add github:tangu2023/dsh-menu
方式 C:从本地目录安装
- 把整个仓库目录放到本地任意位置(例如
D:\plugins\dsh-menu),无需构建。 - 在 DSH 的「插件管理」中安装该 bundle,目标选择仓库目录的绝对路径。插件管理器会自动应用
cordis.patch.yml(把dsh-menu插入当前 profile)。
三种方式装完后都一样
- 重启 DSH 宿主进程让 Host 半区加载(插件管理器的 enable/disable 不会重载已缓存的模块)。
- 浏览器硬刷新(
Ctrl+Shift+R)加载 Client 半区。
说明:
cordis.patch.yml是唯一要求的配置文件,请勿手工修改 profile 下的package.json/cordis.patch.yml,统一由插件管理器写入。本插件零依赖、无构建步骤,所以 git 安装不需要任何 build 授权。
卸载:
dsh plugin --profile web remove dsh-menu(或插件管理器中禁用后移除)。若 pnpm 提示新包保护(
minimumReleaseAge),dsh plugin add会自动把dsh-menu加入 profile 的minimumReleaseAgeExclude,无需手动处理。
🖱️ 使用
在侧边栏「工作区文件」树中右键任意文件或文件夹行即可弹出菜单;「新建文件夹 / 重命名」为内联输入,「删除」需二次确认,其余操作即时执行并 toast 反馈。
🔒 安全设计
- 工作区边界:所有 Host 路由先取会话工作区根(
sessionWorkspaceRoot),再对目标做双向往返路径校验(processPathFromHostPath→fs.resolve→processPath)与严格前缀边界检查(防D:/workspace2这类前缀穿透),任何越界请求返回403。 - 拒绝删根:对工作区根目录的删除操作一律
403。 - 名称校验:非法字符 / 保留名返回
400;重名返回409;路径按normalize后仅以名称参与拼接,杜绝路径穿越。 - 浏览器打开带隔离:通过
/open返回的任何text/html都会附加Content-Security-Policy: sandbox,防止工作区内 HTML 以 GUI 同源权限执行。 - ZIP 流式打包:目录下载不落临时文件、内存有界(
Readable.from+Readable.toWeb背压),手写 ZIP 写入器(UTF-8 文件名、CRC32、data descriptor),零依赖。
🛠️ 开发与脚本
- 无第三方依赖、无构建步骤;语法自检:
node --check index.js/node --check client.js。 - 改 Host(
index.js):需要重启 DSH 宿主进程(看门狗会自动拉起)。 - 改 Client(
client.js):浏览器硬刷新即可(Host 按请求从磁盘读取 client 模块并自带版本缓存破击,无需重启)。 - 冒烟测试:服务运行后直接对路由发起请求,例如:
curl -X POST http://127.0.0.1:12012/api/workspace-files-menu/rename \
-H "Content-Type: application/json" \
-d '{"sessionId":"<会话ID>","path":"D:/workspace/a.txt","name":"b.txt"}'
常见问题
| 现象 | 处理 |
|---|---|
| 右键仍是浏览器默认菜单 | 浏览器硬刷新;确认 shell.overlay 槽位存在 workspace-files-menu 占用 |
| Host 路由 500 / 404 | 插件是 enable 状态但模块未重载 → 重启 DSH 宿主进程 |
| 「在浏览器中打开」403 | 目标不在当前会话工作区内 |
| 重命名报「已存在」 | 目标名已占用(409),换名即可 |
下载中文名文件报 500 |
已在 1.0.0 修复(RFC 6266 响应头编码);旧版本请升级 |
安装 bundle 报 'pnpm' 不是内部或外部命令 |
宿主进程找不到 pnpm → 执行 npm i -g pnpm,或在宿主工作目录放一个 pnpm.cmd shim 指向全局 pnpm |
🤝 兼容性与冲突
依赖的 Harness 接口(随 DSH 版本演进可能需要小幅适配)
shell.overlay槽位:右键菜单的宿主容器- 侧边栏树行属性:
data-files-entry/data-files-path - 主题 token:
--dsw-alias-*(缺失时样式降级,功能不受影响) - Client 注入:
dsh-api-session-controller/dsh-api-remotes/dsh-client-ui-sidebar-right - 官方能力:
remote.session.openWorkspacePath({ action: "reveal" })(用于「在文件管理器中显示」)
与其他插件的关系
- 路由:全部位于
/api/workspace-files-menu/*命名空间,不会与其它插件撞名。 - overlay 槽位:以自有 id
workspace-files-menu追加占用(槽位 id 与包名无关,短 id 便于在检查工具里辨认),不替换、不修改任何已有条目。 - 右键拦截:只在命中
[data-files-entry]且能解析出会话时接管;其它区域(含其它插件的面板)保持浏览器默认菜单。 - 唯一的潜在重叠:若另一个插件也拦截同一批树行的
contextmenu,两者可能各弹一个菜单(当前未发现此类插件)。 - 样式隔离:类名统一
wfm-前缀,<style>带data-plugin标记,便于定位与移除。 - 不改动宿主:不 patch 任何 Harness 模块、不注册全局变量(仅通过
window.__ModuleLoader__.load注册自身模块)。
对其它用户的可用性
- Host 半区只用 Node 内置模块(
node:fs/promises、node:stream、node:child_process),无第三方依赖、无编译步骤。 - 安装由 DSH 插件管理器执行,需要宿主进程能找到
pnpm(见上方常见问题)。 - Windows 已实测;macOS / Linux 对 VS Code 有候选路径回退,其余路由跨平台,但未实机验证。
🖥️ 平台说明
- Windows(主要测试平台):VS Code 通过
PATH中的code命令推导真实Code.exe,并回退常见安装目录(%LOCALAPPDATA%\Programs、Program Files (x86)、Program Files);已实测D:\Program Files\Microsoft VS Code。 - macOS / Linux:VS Code 候选路径包含
/Applications、/usr/bin/code、/usr/local/bin/code等;其余路由(下载 / 浏览器打开 / ZIP 打包)跨平台通用。
🌐 生态与分发
| 渠道 | 地址 | 状态 |
|---|---|---|
| npm | dsh-menu |
✅ 已发布 |
| GitHub | tangu2023/dsh-menu | ✅ 公开,MIT |
| 插件索引 | GitHub topic dsh-plugin |
✅ 已打标(索引站按此 topic 定期同步) |
| 社区清单 | awesome-dsh-plugin PR #6885 | ⏳ 已提交,等待维护者合并 |
合并后即可在 DSH 设置面板内的 dsh-market 插件市场中搜到并一键安装。
📝 版本日志
1.0.2
- 文档:新增「生态与分发」章节(npm / GitHub / topic / 社区清单 / dsh-market)与本节版本日志;顶部补一行安装速览;常见问题补充中文文件名下载的排查项。
1.0.1
- 文档:README 增加 npm / 下载量 / license / topic 徽章;安装章节改为 npm 优先;补充 pnpm 新包保护(
minimumReleaseAge)说明。
1.0.0 — 首个公开版本
- 8 个菜单项:新建文件夹 / 重命名 / 在文件管理器中显示 / 在浏览器中打开 / 在 VS Code 中打开 / 复制文件路径 / 下载(文件夹流式 ZIP)/ 删除(二次确认)。
- 6 条 Host 路由,含工作区边界双向往返校验、CSP sandbox 隔离、零依赖流式 ZIP 打包器。
- 毛玻璃卡片 UI,深色 / 浅色主题自适应,中英双语。
- 修复:非 ASCII(中文等)文件名下载时响应头构造抛异常导致
500;现按 RFC 6266 输出filename+filename*=UTF-8''…。
⚖️ 许可证
MIT © 2025


No comments yet. Be the first to write one.