dsh-file-tree-menu
v0.1.0
Published
Right-click menu for the workspace file tree: add to the conversation, reveal in the file manager, copy the name / relative path / absolute path, rename, and delete.
Readme
dsh-file-tree-menu
给右侧栏的工作区文件树加一个右键菜单:以前右键只能弹出浏览器自带的「Copy」,现在是文件树自己的菜单。
| 菜单项 | 行为 |
|---|---|
| 添加到会话 | 把 @相对路径 插到当前会话输入框的光标处(一次可撤销的纯文本编辑);带空格的路径按 @"路径" 引用,目录带结尾 /。输入框接口不可用时退化为复制到剪贴板并提示。 |
| 在访达中显示 | 用宿主自己的能力在文件管理器里选中该文件。Windows 显示「在文件资源管理器中显示」,Linux 显示「在文件管理器中显示」——文案跟随宿主平台,不看浏览器。 |
| 复制 | 复制这个文件/目录的名称。 |
| 复制相对路径 | 相对工作区根目录的路径,例如 docs/plan.md。 |
| 复制绝对路径 | 树节点上携带的绝对路径。 |
| 重命名 | 弹窗改最后一段名字;回车确认、Esc 取消;不覆盖同名文件。 |
| 删除 | 先确认再删;目录连同内容一起删,不可撤销。 |
只对文件和目录行出现;socket 之类打不开的条目保持原样。
安装
桌面端 profile(~/.dsh/profiles/desktop):
dsh plugin --profile desktop add link:/Users/curleaf/WorkSpace/dsh-file-tree-menu然后退出并重新打开 DeepSeek Harness。新插件要重新读一次 profile,窗口刷新(Cmd+R)不够。
为什么还需要宿主半边
文件树的读写面 workspaceFiles 是只读的(list / stat / read / changes),重命名和删除没有对应接口;「在访达中显示」走的是会话的 openWorkspacePath,只有打开动作。所以插件分成两半:
浏览器 宿主
┌────────────────────────────┐ ┌──────────────────────────────┐
│ 文件树右键菜单 │ │ POST /dsh-file-tree-menu/action │
│ 复制 / @ 引用 / 显示位置 │ ──写──▶ │ 重命名、删除 │
│ 重命名、删除(对话框) │ │ 鉴权、限界、路径校验 │
└────────────────────────────┘ └──────────────────────────────┘写操作的路由只有一条,安全全在宿主这一侧:
- 先过
connection.requestRejection:Host/Origin 围栏 + 浏览器登录 Cookie;没有这个服务的组合直接 503 失败关闭,不会接受匿名写入。 - 请求体限
application/json、64 KiB、已知 action、绝对路径。 - 目标必须存在,且它的父目录 realpath 落在某个会话工作区(或 sandbox 工作区)之内——树里的软链接指到外面也绕不过去;删除/重命名软链接本身仍然允许。
- 工作区根目录永远不能作为目标(它的父目录在外面,第一道限界就拒绝)。
- 重命名只改最后一段,且不覆盖已存在的条目(大小写不敏感卷上的「只改大小写」放行)。
操作完树会自己刷新
文件树本来就在用 workspaceFiles.changes 盯目录,宿主的改名/删除会触发同一条变更流,树自动重读。关掉了「自动刷新」(树头部的暂停按钮)时不会自动重读,按一下刷新即可。
验证
npm testtest/host.test.mjs:真实临时目录 + 假 Cordis 上下文,覆盖改名、删除、越界、软链接逃逸、根目录保护、覆盖拒绝、鉴权、请求体校验。test/client.test.mjs:bundle 的注册契约与路径/@引用规则。test/client-dom.test.mjs:jsdom + 真 React 渲染文件树,覆盖右键菜单内容、三种复制、插入输入框、重命名失败/成功、删除确认、Esc、显示位置。
测试用的 jsdom / react / react-dom 是 devDependencies,不会随插件发布。
已知限制
- 菜单是文件树 DOM 上的
contextmenu监听(核心没有为行菜单留插槽),依赖data-files-entry/data-files-path/data-files-root这几个数据属性。DSH 改这些约定时要跟着改。 - 文案目前是中文;界面语言换成英文时菜单仍是中文。
- 删除是直接删除,不进废纸篓。
- 重命名/删除以宿主进程本身的权限执行(等同于你在终端里操作),不经过会话的沙箱策略;这是你在界面上的主动操作,因此不受智能体沙箱限制。
- 「添加到会话」依赖会话作用域的
inputActions;拿不到时退化成复制引用,不会静默失败。
卸载
从 profile 的 dependencies 里删掉 dsh-file-tree-menu、从 dsh.profile.bundles 删掉同名条目,删掉 node_modules/dsh-file-tree-menu,重启应用。
