Files
reverse-skills-max/vendor-new/rev-skills/docs/dsh-integration.md

13 KiB
Raw Blame History

DSH(DeepSeek Harness)集成

本文是 rev-skills 与 DSH(DeepSeek Harness)集成的长期参考:DSH 在本库语境里是什么、两条集成路线的差别、DSH 强制执行的兼容规则、安装与卸载命令、预设选择方式、验证方法、排错表,以及维护时必须成对同步的文件。

命令行实现见 bin/dsh.mjs 与 bin/install.mjs;bundle 的补丁本体是仓库根的 dsh.patch.yml。

1. DSH 在本库语境里是什么

DSH 是一个宿主(host),它按 Agent Skills 风格扫描技能目录:每个被扫描根目录下识别 <root>/<name>/SKILL.md 或 <root>/<name>.md。本库的 .claude/skills/ 就是这样一个目录,因此内容不需要转换即可被 DSH 读取——需要处理的只是「放到哪个根目录」与「用哪个预设看到它」。

两条能力需要分开理解:

  • 技能发现(@deepseek-ai/dsh-skill-filesystem):扫描根目录 → 解析 frontmatter → 把技能注册进当前预设的可用技能列表。
  • 预设(agent preset):@deepseek-ai/dsh-agent-preset 的一行配置,决定该预设挂载哪些插件、看到哪些技能根。预设把「技能目录」和「agent 的工具与提示词」绑定在一起。

DSH 的默认技能根与优先级(数字小者先匹配,同名技能以先命中者为准):

优先级 根目录 说明
100 <projectRoot>/.dsh/skills 项目级 DSH 技能
200 <projectRoot>/.agents/skills 项目级通用 agent 技能
300 customSkillDirs 由预设显式声明的目录(本库预设用这一档)
400 <dshHome>/skills 全局 DSH 技能(Windows 默认 C:\Users\<用户>\.dsh\skills)
500 <agentsHome>/skills 全局通用 agent 技能
600 bundledSkillDir DSH 自带技能

本机可用 $env:DSH_HOME(Windows)确认第 400 档的实际位置。

2. 两条集成路线

两条路线不互斥,取哪条取决于「要不要一个只带逆向技能层的固定 agent 配置」。

路线一:装进 DSH 技能根(所有预设可见)

把技能拷到第 100 / 400 档,任何预设都能看到这 122 个技能,不需要 bundle:

npx rev-skills install --target dsh            # 交互式选择 global / project
npx rev-skills install --target dsh --global   # → <dshHome>/skills
npx rev-skills install --target dsh --project  # → .dsh/skills
npx rev-skills install --target dsh --dry-run  # 只看计划
npx rev-skills uninstall --target dsh --global

适用场景:只想让技能在任意会话里可用,不需要独立的 agent 配置。代价是技能与预设的工具集、上下文预算混在一起。

路线二:独立预设(自带技能层)

本仓库的根包自身即 bundle(包名 rev-skills):根 package.json 里的 dsh.bundle.patch 指向仓库根 dsh.patch.yml,该补丁插入一行预设 preset-rev-skills。不需要第二个包,也就没有第二处版本号要同步。

  • 预设显示 id(config.id)为 rev-skills,显示名「逆向工程(rev-skills)」,order 为 40;
  • 该预设自带的 skill-filesystem 实例用 includeDefaultRoots: false,即该实例自身不声明第 100–600 档的根,技能根完全由 customSkillDirs 指定;但 DSH 读取技能时会把这个预设层与全局层合并,所以项目/用户技能仍与会话可见(同名条目以更近的预设层为准),其他预设不受影响;
  • bundle 自身不带技能副本,技能始终从仓库的 .claude/skills/ 读取,因此技能增删改不需要重新发布 bundle。

customSkillDirs 的解析顺序(取第一个通过校验的候选;校验 = 目录存在且其中至少有一个 re- 开头的条目):

顺序 候选 说明
1 REV_SKILLS_DIR 环境变量,优先级最高;取值是仓库根目录时解析为 <dir>/.claude/skills,取值是技能目录本身时原样使用
2 <DSH_HOME>/skills 默认 ~/.dsh/skills(Windows %USERPROFILE%\.dsh\skills)——即「路线一」装进去的位置
3 <rev-skills 包目录>/.claude/skills 按包名解析;本包即 bundle,装进 profile 的 node_modules 时命中

候选都不可用时回落到第 2 项;目录暂缺不报错(提供方会持续探测)。

