# dsh-workspace-switch [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的**按工作区启用控制**: 每个工作区自行决定它的会话能用哪些**插件**、**MCP 服务器**与 **Skills**, 并通过工作区行菜单里的弹窗来配置。 [English](README.md) | 中文 ## 它做什么 一个插件,两半: - **宿主半**(`index.js`,构建到 `lib/index.js`)在该工作区创建 Agent 时读取该工作区的配置, 并把配置应用到这个 Agent 自己的 Cordis 作用域,因此同一进程里两个工作区的两个 Agent 看到的能力可以不同: - 被禁用的 **skill** 会在该作用域被一个同名、不可调用的注册遮蔽,从模型的 skill 目录里消失; - 被禁用的 **MCP 服务器**,其 `mcp____*` 工具在该作用域被拒绝; - 被禁用的 **插件**,其条目里声明的工具名在该作用域被拒绝。 同一半还提供弹窗使用的配置路由。 - **浏览器半**(`src/client/`,构建到 `lib/client.js`)在工作区行的 `...` 菜单里加一项, 打开弹窗列出当前组合在各分类下提供的能力,每项一个开关。 没有任何条目的工作区完全继承部署原有的组合,因此在有人配置之前这个插件不改变任何行为。 ## 配置 两个来源描述同一个工作区,后者优先: 1. `/workspace-switch.json`,其 `workspaces` 映射以工作区目录为键; 2. `/.dsh/workspace-switch.json`,存在时整体替换该工作区的共享条目。 ```json { "workspaces": { "E:\\my_project\\godot-game": { "plugins": { "mcp-godot-ai": { "enabled": false, "tools": ["mcp__godot-ai__run"] } }, "mcp": { "godot-ai": { "enabled": false } }, "skills": { "godot-scene-authoring": { "enabled": false } } } } } ``` `enabled: false` 表示在该工作区关闭;缺省即启用。插件条目还要声明该插件注册的**工具名**—— 门禁是按名字拒绝工具的,所以没有 `tools` 的插件条目没有可拒绝的东西。 弹窗写入当前对该工作区生效的那份文档:存在项目文件时写项目文件,否则写共享配置。 写入通过临时文件重命名发布,读方不会看到写了一半的文档。 ## 安装 这是一个 DSH bundle:把它加进 profile 并选中。 ```sh dsh plugin add link:/path/to/dsh_workspace_switch ``` 然后把 `dsh-workspace-switch` 加入该 profile 的 `dsh.profile.bundles`。新的 bundle 行在下次启动 harness 时加载。 ## 构建 浏览器半是 DSH 客户端 bundle,必须构建;需要仓库工具链(本插件在 `scripts/tsdown.client.ts` 内联了自己的客户端构建预设副本,它会从所在检出目录解析 harness 源码)。 ```sh # 在 deepseek-harness 检出目录里 pnpm exec tsdown --config dsh_workspace_switch/tsdown.config.ts # 或在插件目录里执行 pnpm build pnpm exec tsc -p dsh_workspace_switch/tsconfig.typecheck.json # 类型检查浏览器半 node --test "tests/**/*.test.js" # 单元测试 ``` **`lib/` 已提交进版本库。** 包的 `main` 与 `./client` 都指向它,而一份克隆里既没有 harness 源码也没有构建工具链, 否则「从源码安装」(`dsh plugin add github:…`)装到的包会没有任何入口文件。任何改动发布后请把重建的文件一并提交。 独立克隆无法执行构建:内联的预设会 import 只存在于检出目录里的 harness 源码(`../../packages/…`、`../../scripts/…`)。 请在检出目录里构建,再把 `lib/` 提交到这里。 ## 已知限制 - **Skill 只是被门禁遮蔽,并未卸载** —— 文件仍在磁盘上,只是对该工作区从目录中移除且无法加载。 - **插件必须声明工具名** —— 门禁按名字拒绝工具,关闭插件只影响其条目 `tools` 里列出的名字。 - **弹窗列出的是宿主能寻址的东西** —— 插件行来自 profile 的插件管理器(或只读清单); 组合里没有暴露的能力无法配置。 ## 许可证 MIT。