# 技能管理 · 端到端验收记录 日期:2026-09-11 对象:`dsh-plugin-desk` v0.2.1 + 技能面板 环境:DSH 0.1.5-rc.1(子包 0.1.5-rc.2)· Node v24.18.1 · Windows · web profile · `http://127.0.0.1:3080` > 本文件记录**实测输出**,不是预期。凡未实测的都标注为未验证。 ## 1. 库存完整性 `GET /dsh-plugin-desk/api/skills` ```json {"ok":true,"total":60,"complete":true,"managed":0,"corrupt":false} ``` 按作用域拆解(union,近层覆盖远层): ``` global 1 standard 58 ptc 58 minimal 1 cordis 60 ``` 来源分布:`user` 57 / `plugin` 3。 **独立交叉验证**:另用文件系统扫描 `~/.agents/skills` 得 57 个目录、14 个带 `disable-model-invocation: true` —— 与接口给出的「14 个模型不可见」逐项吻合。 ## 2. 用法提示(核心诉求) | 技能 | 实测 `usage` | |---|---| | `handoff` | 模型看不到它 —— 只能用 /handoff 手动唤起 | | `brainstorming`(默认) | 模型会自己调用;也可用 /brainstorming 手动唤起 | 模型侧不可见、只能靠 `/` 唤起的技能数 = **14**,与 §1 的独立统计一致。 ## 3. 清理标记 ``` 嵌套失效 SKILL.md 40 混入非技能文件 2 有至少一条标记的技能 42 ``` 判定依据:`isPotentialSkillPath` 只承认根目录 `.md` 与 `/SKILL.md`,`segments.length > 2` 一律 false(`skill-filesystem/src/index.ts:683`)。抽样确认嵌套那份与生效那份**内容不同**(`brainstorming` 10047 vs 15456 字节)。 ## 4. 来源与升级对象 `archify` → `origin.kind = plugin`,`packageName = @tt-a1i/archify-dsh`,路径 `.../node_modules/@tt-a1i/archify-dsh/skills/archify/SKILL.md`。 其余 57 个 → `kind = user`(路径落在 `~/.agents/skills/`)。 **注意**:`source` 字段在本部署不可信 —— host 进程 cwd 是家目录,预设把用户根报成 `project-agents`。分类改为以路径为准。 ## 5. 开关生效(三层证据) ### 5.1 探针层 ``` {"importOk":true,"keyOk":true,"scopeTagOk":true,"hasPropSkills":true, "canaryWon":true,"winner":"probe-canary/probe","modelInvocable":false, "afterDispose":"filesystem"} ``` rank 0 候选赢下 `standard` 预设层,策略生效,dispose 后干净还原。 ### 5.2 系统层(harness 自身确认) 设 `brainstorming` `model=false` 后,本会话的 `` 目录中 `brainstorming` **消失**;`POST /skills/reset` 后**回来**。往返三次,每次由 harness 重新渲染确认。同样对 `grilling` 复现一次。 ### 5.3 稳定性 - 连续三次 `GET /skills`:`installed=[standard,ptc,minimal,cordis]` 不变,`可开关=60` 不变。 - `dev_reload_package dsh-plugin-desk` 后:`grilling` 的 `provider` 仍为 `plugin-desk-overrides`、`model=false` —— 覆盖跨重载存活(开机即装,非懒装)。 ## 6. 闸门(宁缺勿假) `canToggle` 逐技能判定其服务作用域是否已装本插件 provider: ``` 可开关=60 / 60 (installed 覆盖 standard/ptc/minimal/cordis 之后) ``` 未覆盖时的实测表现(安装失败期间): ```json {"name":"handoff","canToggle":false,"ineffective":true, "toggleBlockedReason":"「standard、ptc、cordis」预设作用域没有本插件的 provider,覆盖会被更近的层盖掉"} ``` ## 7. 状态文件 路径 `~/.dsh/plugin-desk-skills.json`。语义:`model` / `user` 是**要强制生效的 invocation 值**,不是停用标志,读取时原样使用、不取反。`base` 记录插件介入前的默认策略,供「恢复默认」与界面显示。 复位后实测:`{"overrides":{}}`,`managed=0`,`可开关=60/60`。 | # | 断言 | 状态 | |---|---|---| | 1 | 默认零影响(空状态目录与未装插件一致) | ✅ 空状态下 `managed=0`,目录往返不变 | | 2 | 关模型维后从模型目录消失 | ✅ 系统层证据(§5.2) | | 3 | 两维都关后从 `/` 命令目录消失 | ⚠️ 未直接实测(`userInvocable=false` 的路径未端到端走一遍) | | 4 | 只关模型维时 `get()` 仍返回真正文 | ⚠️ 未直接实测(候选赢得名字已证实,正文读取未验证) | | 5 | 重载后仍生效 | ✅ §5.3 | | 6 | 状态文件损坏降级为不覆盖 | ⚠️ 未实测 | | 7 | 未标记技能不受影响 | ✅ `managed` 计数恒等于状态文件条目数(复位后 0) | **未验证项如实列出**,不当作已通过。 ## 8. 与本插件无关的既有问题(顺带发现) 5 个用户预设 `anchored-standard` / `router-spec` / `router-standard` / `whoami-standard` / `zero-anchored-standard` **自身无法挂载**: ``` agent-presets: preset "router-standard" failed to mount: failed to apply loader entry persona (@deepseek-ai/dsh-persona): invalid config: - $.prefix missing required value (at prefix) ``` 它们与本插件无关,但在 `presetInstall.failed` 里如实暴露。由于这些预设的技能同时也由 shipped 预设提供,当前 60 个技能仍全部可开关。 ## 9. 作用域解析根回退(v0.2.1) `@deepseek-ai/dsh-scope` 原先只从 profile 根解析一次;该根不可用时 `scopeModule` 直接为 null,**所有预设作用域静默降级为仅 global 覆盖**,技能开关会被闸门如实拒绝。 修复后依次尝试 profile 根与 DSH 安装根。**差分实测**(人为把 profile 根的 junction 改名,重载插件后读 `/skills`): | 代码版本 | `presetInstall.installed` | `presetInstall.reason` | |---|---|---| | 旧(单根) | `[]` | `@deepseek-ai/dsh-scope 不可解析(部署未提供)` | | 新(双根) | `standard,ptc,minimal,cordis` | 空 | 恢复 junction 后两次读数均无差异。失败信息现在会列出实际尝试过的路径。 **顺带更正**:此前认为 `~/.dsh/profiles/node_modules/dsh-plugin-desk` 这个手工 junction 是预设作用域生效的前提。实测**证伪**——删除它后 `installed` 仍为 `standard,ptc,minimal,cordis`。该 junction 未被任何代码路径解析,已删除。