按工作区隔离插件并诊断冲突,崩溃时可自救
30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Sum556677/dsh-workspace-orchestrator该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · market
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 15 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 插件编排与工作区隔离管理器:扫描插件、按工作区隔离实例,另带独立救援入口。
README
由 DeepSeek 最新模型翻译生成dsh-workspace-orchestrator
按工作区隔离插件、诊断冲突、并在 DSH 崩溃时自救。
DSH 插件编排与工作区隔离管理器:插件清单、冲突扫描、按工作区禁用插件(黑名单)、独立的多开隔离实例,以及一个完全不依赖 DSH 进程的急救工具。
安装
dsh plugin --profile desktop add dsh-workspace-orchestrator
装完托盘彻底退出 DSH 再启动(不是关窗口)。
三个核心能力
1. 工作区插件黑名单(设置 → 工作区编排)
插件默认全开——原生面板怎么开就怎么来。这个面板只负责局部禁用:
- 顶部下拉框自动读取 DSH 左侧栏的工作区列表
- 下方列出所有第三方插件,默认全部打勾
- 取消勾选 = 在这个工作区禁用该插件
- 切换工作区,勾选状态随之切换
写入 $DSH_HOME/workspace-orchestrator/single-mode.json:
{ "version": 2, "workspaces": { "D:/my-project": { "disabledPlugins": ["dsh-novel-writer"] } } }
真正生效在新建会话时:进入某工作区,黑名单里的插件被卸载,其余恢复。
离开该工作区会自动还原。
展开完整文档(README 剩余 1 节)
dsh-workspace-orchestrator
按工作区隔离插件、诊断冲突、并在 DSH 崩溃时自救。
DSH 插件编排与工作区隔离管理器:插件清单、冲突扫描、按工作区禁用插件(黑名单)、独立的多开隔离实例,以及一个完全不依赖 DSH 进程的急救工具。
安装
dsh plugin --profile desktop add dsh-workspace-orchestrator
装完托盘彻底退出 DSH 再启动(不是关窗口)。
三个核心能力
1. 工作区插件黑名单(设置 → 工作区编排)
插件默认全开——原生面板怎么开就怎么来。这个面板只负责局部禁用:
- 顶部下拉框自动读取 DSH 左侧栏的工作区列表
- 下方列出所有第三方插件,默认全部打勾
- 取消勾选 = 在这个工作区禁用该插件
- 切换工作区,勾选状态随之切换
写入 $DSH_HOME/workspace-orchestrator/single-mode.json:
{ "version": 2, "workspaces": { "D:/my-project": { "disabledPlugins": ["dsh-novel-writer"] } } }
真正生效在新建会话时:进入某工作区,黑名单里的插件被卸载,其余恢复。
离开该工作区会自动还原。
带界面的双端插件(如 dsh-webds-bridge)后端被卸载后,*页面上的入口要刷新(Ctrl+Shift+R)才消失——client 代码已经加载进浏览器了,后端管不到。
2. 隔离实例(多开)
面板里的「在此工作区开启隔离实例」,或对 Agent 说「在 D:\code 开一个隔离实例」。
独立 profile、独立会话与存储、OS 分配的端口。同样遵守该工作区的黑名单。
3. 急救工具
DSH 起不来时不依赖 DSH:
bin\rescue.bat --web :: 打开独立急救网页面板(127.0.0.1:8765)
bin\rescue.bat desktop --disable <插件id> :: 命令行禁用坏插件
急救面板可以列出插件、把插件可逆地移出 node_modules 并写入 disabled: true,也支持 bundle 插件(无文件夹可移时改为改配置)。所有改动先备份,可一键恢复。
Agent 工具
| 工具 | 用途 |
| scan_plugins | 列出当前 profile 的第三方插件 |
| scan_conflicts | 静态冲突扫描(重复 id / 重复包 / 重复 service / 循环依赖 / 缺依赖) |
| manage_workspace_scope | 读写工作区黑名单 |
| launch/list/stop_workspace_instance | 隔离实例的生死管理 |
| debug_single_mode | 诊断黑名单:报告每行的 fiber 是 ACTIVE 还是已卸载 |
直接说「调用 debug_single_mode」即可,它会给出结论,例如「dsh-webds-bridge:已禁用,fiber 已卸载 —— 单开模式工作正常」。
排障
插件禁用了还在跑? 调用 debug_single_mode 看 fiber 列:
- NONE = 后端已卸载,你看到的是前端残留 → 刷新页面
- ACTIVE = 没禁用成功 → 看下面的调试日志
开调试日志(默认关闭):
方式一:环境变量后重启 setx DSH_ORCH_DEBUG 1
方式二:运行时开启(立即生效) curl.exe -X POST -H "content-type: application/json" -d "" "http://127.0.0.1:<端口>/workspace-orchestrator/api/scope/debug"
日志写入 $DSH_HOME/workspace-orchestrator/debug.log,含实际 cwd、pathKey、匹配到的黑名单、每行的 fiber 前后状态。
离线自测
node lib/orchestrator-core/verify-context-access.mjs
node lib/orchestrator-core/verify-rescue-web.mjs --home D:\tmp\dsh-test
node lib/orchestrator-core/verify-scope-rpc.mjs --home D:\tmp\dsh-test
node lib/orchestrator-core/verify-blacklist.mjs --home D:\tmp\dsh-test
共 158 项检查,拒绝在真实 ~/.dsh 上运行。
兼容性
| 项 | 值 |
| DSH 运行时 | 0.2.1-rc.2(本版本实测) |
| Node | >= 22.19.0 |
| 前端 | DSH Web / 桌面端共用同一套设置面板 |
| 平台 | Windows 优先(路径规范化、急救 .bat);其余平台未实测 |
设计约束
- 零第三方依赖,零 @deepseek-ai/ import——框架能力只通过 ctx 获取
- apply() 永不抛错:任何失败都记录并降级,插件不会是 profile 启动失败的原因
- 绝不写回 profile patch(除急救工具的显式动作):黑名单只改内存与自己的映射文件
目前已有的内容
| 部分 | 状态 |
| Bundle patch cordis.patch.yml,插入 loader 行 dsh-workspace-orchestrator | 已完成 |
| apply(ctx) —— 注册七个工具,零抛错 IO,绝不让启动失败 | 已完成 |
| scan_plugins —— 第三方插件清单 + 实时隔离实例摘要 | 已完成 |
| launch_workspace_instance — 一次性配置档,隔离会话与存储,端口由操作系统分配 | 完成 |
| list_workspace_instances — 注册表 + 进程/端口存活检查 | 完成 |
| stop_workspace_instance — 按 pid / 配置档名 / 工作区路径停止 | 完成 |
| lib/orchestrator-core/ — 配置档与补丁编排、实例注册表、救援模式 | 完成 |
| bin/rescue.mjs + bin/rescue.bat — 独立救援(无需 DSH 进程) | 完成 |
| bin/rescue.mjs --web — 独立救援 web 面板,支持可逆的禁用/恢复 | 完成 |
| Bundle 级救援(dsh.profile.bundles):仅禁用 / 彻底移除 / 恢复 | 完成 |
| 工作区黑名单(设置面板 + manage_workspace_scope) | 完成 |
| 冲突扫描(lib/conflict-scan.mjs、scan_conflicts 工具 + 设置面板) | 完成 |
| debug_single_mode — 实时 fiber 状态诊断 | 完成 |
| 版本回滚 | 尚未 |
实例相关的代码全部放在 lib/orchestrator-core/;工具只是薄桥接层,负责转换参数、渲染结果,所以同一行为只有一份实现。
兼容性
| 项目 | 值 |
| DSH 运行时验证版本 | 0.2.0-rc.2(桌面应用构建 04f392c9ddd144fa426da2045178797da6db6c11) |
| Electron / Node 宿主 | Electron 44.0.0,Node 24.18.1 |
| @deepseek-ai/cordis | 4.0.4 |
| package.json 中声明 | dsh.compatibleRuntime: "0.2.0-rc.2" |
工程约定
- 不 import @deepseek-ai/。 框架能力通过 ctx 获取(ctx.tools、ctx.logger)。工具以普通定义对象注册,不需要 defineTool;lib/patch-yaml.js 和 lib/profile.js 不依赖任何包,只 import node: 内置模块。
- apply(ctx) 从不抛异常,也不做 IO。 它注册一个工具就返回。每条失败路径都记日志并降级。扫描在 execute 里进行。
- 不加 HTTP 路由。 将来加的话会用 /plugin-orchestrator/ 前缀,冲突时降级。
- 入口 id 唯一。 dsh-workspace-orchestrator;工具名 scan_plugins 同样唯一(注册表会拒绝重复,已验证)。
- 只读。 阶段 1 不向任何地方写入。
scan_plugins
按顺序读取:
1. <profile>/package.json → dsh.profile.bundles(有序的 bundle 选择)和 dependencies(实际安装的内容)。
2. <profile>/cordis.patch.yml → 用户的补丁层:insert 行添加加载器条目,按 id 定位的行覆盖或禁用它们。
3. ctx.get('pluginManager') → 可选。官方管理器服务挂载后,它提供运行时版本和每个 bundle 的加载状态。服务不存在时,相关字段降级为 null,绝不报错。
按第三方插件返回:加载器条目 id、包 name、version、生效的 enabled,以及产生该条目的 source 行(bundle / patch-insert / dependency / patch-override)。@deepseek-ai/ 下的 bundle 会被过滤掉,只做计数。
配置档目录
从宿主进程内部找到当前生效的配置档,才是微妙的地方。DSH_PROFILE_DIR 和 DSH_PROFILE 只注入到工具子进程的环境里,宿主里可能没有,所以它们只是第一猜测。候选按顺序尝试(env:DSH_PROFILE_DIR → 启动器自己的 --profile / 位置参数 argv → hmr.baseDir → env:DSH_PROFILE → 从本模块向上查找),每个候选都要做结构校验:真正的配置档目录里有 package.json,且带 dsh.profile 字段。解析不出来的配置档会如实报告,而不是猜一个。
安装
Desktop 配置档归 Electron 应用所有,所以命令行拒绝启动它,也拒绝 --dump-config 它;不过插件安装是支持的:
dsh plugin --profile <name> add dsh-workspace-orchestrator
其他配置档,把包列进 dsh.profile.bundles(或者把 cordis.patch.yml 当作 --patch 覆盖层加载):
dsh --profile <name> --patch <this-dir>/cordis.patch.yml
目录结构
index.js apply(ctx), the scan_plugins definition, and its renderer
lib/profile.js profile-directory discovery and structural validation
lib/patch-yaml.js dependency-free reader for cordis.patch.yml
lib/scan.js the inventory: sources, resolution, merge, report
cordis.patch.yml bundle patch inserting the loader row
已知限制
lib/patch-yaml.js 不是通用 YAML 解析器。它只读补丁层的那一种形状,并且整块跳过 config:(一行的 config 是任意部署数据——desktop 配置档的 llm-pi-ai 行里就有一份约 230 行的嵌套服务商映射)。流式集合、块标量、锚点/别名和多文档文件都会报成诊断信息,而不是悄悄读错。
六个工具与极简用法
| 工具 | 一句话 | 自然语言示例 |
| scan_plugins | 列出当前配置档的第三方插件 + 已开实例 | 「看看我现在装了哪些第三方插件?」 |
| scan_conflicts | 静态冲突扫描(重复 id / 重复包 / 重复 service / 环 / 缺依赖) | 「扫一下当前配置档有没有插件冲突。」 |
| manage_workspace_scope | 读写「工作区 → 禁用黑名单」 | 「在 D:\novels 禁用 dsh-novel-writer。」 |
| launch_workspace_instance | 为工作区拉起隔离实例,返回 URL | 「在 D:\code 开一个隔离实例。」 |
| list_workspace_instances | 列出本管理器拉起的实例并探活 | 「现在开着几个隔离实例?」 |
| stop_workspace_instance | 按 pid / 配置档 / 工作区关闭实例 | 「把刚才那个实例关掉。」 |
| debug_single_mode | 诊断黑名单:每行 fiber 是 ACTIVE 还是已卸载 | 「调用 debug_single_mode」 |
三条典型用法
1. 多开隔离:说「在 D:\code 开一个隔离实例」→ 智能体调 launch_workspace_instance,返回带 token 的 URL;用完说「关掉」→ stop_workspace_instance。
2. 单开黑名单:在面板取消勾选,或说「在 D:\novels 禁用 X」→ manage_workspace_scope(包名自动反查行 id;有歧义会停下来问你)。
3. 急救:DSH 起不来时不依赖 DSH,直接双击 bin/rescue.bat(或 node bin/rescue.mjs)→ 进救援实例看历史 → rescue.bat desktop --disable <插件id> 一键禁用坏插件并自动备份。
完全不想开实例时用 bin/rescue.bat --web(或 node bin/rescue.mjs --web):起一个独立于 DSH 的网页面板(127.0.0.1:8765,占用则随机端口),看冲突告警、第三方插件清单,并对插件做可逆隔离/恢复——见下节。
急救网页(--web,P3)
bin\rescue.bat --web :: 自动选 profile(优先 desktop),默认 127.0.0.1:8765
bin\rescue.bat --web web --port 9000 :: 指定 profile 和端口
bin\rescue.bat --web --no-open :: 不自动打开浏览器
node bin\rescue.mjs --web :: 有 node 时等价
- rescue.bat 怎么选运行时:优先用 DSH 自带的 Electron(ELECTRON_RUN_AS_NODE=1,无需装 Node)→ 其次 $DSH_HOME/dsh-runtimes//dependencies/node/bin/node.exe → 最后 PATH 里的 node。找不到运行时会在窗口里停留并提示(不会一闪而过)。
- rescue.bat 交互:不带参数双击 → 列出 profile 让输入编号或名字;指定了 --web → 不起救援实例,只开网页;出错时窗口会 pause 保留报错,成功退出不打扰。
- 通信:纯 node:http + 内联 HTML/CSS/JS,无外链 CDN。不启动 DSH、不碰会话数据,只读写 $DSH_HOME/profiles/<profile> 与 $DSH_HOME/workspace-orchestrator/disabled/。接口需页面内嵌的随机 token(x-rescue-token),无 token 一律 403。
页面三块
| 区块 | 内容 |
| 冲突告警 | 静态扫描结果,红色 = error,黄色 = warning / 降级说明 |
| 插件列表 | 第三方插件(含 bundle),状态 + 位置 + 操作按钮 |
| 已隔离备份 | 每次禁用都会留记录,可一键恢复 |
两种插件的禁用方式不同(关键)
| 类型 | 识别方式 | 禁用动作 | 恢复 |
| package | 装在 node_modules | 文件夹移动到 workspace-orchestrator/disabled/<pkg>@<ver>/payload,并追加 disabled: true 行 | 文件夹移回 + 摘除追加行 |
| bundle | profile package.json → dsh.profile.bundles | 没有文件夹可移,只改配置:按该 bundle 自己 cordis.patch.yml 里的真实入口 id(不是包名)逐个追加 disabled: true | 摘除追加行;若当时「彻底移除」过,再从备份还原 manifest 条目 |
- bundle 两个按钮:「仅禁用」只写 patch;「彻底移除」额外把包名从 dsh.profile.bundles 和 dependencies 一并删掉(防止下次 pnpm install 又装回来),两个文件都先备份。
- 为什么禁用行能生效:补丁按顺序应用,后置的同 id 行覆盖前置行(dsh-app-boot 的 applyEntryPatches 语义),所以文件末尾追加的 - id: <入口 id> + disabled: true 一定会盖掉 bundle 自己的 - insert: 行。
- id 是猜的会明说:如果 bundle 没有安装目录或没声明 dsh.bundle.patch,读不到真实入口 id,页面会标黄提示「暂用包名」,不会假装成功。
- 所有写文件动作都先备份(cordis.patch.yml.bak-<ts> / package.json.bak-<ts>),同一毫秒多次改也不会互相覆盖。
- 安全边界:包名与隔离目录名做路径校验;quarantine.json 里的原路径必须仍在本 home 的 profiles/ 内,否则拒绝移动。
- 离线自测:node lib/orchestrator-core/verify-rescue-web.mjs --home D:\tmp\dsh-test(68 项检查,覆盖两种插件的完整闭环;拒绝在真实 ~/.dsh 上运行)。
其他已知边界
- 静态扫描只看 profile node_modules:官方 bundle 在 app.asar 内读不到源码;覆盖率 <50% 时不报"缺失依赖",只留 low-coverage 提示。
- 双模安全防线:单开模式只翻内存里的 disabled(不写盘),并发工作区出现即冻结并告警;真正要隔离请用多开模式。多开实例在 Windows 上随宿主进程退出而终止。
Release 0.1.0 — release notes
首次发布。包含:插件清单与冲突扫描、按工作区隔离的多开实例、单开轻量切换、以及完全独立于 DSH 进程的急救 CLI + 急救网页。
新增
- 急救网页 rescue --web:冲突告警 / 第三方插件清单 / 可逆隔离恢复,全部离线、无 CDN、带 token 鉴权。
- bundle 级急救:dsh.profile.bundles 加载的插件现在也能被列出并禁用(「仅禁用」写 patch 行;「彻底移除」同时清 manifest 的 bundles 与 dependencies),两者都可恢复。
- bin/rescue.mjs --web 自动选 profile、端口被占用自动换随机端口、DSH_RESCUE_NO_OPEN 可禁止自动开浏览器。
修复(本轮)
- 急救面板此前对 bundle 插件完全不可见——dsh.profile.bundles 加载的坏插件无法处理,等于急救失败。
- 嵌套 - insert:(含双层)里的插件行此前识别不到,隔离时会把文件夹移走却不写禁用行,插件实际仍会加载。
- 隔离期间用户改过 patch 后,恢复会静默失败留下孤儿禁用行;现在会按记录精确清理,清理不了就明确扣警。
- 同一毫秒多次改 patch 会覆盖彼此的备份;现已去重。
- 「彻底移除」的校验改到写文件之前,失败时不再留下半改状态。
已知限制
- bundle 若既无安装目录又无 dsh.bundle.patch,真实入口 id 读不到,只能用包名兜底(页面会标黄)。
- 官方 @deepseek-ai/ 插件一律不列出、不可禁用。
- 版本回滚尚未实现。
设置面板:以工作区为中心的插件黑名单(0.3.0)设置 → 工作区编排。视角是「先选工作区,再勾插件」,而勾选的含义是黑名单:插件默认全开(原生 profile 怎么说就怎么来),取消勾选 = 在这个工作区禁用。
0.2.0 是白名单语义(勾选=启用)。原生面板一旦"全开",白名单就完全失效——这正是 0.3.0 反转的原因。
1. 工作区下拉框:自动读取 DSH 左侧栏的工作区列表,选项显示标题(如 DSH_web、DSH_plugin)并附带已禁用数量。
数据源是 $DSH_HOME/storages/workspace.json(DSH 的 workspace 存储单元,domain workspace v2): global.workspaceIds 决定显示顺序,tables.workspaces[<id>] 提供 path / title。只读,不写这个文件。
2. 手动输入:点「手动输入」可填一个 DSH 里还没建过的目录。
下拉框里也会出现「仅绑定,不在侧栏」的条目——映射文件里有、但侧栏已删掉的工作区,保证旧条目不被藏起来。
3. 插件勾选:列出当前 profile 的第三方插件。默认全部打勾(= 全启用);取消勾选会把该插件加入当前工作区的禁用黑名单,提示「xxx 已加入当前工作区的禁用黑名单」。
每次只增删一个 row id(POST /scope/toggle),不会整体覆盖,避免和 Agent 并发改同一条时互相吃掉。
4. 在此工作区开启隔离实例:多开模式按钮。拉起的子 profile 会把黑名单写成 disabled: true 覆盖层。
写入 $DSH_HOME/workspace-orchestrator/single-mode.json(v2): json { "version": 2,
"workspaces": {
"D:/Agent_workspaces/DSH_plugin": { "disabledPlugins": ["dsh-novel-writer"] }
}
}
没有条目的工作区 = 什么都没禁用 = 全部启用。
运行时怎么执行黑名单
进入工作区(session/created)时,对「任一工作区黑名单里出现过的 id ∪ 当前工作区黑名单」逐行执行:
- 在当前工作区黑名单里 → entry.update({ disabled: true })
- 不在 → entry.update({ disabled: false })(恢复)
"恢复非黑名单行"是关键:即使你在原生面板把某插件打开了,只要进入禁止它的工作区,它照样被卸掉;离开该工作区又会自动恢复。本进程曾经关掉过的行(blacklistedNow)即便映射文件之后被清空,切换工作区时也会被还原。
从没被任何工作区列入黑名单的行,单开模式完全不碰,保持原生状态。
多开隔离实例
prepare() 接受 blacklist,写进 orchestrator.overlay.yml:
yaml
workspace blacklist (from single-mode.json)
- id: dsh-novel-writer
disabled: true
补丁后置覆盖前置,所以黑名单在子进程里同样生效。id 里若含 YAML 特殊字符会被加引号,无法借 id 注入额外行。
shareData: true(急救)时忽略黑名单——救援必须拿到原始状态。
Agent 语义对齐
manage_workspace_scope 的描述已改为黑名单口径:「在 D:\novels 禁用插件 X」= action="set" + workspacePath + pluginRowIds,这些 id 表示该工作区禁用的行。action="remove" 删除整个工作区条目 = 恢复全启用。
边界(必须知道)
- 黑名单只记录意图,不改磁盘上的 disabled。真正的启停在新会话建立时执行;当前已开着的会话不会立即改变。
- 面板「运行状态」列显示当前进程里的真实启停,和勾选状态不同步是正常的。
- 没有 loader 行 id 的插件(部分 bundle 加载的行)勾选框是灰的,无法加入黑名单。
- 旧版(v1 白名单)文件:白名单无法无损转成黑名单(不知道哪些是"用户没勾"),所以按空黑名单处理并在面板顶部提示「检测到旧版白名单格式」。需要限制的话重新取消勾选即可——绝不静默猜一个可能是错的禁用集合。
- workspace.json 损坏或不存在时,面板照常渲染,下拉框为空并提示原因,可改用「手动输入」。
工具注册约定(踩坑踩出来的)
- inject: ['tools'] 是必须的。 Cordis 4 对服务访问设了门禁:在
apply() 里读 ctx.tools 却没声明它,会抛 cannot get property "tools" without inject。直接
execute() 的测试台从不走 apply(),所以这个问题只在真实会话里才暴露。
- register() 只校验 output,从不校验 parameters。 参数 schema 写错,要到模型调用时才失败,注册时不会报——在测试台里自己校验。
- 长驻实例就绪后必须 detach(detachInstance):管道式 stdio 是我们读到 URL 的前提,但这些管道会让宿主事件循环一直活着,宿主就永远退不出去。在 Windows 上实例仍会随宿主进程一起死(job-object 语义);要让实例保持存活,就需要一个长期运行的宿主(GUI 或 bin/rescue.mjs)。
单开轻量模式(乙)与自然语言配置
在同一个 DSH 进程内,按当前会话的工作区动态启停插件行,不重启、不写盘。
这是「尽力而为」的便利档,不提供隔离保证;并行多工作区请用多开模式。
用自然语言配置
插件行 id 来自 scan_plugins,绑定关系由 manage_workspace_scope 写入。
所以直接对智能体说:
「先 scan_plugins 看看有哪些第三方插件,然后把网文那几个插件绑定到 D:\novels,把代码插件绑定到 D:\code。」
智能体会依次调用 scan_plugins → manage_workspace_scope,写入: json { "version": 1,
"workspaces": {
"D:/novels": ["novel-writer"],
"D:/code": ["webds-bridge-client"]
}
}
保存在 $DSH_HOME/workspace-orchestrator/single-mode.json。也可以直接问「现在的工作区绑定是怎样的?」(action: "list"),或「把 D:\novels 的绑定删掉」(action: "remove")。
没写进这张表的行永远不会被单开模式碰。 这是刻意的:不猜测「哪个插件属于哪个工作区」。
绑定既可以用行 id,也可以直接给包名(pluginNames)——工具会用 live loader 树把包名反查成行 id。
包名找不到或不唯一时不写入,返回 UNKNOWN names / AMBIGUOUS,让智能体去问用户确认。
静态冲突扫描(scan_conflicts)
对当前配置档(或 profile 参数指定的)做纯静态检查,不执行任何插件代码:
| 级别 | 检查项 |
| error | duplicate-entry-id 同一 loader 行 id 出现多次 |
| error | duplicate-plugin-name 同一个第三方包被插入成多条行(官方包多实例是常态,不报) |
| error | duplicate-service 两个插件 provide 同名 service |
| error | dependency-cycle service 依赖成环 |
| warning | missing-dependency inject 的 service 无人提供 |
数据来源:dsh <profile> --dump-config(desktop 被命令行拒绝,退化为只扫它自己的补丁层,并给出 patch-only 提示)。
依赖边来自插件源码文本里的 static inject = [...]、super(ctx, "svc")、provide("svc")。
已知边界(会写进 notes,不猜):
- 重复 tool 名无法静态得知(注册调用是运行时实参)→ 永远给 tool-names-unknown 提示。
- 只有装在配置档 node_modules 里的插件能读到源码;官方 bundle 在 app.asar 内。
覆盖率 < 50% 时不报告「缺失依赖」(无法区分真缺与读不到),改给 low-coverage 提示。
三条安全防线
| 防线 | 做法 |
| 绝不写回磁盘 | 只调 entry.update({ disabled });从不调用 loader.write/create/remove/update |
| 不碰 config | 只翻 disabled;改 config 会经 internal/update 触发 tree.write() |
| 并发冻结 | sessions.list() 出现 >1 个 distinct cwd 时立即冻结并告警,之后不再切换 |
发生产生切换时,日志里能看到 [single-mode] 检测到并发工作区(N 个)…。
实测(真实 DSH 进程)
_research/verify-single-e2e.mjs 用一次性配置档 + 两个探针插件跑两次:
run A (cwd=D:/ws/e2e-a): probe-a mounted probe-b mounted → probe-b unmounted
run B (cwd=D:/ws/e2e-b): probe-a mounted probe-b mounted → probe-a unmounted
映射文件哈希前后一致(零写回),未误触发冻结。
ctx.get('loader') 与 ctx.get('sessions') 在真实进程里不需要 inject(二者是运行时查找,不是服务属性访问)。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Sum556677/dsh-workspace-orchestrator
按工作区隔离插件并诊断冲突,崩溃时可自救
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,025未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,358已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13938 个插件含 PR 收录与…
★ 350已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7
这是你的仓库?认领条目