background-agents贡献者指南:Monorepo测试策略、lint复杂度约束与代码规范
【免费下载链接】background-agentsAn open-source background agents coding system项目地址: https://gitcode.com/GitHub_Trending/ba/background-agents
background-agents 是一个开源的后台智能体(background agents)编码系统:你发出提示词后,AI 会话在云端沙箱中独立运行,你可以合上电脑,稍后回来审查 PR。本文带你完整走一遍这个 Monorepo 的贡献者指南——从环境搭建、三层测试策略,到两个自研 lint 检查脚本和代码规范,帮你快速提交第一个合格的 PR。
🧩 项目一览:Monorepo 结构速览
上图是 background-agents 的 Web 控制台:左侧是会话与自动化列表,右侧是向后台智能体下达任务的入口。
整个仓库采用 npm workspaces Monorepo 组织,核心包如下:
| 包 | 语言/框架 | 职责 |
|---|---|---|
packages/control-plane | TypeScript / Cloudflare Workers + Durable Objects | 会话生命周期、WebSocket 流、GitHub 集成 |
packages/web | TypeScript / Next.js + React | 用户界面、OAuth、实时会话面板 |
packages/sandbox-runtime | Python + JS | 沙箱内智能体运行时 |
packages/modal-infra | Python 3.12 / Modal | 沙箱生命周期、快照、镜像构建 |
packages/shared | TypeScript | 共享类型、鉴权工具、模型定义 |
packages/slack-bot等 | TypeScript / Workers + Hono | Slack、GitHub、Linear 三方触发器 |
架构上分为三层,通过 WebSocket 串联:Web 客户端 → Control Plane(会话中枢)→ Data Plane(Modal 沙箱)。改动前建议先通读 AGENTS.md 和 docs/HOW_IT_WORKS.md,两者包含完整的架构说明与依赖图。
🚀 环境搭建:一键安装与构建顺序
克隆仓库后,最快的上手路径:
git clone https://gitcode.com/GitHub_Trending/ba/background-agents cd background-agents bash .openinspect/setup.sh # 安装依赖、构建 shared 包、配置 husky 钩子也可以手动执行分步操作(见 CONTRIBUTING.md):
npm install npm run build -w @open-inspect/shared # ⚠️ shared 必须最先构建 npm run typecheck npm run lint npm test关键坑位:@open-inspect/shared是其他所有包的依赖,改了共享类型后必须先构建它(根目录npm run typecheck与npm run build已自动帮你处理了这个顺序,见 package.json)。环境要求 Node ≥ 22.13.0。
🧪 Monorepo 测试策略:三层布局
所有 TypeScript 包使用Vitest,Python 包使用pytest,测试文件位置各有约定:
单元测试:与源码同目录
- control-plane 单测:
src/**/*.test.ts,运行在 Node 环境,配置见 packages/control-plane/vitest.config.ts - web / slack-bot / linear-bot:同样同目录
src/**/*.test.ts - github-bot例外:单独放在
test/*.test.ts - modal-infra:
tests/test_*.py,配合 pytest-asyncio
按包运行测试非常直观:
npm test -w @open-inspect/control-plane # 单测 npm test -w @open-inspect/slack-bot cd packages/modal-infra && pytest tests/ -v # Python 侧根目录 vitest.workspace.ts 把所有包的vitest.config.ts汇聚成一个工作区,一条npm test全仓库跑完。
集成测试:在真实 workerd 运行时里跑
control-plane 是本项目最重的部分,它另有一层集成测试:
npm run test:integration -w @open-inspect/control-plane配置在 packages/control-plane/vitest.integration.config.ts,要点:
- 通过
@cloudflare/vitest-pool-workers的cloudflareTest()插件,在真实 workerd 运行时中执行,并绑定真实 D1 terraform/d1/migrations/下的全部 SQL 迁移会自动应用,无需手工建表- pool-workers 按测试文件隔离 D1 存储;同一文件内的用例共享一个 D1 实例,因此务必在
beforeEach/afterEach中调用cleanD1Tables()防止数据串染 - 常用辅助函数在
test/integration/helpers.ts:initSession()、queryDO()、seedEvents()
给新手的核心建议:涉及会话、调度、WebSocket 的改动,光写单测不够,补一个集成用例才能覆盖 Durable Object + D1 的真实行为。
Python 侧:pytest + ruff 双保险
cd packages/modal-infra && ruff check --fix && ruff formatRuff 规则集中在 ruff.toml:目标 Python 3.12、行宽 100,启用了 bugbear、pyupgrade、type-checking 等规则组,测试文件额外豁免了部分规则。
🔍 Lint 复杂度约束:两个容易忽略的自研检查
除了标准的eslint .与prettier,这个仓库还有两个自研 lint 脚本,CI 中都会执行:
lint:complexity —— 圈复杂度热区报告
npm run lint:complexity # 文本报告 npm run lint:complexity -- --json # 结构化报告脚本 scripts/lint-complexity.mjs 用 ESLint 的complexity规则扫描全部packages/**/*.{ts,tsx},输出按复杂度排序的生产代码热区表。值得了解的三个设计决策:
- 热区阈值 20:圈复杂度超过 20 的函数会被列入报告(见 scripts/lint-complexity.mjs)
- 测试文件单独统计:测试代码不计入生产热区表,避免"为了凑覆盖率写出的大函数"污染报告
- 仅报告、不阻断:复杂度发现不影响退出码——它是一份持续观察的技术债仪表盘,而不是硬门槛。提交大型重构前跑一次,可以看看自己碰的模块是否已是热区
lint:sql-portability —— 可移植 SQL 子集检查
npm run lint:sql-portabilityscripts/lint-sql-portability.mjs 检查 control-plane 存储层的 SQL 是否踩了SQLite 专属语法(因为 Postgres 是计划中的新引擎,现在写一条 SQLite-only 语句,将来就要付出"迁移双胞胎"的代价)。被拦截的典型写法与可移植替代:
| ❌ 不要写 | ✅ 请写成 |
|---|---|
INSERT OR IGNORE / REPLACE | ON CONFLICT DO NOTHING / DO UPDATE SET |
?1、?2编号占位符 | 顺序?,按出现顺序绑定 |
unixepoch()、strftime(...) | 在 TypeScript 里传Date.now()并格式化 |
json_object(...)等 JSON 函数 | 在 TS 中构造 JSON 再作为参数绑定 |
AUTOINCREMENT、CREATE TRIGGER、PRAGMA | 应用层生成 ID / 在 store 里约束 / 留在引擎适配器中 |
完整子集与易错点说明见 docs/PORTABLE_SQL.md。
一个精巧的设计:历史遗留的例外被逐条登记在 scripts/sql-portability-baseline.json 中,写明具体文本与保留理由,数量采用棘轮机制——新增一处会失败,擅自删减一处也会失败,确保技术债清单始终诚实。
📏 代码规范与提交约定
命名规范:把单位写进名字里
AGENTS.md 中最重要的几条约定:
- Python 用秒,TypeScript 用毫秒,与各自生态一致(Modal 的
timeout=收秒,control-plane 全程_MS后缀) - 禁止裸用
timeout:Python 写timeout_seconds,TypeScript 写timeoutMs/INACTIVITY_TIMEOUT_MS - 默认值只定义一次:抽成命名常量到处 import,注释里写
Defaults to DEFAULT_SANDBOX_TIMEOUT_SECONDS而不是重复字面量Default: 7200 - 顺手修坏味道:把一个既有字段穿进新代码路径时,若发现命名/单位本身有问题,就在同一次改动中修掉,而不是把问题扩散开
ESLint 关键规则
eslint.config.js 基于 typescript-eslint + React Hooks,几条会直接影响你代码的规则:
consistent-type-imports:强制类型导入(import type),npm run lint:fix可自动修复no-unused-vars:下划线前缀的变量/参数被豁免no-explicit-any:警告级,尽量避免anyno-restricted-imports:鉴权相关符号必须从子路径导入,例如@open-inspect/shared/auth而非包根——这是有意维护的模块边界,报错信息会直接告诉你正确的导入路径
提交前记得用npm run lint:fix+npm run format,或者交给 husky:lint-staged 会在 pre-commit 阶段对暂存的 TS/TSX 自动执行eslint --fix+prettier --write,对 Python 文件执行ruff check --fix+ruff format(配置见 package.json)。
提交信息:Conventional Commits
使用规范化提交,主题行控制在72 字符以内,细节放 PR 描述而非 commit message:
feat: add new feature fix: resolve issue with X docs: update documentation refactor: restructure module chore: / test: ...✅ 常见踩坑清单(提交 PR 前自查)
- 构建顺序:改了
@open-inspect/shared却没先构建它,下游包的类型检查会满屏报错 - GitHub App 私钥格式:Cloudflare Workers 要求 PKCS#8,用
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt转换 - Durable Object 新绑定:需要两阶段 Terraform 部署(先
enable_durable_object_bindings = false再置true) - 没有 wrangler.toml:control-plane 的配置由 Terraform 生成,仓库里查不到是正常的
- Modal 部署:在
packages/modal-infra下先跑uv run python deploy.py --build-sandbox-image,再uv run modal deploy deploy.py,直接部署src/app.py不会导入任何函数模块
标准 PR 检查单:npm test全绿 →npm run lint通过 →npm run typecheck通过 → 两个自研 lint 脚本通过 → 文档同步更新。CI 在每次推送与 PR 上都会执行 lint、typecheck 与全量测试,推送main还会按变更范围自动部署对应服务。
延伸阅读
- 贡献流程与 PR 规范:CONTRIBUTING.md
- 架构与会话生命周期:docs/HOW_IT_WORKS.md
- 可移植 SQL 子集详解:docs/PORTABLE_SQL.md
- Control Plane 测试与集成说明:packages/control-plane/README.md
准备好后,从docs:或fix:类型的小 PR 开始,就是融入 background-agents 社区的最佳方式。
【免费下载链接】background-agentsAn open-source background agents coding system项目地址: https://gitcode.com/GitHub_Trending/ba/background-agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考