ByteNoteByteNote
vendored 包改名:一份映射表与四条命令
字

字节笔记本

2026年10月6日 · 约 9 分钟读完

vendored 包改名:一份映射表与四条命令

API中转
¥120

DeepSeek Harness 是 DeepSeek 开源的 agent 框架,以「一切皆插件」的架构构建在 Cordis 框架之上。Cordis 框架及其基础库不走普通 npm 依赖,而是以源码形式 vendored 在仓库的 vendor/ 目录下,发布时统一冠以 @deepseek-ai scope。这样做有很实际的原因:每个 harness 包都把框架声明为 peer dependency,发布 harness 就会连带发布这一层框架;如果沿用上游原名发布,等于在 npm registry 上占用别人的包名。于是这个仓库完成了一次系统性的改名(rescope),把九个 vendored 包全部迁到自有 scope 之下。本文整理这次改名沉淀下来的一份映射表、七类刻意保持不变的标识、代码需要修改的四处位置,以及施加、核验与回退的完整命令链。

vendored 包改名映射:上游名到发布名

一份映射表:九个包的新名字

改名覆盖框架核心、基础工具和七个 Cordis 官方插件,规律很统一:上游叫什么,发布名就换成 @deepseek-ai 加上语义化的前缀。

上游名发布名版本角色
cordis@deepseek-ai/cordis4.0.0-rc.7框架核心:Context、Service、Fiber 与事件
cosmokit@deepseek-ai/cosmokit1.8.1框架与 Schemastery 共用的基础工具
schemastery@deepseek-ai/schemastery3.18.0配置 schema,每个插件的 Config 都基于它
@cordisjs/plugin-loader@deepseek-ai/cordis-plugin-loader1.0.0-rc.5cordis.yml 装载、插件解析、repository 缓存
@cordisjs/plugin-include@deepseek-ai/cordis-plugin-include1.0.4配置包含与 patch 叠加
@cordisjs/plugin-group@deepseek-ai/cordis-plugin-group1.0.0嵌套插件分组
@cordisjs/plugin-timer@deepseek-ai/cordis-plugin-timer1.1.2ctx 上随 disposal 回收的定时器
@cordisjs/plugin-hmr@deepseek-ai/cordis-plugin-hmr1.0.15插件与配置的热替换
@cordisjs/plugin-logger-console@deepseek-ai/cordis-plugin-logger-console1.0.0控制台日志导出

子路径导出同样保持原路径结构,例如 @cordisjs/plugin-loader/repository 对应改成 @deepseek-ai/cordis-plugin-loader/repository,只换包名,不动路径。

七类刻意保持不变的东西

改名只动包名,下面这些一概不碰:

  • 目录名与版本号。 vendor/hmr/ 仍然是 vendor/hmr/,每个包保留映射表里记录的上游版本,vendored 目录树依旧读作一份上游快照,随时可以和上游逐行对照。
  • 依赖 range。 依赖条目只换键、不换范围:"cordis": "^4.0.0-rc.7" 变成 "@deepseek-ai/cordis": "^4.0.0-rc.7"。linkWorkspacePackages 正是靠这些保留下来的范围,把依赖解析到仓库内固定的 workspace。
  • cordis: 内建前缀。 cordis:include、cordis:group 是 loader 的协议前缀,不是包名,不在改名范围内。
  • cordis.yml 配置文件家族。 包括 *.cordis.yml、*.cordis.snapshot.yml、cordis.patch.yml,文件名一个不改。
  • 名字里带这个词的 harness 包。 例如 @deepseek-ai/dsh-tool-cordis,它的 cordis 指的是技术栈归属,不是那个框架包。
  • 上游运行时标识符。 例如 Schemastery 的 Symbol.for('schemastery') 及其 vendor: 元数据字段,这类标识参与运行时识别,动了会出问题。
  • docs/ 之外的散文。 各 vendored 包自己的 README 保留写作当时的名字,那里的裸 cordis 也可能是 Python SDK 的选项名或某个 agent preset 的 id;而在 docs/ 之内,散文与所有 Markdown 代码围栏则全部跟着改。

代码要改的四处

位置改前改后
模块 importimport { Context } from 'cordis'import { Context } from '@deepseek-ai/cordis'
类型事件声明合并declare module 'cordis'declare module '@deepseek-ai/cordis'
package.json 依赖键"@cordisjs/plugin-hmr": "^1.0.15""@deepseek-ai/cordis-plugin-hmr": "^1.0.15"
cordis.yml 插件条目name: '@cordisjs/plugin-include'name: '@deepseek-ai/cordis-plugin-include'

rescope-vendor 命令链:施加、核验与回退

施加、核验与回退

整份映射由仓库里的 rescope-vendor 脚本承载并执行,所有引用的改写都不靠手改。四条命令各管一段:

sh
pnpm run rescope-vendor            # 先报告将改什么
pnpm run rescope-vendor --apply    # 改写全部引用
pnpm run rescope-vendor:check      # 断言后置状态,挂在 hygiene gate
pnpm run rescope-vendor --apply --reverse   # 回退到上游名

不带参数先跑一遍,得到的是即将发生的改动报告,此时什么都没写盘;加 --apply 才真正落盘;rescope-vendor:check 在卫生闸门(hygiene gate)里断言改名后的状态,一旦有人手工改动引入漂移就会被拦下;--reverse 则把整棵 vendored 树还原成上游名字,改错了有后悔药。

上游同步之后要重跑一遍改名,并接上脚本打印的再生成步骤:pnpm install 重生成 lockfile,pnpm run gen-third-party-notices 更新第三方声明,再对触及的双语文件对跑 pnpm run verify-translation-pairing --write,保证文档与代码不脱节。

这套做法的价值不止于改名本身:映射收敛在一个脚本里,不变量交给 check 命令守卫,改名这种牵一发动全身的全局操作,就变成了可施加、可核验、可回退的普通工程步骤。维护任何带 vendored 依赖的 monorepo,都值得照这个样子搭一套自己的机制。

相关文章

分享: