Angular 仓库 AI Agent 开发规范:pnpm + Bazel 环境、Zoneless 测试范式与贡献工作流
Angular 官方仓库内置了一份专门面向 AI Agent 的开发规范(AGENTS.md / .agent/rules/agents.md),它浓缩了在此仓库中工作所需的三类关键能力:用 pnpm 与 Bazel 搭建构建测试环境、遵循 Zoneless(无 Zone.js)环境下的“Act, Wait, Assert”异步测试范式,以及通过 gh CLI 和规范化的 commit 消息提交 Pull Request。读完本文,你将能准确复现仓库中的测试运行方式,理解框架自身测试为何不再依赖 detectChanges(),并能按仓库标准完成一次合格的代码提交。
规范文件的定位:AI Agent 的“always_on”工作手册
仓库根目录下的 AGENTS.md 与 .agent/rules/agents.md 内容一致,文件以如下 frontmatter 开头:
---
trigger: always_on
---
这表示该规范对任何进入本仓库工作的 AI Agent 始终生效,而非按需触发。全文仅 35 行,但覆盖四个维度:环境(Environment)、关键文档索引(Key Documentation)、测试约定(Testing)与 Pull Request 流程。它的核心断言是:
This is the source code for the Angular framework. This guide outlines standard practices for AI agents working in this repository.
换言之,该文件不是通用贡献指南,而是把 Angular 框架源码仓库中“与框架自身开发强绑定的约定”提炼为 Agent 可直接执行的规则。
环境与构建命令:pnpm 管理依赖,Bazel 驱动测试
规范文件 Environment 一节给出两条硬性约定:
- 使用
pnpm进行包管理(版本由根目录 package.json 的engines字段指定); - 使用
pnpm bazel test //target运行测试,其中//target是 Bazel 目标路径。
这两条约定与 构建与测试指南 完全一致,该指南是仓库中运行 Bazel 目标的“权威手册”。结合指南内容,完整的工作流命令如下:
# 1. 安装依赖(对应 package.json 中的依赖声明)
pnpm install
# 2. 构建 Angular 框架,产物输出到 dist/packages-dist
pnpm build
# 3. 运行指定 Bazel 目标的测试
pnpm bazel test //target
# 4. 提交 PR 前建议跑完整测试套件
pnpm test //packages/...
# 5. 代码格式检查 / 校验(prettier 格式由 CI 强制)
pnpm lint
# 6. 自动格式化
pnpm ng-dev format changed [shaOrRef] # 只格式化相对某 ref 的变更文件,默认 main
pnpm ng-dev format all # 格式化全部源码
几个值得注意的前提与限制:
- Bazel 是构建测试的第一工具,指南明确 “Bazel is used as the primary tool for building and testing Angular”,调试细节见 Bazel 构建指南 的 “Testing Angular” 章节;
- 提交 PR 前应执行受影响的全部测试(
pnpm test //packages/...),CI 也会在提交后再次运行受影响测试,失败会在 GitHub 上以错误状态呈现; - 代码必须通过格式检查才能合并,仓库使用 prettier 自动格式化,CI 会强制校验。
关键文档索引:三份“必读”规范
规范文件 Key Documentation 一节列出了三份配套文档,均位于 contributing-docs/ 目录:
| 文档 | 作用 |
|---|---|
| Building and Testing | 运行各类目标(build/test/snapshot)的权威指南 |
| Coding Standards | TypeScript 及其他文件的代码风格规范 |
| Commit Guidelines | commit 消息与 PR 标题的格式规范 |
其中 编码规范 明确其适用范围“仅针对 Angular 框架本身的开发,而非用 Angular 构建的应用”,并以 Google JavaScript Style Guide 为基础、prettier 自动格式化由 CI 强制执行;它还包含若干具体的 API 设计要求(例如“避免用布尔参数表达‘做额外的事’,应拆分为不同函数”)。这些是 Agent 在修改框架源码时必须对照的风格基准。
测试约定(核心):Zoneless 与 Async-First
这是规范文件技术含量最高的部分,也是 Agent 在 Angular 仓库写测试时最容易出错的地方。
前提:假定运行在无 Zone 的环境中
规范第一条即声明:
Zoneless & Async-First: Assume a zoneless environment where state changes schedule updates asynchronously.
这意味着:框架自身测试默认运行在 zoneless(不依赖 Zone.js 的 NgZone/ProxyZone)模式下,状态变化会异步地调度变更检测与视图更新。直接推论是:
- 禁止使用
fixture.detectChanges()手动触发更新——它属于 Zone.js 时代的同步刷新手法,与异步调度模型相冲突; - 必须采用 “Act, Wait, Assert” 三步模式:
- Act(操作):更新状态或执行一个动作;
- Wait(等待):
await fixture.whenStable(),让框架处理完已调度的更新; - Assert(断言):验证输出。
这一模式在框架各包的测试中大量出现。例如 Router 包的 router_link_spec.ts 中每个用例都遵循“操作后 await fixture.whenStable() 再断言”的写法,导航集成测试 navigation.spec.ts 亦同。
用 useAutoTick() 通过“快进”假时钟减少等待
为了让测试保持快速,规范要求在可能的情况下最小化等待,推荐方式是引入 useAutoTick()(来自 packages/private/testing/src/utils.ts)通过 mock clock 快进时间。查看该文件源码可以看到其实现非常直白——它在 beforeEach 中安装 Jasmine 的 fake clock 并开启 autoTick,在 afterEach 中卸载:
// packages/private/testing/src/utils.ts (约 L204-L212)
export function useAutoTick() {
beforeEach(() => {
jasmine.clock().install();
jasmine.clock().autoTick();
});
afterEach(() => {
jasmine.clock().uninstall();
});
}
由于定时器在假时钟下“即时推进”,依赖 setTimeout/setInterval 的异步逻辑无需真实等待。实际用例可见 form_builder_spec.ts:它在 describe 顶层调用 useAutoTick(),因此块内大量用例(包括涉及异步校验器的用例)都能以同步断言完成。
确需等待时:真实异步测试 + timeout() / whenStable()
规范同时给出“必须等待”场景的标准做法:使用真实异步测试(it('...', async () => { ... })),并搭配两个工具:
await timeout(ms):等待指定毫秒数;await fixture.whenStable():等待框架进入稳定状态。
timeout 的实现位于同一文件(utils.ts 约 L183-L187),本质是一个基于 setTimeout 的 Promise 包装:
// packages/private/testing/src/utils.ts (约 L183-L187)
export async function timeout(ms?: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
一个典型组合出现在 form_builder_spec.ts 中:
import {useAutoTick, timeout} from '@angular/private/testing';
describe('Form Builder', () => {
useAutoTick(); // 顶层开启假时钟自动推进
it('... 需要等待的用例 ...', async () => {
// Act: 更新状态
// Wait:
await timeout(); // 让出宏任务(约 L250 处用法)
await fixture.whenStable(); // 等待框架稳定(约 L279/L305 处用法)
// Assert:
expect(...).toEqual(...);
});
});
从源码结构看,utils.ts 还配套了几个值得了解的测试辅助函数,Agent 在编写框架测试时同样可以复用:
waitFor(callback, options)(约 L264-L299):以真实时钟为基准的轮询等待器,默认超时 100ms、默认间隔 0,超时后抛出携带“尝试次数 + 最后一次错误 + 原始调用栈”的增强错误信息;expectText(text, options)(约 L245-L258):基于waitFor断言容器(默认为最近 fixture 的nativeElement)文本内容匹配字符串或正则;withBody/withHead(约 L38-L75):为测试自动注入/清理document.body/head中的 HTML;ensureDocument/cleanupDocument(约 L120-L166):在 Node 环境下用 domino 建立document,并在beforeEach/afterEach中自动注册/还原。
Pull Request 与提交规范
规范文件 Pull Requests 一节要求:创建和管理 PR 使用 gh CLI(GitHub CLI)。与之配套的提交格式约束来自 Commit Message 规范,其核心结构为 header + body + footer 三段:
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
Header 采用 <type>(<scope>): <short summary> 格式,其中 type 必须为 build / ci / docs / feat / fix / perf / refactor / test 之一,scope 为受影响的 npm 包名(如 animations、common、compiler-cli、core、forms、router 等),summary 使用现在时、首字母小写、结尾无句号。Body 除 docs 类型外为必填,且至少 20 个字符;Footer 可选。该格式同时用于 PR 标题。
规范要点速查清单
| 场景 | 约定 | 依据 |
|---|---|---|
| 包管理 | 一律使用 pnpm | AGENTS.md Environment 节 |
| 运行测试 | pnpm bazel test //target |
AGENTS.md / 构建指南 |
| 触发更新 | 禁止 fixture.detectChanges(),改用 await fixture.whenStable() |
AGENTS.md Testing 节 |
| 减少等待 | describe 顶层 useAutoTick() |
utils.ts |
| 必须等待 | 真实 async 用例 + await timeout(ms) / await fixture.whenStable() |
utils.ts |
| 代码格式 | prettier,pnpm lint 校验,pnpm ng-dev format 修复 |
构建指南 |
| PR / 提交 | gh CLI + <type>(<scope>): <summary> 格式 |
AGENTS.md / 提交规范 |
需要强调的是,上述约定均以当前仓库实际内容为准:测试工具函数位于私有包 @angular/private/testing(源码路径 packages/private/testing/src/utils.ts),框架包内测试(如 packages/forms/test/、packages/router/test/)即是这些约定的参考实现;Agent 在扩展测试时,优先对齐同包内既有用例的写法,比遵循任何外部惯例都更可靠。
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 StartedRust0624
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