构建生命周期
6 个工具管理一次固件构建,从“这个构建会做什么?“到“开始“再到 “立即停止”。
| 工具 | 做什么 |
|---|---|
build(别名 build.start) | 启动构建。立即返回 task_id。 |
build.status | 检查某个 task_id 的状态:pending、running、succeeded、failed、canceled。 |
build.cancel | 停止一个正在跑或排队的构建。 |
set_target.run | 在构建机器上运行 idf.py set-target。 |
generate_build_plan | 告诉你一次构建会做什么,但不真的跑。 |
get_clean_plan | 告诉你 idf.py clean 或 fullclean 会删什么。 |
build / build.start
在构建服务器上启动一次固件构建,立即返回。构建本身在沙箱里后台跑;
你用 build.status 或读 build://log/{task_id} 跟踪进度。
典型输入:
| 字段 | 类型 | 说明 |
|---|---|---|
target | string | ESP 芯片 —— esp32、esp32s3、esp32c6 等。 |
profile | string | debug(默认)或 release。 |
idf_version | string(可选) | pin 一个特定的 IDF 版本。默认用项目的 .idf-version 或构建服务器的默认值。 |
clean | bool(可选) | true 则做一次干净构建,而不是增量构建。 |
params | object(可选) | 配方特有的覆盖项。 |
返回:
{
"task_id": "0abf...e2",
"status": "pending"
}
task_id 是你跟踪构建用的东西。把它存起来。
示例对话:
把固件编译成 esp32s3 release 版。
你的助手用 {"target": "esp32s3", "profile": "release"} 调用
build,然后看 build.status 直到结束。
仅计划模式: CLI 下 build 默认走远程构建。传 --local 只生成
构建计划而不编译。MCP 服务器下,如果 CONTROL_BASE_URL 或
MCP_AUTH_SECRET 缺失,build 返回 "status": "planning" 的计划。
用 generate_build_plan 可以在任何模式下显式获取无副作用的构建计划。
CLI: espctl build
不想走 MCP,想自己用命令行驱动构建。还是同一个构建服务器、同一个沙箱 —— 只是前端从 AI 助手换成了 CLI。
espctl build [path] [--target <chip>] [--clean] \
[--remote <url> | --local] \
[--git-url <url> [--git-ref <ref>]] \
[--idf-version <ver>] [--sbom]
默认就是远程构建。详见 仅计划模式 vs 远程构建。
标志矩阵
| 标志 | 默认 | 说明 |
|---|---|---|
path(位置参数) | . | 项目目录。.espctl.toml 和 .idf-version 都从这个路径读。 |
--target | .espctl.toml 里的 default_target | 芯片 —— esp32、esp32s3、esp32c3、esp32c6 等。 |
--clean | false | 先清掉构建目录。只在 local 下生效,远程模式忽略。 |
--remote <url> | 从 ~/.config/espctl/credentials.json 读,否则 https://esphome.cloud | 覆盖构建服务器 URL。和 --local 互斥。 |
--local | false | 只生成构建计划,不编译。和 --remote 互斥。 |
--git-url <url> | — | 让 agent 直接 clone 这个仓库,不上传本地项目包。仅远程模式。 |
--git-ref <ref> | (默认分支) | 要 checkout 的分支、tag 或 commit。和 --git-url 一起用。 |
--idf-version <ver> | .idf-version → .espctl.toml 的 [idf_version] → 服务器默认值 | pin 一个特定 IDF 版本。如果 .idf-version 文件不存在,会写一份。 |
--sbom | false | 在 build/sbom.spdx 生成 SPDX SBOM。仅远程模式可用。 |
模式选择顺序
CLI 按下面顺序决定模式:
--local→ 仅计划,不编译。--remote <url>→ 远程构建到这个 URL。- 否则:
espctl login保存的服务器。 - 否则:
https://esphome.cloud(内置默认值)。
常见用法
# 默认:用已保存的凭据走远程构建
espctl build . --target esp32s3
# 远程构建并生成 SPDX SBOM
espctl build . --target esp32s3 --sbom
# 一次性覆盖服务器(不持久化登录)
espctl build . --target esp32 --remote https://staging.example.com
# 直接从一个 git ref 构建(agent 自己 clone,不上传项目)
espctl build --remote https://esphome.cloud \
--git-url https://github.com/ff4415/aegis-examples \
--git-ref v0.4.2 --target esp32c3
# 显式 pin IDF 版本
espctl build --target esp32s3 --idf-version v5.3.1
# 仅计划模式(离线 / 预检)
espctl build --local --target esp32s3
# 本地完整重建
espctl build --local --target esp32s3 --clean
输出与退出码
Human 模式打印分阶段进度(clone、configure、compile、link)和最终
的 manifest 摘要。--json 模式按行输出一串 PipelineEvent JSON
对象,最后一条是 manifest。
成功:退出 0,在项目目录写出 build/flash_bundle.tar.gz。带
--sbom 还会写出 build/sbom.spdx。
编译或运行时失败:退出 1。
配置或目标无效错误:退出 2。
相关 MCP 工具
build/build.start—— 同一个构建,通过编程方式触发。generate_build_plan—— 这就是--local内部干的事。sbom.create—— 仅针对已有task_id生成 SBOM,适合事后补 SBOM。
build.status
检查一个之前启动的构建的状态。
输入:
{ "task_id": "0abf...e2" }
返回:
{
"task_id": "0abf...e2",
"status": "running",
"progress": 0.42,
"started_at": 1712340000,
"updated_at": 1712340060,
"phase": "compiling"
}
status 取值之一:pending、running、succeeded、failed、
canceled。一些助手还会显示 progress(0.0–1.0)和一个自由形式
的 phase(例如 cmake-configure、compiling、linking、
flashing)。
常见模式: 大多数助手每 1–3 秒查一次,带超时。不要硬刷服务 ——
有一个 build://log/{task_id} 资源会随新行到达推送,比反复问更高效。
build.cancel
停止一个 pending 或 running 的构建。如果构建已经结束,这是 no-op
(不会报错)。
输入:
{ "task_id": "0abf...e2" }
返回:
{ "task_id": "0abf...e2", "status": "canceled" }
取消是尽力而为的 —— 服务器先请求构建停下来,短暂等待后强制停止。 已经在跑的编译步骤可能再继续几秒才停。
generate_build_plan
告诉你一次构建会做什么,但不真的跑。适合:
- 在按“开始“之前先看看接下来会发生什么。
- 仅计划模式(没设构建服务器)。
- 为 CI 或审计捕获一份可重现的构建描述。
输入: 和 build 一样(target、profile 等)。
返回: 一个结构化的计划。具体字段取决于配方,但通常包括:
recipe_ididf_version_resolvedtargetprofilecommand_pipeline—— 有序的构建步骤列表expected_artifacts—— 构建会产出哪些文件estimated_duration_secs—— 基于历史的尽力估计
无副作用。 可以反复调。
get_clean_plan
告诉你 idf.py clean(增量清理)或 idf.py fullclean(完全清理)
会从构建目录删什么,但实际不删任何东西。
输入:
{ "scope": "clean" } // 或 "fullclean"
返回: 会被删的文件和目录列表,加上合计。
{
"scope": "clean",
"would_delete": [
"build/esp-idf/main/...",
"build/esp-idf/CMakeFiles/...",
"build/.../*.o"
],
"total_files": 1342,
"total_bytes": 187654321
}
适合在做破坏性清理之前确认,尤其是在 CI 里。