DSH 插件市场 + 治理底座的开源实现。装完即可安全安装/管理任意插件,插件错误绝不影响服务拉起(第一原则)。
- ✅ 是平台层:安装器(installer)+ 健康自检(suite:doctor)+ 市场服务入口。
- ❌ 不是功能全家桶:功能插件(agent-teams / mneme / usage-stats …)是市场内容,按需安装,不预装。
# 0. 前置:已安装 DSH 并运行过一次 dsh web(生成 profile)
# 1. 装平台层(fail-soft → 重启 → injector + hub)
node scripts/install.mjs
# 2. 重启 dsh web(首次安装只需重启一次,让 fail-soft 内核补丁生效)
# 3. 随时自检
npm run doctor # 或 node scripts/doctor-cli.mjs核心约束(第一原则):installer 强制 fail-soft 先装并生效,
suite:doctor确认PLATFORM_READY之后才允许装其余组件 / 市场插件。装坏插件不会拖垮服务—— 会被 fail-soft 自动隔离,市场里一键恢复。
| 状态 | 含义 | 处理 |
|---|---|---|
PLATFORM_READY |
全部就绪 | ✅ 可安装市场插件 |
NEEDS_RESTART |
fail-soft 已装但补丁未生效 | 重启 dsh web 后重跑 |
NEEDS_FIX |
组件缺失 / 补丁需适配 | 按 blockers 修复 |
退出码:0 = READY,2 = RESTART,1 = FIX。
node scripts/doctor-cli.mjs # 人类可读
node scripts/doctor-cli.mjs --json # 纯 JSON(供市场 UI / 脚本消费)检查项:fail-soft 内核补丁健康(复用 @lanbaolu/dsh-fail-soft 的 getPatchStatus)、
super-injector registry 可达性、plugin-hub 自身服务。
市场不是"只收合格"也不是"什么都收",而是分层:
| 层 | 规则 | 徽章 |
|---|---|---|
| 门槛(MUST) | 上架商品必须过合规校验(0 MUST 违规) | Compliant |
| 分级(SHOULD) | 过门槛后按可信度分级,用户知情决策 | Verified > Stable > Experimental |
| 特殊通道(例外) | COMPAT(版本托底)/ 桥接内容(MCP/skills)不满足完整合规,明确标注平台不背书 | COMPAT / Experimental |
平台不替用户做"能不能用"的裁判:合规门槛 + 徽章给足信息,fail-soft 兜住风险(装坏也不挡服务拉起)。
Compliant 徽章不是写死在目录里的——市场展示/上架时用 dsh-plugin-standard 的
verify-plugin 自动校验生成(0 MUST 违规 = 合规,否则标注 Not-Compliant):
- 商品有本地工作区目录 → 直接对本地校验;
- 远程/npm 源 →
npm pack到临时目录后校验; - 结果按
(package, version)缓存 5 分钟,避免每次展示都跑校验。
# 独立校验一个插件目录
node node_modules/dsh-plugin-standard/scripts/verify-plugin.mjs <插件目录> --jsonGET /api/plugin-hub/health→{ ok, service, version }GET /api/plugin-hub/doctor→ 三态 JSON(市场 UI 安装任何插件前必须确认status === "PLATFORM_READY")GET /api/plugin-hub/catalog→ 市场目录 + 各商品质量徽章与安装/隔离状态POST /api/plugin-hub/install{ id }→ 安装市场插件(前置门:非 PLATFORM_READY 拒绝)POST /api/plugin-hub/quarantine{ id, reason? }→ 手动隔离POST /api/plugin-hub/restore{ id }→ 恢复隔离(只删带隔离标记的条目)
plugin_hub_doctor:运行平台健康自检,返回三态与检查明细plugin_hub_status:返回ready布尔(装市场插件前置条件)plugin_hub_catalog:市场目录 + 徽章 + 状态plugin_hub_install/plugin_hub_quarantine/plugin_hub_restore:市场安装/隔离/恢复
# 用外层进程拉起 dsh web:崩溃 → 诊断是否插件 → 隔离后带退避自动重拉
npx dsh-failsoft-web # 或 node scripts/failsoft-web.mjs
npx dsh-failsoft-web -- --port 3080 # 透传参数- dsh 正常退出(0) → 透传退出
- dsh 崩溃 + fail-soft 隔离数增加 → 坏插件已被剔除,带退避自动重拉(默认最多 3 次)
- dsh 崩溃 + 无新隔离 → 跑 doctor 诊断,疑似非插件问题停止重拉
把"插件挂起"转成可捕获的超时错误(code: ETIMEOUT),挂起不再是无响应黑洞:
import { withTimeout, wrapToolWithTimeout } from '@lanbaolu/dsh-plugin-hub/timeout-guard'withTimeout(promise, ms, label):给任意 Promise 加超时wrapToolWithTimeout(tool, ms):给 DSH 工具定义加超时(元数据不变)- 平台自身工具默认
toolTimeoutMs: 120000(可配置)
| 组件 | 作用 |
|---|---|
@lanbaolu/dsh-fail-soft |
容错底座:坏/不兼容插件自动隔离,服务照常拉起(第一原则承载层) |
@dsh-external/dsh-super-injector |
运维底座:运行时注入 / 热重载 / 生产线 |
@lanbaolu/dsh-plugin-hub |
本包:installer + doctor + 市场服务 + 进程级兜底 + 超时护栏 |
npm test # 30 用例(doctor/启动包装器/超时护栏/市场)
node scripts/doctor-cli.mjs # 实际自检BSD-3-Clause
把外部 MCP server 的工具映射成 DSH 工具(Experimental,平台不背书——市场哲学·特殊通道):
- 手写 JSON-RPC over stdio(零依赖),支持
initialize / tools/list / tools/call - 白名单即配置
mcpServers:只连接显式列出的 server(不任意连远程) - 工具名加
[server]_前缀防冲突;inputSchema(JSON Schema)→ DSH 参数自动映射 - 工具注册带超时护栏(挂起 → ETIMEOUT 可捕获)
// 配置(cordis.patch.yml 的 config 或 DEFAULT_CONFIG)
mcpServers: [
{ name: 'filesystem', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'] },
]桥接内容来源不可本地校验 → 一律 Experimental + 白名单;评审核过才升 Verified。
把外部 skill(markdown 指令 + 附带脚本)转成 DSH 可加载资源(Experimental,平台不背书——市场哲学·特殊通道):
- 解析
SKILL.mdfrontmatter(name/description/ 其余 metadata)+ 指令段 + 附带脚本/参考路径(<skill-dir>/scripts/…、<skill-dir>/references/…) - 资源格式对齐 DSH 实际扫描约定(
skills/<name>/SKILL.md+scripts/+references/),可installTo物化到目标 skills 目录 - 白名单即配置
skillsDirs:只加载显式列出的目录(默认空 = 不加载任何 skill,不触碰运行中的 DSH 实例) - 注册点可注入(
registerTo(ctx, { registerResource })),便于测试与未来适配 DSH 资源 API
// 配置(cordis.patch.yml 的 config 或 DEFAULT_CONFIG)
skillsDirs: [
'/path/to/my-skill', // 目录须含 SKILL.md(可带 scripts/ references/)
{ name: 'other', dir: '/path/to/other-skill' },
]// 独立使用(加载 + 查看 + 物化,零副作用)
import { createSkillsBridge } from '@lanbaolu/dsh-plugin-hub/skills-loader'
const bridge = createSkillsBridge({ skillDirs: ['/path/to/my-skill'] })
console.log(bridge.loadAll()) // 每目录结果(单条失败不阻断)
console.log(bridge.resources()) // DSH 可加载资源(experimental: true)
bridge.installTo('/tmp/dsh-skills') // 物化为 skills/<name>/SKILL.md + scripts + references桥接内容来源不可本地校验 → 一律 Experimental + 白名单;评审核过才升 Verified。
最小闭环骨架 执行 → 观测 → 验证 → 记忆 → 复用(默认关闭,作为市场"旗舰示例"由调用方显式开启)。归属 lib/eval-loop.js,依赖注入可独立单测,任何环节失败不阻断服务拉起(fail-soft 全程兜底):
createEvalLoop(deps)+enable(enabled)/onTaskCompleted(task)/isEnabled()- ① 触发 → ② 观测(
getTrajectory,轨迹摘要占位)→ ③ 验证(verify,带置信度,默认关闭)→ ④ 记忆(remember,mneme 沉淀) - 红线:记忆沉淀强制
{ actor: 'autoDream' }(防止 mneme 反思数据被机器写入污染) - 反馈护栏:验证置信度低于
minConfidence(默认 0.7)→ 只记录不沉淀(防固化坏经验);requireVerification: true时未接验证也不沉淀 - 降级:观测/验证缺失或失败时跳过,记忆仍可写;
remember失败也仅记录,不影响整体
import { createEvalLoop } from '@lanbaolu/dsh-plugin-hub/eval-loop'
const loop = createEvalLoop({
minConfidence: 0.7,
getTrajectory: async (task) => ({ steps: 5, tokens: 1200, errors: 0 }), // ② 轨迹摘要
verify: async (task, summary) => ({ score: 0.9, confidence: 0.85 }), // ③ 验证(可缺省)
remember: (entry, { actor }) => mnemeService.update(entry, { actor }), // ④ mneme 沉淀
})
loop.enable(true) // 显式开启(默认关闭)
await loop.onTaskCompleted({ taskId: 't-1', sessionId: 's-1', output: '…' })lib/eval-bridge.js 把 agent-teams 的持久化团队状态(<workspace>/.agent-teams/<teamId>/team.json)里新 completed 的任务,自动喂给 eval-loop,打通最小闭环 执行 → 记忆 → 复用。
- 白名单
evalStateDirs:只轮询显式列出的状态根目录(默认空 = 不轮询、不沉淀,旗舰示例显式开启) - 幂等 + 持久化:同一
(teamId, taskId)只沉淀一次;seenFile(默认~/.dsh/plugin-hub/eval-seen.json)落盘,重启不重喂历史任务 - 默认记忆沉淀:写入
~/.dsh/plugin-hub/eval-entries.jsonl(零依赖);可注入evalRemember接 mneme(service.update(entry, { actor: 'autoDream' }))
# cordis.patch.yml 的 config(或 DEFAULT_CONFIG)
evalLoopEnabled: true
evalStateDirs:
- /Users/me/my-workspace/.agent-teams
evalPollMs: 30000
# 可选注入:evalGetTrajectory / evalVerify / evalRemember / evalMinConfidence / evalRequireVerification// 状态工具
plugin_hub_eval_status // 闭环是否开启、已处理任务数、最近扫描、错误lib/eval-adapters.js 把闭环的依赖注入点接到共享 tools registry 的真实插件工具上,不改任何被接入插件的源码:
- ④ 记忆沉淀:探测 mneme 的
memory_save工具 → 写入 mneme(type: project,标题[任务经验] …,tags 带eval-loop+ 任务 id,source 记录eval-loop:autoDream:<taskId>溯源);mneme 未装配或调用失败 → 自动回退本地 JSONL(~/.dsh/plugin-hub/eval-entries.jsonl),不阻断闭环 - ② 观测:探测 trajectory-debug 的
trajectory_*工具取轨迹摘要;未装 →null(eval-loop 自动降级) - ③ 验证:
evalVerifyEnabled: true时探测 llm-verifier(verifier_compare),映射{ score, confidence };默认关闭(实验性,需后端配置)
# 默认已接好,无需额外配置;仅需开启闭环 + 状态目录
evalLoopEnabled: true
evalStateDirs:
- /Users/me/my-workspace/.agent-teams
# 可选:evalVerifyEnabled: true # 接 llm-verifier 验证环节(实验性)
# 可选注入覆盖:evalRemember / evalGetTrajectory / evalVerifykoishi/cordis 生态插件经 shim + 适配层 接入 DSH,市场目录已上架两个桥接商品(均标 Experimental + BRIDGE,平台不背书):
| 商品 | 包 | 作用 |
|---|---|---|
koishi-bridge |
@lanbaolu/dsh-koishi-bridge |
适配层 bundle:把 koishi-plugin-* 经 shim 别名加载进 DSH(单条失败不阻断) |
koishi-shim |
@lanbaolu/dsh-koishi-shim |
koishi 包名别名(L0/L1:Schema/makeArray/segment),让 koishi 插件 require('koishi') 可解析 |
装配三步(详见 dsh-koishi-bridge/README.md):
- profile
dependencies加别名"koishi": "npm:@lanbaolu/dsh-koishi-shim@^0.1.0" - 装入目标 koishi 插件(如
koishi-plugin-dialogue) dsh-koishi-bridge的cordis.patch.yml配置plugins列表
合规:源码形态 koishi 插件用 verify-plugin --koishi 兼容校验(门槛级 Compliant,非 DSH 原生合规);桥接内容默认 Experimental,评审核过才升 Verified。