A2 · Cordis 内核五概念:Context / Service / Event / Effect / Inject

A2 · Cordis 内核五概念:Context / Service / Event / Effect / Inject

developer preview :API 可能变更。Cordis 以 vendored 形式位于 vendor/cordis,本文路径以该目录为准。

1. 五个核心概念速览

dsh 的底层框架是 Cordis。理解以下五个概念,就理解了 dsh 的扩展机制:
#mermaid-svg-7wJBp3OtRB8ClvwZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7wJBp3OtRB8ClvwZ .error-icon{fill:#552222;}#mermaid-svg-7wJBp3OtRB8ClvwZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7wJBp3OtRB8ClvwZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .marker.cross{stroke:#333333;}#mermaid-svg-7wJBp3OtRB8ClvwZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7wJBp3OtRB8ClvwZ p{margin:0;}#mermaid-svg-7wJBp3OtRB8ClvwZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .cluster-label text{fill:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .cluster-label span{color:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .cluster-label span p{background-color:transparent;}#mermaid-svg-7wJBp3OtRB8ClvwZ .label text,#mermaid-svg-7wJBp3OtRB8ClvwZ span{fill:#333;color:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .node rect,#mermaid-svg-7wJBp3OtRB8ClvwZ .node circle,#mermaid-svg-7wJBp3OtRB8ClvwZ .node ellipse,#mermaid-svg-7wJBp3OtRB8ClvwZ .node polygon,#mermaid-svg-7wJBp3OtRB8ClvwZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .rough-node .label text,#mermaid-svg-7wJBp3OtRB8ClvwZ .node .label text,#mermaid-svg-7wJBp3OtRB8ClvwZ .image-shape .label,#mermaid-svg-7wJBp3OtRB8ClvwZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-7wJBp3OtRB8ClvwZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .rough-node .label,#mermaid-svg-7wJBp3OtRB8ClvwZ .node .label,#mermaid-svg-7wJBp3OtRB8ClvwZ .image-shape .label,#mermaid-svg-7wJBp3OtRB8ClvwZ .icon-shape .label{text-align:center;}#mermaid-svg-7wJBp3OtRB8ClvwZ .node.clickable{cursor:pointer;}#mermaid-svg-7wJBp3OtRB8ClvwZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .arrowheadPath{fill:#333333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7wJBp3OtRB8ClvwZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7wJBp3OtRB8ClvwZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7wJBp3OtRB8ClvwZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7wJBp3OtRB8ClvwZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .cluster text{fill:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ .cluster span{color:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7wJBp3OtRB8ClvwZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7wJBp3OtRB8ClvwZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-7wJBp3OtRB8ClvwZ .icon-shape,#mermaid-svg-7wJBp3OtRB8ClvwZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7wJBp3OtRB8ClvwZ .icon-shape p,#mermaid-svg-7wJBp3OtRB8ClvwZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7wJBp3OtRB8ClvwZ .icon-shape .label rect,#mermaid-svg-7wJBp3OtRB8ClvwZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7wJBp3OtRB8ClvwZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7wJBp3OtRB8ClvwZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7wJBp3OtRB8ClvwZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Cordis 内核五概念
declare module
等就绪再加载
emit/waterfall/...
teardown 自动撤销
通过 effect
Context

服务容器 ctx
Service

占据 ctx.key
Inject

依赖等待
Event

类型化通信
Effect

可逆注册
Plugin

apply(ctx)

  1. 插件(Plugin) :实现 Service 的对象,或带 apply(ctx) 的函数。
  2. 上下文(Context) :服务的容器,服务占据稳定的 ctx.<key>
  3. 注入(Inject):插件声明依赖的服务,等待其就绪才启动。
  4. 事件(Event):类型化通信通道,按模式分发(详见 A3)。
  5. 副作用(Effect):可逆注册,reload / teardown 时自动撤销。

2. Context:服务容器

