20 · 构建、版本与发布
一个 monorepo 如何产出 CLI Server、Web、Electron、Mobile 与 Rust helper,并保持兼容。
不是一个 pnpm build 产出一种应用
根 package.json 用 Vite+ (vp) 作为 workspace 任务编排,但最终产物至少包括:
t3CLI/Server npm 包与 Web 静态资产;- Electron macOS DMG、Windows NSIS、Linux AppImage;
- iOS/Android Expo 原生应用;
- marketing Web;
- Rust resource-monitor 平台二进制;
- T3 Connect relay/Worker 基础设施。
统一仓库允许 contracts 原子升级,发布却必须考虑各端不同节奏:App Store 手机可能几周未更新,而 npx t3@latest 已是新 Server。
根任务图
常用入口包括:
vp i / pnpm install
vp run ... or root scripts
build / typecheck / lint / test / fmt:check
build:desktop / dist:desktop:*
build:resource-monitor / test:resource-monitor
release:smoke根声明 Node ^24.13.1 与 pnpm 11.10.0,但 README 对运行已发布 CLI 还给出更宽的 Node 22.16+/23.11+/24.10+要求。
开发工具链版本与消费者 runtime 范围可以不同,发布验证必须覆盖真正支持矩阵。
Contracts 先行,但要向后兼容
Monorepo build 可以先生成/检查 contracts,再构建 Server 与客户端。编译通过只证明同一 checkout 兼容;发布需要额外策略:
- 新字段优先 optional/default;
- 客户端忽略未知 event/field,但关键 lifecycle 未知时 fail visibly;
- Server 保持旧 RPC 一段窗口,或提供 capability/version handshake;
- migration 将本地数据库升级,却不能要求手机同步升级;
- Provider 协议生成文件与 adapter 变更一同测试。
Server + Web 的打包
npx t3 同时启动本地 backend 和 Web app,意味着 npm 产物要包含可运行 Server、静态 Web assets、必要 migrations 和平台资源。
发布 smoke 应在干净临时 userdata 下启动,检查 health/WebSocket、打开静态入口、列 Provider snapshot,再优雅关闭。
不要在 smoke 中使用真实 ~/.t3:既可能污染用户数据,也会因现存配置让测试假通过。
Electron 打包
scripts/build-desktop-artifact.ts 根据 platform/target/arch 生成安装器。桌面产物还要打包:
- main/preload/renderer;
- 内嵌 Server 与 Web assets;
- 对应平台 resource-monitor;
- 图标、协议注册、更新 metadata;
- 原生依赖与签名/公证材料。
构建成功不等于安装可运行,因此 test:desktop-smoke、artifact smoke 和真实安装器测试分层。更新渠道还要保证下载的 renderer 与 backend 是一组兼容产物。
Rust helper 的平台矩阵
native/resource-monitor 用 Cargo --locked --release 构建。Electron/Server 通过 ResourceMonitorBinary 定位正确 OS/arch binary。
发布容易遗漏的情况:macOS arm64/x64、Windows x64/arm64、Linux executable bit、codesign、libc 兼容。
Helper 是可选遥测能力,找不到时主应用应降级;但打包测试仍要验证目标平台本应携带它。
Mobile 发布
Expo/React Native 包含 Swift/Kotlin 自定义模块,不能只依赖 OTA JS 更新。原生 module API 改变时,需要:
- JS 层 capability/version guard;
- iOS/Android 同步实现与 static check;
- 保持旧 binary 能运行新 JS(若使用 OTA);
- Server contract 仍向后兼容商店旧版。
移动端与 Server 的版本跨度是整个系统最强的兼容性测试。
Provider 协议生成代码
effect-codex-app-server 与 effect-acp 含 _generated Schema/metadata。更新生成文件时应:
- 固定上游协议版本/输入;
- 将生成 diff 与手写 adapter diff 分开审查;
- 运行 decode fixture 与 runtime mapping 测试;
- 检查 unknown/optional 字段兼容;
- 不手工修生成文件而忘记 generator 来源。
发布前门禁
仓库根脚本已经覆盖多数环节,平台签名和商店提交由外部环境完成。门禁应 fail fast,但不能因为可选 Provider 未登录而失败; 使用 mock/capability snapshot 验证未安装状态。
回滚与数据版本
应用 binary 可以回滚,SQLite migration 通常不可逆。新版本升级数据库后旧 Server 是否还能读,是发布策略必须明确的问题。 如果不支持 downgrade,应在启动时检测 schema version 并给出安全错误,不能让旧 binary 猜测新表结构后写坏数据。
Electron auto-update 也要避免在 Agent 正执行时强制重启;更新 ready 可以提示,实际安装等待用户确认或安全 idle 点。
可迁移经验
- Monorepo 原子编译不等于部署原子;用最慢更新的客户端定义兼容窗口。
- 每类产物都需要“能构建”和“安装/启动可用”两层验证。
- 可选 native helper 在运行时可降级,在打包 pipeline 中仍要强验证。
- 生成协议代码、手写语义映射和发布版本应作为一个兼容变更审查。
- 数据库升级与 binary 回滚是不同方向,必须显式声明 downgrade 策略。