按 DSH skills 服务的实际契约,预设作用域的提供方与全局层是合并关系而非替换:同名技能以更近的层胜出。因此该预设是把 rev-skills 技能根作为自己的一层加入,用户项目与家目录下的技能仍可见;includeDefaultRoots: false 只影响这个预设实例自身的根列表。

前置要求:宿主需提供两个包——@deepseek-ai/dsh-agent-preset(agent preset 声明能力)与 @deepseek-ai/dsh-skill-filesystem(本地技能目录发现能力),官方发行版自带。bundle 自身零运行时依赖,不需要为它单独跑安装。

node bin/dsh.mjs check [--dir <skillsRoot>] [--json]
node bin/dsh.mjs preset spec
node bin/dsh.mjs preset status [--profile-dir <dir>] [--json]
node bin/dsh.mjs preset install [--profile-dir <dir>] [--force] [--apply]
node bin/dsh.mjs preset uninstall [--profile-dir <dir>] [--apply]

preset install / preset uninstall 默认是 dry-run,打印将要做的编辑;加 --apply 才写文件(写入前备份,卸载时存在备份则从备份还原)。

安装这条路线最省事的方式是交给 DSH 自带的包管理器——它的目标参数既可以是 npm 包名(从 registry 装已发布版本),也可以是本地路径(link: / file: 规格):

dsh plugin --profile <profile> add rev-skills                  # registry 上的已发布版本
dsh plugin --profile <profile> add link:/path/to/rev-skills    # 本地工作区(改补丁立即生效)

成功后它会自动把 rev-skills 追加进该 profile 的 dsh.profile.bundles(实测:从空 bundles 开始,add 完成后 bundles 变为 [..., "rev-skills"]);失败则还原 package.json、pnpm-lock.yaml 与 node_modules,不留半截状态。GUI 插件管理器走同一套机制。

手工等价写法是把下面两处同时写进 profile 的 package.json:

{
  "dependencies": { "rev-skills": "link:/path/to/rev-skills" },
  "dsh": { "profile": { "bundles": [ "...", "rev-skills" ] } }
}

两处必须同时存在:bundle 行在 dsh.profile.bundles 里,且依赖能解析到该包。profile 的 package.json 位于 $env:DSH_PROFILE_DIR(Windows 默认 C:\Users\<用户>\.dsh\profiles\<profile>\package.json)。

卸载走对称的一条命令,它会同时摘掉依赖与 dsh.profile.bundles 里的那一行(实测),随后重启 DSH;已存在的会话保留创建时的插件组合,需新开会话:

dsh plugin --profile <profile> remove rev-skills
node bin/dsh.mjs preset uninstall --apply    # 仓库自带 CLI 的等价路径(有备份时从备份还原)

发布面的一个硬约束:bundle 的补丁文件必须出现在该包 package.json 的 files 列表里。pnpm 处理 file: 依赖时按 files 复制内容,漏列时 add 会报 failed to read overlay …/node_modules/rev-skills/dsh.patch.yml: ENOENT 并整体回滚(测试里有对应回归断言)。

适用场景:需要一个只见得到本库技能、且带固定工具与提示词的独立 agent 预设。

3. DSH 强制的兼容规则

本库 122 个技能已全部满足下列规则;新增或修改技能时按此自检。

  1. 目录布局(一层):<root>/<name>/SKILL.md 或 <root>/<name>.md。扫描只深入一层——嵌套的 **/SKILL.md 不会被发现,例如 .claude/skills/re-analyze/references/analysis-contract.md 不构成独立技能。
  2. frontmatter 分界行必须精确:开头的行就是 ---(前后无空格、无 BOM),结尾是同样精确的一行 ---;闭合行之后才有正文。
  3. frontmatter 必须是合法 YAML 且解析为 mapping:键值映射,块标量与内联 list 都在 YAML 子集内。解析失败时 DSH 记一条告警并静默跳过该技能(技能看起来"消失",不报错中断)。
  4. name 语法:必须匹配 /^[a-z0-9]+(?:-[a-z0-9]+)*$/(小写字母、数字、单连字符分段),并且与目录名一致。
  5. description 非空:缺失或空串即不注册。本库另有更严的约束——description 必须同时含 CJK 与拉丁字母(validate.mjs 强制,保证中英触发词都可命中)。
  6. 可选键:whenToUse、metadata、disable-model-invocation、user-invocable;本库技能不需要它们即可被发现。
  7. 工具结果裁剪:标准预设会裁剪超过 8192 字符的工具结果。本库有 32 个 SKILL.md 的文件字符数超过该阈值(CRLF 检出下为 34;node bin/dsh.mjs check 会逐条列出字符数与正文行数,最长 re-kernel,约 19979 字符),这些技能被加载时正文可能被截断——需要完整内容时直接读文件,或把该技能拆分为「正文 + references/」。

