Skip to content

DeepSeek Harness 不从 npm 拉取 Cordis 插件框架。相反,vendor/ 存放 Cordis 及其基础库的源码拼接副本,改名为 @deepseek-ai 作用域并作为 workspace 包钉住。这让 harness 完全拥有它的框架层——可审计、可打补丁、可发布——并在构建 agent harness 时针对真实遇到的缺陷加以加固。

为何拼接

vendor/README.md 直白地陈述契约:这些副本之所以放在这里而不是经 npm 依赖,是为了让 harness 完全拥有其框架层。随之而来的三个推论:

  • 改名为 @deepseek-ai 作用域——cordis → @deepseek-ai/cordis@cordisjs/plugin-* → @deepseek-ai/cordis-plugin-*。每个 harness 包都把 cordis 声明为 peer 依赖,因此发布 harness 也就发布了框架层;若按上游名发布则在注册表上侵权。
  • pnpm-workspace.yaml#linkWorkspacePackages: true 使保留下来的 semver 范围解析到这些钉住的 workspace,包括从构建出的 lib/ 导入。两个包另经 overrides 强制链接:@deepseek-ai/cosmokit@deepseek-ai/schemasterylink:vendor/…

卫生门禁 verify-vendored-links 断言每个拼接名的 pnpm-lock.yaml 都解析为 workspace 的 link:,且旁边没有注册表副本。rescope-vendor.ts 在一次上游同步后重新执行 @deepseek-ai 改名。

拼接包名册

