基于官方 7 讲中文教程(deepseek-harness docs/cordis-tutorial/)与本地快速入门项目整理,以实例驱动,方便边学边练。 概念速览见 cordis。

Cordis 是什么

Cordis 是一个「时空可组合性」插件元框架,DeepSeek Harness 的底座:

  • 可逆 effect(时间维度):插件运行时插拔,卸载时全部副作用自动回滚,无需重启宿主进程
  • 响应式 coeffect(空间维度):插件用 inject 声明依赖,依赖就绪自动加载、消失自动卸载、恢复自动复活
  • 核心不到 2,000 行 TS,同一设计已在 Koishi 生产环境跑 4 年(4000+ 插件)

前置要求

  • Node.js >= 20(开发机验证于 v24)
  • TypeScript 基础(插件用 .ts 写,靠 tsx 直接运行,无需编译步骤)
  • 无需任何 API 密钥:前 7 课全部离线可跑

练习环境

两种方式,推荐方式一(已验证通过):

方式一:直接用快速入门项目

cd ~/tmp/proj/cordis
npm install
npm start          # 聚合演示:一次跑完全部课程插件

方式二:从官方教程环境起步

git clone https://github.com/deepseek-ai/deepseek-harness
cd deepseek-harness && pnpm install
# 在 tmp/cordis-tutorial/ 下写代码,用下面命令运行每章示例
node --import tsx ../../vendor/cordis/bin.js

启动器 bin.js 做三件事:创建根 Context → 挂 Loader → Include 插件读取 cordis.yml。注意 Include 会把 baseUrl 重置为 yml 所在目录,所以 yml 里的 './xxx.ts' 相对 yml 自己解析,与运行目录无关。

学习路径(建议顺序)

章节内容关键概念对应命令
01-first-plugin环境 + 第一个插件 + 启动器原理插件即函数、cordis.ymllesson:01
02-lifecycle-effect生命周期与可逆 effectdisposer、fiber.dispose()lesson:02
03-services服务提供与依赖消费Service 子类、injectlesson:03
04-events类型化事件五种模式emit、waterfall 短路lesson:04
05-config-diagnose配置校验 + PENDING 诊断Config schema、fiber 状态机lesson:05/06
06-composition-hmr条目元数据与热替换id/disabled/组/isolate、HMRlesson:07
07-into-harness进入真实 harness:注册工具defineTool、tools/result 事件官方环境

每章对应快速入门项目的一课(npm run lesson:0X),先读代码、再运行、最后做「动手练习」。

概念速查(读代码前 2 分钟)

  1. 插件是实现 Service 的对象:函数(apply(ctx),最常见)/ 对象(带 apply)/ 类(Service 子类)三种形态。可选导出 name(诊断标识)、inject(依赖)、Config(配置 schema)。
  2. Context 是服务容器:服务占据稳定的 ctx.<key>,消费方按 key 查找而非 import 实现 → 配置层可换提供方。
  3. inject 声明依赖:插件停在 PENDING 直到依赖就绪;加载顺序由依赖决定,与 yml 书写顺序无关。
  4. 事件五种分发模式:emit(同步广播)/ parallel(并发等待)/ serial(按序取首个有效返回)/ bail(serial 同步版)/ waterfall(环绕中间件)。waterfall 纪律:只观察的监听器必须调 next(),不调即有意短路。
  5. 注册是可逆副作用:ctx.on()、ctx.plugin()、服务注册本身都是 effect,随插件卸载撤销;框架外的资源(定时器/连接)自己包 ctx.effect() 并返回 disposer。

Fiber 状态机:PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED(或 FAILED)。

常见问题速查

现象排查
插件没输出也没报错遍历 ctx.registry 看 fiber 是否卡在 PENDING(缺服务),见第 03 章
HMR 报 --expose-internals is required启动命令加 --expose-internals flag
yml 里相对路径找不到模块路径相对 yml 所在目录,不是运行目录
编辑 yml 后插件全部重挂条目没写 id,每次读取都视为删了重挂;加 id 即可按 diff 只动变化项

参考链接