DeepSeek Harness Hub
← 返回列表

masquerator-coder/dsh-preset-skills

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

把每个 agent 预设agent preset自己 skills/ 目录里的技能注册为可发现、按预设严格隔离的技能。

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/6 · 已提供中文文档

为每个 dsh agent 预设挂载其各自的 skills/ 目录,按预设隔离。树外实现,零 dsh 源码改动。

综合分
29.5
GitHub 分
29.5
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add masquerator-coder/dsh-preset-skills
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent-presets@deepseek-ai/dsh-scope
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-preset-skills

把每个 agent 预设(agent preset)自己 skills/ 目录里的技能注册为可发现、按预设严格隔离的技能。

- 不泄漏:research 会话只见 research 的技能,teacher 会话只见 teacher 的,兄弟预设互不可见。
- 不动 dsh 源码树:纯 out-of-tree profile bundle 插件。
- 确定性证据:/dsh-preset-skills.log(append-only marker)逐事件记录注册来源、目录与计数。

机制(v4,bundle 事件驱动)

单个 host 平面插件(profile bundle 行 name: dsh-preset-skills),挂 agent/created 生命周期事件:

1. agent 工厂在 setup 阶段先装配预设(web 新建会话与 resume 都是:presets.mount(agentCtx, preset) 在 agent 发布前完成),发布序列随后触发 agent/created。host(无 scope tag)监听者被 dsh-scope 的 carrier filter 放行,所以 host 平面能可靠收到该事件。
2. 回调内惰性解析服务(ctx.get('agentPresets'),绝不在 apply 时缓存)→ composedPreset(agent.ctx) 拿预设 id → agentPresets.resolve(id).path 推出技能目录 dirname(path)/skills(同时覆盖 user 根 ~/.dsh/.agent-presets/ 与 shipped 根 packages/preset/agent-presets/presets/)。
3. 发现/解析复用 parse.ts(目录束 /SKILL.md 与扁平 .md,frontmatter 至少 name+description)。
4. 经 agent 自己的 scoped ctx 拿到 skills 服务再注册:Cordis getTraceable 会把 service 方法调用 this 重定向到访问方 ctx,SkillRegistry.register() 据此把注册落进该 agent 的 scope 层([agentKey → presetStandingKey → …])。因此:
- 该会话自己的 / 目录与模型可见目录(scope 链含 agentKey 层)能看到;
- 兄弟预设永远看不到(standing 键不相交);
- 注册 effect 归 agent scope fiber 所有,agent 释放自动回收,无手动清理。
- 若某预设的 standing 组合自己发布了 skills 服务,则优先走 agentPresets.serviceFor(...)(落 standing 层,同预设所有会话共享);否则回退 agent ctx 通道。
5. v4.2 空白会话动态切预设:dsh 的预设切换(agent-presets select→swap)在空白会话上把 agent scope 重链到新预设 standing,但不会重触发 agent/created。插件新增生产监听 agent-preset/selected(该事件在 recompose 提交后才由 agent-presets 发出),取出 live agent 后做收敛式同步:先只读 prepare 新预设技能 → 释放旧注册集的 disposers → 应用新注册集。所有 per-agent 工作走同一条串行队列,与 agent/created 注册不交错。语义与 dsh recompose 一致:换绑即换视角,旧预设技能立即清出该会话。
6. v4.3 启动 roster 预热(缓解,非根治):见下「启动竞态」。

启动竞态(v4.3 缓解 → 根本修复归属 dsh)

症状:dsh 刚启动进入默认预设时, 里没有预设目录里自定义的技能;切一次预设后才正常。

根因(诊断 2026-09-06,D:\Apps\deepseek-harness):不是本插件没注册——marker 日志证明 agent/created … registered=20 每次都成功。真正的问题在 dsh web UI 侧(ui-skill browser half)的 per-session 技能目录缓存:

- UI 的 scope-birth warm() 在会话诞生瞬间就发 skills/list RPC 并缓存 settled 快照(ui-skill/src/client/index.ts),只在该会话 切预设(agent-preset/selected)或断线重连(connection/reset) 时失效。
- 冷启动时,本插件的首个子代理注册要走 第一次 agentPresets.resolve → 全 roster discovery(逐个 health-check 每个预设组合,冷启动约 5s)。期间 UI 已缓存「注册前」的空快照。
- host 侧 SkillRegistry 注册完成会有 skills/change 事件,且 UI 能订阅恰恰漏了——dsh 把转发到浏览器的 host 事件放在白名单 API_REMOTE_FORWARDED_EVENTS(packages/api/remotes/src/remote-events.ts)里,那里有 commands/change(ui-commands 订阅它目录才不陈旧)但没有 skills/change,所以 UI 根本收不到「技能已注册」。

v4.3 缓解:apply 后立刻用一次 agentPresets.list() 填满 dirCache(所有预设的 skills 目录已解析好),首个 agent/created 注册从 ~5s 降到毫秒级,在常见冷启动下抢在 UI prewarm 前完成。严格 best-effort:roster 未就绪会短暂重试后放弃,回退到慢但正确的 resolve 路径。
真根治(归属 dsh 核心,未在本仓库做):在 API_REMOTE_FORWARDED_EVENTS 增加 skills/change,并让 ui-skill 订阅 ctx.remote.$on('skills/change', clearAll)——与 ui-commands 对 commands/change 的处理完全对称。这样任何技能注册完成,UI 目录缓存立即失效重拉,不再依赖切预设。

Marker 主行示例(build 戳用于区分旧 build/残留进程):

