# dsh-skill-preferences 在 **设置 → 技能** 中管理 [DeepSeek Harness(DSH)](https://github.com/deepseek-ai/deepseek-harness) 技能,分别设置全局、当前用户和当前工作区的偏好。 [English](README.md) ## 版本与兼容性 **0.2.2** 将全局选择项和全局写入权限限制为宿主的管理员角色,替换了 0.2.1 中默认放行所有用户的 `adminUsers` 白名单逻辑。0.2.1 修复了插件响应格式校验不一致和分层开关显示的问题。 插件使用公开的 WebServer、Auth、settings、skills、Agent 和客户端插槽接口,无需修改 DSH 源码或内置 preset。发布验收脚本使用未修改宿主提交 `4d214f38c9fe03aefdfb9d900219f64f4ca85183` 的源码版和编译版,检查打包后的浏览器模块、管理员权限、模型目录、账户隔离和卸载重装,详见 [0.2.2 验收报告](artifacts/installation-verification-0.2.2.json)。peer 依赖的最低版本只是安装约束,不代表所有未来 DSH 提交均兼容。 使用下面的明确版本号安装本次版本。 ## 安装或升级 从 npm 将 0.2.2 安装到 Web profile: ```sh dsh plugin --profile web add dsh-skill-preferences@0.2.2 ``` 重启 DSH Web,然后刷新浏览器。包内的 bundle 会自动挂载宿主插件并提供浏览器模块。只需挂载一次,不需要添加 `dsh-skill-preferences/preset`。 也可以安装本地构建的压缩包: ```sh dsh plugin --profile web add /absolute/path/dsh-skill-preferences-0.2.2.tgz ``` 如果手动维护 profile,可以用其包管理器将插件安装到 `$DSH_HOME/profiles//`,再向该 profile 的 `cordis.patch.yml` 添加以下内容,**作为上述 bundle 安装方式的替代**: ```yaml - insert: - id: skill-preferences name: 'dsh-skill-preferences' ``` 不要同时保留手动挂载行和 bundle 挂载行。除非另行删除保存的设置,升级或卸载重装都会保留已有偏好。 ## 如何使用三个层级 打开 **设置 → 技能**,选择要修改的层级,搜索技能,然后操作开关。 | 所选层级 | 开关修改的内容 | 生效范围 | |---|---|---| | 全局 | 全局禁用列表 | 所有账户、所有工作区 | | 此用户 | 当前登录账户的禁用列表 | 该账户的所有工作区 | | 此工作区 | 当前项目根目录的禁用列表 | 使用该项目的所有账户 | 每个开关**仅显示所选层的设置**。单独显示的“当前会话”状态及禁用来源标签,表示当前账户和工作区叠加后的结果。在工作区关闭某个技能,不会关闭全局或用户层的开关;只有另外两层也保存了禁用记录时,它们才显示为关闭。 三层禁用记录取**并集**,按全局 → 用户 → 工作区逐层限制。开启技能只清除所选层的禁用记录,下层不能覆盖上层的限制。受限制的技能仍会保留在列表中,并说明应在哪一层解除限制。存在上层限制时,界面不会再添加重复的下层限制;已存在的下层禁用记录仍可清除。 用户层要求宿主处于多用户模式且有已认证账户。工作区层要求当前会话具有工作目录。插件将目录规范化为最近的 `.git`、`.dsh` 或 `.agents` 项目根目录;没有标记时使用工作目录本身。 ## 保存位置与全局修改权限 偏好保存在 DSH 的持久化设置命名空间 `skill-preferences`: ```yaml skill-preferences: disabled: [pdf] hints: {} byUser: '<账户-userId>': disabled: [cad] hints: {} byWorkspace: '/absolute/project/root': disabled: [imagegen] hints: {} ``` `hints` 保存关闭技能时的描述和来源,仅用于显示。用户层的键是账户 **userId**,不是登录用户名。服务器根据认证确定用户,客户端不能指定其他账户。工作区偏好按规范化项目根目录共享,不是每个用户各存一份。 多用户模式下,只有宿主角色为 `admin` 的账户可以看到全局选择项并修改全局偏好,普通用户直接调用全局写入接口也会被拒绝。旧 `adminUsers` 字段仅为兼容已保存的设置而保留,不再授予权限。匿名本地模式仍允许全局访问;若已有认证账户,则遵循该账户的宿主角色。普通用户仍可写入工作区层。 普通用户仍会在技能行中看到“全局已关”状态徽标,用于解释继承的限制;该徽标不提供全局编辑权限。 写入按顺序执行,持久化成功后才返回,并保留其他层的数据。保存后会使插件的技能目录缓存失效,无需重启 DSH。 ## HTTP 接口 插件提供两个 JSON 接口,调用宿主的认证服务。多用户请求需要有效的 `Authorization: Bearer `。浏览器每次请求都会读取当前 DSH token。 | POST 端点 | JSON 请求体 | |---|---| | `/plugin-skill-preferences/list` | `{ "query": {} }` | | `/plugin-skill-preferences/setEnabled` | `{ "change": { "name": "pdf", "enabled": false, "target": "workspace", "cwd": "/project" } }` | `query` 和 `change` 均支持可选字符串 `cwd`、`presetId`。省略 `presetId` 时使用宿主默认 preset。`target` 可为 `global`、`user` 或 `workspace`,默认为 `global`;工作区写入必须提供 `cwd`。 成功响应为 `{ "ok": true, "value": { "skills": [], "userAvailable": true, "isAdmin": true } }`。每条技能除名称、描述、来源及 provider 外,还包含 `disabled`、`disabledLayers`、`modelInvocable` 和 `userInvocable`。`disabled` 是叠加后的状态,单层状态应检查该层是否在 `disabledLayers` 中。`isAdmin` 表示插件的全局修改权限。失败响应为 `{ "ok": false, "error": { "code": "...", "message": "..." } }`,并附相应 HTTP 状态码。 接口限制请求大小并校验数据格式。默认允许回环地址和服务器绑定的 IP。使用域名反向代理时,需要将准确的 `host[:port]` 配置到插件组合选项 `http.trustedHosts`,浏览器来源也必须匹配。此部署选项与持久化技能偏好分开保存。 ## 生效方式与限制 插件注册返回完整快照的技能提供者,通过技能的模型/用户调用策略执行禁用。每个运行中的 Agent 使用绑定到持久会话所有者的提供者,避免账号目录混用,无需修改宿主的共享缓存。保存偏好后,下一次 Agent 步骤更新模型技能目录,后续技能加载使用新策略。 - DSH 已打开的 `/` 技能建议菜单可能在保存后保留旧列表。刷新页面即可重新加载建议,设置页也提供刷新提示。 - 会话尚未创建运行中的 Agent 时,DSH 原生 `skill.list` 可能读取共享 preset 目录,尚未应用该账户的 Agent 提供者,因此此时可能没有体现用户层禁用。插件设置接口始终计算三层偏好,技能执行使用运行中 Agent 的策略。 - 只在宿主 profile 中挂载一次插件。在每个 preset 中重复挂载会造成设置命名空间冲突。 - DSH 可能输出正常的同名技能遮蔽提示。`hints` 中保留的旧描述也可能过时。 ## 开发与验收 使用 `npm install` 安装开发依赖。测试和安装验收需要已构建的 DSH 仓库及其宿主包。包含本地宿主链接的开发锁文件仅保留在本机。 ```sh npm test npm run build npm pack npm run verify:installation -- --dsh-root /path/to/deepsleep --require-clean-host --output artifacts/installation-verification.json ``` `prepack` 会重新构建宿主端与浏览器端,避免将不同步的旧产物一起打包。验收脚本将压缩包安装到独立 profile,运行真实的源码版和编译版 CLI,检查实际提供的浏览器模块与服务器响应、账户隔离、层级叠加、完整快照、真实模型请求、持久化及卸载重装。它使用临时账户和目录,不修改日常使用的 profile。 可以用 `--mode source` 或 `--mode built` 单独验收一种运行方式,用 `--keep-temp` 保留诊断文件,用 `--update-snapshot` 记录经过审查的预期变化。[快照](tests/snapshots/installation.json)和 [0.2.2 报告](artifacts/installation-verification-0.2.2.json)不包含 token、密码、账户 ID 或临时路径。