Context 是 Cordis 的核心代理对象。服务通过 declare module 合并把自身挂到 ctx 上,其他插件按 key 查找而非 import 具体实现

ts 复制代码
// vendor/cordis/src/context.ts
export class Context {
  static readonly effect: unique symbol = symbols.effect
  static readonly isolate: unique symbol = symbols.isolate
  static readonly intercept: unique symbol = symbols.intercept
  extend(meta = {}): this { /* ... */ }
  isolate(name: string, label?: symbol) { /* ... */ }
  intercept<K extends InjectKey>(name: K, config: any): this
}

3. Service:占用一个 ctx key

每个服务是一个 Service 子类,构造时向 ctx.reflect.provide(name, self) 注册自身,占据稳定 key。

ts 复制代码
// vendor/cordis/src/service.ts
export abstract class Service<out T = never> {
  static readonly init: unique symbol = symbols.init
  static readonly check: unique symbol = symbols.check
  constructor(protected ctx: Context, name: string) {
    name ??= this.constructor['provide'] as string
    // ...
    self.ctx.reflect.provide(name, self, this[symbols.check])
  }
}

4. Inject:声明依赖,表达加载顺序

插件用 inject 声明所需服务;Cordis 在依赖就绪后才挂载它,加载顺序由依赖关系表达,而非手动编排

ts 复制代码
// vendor/cordis/src/registry.ts
export function Inject<K extends InjectKey>(name: K, config?: ...) { /* 装饰器 */ }
export class RegistryService {
  inject(inject: Inject, callback: Plugin.Function<void>) {
    return this.plugin({ inject, apply: callback, name: callback.name })
  }
}

5. Event:类型化、带模式分发

事件通过 TS 声明合并注册,再以 emit / parallel / serial / waterfall / bail 分发(详见 A3)。

6. Effect:可逆的副作用

所有注册(监听、工具、定时器)都通过 ctx.effect()ctx.on() 安装。一个 effect 返回 disposer,teardown 时按相反顺序执行。

ts 复制代码
// vendor/cordis/src/fiber.ts
export const enum FiberState { PENDING, LOADING, ACTIVE, FAILED, DISPOSED, UNLOADING }
export class Fiber {
  effect(execute: () => Effect, label = 'anonymous'): any { /* 返回 disposer */ }
}

7. 可运行示例:最小插件

ts 复制代码
// scratch-plugin/src/hello.ts
import type { Context } from '@deepseek-ai/cordis'

export const name = 'hello-plugin'
export function apply(ctx: Context) {
  ctx.effect(() => {
    const timer = setInterval(() => console.log('heartbeat'), 5000)
    return () => clearInterval(timer) // 卸载时自动清理
  })
}

加载方式见 A4(通过 --patch)。

8. 核心术语中英对照

中文 英文 说明
上下文 Context 服务容器
服务 Service 占用 ctx.<key> 的单例
注入 Inject 声明服务依赖
事件 Event 类型化通信通道
副作用 Effect 可逆注册,返回 disposer
纤维 Fiber 插件运行时实例

9. 官方文档 vs 源码 对照表

主题 官方文档 精确源码路径
Cordis 入门 reference/cordis-primer docs/cordis-primer.md
Context 类 --- vendor/cordis/src/context.ts
Service 基类 --- vendor/cordis/src/service.ts
插件加载 / 注入 --- vendor/cordis/src/registry.ts
Effect 生命周期 --- vendor/cordis/src/fiber.ts

10. 一句话小结

Cordis 把「能力」抽象为「占据 ctx key 的服务 + 类型化事件 + 可逆 effect」,dsh 的全部可替换性都建立在这三件套之上。

相关推荐
头茬韭菜6 天前
DeepSeek Harness 技术文档系列
herness
无心水1 个月前
【全域智能营销实战】10、三大引擎协同工作流:从用户消息到智能决策的完整链路
人工智能·springai·openclaw·顶尖架构师·全域智能营销·harmess·herness