[preset-skills] agent/created build=v4.2 agent=session-… preset=teacher presetSource=composed
agentPresets=present dir=C:\Users\fuqia\.dsh\.agent-presets\teacher\skills
state=ok found=5 registered=5
[preset-skills] sync build=v4.2 agent=session-… source=selected from=research to=teacher
dir=C:\Users\fuqia\.dsh\.agent-presets\teacher\skills state=ok found=5 disposed=20 registered=5

构建 / 测试 / 部署

node build.mjs                    # esbuild 打包 src → lib/index.js(需要 danger-full-access;yaml 保持 external)
npm run test                      # node --test tests/*.test.mjs(真实 preset 目录 + mock 注册 sink)
node smoke-parse.mjs              # 解析层自检(research/teacher/developer 计数)

dev 类型检查(本机,指向 harness 的 TS + @types/node):

node "D:/Apps/deepseek-harness/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/bin/tsc" -p tsconfig.typecheck.json

bundle 接线(已在 profile):~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 数组含 dsh-preset-skills;dsh 启动时按包的 dsh.bundle.patch → cordis.patch.yml 把行 name: dsh-preset-skills(裸包名,解析到包 main 的 apply(ctx, config))插进组合树。改代码后:

1) 仓库内构建,2) 同步到 profile 安装位(git 依赖拷贝,不重跑 pnpm update 也行)
cp lib/index.js lib/index.js.map lib/index.d.ts cordis.patch.yml \
~/.dsh/profiles/web/node_modules/dsh-preset-skills/lib/
3) 重启 dsh web 生效;可用 --dump-config 确认组合树里有 preset-skills 行

文件锁提示(Windows):dsh web 运行时会锁定 profile 里 dsh-preset-skills/lib/index.js,直接覆盖报 Access denied。顺序必须是先停 dsh web → 再覆盖 → 再启动。PowerShell 一键:

先手动停止运行中的 dsh web(监听 :3080 的进程),再执行:
Copy-Item lib\index.js, lib\index.js.map, lib\index.d.ts
-Destination "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-preset-skills\lib" -Force
然后重启 dsh web,看 marker:apply build=v4.3.0 + roster prewarm rows=N dirs=M

分发铁律:lib/(构建产物)随 git 提交,package.json 无 prepare 脚本 → 任何机器 git 安装零 allowBuilds。lib/index.js.map 不被 git 跟踪(git status 不会显示它),但它参与 esbuild sourcemap 定位,覆盖部署时仍一并拷到 profile 保持一致。

验证(2026-09-05 真机,dsh web)

新建会话(web UI 实测)marker 证据:

- research 会话:agent/created … preset=research … found=20 registered=20
- teacher 会话:agent/created … preset=teacher … found=5 registered=5
- standard(shipped,无 skills 目录):found=0 registered=0(优雅空转)

模型可见  目录(解压会话 session.jsonl.zstd 取证):

- research 会话:research 20 项 + 全局技能;无 teacher 项。
- teacher 会话:teacher 5 项(chaoxing-suite、lesson-plan-generator、ppt-master、programmatic-excel-generation、teaching-ppt-pipeline)+ 全局技能;research 泄漏为空。
旧机制已移除:三预设(research/teacher/developer)的 agent.cordis.yml 不再含 preset-skills/./preset-skills/index.mjs 行(grep 计数 0),其 preset-skills/ 目录已不存在;新机制独立成立。

v4.2 动态切预设真机验证(dsh web,2026-09-05):新建 research 会话(marker:sync source=created … to=research … registered=20)→ 空白态切 teacher → 发 hi,marker:sync build=v4.2 … source=selected from=research to=teacher … disposed=20 registered=5;模型可见  = teacher 5 项 + 全局,research 泄漏为空。对比 v4.1 同场景(遗留旧预设、新预设缺失)已修复。

已知边界

- 动态切预设(v4.2 已支持,限空白会话):dsh 只允许在从未跑过模型回合的空白会话里切预设(turnBoundary 守卫)。切换后插件立即把该会话的注册收敛到新预设(释放旧集、应用新集)。已开始过对话的会话其预设被 dsh 锁定,无需也无法切换。若未来 dsh 允许会话中途换预设,需要新的收敛语义(含历史一致性设计)。
- 子代理(delegation depth > 0)跳过注册(避免高频读盘);子代理看不到父 agent 的 agentKey 层技能(如需请走 standing 层或另行扩展)。
- 启动首次会话的 UI 目录缓存竞态(v4.3 缓解,未根治):dsh web 的 ui-skill 缓存每会话技能目录,只在切预设/断线时才失效,且 skills/change 不在 dsh 转发白名单 → UI 收不到「技能已注册」。v4.3 用一次 roster 预填把注册压到毫秒级,让注册抢在 UI prewarm 前;但理论上仍可能输掉极窄的竞态窗口。彻底修复需改 dsh 核心(白名单加 skills/change + ui-skill 订阅),见上文「启动竞态」。
- marker 日志随每事件追加;config.debug: true 会额外记录候选事件探针(噪音较大),排查用。

环境锚点

- 工作区:D:\Coding\DSH-Plugin\dsh-preset-skills
- dsh 源码:D:\Apps\deepseek-harness(未改动)
- DSH_HOME:C:\Users\fuqia\.dsh;user 预设根 .agent-presets\:teacher=5、developer=2、research=20
- profile:C:\Users\fuqia\.dsh\profiles\web(bundles 含 dsh-preset-skills)
- git origin:git@gitcode.com:foqiang/dsh-preset-skills.git(SSH)

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(masquerator-coder)的其他插件

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群