DSH plugin 热重载怎么做?cordis.yml 组合、HMR 与 PENDING 诊断
DSH plugin 的热重载机制是「先卸载、再加载」:cordis.yml 选择要应用的插件树,@deepseek-ai/dsh-hmr 监视文件并在保存时用卸载(释放 effect)+ 依赖驱动加载替换正在运行的插件。 想精确热换要给配置项加 id;插件一直不加载又不报错,通常是 inject 的服务没有提供方、fiber 停在 PENDING。
DSH plugin 的 cordis.yml 怎么组合插件树:id、disabled 与组
cordis.yml 才是决定应用哪些插件的地方——每项能力都是插件,这份配置选择插件树(来源)。 配置项除 name 与 config 外还接受其他元数据:
- id: greeter # stable identity for this entry
name: './greeter.ts'
- id: consumer
name: './consumer.ts'
disabled: true # keep the entry, skip mounting it
id提供稳定标识 — 让 loader 区分「修改现有项」与「先删除再添加」。预期:改配置时只重挂受影响部分。disabled: true卸载但不删除 — 保留配置项、跳过挂载。预期:改回原值后插件恢复,且因依赖其服务而 PENDING 的插件也会重新加载。- 组可嵌套子列表 — 把一组配置项作为一个单元加载与卸载。预期:整组一起上下线。
isolate提供独立服务实例 — 为组隔离某项服务的实例。预期:两个组各自看到配置不同的同名提供方,互不影响。
关键因果:不带 id 的配置项在每次读取时都会获得一个新生成的 id,所以只要配置文件发生任何编辑,即使自身文本未变,它也会被视为先删除再添加并重新挂载。
DSH plugin 怎么热重载:dsh-hmr 的卸载与重新加载
HMR 之所以成立,是因为卸载会释放 effect、加载会遵循依赖关系,于是「先卸载、再加载」就能替换正在运行的插件(来源)。 按下面四步配置并验证:
- id: logger
name: '@deepseek-ai/cordis-plugin-logger-console'
- id: timer
name: '@deepseek-ai/cordis-plugin-timer'
- id: hmr
name: '@deepseek-ai/dsh-hmr'
config:
root: ['.']
- id: hello
name: './hello.ts'
- 在
cordis.yml里挂上@deepseek-ai/dsh-hmr,并把config.root设为要监视的目录(如['.'])。预期:保存文件后旧实例先卸载、新代码随后加载。 - 同时挂上
@deepseek-ai/cordis-plugin-logger-console,让 HMR 通过 Cordis logger 服务记录日志。预期:能看到卸载 / 加载的消息;缺了控制台导出器就完全看不到输出。 - 同时挂上
@deepseek-ai/cordis-plugin-timer,HMR 靠它inject的timer服务做去抖。预期:插件不会卡在 PENDING;缺了 timer 会永远停在 PENDING 且不发出任何提示。 - 在 tsx 下启动并按需保存插件文件,例如运行
node --import tsx ../../vendor/cordis/bin.js。预期:旧实例的所有 effect 回卷,新代码加载、apply再次运行;编辑cordis.yml本身也会按id只更新变化的部分。
想先弄懂 effect 与卸载回卷,回看 DSH plugin 事件系统。
DSH plugin 卡在 PENDING 怎么诊断:inject 无提供方
如果插件的 inject 指定了无人提供的服务,它会一直等待、不输出任何内容——这不是错误,因为 PENDING 是合法状态,提供方可能稍后才挂载(来源)。 按下面四步定位:
import { FiberState, type Context } from '@deepseek-ai/cordis'
export const name = 'diagnose'
export function apply(ctx: Context) {
setTimeout(() => {
for (const runtime of ctx.registry.values()) {
for (const fiber of runtime.fibers) {
if (fiber.state === FiberState.PENDING) {
console.log(`${fiber.name} is PENDING — a required service is missing`)
}
}
}
}, 500)
}
- 先确认现象是「既不执行、也不报错」,排除会抛错的那类故障。预期:终端里没有错误栈,进程仍在运行。
- 在任意上下文里遍历注册表:对
ctx.registry.values()以及每个runtime.fibers逐个检查。预期:拿到全部插件的 fiber 及其状态。 - 筛选
fiber.state === FiberState.PENDING的 fiber。预期:打印出卡住等待的插件名,说明它inject的某个必需服务没有提供方。 - 补上该服务的提供方,或去掉对应的
inject。预期:fiber 从 PENDING 转为 ACTIVE 并开始执行。
不加 PENDING 过滤条件迭代时还会看到 loader 自身的插件(Loader、Include)处于 ACTIVE,因为配置文件本身也是通过插件挂载的。
写完自检三项(对任何 DSH插件 都适用):常用插件是否都写了 id;HMR 的 logger / timer 依赖是否齐;出现「没反应」时是否先看了 fiber 状态。想把这套诊断用在真实服务上,见 Cordis 入门;想找现成的日志 / 定时类插件,可在 DSH Plugin Hub 检索。
常见问题
DSH plugin 用 cordis.yml 选择插件树,id 为配置项提供稳定标识,让 loader 能区分「修改现有项」与「先删后加」;disabled: true 会卸载插件但保留配置项。改回原值后,插件以及因依赖其服务而处于 PENDING 的插件都会重新加载。
DSH plugin 在 cordis.yml 里挂上 @deepseek-ai/dsh-hmr 并配置 root 监视目录即可热重载;HMR 通过 logger 服务记录日志,所以没有 @deepseek-ai/cordis-plugin-logger-console 就看不到消息。它还 inject timer 服务做去抖,缺少 @deepseek-ai/cordis-plugin-timer 时会一直停在 PENDING。
会触发重新加载:DSH plugin 的 loader 按 id 比较配置项,只挂载、卸载或重新配置发生变化的部分。没有 id 的配置项每次读取都会获得新生成的 id,所以只要配置文件有任何编辑,即使自身文本没变也会被当作先删除再添加并重新挂载。
DSH plugin 若 inject 指定了无人提供的服务,就会一直等待而不输出任何内容,因为 PENDING 是合法状态。此时应检查该插件的 fiber 状态:遍历 ctx.registry.values() 与 runtime.fibers,看到 FiberState.PENDING 就说明有必需服务缺失。
DSH plugin 的组可以嵌套一份配置项子列表,把多个插件作为一个单元加载与卸载;isolate 则为组提供某项服务名称的独立实例。这样两个组可以各自看到配置不同的服务提供方而互不影响。
相关术语
- cordis.yml
- cordis.yml 是 DSH plugin 的插件树配置来源,用 id、name、config、disabled 等字段决定应用哪些插件、以什么顺序组合,装载器按 id 比较差异并热更新。— https://deepseek-harness.github.io/deepseek-harness/develop/cordis-tutorial/06-composition-and-hmr
- HMR
- HMR 即热模块替换,是 DSH plugin 在文件保存后先卸载旧实例、再加载新代码的机制,由 @deepseek-ai/dsh-hmr 监视文件触发,卸载会回卷该插件的全部 effect。— https://deepseek-harness.github.io/deepseek-harness/develop/cordis-tutorial/06-composition-and-hmr
- FiberState.PENDING
- FiberState.PENDING 是 DSH plugin 的插件纤维状态之一,表示插件在等待某个必需服务,属于合法状态而非错误,通常在 inject 的服务没有提供方时出现。— https://deepseek-harness.github.io/deepseek-harness/develop/cordis-tutorial/06-composition-and-hmr
- isolate
- isolate 是 DSH plugin 的组级配置,为某个组提供某项服务名称的独立实例,使不同组能看到配置不同、互不影响的同名服务提供方。— https://deepseek-harness.github.io/deepseek-harness/develop/cordis-tutorial/06-composition-and-hmr
来源
- DeepSeek Harness 官方文档 - Cordis 教程:组合与 HMR· deepseek-ai
- DeepSeek Harness 官方文档 - Cordis 入门· deepseek-ai