ECC bun-runtime Skill 实战指南:Bun 运行时选型、Node 迁移与 Agent 工作流集成
ECC 的 bun-runtime 技能文档是一份面向 JavaScript 开发者与 Agent 的运行时决策指南:它回答“什么时候该用 Bun 而不是 Node”“如何从 Node 迁移到 Bun”以及“如何在 Vercel 等平台上落地 Bun”。读完本文,你将掌握 Bun 四位一体(运行时、包管理器、打包器、测试运行器)的完整命令面、迁移对照表、Vercel 部署配置,并了解 ECC 仓库自身如何从源码层面检测、识别并调度 Bun 作为项目包管理器。
一、文档定位:ECC 技能体系中的 bun-runtime
该技能文档位于 bun-runtime SKILL.md,其 YAML 头声明了技能名与适用范围:
---
name: bun-runtime
description: Bun as runtime, package manager, bundler, and test runner. When to choose Bun vs Node, migration notes, and Vercel support.
---
从源码结构看,这个技能在 ECC 中有三重入口:
- npm 发布包:package.json 的
files清单中显式包含了skills/bun-runtime/,说明该技能随 ECC 安装包分发给 Claude Code、Codex、Cursor 等 harness 使用; - Agent 清单:agent.yaml 第 29 行将
bun-runtime列为可用技能之一; - 版本记录:CHANGELOG.md 记录该技能随
#529引入,README.md 则将其与nextjs-turbopack等并列为“现代 JS 工具链”相关技能。
技能的触发场景在文档 “Use when” 一节中明确:采用 Bun、从 Node 迁移、编写/调试 Bun 脚本与测试、或配置 Vercel 等平台上的 Bun 运行时。下文按文档原始脉络展开。
二、选型决策:何时用 Bun,何时留在 Node
文档给出的决策规则是两条清单,直接继承如下:
- 优先选 Bun:新建 JS/TS 项目;对依赖安装/运行速度敏感的脚本;部署到启用 Bun 运行时的 Vercel 项目;希望一套工具链同时覆盖 run + install + test + build 的场景。
- 优先选 Node:追求最大生态兼容性;遗留工具链假设运行在 Node 上;某个依赖存在已知的 Bun 兼容性问题。
这个“宁稳勿快”的边界划分值得注意:文档没有绝对化 Bun,而是把“依赖存在已知 Bun 问题”列为回退 Node 的硬性条件。在实际项目评审中,这对应一条可操作的验证步骤——先跑完整依赖安装与构建,再决定是否切换。
三、Bun 的四位一体:架构要点
文档 “How It Works” 一节把 Bun 拆成四个能力面,每一条都有对应实现事实:
| 能力面 | 文档要点 | 说明 |
|---|---|---|
| 运行时 | Drop-in 兼容 Node 的运行时,基于 JavaScriptCore,以 Zig 实现 | Node 兼容意味着绝大多数 node: 内建模块可直接运行 |
| 包管理器 | bun install 显著快于 npm/yarn;当前版本默认生成文本型 bun.lock,旧版本使用二进制的 bun.lockb |
锁文件格式的代际差异是迁移时的关键细节 |
| 打包器 | 内置 bundler 与 transpiler,覆盖应用与库 | 支持 .ts 直接执行与构建 |
| 测试运行器 | 内置 bun test,提供类 Jest 的 API |
无需额外安装 Jest 即可跑测试 |
其中 bun.lock(文本)与 bun.lockb(二进制)的代际差异,正是 ECC 仓库源码中一个真实处理的点——后文源码剖析部分会展示 ECC 如何同时识别这两种锁文件。
四、从 Node 迁移到 Bun:完整迁移清单
文档的迁移段落可以整理为一张命令对照表,供逐条执行:
| 操作 | Node/npm 写法 | Bun 写法 |
|---|---|---|
| 运行脚本 | node script.js |
bun run script.js 或 bun script.js |
| 安装依赖 | npm install |
bun install |
| 执行 npm scripts | npm run <script> |
bun run <script> |
| 一次性运行 CLI(npx 风格) | npx <pkg> |
bun x <pkg> |
文档补充的两条原则:
- Node 内建模块(built-ins)受支持,可直接迁移;
- 当 Bun 提供了对应的原生 API 时,优先使用 Bun API 以获得更好的性能。
ECC 仓库自身就提供了一个 Bun 在真实 Agent 工作流中的使用样例:react-build.md 与 react-build-resolver.md 中的构建排障流程直接使用 bun run build 执行构建、用 bun build ./src/index.tsx --outdir=dist 做快速产物验证,与本文 Vercel 一节中的 bun build 用法完全一致。
五、实操命令与代码示例
以下示例完整继承自原文档,可直接复制到 Bun 环境中运行。
5.1 安装与运行
# 安装依赖(创建/更新 bun.lock 或 bun.lockb)
bun install
# 运行脚本或文件
bun run dev
bun run src/index.ts
bun src/index.ts
注意 bun run src/index.ts 与 bun src/index.ts 两种写法等价——前者是“运行”语义,后者直接以 Bun 作为可执行解释器。由于 Bun 原生执行 .ts,TypeScript 项目无需配置 ts-node 或 esbuild-register。
5.2 脚本与环境变量
bun run --env-file=.env dev
FOO=bar bun run script.ts
--env-file 是 Bun 内建的 .env 加载方式,替代了 Node 项目里常见的 dotenv 依赖;前缀式内联环境变量(FOO=bar)则与 POSIX shell 语义一致。
5.3 测试
bun test
bun test --watch
// test/example.test.ts
import { expect, test } from "bun:test";
test("add", () => {
expect(1 + 2).toBe(3);
});
bun:test 模块提供 test 与 expect,断言风格对齐 Jest(toBe 等),迁移 Jest 测试时主要工作是替换 import 来源,断言主体大多可以保留。
5.4 运行时 API
const file = Bun.file("package.json");
const json = await file.json();
Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello");
},
});
示例展示了 Bun API 的两个高频面:Bun.file 的异步文件读取(file.json() 一步完成读取 + 解析)和 Bun.serve 的内建 HTTP 服务器(标准 fetch 风格 handler,返回 Response 对象)。这类 API 正是文档所说“存在 Bun 原生 API 时优先使用”的具体所指。
六、Vercel 部署 Bun
文档给出了三步部署配置:
- 运行时切换:在项目设置中将 runtime 设为 Bun;
- 构建命令:
bun run build,或对单个入口直接打包:bun build ./src/index.ts --outdir=dist; - 安装命令:
bun install --frozen-lockfile,保证可复现的依赖部署。
--frozen-lockfile 的语义与 CI 场景一致:锁文件与 package.json 不一致时直接失败而不是静默更新锁文件。这条配置对团队协作尤其重要,因为 Bun 生态演进快(文档 Best Practices 也强调这一点),锁文件漂移会破坏部署一致性。
七、ECC 源码级剖析:Bun 如何被检测、识别与调度
技能文档讲的是“开发者视角”的 Bun 用法;而 ECC 仓库源码则展示了“Agent 视角”如何自动感知 Bun 项目。核心实现在 scripts/lib/package-manager.js。
7.1 Bun 的命令与锁文件映射表
该文件定义了四个包管理器的完整命令配置,其中 bun 条目(L44-L56)如下:
bun: {
name: 'bun',
lockFile: 'bun.lock',
// Bun switched its default lockfile from the binary bun.lockb to the
// text-based bun.lock. Keep recognizing the legacy file too.
lockFileAliases: ['bun.lockb'],
installCmd: 'bun install',
runCmd: 'bun run',
execCmd: 'bunx',
testCmd: 'bun test',
buildCmd: 'bun run build',
devCmd: 'bun run dev'
}
这段代码与技能文档形成精确互证:
lockFile: 'bun.lock'+lockFileAliases: ['bun.lockb']正是文档中“当前默认文本锁文件、旧版二进制锁文件”这一代际差异的落地实现——detectFromLockFile()(L95-L105)会把主锁文件名与别名合并后逐一检查文件存在性;installCmd/runCmd/execCmd/testCmd四个字段对应了文档迁移表中的bun install、bun run、bun x(实际调用bunx可执行入口)、bun test,确保 Agent 在任何 harness 中生成的命令与 Bun 语义一致。
7.2 六级检测优先级
getPackageManager()(L166-L239)按固定顺序检测当前项目应使用的包管理器:
- 环境变量
CLAUDE_PACKAGE_MANAGER; - 项目配置
.claude/package-manager.json; package.json的packageManager字段(支持bun@1.x这种带版本号写法,代码按@截取出管理器名);- 锁文件存在性(含
bun.lockb别名); - 全局配置
~/.claude/package-manager.json; - 兜底默认
npm。
用户可通过 commands/setup-pm.md 描述的 /setup-pm 命令或 scripts/setup-package-manager.js 手动干预:--detect 查看检测结果、--project bun 为当前项目写入 Bun 偏好、--global <pm> 写入全局偏好。该脚本帮助文本中对 bun 的定位是 “All-in-one JavaScript runtime & toolkit”,与技能文档第一句定义一致。
一个值得借鉴的工程细节:第 6 级兜底从“探测系统中实际安装了哪些包管理器”改为“直接默认 npm”。源码注释(L227-L238)解释了原因——早期版本会 spawn 子进程执行 where.exe/which,在 Windows 上触发 Bun 的 spawn 限制(issue #162)导致插件冻结;热路径改用纯文件检测(detectFromLockFile / detectFromPackageJson)避免了该问题。这是“Bun 生态演进快、需要持续关注运行时行为”在 ECC 代码中的真实案例,也为 Bun 用户在 CI/钩子热路径中的子进程使用提供了反面参考。
7.3 锁文件到命令的映射约定
commands/prp-implement.md 中维护了一张“锁文件 → 包管理器 → 运行前缀”的映射表,其中 bun.lockb 对应 bun 与 bun run;commands/project-init.md 与 commands/setup-pm.md 的项目初始化清单也把 bun.lockb 列为标准包管理器探测文件之一。这些文档间的约定彼此一致,保证 ECC 的各条命令流对 Bun 项目的识别口径统一。相关行为由 tests/lib/package-manager.test.js 覆盖:该测试用隔离的临时 HOME 与临时项目目录验证 PACKAGE_MANAGERS 常量完整性与各级检测逻辑,是理解上述检测链路可参考的“活文档”。
八、最佳实践
完整继承原文档的三条实践,并补充两条来自仓库实践的延伸建议:
- 提交锁文件(
bun.lock或bun.lockb)以保证可复现安装; - 优先
bun run执行脚本;TypeScript 文件由 Bun 原生执行,无需额外转译配置; - 保持依赖及时更新——Bun 与生态演进快,锁文件与依赖漂移要及时收敛;
- 在 CI 与部署平台使用
bun install --frozen-lockfile,把“锁文件一致性”变成硬性门禁; - 在钩子或启动热路径中避免为探测环境而频繁 spawn 子进程,ECC 曾因 Bun 的 spawn 限制在 Windows 上遭遇冻结(见 scripts/lib/package-manager.js 的注释说明),纯文件检测是更稳的模式。
九、延伸阅读文件
- 技能原文:.agents/skills/bun-runtime/SKILL.md,发布副本 skills/bun-runtime/SKILL.md
- 包管理器检测库:scripts/lib/package-manager.js
- 检测行为测试:tests/lib/package-manager.test.js
- 交互式设置脚本:scripts/setup-package-manager.js、命令说明 commands/setup-pm.md
- Bun 构建排障工作流:commands/react-build.md、agents/react-build-resolver.md
- 锁文件映射约定:commands/prp-implement.md、commands/project-init.md
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