本机自检 frontmatter 的最短路径:

node validate.mjs      # 结构校验(frontmatter / 命名 / 能力标签 / 死链 / guard / 章节)
node bin/dsh.mjs check # 按 DSH 发现规则校验技能根(一层布局 / 分界行 / name 文法 / 裁剪阈值)

YAML 本身按换行解析,DSH 允许分界行尾带 CR;本库随库脚本(validate.mjs / lib/frontmatter.mjs)按 LF 解析,因此检出的工作区行尾须与仓库声明一致(.gitattributes 与 core.autocrlf 的取向见仓库根)。

4. 验证

  1. node validate.mjs 输出 OK: 122 skills validated——内容层通过。
  2. node bin/dsh.mjs check——按 DSH 发现规则校验技能根,通过时输出 OK: N skills DSH-compatible;--dir <skillsRoot> 换根、--json 逐条给出检查项与告警。
  3. node bin/dsh.mjs preset spec——确认解析到的技能根(REV_SKILLS_DIR → <DSH_HOME>/skills → 包目录,见第 2 节的顺序表)。
  4. 新开会话,在预设列表里选中「逆向工程(rev-skills)」:skill 工具目录中应出现入口技能 re-analyze 与其余 121 个 re-* 技能;加载 re-analyze 能返回正文即技能根解析正确。
  5. 对照检查:切回 standard 预设的会话,re-* 技能不再由预设层提供——若该会话仍能看到 re-*,说明技能同时装进了被扫描的全局技能根(路线一),那属于预期结果而非故障。

5. 排错

现象 常见原因 处理
技能全部看不到 装错根目录(--project 装到了 .claude/skills 而非 .dsh/skills) 重跑 --target dsh --global 或 --project,用 node bin/dsh.mjs check 核对根
只有个别技能看不到 frontmatter 首尾不是精确 ---,或 YAML 不合法 DSH 日志会有告警并跳过该条;跑 node validate.mjs 定位;修正分界行/YAML
技能名不合法 name 含大写、下划线、连续连字符或与目录名不一致 改为 <root>/<name>/SKILL.md 且 name 匹配 /^[a-z0-9]+(?:-[a-z0-9]+)*$/
技能列表里没有 references/ 里的文件 扫描只深入一层,嵌套 **/SKILL.md 不发现 属预期行为;把需要独立触发的内容提升为顶层技能
预设不出现 bundle 名不在 profile 的 dsh.profile.bundles,或依赖未安装 跑 node bin/dsh.mjs preset status;补 bundle 行与依赖后重装 profile
预设改完没生效 profile 未重新安装/未应用 node bin/dsh.mjs preset install --apply,或从 GUI 插件管理器重新安装 bundle
旧会话看不到新预设 已存在的会话保留创建时的插件组合 新开一个会话(旧会话不会热切预设)
技能根解析到了别处 REV_SKILLS_DIR 或 <DSH_HOME>/skills 先命中,且其中存在 re- 条目 用 node bin/dsh.mjs preset spec 看命中项,清掉不该命中的目录或变量
改了技能正文但会话里没变 正文按需加载,编辑正文不需重启 重新触发该技能即可
改了技能 frontmatter 但会话里没变 frontmatter 在启动/加载时解析并缓存 重启 DSH 会话(或重载技能根)后生效
技能正文被截断 正文超过 8192 字符被预设裁剪 直接读文件,或把长技能拆分为正文 + references/

6. 维护同步点

改 DSH 相关文件时,下列配对必须同时更新,否则出现"命令能跑但预设装不上"这类不一致:

项 一处 另一处
补丁文件 根 package.json → dsh.bundle.patch dsh.patch.yml 实际路径,且该路径必须出现在根 package.json 的 files 里
bundle 名 根 package.json → name(rev-skills) profile package.json → dsh.profile.bundles 的对应行 + 同名依赖;本文档与 README 的安装示例
预设 id dsh.patch.yml 的 config.id(rev-skills) 本文档的说明
技能根 dsh.patch.yml 的 customSkillDirs 解析顺序 REV_SKILLS_DIR 覆盖逻辑、bin/dsh.mjs 的 resolveLocalSkillRoot 与本文档第 2 节的候选表

版本号不再有第二处:bundle 就是根包,根 package.json 的 version 与 .claude-plugin/marketplace.json 成对即可。

发布流程与其他宿主一致:npm test 通过 → git tag → npm publish → 同步 package.json 与 .claude-plugin/marketplace.json 的版本号。