dsh-workspace-gate
Manifest validPer-workspace gate that hides the tool schemas and system prompt sections of selected plugins from the model in directories that do not need them.
简体中文 | English
dsh-workspace-gate · 工作区插件门控
插件照常加载,但按工作区把它不该占的提示词前缀摘掉——工具 schema 与提示词段都不再进模型上下文。
一个 DeepSeek Harness(dsh)插件。
它让"要不要让模型看见某个插件"从全局下沉到工作区:插件依然全部加载、功能随时可用, 但在你指定的目录下,它的工具 JSON schema 和系统提示词段不再出现在每一次请求里。 省下的是每轮请求的输入 token,而不是插件的加载开销。
目录
它解决什么问题
DSH 自带的插件管理只有 全局 开关:一个插件要么对所有工作区都开,要么都关。
但插件对 prompt 的成本是每轮都付的——只要它启用了,它的工具 JSON schema 和 系统提示词段就会出现在每一次请求里,哪怕这次对话完全用不到它。
典型场景:
- 装了「小说写作」插件,但你 90% 的时间在写代码;
- 装了「网页搜索」全家桶,但某个离线项目根本不该联网;
- 学生工作区只需要讲解/脑图,教师工作区只需要备课/教案。
本插件把"要不要让模型看见"从全局下沉到工作区,不动全局开关、不重启、不重载插件。
它做什么 / 不做什么
| 做 | 不做 |
|---|---|
| 按目录(含子目录继承)决定哪些工具/段不进 prompt | ❌ 不安装/卸载/升级插件 |
| 组级开关 + 展开到单个工具名/段名 | ❌ 不改变插件的全局启用状态 |
| 按来源分档:第三方 / 自定义 / 官方 / 官方可选包 | ❌ 不能把全局已停用的插件"变出来"(只减不加) |
| 自动归属推断 + 静态扫包 + 手工归属 | ❌ 不回溯已开会话(前缀已经发出去了) |
| fail-open:任何异常都当作"没配置" | ❌ 不碰 sandbox / approval 策略 |
主要特性
- 工作区级收窄:配置单位是目录,子目录自动继承最近祖先(给
D:\Projects配一次,D:\Projects\api就继承)。 - 只减不加:用的是 DSH 最弱的收窄原语
ctx.tools.restrict(),它只能移除,不会新增能力。 - 两类可见面都管:工具 schema + 系统提示词段(后者用"同名空文本段遮蔽"实现)。
- 按来源分档:靠 bundle 的
availability判断"随 dsh 安装"还是"用户自装", 第三方档默认展开,官方档默认收起。 - 归属可手工矫正:每个工具/段右侧有归属下拉,可以把未归属的项并入已有分组或新建分组。
- 模型可调:
workspace_gate工具支持status/list/set。 - 可控的噪声:不写 DOM、不加载宿主客户端包、颜色只用
--dsw-alias-*主题 token。 - 可测试:核心逻辑抽在
lib/policy.mjs,24 条单测,不启动 DSH 也能跑。
界面
插件管理页会多出一个 「按工作区」 页签:
插件照常加载;勾掉的插件,它的工具与提示词段不再进入这个目录的请求。
存储: ~/.dsh/data/workspace-gate.json [重新扫描]
工作区 (default-workspace) (my-project ●) (+ 添加目录)
C:\work\my-project · 跟随全局 · 已关 1 组 · 共 9 组
插件组 [筛选…]
› 第三方 2 ≈ 2.7k
[网] web-search-free [9 工具][1 段] ≈2.7k › ●
› 自定义分组 1
› 官方 7 ≈ 17.8k
› 官方可选包 1
› 未归属 27
- 行尾开关 = 这一组在这个目录下是否可见;
›展开后可以只勾单个工具/段,右侧下拉可以改它的归属;- 顶部显示当前目录、是否已单独配置、关了几组、大概省多少 token/轮。
安装
本插件是标准 DSH bundle(package.json 里声明 dsh.bundle.patch)。
三种装法,推荐顺序从上往下;装好后都会在插件管理页出现「工作区插件门控」这一行。
已发布到 npm:
dsh-workspace-gate@0.1.1。 能访问 npm 的机器可以直接dsh plugin --profile <your-profile> add dsh-workspace-gate@0.1.1,不必走 GitHub。
版本要求:
engines.dsh = ^0.2.1-rc.2。比这更老的 DSH 会被插件管理器直接拒绝安装, 而不是装上以后在运行期报错。
方式 1 · 让 AI 帮你装(最省事,推荐新手)
新开一个会话,把这句话发给助手:
帮我安装这个 DSH 插件:
github:M1r0er/dsh-workspace-gate
助手会调用 plugin_manager 完成「pnpm 安装 → 选中 bundle → 激活」整条链路,最后告诉你
application: applied。然后刷新页面即可。
- 前提:当前会话的预设启用了
plugin_manager工具。DSH 默认只在 Creator 模式下启用它, 其它预设默认关闭;如果助手说没有这个工具,切到 Creator 再试,或改用方式 2。 - 安装 Host 代码属于高权限操作,会请求一次性授权。
方式 2 · Web 插件页安装(不碰命令行)
- 打开 DSH 的 插件 页;
- 点安装入口,在 spec 里填
github:M1r0er/dsh-workspace-gate(也可以填你本地 clone 的绝对路径); - 若弹出 “Allow these scripts and retry”,确认后重试一次;
- 列表里出现
dsh-workspace-gate即装好,刷新页面; - 确认「工作区插件门控」这一行是开启状态。
方式 3 · 命令行(知道自己在做什么的人)
# A. 用 dsh CLI(profile 不是 Desktop 时)
dsh plugin --profile <your-profile> add github:M1r0er/dsh-workspace-gate
# B. 直接进 profile 目录用 pnpm
cd ~/.dsh/profiles/<your-profile>
pnpm add github:M1r0er/dsh-workspace-gate
# C. 本地目录(开发/调试)
git clone https://github.com/M1r0er/dsh-workspace-gate.git
pnpm add link:<克隆下来的绝对路径>
# D. 从 npm(0.1.1 起可用)
dsh plugin --profile <your-profile> add dsh-workspace-gate@0.1.1
--profile <name>决定改哪个 profile 目录:--profile web改的是~/.dsh/profiles/web, 而桌面版 GUI 跑的是desktopprofile —— 装进web,桌面窗口里看不到,两个 profile 的 依赖和dsh.profile.bundles互相独立。要装进桌面版,请用它自己的插件页 (npm 版 CLI 会拒绝管理desktop)。
⚠️ pnpm 只装依赖,不会把包写进
dsh.profile.bundles。 少这一步插件不会加载。装完必须再做一件事:
- 打开 Web 插件页,把
dsh-workspace-gate这个 bundle 打开;或- 手工在
~/.dsh/profiles/<profile>/package.json的dsh.profile.bundles数组末尾加"dsh-workspace-gate"。然后重启 DSH(没有 HMR 时)才会加载。
装好后:关掉插件管理页里「工作区插件门控」这一行 = 门控整体不生效,行为回到未安装状态(fail-open)。
常见坑
| 现象 | 原因 / 处理 |
|---|---|
| 装完插件页没有这一行 | bundle 没被选中:按方式 3 的提示把它加进 dsh.profile.bundles |
返回 already-installed | 同 spec 已装过;先在插件页 Remove 再装 |
| 桌面版提示 CLI 不接管 | Desktop profile 由 Electron 托管,npm CLI 会拒绝管理它;请用 Web 插件页 |
| 安装卡在 build scripts | pnpm 11 默认拦截安装脚本;在弹窗里批准后重试 |
| 想在插件市场里搜到 | 仓库已打 dsh-plugin topic,但要在市场出现还需被 awesome-dsh-plugin 索引收录(提交 PR) |
使用
给人
插件管理 → 「按工作区」→ 选目录 → 关掉不需要的组 → 保存。对新会话生效。
给模型
workspace_gate(action:"status") # 最近哪些会话命中了哪个目录、摘掉了什么
workspace_gate(action:"list") # 可门控的插件 → 工具名/段名
workspace_gate(action:"set", dir:"D:\\Projects\\api",
hide:["plugin:r18-novel"]) # 需要显式给 dir
workspace_gate(action:"set", dir:"D:\\Projects",
show:["tool:read"]) # 从隐藏清单移除
这个工具没有用
deferLoading:实测打开后子会话里它直接不可见,模型想调也调不到。
两种写法等价(dir 必须是绝对路径,子目录会继承):
- 隐藏整组:
plugin:<分组 id> - 隐藏单项:
tool:<工具名>/section:<段名>
归属是怎么判断的
DSH 运行时不记录某个工具是哪个插件注册的(tools.register() 只按名字存),
所以"按插件勾选"只能推断。本插件按强度依次尝试:
| 顺序 | 手段 | 说明 | 可靠度 |
|---|---|---|---|
| 1 | 段名命名空间 | r18-novel:protocol → r18-novel,与插件 id/包名归一后比较 | 高(约定) |
| 2 | 工具名前缀 | 工具名 token 与插件 id 或包名 token 的前导全等匹配 | 中高 |
| 3 | 静态扫包 | 读包入口(第三方递归扫 .js)里的 name: 'x' 定义位,与未归属工具名求交,只在唯一命中时采纳 | 较高 |
| 4 | 手工归属 | 界面里自己指定,赢过以上全部 | 最高 |
静态扫包解决的是这类情况:dsh-free-search 的 profile 行 id 是 web-search-free,
而它注册的 platform_search / video_search / weather 等名字里根本不含包名——
只靠前缀只能认出 1/9,扫包之后 9 个全部归位。
硬边界:官方内置包在 app.asar 里,磁盘上没有目录,扫不到;运行时动态注册的工具
(没有对应文件插件)也没有包可扫。这些会留在「未归属」,用手工归属分类即可。
数据存放
<profile>/data/workspace-gate.json(本机示例:~/.dsh/data/workspace-gate.json)
{
"version": 1,
"overrides": {
"d:/projects/api": ["plugin:r18-novel", "tool:free_search_news"]
},
"assignments": {
"tool:read": "文件工具"
}
}
overrides:按工作区的隐藏清单,键是归一化目录(小写 +/),子目录继承最近祖先;assignments:全局的手工归属,赢过自动推断,只改分组、不影响"要不要隐藏";- 文件损坏 / 读不到 → 退化为空配置(全放行),不会让门控把会话搞挂。
为什么不是"真·停用插件"
三条硬理由:
- 全局状态。profile 的
disabled是每个 profile 一份,不是每个工作区一份; 两个工作区想一开一关只能来回改文件。 - 来回改 = 反复重激活。会触发 Loader 重载,而且同时开两个工作区会互相打架。
- 那也不省 token。真停用省的是内存与启动开销;而 token 取决于 prompt 里有什么。 本插件摘的正是"模型侧的东西",与工作区数量无关。
实测数据
本机 DSH 0.2.0-rc.2 / desktop profile:
| 事实 | 数值 |
|---|---|
全局可见工具(tools.schemas(undefined)) | 19 |
| 4 个 preset 作用域并集 | 53 |
| 某个具体会话可见工具 | 52–59 |
| 提示词段(按 preset 并集取) | 20 |
| 插件行总数 | 204 |
两个踩出来的坑:
- 只查全局会漏掉 34+ 个工具——多数标准工具由 agent preset 在自己的作用域注册,
清单必须按 preset 逐个
agentPresets.acquireScope(id)取并集。 systemPrompt.assemble()是 async,不await只拿到一个空对象。
验证记录(对某个目录隐藏 tool:read 与 section:free-search:engines 后新开子会话):
bound = { cwd: "D:\\DSH Workspace", key: "d:/dsh workspace",
deny: ["weather"], sections: ["free-search:engines"], skipped: [] }
weather in agentTools : no
free-search:engines in agentSections : no
skipped: [] 说明两个名字都被接受——包括 preset 作用域里的工具,即 restrict 对
"继承面"(全局 + 祖先层)有效,不必是全局注册。
开发
npm run check # node --check 三个入口
npm test # 24 条单测(纯逻辑,不需要 DSH)
index.js Host 半:绑定 agent、workspace_gate 工具、HTTP 路由
client.js Client 半:插件页「按工作区」页签
lib/policy.mjs 纯逻辑:目录匹配、归属推断、spec 展开、存储规整
tests/policy.test.mjs 上面那层的单测
cordis.patch.yml 组合包的行声明
locale/{zh,en}.json 插件管理页标题与描述
icon.svg 图标
Host 与 Client 之间的通道是本插件自注册的 HTTP 路由
(/workspace-gate/state|apply|assign|refresh):第三方插件的 Host 服务无法凭空长出
一个 remote namespace,而 webServer.register() 是宿主公开的接缝。
已知边界
- 只对新会话生效:已开会话的前缀已经发出去,不回溯。
- 只减不加:不会把全局已停用的插件变出来。
- 归属靠推断:
app.asar内与动态注册的工具无法自动归属,需手工分类。 restrict只作用于继承面:极少见的、在该 agent 自己层注册的工具会落进skipped。- 折叠状态不持久化:刷新后回到默认展开策略。
许可证
MIT © 2026 M1r0er
本仓库打了 dsh-plugin topic,便于在 DSH 插件索引/市场里被检索到。
Comments
Loading…
Similar plugins
by MrWeiCodes
Fine-grained permission gateway: per-category tool-call review (outside-workspace directories, commands, file read/write, subagents, repeated actions) with global & per-project allow/deny exceptions,
★ 11
↓ 485/wk
MIT
JavaScript
Oct 18, 2026
dsh plugin --profile web add @mrweicodes/dsh-permgateby Momojie-S
DSH plugin: per-workspace .env injection for shell subprocesses
★ 2
MIT
JavaScript
Oct 10, 2026
dsh plugin --profile web add @momojie-s/dsh-workspace-envby doebkblcya
A VS Code-style workbench (Preview + Files/Git panels) plugin for the DSH Web GUI
★ 0
TypeScript
Aug 18, 2026
dsh plugin --profile web add @doebkblcya/dsh-workbenchDSH plugin: matches a model you declared on a custom gateway to the capability metadata it should have — context window, output cap, reasoning levels and image support — by looking the bare model name
★ 0
dsh plugin --profile web add dsh-model-metadataby yanglaofish
Routes model requests, web fetches/searches and spawned tools through the Windows system proxy or a custom address — idempotent kernel (reads never rebuild the dispatcher), header one-click toggle, pe
★ 4
↓ 322/wk
MIT
JavaScript
Sep 23, 2026
dsh plugin --profile web add @yanglaofish/dsh-proxy-proby chaggle
Native DeepSeek Harness plugin: gates pwsh tool calls against PowerShell pitfalls via the official tools/pre-execute interception point, bundles the powershell-check skill
★ 4
MIT
JavaScript
Oct 17, 2026
dsh plugin --profile web add @chaggle/dsh-powershell-check