dsh-multi-root-explorer
Verifieddsh-multi-root-explorer · v0.1.6 · MIT · Web UI
Workspace Explorer for DeepSeek Harness: replaces the native sidebar workspace region with a multi-root browser — a conversation tree grouped by each session's real working directory, plus a read-only resource tree that previews files in the native right
Install
dsh plugin add dsh-multi-root-explorer Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-multi-root-explorer(工作区资源管理器)
给 DeepSeek Harness 用的工作区浏览器:它接管左侧栏的工作区区域,换成两个选项卡——对话按每个会话真实的工作目录归入目录树,资源是一个只读的文件树,点文件用 DSH 原生右侧栏预览。
中文 | English

状态:预览版。 自动化测试全部通过,但尚未在所有 DSH 版本上做完整实机验收。安装前请先看已知限制。
它能做什么
- 固定多根目录。 你导入的目录就是根,不会随着会话增减被重算成某个公共祖先。
- 会话变成目录树。 每个会话按它真实的
cwd归位:当前目录的直接会话排在前面,子文件夹排在后面,逐层递归。cwd在根目录之外的历史会话保留独立入口;没有cwd的会话单独一组。 - 资源只读浏览。 目录按层加载并分页,打开一个大盘不会先递归扫全盘。点文件交给 DSH 自己的右侧栏预览,主栏对话不受影响。
- 两个选项卡各自独立的隐藏,且完全可逆。 点标题栏的小眼睛进入选择模式:已隐藏的项会显示出来并处于选中状态。点一个未选中的文件夹=选中它(整个子树随之显示为选中);点一个"被父目录覆盖"的子项=把它单独排除,祖先展开成同级项、其余保持选中;单击已选中的文件夹=它连同子树一起取消;双击已选中的文件夹=父目录取消、全部子项保持选中,提交后就是一个空文件夹。选中的后代按需向 Host 查询该目录自身的层级,所以没展开过的子文件夹同样会被覆盖。再点一次小眼睛就只隐藏最终选中的那些;隐藏只影响显示,不动任何文件、目录或会话记录。
- 每个文件夹都有操作菜单。 右键或右端
···可以在该目录里开启新会话、在系统资源管理器中打开;资源还支持复制绝对路径。 - 拖进输入框就是原生引用。 资源行是标准拖拽源(
text/plain、text/uri-list,外加一个插件私有的格式),效果固定为copy。拖到对话输入框里时会自动提升成 DSH 原生的原子引用——文件图标 + 文件名 + 业务色,和从@菜单里选中一个候选完全一样。提升失败时(例如落点紧邻文字、补全菜单没有为这段文本打开)会保留一条可读的引用文本并说明原因,不会把草稿弄乱。 @能检索所有工作区。 DSH 自带的文件补全只索引会话的工作目录,插件另外注册了一个@源,覆盖全部已登记工作区(包括其他盘上的根),并在 Host 侧维护一份有界索引:沿用官方的排除目录策略(node_modules等)、切片后台遍历、查询永不阻塞。- 工作状态诚实。 会话的状态卡和行首圆点不只看会话自己的 agent:子 agent 还在工作时(即使主 agent 已经停下)以及 goal 仍在逐轮推进时(两轮之间的空档),都显示「工作中」。
- 支持原生归档。 归档/取消归档走 DSH 自己的服务,并且和「永久删除」明确分开。
- 卸载后不会丢对话。 插件运行期间会把有普通会话的目录登记为 DSH 原生工作区,所以停用或卸载插件后,你的对话仍然能在原生界面找到。
环境要求
- DeepSeek Harness
>= 0.2.0-rc.1(声明在dsh.engines.dsh)。 - 浏览器需支持 Popover API(
element.showPopover)。菜单和悬停卡渲染在顶层;不支持时插件会明确报错并关闭菜单,而不是把菜单放错位置。 - 通过回环地址访问 DSH。插件的 HTTP 路由会拒绝非回环 socket、非回环
Host头和跨站请求。
插件没有任何运行时依赖,只用 DSH 客户端模块加载器已经提供的 react。
安装
四种方式,任选一种。装完都要重启 DSH(重启应用与 Host),然后刷新页面 —— Host 路由不支持热重载,只刷新页面不够。
💡 方式 2、3 需要机器上有
dsh命令。 桌面应用版用户如果提示找不到命令,请用 方式 1 或 方式 4 —— 这两条完全不依赖命令行。
1. 应用内插件市场(最省事,不依赖命令行)
打开设置 → 插件市场,搜索 dsh-multi-root-explorer,一键安装。市场会替你改好 profile 并提示何时重启。社区目录上架前(搜不到时)请用方式 2 或 4。
2. npm 包(命令行;永远取最新已发布版本)
dsh plugin --profile <你的 profile 名> add dsh-multi-root-explorer
写包名而不是 git 地址:包管理器会取 npm 上的最新已发布版本,以后发新版自动跟上。当前版本号见 npm 页面。
3. 从 GitHub 装(不经过 npm)
方式 A:预构建包(永远取最新发布版)
dsh plugin --profile <你的 profile 名> add https://github.com/Nethur-auro/dsh-multi-root-explorer/releases/latest/download/dsh-multi-root-explorer.tgz
链接里的 latest 在请求时解析,而资源文件名刻意不带版本号,所以它永远指向最新一次发布、也不会随发版失效。(本插件没有构建步骤:lib/ 是随仓库提交的成品,scripts 里只有 test,所以预构建包和源码装出来的东西一致。)
方式 B:源码(跟踪 main 分支)
dsh plugin --profile <你的 profile 名> add git+https://github.com/Nethur-auro/dsh-multi-root-explorer.git
装的是仓库 main 的当前提交。本项目每次发布都把 main 停在那个发布提交上,所以 main HEAD 与最新 tag 始终是同一点 —— 源码装到的就是最新发布版。代价是包管理器按 commit 缓存,升级要重装一次。
4. 手动改 profile(不依赖命令行)
插件管理器本质上就是改你 profile 的 $DSH_HOME/profiles/<你的 profile 名>/package.json(默认 ~/.dsh)。加依赖和 bundle 条目:
{
"dependencies": {
"dsh-multi-root-explorer": "^0.1.4"
},
"dsh": {
"profile": {
"bundles": ["dsh-multi-root-explorer"]
}
}
}
然后在该目录里 pnpm install,再重启 DSH。手动做和插件管理器做的是同一件事,所以除非有特别理由,优先用方式 1 或 2。
怎么确认装上了
看左侧栏:工作区区域应该出现对话 / Conversations和资源 / Resources两个选项卡,并且有插件自己的标题栏。如果看起来没变化,说明 Host 还没加载新代码——重启 DSH,而不是只刷新页面,Host 路由不支持热重载。
使用
- 点「添加工作区」选目录,需要几个根就加几个。
- 「对话」页显示文件夹和会话;「资源」页显示文件夹和文件。目录第一次展开时才加载该层。
- 点文件用右侧栏预览。预览需要一个可用会话作为授权上下文。
- 文件夹右键或
···:在该目录开启新会话、在系统资源管理器中打开、(资源)复制路径。 - 会话右键:打开、重命名、归档、永久删除。永久删除有风险,见安全与永久删除。
- 用小眼睛按选项卡隐藏条目;被你隐藏的东西都能在设置里恢复显示。
- 「显示隐藏项」额外显示点开头的名字、
node_modules和dsh-acl-recovery——它们默认是隐藏的。
数据与隐私
插件自己的数据都在 $DSH_HOME/storages/workspace-explorer/ 下:
config.json——版本 3:根目录、目录别名、两份互相独立的隐藏列表、展开状态和偏好。v1/v2 在迁移前会先备份;文件损坏或版本比程序新时会拒绝覆盖,而不是静默替换成空配置。native-bridge.json——插件自己的幂等与进度记录。它只是记账,不是你的会话或原生工作区状态的副本。
写入是串行化 + 原子替换的。移除 bundle 不会删掉这个目录;要清理请先确认没有待完成的新会话操作,并且绝不要把删除 DSH 会话数据当成插件清理的一部分。
资源浏览从头到尾都是只读的:插件不会在你的工作区里创建、写入、移动或删除任何文件。请求受注册根、realpath 边界(含中间链接)和回环/同源校验限制。
安全与永久删除
永久删除是一个早就存在、被刻意隔离的功能,而且不可恢复。 目标 DSH 版本没有官方会话删除接口,所以那一个动作会直接移除会话自己的持久化产物。它依赖具体版本的存储结构,不是 DSH 支持的接口,应当只当作最后手段。请优先使用归档。
停用插件、卸载插件或清除配置,都不会触发这条代码路径。
已知限制
- 自动化测试是契约测试,不是实机验收。 它们用 mock,不碰你的真实会话。「已命名但未发出」的会话跨新 Host 进程是否恢复、卸载后原生列表是否立刻可见、不同缩放下浮层位置是否正确,都还需要在你的版本上验证。不要在正在工作的 profile 上强制退出做持久化测试。
- 把拖拽提升成引用用到了未公开的接口。 编辑器只把
text/plain当纯文本插入,而引用块只能由输入管线在"选中一个补全候选"时生成,所以插件在文本落位之后调用管线自己的pick来补上这一步。每一环都做了能力探测,任何一环对不上就退化成引用文本(也就是拖拽最初的行为);但 DSH 升级若改了这些内部字段,自动提升会失效——lib/client.js里标了ADAPTATION POINT注释,写明了依赖的确切字段,便于跟着适配。 - 选中一个文件夹需要一次 Host 查询。 资源树是分页懒加载的,而"选中父文件夹"必须覆盖它的全部子项,所以插件在点击时按需读一次该目录自身的层级(并翻完分页),而不是只看已经展开过的部分。目录特别大时这一次点击会稍慢。
- 菜单需要 Popover API。 浏览器不支持时,插件会给出明确错误提示,而不是显示一个位置错乱的菜单。
- 改源码不等于改了运行中的 Host。 在本仓库改文件不会更新正在运行的 DSH;Host 路由需要重启。
测试
无依赖、无需安装:
node test/run.mjs
# 或 npm test
运行器会找出所有 *.test.mjs 和 selftest.mjs,用同一个 Node 可执行文件依次跑完(当前 158 + 138 + 15)。覆盖范围:目录列举与分页、配置与迁移与各项上限、路由族与信任栅栏、路径命名空间与跨平台拼写、对话树模型、隐藏作用域与目标边界校验、引用文本与 @ 候选索引及排序、拖拽提升的每一条降级路径、工作状态折叠(子 agent 与 goal)、原生桥接的创建/重命名/保存契约。
设计文档
许可
MIT © 2026 Nethur-auro