Remotion 版本发布全流程解析:release Skill 清单背后的 set-version 与 publish 实现
本文基于 Remotion 仓库内的智能体技能文档 .agents/skills/release/SKILL.md,完整拆解一次 Remotion 4.x 版本发布的标准作业流程:从环境校验、NPM 令牌创建、版本号递增、Lambda 烟雾测试,到多包并发发布、模板仓库同步与 Changelog 生成。读完后,你既能拿到一份可直接执行的发布检查单,也能理解每个步骤背后 set-version.ts、publish.ts 与 release-package-policy.ts 等源码的实现细节与失败中止条件。
一、release Skill 是什么:给 AI Agent 的发布检查单
.agents/skills/release/SKILL.md 是 Remotion 仓库为 AI 编码代理(如 Codex)定义的"发布新 Remotion 版本"技能,frontmatter 仅两行元信息:
---
name: release
description: Release a new Remotion version
---
正文是一条按顺序执行的操作清单。它的设计思路很典型:把人类发布工程师脑子里的"发布肌肉记忆"固化为可被 Agent 逐步执行的确定性步骤,每一步都明确了失败时的处理策略(立即中止 / 等待修复 / 等待人工审批)。整个流程可以归纳为七个阶段:
| 阶段 | 核心命令 | 失败策略 |
|---|---|---|
| 环境清理与校验 | 杀掉 turbo 进程、gcloud auth print-access-token |
校验失败则不继续 |
| NPM 凭证准备 | npm login + 1Password 取密码/OTP + npm token create |
人工完成 2FA |
| 构建 | bun i、bun run build |
— |
| 版本号递增 | bun set-version.ts <version> |
退出码非 0 立即中止 |
| Lambda 烟雾测试 | cd packages/example && sh runlambda.sh |
失败则中止 |
| 发布 | NPM_CONFIG_TOKEN=<token> bun run release、bun run publishtemplates |
模板发布失败则停止并上报 |
| Changelog 生成 | git log + gh CLI |
发布前必须人工审批 |
二、阶段一:环境清理与三项前置校验
2.1 杀掉残留的 turbo 进程
清单第一步要求:以 SIGKILL 杀掉任何可能正在运行的 turbo 进程。仓库根 package.json 中大量脚本基于 Turborepo(如 "build": "turbo run make --no-update-notifier"),构建进程如果残留,可能占用 dist 产物或缓存目录,干扰发布构建,因此必须先清理。
2.2 校验 gcloud 登录态
发布流程涉及 Cloud Run 相关包的构建与部署验证,清单要求在开始发布前运行:
gcloud auth print-access-token >/dev/null
若失败则执行 gcloud auth login 后重新检查,检查不通过就不得继续发布。这是一个典型的"前置依赖显式断言"写法,避免流程进行到一半才发现云凭据过期。
2.3 Codex 环境的 Ruby 版本陷阱
这是清单中最有针对性的一条。Codex 可能以非交互式 shell 启动,PATH 中 /usr/bin 排在 ~/.rbenv/shims 之前,导致即使用户终端用的是 Ruby 3.3.x,发布命令里调用 Ruby/Bundler 时实际走的是系统的 Ruby 2.6。修复方式是显式把 rbenv 的 shims 目录提到 PATH 最前:
PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH" <command>
并用同样的方式验证 ruby --version 输出的是 rbenv 的 Ruby。
这条限制在仓库中有直接依据:packages/lambda-ruby/remotion_lambda.gemspec 声明了运行时依赖 json(> 2.0.0)、rexml 等 gem,其中 json 2.x 系列要求 Ruby >= 2.7。若发布链路中 Ruby 回落到 2.6,lambda-ruby 包的 gem 解析会直接失败。从 gemspec 与 packages/lambda-ruby/package.json 的版本号(均为 4.0.520)一致也可看出:Ruby SDK 的 gem 版本与 npm 包版本是锁定的,同一次发布必须同时满足两个生态的要求。
三、阶段二:NPM 凭证准备(登录、取密、建令牌)
3.1 登录与二次认证
清单要求先运行 npm login(2FA 由人工在浏览器中完成),然后通过 1Password CLI 获取两样东西:
# 密码
op item get "Npmjs" --fields password --reveal --account remotiondev.1password.com
# 一次性密码 OTP
op item get "Npmjs" --otp --account remotiondev.1password.com
把密码存进 shell 变量(如 $PASSWORD),后面用管道喂给 npm。
3.2 创建专用发布令牌
令牌创建命令是清单里信息密度最高的一条,参数逐项解释:
npm token create \
--name="PublishRemotionXXXXXX" \
--packages "remotion" \
--packages "create-video" \
--packages-and-scopes-permission read-write \
--bypass-2fa \
--scopes "@remotion" \
--otp=<otp>
--name中的XXXXXX要替换成随机字符串,保证每次发布生成的令牌名唯一,便于事后审计与吊销;--packages "remotion" --packages "create-video"加上--scopes "@remotion",把写权限收敛到核心包remotion、create-video与整个@remotionscope——即覆盖 monorepo 内所有以@remotion/*发布的包;--bypass-2fa配合--otp实现非交互式的 2FA 通过,因为npm token create过程中还需要输入密码,清单指定用echo "$PASSWORD" |管道传入;- 记好生成的 token 值,阶段六发布时要用。
四、阶段三:构建与版本号递增
4.1 安装与构建
bun i
bun run build
对照根 package.json 可见,build 实际是 turbo run make --no-update-notifier,即通过 Turborepo 对全部 workspace 包执行各自的 make 任务(仓库根 packageManager 为 bun@1.3.3)。
4.2 查询当前版本并递增
npm view remotion version # 得到线上最新版本号
bun set-version.ts <version> # <version> = 当前版本 + 1
清单明确:set-version.ts 退出码非 0 时,立即中止整个发布流程。以当前仓库为例,packages/core/package.json 中 "version": "4.0.520",下一次发布就应传入 4.0.521。
4.3 深入 set-version.ts:一个"递增版本号"命令到底改了什么
set-version.ts 并不只是改一行 version 字段,它是一条完整的"版本一致性"流水线:
-
分支断言:执行
git rev-parse --abbrev-ref HEAD,不在main分支直接抛错(set-version.ts#L29-L36)。 -
遍历
packages/下所有含 package.json 的目录(以及cloudrun/container),跳过FEATURED_TEMPLATES中声明的模板目录——模板有独立的版本同步机制(见第六节);同时删除各包的tsconfig.tsbuildinfo旧构建信息。 -
发布策略过滤:对每个包调用 release-package-policy.ts 的
shouldReleasePackage()。该策略维护了一个"v5 将移除的包"名单:export const packagesRemovedInV5 = [ '@remotion/light-leaks', '@remotion/media-parser', '@remotion/starburst', '@remotion/webcodecs', ] as const;逻辑是:若发布主版本号 < 5,这些包照常发布;一旦进入 v5,它们将被排除出发布范围。配套地,
moveRemovedDependenciesToDevDependencies()会把其他包dependencies中指向这些包的依赖降级移入devDependencies,避免用户项目继续安装即将停发的包。 -
写回 version 字段,并对非 private 包执行第 3 步的依赖调整。
-
同步 Agent 技能版本:遍历
packages/skills/skills/*/SKILL.md,在 frontmatter 中替换(或补写)version: <version>行(set-version.ts#L99-L119)。这也是本文档所在目录的技能们会随版本一起更新版本号的机制。 -
同步插件清单:更新
agent-plugin/plugin.json、agent-plugin/.codex-plugin/plugin.json、claude-code-plugin/.claude-plugin/plugin.json、kimi-code-plugin/.kimi-plugin/plugin.json中的version字段(set-version.ts#L121-L137)。 -
核心包版本固化:分别进入
packages/core与packages/media-parser执行bun ensure-correct-version.ts。以 packages/core/ensure-correct-version.ts 为例,它会:- 从
package.json读取新版本,生成src/version.ts(导出VERSION常量,标注"Automatically generated on publish"); - 重新执行
bun run make与bun x tsgo -d; - 验证产物:检查
dist/esm/version.mjs与dist/cjs/version.js中确实包含新版本号,否则process.exit(1);并断言不存在的错误产物(如dist/index.js)。
这解释了清单中"退出码非 0 即中止"的原因——该脚本内置了产物级断言,退出码非 0 意味着构建产物与版本号不一致,此时发布必然出错。
- 从
-
重建与回归:清理
packages/studio的dist,重新bun run build,重新生成 Google Fonts 数据(packages/google-fonts),运行packages/it-tests的src/monorepo集成测试,构建 compositor(bun build.ts --all),最后再执行一次bun i刷新锁定依赖。 -
提交与打标签:
git add .、提交信息为v<version>的 commit,删除本地与远端可能存在的同名旧 tag 后重新打v<version>(set-version.ts#L173-L183),支持--no-commit参数跳过本步。
可以看到,清单里一句简单的"运行 bun set-version.ts <version>",背后是横跨全部 workspace 包的版本一致性校验与一次回归测试。
五、阶段四:Lambda 烟雾测试(发布前最后一道闸门)
cd packages/example && sh runlambda.sh && cd ../..
清单要求:此步失败则中止发布。packages/example/runlambda.sh 的内容是一次真实的"部署 + 渲染"端到端验证:
set -e
cd ../..
bunx turbo run make --filter=@remotion/lambda # 构建 @remotion/lambda 包
cd packages/lambda && bun run makeruntime # 构建 Lambda 运行时
cd ../example
bunx remotion lambda functions rmall -f # 清空旧函数
bunx remotion lambda functions deploy --memory=2048 --disk=10000
bunx remotion lambda sites create --site-name=testbed-v6 --log=verbose --enable-folder-expiry
bunx remotion lambda render testbed-v6 NewVideo --log=verbose --delete-after="1-day" --api-key=<api-key>
它在 AWS 上用真实凭据重建 Lambda 函数、创建测试站点 testbed-v6 并渲染示例视频 NewVideo。由于 set -e 的存在,任一子命令失败都会使整个脚本非 0 退出,从而触发清单中的中止策略。对发布流程而言,这一步的意义是:验证"即将发布到 npm 的 @remotion/lambda 及运行时"在真实云环境中可部署、可渲染,把问题挡在用户下载之前。
六、阶段五:npm 多包并发发布
NPM_CONFIG_TOKEN=<token> bun run release
对照根 package.json#L48,release 脚本是一条三段式命令:
"release": "bun publish.ts && turbo run publishprivate --concurrency=1 && git push --tags && git push"
- 第一段
bun publish.ts:发布全部公开 npm 包; - 第二段
turbo run publishprivate --concurrency=1:串行执行各包声明的publishprivate任务(如 Ruby gem、Go/Python SDK 等其他生态产物); - 第三段:推送 tag 与分支,使
v<version>tag 到达远端。
6.1 publish.ts 的实现细节
根目录 publish.ts 的发布逻辑值得逐条拆解:
- 版本号来源:从 packages/core/package.json 读取
version(当前为 4.0.520)——即"core 包的版本就是本次发布版本"的单一事实源,与set-version.ts全仓统一改号的设计呼应。 - 包筛选:遍历
packages/下含package.json的目录,跳过FEATURED_TEMPLATES模板目录、跳过private: true的包、再经shouldReleasePackage()过滤(v5 名单中的包在 v5+ 不再发布)。 - LICENSE 自动补齐:若某包的
license字段引用了LICENSE.md但包内没有该文件,先临时复制根目录LICENSE.md进去,bun publish完成后再删除——保证 npm 上每个包都带许可证文件。 - 并发控制与幂等:用
p-limit把并发限制在 4(const p = limit(4)),每个包执行bun publish --tolerate-republish——--tolerate-republish使重复发布同一版本不报错,这为"发布中断后重跑"提供了幂等性保障。
6.2 阶段六:模板仓库同步(publishtemplates)
bun run publishtemplates
对应根 package.json#L51 的 cd packages/it-tests && bun src/templates/publish.ts。清单要求:任一模板发布失败,就停止发布工作流并上报失败。
packages/it-tests/src/templates/publish.ts 实现了这件事,核心机制:
- 同步目标:
FEATURED_TEMPLATES中每个templateInMonorepo非空的模板,克隆对应的独立 GitHub 模板仓库,清空旧文件后把 monorepo 内的模板目录整体拷入并推送; - 版本改写:拷贝
package.json时把所有workspace:*替换为^4.0.0(publish.ts#L75-L79),因为模板在 monorepo 外用 workspace 协议引用本地包,发布到独立仓库后必须换成真实 npm 版本范围——这正是"用新发布的包重新发布所有模板"的落地点; - 范围不止模板:同一脚本还会构建并同步 Agent 插件仓库(Codex 插件、Cursor 插件、Claude Code 插件、Kimi Code 插件),把
plugin.json的版本号同步为 monorepo 包版本并打v<version>tag,以及同步 Canvas Capture 浏览器扩展仓库; - 失败即非 0 退出:脚本收集所有
Promise.allSettled结果,只要有 rejected 就打印失败清单并process.exit(1)(publish.ts#L431-L442)——与 SKILL.md"停止并报告失败"的指令严格对应。
七、阶段七:Changelog 生成规范(逐条继承)
清单最后一大段定义了 Changelog 的生成规则,产物保存到 /tmp/release-<version>.md。完整规则如下:
-
取提交范围:
git log v<prev>..v<new> --oneline获取两个 tag 之间全部提交; -
提取 PR:从 merge commit 中解析 PR 号,对每个 PR 执行:
gh pr view <number> --json title,author,number,url \ --jq '"* \(.title) by @\(.author.login) in \(.url)"' -
分节归类:PR 归入 "What's Changed"、"Templates"、"Docs"、"Internal" 四节;所有
template-*相关变更单独进 "Templates" 节; -
排序规则:"What's Changed" 内按包分组使同包条目相邻(不加子标题,只调整顺序),且
remotion核心包的变更必须排在最前——这与第六节中 core 包作为版本事实源的地位一致; -
标题清洗:去掉冗余前缀,例如 Docs 节条目去掉 "Docs:" 字样;
-
新文档页加链接:运行
git diff --diff-filter=A --name-only v<prev>..v<new> \ -- 'packages/docs/docs/**/*.mdx' 'packages/docs/docs/**/*.md'列出本版本新增的文档页,把每个新增页映射回引入它的 PR,将该条目标题包成指向文档站的 markdown 链接;页面 URL 优先取 mdx frontmatter 中的
slug:字段,否则按文件相对packages/docs/docs/的路径推导;没有新文档页的条目保持纯文本不加链接; -
识别新贡献者:
gh api repos/remotion-dev/remotion/contributors --paginate --jq '.[].login'拉取历史贡献者列表,与本版本 PR 作者比对,只有真正的新面孔才写入 "New Contributors" 节; -
收尾:底部固定追加一行
**Full Changelog**:并附v<prev>...v<new>的 compare 链接; -
格式对齐:使用与上一次 GitHub Release 完全相同的格式(可用
gh release view v<prev>查看对照); -
人工审批:changelog 未经作者批准不得发布,并允许作者在发布前直接编辑。
八、失败策略总览与流程特点
把散落在清单各处的中止条件集中起来,可以画出这个发布流水线的"安全边界":
| 检查点 | 触发条件 | 动作 |
|---|---|---|
| gcloud 认证 | token 打印失败 | 登录重试,不通过则不发布 |
| Ruby 版本 | 发布命令走错 ruby | 前置修正 PATH(仅预防,运行前验证) |
set-version.ts |
退出码非 0 | 立即中止整个发布 |
runlambda.sh |
任一步失败(set -e) |
中止发布 |
publishtemplates |
任一模板/插件同步失败(process.exit(1)) |
停止工作流并上报 |
| Changelog | 未获人工批准 | 不发布 |
从这套流程的源码结构可以看出几个设计取向:单一版本事实源(core 包版本驱动全仓改号)、产物级验证(ensure-correct-version.ts 校验 dist 内容而非只看源码)、幂等发布(--tolerate-republish + tag 先删后建)、以及把验证前移到发布之前(Lambda 端到端渲染、monorepo 集成测试都在 bun run release 之前跑完)。对于维护多包 monorepo 的团队,.agents/skills/release/SKILL.md 与其背后的 set-version.ts、publish.ts、release-package-policy.ts 构成了一套值得参考的"版本一致性 + 发布闸门"工程范式。
需要注意的适用前提:以上流程基于当前仓库的 4.x 版本线(core 当前为 4.0.520)与 Bun/Turborepo 工具链;npm token create、1Password、gh、gcloud 等外部工具与真实云账号凭据仅发布负责人可用,读者在非发布环境中只能查看这些脚本与配置,不应实际执行发布命令。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00