dsh-capability-menu

为 DeepSeek Harness 统一管理 Tools 和 Skills 的暴露水平(上下文占用大小)与执行方式

npm version downloads GitHub stars DeepSeek Harness 0.1.2-rc.1 featured in awesome-dsh-plugin CI

简体中文 · English


## 目录 - [能力总览](#能力总览) - [快速安装](#快速安装) - [暴露策略](#暴露策略) - [配置文件](#配置文件) --- ## 能力总览 dsh-capability-menu 是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的一个 Cordis 插件,为海量 tools / skills(MCP 工具与内置原生工具)建立统一能力目录(`ctx.capability`),并以**常驻 / 按需 / 禁用**三档管理暴露程度和执行方式——随时调整 agent 的能力边界,避免海量 tools/skills 塞满一次请求、节省 token 和上下文。调整即时生效、无需重启,纯插件机制组合进 Harness 运行时,不改上游源码。**不挂载本插件(policy)时一切照旧、全量可见;挂载但未配置任何规则时,所有能力默认常驻。** ### 能力模型 Capability 是本插件引入的上位概念:Tool / Skill 是不同类型的 capability。 | kind | 对 Agent 提供 | action | 备注 | | --- | --- | --- | --- | | `tool` | 执行一个动作(MCP 工具或内置原生工具) | `execute` | 由 `ctx.tools` 索引 | | `skill` | 某类任务的方法/流程/知识 | `load` | 由 `ctx.skills` 索引 | 模型获得两个元工具: | 工具 | 作用 | 对应 entry | | --- | --- | --- | | `meta_search` | 检索能力目录(Tool / Skill),list/detail 双模式 | `@daweifu/capability-menu/search` | | `meta_invoke` | 统一执行面:Tool 真执行(走完整 `ctx.tools` 管线)+ Skill 加载 | `@daweifu/capability-menu/invoke` | ### 能力菜单

Tools 页 Skills 页

策略与目录 · 三档策略配置 策略与目录 · 按需能力目录

安装后,「设置 / 通用设置」下出现「能力菜单」tab(位于「模型」与「插件」之间),用于可视化查看和调整暴露策略,改动即时生效、无需重启: - **Tools / Skills 页签**:顶部 Tab 栏为 `Tools` 与 `Skills`,右侧是各档数量统计、「刷新」与「注册能力」;只读的「策略与目录」入口在页头说明行右侧。Tools 页按 server 分组、可折叠:MCP 工具挂在各自 server(`gongfeng`/`km`…)下;内置原生工具(来自 agent preset 的 `bash`/`read`/`write`/`glob`/`grep`…)统一挂在保留的「系统内置」组(server 键 `built-in`)。点击某行查看模型侧工具定义 name / description / parameters。 - **Skills 页签**:内部再分「全局技能 / 项目技能」两个子页签(始终显示,空的一侧显示空态提示),顶部数量统计跟随当前子页签。点击技能行展开目录树,点文件预览 SKILL.md 等正文。 - **三态圆点与循环切换**:每个能力带一个分类圆点——实心 = 常驻、上半实心圆环 = 按需、圆环 + 斜杠(禁行标志)= 禁用;点击能力旁圆点或分类计数即可循环切换(内置原生工具与 MCP 工具同等可管),若被更高优先级规则(如通配)覆盖,界面会提示「分类未生效」。 - **策略与目录**:点页头说明行右侧的按钮弹出只读弹层,含两份文件——「三档策略配置」是**生效策略的语义化视图**(默认全部能力常驻:`tools.resident` 每个 server 显示 `*`,例外只在 `on-demand`/`disabled` 里按 server → 工具名 分级列出;skills 无 server 维度,`skills.resident` 恒为 `*`),以及「按需能力目录」物化文件(`catalogFile`)的路径与内容。弹层里的策略是只读视图——改规则的入口是页面上点选,改动会在停手后自动写回 profile 的 `cordis.patch.yml`。 - **注册能力**:点右上角「注册能力」按钮弹出注册表单,内含「MCP 服务器 / Skill 目录」两个子页签,**默认停在你当前所在的页签**(Tools → MCP,Skills → Skill)。弹窗里只放表单,不重复罗列已注册项——那些在列表里就有,且各带「编辑」入口。 - **MCP 服务器**:注册即写入 patch 文件里的 `@deepseek-ai/dsh-mcp-client` 条目,**由 dsh 原生挂载**(插件不自己管连接)。与手写的声明式条目同文件、同一张表,无需重启 dsh(live profile 下改动热重载生效)。字段:`serverName`、传输方式(在 `dsh-mcp-client` 中为必填、无默认值,表单代为选定默认 `streamable-http`:该 MCP server 作为独立进程运行,客户端经 HTTP 端点连接,只需 URL;`stdio`:由客户端将该 server 作为本地子进程启动,需给出命令等启动信息)、stdio 的命令 / 参数 / 工作目录 / 环境变量、http 的 URL / **请求头**、超时(秒)。 > **请求头**用于认证:每行 `Key: Value`,`Authorization: Bearer …` 等凭据填写于此。明文存入 `~/.dsh/cordis.patch.yml`(与手写条目一致)。 - **Skill 目录**:可选两种位置——**全局**(`~/.dsh/skills/`,所有会话可见)或**项目**(`<项目根>/.dsh/skills/`,只对 cwd 落在该项目内的会话可见)。选项目时只需填项目内**任意一个已存在的路径**,项目根按 dsh 的规则确定(从该路径向上找最近的 `.git`;一路没有 `.git` 时就用该路径本身),面板会回报实际写入的路径——所以不会出现「注册成功但 dsh 从不扫描那个目录」。两种情况都是建软链,与 dsh 原生的 skill 发现机制一致。注册时会按 dsh 加载器的口径校验 `SKILL.md`——frontmatter 必须能解析成 YAML 映射、含字符串 `name`(仅小写字母、数字与连字符,如 `my-skill`)与 `description`,且 `disable-model-invocation` / `user-invocable` 若出现必须是可读作布尔的值(`true`/`false`/`1`/`0`/`on`/`off`…)。不合格直接报错,不会出现「注册成功但 dsh 静默不加载」;废弃的旧字段名(`disableModelInvocation` 等)也会被指出并给出规范写法。技能名取自目录名;重命名须先移除、再重新注册。 - **编辑**:Tools 页每个 MCP server 分组头右侧、Skills 页每个已注册技能行右侧都有「编辑」,点开预填当前配置,可改、可存、可移除。**移除前会先确认**,并说明这次移除的实际后果:MCP 即删除其 patch 行(配置与 headers 一并删除,`mcp____*` 工具随之失效);Skill 分两种——软链仅删除 `~/.dsh/skills/` 下的链接、源目录不受影响,若该项是 skills 根下的**真实目录**(非软链),则连同文件递归删除、且不可恢复。**系统内置分组没有编辑按钮**——它不是真实 MCP 服务器,没有可编辑的条目;不在 `~/.dsh/skills/` 下注册的技能(项目技能、内置技能)同理。技能行**没有「编辑」时**只显示下面二者之一——能纳管的显示动作,不能纳管的显示它来自哪儿,不会同时出现(那等于把同一件事说两遍)。对 `~/.agents/skills` / `customSkillDirs` 这类**用户级根**里的技能提供「纳入管理」:点击先确认(会在 dsh 的技能根目录下建一条指向它的软链,**内容不动**,与现有条目的做法一致)。不能纳管的(随 dsh 预置、无文件系统目录的)显示来源:命名单一目录的显示该路径(如 `~/.agents/skills`),成类的显示「自定义技能目录」「随 dsh 预置」。项目技能条目同样带「编辑」(其所属根由条目自己带回,无需你重填路径);**位置不可改**——把技能从一个根挪到另一个根等于「移除 + 重新注册」。MCP 的 `serverName` 编辑时**只读**:它构成工具名前缀 `mcp____`,并已被既有会话历史与权限规则引用,修改后这些记录将不再匹配。 - **刷新**:点「刷新」按钮重建能力目录并重新拉取列表。注册来源后会自动刷新一次,通常不必手动点;手动刷新主要用于你在 dsh 之外改动了来源(手改 patch 文件、手动软链 skill 目录)之后。 ## 快速安装 前置:已安装 Node.js 与 dsh CLI(`dsh plugin` 内部会转发给 pnpm)。 ### 从 npm 安装(推荐) 单包同时提供服务端插件与前端「能力菜单」tab,装完即可在「设置 / 通用设置」下看到: ```sh dsh plugin --profile web add @daweifu/capability-menu ``` ### 从源码安装 ```sh git clone https://github.com/PKUfudawei/dsh-capability-menu.git cd dsh-capability-menu pnpm install # prepare 脚本自动构建 lib/(服务端)与 lib/client.js(前端) dsh plugin --profile web add ./dsh-capability-menu ``` ### 验证安装 ```sh dsh --profile web --dump-config | grep -E 'capability-menu' ``` ``` # == @daweifu/capability-menu - id: capability-menu-registry name: '@daweifu/capability-menu/registry' - id: capability-menu-search name: '@daweifu/capability-menu/search' - id: capability-menu-invoke name: '@daweifu/capability-menu/invoke' - id: capability-menu-policy name: '@daweifu/capability-menu/policy' - id: capability-menu name: '@daweifu/capability-menu' ``` ### 卸载 ```sh dsh plugin --profile web remove @daweifu/capability-menu ``` ## 暴露策略 所有能力(Tool 与 Skill)按 **暴露程度**(模型在上下文中看到什么)与 **执行方式** 分为三档: ### Tools / Skills 三档暴露与执行对照 | 档位 | 能力 | 暴露方式(模型视野) | 发现 | 执行方式 | | --- | --- | --- | --- | --- | | **常驻** | tool | 完整 schema 进 `assembly.tools` → 模型请求 `tools` payload,每步可见 | 无需发现(已常驻) | 模型直接调用,运行时走完整 `ctx.tools` 管线 | | | skill | 名字+描述进 `` 目录(正文不在目录) | 无需发现(已常驻) | `skill` 工具按需加载正文(渐进加载) | | **按需** | tool | 不进 payload(零上下文成本) | `meta_search` list / `grep` 检索物化目录 YAML(`catalogFile`) | `meta_invoke` 执行(走 `ctx.tools.execute`,管线完整);或 detail 拿 schema 后直接调 | | | skill | 不进 `` 目录 | `meta_search` 检索 / `grep` 检索物化目录 YAML(`catalogFile`) | `meta_invoke` 加载 SKILL.md 正文(经 `ctx.skills`) | | **禁用** | tool | 不进 payload | `meta_search` 不返回、目录 YAML 不写入 | `meta_invoke` 拒绝;模型幻觉直调也在 `tools/pre-execute` 被硬拒绝 | | | skill | 不进 `` 目录 | `meta_search` 不返回、目录 YAML 不写入 | `meta_invoke` 拒绝;`skill` 工具在 `tools/pre-execute` 硬拒绝 | > **覆盖与保留**: > - `tool` 档同时覆盖 `mcp__` 编目工具与内置原生工具——原生工具统一以保留的 `built-in` server 归组,与 MCP 工具一样三档可管。**请勿把真实 MCP server 命名为 `built-in`。** > - `meta_search`/`meta_invoke` 是本插件的控制面:恒常驻、不可被禁用(在规则里禁用它们会在启动时报错)。`run_code` 是 Code Mode 保留传输层:不进目录、不在「能力菜单」出现,请勿为它配置三档规则。 > - **不建议把高频核心工具设为按需**:按需的内置工具会退出模型常驻视野,使用时需要 `meta_search` → `meta_invoke` 两跳调用。 ## 配置文件 规则写在 profile 的 `cordis.patch.yml` 里 `capability-menu-policy` 插件 entry 的 `config` 下(外层 `- insert:` / `id` / `name` 是 Cordis patch 的挂载样板,与规则无关)。**手写和「能力菜单」里点选都可以**:点选只改内存(所以响应快),停手约 1.5s 后再自动写回这个 entry——因为写这个文件会让 dsh 热重载本插件并重跑一次能力枚举,所以不能每次点击都写。 ```yaml config: tools: resident: - execute_cmd - get_session_context - search_kb - 'mcp__gongfeng__*' # 通配:该 server 下全部常驻 on-demand: - 'mcp__*' # 通配兜底 - 'server:km:*' # 按 server 前缀批量按需 disabled: - 'mcp__secret__*' # 禁用优先级最高,压过常驻 skills: resident: - debugging - coding on-demand: - legacy_skill # 显式按需(未列出即默认常驻) disabled: - forbidden_skill metaTools: - meta_search # 恒常驻,不可被禁用 - meta_invoke ``` > 配置键即档位英文词:`resident`(常驻)/ `on-demand`(按需)/ `disabled`(禁用)。 ### 全部配置项 | 配置项 | 归属 entry | 默认值 | 说明 | | --- | --- | --- | --- | | `tools` / `skills` / `metaTools` | `capability-menu-policy` | 见上 | 三档分类规则;能力菜单的改动会(防抖后)自动写回本 entry 的 `config` | | `catalogFile` | `capability-menu-registry` | `~/.dsh/capability-catalog.yaml` | 按需能力目录物化路径,置空禁用 | | `refreshDebounceMs` | `capability-menu-registry` | `200` | 变更事件的重建防抖窗口(ms);`0` 关闭防抖 | | `patchFile` | `capability-menu-policy` | `~/.dsh/cordis.patch.yml`(`$DSH_HOME` 优先) | 注册 MCP 服务器写入的 patch 文件 | | `skillsDir` | `capability-menu-policy` | `~/.dsh/skills` | 注册 Skill 目录的技能根 | | `persistDebounceMs` | `capability-menu-policy` | `1500` | 点选改动写回 patch 文件前的防抖窗口(ms)| **规则优先级**(从上到下命中即停;同档内精确规则优先于通配): | 优先级 | 规则 | 示例 | 效果 | | --- | --- | --- | --- | | 1 | `disabled` 精确 | `disabled: [forbidden_skill]` | 最硬禁用,压过一切 | | 2 | `disabled` 通配 | `disabled: ['mcp__secret__*']` | 整组禁用 | | 3 | `resident` 精确 | `resident: [bash]` | 单个能力显式常驻 | | 4 | `on-demand` 精确 | `on-demand: [legacy_skill]` | 单个能力显式按需(能力菜单点击写入的就是这类) | | 5 | `resident` 通配 | `resident: ['mcp__gongfeng__*']` | 整组常驻 | | 6 | `on-demand` 通配 | `on-demand: ['mcp__*']` | 兜底批量按需 | | 默认 | 未命中任何规则 | — | 常驻 | 要点: - **精确规则优先于通配(跨档也成立)**:例如存在 `resident: ['mcp__gongfeng__*']` 时,在「能力菜单」把某工具点成按需会写入一条精确 `on-demand` 规则并生效,不会被通配压回;若仍被更高优先级规则覆盖,界面提示「分类未生效」。 > **两类改动,持久化方式不同**: > > - **三档分类**只写入运行时内存、不落盘;要持久化(随 profile 生效、可版本管理/批量声明),编辑 profile 的 `cordis.patch.yml` 即可——这就是分类的持久化入口,无需额外的导入/导出按钮。 > - **注册的来源**(MCP 服务器、Skill 目录)由插件直接落盘:MCP 写进 patch 文件、Skill 在 `~/.dsh/skills/` 建软链,重启后仍在。 ### 按需能力目录(`catalogFile`,唯一物化目录,grep 可检索) On-demand 能力自动物化成**一个 YAML 文件**给模型检索(改档位只重写这个文件——库存没变,不需要重新枚举工具与各 agent preset 的技能层): - 文件位置在 **registry entry(`capability-menu-registry`)** 的 `config.catalogFile`,默认 `~/.dsh/capability-catalog.yaml`,置空禁用;工具/技能变更或分类调整后自动重写。没有任何按需能力时不注入目录指引,省上下文。 - 技能必须**已注册进 `ctx.skills`**(SKILL.md 放用户/项目技能根或挂 `customSkillDirs`)才会自动出现;无独立手写输入清单。 - 模型用 `grep`/`read` 浏览该文件(或调 `meta_search`)拿到条目的 id 与 `kind`,再调 `meta_invoke(id, kind)` 执行/加载。技能 id 即裸名(`frontend-design`),tool/skill 由 `kind` 区分。 ```yaml # ~/.dsh/capability-catalog.yaml(自动生成;仅含 On-demand 能力, # Resident 已常驻、Disabled 不可发现,均不写入;列表以 `-` 每项一行的 block 序列写出) capabilities: - id: mcp__km__search kind: tool name: mcp__km__search description: 搜索知识库 server: km - id: legacy_skill kind: skill name: legacy_skill description: 处理旧工程的低频技能 whenToUse: 处理旧工程时使用 ``` > 目录文件默认写在宿主 `~/.dsh`,需要模型侧 `bash`/`read` 工具的沙箱能访问该路径;若沙箱隔离宿主目录,请把 `catalogFile` 显式配置到沙箱可见的路径。默认路径在多个 dsh 实例间共享(last-write-wins),多实例部署时请为每个实例配置独立的 `catalogFile`。 ## License 本项目遵循 [Apache License 2.0](LICENSE)。