多根工作区浏览器 Nethur-auro/dsh-multi-root-explorer
DeepSeek Harnessv0.1.8dsh-multi-root-explorer工作区资源管理器
30.8/100
综合分
1
GitHub 星标
261
npm 周下载
—/5
用户评分
数据截至 2026/10/10 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-multi-root-explorernpm 源 · dsh-multi-root-explorer 的发布者账号已校验与本仓库一致
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · browser
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 25 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-multi-root-explorer @ 0.1.8
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 21:23:08
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 34 处,展示前 32 条)
- 发起网络请求lib/client.js:409
response = await fetch(url, { credentials: 'same-origin', ...options }) - 发起网络请求lib/client.js:455
response = await fetch('open-in-app/open', { - 写入剪贴板lib/client.js:1664
await navigator.clipboard.writeText(path) - 读取本地文件lib/host/store.js:208
const text = await readFile(this.#file, 'utf8') - 写入本地文件lib/host/store.js:222
await writeFile(backup, text, { encoding: 'utf8', flag: 'wx' }) - 写入本地文件lib/host/store.js:228
await writeFile(backup, text, { encoding: 'utf8', flag: 'wx' }) - 写入本地文件lib/host/store.js:290
await mkdir(dir, { recursive: true }) - 写入本地文件lib/host/store.js:292
await writeFile(temporary, `${JSON.stringify(config, null, 2)}\n`, 'utf8') - 写入本地文件lib/host/store.js:293
await rename(temporary, this.#file) - 读取本地文件lib/host/store.js:305
const info = await stat(root.path) - 读取本地文件lib/host/routes.js:241
try { realRoot = canonical(await realpath(root.path)) } catch { realRoot = canonical(root.path) } - 读取本地文件lib/host/routes.js:245
try { if (!(await stat(lookup)).isDirectory()) throw new ExplorerError('not-a-directory', 'conversation hidden path must be a directory') } catch (err - 读取本地文件lib/host/routes.js:256
const resolved = canonical(await realpath(current)) - 读取本地文件lib/host/routes.js:285
const resolved = canonical(await realpath(candidate)) - 读取本地文件lib/host/routes.js:372
path = canonical(await realpath(input)) - 读取本地文件lib/host/routes.js:373
if (!(await stat(path)).isDirectory()) throw new ExplorerError('not-a-directory', 'root must be a directory') - 读取本地文件lib/host/sessions.js:52
return (await stat(path)).isDirectory() - 读取本地文件lib/host/sessions.js:73
projects = await readdir(root, { withFileTypes: true }) - 删除本地文件递归lib/host/sessions.js:95
await rm(candidate, { recursive: true, force: true }) - 删除本地文件lib/host/sessions.js:103
await rm(candidate, { force: true }) - 读取本地文件lib/host/native-bridge.js:20
const resolved = await realpath(path) - 读取本地文件lib/host/native-bridge.js:21
if (!(await stat(resolved)).isDirectory()) fail('not-directory', 'The target is not a directory') - 读取本地文件lib/host/native-bridge.js:58
const data = JSON.parse(await readFile(this.file, 'utf8')) - 写入本地文件lib/host/native-bridge.js:67
await mkdir(dirname(this.file), { recursive: true }) - 写入本地文件lib/host/native-bridge.js:72
await rename(temp, this.file) - 读取本地文件lib/host/listing.js:22
const realRoot = canonical(await realpath(root)) - 读取本地文件lib/host/listing.js:28
resolved = canonical(await realpath(lexical)) - 读取本地文件lib/host/listing.js:33
if (!(await stat(requested)).isDirectory()) throw new ExplorerError('not-a-directory', `not a directory: ${requested}`) - 读取本地文件lib/host/listing.js:41
try { records = await readdir(requested, { withFileTypes: true }) } catch (error) { throw filesystemError(error, requested) } - 读取本地文件lib/host/listing.js:50
const destination = canonical(await realpath(path)) - 读取本地文件lib/host/listing.js:52
const info = await stat(path) - 读取本地文件lib/host/search.js:225
children = await readdir(relative === '' ? root : `${root}/${relative}`, { withFileTypes: true })
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 侧边栏多根会话树
- 只读资源浏览
DeepSeek Harness 工作区浏览器:侧边栏里多根会话树加只读资源浏览。
最近更新
在 GitHub 查看全部 →v0.1.82026-10-09
· 0.1.8
· 资源树自动跟上磁盘。 已加载的目录层每隔几秒用 Host 的目录版本号探测一次,只有真的变了才重新取那一层,并且在已翻到的深度内重取,手工翻出来的分页不会被收回。
· 新会话交给 DSH 命名。 在文件夹里新建会话时不再预先写死标题,标题留给 DSH 自己的标题器,按你发的第一条消息命名。
· 修复重命名输入框。 之前每敲一个字都会被全选替换,最后只剩最后一个字;现在打开时全选一次,输入过程中不再打断。
v0.1.72026-10-05
· 修复
面板右上角那三个控件(眼睛 / 刷新 / 设置)贴着面板右边缘,装了描边类主题插件时会被压住。
那行的样式只有左内边距、右边是 0,而控件靠 margin-left:auto 顶到最右侧,所以正好落在边缘上。现在这行的右内边距和下面那行选项卡一致(8px),控件随之左移 8px,与选项卡的右边缘对齐,同时也给主题插件的边距让出了位置。
只有装了描边/边框类皮肤才看得出来;不装皮肤时几乎无感(只是控件与下方选项卡对齐了)。
如果还差一点,说一句"再多一点/少一点"即可 —— 这是一行的改动。
v0.1.62026-10-05
· 修复
在文字后面拖拽不会变成引用块(报 no-menu,只留下一段 @路径 文本)
拖拽写进编辑器的文本是原样插入的。当落点紧贴前一个词(变成 文字@路径)时,DSH 补全管线的 token 边界规则不认为这是 token —— 菜单根本不会打开,也就无从提升成引用块。表现就是那句「拖拽引用未自动转换,原因:no-menu」;而只要前面加一个空格就正常。
现在拖拽载荷里的纯文本自带一个前导分隔空格,所以无论在什么位置落下,这段 mention 都是可识别的 token,能正常提升为引用块。
词表里登记的仍是不带空格的干净 mention(管线读的是它自己跟踪到的 token,不含分隔符),所以已有的补全与着色行为不受影响 —— 有一条既有测试正好在守这一点。
唯一的代价:如果把文件拖到一个空草稿的最前面,会留下一个前导空格。它无害,在 Markdown 里也不影响渲染。
· 升级建议
建议升级 —— 这是可见的功能缺陷。GitHub 的安装链接永远指向最新发布版,无需改任何东西。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。
README
由 DeepSeek 最新模型翻译生成dsh-multi-root-explorer(工作区资源管理器)
给 DeepSeek Harness 用的工作区浏览器:它接管左侧栏的工作区区域,换成两个选项卡——对话按每个会话真实的工作目录归入目录树,资源是一个只读的文件树,点文件用 DSH 原生右侧栏预览。
插件在侧边栏里的样子:已登记的工作区展开为带会话数量的文件夹,上方是「对话 / 资源」选项卡,以及小眼睛、刷新和设置按钮(目录名与会话标题已打码)
状态:预览版。 自动化测试全部通过,但尚未在所有 DSH 版本上做完整实机验收。安装前请先看已知限制。
它能做什么
- 固定多根目录。 你导入的目录就是根,不会随着会话增减被重算成某个公共祖先。
- 会话变成目录树。 每个会话按它真实的 cwd 归位:当前目录的直接会话排在前面,子文件夹排在后面,逐层递归。cwd 在根目录之外的历史会话保留独立入口;没有 cwd 的会话单独一组。
- 资源只读浏览。 目录按层加载并分页,打开一个大盘不会先递归扫全盘。点文件交给 DSH 自己的右侧栏预览,主栏对话不受影响。
- 资源树自己跟上磁盘。 已加载的目录层每隔几秒拿一次 Host 的目录版本号做探测,只有真的变了才重新取那一层,而且在已经翻到的深度内重取——手工翻出来的分页不会被收回去。探测是逐个分片轮着来的,目录再多也不会一次打满。
展开完整文档(README 剩余 1 节)
dsh-multi-root-explorer(工作区资源管理器)
给 DeepSeek Harness 用的工作区浏览器:它接管左侧栏的工作区区域,换成两个选项卡——对话按每个会话真实的工作目录归入目录树,资源是一个只读的文件树,点文件用 DSH 原生右侧栏预览。
插件在侧边栏里的样子:已登记的工作区展开为带会话数量的文件夹,上方是「对话 / 资源」选项卡,以及小眼睛、刷新和设置按钮(目录名与会话标题已打码)
状态:预览版。 自动化测试全部通过,但尚未在所有 DSH 版本上做完整实机验收。安装前请先看已知限制。
它能做什么
- 固定多根目录。 你导入的目录就是根,不会随着会话增减被重算成某个公共祖先。
- 会话变成目录树。 每个会话按它真实的 cwd 归位:当前目录的直接会话排在前面,子文件夹排在后面,逐层递归。cwd 在根目录之外的历史会话保留独立入口;没有 cwd 的会话单独一组。
- 资源只读浏览。 目录按层加载并分页,打开一个大盘不会先递归扫全盘。点文件交给 DSH 自己的右侧栏预览,主栏对话不受影响。
- 资源树自己跟上磁盘。 已加载的目录层每隔几秒拿一次 Host 的目录版本号做探测,只有真的变了才重新取那一层,而且在已经翻到的深度内重取——手工翻出来的分页不会被收回去。探测是逐个分片轮着来的,目录再多也不会一次打满。
- 两个选项卡各自独立的隐藏,且完全可逆。 点标题栏的小眼睛进入选择模式:已隐藏的项会显示出来并处于选中状态。点一个未选中的文件夹=选中它(整个子树随之显示为选中);点一个"被父目录覆盖"的子项=把它单独排除,祖先展开成同级项、其余保持选中;单击已选中的文件夹=它连同子树一起取消;双击已选中的文件夹=父目录取消、全部子项保持选中,提交后就是一个空文件夹。选中的后代按需向 Host 查询该目录自身的层级,所以没展开过的子文件夹同样会被覆盖。再点一次小眼睛就只隐藏最终选中的那些;隐藏只影响显示,不动任何文件、目录或会话记录。
- 每个文件夹都有操作菜单。 右键或右端 ··· 可以在该目录里开启新会话、在系统资源管理器中打开;资源还支持复制绝对路径。新会话不预先命名:标题留给 DSH 自己的标题器,按你发的第一条消息命名。
- 拖进输入框就是原生引用。 资源行是标准拖拽源(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.8"
},
"dsh": {
"profile": {
"bundles": ["dsh-multi-root-explorer"]
}
}
}
然后在该目录里 pnpm install,再重启 DSH。手动做和插件管理器做的是同一件事,所以除非有特别理由,优先用方式 1 或 2。
怎么确认装上了
看左侧栏:工作区区域应该出现对话 / Conversations和资源 / Resources两个选项卡,并且有插件自己的标题栏。如果看起来没变化,说明 Host 还没加载新代码——重启 DSH,而不是只刷新页面,Host 路由不支持热重载。
使用
1. 点「添加工作区」选目录,需要几个根就加几个。
2. 「对话」页显示文件夹和会话;「资源」页显示文件夹和文件。目录第一次展开时才加载该层。
3. 点文件用右侧栏预览。预览需要一个可用会话作为授权上下文。
4. 文件夹右键或 ···:在该目录开启新会话、在系统资源管理器中打开、(资源)复制路径。
5. 会话右键:打开、重命名、归档、永久删除。永久删除有风险,见安全与永久删除。
6. 用小眼睛按选项卡隐藏条目;被你隐藏的东西都能在设置里恢复显示。
7. 「显示隐藏项」额外显示点开头的名字、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 可执行文件依次跑完(当前 160 + 172 + 16)。覆盖范围:目录列举与分页、配置与迁移与各项上限、路由族与信任栅栏、路径命名空间与跨平台拼写、对话树模型、隐藏作用域与目标边界校验、引用文本与 @ 候选索引及排序、拖拽提升的每一条降级路径、工作状态折叠(子 agent 与 goal)、资源层的新旧比对、原生桥接的创建/重命名/保存契约。
设计文档
- 缺陷修复方案与验收矩阵
- 树顺序与分栏独立隐藏设计
许可
MIT © 2026 Nethur-auro预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Nethur-auro/dsh-multi-root-explorer
dsh-multi-root-explorer工作区资源管理器
相关插件 · 浏览器
智能体插件框架deepseek-ai/deepseek-harness
DeepSeek Harnessdsh是由 DeepSeek AI 开发的开源 agent harness智能体框架。
★ 270,422已汉化DSH
71.9
多设备 Agent 看板YaoApp/yao
✨ 所有 Agent 和工作区集中管理,覆盖你的每一台设备。任务看板追踪进度,桌面端、移动端、浏览器、API…
★ 8,147已汉化DSH
71.2
可扩展侧边栏工作台omdsh-dev/DSH-better-sidebar
DSH 的双工作台:原生右侧栏 + 自绘底部面板,并把 ctx.betterSidebar 服务开放给所有插件
★ 4,761已汉化DSH
71.1
浏览器自动化桥Tencent/BrowserSkill
你的 Agent。你的浏览器。连接,就能协作。
★ 9,967已汉化DSH
71
AI 小说创作工作台EthanYoQ/AI-Novel-Writer
AI 小说作家 / AI Novel Writer
★ 1,591已汉化DSH
70.7
智能体浏览器引擎platonai/Browser4
DeepSeek Harness 集成
★ 1,175已汉化DSH
70.4
这是你的仓库?认领条目