目录npm 名(vendor/*/package.json上游原名在 dsh 中的作用
cordis/@deepseek-ai/cordiscordis核心 DI/插件元框架——ContextServiceFiber、生命周期、注入
cosmokit/@deepseek-ai/cosmokitcosmokit通用工具(random、path、promise 辅助),跨族使用
schemastery/@deepseek-ai/schemasteryschemastery类型驱动 schema 校验器(z.object,…),用于每个插件 Config
loader/@deepseek-ai/cordis-plugin-loader@cordisjs/plugin-loader运行时插件 loader,持有 EntryTree;导入插件并应用配置
include/@deepseek-ai/cordis-plugin-include@cordisjs/plugin-include文件支撑的 loader 树:读 YAML/JSON 配置为条目,写回更新
group/@deepseek-ai/cordis-plugin-group@cordisjs/plugin-group嵌套插件组 / 条目嵌套
hmr/@deepseek-ai/cordis-plugin-hmr@cordisjs/plugin-hmr热重载:监视源码、清模块缓存、只重载受影响的插件条目
logger-console/@deepseek-ai/cordis-plugin-logger-console@cordisjs/plugin-logger-console内置 logger 服务的控制台导出器
timer/@deepseek-ai/cordis-plugin-timer@cordisjs/plugin-timer可 dispose 的定时器服务(挂载于 base/spine 组合;schedule/提醒功能用它——dsh-schedule 运行自己的 setTimeout 循环)

每个库在代码中的作用

  • cordis——地基。一切皆插件:agent、LLM 层、工具与会话运行时都是 Cordis Service,登记为 ctx.*vendor/cordis/src/fiber.ts 携带最重要的本地加固(见下)。站点的 Cordis 入门深入讲解它。
  • schemastery + cosmokit——插件 Config schema 写成 z.object({…})(schemastery),cosmokit 提供工具。cordis 自身用 cosmokit 与 schemastery。
  • loader——把条目列表(cordis.yml)变成运行中插件图的 EntryTreedsh 的配置系统(profile bundle、cordis.patch.yml--patch 覆盖层)建立在 Loader + Include 之上。
  • include——以配置文件为后端的 loader 树;include 定义让用户配置覆盖默认值的补丁层。为 dsh 的事务化配置重载语义做了大量打补丁。
  • hmr——监视文件,只重载依赖某变更应用文件的插件条目;框架级变更回退到 loader.exit()(进程重启)。
  • group——嵌套组,使条目可以挂载子项。
  • timer——可 dispose 的定时器,挂载于 base/spine 组合。(schedule 特性建立在它之上:@deepseek-ai/dsh-schedule 运行自己的 setTimeout/clearTimeout 循环。)
  • logger-console——把内置 logger 路由到控制台;ACP 服务器刻意挂载它,使 stdout 保持协议纯净。

如何被消费

每个 harness 包把 @deepseek-ai/cordis(以及有时还有插件兄弟)声明为 peer 依赖pnpm-workspace.yaml#linkWorkspacePackages 与 cosmokit/schemastery 的 overrides 把它们钉到拼接 workspace。消费者如同导入普通作用域包一样使用它们:

ts
import type { Context } from '@deepseek-ai/cordis'
import Timer from '@deepseek-ai/cordis-plugin-timer'
import z from '@deepseek-ai/schemastery'

拼接包的第三方依赖(如 @standard-schema/specjs-yamlchokidarpicomatch)留在 npm 上,不拼接。

本地修改:诚实且深入

vendor/README.md 维护一份穷尽的本地修改日志——每一处与上游的差异。值得注意的 dsh 专项加固:include/group/loader 的事务化配置对账(回滚实时更新、串行子树变更)、hmr 的精确配置监视与串行化刷新(含死锁修复)、引入上游 PR cordiverse/cordis#41(惰性配置解析),以及 cordis/src/fiber.ts生命周期加固——它补上三个可重入 dispose 漏洞:在 setup 体运行前登记 effect 的 owner-list 包装器、异步清理等待静止(quiescence)、在 owner 处于 UNLOADING 时拒绝创建 effect。

这些条目会引用下游测试,让评审者能找到覆盖。例如,Include 的串行化写入与 HMR 扫描抑制加固“Covered by the patch-overlay boot-failure built-bin case in apps/cli/tests/built-bin.e2e.ts”,持久化的 Include 写入则由“packages/host/directory-picker-auto/tests/loader-composition.spec.ts with injected transient and terminal rename failures”覆盖。有些修改纯属务实——重新生成的 package.json/tsconfig.json、为双 ESM+CJS 输出提供的逐包 tsdown.config.ts 覆盖(schemastery、logger-console),以及补充 @param/@returns JSDoc 以便网站 API 参考生成器能干净地报错。

vendor/ 下的 AGENTS.md 警示贡献者:不要随意改动 vendor/*/src/;每处本地差异都必须穷尽地记入 vendor/README.md。这正是让拼接层在跨同步时可审计的关键。

作为 peer 依赖被消费

因为每个消费者都把框架声明为 peer(这样发布时会解析到已发布的 scoped 名),挂载某个 Cordis 插件的包就会在自己的 package.json 里这样声明。不变量服务是个典型例子:

jsonc
// packages/runtime-diagnostics/invariants/package.json(节选)
"peerDependencies": {
  "@deepseek-ai/cordis": "workspace:^"
},
"dependencies": {
  "@deepseek-ai/schemastery": "workspace:^"
}

注意分工:cordispeer(其类型面定义 Context),而 schemastery 只是本包 Config schema 用到的普通 dependency

同步流程

要从上游刷新某个拼接包,README 规定:记下上游 git rev-parse HEAD,复制包的 src/(以及 bin.js/README.md/LICENSE 若变动),重新应用本地修改(或若上游使其不再必要则删去——两种都要更新日志),更新清单表中的版本与 commit 哈希,然后 pnpm install && pnpm run test && pnpm run build。因此每处差异都带一个刻意的重新应用步骤,而非被静默合并。

@deepseek-ai 改名与 hygiene 保障

改名是被强制而非假设的。scripts/rescope-vendor.ts 重写每个拼接 manifest 的 name、内部依赖项与模块说明符为 scoped 名(一次同步后用 pnpm run rescope-vendor --apply 重新应用);pnpm run rescope-vendor:check 校验没有未 scoped 的引用泄漏回来。随后 hygiene 组合用 verify-vendored-links(每个名字解析为 link: workspace、无注册表副本)与 verify-cordis-config 确认整条链。因为 pnpm-workspace.yaml 设置了 linkWorkspacePackages: true,来自某包已构建 lib/ 的导入同样落在钉住的 workspace 源码上,而不是一次 npm 解析。

延伸阅读

  • 欢迎页——Cordis 入门了解框架如何被使用。
  • CI 与发布verify-vendored-linksrescope-vendorrelease(vendor) 族流程。
  • vendor/README.md— 完整清单、本地修改日志与同步流程。
  • pnpm-workspace.yaml— 钉住 workspace 的 linkWorkspacePackages / overrides 机制。
  • docs/cookbook/adding-a-vendored-package.md— 如何新增一个新的拼接包。
  • docs/rescope.md— 面向消费者的 @deepseek-ai 命名映射复述。