$dshubuser@dshub:~/plugins$
  • 插件
  • 提交插件
  • 博客
组合与热重载(HMR):导入新模块,回卷旧 Fiber,再激活替换
2026/08/28

组合与热重载(HMR):导入新模块,回卷旧 Fiber,再激活替换

理解稳定 id、配置组和 Cordis HMR 的卸载—重载流程,并学会定位始终停在 PENDING 的插件。

HMR 的真实流程:保存文件 → 导入替换模块 → 旧插件卸载并回卷 effect → 注册替换 → 依赖满足后激活。

如果只把 HMR 理解成“重新 import”,就会漏掉最重要的部分:旧实例必须先失去所有运行时副作用。

01 / 配置项是可比较的运行时节点

Cordis HMR comparing configuration rows by id and selecting only changed plugin nodes

配置项可以带稳定身份:

- id: logger
  name: '@deepseek-ai/cordis-plugin-logger-console'
- id: timer
  name: '@deepseek-ai/cordis-plugin-timer'
- id: hmr
  name: '@deepseek-ai/cordis-plugin-hmr'
  config:
    root: ['.']
- id: hello
  name: './hello.ts'

id 让 Loader 在 cordis.yml 改动后区分保留、卸载和重新配置的行。没有 id 的行每次读取都可能得到新身份,从而被当作先删后加。

group 可以让一组配置作为单元装卸,isolate 可以让组拥有独立的服务实例。

这个 HMR 示例还依赖 timer 服务,并需要 Node 的 loader 内部接口;它是服务端 Node HMR,不等同于浏览器端的 client-plugin HMR。

02 / HMR 先导入替换,再卸载旧实例

Cordis HMR cycle from file save through old Fiber disposal to new plugin activation

@deepseek-ai/cordis-plugin-hmr 监视文件变化:

  1. 文件保存后,HMR 判断变化属于配置、插件模块还是框架外部文件。
  2. 对于插件模块变化,HMR 先导入替换模块。
  3. 需要重载的旧 runtime 被卸载,所有 effect 先回卷。
  4. 替换模块随后注册并运行 apply。
  5. 如果它依赖的服务尚未就绪,新 Fiber 会停在 PENDING,而不是半启动。

外部或框架文件不是单个插件的重载单位;这类变化会让 Loader 退出,由宿主重新启动。

因此修改 hello.ts 可以看到旧输出停止,新输出出现;修改配置则由 Loader 按 id 进行局部更新。

03 / 为什么 HMR 也可能“没反应”

有两类问题要分开:

  • 路径或包名拼写错误属于解析问题,先检查 name 和日志。
  • 依赖没有 provider 时属于合法的 PENDING,插件不会输出,也不会抛异常。

可以通过注册表观察 Pending Fiber:

import { FiberState } from '@deepseek-ai/cordis'

for (const runtime of ctx.registry.values()) {
  for (const fiber of runtime.fibers) {
    if (fiber.state === FiberState.PENDING) {
      console.log(fiber.name + ' is PENDING')
    }
  }
}

04 / HMR 的安全边界

HMR 只能可靠地撤销已经注册为 effect 的资源。事件监听器、服务注册和子插件由 Cordis 管理;自建定时器、连接和 watcher 必须在 ctx.effect() 中返回 disposer。

如果资源逃离 Fiber,重复保存文件就可能留下重复监听器或旧连接。所谓“热重载安全”,首先是所有权清晰,其次才是 watcher 是否能检测到文件。

05 / DSH 为什么把 HMR 放进基础组合

dsh-base 的配置中包含 timer 与 HMR 插件,profile 在此基础上继续叠加模型、工具、会话和 Agent 能力。修改插件时,运行中的 dsh 可以沿用同一套卸载—重载语义,而不是为每个能力写一套刷新逻辑。

headless 和 web overlay 会禁用服务器 HMR;浏览器端的 client-plugin HMR 是独立链路,不能用这套 Node watcher 的行为推断它。

下一步

  • cordis.yml:配置文件组合应用
  • 生命周期与 effect:可逆的注册
  • Cordis 在 DeepSeek Harness 里

来源:组合与 HMR 教程、HMR 插件、dsh-base 配置。

全部文章

作者

avatar for DSH Research
DSH Research

分类

  • Agent 基础设施
01 / 配置项是可比较的运行时节点02 / HMR 先导入替换,再卸载旧实例03 / 为什么 HMR 也可能“没反应”04 / HMR 的安全边界05 / DSH 为什么把 HMR 放进基础组合下一步

更多文章

生命周期与 effect:让 Cordis 注册可以回卷
Agent 基础设施

生命周期与 effect:让 Cordis 注册可以回卷

跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。

avatar for DSH Research
DSH Research
2026/08/24
inject:让依赖决定加载顺序,而不是 YAML 行号
Agent 基础设施

inject:让依赖决定加载顺序,而不是 YAML 行号

理解 Cordis 的 PENDING、依赖跟踪和可选服务探测,解释为什么 provider 更换会自动带动 consumer。

avatar for DSH Research
DSH Research
2026/08/23
Cordis 在 DeepSeek Harness 里:一切皆插件如何落地
Agent 基础设施

Cordis 在 DeepSeek Harness 里:一切皆插件如何落地

从 dsh-base、Context 服务、事件域和工具流水线出发,理解 Cordis 如何组织一个可替换的 Agent 运行时。

avatar for DSH Research
DSH Research
2026/08/29

邮件列表

加入我们的社区

订阅邮件列表,及时获取最新消息和更新

[dshub] [zsh]$ dshub ls$ dshub submit$ dshub blog
-- NORMAL -- ✓ 2026 dshub