chore(i18n): refresh zh-CN translations
This commit is contained in:
parent
829cf4124c
commit
aaee14fcad
@ -1,42 +1,42 @@
|
||||
---
|
||||
read_when:
|
||||
- 处理 Telegram 功能或网络钩子
|
||||
summary: Telegram 机器人支持状态、能力和配置
|
||||
- 开发 Telegram 功能或网络钩子
|
||||
summary: Telegram 机器人支持状态、功能能力和配置
|
||||
title: Telegram
|
||||
x-i18n:
|
||||
generated_at: "2026-05-04T07:29:50Z"
|
||||
generated_at: "2026-05-05T04:26:41Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 5711d53cf908a14024bc5a94f7d590bb4bcb6963a1d78049d7782871f4eae932
|
||||
source_hash: 03c75169335378482b80f1ceb669cefaa034ad3e589cf5f1d14c8252608ee46a
|
||||
source_path: channels/telegram.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
通过 grammY,可用于生产环境中的 bot 私信和群组。默认模式是长轮询;webhook 模式可选。
|
||||
Production-ready for bot DMs and groups via grammY. Long polling is the default mode; webhook mode is optional.
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="配对" icon="link" href="/zh-CN/channels/pairing">
|
||||
Telegram 的默认私信策略是配对。
|
||||
<Card title="Pairing" icon="link" href="/zh-CN/channels/pairing">
|
||||
Default DM policy for Telegram is pairing.
|
||||
</Card>
|
||||
<Card title="渠道故障排除" icon="wrench" href="/zh-CN/channels/troubleshooting">
|
||||
跨渠道诊断和修复手册。
|
||||
<Card title="Channel troubleshooting" icon="wrench" href="/zh-CN/channels/troubleshooting">
|
||||
Cross-channel diagnostics and repair playbooks.
|
||||
</Card>
|
||||
<Card title="Gateway 网关配置" icon="settings" href="/zh-CN/gateway/configuration">
|
||||
完整的渠道配置模式和示例。
|
||||
<Card title="Gateway configuration" icon="settings" href="/zh-CN/gateway/configuration">
|
||||
Full channel config patterns and examples.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## 快速设置
|
||||
## Quick setup
|
||||
|
||||
<Steps>
|
||||
<Step title="在 BotFather 中创建 bot token">
|
||||
打开 Telegram 并与 **@BotFather** 聊天(确认账号名正是 `@BotFather`)。
|
||||
<Step title="Create the bot token in BotFather">
|
||||
Open Telegram and chat with **@BotFather** (confirm the handle is exactly `@BotFather`).
|
||||
|
||||
运行 `/newbot`,按提示操作,并保存 token。
|
||||
Run `/newbot`, follow prompts, and save the token.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="配置 token 和私信策略">
|
||||
<Step title="Configure token and DM policy">
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -51,12 +51,12 @@ x-i18n:
|
||||
}
|
||||
```
|
||||
|
||||
环境变量回退:`TELEGRAM_BOT_TOKEN=...`(仅默认账号)。
|
||||
Telegram **不**使用 `openclaw channels login telegram`;请在配置/环境变量中配置 token,然后启动 gateway。
|
||||
Env fallback: `TELEGRAM_BOT_TOKEN=...` (default account only).
|
||||
Telegram does **not** use `openclaw channels login telegram`; configure token in config/env, then start gateway.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="启动 gateway 并批准第一条私信">
|
||||
<Step title="Start gateway and approve first DM">
|
||||
|
||||
```bash
|
||||
openclaw gateway
|
||||
@ -64,119 +64,119 @@ openclaw pairing list telegram
|
||||
openclaw pairing approve telegram <CODE>
|
||||
```
|
||||
|
||||
配对码会在 1 小时后过期。
|
||||
Pairing codes expire after 1 hour.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="将 bot 添加到群组">
|
||||
将 bot 添加到你的群组,然后设置 `channels.telegram.groups` 和 `groupPolicy` 以匹配你的访问模型。
|
||||
<Step title="Add the bot to a group">
|
||||
Add the bot to your group, then set `channels.telegram.groups` and `groupPolicy` to match your access model.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
Token 解析顺序可感知账号。实际使用中,配置值优先于环境变量回退,且 `TELEGRAM_BOT_TOKEN` 仅适用于默认账号。
|
||||
Token resolution order is account-aware. In practice, config values win over env fallback, and `TELEGRAM_BOT_TOKEN` only applies to the default account.
|
||||
</Note>
|
||||
|
||||
## Telegram 侧设置
|
||||
## Telegram side settings
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="隐私模式和群组可见性">
|
||||
Telegram bot 默认启用**隐私模式**,这会限制它们能收到哪些群组消息。
|
||||
<Accordion title="Privacy mode and group visibility">
|
||||
Telegram bots default to **Privacy Mode**, which limits what group messages they receive.
|
||||
|
||||
如果 bot 必须看到所有群组消息,可以:
|
||||
If the bot must see all group messages, either:
|
||||
|
||||
- 通过 `/setprivacy` 禁用隐私模式,或
|
||||
- 将 bot 设为群组管理员。
|
||||
- disable privacy mode via `/setprivacy`, or
|
||||
- make the bot a group admin.
|
||||
|
||||
切换隐私模式时,请在每个群组中移除并重新添加 bot,以便 Telegram 应用变更。
|
||||
When toggling privacy mode, remove + re-add the bot in each group so Telegram applies the change.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="群组权限">
|
||||
管理员状态在 Telegram 群组设置中控制。
|
||||
<Accordion title="Group permissions">
|
||||
Admin status is controlled in Telegram group settings.
|
||||
|
||||
管理员 bot 会收到所有群组消息,这对于始终在线的群组行为很有用。
|
||||
Admin bots receive all group messages, which is useful for always-on group behavior.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="有用的 BotFather 开关">
|
||||
<Accordion title="Helpful BotFather toggles">
|
||||
|
||||
- `/setjoingroups` 用于允许/拒绝加入群组
|
||||
- `/setprivacy` 用于群组可见性行为
|
||||
- `/setjoingroups` to allow/deny group adds
|
||||
- `/setprivacy` for group visibility behavior
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 访问控制和激活
|
||||
## Access control and activation
|
||||
|
||||
<Tabs>
|
||||
<Tab title="私信策略">
|
||||
`channels.telegram.dmPolicy` 控制直接消息访问:
|
||||
<Tab title="DM policy">
|
||||
`channels.telegram.dmPolicy` controls direct message access:
|
||||
|
||||
- `pairing`(默认)
|
||||
- `allowlist`(要求 `allowFrom` 中至少有一个发送者 ID)
|
||||
- `open`(要求 `allowFrom` 包含 `"*"`)
|
||||
- `pairing` (default)
|
||||
- `allowlist` (requires at least one sender ID in `allowFrom`)
|
||||
- `open` (requires `allowFrom` to include `"*"`)
|
||||
- `disabled`
|
||||
|
||||
`dmPolicy: "open"` 搭配 `allowFrom: ["*"]` 会允许任何找到或猜到 bot 用户名的 Telegram 账号向 bot 发送命令。仅应将其用于工具受到严格限制、刻意公开的 bot;单所有者 bot 应使用带数字用户 ID 的 `allowlist`。
|
||||
`dmPolicy: "open"` with `allowFrom: ["*"]` lets any Telegram account that finds or guesses the bot username command the bot. Use it only for intentionally public bots with tightly restricted tools; one-owner bots should use `allowlist` with numeric user IDs.
|
||||
|
||||
`channels.telegram.allowFrom` 接受数字 Telegram 用户 ID。`telegram:` / `tg:` 前缀会被接受并规范化。
|
||||
在多账号配置中,限制性的顶层 `channels.telegram.allowFrom` 会被视为安全边界:账号级 `allowFrom: ["*"]` 条目不会使该账号公开,除非合并后的有效账号允许列表仍包含显式通配符。
|
||||
`dmPolicy: "allowlist"` 搭配空的 `allowFrom` 会阻止所有私信,并会被配置验证拒绝。
|
||||
设置流程只会请求数字用户 ID。
|
||||
如果你已升级且配置中包含 `@username` 允许列表条目,请运行 `openclaw doctor --fix` 来解析它们(尽力而为;需要 Telegram bot token)。
|
||||
如果你之前依赖配对存储允许列表文件,`openclaw doctor --fix` 可以在允许列表流程中将条目恢复到 `channels.telegram.allowFrom`(例如当 `dmPolicy: "allowlist"` 尚无显式 ID 时)。
|
||||
`channels.telegram.allowFrom` accepts numeric Telegram user IDs. `telegram:` / `tg:` prefixes are accepted and normalized.
|
||||
In multi-account configs, a restrictive top-level `channels.telegram.allowFrom` is treated as a safety boundary: account-level `allowFrom: ["*"]` entries do not make that account public unless the effective account allowlist still contains an explicit wildcard after merging.
|
||||
`dmPolicy: "allowlist"` with empty `allowFrom` blocks all DMs and is rejected by config validation.
|
||||
Setup asks for numeric user IDs only.
|
||||
If you upgraded and your config contains `@username` allowlist entries, run `openclaw doctor --fix` to resolve them (best-effort; requires a Telegram bot token).
|
||||
If you previously relied on pairing-store allowlist files, `openclaw doctor --fix` can recover entries into `channels.telegram.allowFrom` in allowlist flows (for example when `dmPolicy: "allowlist"` has no explicit IDs yet).
|
||||
|
||||
对于单所有者 bot,建议使用 `dmPolicy: "allowlist"` 并配置显式数字 `allowFrom` ID,以便在配置中持久保存访问策略(而不是依赖之前的配对批准)。
|
||||
For one-owner bots, prefer `dmPolicy: "allowlist"` with explicit numeric `allowFrom` IDs to keep access policy durable in config (instead of depending on previous pairing approvals).
|
||||
|
||||
常见误解:私信配对批准并不意味着“此发送者在所有地方都已授权”。
|
||||
配对授予私信访问权限。如果尚不存在命令所有者,第一次批准的配对也会设置 `commands.ownerAllowFrom`,使仅所有者命令和 exec 批准拥有显式操作员账号。
|
||||
群组发送者授权仍来自显式配置允许列表。
|
||||
如果你想要“我授权一次后,私信和群组命令都可用”,请将你的数字 Telegram 用户 ID 放入 `channels.telegram.allowFrom`;对于仅所有者命令,请确保 `commands.ownerAllowFrom` 包含 `telegram:<your user id>`。
|
||||
Common confusion: DM pairing approval does not mean "this sender is authorized everywhere".
|
||||
Pairing grants DM access. If no command owner exists yet, the first approved pairing also sets `commands.ownerAllowFrom` so owner-only commands and exec approvals have an explicit operator account.
|
||||
Group sender authorization still comes from explicit config allowlists.
|
||||
If you want "I am authorized once and both DMs and group commands work", put your numeric Telegram user ID in `channels.telegram.allowFrom`; for owner-only commands, make sure `commands.ownerAllowFrom` contains `telegram:<your user id>`.
|
||||
|
||||
### 查找你的 Telegram 用户 ID
|
||||
### Finding your Telegram user ID
|
||||
|
||||
更安全(无第三方 bot):
|
||||
Safer (no third-party bot):
|
||||
|
||||
1. 给你的 bot 发送私信。
|
||||
2. 运行 `openclaw logs --follow`。
|
||||
3. 读取 `from.id`。
|
||||
1. DM your bot.
|
||||
2. Run `openclaw logs --follow`.
|
||||
3. Read `from.id`.
|
||||
|
||||
官方 Bot API 方法:
|
||||
Official Bot API method:
|
||||
|
||||
```bash
|
||||
curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
```
|
||||
|
||||
第三方方法(隐私性较低):`@userinfobot` 或 `@getidsbot`。
|
||||
Third-party method (less private): `@userinfobot` or `@getidsbot`.
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="群组策略和允许列表">
|
||||
两个控制项会共同生效:
|
||||
<Tab title="Group policy and allowlists">
|
||||
Two controls apply together:
|
||||
|
||||
1. **允许哪些群组**(`channels.telegram.groups`)
|
||||
- 没有 `groups` 配置:
|
||||
- 使用 `groupPolicy: "open"`:任何群组都可以通过群组 ID 检查
|
||||
- 使用 `groupPolicy: "allowlist"`(默认):群组会被阻止,直到你添加 `groups` 条目(或 `"*"`)
|
||||
- 已配置 `groups`:作为允许列表生效(显式 ID 或 `"*"`)
|
||||
1. **Which groups are allowed** (`channels.telegram.groups`)
|
||||
- no `groups` config:
|
||||
- with `groupPolicy: "open"`: any group can pass group-ID checks
|
||||
- with `groupPolicy: "allowlist"` (default): groups are blocked until you add `groups` entries (or `"*"`)
|
||||
- `groups` configured: acts as allowlist (explicit IDs or `"*"`)
|
||||
|
||||
2. **群组中允许哪些发送者**(`channels.telegram.groupPolicy`)
|
||||
2. **Which senders are allowed in groups** (`channels.telegram.groupPolicy`)
|
||||
- `open`
|
||||
- `allowlist`(默认)
|
||||
- `allowlist` (default)
|
||||
- `disabled`
|
||||
|
||||
`groupAllowFrom` 用于群组发送者过滤。如果未设置,Telegram 会回退到 `allowFrom`。
|
||||
`groupAllowFrom` 条目应为数字 Telegram 用户 ID(`telegram:` / `tg:` 前缀会被规范化)。
|
||||
不要将 Telegram 群组或超级群组聊天 ID 放入 `groupAllowFrom`。负数聊天 ID 应放在 `channels.telegram.groups` 下。
|
||||
非数字条目在发送者授权中会被忽略。
|
||||
安全边界(`2026.2.25+`):群组发送者认证**不会**继承私信配对存储批准。
|
||||
配对仅适用于私信。对于群组,请设置 `groupAllowFrom` 或每群组/每话题的 `allowFrom`。
|
||||
如果未设置 `groupAllowFrom`,Telegram 会回退到配置中的 `allowFrom`,而不是配对存储。
|
||||
单所有者 bot 的实用模式:在 `channels.telegram.allowFrom` 中设置你的用户 ID,保持 `groupAllowFrom` 未设置,并在 `channels.telegram.groups` 下允许目标群组。
|
||||
运行时说明:如果完全缺少 `channels.telegram`,除非显式设置了 `channels.defaults.groupPolicy`,否则运行时默认以失败关闭方式使用 `groupPolicy="allowlist"`。
|
||||
`groupAllowFrom` is used for group sender filtering. If not set, Telegram falls back to `allowFrom`.
|
||||
`groupAllowFrom` entries should be numeric Telegram user IDs (`telegram:` / `tg:` prefixes are normalized).
|
||||
Do not put Telegram group or supergroup chat IDs in `groupAllowFrom`. Negative chat IDs belong under `channels.telegram.groups`.
|
||||
Non-numeric entries are ignored for sender authorization.
|
||||
Security boundary (`2026.2.25+`): group sender auth does **not** inherit DM pairing-store approvals.
|
||||
Pairing stays DM-only. For groups, set `groupAllowFrom` or per-group/per-topic `allowFrom`.
|
||||
If `groupAllowFrom` is unset, Telegram falls back to config `allowFrom`, not the pairing store.
|
||||
Practical pattern for one-owner bots: set your user ID in `channels.telegram.allowFrom`, leave `groupAllowFrom` unset, and allow the target groups under `channels.telegram.groups`.
|
||||
Runtime note: if `channels.telegram` is completely missing, runtime defaults to fail-closed `groupPolicy="allowlist"` unless `channels.defaults.groupPolicy` is explicitly set.
|
||||
|
||||
示例:允许某个特定群组中的任何成员:
|
||||
Example: allow any member in one specific group:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -193,7 +193,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
示例:只允许某个特定群组中的特定用户:
|
||||
Example: allow only specific users inside one specific group:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -211,34 +211,34 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
```
|
||||
|
||||
<Warning>
|
||||
常见错误:`groupAllowFrom` 不是 Telegram 群组允许列表。
|
||||
Common mistake: `groupAllowFrom` is not a Telegram group allowlist.
|
||||
|
||||
- 将像 `-1001234567890` 这样的负数 Telegram 群组或超级群组聊天 ID 放在 `channels.telegram.groups` 下。
|
||||
- 当你想限制允许群组中哪些人可以触发 bot 时,将像 `8734062810` 这样的 Telegram 用户 ID 放在 `groupAllowFrom` 下。
|
||||
- 仅当你希望允许群组中的任何成员都能与 bot 对话时,才使用 `groupAllowFrom: ["*"]`。
|
||||
- Put negative Telegram group or supergroup chat IDs like `-1001234567890` under `channels.telegram.groups`.
|
||||
- Put Telegram user IDs like `8734062810` under `groupAllowFrom` when you want to limit which people inside an allowed group can trigger the bot.
|
||||
- Use `groupAllowFrom: ["*"]` only when you want any member of an allowed group to be able to talk to the bot.
|
||||
|
||||
</Warning>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="提及行为">
|
||||
群组回复默认需要提及。
|
||||
<Tab title="Mention behavior">
|
||||
Group replies require mention by default.
|
||||
|
||||
提及可以来自:
|
||||
Mention can come from:
|
||||
|
||||
- 原生 `@botusername` 提及,或
|
||||
- 以下位置的提及模式:
|
||||
- native `@botusername` mention, or
|
||||
- mention patterns in:
|
||||
- `agents.list[].groupChat.mentionPatterns`
|
||||
- `messages.groupChat.mentionPatterns`
|
||||
|
||||
会话级命令开关:
|
||||
Session-level command toggles:
|
||||
|
||||
- `/activation always`
|
||||
- `/activation mention`
|
||||
|
||||
这些只会更新会话状态。使用配置来持久化。
|
||||
These update session state only. Use config for persistence.
|
||||
|
||||
持久化配置示例:
|
||||
Persistent config example:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -252,45 +252,45 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
获取群组聊天 ID:
|
||||
Getting the group chat ID:
|
||||
|
||||
- 将群组消息转发给 `@userinfobot` / `@getidsbot`
|
||||
- 或从 `openclaw logs --follow` 读取 `chat.id`
|
||||
- 或检查 Bot API `getUpdates`
|
||||
- forward a group message to `@userinfobot` / `@getidsbot`
|
||||
- or read `chat.id` from `openclaw logs --follow`
|
||||
- or inspect Bot API `getUpdates`
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## 运行时行为
|
||||
## Runtime behavior
|
||||
|
||||
- Telegram 由 gateway 进程拥有。
|
||||
- 路由是确定性的:Telegram 入站消息会回复到 Telegram(模型不会选择渠道)。
|
||||
- 入站消息会规范化为共享渠道信封,包含回复元数据和媒体占位符。
|
||||
- 群组会话按群组 ID 隔离。论坛话题会追加 `:topic:<threadId>` 以保持话题隔离。
|
||||
- 私信消息可以携带 `message_thread_id`;OpenClaw 会保留线程 ID 用于回复,但默认保持私信使用扁平会话。当你有意需要私信话题会话隔离时,请配置 `channels.telegram.dm.threadReplies: "inbound"`、`channels.telegram.direct.<chatId>.threadReplies: "inbound"`、`requireTopic: true`,或匹配的话题配置。
|
||||
- 长轮询使用 grammY runner,并按每聊天/每线程排序。整体 runner sink 并发使用 `agents.defaults.maxConcurrent`。
|
||||
- 每个 gateway 进程内部都会保护长轮询,因此同一时间只有一个活跃 poller 可以使用一个 bot token。如果你仍然看到 `getUpdates` 409 冲突,很可能是另一个 OpenClaw gateway、脚本或外部 poller 正在使用同一个 token。
|
||||
- 默认情况下,长轮询看门狗重启会在 120 秒没有完成 `getUpdates` 存活检查后触发。只有当你的部署在长时间运行的工作期间仍看到误判的轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。该值以毫秒为单位,允许范围为 `30000` 到 `600000`;支持按账号覆盖。
|
||||
- Telegram Bot API 不支持已读回执(`sendReadReceipts` 不适用)。
|
||||
- Telegram is owned by the gateway process.
|
||||
- Routing is deterministic: Telegram inbound replies back to Telegram (the model does not pick channels).
|
||||
- Inbound messages normalize into the shared channel envelope with reply metadata and media placeholders.
|
||||
- Group sessions are isolated by group ID. Forum topics append `:topic:<threadId>` to keep topics isolated.
|
||||
- DM messages can carry `message_thread_id`; OpenClaw preserves the thread ID for replies but keeps DMs on the flat session by default. Configure `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct.<chatId>.threadReplies: "inbound"`, `requireTopic: true`, or a matching topic config when you intentionally want DM topic session isolation.
|
||||
- Long polling uses grammY runner with per-chat/per-thread sequencing. Overall runner sink concurrency uses `agents.defaults.maxConcurrent`.
|
||||
- Long polling is guarded inside each gateway process so only one active poller can use a bot token at a time. If you still see `getUpdates` 409 conflicts, another OpenClaw gateway, script, or external poller is likely using the same token.
|
||||
- Long-polling watchdog restarts trigger after 120 seconds without completed `getUpdates` liveness by default. Increase `channels.telegram.pollingStallThresholdMs` only if your deployment still sees false polling-stall restarts during long-running work. The value is in milliseconds and is allowed from `30000` to `600000`; per-account overrides are supported.
|
||||
- Telegram Bot API has no read-receipt support (`sendReadReceipts` does not apply).
|
||||
|
||||
## 功能参考
|
||||
## Feature reference
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="实时流式预览(消息编辑)">
|
||||
OpenClaw 可以实时流式传输部分回复:
|
||||
<Accordion title="Live stream preview (message edits)">
|
||||
OpenClaw can stream partial replies in real time:
|
||||
|
||||
- 直接聊天:预览消息 + `editMessageText`
|
||||
- 群组/话题:预览消息 + `editMessageText`
|
||||
- direct chats: preview message + `editMessageText`
|
||||
- groups/topics: preview message + `editMessageText`
|
||||
|
||||
要求:
|
||||
Requirement:
|
||||
|
||||
- `channels.telegram.streaming` 为 `off | partial | block | progress`(默认:`partial`)
|
||||
- `progress` 会保留一个可编辑的 Status 草稿,并使用工具进度更新它,直到最终送达
|
||||
- `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一条已编辑预览消息(默认:预览流式传输启用时为 `true`)
|
||||
- `streaming.preview.commandText` 控制这些工具进度行中的命令/exec 详情:`raw`(默认,保留已发布行为)或 `status`(仅工具标签)
|
||||
- 会检测旧版 `channels.telegram.streamMode` 和布尔型 `streaming` 值;运行 `openclaw doctor --fix` 将它们迁移到 `channels.telegram.streaming.mode`
|
||||
- `channels.telegram.streaming` is `off | partial | block | progress` (default: `partial`)
|
||||
- `progress` keeps one editable status draft and updates it with tool progress until final delivery
|
||||
- `streaming.preview.toolProgress` controls whether tool/progress updates reuse the same edited preview message (default: `true` when preview streaming is active)
|
||||
- `streaming.preview.commandText` controls command/exec detail inside those tool-progress lines: `raw` (default, preserves released behavior) or `status` (tool label only)
|
||||
- legacy `channels.telegram.streamMode` and boolean `streaming` values are detected; run `openclaw doctor --fix` to migrate them to `channels.telegram.streaming.mode`
|
||||
|
||||
工具进度预览更新是在工具运行时显示的短 Status 行,例如命令执行、文件读取、规划更新或 patch 摘要。Telegram 默认启用这些更新,以匹配 `v2026.4.22` 及之后版本中已发布的 OpenClaw 行为。若要保留答案文本的已编辑预览,但隐藏工具进度行,请设置:
|
||||
Tool-progress preview updates are the short status lines shown while tools run, for example command execution, file reads, planning updates, or patch summaries. Telegram keeps these enabled by default to match released OpenClaw behavior from `v2026.4.22` and later. To keep the edited preview for answer text but hide tool-progress lines, set:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -307,7 +307,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
若要保持工具进度可见但隐藏命令/exec 文本,请设置:
|
||||
To keep tool-progress visible but hide command/exec text, set:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -324,7 +324,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
对于进度草稿模式,将同样的命令文本策略放在 `streaming.progress` 下:
|
||||
对于进度草稿模式,将相同的命令文本策略放在 `streaming.progress` 下:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -342,34 +342,35 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
仅在你需要只交付最终内容时使用 `streaming.mode: "off"`:Telegram 预览编辑会被禁用,通用工具/进度杂讯会被抑制,而不是作为独立 Status 消息发送。审批提示、媒体载荷和错误仍会通过正常最终交付路径发送。当你只想保留回答预览编辑,同时隐藏工具进度 Status 行时,使用 `streaming.preview.toolProgress: false`。
|
||||
仅当你希望只进行最终交付时,才使用 `streaming.mode: "off"`:Telegram 预览编辑会被禁用,通用工具/进度杂讯会被抑制,而不是作为独立 Status 消息发送。审批提示、媒体载荷和错误仍会通过正常的最终交付路径路由。当你只想保留答案预览编辑,同时隐藏工具进度 Status 行时,使用 `streaming.preview.toolProgress: false`。
|
||||
|
||||
<Note>
|
||||
Telegram 选中引用回复是例外。当 `replyToMode` 为 `"first"`、`"all"` 或 `"batched"`,且入站消息包含选中的引用文本时,OpenClaw 会通过 Telegram 的原生引用回复路径发送最终回答,而不是编辑回答预览,因此 `streaming.preview.toolProgress` 无法显示该轮的简短 Status 行。不含选中引用文本的当前消息回复仍会保留预览流式传输。当工具进度可见性比原生引用回复更重要时,设置 `replyToMode: "off"`,或设置 `streaming.preview.toolProgress: false` 以确认这种取舍。
|
||||
Telegram 选中文本引用回复是例外。当 `replyToMode` 为 `"first"`、`"all"` 或 `"batched"`,且入站消息包含选中的引用文本时,OpenClaw 会通过 Telegram 的原生引用回复路径发送最终答案,而不是编辑答案预览,因此 `streaming.preview.toolProgress` 无法为该轮显示短 Status 行。没有选中引用文本的当前消息回复仍会保留预览流式传输。当工具进度可见性比原生引用回复更重要时,设置 `replyToMode: "off"`;或者设置 `streaming.preview.toolProgress: false` 以接受该取舍。
|
||||
</Note>
|
||||
|
||||
对于纯文本回复:
|
||||
|
||||
- 简短私信/群组/topic 预览:OpenClaw 会保留同一条预览消息,并在原位置执行最终编辑,除非预览出现后发送过一条可见的非预览消息
|
||||
- 预览之后跟随可见的非预览输出:OpenClaw 会将完成后的回复作为新的最终消息发送,并清理较旧的预览,因此最终回答会出现在中间输出之后
|
||||
- 超过约一分钟的预览:OpenClaw 会将完成后的回复作为新的最终消息发送,然后清理预览,因此 Telegram 的可见时间戳会反映完成时间,而不是预览创建时间
|
||||
- 简短私信/群组/topic 预览:OpenClaw 会保留同一条预览消息并在原位执行最终编辑,除非预览出现后发送过可见的非预览消息
|
||||
- 拆分成多条 Telegram 消息的长文本最终结果会尽可能复用现有预览作为第一个最终分块,然后只发送剩余分块
|
||||
- 预览之后出现可见的非预览输出:OpenClaw 会将完成后的回复作为新的最终消息发送,并清理旧预览,因此最终答案会出现在中间输出之后
|
||||
- 超过约一分钟的预览:OpenClaw 会将完成后的回复作为新的最终消息发送,然后清理预览,因此 Telegram 可见时间戳反映的是完成时间,而不是预览创建时间
|
||||
|
||||
对于复杂回复(例如媒体载荷),OpenClaw 会回退到正常最终交付,然后清理预览消息。
|
||||
对于复杂回复(例如媒体载荷),OpenClaw 会回退到正常的最终交付,然后清理预览消息。
|
||||
|
||||
预览流式传输与分块流式传输相互独立。当为 Telegram 显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。
|
||||
预览流式传输与分块流式传输是分开的。当为 Telegram 显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。
|
||||
|
||||
仅限 Telegram 的推理流:
|
||||
|
||||
- `/reasoning stream` 会在生成期间将推理发送到实时预览
|
||||
- `/reasoning stream` 会在生成过程中将推理发送到实时预览
|
||||
- 最终交付后会删除推理预览;当推理应保持可见时,使用 `/reasoning on`
|
||||
- 最终回答发送时不包含推理文本
|
||||
- 最终答案发送时不包含推理文本
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Formatting and HTML fallback">
|
||||
<Accordion title="格式化和 HTML 回退">
|
||||
出站文本使用 Telegram `parse_mode: "HTML"`。
|
||||
|
||||
- 类 Markdown 文本会渲染为 Telegram 安全的 HTML。
|
||||
- 类 Markdown 文本会渲染为 Telegram 安全 HTML。
|
||||
- 原始模型 HTML 会被转义,以减少 Telegram 解析失败。
|
||||
- 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。
|
||||
|
||||
@ -377,14 +378,14 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Native commands and custom commands">
|
||||
<Accordion title="原生命令和自定义命令">
|
||||
Telegram 命令菜单注册会在启动时通过 `setMyCommands` 处理。
|
||||
|
||||
原生命令默认值:
|
||||
|
||||
- `commands.native: "auto"` 会为 Telegram 启用原生命令
|
||||
- `commands.native: "auto"` 为 Telegram 启用原生命令
|
||||
|
||||
添加自定义命令菜单条目:
|
||||
添加自定义命令菜单项:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -401,47 +402,47 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
规则:
|
||||
|
||||
- 名称会规范化(去掉前导 `/`,转为小写)
|
||||
- 名称会被规范化(移除前导 `/`,转为小写)
|
||||
- 有效模式:`a-z`、`0-9`、`_`,长度 `1..32`
|
||||
- 自定义命令不能覆盖原生命令
|
||||
- 冲突/重复项会被跳过并记录日志
|
||||
|
||||
注意:
|
||||
|
||||
- 自定义命令只是菜单条目;它们不会自动实现行为
|
||||
- 插件/skill 命令即使未显示在 Telegram 菜单中,键入时仍可工作
|
||||
- 自定义命令仅是菜单项;它们不会自动实现行为
|
||||
- 即使未显示在 Telegram 菜单中,插件/skill 命令在输入时仍可工作
|
||||
|
||||
如果禁用原生命令,内置命令会被移除。自定义/插件命令在配置后仍可能注册。
|
||||
如果原生命令被禁用,内置命令会被移除。自定义/插件命令如果已配置,仍可能注册。
|
||||
|
||||
常见设置失败:
|
||||
|
||||
- `setMyCommands failed` 带 `BOT_COMMANDS_TOO_MUCH` 表示 Telegram 菜单在裁剪后仍溢出;减少插件/skill/自定义命令,或禁用 `channels.telegram.commands.native`。
|
||||
- 当直接的 Bot API curl 命令可用,但 `deleteWebhook`、`deleteMyCommands` 或 `setMyCommands` 因 `404: Not Found` 失败时,可能表示 `channels.telegram.apiRoot` 被设置为了完整的 `/bot<TOKEN>` 端点。`apiRoot` 必须只是 Bot API 根路径,`openclaw doctor --fix` 会移除意外尾随的 `/bot<TOKEN>`。
|
||||
- `getMe returned 401` 表示 Telegram 拒绝了配置的 bot 令牌。使用当前 BotFather 令牌更新 `botToken`、`tokenFile` 或 `TELEGRAM_BOT_TOKEN`;OpenClaw 会在轮询前停止,因此这不会被报告为 webhook 清理失败。
|
||||
- `setMyCommands failed` 带网络/fetch 错误通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻止。
|
||||
- `setMyCommands failed` 并带有 `BOT_COMMANDS_TOO_MUCH` 表示 Telegram 菜单在裁剪后仍然溢出;减少插件/skill/自定义命令,或禁用 `channels.telegram.commands.native`。
|
||||
- 当直接 Bot API curl 命令可用,但 `deleteWebhook`、`deleteMyCommands` 或 `setMyCommands` 失败并返回 `404: Not Found` 时,可能表示 `channels.telegram.apiRoot` 被设置为完整的 `/bot<TOKEN>` 端点。`apiRoot` 必须只是 Bot API 根地址,且 `openclaw doctor --fix` 会移除意外尾随的 `/bot<TOKEN>`。
|
||||
- `getMe returned 401` 表示 Telegram 拒绝了已配置的 bot token。用当前 BotFather token 更新 `botToken`、`tokenFile` 或 `TELEGRAM_BOT_TOKEN`;OpenClaw 会在轮询前停止,因此这不会被报告为 webhook 清理失败。
|
||||
- `setMyCommands failed` 并带有网络/fetch 错误通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻止。
|
||||
|
||||
### 设备配对命令(`device-pair` 插件)
|
||||
|
||||
安装 `device-pair` 插件后:
|
||||
|
||||
1. `/pair` 生成设置代码
|
||||
2. 在 iOS 应用中粘贴代码
|
||||
2. 在 iOS app 中粘贴代码
|
||||
3. `/pair pending` 列出待处理请求(包括角色/作用域)
|
||||
4. 批准请求:
|
||||
- `/pair approve <requestId>` 用于显式批准
|
||||
- `/pair approve` 用于只有一个待处理请求的情况
|
||||
- `/pair approve latest` 用于最新请求
|
||||
- 当只有一个待处理请求时使用 `/pair approve`
|
||||
- `/pair approve latest` 用于最近的请求
|
||||
|
||||
设置代码携带一个短期有效的引导令牌。内置引导交接会将主节点令牌保持在 `scopes: []`;任何交接的 operator 令牌仍被限制在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。引导作用域检查带有角色前缀,因此该 operator 允许列表只满足 operator 请求;非 operator 角色仍需要其自身角色前缀下的作用域。
|
||||
设置代码携带一个短生命周期的 bootstrap token。内置 bootstrap 移交会将主节点 token 保持在 `scopes: []`;任何被移交的 operator token 都会被限定在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。Bootstrap 作用域检查带有角色前缀,因此该 operator 允许列表只满足 operator 请求;非 operator 角色仍需要其自身角色前缀下的作用域。
|
||||
|
||||
如果设备使用变更后的认证详细信息重试(例如角色/作用域/公钥),之前的待处理请求会被取代,新的请求会使用不同的 `requestId`。批准前请重新运行 `/pair pending`。
|
||||
如果设备使用变更后的认证详细信息(例如角色/作用域/公钥)重试,之前的待处理请求会被取代,新请求会使用不同的 `requestId`。批准前重新运行 `/pair pending`。
|
||||
|
||||
更多详情:[配对](/zh-CN/channels/pairing#pair-via-telegram-recommended-for-ios)。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Inline buttons">
|
||||
配置内联键盘范围:
|
||||
<Accordion title="内联按钮">
|
||||
配置内联键盘作用域:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -473,7 +474,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
范围:
|
||||
作用域:
|
||||
|
||||
- `off`
|
||||
- `dm`
|
||||
@ -506,16 +507,16 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Telegram message actions for agents and automation">
|
||||
<Accordion title="用于智能体和自动化的 Telegram 消息操作">
|
||||
Telegram 工具操作包括:
|
||||
|
||||
- `sendMessage`(`to`、`content`、可选 `mediaUrl`、`replyToMessageId`、`messageThreadId`)
|
||||
- `sendMessage`(`to`、`content`,可选 `mediaUrl`、`replyToMessageId`、`messageThreadId`)
|
||||
- `react`(`chatId`、`messageId`、`emoji`)
|
||||
- `deleteMessage`(`chatId`、`messageId`)
|
||||
- `editMessage`(`chatId`、`messageId`、`content`)
|
||||
- `createForumTopic`(`chatId`、`name`、可选 `iconColor`、`iconCustomEmojiId`)
|
||||
- `createForumTopic`(`chatId`、`name`,可选 `iconColor`、`iconCustomEmojiId`)
|
||||
|
||||
渠道消息操作会暴露符合人体工学的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。
|
||||
频道消息操作暴露了符合人体工程学的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。
|
||||
|
||||
门控控制:
|
||||
|
||||
@ -524,14 +525,14 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
- `channels.telegram.actions.reactions`
|
||||
- `channels.telegram.actions.sticker`(默认:禁用)
|
||||
|
||||
注意:`edit` 和 `topic-create` 当前默认启用,并且没有单独的 `channels.telegram.actions.*` 开关。
|
||||
运行时发送使用活动配置/密钥快照(启动/重载),因此操作路径不会在每次发送时执行临时 SecretRef 重新解析。
|
||||
注意:`edit` 和 `topic-create` 当前默认启用,且没有单独的 `channels.telegram.actions.*` 开关。
|
||||
运行时发送使用活动配置/secrets 快照(启动/重新加载),因此操作路径不会在每次发送时执行临时 SecretRef 重新解析。
|
||||
|
||||
移除回应的语义:[/tools/reactions](/zh-CN/tools/reactions)
|
||||
Reaction 移除语义:[/tools/reactions](/zh-CN/tools/reactions)
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Reply threading tags">
|
||||
<Accordion title="回复线程标签">
|
||||
Telegram 支持在生成输出中使用显式回复线程标签:
|
||||
|
||||
- `[[reply_to_current]]` 回复触发消息
|
||||
@ -543,29 +544,29 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
- `first`
|
||||
- `all`
|
||||
|
||||
当启用回复线程,且原始 Telegram 文本或说明文字可用时,OpenClaw 会自动包含原生 Telegram 引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元,因此较长消息会从开头引用;如果 Telegram 拒绝该引用,则回退为普通回复。
|
||||
当回复线程启用且原始 Telegram 文本或标题可用时,OpenClaw 会自动包含原生 Telegram 引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元,因此更长的消息会从开头引用;如果 Telegram 拒绝引用,则回退为普通回复。
|
||||
|
||||
注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Forum topics and thread behavior">
|
||||
论坛超级群组:
|
||||
<Accordion title="Forum topic 和线程行为">
|
||||
Forum supergroup:
|
||||
|
||||
- topic 会话键会追加 `:topic:<threadId>`
|
||||
- 回复和正在输入目标指向 topic 线程
|
||||
- 回复和正在输入操作会指向 topic 线程
|
||||
- topic 配置路径:
|
||||
`channels.telegram.groups.<chatId>.topics.<threadId>`
|
||||
|
||||
常规 topic(`threadId=1`)特殊情况:
|
||||
General topic(`threadId=1`)特殊情况:
|
||||
|
||||
- 消息发送会省略 `message_thread_id`(Telegram 会拒绝 `sendMessage(...thread_id=1)`)
|
||||
- 正在输入操作仍包含 `message_thread_id`
|
||||
- 正在输入操作仍会包含 `message_thread_id`
|
||||
|
||||
Topic 继承:topic 条目会继承群组设置,除非被覆盖(`requireMention`、`allowFrom`、`skills`、`systemPrompt`、`enabled`、`groupPolicy`)。
|
||||
`agentId` 仅限 topic,不会从群组默认值继承。
|
||||
`agentId` 仅属于 topic,不会从群组默认值继承。
|
||||
|
||||
**按 topic 的智能体路由**:每个 topic 都可以通过在 topic 配置中设置 `agentId` 路由到不同的智能体。这会让每个 topic 拥有各自隔离的工作区、记忆和会话。示例:
|
||||
**按 topic 的智能体路由**:每个 topic 都可以通过在 topic 配置中设置 `agentId` 路由到不同智能体。这让每个 topic 都有自己的隔离工作区、记忆和会话。示例:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -585,26 +586,24 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
然后每个 topic 都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3`
|
||||
随后每个 topic 都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3`
|
||||
|
||||
**持久 ACP topic 绑定**:论坛 topic 可以通过顶层类型化 ACP 绑定固定 ACP harness 会话(`bindings[]`,包含 `type: "acp"` 和 `match.channel: "telegram"`、`peer.kind: "group"`,以及类似 `-1001234567890:topic:42` 的 topic 限定 id)。当前范围限定为群组/超级群组中的论坛 topic。参见 [ACP Agents](/zh-CN/tools/acp-agents)。
|
||||
**持久 ACP topic 绑定**:Forum topic 可以通过顶层类型化 ACP 绑定(`bindings[]`,包含 `type: "acp"`、`match.channel: "telegram"`、`peer.kind: "group"`,以及类似 `-1001234567890:topic:42` 的 topic 限定 id)固定 ACP harness 会话。当前作用域限于群组/supergroup 中的 forum topic。参见 [ACP Agents](/zh-CN/tools/acp-agents)。
|
||||
|
||||
**从聊天创建线程绑定 ACP**:`/acp spawn <agent> --thread here|auto` 会将当前 topic 绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会将创建确认固定在 topic 内。需要 `channels.telegram.threadBindings.spawnSessions` 保持启用(默认:`true`)。
|
||||
**从聊天生成线程绑定 ACP**:`/acp spawn <agent> --thread here|auto` 将当前 topic 绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会在 topic 内固定生成确认。需要保持启用 `channels.telegram.threadBindings.spawnSessions`(默认:`true`)。
|
||||
|
||||
模板上下文会暴露 `MessageThreadId` 和 `IsForum`。带有 `message_thread_id` 的私信聊天默认在扁平会话上保留私信路由和回复元数据;只有在配置了 `threadReplies: "inbound"`、`threadReplies: "always"`、`requireTopic: true` 或匹配的 topic 配置时,才会使用线程感知的会话键。使用顶层 `channels.telegram.dm.threadReplies` 设置账户默认值,或使用 `direct.<chatId>.threadReplies` 设置单个私信。
|
||||
模板上下文会暴露 `MessageThreadId` 和 `IsForum`。带有 `message_thread_id` 的私信聊天默认在扁平会话上保留私信路由和回复元数据;只有在配置了 `threadReplies: "inbound"`、`threadReplies: "always"`、`requireTopic: true` 或匹配的主题配置时,它们才会使用线程感知的会话键。使用顶层 `channels.telegram.dm.threadReplies` 作为账号默认值,或使用 `direct.<chatId>.threadReplies` 针对某个私信设置。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="音频、视频和贴纸">
|
||||
<Accordion title="Audio, video, and stickers">
|
||||
### 音频消息
|
||||
|
||||
Telegram 会区分语音便签和音频文件。
|
||||
Telegram 会区分语音消息和音频文件。
|
||||
|
||||
- 默认:音频文件行为
|
||||
- 在智能体回复中添加标签 `[[audio_as_voice]]`,强制以语音便签发送
|
||||
- 入站语音便签转写会在智能体上下文中被标记为机器生成、
|
||||
不受信任的文本;提及检测仍使用原始
|
||||
转写,因此受提及门控的语音消息会继续工作。
|
||||
- 在智能体回复中添加标签 `[[audio_as_voice]]` 可强制作为语音消息发送
|
||||
- 入站语音消息的转录会在智能体上下文中被标记为机器生成的、不受信任的文本;提及检测仍使用原始转录,因此受提及门控的语音消息会继续生效。
|
||||
|
||||
消息操作示例:
|
||||
|
||||
@ -620,7 +619,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
### 视频消息
|
||||
|
||||
Telegram 会区分视频文件和视频便签。
|
||||
Telegram 会区分视频文件和视频消息。
|
||||
|
||||
消息操作示例:
|
||||
|
||||
@ -634,7 +633,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
}
|
||||
```
|
||||
|
||||
视频便签不支持字幕;提供的消息文本会单独发送。
|
||||
视频消息不支持说明文字;提供的消息文本会单独发送。
|
||||
|
||||
### 贴纸
|
||||
|
||||
@ -656,7 +655,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
- `~/.openclaw/telegram/sticker-cache.json`
|
||||
|
||||
贴纸会被描述一次(如果可行)并缓存,以减少重复的视觉调用。
|
||||
贴纸会被描述一次(如果可行),并缓存以减少重复的视觉调用。
|
||||
|
||||
启用贴纸操作:
|
||||
|
||||
@ -696,10 +695,10 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="回应通知">
|
||||
Telegram 回应会作为 `message_reaction` 更新到达(与消息载荷分离)。
|
||||
<Accordion title="Reaction notifications">
|
||||
Telegram 表情回应会以 `message_reaction` 更新形式到达(独立于消息负载)。
|
||||
|
||||
启用后,OpenClaw 会将如下系统事件加入队列:
|
||||
启用后,OpenClaw 会将类似下面的系统事件加入队列:
|
||||
|
||||
- `Telegram reaction added: 👍 by Alice (@alice) on msg 42`
|
||||
|
||||
@ -708,36 +707,36 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
- `channels.telegram.reactionNotifications`:`off | own | all`(默认:`own`)
|
||||
- `channels.telegram.reactionLevel`:`off | ack | minimal | extensive`(默认:`minimal`)
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- `own` 表示仅用户对机器人发送消息的回应(通过已发送消息缓存尽力实现)。
|
||||
- 回应事件仍遵循 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。
|
||||
- Telegram 不会在回应更新中提供线程 ID。
|
||||
- 非论坛群组路由到群组聊天会话
|
||||
- 论坛群组路由到群组通用 topic 会话(`:topic:1`),而不是确切的来源 topic
|
||||
- `own` 表示仅用户对机器人发送消息的表情回应(通过已发送消息缓存尽力判断)。
|
||||
- 表情回应事件仍遵守 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。
|
||||
- Telegram 不会在表情回应更新中提供线程 ID。
|
||||
- 非论坛群组会路由到群聊会话
|
||||
- 论坛群组会路由到群组通用主题会话(`:topic:1`),而不是确切的来源主题
|
||||
|
||||
轮询/webhook 的 `allowed_updates` 会自动包含 `message_reaction`。
|
||||
用于轮询/webhook 的 `allowed_updates` 会自动包含 `message_reaction`。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="ACK 回应">
|
||||
`ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认 emoji。
|
||||
<Accordion title="Ack reactions">
|
||||
`ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认表情符号。
|
||||
|
||||
解析顺序:
|
||||
|
||||
- `channels.telegram.accounts.<accountId>.ackReaction`
|
||||
- `channels.telegram.ackReaction`
|
||||
- `messages.ackReaction`
|
||||
- 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 "👀")
|
||||
- 智能体身份表情符号回退值(`agents.list[].identity.emoji`,否则为 “👀”)
|
||||
|
||||
注意事项:
|
||||
说明:
|
||||
|
||||
- Telegram 期望使用 unicode emoji(例如 "👀")。
|
||||
- 使用 `""` 可为某个渠道或账户禁用回应。
|
||||
- Telegram 期望 unicode 表情符号(例如 “👀”)。
|
||||
- 使用 `""` 可为某个渠道或账号禁用该表情回应。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="来自 Telegram 事件和命令的配置写入">
|
||||
<Accordion title="Config writes from Telegram events and commands">
|
||||
渠道配置写入默认启用(`configWrites !== false`)。
|
||||
|
||||
Telegram 触发的写入包括:
|
||||
@ -759,32 +758,32 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="长轮询与 webhook">
|
||||
默认使用长轮询。对于 webhook 模式,设置 `channels.telegram.webhookUrl` 和 `channels.telegram.webhookSecret`;可选设置 `webhookPath`、`webhookHost`、`webhookPort`(默认值为 `/telegram-webhook`、`127.0.0.1`、`8787`)。
|
||||
<Accordion title="Long polling vs webhook">
|
||||
默认使用长轮询。若要使用 webhook 模式,请设置 `channels.telegram.webhookUrl` 和 `channels.telegram.webhookSecret`;可选设置 `webhookPath`、`webhookHost`、`webhookPort`(默认分别为 `/telegram-webhook`、`127.0.0.1`、`8787`)。
|
||||
|
||||
本地监听器绑定到 `127.0.0.1:8787`。对于公网入口,可以在本地端口前放置反向代理,或有意设置 `webhookHost: "0.0.0.0"`。
|
||||
|
||||
webhook 模式会先验证请求守卫、Telegram secret token 和 JSON 正文,然后才向 Telegram 返回 `200`。
|
||||
随后 OpenClaw 会通过与长轮询相同的每聊天/每 topic 机器人通道异步处理该更新,因此较慢的智能体轮次不会阻塞 Telegram 的投递 ACK。
|
||||
webhook 模式会在向 Telegram 返回 `200` 之前验证请求防护、Telegram secret token 和 JSON 正文。
|
||||
随后 OpenClaw 会通过与长轮询相同的按聊天/按主题机器人通道异步处理该更新,因此较慢的智能体回合不会阻塞 Telegram 的投递 ACK。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="限制、重试和 CLI 目标">
|
||||
<Accordion title="Limits, retry, and CLI targets">
|
||||
- `channels.telegram.textChunkLimit` 默认值为 4000。
|
||||
- `channels.telegram.chunkMode="newline"` 在按长度拆分前会优先选择段落边界(空行)。
|
||||
- `channels.telegram.chunkMode="newline"` 会优先按段落边界(空行)切分,再按长度切分。
|
||||
- `channels.telegram.mediaMaxMb`(默认 100)限制入站和出站 Telegram 媒体大小。
|
||||
- `channels.telegram.mediaGroupFlushMs`(默认 500)控制 Telegram 相册/媒体组在 OpenClaw 将其作为一条入站消息分发前的缓冲时长。如果相册部分到达较晚,请增大该值;如果要降低相册回复延迟,请减小该值。
|
||||
- `channels.telegram.timeoutSeconds` 覆盖 Telegram API 客户端超时(如果未设置,则使用 grammY 默认值)。机器人客户端会将配置值限制在低于 60 秒出站文本/typing 请求守卫的范围内,避免 grammY 在 OpenClaw 的传输守卫和回退运行前中止可见回复投递。长轮询仍使用 45 秒的 `getUpdates` 请求守卫,因此空闲轮询不会被无限期遗弃。
|
||||
- `channels.telegram.pollingStallThresholdMs` 默认值为 `120000`;仅在误报轮询停滞重启时,在 `30000` 到 `600000` 之间调节。
|
||||
- `channels.telegram.mediaGroupFlushMs`(默认 500)控制 Telegram 相册/媒体组在 OpenClaw 将其作为一条入站消息分发前缓冲多久。如果相册部分到达较晚,请增大该值;若要降低相册回复延迟,请减小该值。
|
||||
- `channels.telegram.timeoutSeconds` 会覆盖 Telegram API 客户端超时(若未设置,则使用 grammY 默认值)。机器人客户端会将配置值限制在 60 秒出站文本/输入状态请求防护以下,避免 grammY 在 OpenClaw 的传输防护和回退逻辑运行前中止可见回复投递。长轮询仍使用 45 秒 `getUpdates` 请求防护,因此空闲轮询不会被无限期放弃。
|
||||
- `channels.telegram.pollingStallThresholdMs` 默认值为 `120000`;只有在出现误报的轮询停滞重启时,才在 `30000` 到 `600000` 之间调节。
|
||||
- 群组上下文历史使用 `channels.telegram.historyLimit` 或 `messages.groupChat.historyLimit`(默认 50);`0` 表示禁用。
|
||||
- 回复/引用/转发的补充上下文目前按接收内容传递。
|
||||
- Telegram 允许列表主要用于控制谁可以触发智能体,而不是完整的补充上下文删减边界。
|
||||
- 回复/引用/转发的补充上下文目前会按收到的内容传递。
|
||||
- Telegram 允许列表主要控制谁能触发智能体,而不是完整的补充上下文脱敏边界。
|
||||
- 私信历史控制:
|
||||
- `channels.telegram.dmHistoryLimit`
|
||||
- `channels.telegram.dms["<user_id>"].historyLimit`
|
||||
- `channels.telegram.retry` 配置适用于 Telegram 发送辅助函数(CLI/工具/操作),用于可恢复的出站 API 错误。入站最终回复投递也会对 Telegram 预连接失败使用有界安全发送重试,但不会重试可能造成可见消息重复的模糊发送后网络信封。
|
||||
- `channels.telegram.retry` 配置适用于 Telegram 发送辅助函数(CLI/工具/操作)中的可恢复出站 API 错误。入站最终回复投递也会针对 Telegram 预连接失败使用有界安全发送重试,但不会重试可能导致可见消息重复的模糊发送后网络封装。
|
||||
|
||||
CLI 和消息工具发送目标可以是数字聊天 ID、用户名或论坛 topic 目标:
|
||||
CLI 和消息工具发送目标可以是数字聊天 ID、用户名或论坛主题目标:
|
||||
|
||||
```bash
|
||||
openclaw message send --channel telegram --target 123456789 --message "hi"
|
||||
@ -792,7 +791,7 @@ openclaw message send --channel telegram --target @name --message "hi"
|
||||
openclaw message send --channel telegram --target -1001234567890:topic:42 --message "hi topic"
|
||||
```
|
||||
|
||||
Telegram 投票使用 `openclaw message poll`,并支持论坛 topic:
|
||||
Telegram 投票使用 `openclaw message poll`,并支持论坛主题:
|
||||
|
||||
```bash
|
||||
openclaw message poll --channel telegram --target 123456789 \
|
||||
@ -802,57 +801,57 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
|
||||
--poll-duration-seconds 300 --poll-public
|
||||
```
|
||||
|
||||
仅 Telegram 的投票标志:
|
||||
仅 Telegram 支持的投票标志:
|
||||
|
||||
- `--poll-duration-seconds`(5-600)
|
||||
- `--poll-duration-seconds` (5-600)
|
||||
- `--poll-anonymous`
|
||||
- `--poll-public`
|
||||
- 用于论坛 topic 的 `--thread-id`(或使用 `:topic:` 目标)
|
||||
- `--thread-id` 用于论坛主题(或使用 `:topic:` 目标)
|
||||
|
||||
Telegram 发送还支持:
|
||||
|
||||
- 当 `channels.telegram.capabilities.inlineButtons` 允许时,将 `--presentation` 与 `buttons` 块配合用于内联键盘
|
||||
- 当 `channels.telegram.capabilities.inlineButtons` 允许时,使用带 `buttons` 块的 `--presentation` 创建内联键盘
|
||||
- 当机器人可以在该聊天中置顶时,使用 `--pin` 或 `--delivery '{"pin":true}'` 请求置顶投递
|
||||
- 使用 `--force-document` 将出站图片和 GIF 作为文档发送,而不是压缩照片或动画媒体上传
|
||||
|
||||
操作门控:
|
||||
|
||||
- `channels.telegram.actions.sendMessage=false` 会禁用出站 Telegram 消息,包括投票
|
||||
- `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,同时保留常规发送启用
|
||||
- `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,但保留常规发送功能
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Telegram 中的 exec 批准">
|
||||
Telegram 支持在批准者私信中进行 exec 批准,也可以选择在来源聊天或 topic 中发布提示。批准者必须是数字 Telegram 用户 ID。
|
||||
<Accordion title="Exec approvals in Telegram">
|
||||
Telegram 支持在审批者私信中进行 exec 审批,也可以选择在来源聊天或主题中发布提示。审批者必须是数字 Telegram 用户 ID。
|
||||
|
||||
配置路径:
|
||||
|
||||
- `channels.telegram.execApprovals.enabled`(当至少一个批准者可解析时自动启用)
|
||||
- `channels.telegram.execApprovals.approvers`(回退到 `commands.ownerAllowFrom` 中的数字 owner ID)
|
||||
- `channels.telegram.execApprovals.enabled`(当至少一个审批者可解析时自动启用)
|
||||
- `channels.telegram.execApprovals.approvers`(回退到 `commands.ownerAllowFrom` 中的数字所有者 ID)
|
||||
- `channels.telegram.execApprovals.target`:`dm`(默认)| `channel` | `both`
|
||||
- `agentFilter`、`sessionFilter`
|
||||
|
||||
`channels.telegram.allowFrom`、`groupAllowFrom` 和 `defaultTo` 控制谁可以与机器人对话,以及机器人把普通回复发送到哪里。它们不会让某人成为 exec 批准者。当尚无命令 owner 时,第一个已批准的私信配对会引导初始化 `commands.ownerAllowFrom`,因此单 owner 设置仍可工作,而无需在 `execApprovals.approvers` 下重复 ID。
|
||||
`channels.telegram.allowFrom`、`groupAllowFrom` 和 `defaultTo` 控制谁可以与机器人对话以及机器人将普通回复发送到哪里。它们不会让某人成为 exec 审批者。当尚不存在命令所有者时,首次获批的私信配对会引导生成 `commands.ownerAllowFrom`,因此单所有者设置仍可正常工作,而不必在 `execApprovals.approvers` 下重复 ID。
|
||||
|
||||
渠道投递会在聊天中显示命令文本;仅在受信任的群组/topic 中启用 `channel` 或 `both`。当提示落在论坛 topic 中时,OpenClaw 会为批准提示和后续消息保留该 topic。exec 批准默认在 30 分钟后过期。
|
||||
渠道投递会在聊天中显示命令文本;只应在受信任的群组/主题中启用 `channel` 或 `both`。当提示落在论坛主题中时,OpenClaw 会为审批提示和后续消息保留该主题。exec 审批默认在 30 分钟后过期。
|
||||
|
||||
内联批准按钮还要求 `channels.telegram.capabilities.inlineButtons` 允许目标表面(`dm`、`group` 或 `all`)。以 `plugin:` 为前缀的批准 ID 会通过插件批准解析;其他 ID 会先通过 exec 批准解析。
|
||||
内联审批按钮还要求 `channels.telegram.capabilities.inlineButtons` 允许目标界面(`dm`、`group` 或 `all`)。以 `plugin:` 为前缀的审批 ID 会通过插件审批解析;其他 ID 会先通过 exec 审批解析。
|
||||
|
||||
请参阅 [exec 批准](/zh-CN/tools/exec-approvals)。
|
||||
参见 [Exec 审批](/zh-CN/tools/exec-approvals)。
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 错误回复控制
|
||||
|
||||
当智能体遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制错误回复。两个配置键控制此行为:
|
||||
当智能体遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制它。两个配置键控制此行为:
|
||||
|
||||
| 键 | 值 | 默认值 | 描述 |
|
||||
| ----------------------------------- | ----------------- | ------- | --------------------------------------------------------------------------------------- |
|
||||
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 会向聊天发送一条友好的错误消息。`silent` 会完全抑制错误回复。 |
|
||||
| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | 向同一聊天发送错误回复的最小间隔时间。防止中断期间出现错误垃圾消息。 |
|
||||
| 键 | 值 | 默认值 | 描述 |
|
||||
| ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 会向聊天发送友好的错误消息。`silent` 会完全抑制错误回复。 |
|
||||
| `channels.telegram.errorCooldownMs` | 数字(毫秒) | `60000` | 同一聊天两次错误回复之间的最短时间。防止故障期间产生错误刷屏。 |
|
||||
|
||||
支持按账户、按群组和按 topic 覆盖(继承方式与其他 Telegram 配置键相同)。
|
||||
支持按账号、按群组和按主题覆盖(继承方式与其他 Telegram 配置键相同)。
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -873,13 +872,13 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
|
||||
## 故障排除
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="机器人不响应未提及它的群组消息">
|
||||
<Accordion title="Bot does not respond to non mention group messages">
|
||||
|
||||
- 如果 `requireMention=false`,Telegram 隐私模式必须允许完整可见性。
|
||||
- BotFather:`/setprivacy` -> Disable
|
||||
- 然后将机器人从群组中移除并重新添加
|
||||
- 当配置预期接收未提及机器人的群组消息时,`openclaw channels status` 会发出警告。
|
||||
- `openclaw channels status --probe` 可以检查显式数字群组 ID;通配符 `"*"` 无法进行成员探测。
|
||||
- 然后移除机器人并重新添加到群组
|
||||
- 当配置预期接收未提及的群组消息时,`openclaw channels status` 会发出警告。
|
||||
- `openclaw channels status --probe` 可以检查明确的数字群组 ID;通配符 `"*"` 无法探测成员资格。
|
||||
- 快速会话测试:`/activation always`。
|
||||
|
||||
</Accordion>
|
||||
@ -887,8 +886,8 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
|
||||
<Accordion title="机器人完全看不到群组消息">
|
||||
|
||||
- 当 `channels.telegram.groups` 存在时,群组必须被列出(或包含 `"*"`)
|
||||
- 验证机器人在群组中的成员身份
|
||||
- 查看日志:`openclaw logs --follow` 以了解跳过原因
|
||||
- 验证机器人在群组中的成员资格
|
||||
- 查看日志:使用 `openclaw logs --follow` 查看跳过原因
|
||||
|
||||
</Accordion>
|
||||
|
||||
@ -896,33 +895,33 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
|
||||
|
||||
- 授权你的发送者身份(配对和/或数字 `allowFrom`)
|
||||
- 即使群组策略为 `open`,命令授权仍然适用
|
||||
- `setMyCommands failed` 携带 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;减少插件/skill/自定义命令,或禁用原生菜单
|
||||
- `deleteMyCommands` / `setMyCommands` 启动调用和 `sendChatAction` 输入状态调用都有边界限制,并会在请求超时时通过 Telegram 的传输回退重试一次。持续的网络/抓取错误通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题
|
||||
- `setMyCommands failed` 与 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;减少插件/Skill/自定义命令,或禁用原生命令菜单
|
||||
- `deleteMyCommands` / `setMyCommands` 启动调用和 `sendChatAction` 正在输入调用都有边界限制,并会在请求超时时通过 Telegram 的传输回退重试一次。持续的网络/抓取错误通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="启动报告未授权令牌">
|
||||
|
||||
- `getMe returned 401` 是已配置机器人令牌的 Telegram 身份验证失败。
|
||||
- 在 BotFather 中重新复制或重新生成机器人令牌,然后更新默认账户的 `channels.telegram.botToken`、`channels.telegram.tokenFile`、`channels.telegram.accounts.<id>.botToken` 或 `TELEGRAM_BOT_TOKEN`。
|
||||
- 启动期间出现 `deleteWebhook 401 Unauthorized` 也是身份验证失败;将其视为“没有 webhook 存在”只会把相同的错误令牌失败推迟到后续 API 调用。
|
||||
- `getMe returned 401` 是配置的机器人令牌发生 Telegram 身份验证失败。
|
||||
- 在 BotFather 中重新复制或重新生成机器人令牌,然后为默认账号更新 `channels.telegram.botToken`、`channels.telegram.tokenFile`、`channels.telegram.accounts.<id>.botToken` 或 `TELEGRAM_BOT_TOKEN`。
|
||||
- 启动期间的 `deleteWebhook 401 Unauthorized` 也是身份验证失败;将其视为“webhook 不存在”只会把同一个错误令牌失败推迟到后续 API 调用。
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="轮询或网络不稳定">
|
||||
|
||||
- Node 22+ + 自定义 fetch/proxy 在 AbortSignal 类型不匹配时可能触发立即中止行为。
|
||||
- 一些主机会先将 `api.telegram.org` 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性的 Telegram API 失败。
|
||||
- 如果日志包含 `TypeError: fetch failed` 或 `Network request for 'getUpdates' failed!`,OpenClaw 现在会将这些作为可恢复的网络错误重试。
|
||||
- 在轮询启动期间,OpenClaw 会为 grammY 复用启动时成功的 `getMe` 探测,因此运行器在第一次 `getUpdates` 之前不需要第二次 `getMe`。
|
||||
- 如果 `deleteWebhook` 在轮询启动期间因瞬时网络错误失败,OpenClaw 会继续进入长轮询,而不是再发起一次预轮询控制平面调用。仍处于活动状态的 webhook 会表现为 `getUpdates` 冲突;随后 OpenClaw 会重建 Telegram 传输并重试 webhook 清理。
|
||||
- 如果 Telegram 套接字按较短的固定周期回收,请检查是否存在过低的 `channels.telegram.timeoutSeconds`;机器人客户端会将低于出站和 `getUpdates` 请求保护值的配置值钳制到保护值以上,但旧版本在该值低于这些保护值时可能会中止每次轮询或回复。
|
||||
- 如果日志包含 `Polling stall detected`,OpenClaw 默认会在 120 秒没有完成长轮询存活信号后重启轮询并重建 Telegram 传输。
|
||||
- 当运行中的轮询账户在启动宽限期后未完成 `getUpdates`、运行中的 webhook 账户在启动宽限期后未完成 `setWebhook`,或最近一次成功的轮询传输活动已过期时,`openclaw channels status --probe` 和 `openclaw doctor` 会发出警告。
|
||||
- 仅当长时间运行的 `getUpdates` 调用健康、但你的主机仍报告误报的轮询停滞重启时,才增大 `channels.telegram.pollingStallThresholdMs`。持续停滞通常指向主机与 `api.telegram.org` 之间的代理、DNS、IPv6 或 TLS 出站问题。
|
||||
- Telegram 也会遵循 Bot API 传输的进程代理环境,包括 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 及其小写变体。`NO_PROXY` / `no_proxy` 仍可绕过 `api.telegram.org`。
|
||||
- 如果服务环境中通过 `OPENCLAW_PROXY_URL` 配置了 OpenClaw 托管代理,并且不存在标准代理环境,Telegram 也会将该 URL 用于 Bot API 传输。
|
||||
- 在直接出站/TLS 不稳定的 VPS 主机上,通过 `channels.telegram.proxy` 路由 Telegram API 调用:
|
||||
- Node 22+ + 自定义 fetch/proxy 可能会在 AbortSignal 类型不匹配时触发立即中止行为。
|
||||
- 某些主机会先将 `api.telegram.org` 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性 Telegram API 失败。
|
||||
- 如果日志包含 `TypeError: fetch failed` 或 `Network request for 'getUpdates' failed!`,OpenClaw 现在会将这些错误作为可恢复的网络错误重试。
|
||||
- 在轮询启动期间,OpenClaw 会为 grammY 复用成功的启动 `getMe` 探测,因此运行器在第一次 `getUpdates` 之前不需要第二次 `getMe`。
|
||||
- 如果 `deleteWebhook` 在轮询启动期间因瞬态网络错误失败,OpenClaw 会继续进入长轮询,而不是再发起一次轮询前的控制平面调用。仍处于活动状态的 webhook 会表现为 `getUpdates` 冲突;随后 OpenClaw 会重建 Telegram 传输并重试 webhook 清理。
|
||||
- 如果 Telegram 套接字按较短的固定周期回收,请检查是否设置了较低的 `channels.telegram.timeoutSeconds`;机器人客户端会将低于出站和 `getUpdates` 请求保护值的配置值钳制到保护值以上,但旧版本在该值低于这些保护值时可能会中止每次轮询或回复。
|
||||
- 如果日志包含 `Polling stall detected`,默认情况下,OpenClaw 会在 120 秒内没有完成的长轮询存活信号后重启轮询并重建 Telegram 传输。
|
||||
- 当正在运行的轮询账号在启动宽限期后尚未完成 `getUpdates`、正在运行的 webhook 账号在启动宽限期后尚未完成 `setWebhook`,或最后一次成功的轮询传输活动已过期时,`openclaw channels status --probe` 和 `openclaw doctor` 会发出警告。
|
||||
- 仅当长时间运行的 `getUpdates` 调用健康,但你的主机仍报告错误的轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。持续停滞通常指向主机与 `api.telegram.org` 之间的代理、DNS、IPv6 或 TLS 出站问题。
|
||||
- Telegram 也会遵循用于 Bot API 传输的进程代理环境变量,包括 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 及其小写变体。`NO_PROXY` / `no_proxy` 仍可绕过 `api.telegram.org`。
|
||||
- 如果在服务环境中通过 `OPENCLAW_PROXY_URL` 配置了 OpenClaw 托管代理,并且不存在标准代理环境变量,Telegram 也会将该 URL 用于 Bot API 传输。
|
||||
- 在直连出站/TLS 不稳定的 VPS 主机上,通过 `channels.telegram.proxy` 路由 Telegram API 调用:
|
||||
|
||||
```yaml
|
||||
channels:
|
||||
@ -930,8 +929,8 @@ channels:
|
||||
proxy: socks5://<user>:<password>@proxy-host:1080
|
||||
```
|
||||
|
||||
- Node 22+ 默认使用 `autoSelectFamily=true`(WSL2 除外)。Telegram DNS 结果顺序依次遵循 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`、`channels.telegram.network.dnsResultOrder`、进程默认值(例如 `NODE_OPTIONS=--dns-result-order=ipv4first`);如果都不适用,Node 22+ 会回退到 `ipv4first`。
|
||||
- 如果你的主机是 WSL2,或明确在仅 IPv4 行为下工作得更好,请强制选择地址族:
|
||||
- Node 22+ 默认使用 `autoSelectFamily=true`(WSL2 除外)。Telegram DNS 结果顺序依次遵循 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`、`channels.telegram.network.dnsResultOrder`,然后是进程默认值,例如 `NODE_OPTIONS=--dns-result-order=ipv4first`;如果都不适用,Node 22+ 会回退到 `ipv4first`。
|
||||
- 如果你的主机是 WSL2,或明确在仅 IPv4 行为下工作更好,请强制选择地址族:
|
||||
|
||||
```yaml
|
||||
channels:
|
||||
@ -940,7 +939,7 @@ channels:
|
||||
autoSelectFamily: false
|
||||
```
|
||||
|
||||
- 默认已允许 Telegram 媒体下载使用 RFC 2544 基准测试范围应答(`198.18.0.0/15`)。如果可信的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写为其他私有/内部/特殊用途地址,你可以选择启用仅限 Telegram 的绕过:
|
||||
- 默认情况下,Telegram 媒体下载已允许 RFC 2544 基准测试范围答案(`198.18.0.0/15`)。如果可信的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写为其他私有/内部/特殊用途地址,你可以选择启用仅限 Telegram 的绕过:
|
||||
|
||||
```yaml
|
||||
channels:
|
||||
@ -949,22 +948,19 @@ channels:
|
||||
dangerouslyAllowPrivateNetwork: true
|
||||
```
|
||||
|
||||
- 同一选择启用项也可按账户配置在
|
||||
- 同一个可选启用项也可在每个账号级别使用:
|
||||
`channels.telegram.accounts.<accountId>.network.dangerouslyAllowPrivateNetwork`。
|
||||
- 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持
|
||||
危险标志关闭。Telegram 媒体默认已允许 RFC 2544
|
||||
基准测试范围。
|
||||
- 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544 基准测试范围。
|
||||
|
||||
<Warning>
|
||||
`channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram
|
||||
媒体 SSRF 防护。仅在可信的运营者控制代理环境中使用,例如 Clash、Mihomo 或 Surge fake-IP 路由,并且它们会合成 RFC 2544 基准测试范围之外的私有或特殊用途应答。对于普通公网 Telegram 访问,请保持关闭。
|
||||
`channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram 媒体 SSRF 防护。仅在可信、由操作方控制的代理环境中使用它,例如 Clash、Mihomo 或 Surge fake-IP 路由,并且这些环境会合成 RFC 2544 基准测试范围之外的私有或特殊用途答案。对于普通公共互联网 Telegram 访问,请保持关闭。
|
||||
</Warning>
|
||||
|
||||
- 环境覆盖(临时):
|
||||
- `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1`
|
||||
- `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1`
|
||||
- `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first`
|
||||
- 验证 DNS 应答:
|
||||
- 验证 DNS 答案:
|
||||
|
||||
```bash
|
||||
dig +short api.telegram.org A
|
||||
@ -984,7 +980,7 @@ dig +short api.telegram.org AAAA
|
||||
|
||||
- 启动/身份验证:`enabled`、`botToken`、`tokenFile`、`accounts.*`(`tokenFile` 必须指向常规文件;符号链接会被拒绝)
|
||||
- 访问控制:`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`、`groups`、`groups.*.topics.*`、顶层 `bindings[]`(`type: "acp"`)
|
||||
- 执行审批:`execApprovals`、`accounts.*.execApprovals`
|
||||
- exec 批准:`execApprovals`、`accounts.*.execApprovals`
|
||||
- 命令/菜单:`commands.native`、`commands.nativeSkills`、`customCommands`
|
||||
- 线程/回复:`replyToMode`、`dm.threadReplies`、`direct.*.threadReplies`
|
||||
- 流式传输:`streaming`(预览)、`streaming.preview.toolProgress`、`blockStreaming`
|
||||
@ -993,14 +989,14 @@ dig +short api.telegram.org AAAA
|
||||
- 自定义 API 根:`apiRoot`(仅 Bot API 根;不要包含 `/bot<TOKEN>`)
|
||||
- webhook:`webhookUrl`、`webhookSecret`、`webhookPath`、`webhookHost`
|
||||
- 操作/能力:`capabilities.inlineButtons`、`actions.sendMessage|editMessage|deleteMessage|reactions|sticker`
|
||||
- 表情回应:`reactionNotifications`、`reactionLevel`
|
||||
- reaction:`reactionNotifications`、`reactionLevel`
|
||||
- 错误:`errorPolicy`、`errorCooldownMs`
|
||||
- 写入/历史记录:`configWrites`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit`
|
||||
- 写入/历史:`configWrites`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit`
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Note>
|
||||
多账户优先级:当配置了两个或更多账户 ID 时,设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`)以明确默认路由。否则 OpenClaw 会回退到第一个规范化账户 ID,且 `openclaw doctor` 会发出警告。命名账户会继承 `channels.telegram.allowFrom` / `groupAllowFrom`,但不会继承 `accounts.default.*` 值。
|
||||
多账号优先级:当配置了两个或更多账号 ID 时,请设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`)以明确默认路由。否则 OpenClaw 会回退到第一个规范化后的账号 ID,并且 `openclaw doctor` 会发出警告。命名账号会继承 `channels.telegram.allowFrom` / `groupAllowFrom`,但不会继承 `accounts.default.*` 值。
|
||||
</Note>
|
||||
|
||||
## 相关
|
||||
|
||||
380
docs/zh-CN/ci.md
380
docs/zh-CN/ci.md
@ -1,94 +1,94 @@
|
||||
---
|
||||
read_when:
|
||||
- 你需要了解为什么某个 CI 作业运行了或没有运行
|
||||
- 你正在调试一个失败的 GitHub Actions 检查
|
||||
- 你正在协调一次发布验证的运行或重新运行
|
||||
- 你正在调试一项失败的 GitHub Actions 检查
|
||||
- 你正在协调发布验证的运行或重新运行
|
||||
- 你正在更改 ClawSweeper 调度或 GitHub 活动转发
|
||||
summary: CI 作业图、作用域门禁、发布总括任务和本地等价命令
|
||||
summary: CI 作业图、范围门控、发布总括任务和本地命令等价项
|
||||
title: CI 流水线
|
||||
x-i18n:
|
||||
generated_at: "2026-05-05T01:33:54Z"
|
||||
generated_at: "2026-05-05T04:27:03Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 16771940889d1fa944a5bfafe1152a033d96625595a2d89ff2cedbd3022cee66
|
||||
source_hash: 31fe6704e18f9efc519a1a73fc3aa8ae3909d6a27553874eb477e73979a94af2
|
||||
source_path: ci.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
OpenClaw CI 会在每次推送到 `main` 和每个拉取请求上运行。`preflight` 作业会分类差异,并在只有无关区域发生变更时关闭昂贵的流水线。手动 `workflow_dispatch` 运行会有意绕过智能作用域划分,并为发布候选版本和广泛验证展开完整图。Android 流水线通过 `include_android` 保持可选启用。仅发布阶段的插件覆盖位于单独的 [`Plugin Prerelease`](#plugin-prerelease) 工作流中,并且只会从 [`Full Release Validation`](#full-release-validation) 或显式手动分发运行。
|
||||
OpenClaw CI 在每次推送到 `main` 以及每个 pull request 上运行。`preflight` 作业会对 diff 分类,并在只有无关区域发生变更时关闭昂贵的 lane。手动 `workflow_dispatch` 运行会有意绕过智能范围限定,并为候选发布版本和广泛验证展开完整图。Android lane 通过 `include_android` 保持选择加入。仅发布使用的插件覆盖率位于单独的 [`Plugin Prerelease`](#plugin-prerelease) workflow 中,并且只会从 [`Full Release Validation`](#full-release-validation) 或显式手动 dispatch 运行。
|
||||
|
||||
## 流水线概览
|
||||
|
||||
| 作业 | 目的 | 运行时机 |
|
||||
| 作业 | 用途 | 运行时机 |
|
||||
| -------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------- |
|
||||
| `preflight` | 检测仅文档变更、变更作用域、变更插件,并构建 CI 清单 | 始终在非草稿推送和 PR 上运行 |
|
||||
| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 始终在非草稿推送和 PR 上运行 |
|
||||
| `security-dependency-audit` | 针对 npm advisories 进行无依赖的生产锁文件审计 | 始终在非草稿推送和 PR 上运行 |
|
||||
| `security-fast` | 快速安全作业的必需聚合项 | 始终在非草稿推送和 PR 上运行 |
|
||||
| `check-dependencies` | 生产 Knip 仅依赖检查加未使用文件 allowlist 守卫 | Node 相关变更 |
|
||||
| `preflight` | 检测仅文档变更、变更范围、变更插件,并构建 CI 清单 | 始终在非 draft 推送和 PR 上运行 |
|
||||
| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和 workflow 审计 | 始终在非 draft 推送和 PR 上运行 |
|
||||
| `security-dependency-audit` | 针对 npm 公告,对 production lockfile 进行无依赖审计 | 始终在非 draft 推送和 PR 上运行 |
|
||||
| `security-fast` | 快速安全作业所需的聚合项 | 始终在非 draft 推送和 PR 上运行 |
|
||||
| `check-dependencies` | 仅 production Knip 依赖检查,加上未使用文件 allowlist 守卫 | Node 相关变更 |
|
||||
| `build-artifacts` | 构建 `dist/`、Control UI、构建产物检查,以及可复用的下游产物 | Node 相关变更 |
|
||||
| `checks-fast-core` | 快速 Linux 正确性流水线,例如内置插件/插件契约/协议检查 | Node 相关变更 |
|
||||
| `checks-fast-contracts-channels` | 分片的渠道契约检查,带有稳定的聚合检查结果 | Node 相关变更 |
|
||||
| `checks-node-core-test` | 核心 Node 测试分片,不包括渠道、内置、契约和插件流水线 | Node 相关变更 |
|
||||
| `check` | 分片的主本地门禁等价项:生产类型、lint、守卫、测试类型和严格 smoke | Node 相关变更 |
|
||||
| `checks-fast-core` | 快速 Linux 正确性 lane,例如内置插件、插件契约和协议检查 | Node 相关变更 |
|
||||
| `checks-fast-contracts-channels` | 分片的渠道契约检查,并提供稳定的聚合检查结果 | Node 相关变更 |
|
||||
| `checks-node-core-test` | Core Node 测试分片,排除渠道、内置、契约和插件 lane | Node 相关变更 |
|
||||
| `check` | 分片的主要本地 gate 等价项:production 类型、lint、守卫、测试类型和严格 smoke | Node 相关变更 |
|
||||
| `check-additional` | 架构、分片边界/提示词漂移、插件守卫、包边界和 Gateway 网关 watch | Node 相关变更 |
|
||||
| `build-smoke` | 已构建 CLI smoke 测试和启动内存 smoke | Node 相关变更 |
|
||||
| `checks` | 构建产物渠道测试的验证器 | Node 相关变更 |
|
||||
| `checks-node-compat-node22` | Node 22 兼容性构建和 smoke 流水线 | 发布用手动 CI 分发 |
|
||||
| `check-docs` | 文档格式、lint 和断链检查 | 文档已变更 |
|
||||
| `skills-python` | Python 支持的 Skills 的 Ruff + pytest | Python Skill 相关变更 |
|
||||
| `checks-windows` | Windows 专用进程/路径测试,以及共享运行时导入说明符回归测试 | Windows 相关变更 |
|
||||
| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试流水线 | macOS 相关变更 |
|
||||
| `checks-node-compat-node22` | Node 22 兼容性构建和 smoke lane | 发布版手动 CI dispatch |
|
||||
| `check-docs` | 文档格式化、lint 和断链检查 | 文档变更 |
|
||||
| `skills-python` | Python 支撑的 Skills 的 Ruff + pytest | Python Skill 相关变更 |
|
||||
| `checks-windows` | Windows 专用进程/路径测试,加上共享运行时导入 specifier 回归检查 | Windows 相关变更 |
|
||||
| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试 lane | macOS 相关变更 |
|
||||
| `macos-swift` | macOS 应用的 Swift lint、构建和测试 | macOS 相关变更 |
|
||||
| `android` | 两种 flavor 的 Android 单元测试加一个 debug APK 构建 | Android 相关变更 |
|
||||
| `test-performance-agent` | 受信任活动后的每日 Codex 慢测试优化 | 主 CI 成功或手动分发 |
|
||||
| `openclaw-performance` | 每日/按需 Kova 运行时性能报告,包含 mock-provider、deep-profile 和 GPT 5.4 live 流水线 | 定时和手动分发 |
|
||||
| `android` | 两种 flavor 的 Android 单元测试,加上一个 debug APK 构建 | Android 相关变更 |
|
||||
| `test-performance-agent` | 可信活动之后的每日 Codex 慢测试优化 | 主 CI 成功或手动 dispatch |
|
||||
| `openclaw-performance` | 每日/按需的 Kova 运行时性能报告,包含 mock provider、deep profile 和 GPT 5.4 live lane | 定时和手动 dispatch |
|
||||
|
||||
## Fail-fast 顺序
|
||||
## 快速失败顺序
|
||||
|
||||
1. `preflight` 决定哪些流水线会存在。`docs-scope` 和 `changed-scope` 逻辑是此作业内的步骤,不是独立作业。
|
||||
2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而不等待更重的产物和平台矩阵作业。
|
||||
3. `build-artifacts` 会与快速 Linux 流水线重叠运行,这样下游消费者可以在共享构建准备好后立即开始。
|
||||
4. 更重的平台和运行时流水线随后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。
|
||||
1. `preflight` 决定哪些 lane 实际存在。`docs-scope` 和 `changed-scope` 逻辑是此作业内部的步骤,而不是独立作业。
|
||||
2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,无需等待更重的产物和平台矩阵作业。
|
||||
3. `build-artifacts` 与快速 Linux lane 重叠运行,使下游消费者可以在共享构建就绪后立即开始。
|
||||
4. 更重的平台和运行时 lane 随后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。
|
||||
|
||||
当同一个 PR 或 `main` ref 上有更新的推送落地时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个工作流已经被取代后继续排队。自动 CI 并发键带版本号(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸项无法无限期阻塞新的 main 运行。手动全套件运行使用 `CI-manual-v1-*`,并且不会取消正在进行的运行。
|
||||
当同一个 PR 或 `main` ref 上有更新的推送落地时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个 workflow 已被取代后继续排队。自动 CI 并发键带有版本号(`CI-v7-*`),因此 GitHub 侧旧队列组中的僵尸项不能无限期阻塞较新的 main 运行。手动全套件运行使用 `CI-manual-v1-*`,并且不会取消正在进行的运行。
|
||||
|
||||
## 作用域和路由
|
||||
## 范围和路由
|
||||
|
||||
作用域逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。手动分发会跳过 changed-scope 检测,并让 preflight 清单表现得像每个受作用域约束的区域都已变更一样。
|
||||
范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。手动 dispatch 会跳过 changed-scope 检测,并让 preflight 清单表现得像每个限定范围区域都发生了变更。
|
||||
|
||||
- **CI 工作流编辑**会验证 Node CI 图和工作流 linting,但不会单独强制 Windows、Android 或 macOS 原生构建;这些平台流水线仍限定为平台源代码变更。
|
||||
- **仅 CI 路由编辑、选定的廉价核心测试 fixture 编辑,以及窄范围插件契约 helper/测试路由编辑**使用快速 Node-only 清单路径:`preflight`、security 和单个 `checks-fast-core` 任务。当变更仅限于该快速任务直接执行的路由或 helper 表面时,该路径会跳过构建产物、Node 22 兼容性、渠道契约、完整核心分片、内置插件分片和额外守卫矩阵。
|
||||
- **Windows Node 检查**限定于 Windows 专用进程/路径 wrapper、npm/pnpm/UI runner helper、包管理器配置,以及执行该流水线的 CI 工作流表面;无关源码、插件、install-smoke 和仅测试变更仍留在 Linux Node 流水线上。
|
||||
- **CI workflow 编辑**会验证 Node CI 图和 workflow lint,但其本身不会强制运行 Windows、Android 或 macOS native 构建;这些平台 lane 仍限定在平台源代码变更上。
|
||||
- **仅 CI 路由编辑、选定的廉价 core-test fixture 编辑,以及窄范围插件契约 helper/test-routing 编辑**使用快速 Node-only 清单路径:`preflight`、security 和单个 `checks-fast-core` 任务。当变更仅限于快速任务直接覆盖的路由或 helper 表面时,该路径会跳过构建产物、Node 22 兼容性、渠道契约、完整 core 分片、内置插件分片和额外守卫矩阵。
|
||||
- **Windows Node 检查**限定在 Windows 专用进程/路径 wrapper、npm/pnpm/UI runner helper、包管理器配置,以及执行该 lane 的 CI workflow 表面;无关源代码、插件、install-smoke 和仅测试变更会留在 Linux Node lane 上。
|
||||
|
||||
最慢的 Node 测试族会被拆分或均衡,使每个作业保持较小规模且不过度预留 runner:渠道契约作为三个加权分片运行,核心单元 fast/support 流水线单独运行,核心运行时基础设施拆分为 state 和 process/config 分片,auto-reply 以均衡 worker 运行(reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片),agentic Gateway 网关/server 配置拆分到 chat/auth/model/http-plugin/runtime/startup 流水线,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试使用各自专用的 Vitest 配置,而不是共享插件 catch-all。Include-pattern 分片使用 CI 分片名称记录 timing 条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分整个配置和过滤后的分片。`check-additional` 将 package-boundary compile/canary 工作放在一起,并将运行时拓扑架构与 Gateway 网关 watch 覆盖分开;边界守卫列表跨四个矩阵分片条带化,每个分片并发运行选定的独立守卫并打印每项检查的 timing,包括 `pnpm prompt:snapshots:check`,这样 Codex 运行时 happy-path 提示词漂移会固定到导致它的 PR 上。Gateway 网关 watch、渠道测试和核心 support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已经构建完成后,在 `build-artifacts` 内并发运行。
|
||||
最慢的 Node 测试族会被拆分或均衡,使每个作业保持较小规模而不过度预留 runner:渠道契约作为三个加权分片运行,core unit fast/support lane 单独运行,core runtime infra 在 state 和 process/config 分片之间拆分,auto-reply 作为均衡 worker 运行(reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片),agentic gateway/server 配置则拆分到 chat/auth/model/http-plugin/runtime/startup lane 中,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试使用其专用 Vitest 配置,而不是共享插件 catch-all。Include-pattern 分片使用 CI 分片名称记录计时条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分完整配置和过滤后的分片。`check-additional` 将 package-boundary compile/canary 工作保持在一起,并将运行时拓扑架构与 Gateway 网关 watch 覆盖率分开;边界守卫列表按四个矩阵分片条带化,每个分片并发运行选定的独立守卫并打印每项检查的计时,包括 `pnpm prompt:snapshots:check`,这样 Codex 运行时 happy-path 提示词漂移会被钉在造成它的 PR 上。Gateway 网关 watch、渠道测试和 core support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已构建完成后,在 `build-artifacts` 内部并发运行。
|
||||
|
||||
Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。third-party flavor 没有单独的 source set 或 manifest;其单元测试流水线仍会使用 SMS/call-log BuildConfig 标志编译该 flavor,同时避免在每个 Android 相关推送上重复执行 debug APK 打包作业。
|
||||
Android CI 会运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,随后构建 Play debug APK。third-party flavor 没有单独的 source set 或 manifest;它的单元测试 lane 仍会使用 SMS/call-log BuildConfig flag 编译该 flavor,同时避免在每次 Android 相关推送上重复执行 debug APK 打包作业。
|
||||
|
||||
`check-dependencies` 分片运行 `pnpm deadcode:dependencies`(生产 Knip 仅依赖检查,固定到最新 Knip 版本,并为 `dlx` 安装禁用 pnpm 的最小发布年龄)和 `pnpm deadcode:unused-files`,后者会将 Knip 的生产未使用文件发现结果与 `scripts/deadcode-unused-files.allowlist.mjs` 进行比较。当 PR 添加新的未审查未使用文件,或留下过期 allowlist 条目时,未使用文件守卫会失败,同时保留 Knip 无法静态解析的有意动态插件、生成内容、构建、live-test 和包桥接表面。
|
||||
`check-dependencies` 分片运行 `pnpm deadcode:dependencies`(仅 production Knip 依赖检查,固定到最新 Knip 版本,并在 `dlx` 安装中禁用 pnpm 的最低发布年龄限制)和 `pnpm deadcode:unused-files`,后者会将 Knip 的 production 未使用文件发现与 `scripts/deadcode-unused-files.allowlist.mjs` 进行比较。当 PR 添加新的未经审查的未使用文件,或留下陈旧 allowlist 条目时,未使用文件守卫会失败,同时保留 Knip 无法静态解析的有意动态插件、生成内容、构建、live-test 和包 bridge 表面。
|
||||
|
||||
## ClawSweeper 活动转发
|
||||
|
||||
`.github/workflows/clawsweeper-dispatch.yml` 是从 OpenClaw 仓库活动到 ClawSweeper 的目标侧桥接。它不会检出或执行不受信任的拉取请求代码。该工作流会从 `CLAWSWEEPER_APP_PRIVATE_KEY` 创建 GitHub App token,然后向 `openclaw/clawsweeper` 分发紧凑的 `repository_dispatch` payload。
|
||||
`.github/workflows/clawsweeper-dispatch.yml` 是从 OpenClaw 仓库活动到 ClawSweeper 的目标侧 bridge。它不会 checkout 或执行不可信的 pull request 代码。该 workflow 会从 `CLAWSWEEPER_APP_PRIVATE_KEY` 创建 GitHub App token,然后向 `openclaw/clawsweeper` dispatch 紧凑的 `repository_dispatch` payload。
|
||||
|
||||
该工作流有四条流水线:
|
||||
该 workflow 有四个 lane:
|
||||
|
||||
- `clawsweeper_item` 用于精确的 issue 和拉取请求审查请求;
|
||||
- `clawsweeper_comment` 用于 issue 评论中的显式 ClawSweeper 命令;
|
||||
- `clawsweeper_commit_review` 用于 `main` 推送上的提交级审查请求;
|
||||
- `clawsweeper_item` 用于精确 issue 和 pull request review 请求;
|
||||
- `clawsweeper_comment` 用于 issue comment 中显式的 ClawSweeper 命令;
|
||||
- `clawsweeper_commit_review` 用于 `main` 推送上的 commit 级 review 请求;
|
||||
- `github_activity` 用于 ClawSweeper agent 可能检查的一般 GitHub 活动。
|
||||
|
||||
`github_activity` 流水线仅转发规范化元数据:事件类型、操作、actor、仓库、条目编号、URL、标题、状态,以及存在评论或审查时的短摘录。它有意避免转发完整 webhook body。`openclaw/clawsweeper` 中的接收工作流是 `.github/workflows/github-activity.yml`,它会将规范化事件发布到 OpenClaw Gateway 网关 hook,供 ClawSweeper agent 使用。
|
||||
`github_activity` lane 只转发规范化元数据:事件类型、action、actor、仓库、item 编号、URL、标题、状态,以及存在 comment 或 review 时的简短摘录。它有意避免转发完整 webhook body。`openclaw/clawsweeper` 中接收方 workflow 是 `.github/workflows/github-activity.yml`,它会将规范化事件发布到 ClawSweeper agent 的 OpenClaw Gateway 网关 hook。
|
||||
|
||||
一般活动是观察,而不是默认投递。ClawSweeper agent 会在其提示词中接收 Discord 目标,并且只有当事件令人意外、可操作、有风险或对运营有用时,才应发布到 `#clawsweeper`。常规打开、编辑、bot 变动、重复 webhook 噪声和正常审查流量都应产生 `NO_REPLY`。
|
||||
一般活动是观察,而不是默认投递。ClawSweeper agent 会在其提示词中接收 Discord 目标,并且只有在事件令人意外、可行动、有风险或具有运维用途时才应发布到 `#clawsweeper`。常规打开、编辑、bot churn、重复 webhook 噪声和正常 review 流量应产生 `NO_REPLY`。
|
||||
|
||||
在这条路径中,始终将 GitHub 标题、评论、正文、审查文本、分支名称和提交消息视为不受信任的数据。它们是摘要和分流的输入,而不是工作流或 agent 运行时的指令。
|
||||
在整个路径中,将 GitHub 标题、comment、body、review 文本、分支名称和 commit message 视为不可信数据。它们是摘要和分流的输入,不是 workflow 或 agent 运行时的指令。
|
||||
|
||||
## 手动分发
|
||||
## 手动 dispatch
|
||||
|
||||
手动 CI 触发会运行与普通 CI 相同的作业图,但会强制启用每个非 Android 范围通道:Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python Skills、Windows、macOS 和 Control UI i18n。独立的手动 CI 触发仅在 `include_android=true` 时运行 Android;完整发布总括流程通过传入 `include_android=true` 启用 Android。插件预发布静态检查、仅发布使用的 `agentic-plugins` 分片、完整插件批量扫描以及插件预发布 Docker 通道均排除在 CI 之外。Docker 预发布套件只会在 `Full Release Validation` 触发单独的 `Plugin Prerelease` 工作流并启用发布验证门禁时运行。
|
||||
手动 CI 调度运行与普通 CI 相同的作业图,但会强制开启所有非 Android 作用域的 lane:Linux Node 分片、内置插件分片、渠道合约、Node 22 兼容性、`check`、`check-additional`、构建 smoke、文档检查、Python Skills、Windows、macOS 和 Control UI i18n。独立的手动 CI 调度仅在 `include_android=true` 时运行 Android;完整发布总控通过传入 `include_android=true` 启用 Android。插件预发布静态检查、仅发布用的 `agentic-plugins` 分片、完整扩展批量 sweep,以及插件预发布 Docker lane 均不包含在 CI 中。Docker 预发布套件仅在 `Full Release Validation` 以启用发布验证 gate 的方式调度单独的 `Plugin Prerelease` 工作流时运行。
|
||||
|
||||
手动运行使用唯一的并发组,因此候选发布版本的完整套件不会被同一 ref 上的其他 push 或 PR 运行取消。可选的 `target_ref` 输入允许受信任的调用方在使用所选触发 ref 中工作流文件的同时,针对某个分支、标签或完整提交 SHA 运行该作业图。
|
||||
手动运行使用唯一的并发组,因此候选发布版本的完整套件不会被同一 ref 上的其他 push 或 PR 运行取消。可选的 `target_ref` 输入允许受信任调用方在使用所选调度 ref 中的工作流文件时,针对分支、标签或完整提交 SHA 运行该作业图。
|
||||
|
||||
```bash
|
||||
gh workflow run ci.yml --ref release/YYYY.M.D
|
||||
@ -100,10 +100,10 @@ gh workflow run full-release-validation.yml --ref main -f ref=<branch-or-sha>
|
||||
|
||||
| 运行器 | 作业 |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ubuntu-24.04` | `preflight`、快速安全作业和聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速协议/契约/内置检查、分片渠道契约检查、除 lint 之外的 `check` 分片、`check-additional` 分片和聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,这样 Blacksmith 矩阵可以更早排队 |
|
||||
| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`、较低权重的插件分片、`checks-fast-core`、`checks-node-compat-node22`、`check-prod-types` 和 `check-test-types` |
|
||||
| `ubuntu-24.04` | `preflight`,快速安全作业和聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`),快速协议/合约/内置检查,分片渠道合约检查,除 lint 外的 `check` 分片,`check-additional` 分片和聚合,Node 测试聚合验证器,文档检查,Python Skills,workflow-sanity,labeler,auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,以便 Blacksmith 矩阵可以更早排队 |
|
||||
| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`、较低权重的扩展分片、`checks-fast-core`、`checks-node-compat-node22`、`check-prod-types` 和 `check-test-types` |
|
||||
| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`、build-smoke、Linux Node 测试分片、内置插件测试分片、`android` |
|
||||
| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(对 CPU 足够敏感,以至于 8 vCPU 的成本高于节省的时间);install-smoke Docker 构建(32-vCPU 排队时间的成本高于节省的时间) |
|
||||
| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(对 CPU 足够敏感,8 vCPU 的成本高于节省的时间);install-smoke Docker 构建(32 vCPU 的排队时间成本高于节省的时间) |
|
||||
| `blacksmith-16vcpu-windows-2025` | `checks-windows` |
|
||||
| `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-node`;fork 回退到 `macos-latest` |
|
||||
| `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-swift`;fork 回退到 `macos-latest` |
|
||||
@ -137,7 +137,7 @@ pnpm perf:kova:summary --report .artifacts/kova/reports/mock-provider/report.jso
|
||||
|
||||
## OpenClaw 性能
|
||||
|
||||
`OpenClaw Performance` 是产品/运行时性能工作流。它每天在 `main` 上运行,也可以手动触发:
|
||||
`OpenClaw Performance` 是产品/运行时性能工作流。它每天在 `main` 上运行,也可以手动调度:
|
||||
|
||||
```bash
|
||||
gh workflow run openclaw-performance.yml --ref main -f profile=diagnostic -f repeat=3
|
||||
@ -145,25 +145,25 @@ gh workflow run openclaw-performance.yml --ref main -f profile=smoke -f repeat=1
|
||||
gh workflow run openclaw-performance.yml --ref main -f target_ref=v2026.5.2 -f profile=diagnostic -f repeat=3
|
||||
```
|
||||
|
||||
手动触发通常会对工作流 ref 进行基准测试。设置 `target_ref` 可使用当前工作流实现对发布标签或其他分支进行基准测试。已发布报告路径和 latest 指针按被测试 ref 编排,每个 `index.md` 都会记录被测试的 ref/SHA、工作流 ref/SHA、Kova ref、profile、通道认证模式、模型、重复次数和场景过滤器。
|
||||
手动调度通常会对工作流 ref 进行基准测试。设置 `target_ref` 可使用当前工作流实现对发布标签或其他分支进行基准测试。已发布的报告路径和 latest 指针按被测试的 ref 编码,每个 `index.md` 都记录被测试的 ref/SHA、工作流 ref/SHA、Kova ref、profile、lane 认证模式、模型、重复次数和场景过滤器。
|
||||
|
||||
该工作流会从固定版本安装 OCM,并从 `openclaw/Kova` 的固定 `kova_ref` 输入安装 Kova,然后运行三个通道:
|
||||
该工作流从固定发布版本安装 OCM,并从 `openclaw/Kova` 的固定 `kova_ref` 输入安装 Kova,然后运行三个 lane:
|
||||
|
||||
- `mock-provider`:Kova 诊断场景,针对使用确定性伪 OpenAI 兼容认证的本地构建运行时。
|
||||
- `mock-deep-profile`:针对启动、Gateway 网关和智能体轮次热点的 CPU/堆/跟踪性能分析。
|
||||
- `live-gpt54`:一次真实的 OpenAI `openai/gpt-5.4` 智能体轮次;当 `OPENAI_API_KEY` 不可用时跳过。
|
||||
- `mock-provider`:使用确定性的伪 OpenAI 兼容认证,针对本地构建运行时运行 Kova 诊断场景。
|
||||
- `mock-deep-profile`:针对启动、Gateway 网关和智能体轮次热点进行 CPU/堆/trace profiling。
|
||||
- `live-gpt54`:真实的 OpenAI `openai/gpt-5.4` 智能体轮次,在 `OPENAI_API_KEY` 不可用时跳过。
|
||||
|
||||
mock-provider 通道还会在 Kova 通过后运行 OpenClaw 原生源码探测:默认、hook 和 50 插件启动场景下的 Gateway 网关启动时间和内存;重复的 mock-OpenAI `channel-chat-baseline` hello 循环;以及针对已启动 Gateway 网关的 CLI 启动命令。源码探测 Markdown 摘要位于报告包中的 `source/index.md`,原始 JSON 放在旁边。
|
||||
mock-provider lane 还会在 Kova 通过后运行 OpenClaw 原生源码 probe:覆盖默认、hook 和 50 插件启动场景下的 Gateway 网关启动时间和内存;重复的模拟 OpenAI `channel-chat-baseline` hello 循环;以及针对已启动 Gateway 网关的 CLI 启动命令。源码 probe 的 Markdown 摘要位于报告包中的 `source/index.md`,旁边有原始 JSON。
|
||||
|
||||
每个通道都会上传 GitHub 构件。配置 `CLAWGRIT_REPORTS_TOKEN` 后,该工作流还会将 `report.json`、`report.md`、包、`index.md` 和源码探测构件提交到 `openclaw/clawgrit-reports`,路径为 `openclaw-performance/<tested-ref>/<run-id>-<attempt>/<lane>/`。当前被测试 ref 指针会写入为 `openclaw-performance/<tested-ref>/latest-<lane>.json`。
|
||||
每个 lane 都会上传 GitHub artifacts。配置 `CLAWGRIT_REPORTS_TOKEN` 后,工作流还会将 `report.json`、`report.md`、包、`index.md` 和源码 probe artifacts 提交到 `openclaw/clawgrit-reports` 的 `openclaw-performance/<tested-ref>/<run-id>-<attempt>/<lane>/` 下。当前被测试 ref 的指针会写为 `openclaw-performance/<tested-ref>/latest-<lane>.json`。
|
||||
|
||||
## 完整发布验证
|
||||
|
||||
`Full Release Validation` 是用于“发布前运行所有内容”的手动总括工作流。它接受分支、标签或完整提交 SHA,使用该目标触发手动 `CI` 工作流,触发 `Plugin Prerelease` 以提供仅发布使用的插件/包/静态/Docker 证明,并触发 `OpenClaw Release Checks` 以执行安装冒烟、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram 通道。稳定版/默认运行会把完整的 live/E2E 和 Docker 发布路径覆盖保留在 `run_release_soak=true` 之后;`release_profile=full` 会强制启用该 soak 覆盖,因此广泛的 advisory 验证仍然保持广泛。使用 `rerun_group=all` 和 `release_profile=full` 时,它还会针对来自 release checks 的 `release-package-under-test` 构件运行 `NPM Telegram Beta E2E`。发布后,传入 `npm_telegram_package_spec` 可针对已发布的 npm 包重新运行同一个 Telegram 包通道。
|
||||
`Full Release Validation` 是用于“发布前运行所有内容”的手动总控工作流。它接受分支、标签或完整提交 SHA,使用该目标调度手动 `CI` 工作流,调度 `Plugin Prerelease` 以提供仅发布用的插件/包/静态/Docker 证明,并调度 `OpenClaw Release Checks` 以运行安装 smoke、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram lane。稳定版/默认运行会将详尽的 live/E2E 和 Docker 发布路径覆盖保留在 `run_release_soak=true` 后面;`release_profile=full` 会强制开启该 soak 覆盖,以便广泛的 advisory 验证保持广泛覆盖。使用 `rerun_group=all` 和 `release_profile=full` 时,它还会针对 release checks 生成的 `release-package-under-test` artifact 运行 `NPM Telegram Beta E2E`。发布后,传入 `npm_telegram_package_spec` 可针对已发布的 npm 包重新运行相同的 Telegram 包 lane。
|
||||
|
||||
请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解阶段矩阵、确切工作流作业名称、profile 差异、构件和定向重运行句柄。
|
||||
请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解阶段矩阵、确切的工作流作业名称、profile 差异、artifacts,以及聚焦重跑句柄。
|
||||
|
||||
`OpenClaw Release Publish` 是手动的变更型发布工作流。发布标签存在且 OpenClaw npm preflight 成功后,从 `release/YYYY.M.D` 或 `main` 触发它。它会验证 `pnpm plugins:sync:check`,为所有可发布插件包触发 `Plugin NPM Release`,为同一发布 SHA 触发 `Plugin ClawHub Release`,然后才会使用保存的 `preflight_run_id` 触发 `OpenClaw NPM Release`。
|
||||
`OpenClaw Release Publish` 是会产生变更的手动发布工作流。请在发布标签存在且 OpenClaw npm preflight 已成功后,从 `release/YYYY.M.D` 或 `main` 调度它。它会验证 `pnpm plugins:sync:check`,为所有可发布插件包调度 `Plugin NPM Release`,为同一发布 SHA 调度 `Plugin ClawHub Release`,然后才使用保存的 `preflight_run_id` 调度 `OpenClaw NPM Release`。
|
||||
|
||||
```bash
|
||||
gh workflow run openclaw-release-publish.yml \
|
||||
@ -173,35 +173,35 @@ gh workflow run openclaw-release-publish.yml \
|
||||
-f npm_dist_tag=beta
|
||||
```
|
||||
|
||||
若要在快速移动的分支上提供固定提交证明,请使用辅助命令,而不是 `gh workflow run ... --ref main -f ref=<sha>`:
|
||||
对于快速移动分支上的固定提交证明,请使用 helper,而不是 `gh workflow run ... --ref main -f ref=<sha>`:
|
||||
|
||||
```bash
|
||||
pnpm ci:full-release --sha <full-sha>
|
||||
```
|
||||
|
||||
GitHub 工作流触发 ref 必须是分支或标签,不能是原始提交 SHA。该辅助命令会在目标 SHA 处推送一个临时 `release-ci/<sha>-...` 分支,从该固定 ref 触发 `Full Release Validation`,验证每个子工作流的 `headSha` 都与目标匹配,并在运行完成时删除临时分支。如果任何子工作流运行在不同的 SHA 上,总括验证器也会失败。
|
||||
GitHub 工作流调度 ref 必须是分支或标签,不能是原始提交 SHA。该 helper 会在目标 SHA 上推送一个临时 `release-ci/<sha>-...` 分支,从该固定 ref 调度 `Full Release Validation`,验证每个子工作流的 `headSha` 都与目标匹配,并在运行完成后删除临时分支。如果任何子工作流在不同 SHA 上运行,总控验证器也会失败。
|
||||
|
||||
`release_profile` 控制传递给发布检查的实时/提供商覆盖范围。手动发布工作流默认使用 `stable`;只有在你有意需要宽泛的 advisory provider/media 矩阵时才使用 `full`。`run_release_soak` 控制 stable/default 发布检查是否运行详尽的实时/E2E 和 Docker 发布路径 soak;`full` 会强制启用 soak。
|
||||
`release_profile` 控制传入发布检查的实时/提供商覆盖范围。手动发布工作流默认使用 `stable`;只有当你有意需要广泛的 advisory 提供商/媒体矩阵时,才使用 `full`。`run_release_soak` 控制 stable/default 发布检查是否运行详尽的实时/E2E 和 Docker 发布路径 soak;`full` 会强制启用 soak。
|
||||
|
||||
- `minimum` 保留最快的 OpenAI/core 发布关键通道。
|
||||
- `stable` 添加 stable provider/backend 集合。
|
||||
- `full` 运行宽泛的 advisory provider/media 矩阵。
|
||||
- `minimum` 保留最快的 OpenAI/核心发布关键通道。
|
||||
- `stable` 添加 stable 提供商/后端集合。
|
||||
- `full` 运行广泛的 advisory 提供商/媒体矩阵。
|
||||
|
||||
总控流程会记录已调度的子运行 ID,最终的 `Verify full validation` 作业会重新检查当前子运行结论,并为每个子运行追加最慢作业表。如果某个子工作流被重新运行并转为绿色,只需重新运行父级 verifier 作业,以刷新总控结果和耗时摘要。
|
||||
总控工作流会记录已调度的子运行 ID,最终的 `Verify full validation` 作业会重新检查当前子运行结论,并为每个子运行追加最慢作业表。如果某个子工作流被重新运行并转为绿色,只需重新运行父级 verifier 作业,即可刷新总控结果和耗时摘要。
|
||||
|
||||
对于恢复,`Full Release Validation` 和 `OpenClaw Release Checks` 都接受 `rerun_group`。发布候选版本使用 `all`;仅正常 full CI 子项使用 `ci`;仅插件预发布子项使用 `plugin-prerelease`;每个发布子项使用 `release-checks`;也可以在总控流程上使用更窄的分组:`install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 或 `npm-telegram`。这样可以在完成聚焦修复后,将失败发布环境的重跑范围控制住。对于单个失败的 cross-OS 通道,将 `rerun_group=cross-os` 与 `cross_os_suite_filter` 结合使用,例如 `windows/packaged-upgrade`;长时间运行的 cross-OS 命令会输出 heartbeat 行,packaged-upgrade 摘要会包含各阶段耗时。QA release-check 通道是 advisory,因此仅 QA 失败会发出警告,但不会阻塞 release-check verifier。
|
||||
对于恢复,`Full Release Validation` 和 `OpenClaw Release Checks` 都接受 `rerun_group`。发布候选版本使用 `all`,仅普通完整 CI 子项使用 `ci`,仅插件预发布子项使用 `plugin-prerelease`,每个发布子项使用 `release-checks`,或在总控工作流上使用更窄的组:`install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 或 `npm-telegram`。这样可以在做出聚焦修复后,将失败发布盒子的重新运行范围保持有界。对于单个失败的跨 OS 通道,将 `rerun_group=cross-os` 与 `cross_os_suite_filter` 组合使用,例如 `windows/packaged-upgrade`;长时间运行的跨 OS 命令会发出 heartbeat 行,packaged-upgrade 摘要会包含每阶段耗时。QA 发布检查通道是 advisory,因此仅 QA 失败会发出警告,但不会阻止发布检查 verifier。
|
||||
|
||||
`OpenClaw Release Checks` 使用受信任的工作流 ref 将选定 ref 一次解析为 `release-package-under-test` tarball,然后将该 artifact 传递给 cross-OS 检查和包验收,以及在运行 soak 覆盖时传递给 live/E2E 发布路径 Docker 工作流。这样可以让各个发布环境中的包字节保持一致,并避免在多个子作业中重复打包同一个候选版本。
|
||||
`OpenClaw Release Checks` 使用受信任的工作流 ref,将所选 ref 一次解析为 `release-package-under-test` tarball,然后把该 artifact 传给跨 OS 检查和软件包验收,以及在运行 soak 覆盖时传给实时/E2E 发布路径 Docker 工作流。这样可以让发布盒子之间的软件包字节保持一致,并避免在多个子作业中重新打包同一个候选版本。
|
||||
|
||||
针对 `ref=main` 和 `rerun_group=all` 的重复 `Full Release Validation` 运行会取代较旧的总控流程。当父级被取消时,父级 monitor 会取消它已调度的任何子工作流,因此较新的 main 验证不会排在过期的两小时 release-check 运行之后。发布分支/tag 验证和聚焦重跑分组会保持 `cancel-in-progress: false`。
|
||||
`ref=main` 和 `rerun_group=all` 的重复 `Full Release Validation` 运行会取代较旧的总控工作流。当父级被取消时,父级监控器会取消它已经调度的任何子工作流,因此较新的 main 验证不会卡在陈旧的两小时发布检查运行之后。发布分支/标签验证和聚焦重新运行组会保持 `cancel-in-progress: false`。
|
||||
|
||||
## 实时和 E2E 分片
|
||||
|
||||
发布 live/E2E 子项保留宽泛的原生 `pnpm test:live` 覆盖,但会通过 `scripts/test-live-shard.mjs` 以命名分片运行,而不是作为一个串行作业运行:
|
||||
发布实时/E2E 子项保留广泛的原生 `pnpm test:live` 覆盖,但它通过 `scripts/test-live-shard.mjs` 以命名分片运行,而不是作为一个串行作业运行:
|
||||
|
||||
- `native-live-src-agents`
|
||||
- `native-live-src-gateway-core`
|
||||
- provider-filtered `native-live-src-gateway-profiles` 作业
|
||||
- 提供商过滤的 `native-live-src-gateway-profiles` 作业
|
||||
- `native-live-src-gateway-backends`
|
||||
- `native-live-test`
|
||||
- `native-live-extensions-a-k`
|
||||
@ -209,59 +209,59 @@ GitHub 工作流触发 ref 必须是分支或标签,不能是原始提交 SHA
|
||||
- `native-live-extensions-openai`
|
||||
- `native-live-extensions-o-z-other`
|
||||
- `native-live-extensions-xai`
|
||||
- 拆分后的媒体音频/视频分片,以及 provider-filtered 音乐分片
|
||||
- 拆分的媒体音频/视频分片和提供商过滤的音乐分片
|
||||
|
||||
这会保持相同的文件覆盖,同时让缓慢的实时提供商失败更容易重跑和诊断。聚合分片名称 `native-live-extensions-o-z`、`native-live-extensions-media` 和 `native-live-extensions-media-music` 对手动一次性重跑仍然有效。
|
||||
这样既保持相同的文件覆盖,又让缓慢的实时提供商失败更容易重新运行和诊断。聚合的 `native-live-extensions-o-z`、`native-live-extensions-media` 和 `native-live-extensions-media-music` 分片名称仍然可用于手动一次性重新运行。
|
||||
|
||||
原生实时媒体分片在 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` 中运行,该镜像由 `Live Media Runner Image` 工作流构建。该镜像预装了 `ffmpeg` 和 `ffprobe`;媒体作业只会在设置前验证这些二进制文件。将 Docker 支持的实时套件保留在普通 Blacksmith runner 上运行,因为容器作业不适合启动嵌套 Docker 测试。
|
||||
原生实时媒体分片在 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` 中运行,该镜像由 `Live Media Runner Image` 工作流构建。该镜像预安装了 `ffmpeg` 和 `ffprobe`;媒体作业只会在设置前验证这些二进制文件。将 Docker 支持的实时套件保留在普通 Blacksmith runner 上运行——容器作业并不适合启动嵌套 Docker 测试。
|
||||
|
||||
Docker 支持的实时 model/backend 分片会为每个选定提交使用一个单独共享的 `ghcr.io/openclaw/openclaw-live-test:<sha>` 镜像。实时发布工作流会构建并推送该镜像一次,然后 Docker 实时模型、按提供商分片的 Gateway 网关、CLI 后端、ACP bind 和 Codex harness 分片会以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。Gateway 网关 Docker 分片带有显式的脚本级 `timeout` 上限,低于工作流作业超时时间,因此卡住的容器或清理路径会快速失败,而不是耗尽整个 release-check 预算。如果这些分片独立重建完整 source Docker target,则发布运行配置有误,并会把 wall clock 浪费在重复镜像构建上。
|
||||
Docker 支持的实时模型/后端分片会为每个所选 commit 使用单独的共享 `ghcr.io/openclaw/openclaw-live-test:<sha>` 镜像。实时发布工作流会构建并推送该镜像一次,然后 Docker 实时模型、按提供商分片的 Gateway 网关、CLI 后端、ACP bind 和 Codex harness 分片会以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。Gateway 网关 Docker 分片带有明确的脚本级 `timeout` 上限,低于工作流作业超时,因此卡住的容器或清理路径会快速失败,而不是消耗整个发布检查预算。如果这些分片独立重新构建完整源 Docker 目标,则说明发布运行配置错误,并会在重复镜像构建上浪费实际耗时。
|
||||
|
||||
## 包验收
|
||||
## 软件包验收
|
||||
|
||||
当问题是“这个可安装的 OpenClaw 包作为产品是否可用?”时,使用 `Package Acceptance`。它不同于普通 CI:普通 CI 验证 source tree,而包验收会通过用户在安装或更新后使用的同一个 Docker E2E harness 来验证单个 tarball。
|
||||
当问题是“这个可安装的 OpenClaw 软件包作为产品能否工作?”时,使用 `Package Acceptance`。它不同于普通 CI:普通 CI 验证源代码树,而软件包验收会通过用户在安装或更新后实际使用的同一个 Docker E2E harness 验证单个 tarball。
|
||||
|
||||
### 作业
|
||||
|
||||
1. `resolve_package` 检出 `workflow_ref`,解析一个包候选,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者都作为 `package-under-test` artifact 上传,并在 GitHub step summary 中打印来源、workflow ref、package ref、版本、SHA-256 和 profile。
|
||||
2. `docker_acceptance` 使用 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。可复用工作流会下载该 artifact、验证 tarball 清单、在需要时准备 package-digest Docker 镜像,并针对该包运行选定 Docker 通道,而不是打包工作流 checkout。当一个 profile 选择多个目标 `docker_lanes` 时,可复用工作流会准备一次包和共享镜像,然后将这些通道扇出为并行的目标 Docker 作业,并带有唯一 artifact。
|
||||
3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不是 `none` 时运行;如果包验收已解析出一个包,它会安装同一个 `package-under-test` artifact;独立 Telegram 调度仍可安装已发布的 npm spec。
|
||||
4. `summary` 会在包解析、Docker 验收或可选 Telegram 通道失败时使工作流失败。
|
||||
1. `resolve_package` 检出 `workflow_ref`,解析一个软件包候选,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者作为 `package-under-test` artifact 上传,并在 GitHub 步骤摘要中打印来源、工作流 ref、软件包 ref、版本、SHA-256 和 profile。
|
||||
2. `docker_acceptance` 以 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。可复用工作流会下载该 artifact,验证 tarball inventory,在需要时准备 package-digest Docker 镜像,并针对该软件包运行所选 Docker 通道,而不是打包工作流检出内容。当某个 profile 选择多个目标 `docker_lanes` 时,可复用工作流会准备一次软件包和共享镜像,然后将这些通道扇出为并行的目标 Docker 作业,并使用唯一 artifact。
|
||||
3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不是 `none` 时运行,并且在软件包验收解析出 `package-under-test` artifact 时安装同一个 artifact;独立 Telegram 调度仍然可以安装已发布的 npm spec。
|
||||
4. 如果软件包解析、Docker 验收或可选 Telegram 通道失败,`summary` 会使工作流失败。
|
||||
|
||||
### 候选来源
|
||||
|
||||
- `source=npm` 只接受 `openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。将它用于已发布的 prerelease/stable 验收。
|
||||
- `source=ref` 会打包一个受信任的 `package_ref` 分支、tag 或完整提交 SHA。解析器会获取 OpenClaw 分支/tag,验证选定提交可从仓库分支历史或发布 tag 访问,在 detached worktree 中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 打包。
|
||||
- `source=url` 会下载 HTTPS `.tgz`;`package_sha256` 必填。
|
||||
- `source=artifact` 会从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 可选,但对于外部共享的 artifact 应提供。
|
||||
- `source=npm` 只接受 `openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。将它用于已发布预发布版/stable 版验收。
|
||||
- `source=ref` 打包受信任的 `package_ref` 分支、标签或完整 commit SHA。解析器会获取 OpenClaw 分支/标签,验证所选 commit 可从仓库分支历史或发布标签到达,在 detached worktree 中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 打包。
|
||||
- `source=url` 下载 HTTPS `.tgz`;必须提供 `package_sha256`。
|
||||
- `source=artifact` 从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 是可选的,但对于外部共享的 artifact 应提供。
|
||||
|
||||
保持 `workflow_ref` 和 `package_ref` 分离。`workflow_ref` 是运行测试的受信任 workflow/harness 代码。`package_ref` 是在 `source=ref` 时会被打包的源提交。这让当前测试 harness 能够验证较旧的受信任源提交,而无需运行旧工作流逻辑。
|
||||
保持 `workflow_ref` 和 `package_ref` 分离。`workflow_ref` 是运行测试的受信任工作流/harness 代码。`package_ref` 是在 `source=ref` 时被打包的源 commit。这样当前测试 harness 就能验证较旧的受信任源 commit,而无需运行旧工作流逻辑。
|
||||
|
||||
### 套件 profile
|
||||
|
||||
- `smoke` — `npm-onboard-channel-agent`、`gateway-network`、`config-reload`
|
||||
- `package` — `npm-onboard-channel-agent`、`doctor-switch`、`update-channel-switch`、`upgrade-survivor`、`published-upgrade-survivor`、`plugins-offline`、`plugin-update`
|
||||
- `product` — `package` 加上 `mcp-channels`、`cron-mcp-cleanup`、`openai-web-search-minimal`、`openwebui`
|
||||
- `full` — 带 OpenWebUI 的完整 Docker 发布路径 chunks
|
||||
- `full` — 带 OpenWebUI 的完整 Docker 发布路径分块
|
||||
- `custom` — 精确的 `docker_lanes`;当 `suite_profile=custom` 时必需
|
||||
|
||||
`package` profile 使用离线插件覆盖,因此已发布包验证不会受实时 ClawHub 可用性限制。可选 Telegram 通道会在 `NPM Telegram Beta E2E` 中复用 `package-under-test` artifact,并为独立调度保留已发布 npm spec 路径。
|
||||
`package` profile 使用离线插件覆盖,因此已发布软件包验证不会受实时 ClawHub 可用性阻塞。可选 Telegram 通道会在 `NPM Telegram Beta E2E` 中复用 `package-under-test` artifact,并为独立调度保留已发布 npm spec 路径。
|
||||
|
||||
有关专门的更新和插件测试策略,包括本地命令、Docker 通道、包验收输入、发布默认值和失败分诊,请参阅[更新和插件测试](/zh-CN/help/testing-updates-plugins)。
|
||||
有关专用更新和插件测试策略,包括本地命令、Docker 通道、软件包验收输入、发布默认值和失败分流,请参阅[更新和插件测试](/zh-CN/help/testing-updates-plugins)。
|
||||
|
||||
发布检查会使用 `source=artifact`、准备好的发布包 artifact、`suite_profile=custom`、`docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'` 和 `telegram_mode=mock-openai` 调用包验收。这样可以让包迁移、更新、陈旧插件依赖清理、已配置插件安装修复、离线插件、插件更新和 Telegram 证明都基于同一个已解析的包 tarball。设置 Full Release Validation 或 OpenClaw Release Checks 上的 `package_acceptance_package_spec`,可以针对已发布的 npm 包运行同一个矩阵,而不是针对 SHA 构建的 artifact。Cross-OS 发布检查仍覆盖 OS 特定的新手引导、安装程序和平台行为;包/更新产品验证应从包验收开始。`published-upgrade-survivor` Docker 通道会在阻塞发布路径中为每次运行验证一个已发布包基线。在包验收中,解析出的 `package-under-test` tarball 始终是候选版本,而 `published_upgrade_survivor_baseline` 会选择 fallback 已发布基线,默认值为 `openclaw@latest`;失败通道重跑命令会保留该基线。带有 `run_release_soak=true` 或 `release_profile=full` 的 Full Release Validation 会设置 `published_upgrade_survivor_baselines=all-since-2026.4.23` 和 `published_upgrade_survivor_scenarios=reported-issues`,以扩展覆盖从 `2026.4.23` 到 `latest` 的每个 stable npm release,以及面向问题的 fixtures,涵盖 Feishu 配置、保留的 bootstrap/persona 文件、已配置的 OpenClaw 插件安装、波浪号日志路径和陈旧的 legacy 插件依赖根。单独的 `Update Migration` 工作流在问题是详尽的已发布更新清理,而不是普通 Full Release CI 覆盖范围时,会使用 `update-migration` Docker 通道以及 `all-since-2026.4.23` 和 `plugin-deps-cleanup`。本地聚合运行可以通过 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 传递精确包 spec;也可以通过 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 保留单个通道,例如 `openclaw@2026.4.15`;或者设置 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` 以运行场景矩阵。已发布通道会使用内置的 `openclaw config set` 命令 recipe 配置基线,在 `summary.json` 中记录 recipe 步骤,并在 Gateway 网关启动后探测 `/healthz`、`/readyz` 以及 RPC status。Windows packaged 和 installer fresh 通道还会验证已安装包能够从原始绝对 Windows 路径导入 browser-control override。OpenAI cross-OS agent-turn smoke 在已设置时默认使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 `openai/gpt-5.4`,因此安装和 Gateway 网关证明会保留在 GPT-5 测试模型上,同时避免 GPT-4.x 默认值。
|
||||
发布检查会使用 `source=artifact`、准备好的发布软件包 artifact、`suite_profile=custom`、`docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'` 和 `telegram_mode=mock-openai` 调用软件包验收。这样可以在同一个已解析的软件包 tarball 上完成软件包迁移、更新、陈旧插件依赖清理、已配置插件安装修复、离线插件、插件更新和 Telegram 证明。设置 Full Release Validation 或 OpenClaw Release Checks 上的 `package_acceptance_package_spec`,即可针对已发布的 npm 软件包运行同一矩阵,而不是针对按 SHA 构建的 artifact。跨 OS 发布检查仍会覆盖特定 OS 的新手引导、安装器和平台行为;软件包/更新产品验证应从软件包验收开始。`published-upgrade-survivor` Docker 通道会在阻塞发布路径中为每次运行验证一个已发布软件包基线。在软件包验收中,已解析的 `package-under-test` tarball 始终是候选版本,`published_upgrade_survivor_baseline` 选择 fallback 已发布基线,默认值为 `openclaw@latest`;失败通道重新运行命令会保留该基线。带有 `run_release_soak=true` 或 `release_profile=full` 的 Full Release Validation 会设置 `published_upgrade_survivor_baselines='last-stable-4 2026.4.23 2026.5.2 2026.4.15'` 和 `published_upgrade_survivor_scenarios=reported-issues`,以扩展到最新四个 stable npm 版本、固定的插件兼容性边界版本,以及针对 Feishu 配置、保留的 bootstrap/persona 文件、已配置 OpenClaw 插件安装、波浪号日志路径和陈旧旧版插件依赖根的问题形态 fixture。多基线 published-upgrade survivor 选择会按基线分片到单独的目标 Docker runner 作业中。单独的 `Update Migration` 工作流在问题是详尽的已发布更新清理,而不是普通 Full Release CI 覆盖范围时,使用 `update-migration` Docker 通道以及 `all-since-2026.4.23` 和 `plugin-deps-cleanup`。本地聚合运行可以使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 传入精确软件包 spec,使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 保留单个通道,例如 `openclaw@2026.4.15`,或设置 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` 以运行场景矩阵。已发布通道会用内置的 `openclaw config set` 命令 recipe 配置基线,在 `summary.json` 中记录 recipe 步骤,并在 Gateway 网关启动后探测 `/healthz`、`/readyz` 以及 RPC status。Windows packaged 和 installer fresh 通道还会验证已安装软件包能否从原始绝对 Windows 路径导入 browser-control override。OpenAI 跨 OS agent-turn smoke 会在设置时默认使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 `openai/gpt-5.4`,因此安装和 Gateway 网关证明会停留在 GPT-5 测试模型上,同时避免 GPT-4.x 默认值。
|
||||
|
||||
### 旧版兼容窗口
|
||||
|
||||
包验收对已发布包有有界的旧版兼容窗口。到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,可以使用兼容路径:
|
||||
软件包验收为已经发布的软件包提供有界的旧版兼容窗口。直到 `2026.4.25` 的软件包,包括 `2026.4.25-beta.*`,都可以使用兼容路径:
|
||||
|
||||
- `dist/postinstall-inventory.json` 中已知的私有 QA 条目可以指向 tarball 省略的文件;
|
||||
- 当包未暴露 `gateway install --wrapper` flag 时,`doctor-switch` 可以跳过该持久化子用例;
|
||||
- `update-channel-switch` 可以从 tarball 派生的 fake git fixture 中剪除缺失的 `pnpm.patchedDependencies`,并可以记录缺失的持久化 `update.channel`;
|
||||
- 插件 smoke 可以读取 legacy 安装记录位置,或接受缺失的 marketplace 安装记录持久化;
|
||||
- `plugin-update` 可以允许配置元数据迁移,同时仍要求安装记录和 no-reinstall 行为保持不变。
|
||||
- `dist/postinstall-inventory.json` 中已知的私有 QA 条目可能指向 tarball 中省略的文件;
|
||||
- 当软件包未暴露 `gateway install --wrapper` 标志时,`doctor-switch` 可以跳过其持久化子用例;
|
||||
- `update-channel-switch` 可以从 tarball 派生的伪 git fixture 中修剪缺失的 `pnpm.patchedDependencies`,并且可以记录缺失的持久化 `update.channel`;
|
||||
- 插件 smoke 可以读取旧版安装记录位置,或接受缺失的 marketplace 安装记录持久化;
|
||||
- `plugin-update` 可以允许配置元数据迁移,同时仍要求安装记录和无重新安装行为保持不变。
|
||||
|
||||
已发布的 `2026.4.26` 包也可以对已交付的本地构建元数据 stamp 文件发出警告。更晚的包必须满足现代契约;相同条件会失败,而不是警告或跳过。
|
||||
已发布的 `2026.4.26` 包也可能会对已经发布的本地构建元数据戳文件发出警告。后续包必须满足现代契约;相同条件会失败,而不是警告或跳过。
|
||||
|
||||
### 示例
|
||||
|
||||
@ -304,110 +304,110 @@ gh workflow run package-acceptance.yml \
|
||||
-f docker_lanes='install-e2e plugin-update'
|
||||
```
|
||||
|
||||
调试失败的包验收运行时,从 `resolve_package` 摘要开始,确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 产物:`.artifacts/docker-tests/**/summary.json`、`failures.json`、车道日志、阶段计时和重新运行命令。优先重新运行失败的包配置文件或精确的 Docker 车道,而不是重新运行完整发布验证。
|
||||
调试失败的包验收运行时,先查看 `resolve_package` 摘要,确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 工件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、lane 日志、阶段耗时和重新运行命令。优先重新运行失败的包配置文件或精确的 Docker lane,而不是重新运行完整发布验证。
|
||||
|
||||
## 安装冒烟测试
|
||||
|
||||
单独的 `Install Smoke` 工作流通过自己的 `preflight` 作业复用同一个范围脚本。它将冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。
|
||||
独立的 `Install Smoke` 工作流通过自己的 `preflight` 作业复用同一个范围脚本。它将冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。
|
||||
|
||||
- **快速路径**会在拉取请求触及 Docker/包表面、内置插件包/清单变更,或 Docker 冒烟作业会覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面时运行。仅源代码的内置插件变更、仅测试编辑和仅文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像、检查 CLI、运行智能体删除共享工作区 CLI 冒烟测试、运行容器 Gateway 网关网络 e2e、验证内置插件构建参数,并在 240 秒聚合命令超时内运行有界的内置插件 Docker 配置文件(每个场景的 Docker 运行会单独设定上限)。
|
||||
- **完整路径**会保留 QR 包安装和安装器 Docker/更新覆盖,用于夜间定时运行、手动分发、workflow-call 发布检查,以及真正触及安装器/包/Docker 表面的拉取请求。在完整模式下,install-smoke 会准备或复用一个目标 SHA 的 GHCR 根 Dockerfile 冒烟镜像,然后将 QR 包安装、根 Dockerfile/Gateway 网关冒烟测试、安装器/更新冒烟测试,以及快速内置插件 Docker E2E 作为独立作业运行,这样安装器工作就不必等待根镜像冒烟测试完成。
|
||||
- **快速路径**会在 pull request 触及 Docker/包表面、内置插件包/清单变更,或 Docker 冒烟作业会覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面时运行。仅源码的内置插件变更、仅测试编辑和仅文档编辑不会预留 Docker worker。快速路径会构建一次根 Dockerfile 镜像、检查 CLI、运行 agents delete shared-workspace CLI 冒烟测试、运行容器 Gateway 网关网络 e2e、验证内置扩展构建参数,并在 240 秒聚合命令超时内运行有界的内置插件 Docker 配置文件(每个场景的 Docker 运行单独设置上限)。
|
||||
- **完整路径**保留 QR 包安装以及安装器 Docker/更新覆盖,用于夜间定时运行、手动分发、workflow-call 发布检查,以及真正触及安装器/包/Docker 表面的 pull request。在完整模式下,install-smoke 会准备或复用一个目标 SHA GHCR 根 Dockerfile 冒烟镜像,然后将 QR 包安装、根 Dockerfile/Gateway 网关冒烟、安装器/更新冒烟,以及快速内置插件 Docker E2E 作为独立作业运行,这样安装器工作就不会被根镜像冒烟阻塞。
|
||||
|
||||
`main` 推送(包括合并提交)不会强制完整路径;当变更范围逻辑会在推送上请求完整覆盖时,工作流会保留快速 Docker 冒烟测试,并将完整安装冒烟测试留给夜间或发布验证。
|
||||
`main` 推送(包括合并提交)不会强制使用完整路径;当变更范围逻辑会在推送上请求完整覆盖时,工作流会保留快速 Docker 冒烟,并将完整安装冒烟留给夜间或发布验证。
|
||||
|
||||
较慢的 Bun 全局安装 image-provider 冒烟测试由 `run_bun_global_install_smoke` 单独控制。它会在夜间计划和发布检查工作流中运行,手动 `Install Smoke` 分发可以选择启用它,但拉取请求和 `main` 推送不会运行。QR 和安装器 Docker 测试保留各自专注安装的 Dockerfile。
|
||||
较慢的 Bun 全局安装 image-provider 冒烟由 `run_bun_global_install_smoke` 单独控制。它会在夜间计划和发布检查工作流中运行,手动 `Install Smoke` 分发也可以选择加入,但 pull request 和 `main` 推送不会运行它。QR 和安装器 Docker 测试保留各自专注于安装的 Dockerfile。
|
||||
|
||||
## 本地 Docker E2E
|
||||
|
||||
`pnpm test:docker:all` 会预构建一个共享的实时测试镜像,将 OpenClaw 打包一次为 npm tarball,并构建两个共享的 `scripts/e2e/Dockerfile` 镜像:
|
||||
`pnpm test:docker:all` 会预构建一个共享 live-test 镜像,将 OpenClaw 打包一次为 npm tarball,并构建两个共享 `scripts/e2e/Dockerfile` 镜像:
|
||||
|
||||
- 一个用于安装器/更新/插件依赖车道的裸 Node/Git runner;
|
||||
- 一个将同一 tarball 安装到 `/app` 中、用于常规功能车道的功能镜像。
|
||||
- 用于安装器/更新/插件依赖 lane 的裸 Node/Git runner;
|
||||
- 一个功能镜像,会将同一个 tarball 安装到 `/app` 中,用于普通功能 lane。
|
||||
|
||||
Docker 车道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,runner 只执行选中的计划。调度器使用 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每条车道选择镜像,然后用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行车道。
|
||||
Docker lane 定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,runner 只执行选中的计划。调度器通过 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每个 lane 选择镜像,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 lane。
|
||||
|
||||
### 可调参数
|
||||
### 可调项
|
||||
|
||||
| 变量 | 默认值 | 用途 |
|
||||
| -------------------------------------- | ------ | --------------------------------------------------------------------------------------------- |
|
||||
| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 常规车道的主池槽位数。 |
|
||||
| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 对提供商敏感的尾部池槽位数。 |
|
||||
| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 并发实时车道上限,避免提供商限流。 |
|
||||
| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 并发 npm 安装车道上限。 |
|
||||
| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 并发多服务车道上限。 |
|
||||
| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | 车道启动之间的错峰时间,用于避免 Docker daemon 创建风暴;设为 `0` 表示不使用错峰。 |
|
||||
| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 每条车道的兜底超时(120 分钟);选定的实时/尾部车道使用更严格的上限。 |
|
||||
| `OPENCLAW_DOCKER_ALL_DRY_RUN` | 未设置 | `1` 会打印调度器计划而不运行车道。 |
|
||||
| `OPENCLAW_DOCKER_ALL_LANES` | 未设置 | 逗号分隔的精确车道列表;跳过清理冒烟测试,以便智能体复现单个失败车道。 |
|
||||
| 变量 | 默认值 | 用途 |
|
||||
| -------------------------------------- | ------- | --------------------------------------------------------------------------------------------- |
|
||||
| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 普通 lane 的主池槽位数。 |
|
||||
| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 提供商敏感的尾池槽位数。 |
|
||||
| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 并发 live lane 上限,避免提供商限流。 |
|
||||
| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 并发 npm install lane 上限。 |
|
||||
| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 并发多服务 lane 上限。 |
|
||||
| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | lane 启动之间的错峰时间,避免 Docker 守护进程创建风暴;设为 `0` 表示不做错峰。 |
|
||||
| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 每个 lane 的兜底超时(120 分钟);选定的 live/tail lane 使用更严格的上限。 |
|
||||
| `OPENCLAW_DOCKER_ALL_DRY_RUN` | unset | `1` 会打印调度器计划,而不运行 lane。 |
|
||||
| `OPENCLAW_DOCKER_ALL_LANES` | unset | 逗号分隔的精确 lane 列表;跳过清理冒烟,以便智能体可以复现一个失败 lane。 |
|
||||
|
||||
超过其有效上限的车道仍可从空池启动,然后独占运行,直到释放容量。本地聚合会预检 Docker、移除陈旧的 OpenClaw E2E 容器、输出活动车道状态、持久化车道计时以便按最长优先排序,并且默认在第一次失败后停止调度新的池化车道。
|
||||
比有效上限更重的 lane 仍然可以从空池启动,然后独占运行,直到释放容量。本地聚合会预检 Docker、移除陈旧的 OpenClaw E2E 容器、输出活跃 lane 状态、持久化 lane 耗时以便按最长优先排序,并且默认在第一次失败后停止调度新的池化 lane。
|
||||
|
||||
### 可复用实时/E2E 工作流
|
||||
### 可复用 live/E2E 工作流
|
||||
|
||||
可复用实时/E2E 工作流会询问 `scripts/test-docker-all.mjs --plan-json` 需要哪些包、镜像类型、实时镜像、车道和凭证覆盖。随后 `scripts/docker-e2e.mjs` 会将该计划转换为 GitHub 输出和摘要。它要么通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw,要么下载当前运行的包产物,要么从 `package_artifact_run_id` 下载包产物;验证 tarball 清单;当计划需要已安装包的车道时,通过 Blacksmith 的 Docker layer cache 构建并推送带包摘要标签的裸/功能 GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image`/`docker_e2e_functional_image` 输入或现有包摘要镜像,而不是重新构建。Docker 镜像拉取会使用有界的每次尝试 180 秒超时重试,因此卡住的 registry/cache 流会快速重试,而不会消耗 CI 关键路径的大部分时间。
|
||||
可复用 live/E2E 工作流会询问 `scripts/test-docker-all.mjs --plan-json` 需要哪些包、镜像类型、live 镜像、lane 和凭证覆盖。随后 `scripts/docker-e2e.mjs` 会将该计划转换为 GitHub 输出和摘要。它会通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw、下载当前运行的包工件,或从 `package_artifact_run_id` 下载包工件;验证 tarball 清单;在计划需要已安装包的 lane 时,通过 Blacksmith 的 Docker 层缓存构建并推送带包摘要标签的裸/功能 GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image`/`docker_e2e_functional_image` 输入或现有的包摘要镜像,而不是重新构建。Docker 镜像拉取会使用有界的每次 180 秒超时进行重试,因此卡住的 registry/cache 流会快速重试,而不是消耗 CI 关键路径的大部分时间。
|
||||
|
||||
### 发布路径分块
|
||||
|
||||
发布 Docker 覆盖会使用较小的分块作业并设置 `OPENCLAW_SKIP_DOCKER_BUILD=1`,这样每个分块只拉取自己需要的镜像类型,并通过同一个加权调度器执行多条车道:
|
||||
发布 Docker 覆盖使用较小的分块作业并设置 `OPENCLAW_SKIP_DOCKER_BUILD=1`,这样每个分块只拉取自己需要的镜像类型,并通过同一个加权调度器执行多个 lane:
|
||||
|
||||
- `OPENCLAW_DOCKER_ALL_PROFILE=release-path`
|
||||
- `OPENCLAW_DOCKER_ALL_CHUNK=core | package-update-openai | package-update-anthropic | package-update-core | plugins-runtime-plugins | plugins-runtime-services | plugins-runtime-install-a..h`
|
||||
|
||||
当前发布 Docker 分块包括 `core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`,以及从 `plugins-runtime-install-a` 到 `plugins-runtime-install-h`。`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍是聚合插件/运行时别名。`install-e2e` 车道别名仍是两个提供商安装器车道的聚合手动重新运行别名。
|
||||
当前发布 Docker 分块为 `core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`,以及从 `plugins-runtime-install-a` 到 `plugins-runtime-install-h`。`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍然是聚合的插件/运行时别名。`install-e2e` lane 别名仍然是两个提供商安装器 lane 的聚合手动重跑别名。
|
||||
|
||||
当完整发布路径覆盖请求 OpenWebUI 时,它会并入 `plugins-runtime-services`;只有 OpenWebUI 专用分发才保留独立的 `openwebui` 分块。内置渠道更新车道会针对瞬时 npm 网络故障重试一次。
|
||||
当完整发布路径覆盖请求 OpenWebUI 时,它会被并入 `plugins-runtime-services`,并且只为仅 OpenWebUI 分发保留独立的 `openwebui` 分块。内置渠道更新 lane 会针对临时 npm 网络故障重试一次。
|
||||
|
||||
每个分块都会上传 `.artifacts/docker-tests/`,其中包含车道日志、计时、`summary.json`、`failures.json`、阶段计时、调度器计划 JSON、慢车道表和每条车道的重新运行命令。工作流的 `docker_lanes` 输入会针对已准备的镜像运行选中的车道,而不是运行分块作业;这会将失败车道调试限制在一个目标明确的 Docker 作业内,并为该运行准备、下载或复用包产物;如果选中的车道是实时 Docker 车道,目标作业会为这次重新运行在本地构建实时测试镜像。生成的每车道 GitHub 重新运行命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和已准备镜像输入,因此失败车道可以复用失败运行中的精确包和镜像。
|
||||
每个分块都会上传 `.artifacts/docker-tests/`,其中包含 lane 日志、耗时、`summary.json`、`failures.json`、阶段耗时、调度器计划 JSON、慢 lane 表和每 lane 重新运行命令。工作流 `docker_lanes` 输入会针对准备好的镜像运行选定 lane,而不是运行分块作业,这会将失败 lane 调试限制在一个目标 Docker 作业内,并为该运行准备、下载或复用包工件;如果选定 lane 是 live Docker lane,目标作业会为该次重跑在本地构建 live-test 镜像。生成的每 lane GitHub 重新运行命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和准备好的镜像输入,因此失败的 lane 可以复用失败运行中的精确包和镜像。
|
||||
|
||||
```bash
|
||||
pnpm test:docker:rerun <run-id> # download Docker artifacts and print combined/per-lane targeted rerun commands
|
||||
pnpm test:docker:timings <summary> # slow-lane and phase critical-path summaries
|
||||
```
|
||||
|
||||
计划的实时/E2E 工作流每天运行完整发布路径 Docker 套件。
|
||||
计划的 live/E2E 工作流每天运行完整发布路径 Docker 套件。
|
||||
|
||||
## 插件预发布
|
||||
|
||||
`Plugin Prerelease` 是成本更高的产品/包覆盖,因此它是一个单独的工作流,由 `Full Release Validation` 或明确的操作员分发触发。常规拉取请求、`main` 推送和独立的手动 CI 分发都不会启用该套件。它会在八个插件 worker 之间均衡内置插件测试;这些插件分片作业每次最多运行两个插件配置组,每组使用一个 Vitest worker 和更大的 Node 堆,因此导入较重的插件批次不会创建额外 CI 作业。仅发布的 Docker 预发布路径会以小组批量运行目标 Docker 车道,避免为一到三分钟的作业占用数十个 runner。
|
||||
`Plugin Prerelease` 是成本更高的产品/包覆盖,因此它是一个由 `Full Release Validation` 或显式操作员分发的独立工作流。普通 pull request、`main` 推送和独立手动 CI 分发会保持该套件关闭。它会在八个扩展 worker 之间平衡内置插件测试;这些扩展分片作业一次最多运行两个插件配置组,每组使用一个 Vitest worker 和更大的 Node 堆,这样导入密集的插件批次就不会创建额外 CI 作业。仅发布的 Docker 预发布路径会以小组批处理目标 Docker lane,避免为一到三分钟的作业预留数十个 runner。
|
||||
|
||||
## QA Lab
|
||||
|
||||
QA Lab 拥有独立于主智能范围工作流之外的专用 CI 车道。Agentic parity 嵌套在广泛的 QA 和发布 harness 下,而不是独立的 PR 工作流。当 parity 应随广泛验证运行一起执行时,使用带有 `rerun_group=qa-parity` 的 `Full Release Validation`。
|
||||
QA Lab 在主智能范围工作流之外有专用 CI lane。Agentic parity 嵌套在宽泛 QA 和发布 harness 之下,而不是独立的 PR 工作流。当 parity 应随宽泛验证运行一起执行时,使用 `Full Release Validation` 并设置 `rerun_group=qa-parity`。
|
||||
|
||||
- `QA-Lab - All Lanes` 工作流每晚在 `main` 上运行,也可手动分发;它会将 mock parity 车道、实时 Matrix 车道,以及实时 Telegram 和 Discord 车道展开为并行作业。实时作业使用 `qa-live-shared` 环境,Telegram/Discord 使用 Convex 租约。
|
||||
- `QA-Lab - All Lanes` 工作流每晚在 `main` 上运行,也可手动分发;它会将 mock parity lane、live Matrix lane,以及 live Telegram 和 Discord lane 扇出为并行作业。live 作业使用 `qa-live-shared` 环境,Telegram/Discord 使用 Convex 租约。
|
||||
|
||||
发布检查会使用确定性 mock 提供商和 mock 限定模型(`mock-openai/gpt-5.5` 和 `mock-openai/gpt-5.5-alt`)运行 Matrix 和 Telegram 实时传输车道,因此渠道契约与实时模型延迟和常规提供商插件启动相隔离。实时传输 Gateway 网关会禁用记忆搜索,因为 QA parity 会单独覆盖记忆行为;提供商连接性由单独的实时模型、原生提供商和 Docker 提供商套件覆盖。
|
||||
发布检查会使用确定性的 mock 提供商和 mock 限定模型(`mock-openai/gpt-5.5` 和 `mock-openai/gpt-5.5-alt`)运行 Matrix 和 Telegram live 传输 lane,这样渠道契约就与 live 模型延迟和普通提供商插件启动隔离。live 传输 Gateway 网关会禁用记忆搜索,因为 QA parity 单独覆盖记忆行为;提供商连通性由独立的 live 模型、原生提供商和 Docker 提供商套件覆盖。
|
||||
|
||||
Matrix 会为计划和发布门禁使用 `--profile fast`,仅在检出的 CLI 支持时添加 `--fail-fast`。CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 分发始终会将完整 Matrix 覆盖分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。
|
||||
Matrix 在计划和发布 gate 中使用 `--profile fast`,仅当检出的 CLI 支持时才添加 `--fail-fast`。CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 分发始终会将完整 Matrix 覆盖分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。
|
||||
|
||||
`OpenClaw Release Checks` 也会在发布批准前运行发布关键的 QA Lab 车道;其 QA parity 门禁会将候选包和基线包作为并行车道作业运行,然后把两个产物都下载到一个小型报告作业中,用于最终 parity 比较。
|
||||
`OpenClaw Release Checks` 也会在发布批准前运行发布关键的 QA Lab lane;其 QA parity gate 会将候选包和基线包作为并行 lane 作业运行,然后把两个工件下载到一个小型报告作业中,用于最终 parity 对比。
|
||||
|
||||
对于常规 PR,应遵循限定范围的 CI/检查证据,而不是将 parity 视为必需状态。
|
||||
对于普通 PR,遵循有范围限定的 CI/检查证据,而不是将 parity 视为必需状态。
|
||||
|
||||
## CodeQL
|
||||
|
||||
`CodeQL` 工作流有意作为范围狭窄的第一遍安全扫描器,而不是完整仓库扫描。每日、手动和非草稿拉取请求守卫运行会扫描 Actions 工作流代码,以及最高风险的 JavaScript/TypeScript 表面,并使用高置信度安全查询筛选高/严重 `security-severity`。
|
||||
`CodeQL` 工作流有意作为一个范围较窄的第一轮安全扫描器,而不是完整的仓库扫描。每日、手动以及非草稿拉取请求保护运行会扫描 Actions 工作流代码,以及风险最高的 JavaScript/TypeScript 范围,并使用高置信度安全查询,筛选出高/严重 `security-severity`。
|
||||
|
||||
拉取请求守卫保持轻量:它只会在 `.github/actions`、`.github/codeql`、`.github/workflows`、`packages` 或 `src` 下发生变更时启动,并运行与定时工作流相同的高置信度安全矩阵。Android 和 macOS CodeQL 不包含在 PR 默认项中。
|
||||
拉取请求保护保持轻量:它只会针对 `.github/actions`、`.github/codeql`、`.github/workflows`、`packages` 或 `src` 下的变更启动,并运行与定时工作流相同的高置信度安全矩阵。Android 和 macOS CodeQL 不包含在 PR 默认项中。
|
||||
|
||||
### 安全类别
|
||||
|
||||
| 类别 | 表面 |
|
||||
| 类别 | 范围 |
|
||||
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/codeql-security-high/core-auth-secrets` | 认证、密钥、沙箱、cron 和 Gateway 网关基线 |
|
||||
| `/codeql-security-high/channel-runtime-boundary` | 核心渠道实现契约,加上渠道插件运行时、Gateway 网关、插件 SDK、密钥、审计触点 |
|
||||
| `/codeql-security-high/network-ssrf-boundary` | 核心 SSRF、IP 解析、网络守卫、Web 抓取和插件 SDK SSRF 策略表面 |
|
||||
| `/codeql-security-high/mcp-process-tool-boundary` | MCP 服务器、进程执行辅助工具、出站投递,以及智能体工具执行门控 |
|
||||
| `/codeql-security-high/plugin-trust-boundary` | 插件安装、加载器、清单、注册表、包管理器安装、源加载,以及插件 SDK 包契约信任表面 |
|
||||
| `/codeql-security-high/channel-runtime-boundary` | 核心渠道实现契约,以及渠道插件运行时、Gateway 网关、插件 SDK、密钥、审计接触点 |
|
||||
| `/codeql-security-high/network-ssrf-boundary` | 核心 SSRF、IP 解析、网络防护、web-fetch 和插件 SDK SSRF 策略范围 |
|
||||
| `/codeql-security-high/mcp-process-tool-boundary` | MCP 服务器、进程执行辅助工具、出站投递,以及智能体工具执行闸门 |
|
||||
| `/codeql-security-high/plugin-trust-boundary` | 插件安装、加载器、清单、注册表、包管理器安装、源码加载,以及插件 SDK 包契约信任范围 |
|
||||
|
||||
### 平台特定安全分片
|
||||
|
||||
- `CodeQL Android Critical Security` — 定时 Android 安全分片。在工作流健全性接受的最小 Blacksmith Linux runner 上手动构建 Android 应用以供 CodeQL 使用。上传到 `/codeql-critical-security/android` 下。
|
||||
- `CodeQL macOS Critical Security` — 每周/手动 macOS 安全分片。在 Blacksmith macOS 上手动构建 macOS 应用以供 CodeQL 使用,从上传的 SARIF 中过滤依赖构建结果,并上传到 `/codeql-critical-security/macos` 下。它被排除在每日默认项之外,因为即使结果干净,macOS 构建也会主导运行时长。
|
||||
- `CodeQL Android Critical Security` — 定时 Android 安全分片。在工作流完整性检查接受的最小 Blacksmith Linux runner 上手动构建 Android 应用以供 CodeQL 使用。上传到 `/codeql-critical-security/android` 下。
|
||||
- `CodeQL macOS Critical Security` — 每周/手动 macOS 安全分片。在 Blacksmith macOS 上手动构建 macOS 应用以供 CodeQL 使用,从上传的 SARIF 中过滤掉依赖构建结果,并上传到 `/codeql-critical-security/macos` 下。它保留在每日默认项之外,因为即使结果干净,macOS 构建也会主导运行时间。
|
||||
|
||||
### 关键质量类别
|
||||
### Critical Quality 类别
|
||||
|
||||
`CodeQL Critical Quality` 是对应的非安全分片。它只在较小的 Blacksmith Linux runner 上,对范围狭窄的高价值表面运行错误严重级别、非安全 JavaScript/TypeScript 质量查询。它的拉取请求守卫有意小于定时配置:非草稿 PR 只会针对智能体命令/模型/工具执行和回复分发代码、配置架构/迁移/IO 代码、认证/密钥/沙箱/安全代码、核心渠道和内置渠道插件运行时、Gateway 网关协议/服务器方法、记忆运行时/SDK 粘合代码、MCP/进程/出站投递、提供商运行时/模型目录、会话诊断/投递队列、插件加载器、插件 SDK/包契约,或插件 SDK 回复运行时变更,运行匹配的 `agent-runtime-boundary`、`config-boundary`、`core-auth-secrets`、`channel-runtime-boundary`、`gateway-runtime-boundary`、`memory-runtime-boundary`、`mcp-process-runtime-boundary`、`provider-runtime-boundary`、`session-diagnostics-boundary`、`plugin-boundary`、`plugin-sdk-package-contract` 和 `plugin-sdk-reply-runtime` 分片。CodeQL 配置和质量工作流变更会运行全部十二个 PR 质量分片。
|
||||
`CodeQL Critical Quality` 是对应的非安全分片。它在较小的 Blacksmith Linux runner 上,仅对范围较窄的高价值表面运行错误严重级别、非安全 JavaScript/TypeScript 质量查询。它的拉取请求保护有意小于定时配置:非草稿 PR 只会针对智能体命令/模型/工具执行和回复调度代码、配置 schema/迁移/IO 代码、认证/密钥/沙箱/安全代码、核心渠道和内置渠道插件运行时、Gateway 网关协议/服务器方法、memory 运行时/SDK 胶水层、MCP/进程/出站投递、提供商运行时/模型目录、会话诊断/投递队列、插件加载器、插件 SDK/包契约,或插件 SDK 回复运行时变更,运行匹配的 `agent-runtime-boundary`、`config-boundary`、`core-auth-secrets`、`channel-runtime-boundary`、`gateway-runtime-boundary`、`memory-runtime-boundary`、`mcp-process-runtime-boundary`、`provider-runtime-boundary`、`session-diagnostics-boundary`、`plugin-boundary`、`plugin-sdk-package-contract` 和 `plugin-sdk-reply-runtime` 分片。CodeQL 配置和质量工作流变更会运行全部十二个 PR 质量分片。
|
||||
|
||||
手动调度接受:
|
||||
|
||||
@ -415,40 +415,40 @@ Matrix 会为计划和发布门禁使用 `--profile fast`,仅在检出的 CLI
|
||||
profile=all|agent-runtime-boundary|config-boundary|core-auth-secrets|channel-runtime-boundary|gateway-runtime-boundary|memory-runtime-boundary|mcp-process-runtime-boundary|plugin-boundary|plugin-sdk-package-contract|plugin-sdk-reply-runtime|provider-runtime-boundary|session-diagnostics-boundary
|
||||
```
|
||||
|
||||
狭窄配置是用于单独运行一个质量分片的教学/迭代钩子。
|
||||
窄配置是用于单独运行一个质量分片的教学/迭代钩子。
|
||||
|
||||
| 类别 | 表面 |
|
||||
| 类别 | 范围 |
|
||||
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/codeql-critical-quality/core-auth-secrets` | 认证、密钥、沙箱、cron 和 Gateway 网关安全边界代码 |
|
||||
| `/codeql-critical-quality/config-boundary` | 配置架构、迁移、规范化和 IO 契约 |
|
||||
| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 网关协议架构和服务器方法契约 |
|
||||
| `/codeql-critical-quality/channel-runtime-boundary` | 核心渠道和内置渠道插件实现契约 |
|
||||
| `/codeql-critical-quality/agent-runtime-boundary` | 命令执行、模型/提供商分发、自动回复分发和队列,以及 ACP 控制平面运行时契约 |
|
||||
| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 服务器和工具桥、进程监督辅助工具,以及出站投递契约 |
|
||||
| `/codeql-critical-quality/memory-runtime-boundary` | 记忆主机 SDK、记忆运行时 facade、记忆插件 SDK 别名、记忆运行时激活粘合代码,以及记忆 Doctor 命令 |
|
||||
| `/codeql-critical-quality/session-diagnostics-boundary` | 回复队列内部、会话投递队列、出站会话绑定/投递辅助工具、诊断事件/日志包表面,以及会话 Doctor CLI 契约 |
|
||||
| `/codeql-critical-quality/plugin-sdk-reply-runtime` | 插件 SDK 入站回复分发、回复载荷/分块/运行时辅助工具、渠道回复选项、投递队列,以及会话/线程绑定辅助工具 |
|
||||
| `/codeql-critical-quality/provider-runtime-boundary` | 模型目录规范化、提供商认证和设备发现、提供商运行时注册、提供商默认值/目录,以及 Web/搜索/抓取/嵌入注册表 |
|
||||
| `/codeql-critical-quality/ui-control-plane` | 控制 UI 启动、本地持久化、Gateway 网关控制流,以及任务控制平面运行时契约 |
|
||||
| `/codeql-critical-quality/web-media-runtime-boundary` | 核心 Web 抓取/搜索、媒体 IO、媒体理解、图像生成,以及媒体生成运行时契约 |
|
||||
| `/codeql-critical-quality/plugin-boundary` | 加载器、注册表、公共表面,以及插件 SDK 入口点契约 |
|
||||
| `/codeql-critical-quality/plugin-sdk-package-contract` | 已发布包侧插件 SDK 源代码和插件包契约辅助工具 |
|
||||
| `/codeql-critical-quality/core-auth-secrets` | 认证、密钥、沙箱、cron 和 Gateway 网关安全边界代码 |
|
||||
| `/codeql-critical-quality/config-boundary` | 配置 schema、迁移、规范化和 IO 契约 |
|
||||
| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 网关协议 schema 和服务器方法契约 |
|
||||
| `/codeql-critical-quality/channel-runtime-boundary` | 核心渠道和内置渠道插件实现契约 |
|
||||
| `/codeql-critical-quality/agent-runtime-boundary` | 命令执行、模型/提供商调度、自动回复调度和队列,以及 ACP 控制平面运行时契约 |
|
||||
| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 服务器和工具桥接、进程监督辅助工具,以及出站投递契约 |
|
||||
| `/codeql-critical-quality/memory-runtime-boundary` | Memory host SDK、memory 运行时 facade、memory 插件 SDK 别名、memory 运行时激活胶水层,以及 memory doctor 命令 |
|
||||
| `/codeql-critical-quality/session-diagnostics-boundary` | 回复队列内部机制、会话投递队列、出站会话绑定/投递辅助工具、诊断事件/日志包范围,以及会话 doctor CLI 契约 |
|
||||
| `/codeql-critical-quality/plugin-sdk-reply-runtime` | 插件 SDK 入站回复调度、回复载荷/分块/运行时辅助工具、渠道回复选项、投递队列,以及会话/thread 绑定辅助工具 |
|
||||
| `/codeql-critical-quality/provider-runtime-boundary` | 模型目录规范化、提供商认证和设备发现、提供商运行时注册、提供商默认值/目录,以及 web/search/fetch/embedding 注册表 |
|
||||
| `/codeql-critical-quality/ui-control-plane` | Control UI 引导启动、本地持久化、Gateway 网关控制流,以及任务控制平面运行时契约 |
|
||||
| `/codeql-critical-quality/web-media-runtime-boundary` | 核心 web fetch/search、媒体 IO、媒体理解、图像生成,以及媒体生成运行时契约 |
|
||||
| `/codeql-critical-quality/plugin-boundary` | 加载器、注册表、公共表面,以及插件 SDK 入口点契约 |
|
||||
| `/codeql-critical-quality/plugin-sdk-package-contract` | 已发布包侧插件 SDK 源码和插件包契约辅助工具 |
|
||||
|
||||
质量与安全保持分离,这样质量发现就可以在不遮蔽安全信号的情况下进行定时、度量、禁用或扩展。Swift、Python 和内置插件 CodeQL 扩展应仅在狭窄配置拥有稳定运行时和信号之后,作为有范围或分片的后续工作加回。
|
||||
质量与安全保持分离,因此质量发现可以被定时、度量、禁用或扩展,而不会遮蔽安全信号。Swift、Python 和内置插件 CodeQL 扩展只应在窄配置具备稳定运行时间和信号之后,作为有范围限定或分片的后续工作加回。
|
||||
|
||||
## 维护工作流
|
||||
|
||||
### Docs Agent
|
||||
|
||||
`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近落地的变更保持一致。它没有纯定时计划:`main` 上成功的非机器人 push CI 运行可以触发它,手动调度也可以直接运行它。当 `main` 已继续前进,或过去一小时内已经创建了另一个未跳过的 Docs Agent 运行时,workflow-run 调用会跳过。运行时,它会审核从上一个未跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此一次每小时运行可以覆盖自上次文档处理以来积累的所有 main 变更。
|
||||
`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近落地的变更保持一致。它没有纯定时计划:`main` 上一次成功的非机器人 push CI 运行可以触发它,手动调度也可以直接运行它。当 `main` 已经前移,或者过去一小时内创建了另一个未跳过的 Docs Agent 运行时,workflow-run 调用会跳过。运行时,它会审查从上一个未跳过 Docs Agent 来源 SHA 到当前 `main` 的提交范围,因此每小时一次的运行可以覆盖自上次文档处理以来累计的所有 main 变更。
|
||||
|
||||
### Test Performance Agent
|
||||
|
||||
`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时计划:`main` 上成功的非机器人 push CI 运行可以触发它,但如果同一个 UTC 日已经有另一个 workflow-run 调用运行过或正在运行,它会跳过。手动调度会绕过该每日活动门控。该通道会构建完整套件分组 Vitest 性能报告,让 Codex 只做保持覆盖率的小型测试性能修复,而不是大范围重构,然后重新运行完整套件报告,并拒绝会降低通过基线测试数量的变更。如果基线存在失败测试,Codex 只能修复明显失败,且 agent 后的完整套件报告必须通过后才能提交任何内容。当机器人 push 落地前 `main` 前进时,该通道会 rebase 已验证补丁,重新运行 `pnpm check:changed`,并重试 push;有冲突的陈旧补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以保持与 docs agent 相同的 drop-sudo 安全姿态。
|
||||
`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时计划:`main` 上一次成功的非机器人 push CI 运行可以触发它,但如果当天 UTC 已经有另一个 workflow-run 调用运行过或正在运行,它会跳过。手动调度会绕过该每日活动闸门。该通道会构建完整测试套件分组 Vitest 性能报告,让 Codex 只做小规模、保持覆盖率的测试性能修复,而不是广泛重构,然后重新运行完整测试套件报告,并拒绝会降低通过基线测试数量的变更。如果基线存在失败测试,Codex 只能修复明显失败,并且 agent 后的完整测试套件报告必须通过后才能提交任何内容。当 `main` 在机器人 push 落地前前移时,该通道会 rebase 已验证的补丁,重新运行 `pnpm check:changed`,并重试 push;有冲突的过期补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以保持与 docs agent 相同的 drop-sudo 安全姿态。
|
||||
|
||||
### 合并后的重复 PR
|
||||
|
||||
`Duplicate PRs After Merge` 工作流是一个手动维护者工作流,用于落地后的重复项清理。它默认 dry-run,且只有在 `apply=true` 时才会关闭显式列出的 PR。在修改 GitHub 前,它会验证已落地 PR 已合并,并且每个重复项都有共享的引用 issue 或重叠的变更 hunk。
|
||||
`Duplicate PRs After Merge` 工作流是一个手动维护者工作流,用于落地后的重复项清理。它默认 dry-run,并且只有在 `apply=true` 时才关闭明确列出的 PR。在修改 GitHub 之前,它会验证已落地的 PR 已合并,并且每个重复 PR 要么共享被引用的问题,要么存在重叠的变更 hunk。
|
||||
|
||||
```bash
|
||||
gh workflow run duplicate-after-merge.yml \
|
||||
@ -457,29 +457,29 @@ gh workflow run duplicate-after-merge.yml \
|
||||
-f apply=true
|
||||
```
|
||||
|
||||
## 本地检查门控和变更路由
|
||||
## 本地检查闸门和变更路由
|
||||
|
||||
本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。该本地检查门控在架构边界方面比宽泛的 CI 平台范围更严格:
|
||||
本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。这个本地检查闸门在架构边界上比广泛的 CI 平台范围更严格:
|
||||
|
||||
- 核心生产变更会运行核心生产和核心测试类型检查,加上核心 lint/guards;
|
||||
- 仅核心测试变更只运行核心测试类型检查,加上核心 lint;
|
||||
- 扩展生产变更会运行扩展生产和扩展测试类型检查,加上扩展 lint;
|
||||
- 仅扩展测试变更会运行扩展测试类型检查,加上扩展 lint;
|
||||
- 公共插件 SDK 或插件契约变更会扩展到扩展类型检查,因为扩展依赖这些核心契约(Vitest 扩展扫描仍然是显式测试工作);
|
||||
- 仅发布元数据版本 bump 会运行定向版本/配置/根依赖检查;
|
||||
- 未知 root/配置变更会故障安全地进入所有检查通道。
|
||||
- 核心生产变更会运行核心生产和核心测试类型检查,以及核心 lint/guard;
|
||||
- 仅核心测试变更只会运行核心测试类型检查和核心 lint;
|
||||
- 插件生产变更会运行插件生产和插件测试类型检查,以及插件 lint;
|
||||
- 仅插件测试变更会运行插件测试类型检查和插件 lint;
|
||||
- 公共插件 SDK 或插件契约变更会扩展到插件类型检查,因为插件依赖这些核心契约(Vitest 插件扫描仍然是显式测试工作);
|
||||
- 仅发布元数据的版本 bump 会运行有针对性的版本/配置/根依赖检查;
|
||||
- 未知的 root/配置变更会故障安全地进入全部检查通道。
|
||||
|
||||
本地 changed-test 路由位于 `scripts/test-projects.test-support.mjs`,并且有意比 `check:changed` 更便宜:直接测试编辑会运行自身,源代码编辑优先使用显式映射,然后是同级测试和导入图依赖项。共享群组房间投递配置是显式映射之一:对群组可见回复配置、源回复投递模式或消息工具系统提示的变更,会经过核心回复测试以及 Discord 和 Slack 投递回归测试,因此共享默认值变更会在首次 PR push 前失败。只有当变更范围足够覆盖整个 harness,以至于廉价映射集合不是可信代理时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。
|
||||
本地 changed-test 路由位于 `scripts/test-projects.test-support.mjs`,并且有意比 `check:changed` 更便宜:直接测试编辑会运行自身,源码编辑优先使用显式映射,然后运行同级测试和导入图依赖项。共享 group-room 投递配置是显式映射之一:对 group visible-reply 配置、源码回复投递模式或 message-tool 系统提示词的变更,会路由到核心回复测试,以及 Discord 和 Slack 投递回归测试,因此共享默认值变更会在第一次 PR push 之前失败。只有当变更影响范围足够覆盖整个 harness,以至于廉价映射集合不是可信代理时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。
|
||||
|
||||
## Testbox 验证
|
||||
|
||||
从仓库根目录运行 Testbox,并优先使用全新预热的 box 进行广泛验证。在对复用过、已过期,或刚报告了异常大规模同步的 box 执行慢速 gate 之前,先在 box 内运行 `pnpm testbox:sanity`。
|
||||
从仓库根目录运行 Testbox,并优先为广泛验证使用全新预热的 box。在一个被复用、已过期,或刚刚报告了意外大规模同步的 box 上运行耗时检查前,先在 box 内运行 `pnpm testbox:sanity`。
|
||||
|
||||
当所需的根文件(例如 `pnpm-lock.yaml`)消失,或 `git status --short` 显示至少 200 个已跟踪删除项时,sanity check 会快速失败。这通常意味着远程同步状态不是 PR 的可信副本;停止那个 box,并改为预热一个新的 box,而不是调试产品测试失败。对于有意进行大规模删除的 PR,请为该次 sanity run 设置 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`。
|
||||
当 `pnpm-lock.yaml` 等必需的根文件消失,或 `git status --short` 显示至少 200 个已跟踪删除时,完整性检查会快速失败。这通常意味着远程同步状态不是 PR 的可信副本;停止该 box 并预热一个新的,而不是调试产品测试失败。对于有意进行大规模删除的 PR,请为该完整性检查设置 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`。
|
||||
|
||||
`pnpm testbox:run` 还会终止本地 Blacksmith CLI 调用:如果它在同步阶段停留超过五分钟且没有同步后的输出。设置 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` 可禁用该保护,或为异常大的本地 diff 使用更大的毫秒值。
|
||||
如果本地 Blacksmith CLI 调用在同步阶段停留超过五分钟且没有同步后输出,`pnpm testbox:run` 也会终止它。设置 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` 可禁用该保护,或为异常大的本地差异使用更大的毫秒值。
|
||||
|
||||
Crabbox 是仓库自有的远程 box 包装器,用于维护者 Linux 验证。当某个检查对本地编辑循环来说过于广泛、CI 对等性很重要,或验证需要 secrets、Docker、package lanes、可复用 box,或远程日志时,请使用它。常规 OpenClaw 后端是 `blacksmith-testbox`;自有 AWS/Hetzner 容量是在 Blacksmith 中断、配额问题,或明确进行自有容量测试时的 fallback。
|
||||
Crabbox 是仓库自有的远程 box 包装器,用于维护者 Linux 验证。当某项检查对本地编辑循环来说过于宽泛、需要 CI 一致性,或验证需要密钥、Docker、包验证通道、可复用 box 或远程日志时使用它。正常的 OpenClaw 后端是 `blacksmith-testbox`;自有 AWS/Hetzner 容量是 Blacksmith 中断、配额问题或明确进行自有容量测试时的后备方案。
|
||||
|
||||
首次运行前,从仓库根目录检查包装器:
|
||||
|
||||
@ -487,9 +487,9 @@ Crabbox 是仓库自有的远程 box 包装器,用于维护者 Linux 验证。
|
||||
pnpm crabbox:run -- --help | sed -n '1,120p'
|
||||
```
|
||||
|
||||
如果 Crabbox 二进制文件过旧且未声明 `blacksmith-testbox`,仓库包装器会拒绝运行。即使 `.crabbox.yaml` 有自有云默认值,也要显式传入 provider。
|
||||
如果 Crabbox 二进制文件过旧且未声明 `blacksmith-testbox`,仓库包装器会拒绝使用。即使 `.crabbox.yaml` 有自有云默认值,也要显式传入提供商。
|
||||
|
||||
Changed gate:
|
||||
变更检查门:
|
||||
|
||||
```bash
|
||||
pnpm crabbox:run -- --provider blacksmith-testbox \
|
||||
@ -534,21 +534,21 @@ pnpm crabbox:run -- --provider blacksmith-testbox \
|
||||
"env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test"
|
||||
```
|
||||
|
||||
阅读最终的 JSON 摘要。有用的字段是 `provider`、`leaseId`、`syncDelegated`、`exitCode`、`commandMs` 和 `totalMs`。一次性的 Blacksmith 后端 Crabbox 运行应自动停止 Testbox;如果运行被中断或清理状态不明确,请检查 live boxes,并只停止你创建的 box:
|
||||
阅读最终 JSON 摘要。有用字段是 `provider`、`leaseId`、`syncDelegated`、`exitCode`、`commandMs` 和 `totalMs`。一次性的 Blacksmith 后端 Crabbox 运行应自动停止 Testbox;如果运行被中断或清理状态不明确,请检查实时 box,并只停止你创建的 box:
|
||||
|
||||
```bash
|
||||
blacksmith testbox list
|
||||
blacksmith testbox stop --id <tbx_id>
|
||||
```
|
||||
|
||||
只有在你有意需要在同一个已 hydrated 的 box 上执行多条命令时,才使用复用:
|
||||
仅在你有意需要在同一个已补水 box 上运行多个命令时使用复用:
|
||||
|
||||
```bash
|
||||
pnpm crabbox:run -- --provider blacksmith-testbox --id <tbx_id> --no-sync --timing-json --shell -- "pnpm test <path-or-filter>"
|
||||
pnpm crabbox:stop -- <tbx_id>
|
||||
```
|
||||
|
||||
如果 Crabbox 是损坏的层,但 Blacksmith 本身可用,请将 direct Blacksmith 作为窄 fallback:
|
||||
如果 Crabbox 是出问题的层,但 Blacksmith 本身可用,请使用直接 Blacksmith 作为窄范围后备方案:
|
||||
|
||||
```bash
|
||||
blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90
|
||||
@ -556,7 +556,7 @@ blacksmith testbox run --id <tbx_id> "env CI=1 NODE_OPTIONS=--max-old-space-size
|
||||
blacksmith testbox stop --id <tbx_id>
|
||||
```
|
||||
|
||||
仅当 Blacksmith 宕机、受配额限制、缺少所需环境,或明确目标是自有容量时,才升级到自有 Crabbox 容量:
|
||||
仅当 Blacksmith 不可用、受配额限制、缺少所需环境,或明确目标是自有容量时,才升级到自有 Crabbox 容量:
|
||||
|
||||
```bash
|
||||
pnpm crabbox:warmup -- --provider aws --class beast --market on-demand --idle-timeout 90m
|
||||
@ -565,7 +565,7 @@ pnpm crabbox:run -- --id <cbx_id-or-slug> --timing-json --shell -- "env NODE_OPT
|
||||
pnpm crabbox:stop -- <cbx_id-or-slug>
|
||||
```
|
||||
|
||||
`.crabbox.yaml` 负责自有云 lanes 的 provider、sync 和 GitHub Actions hydration 默认值。它排除本地 `.git`,使 hydrated Actions checkout 保持自己的远程 Git 元数据,而不是同步维护者本地的 remotes 和 object stores;它还排除绝不应传输的本地 runtime/build artifacts。`.github/workflows/crabbox-hydrate.yml` 负责 checkout、Node/pnpm 设置、`origin/main` fetch,以及面向自有云 `crabbox run --id <cbx_id>` 命令的非 secret 环境交接。
|
||||
`.crabbox.yaml` 负责自有云通道的提供商、同步和 GitHub Actions 补水默认值。它会排除本地 `.git`,因此已补水的 Actions checkout 会保留自己的远程 Git 元数据,而不是同步维护者本地的 remotes 和对象存储;它还会排除绝不应传输的本地运行时/构建产物。`.github/workflows/crabbox-hydrate.yml` 负责自有云 `crabbox run --id <cbx_id>` 命令的 checkout、Node/pnpm 设置、`origin/main` 拉取,以及非密钥环境交接。
|
||||
|
||||
## 相关
|
||||
|
||||
|
||||
@ -1,71 +1,71 @@
|
||||
---
|
||||
read_when:
|
||||
- 了解 QA 栈如何协同工作
|
||||
- 了解 QA 技术栈如何协同工作
|
||||
- 扩展 qa-lab、qa-channel 或传输适配器
|
||||
- 添加由仓库支持的 QA 场景
|
||||
- 围绕 Gateway 网关仪表板构建更高真实度的 QA 自动化
|
||||
summary: QA 栈概览:qa-lab、qa-channel、由仓库支持的场景、实时传输通道、传输适配器和报告。
|
||||
- 围绕 Gateway 网关仪表板构建更贴近真实场景的 QA 自动化
|
||||
summary: QA 栈概览:qa-lab、qa-channel、仓库支持的场景、实时传输通道、传输适配器和报告。
|
||||
title: QA overview
|
||||
x-i18n:
|
||||
generated_at: "2026-05-05T01:21:32Z"
|
||||
generated_at: "2026-05-05T04:27:07Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 83adbe934d73265a1b47ee463c98fdd3eddfb1cd063d3a46a83dfc7568df0a96
|
||||
source_hash: dac200f60fd6215ddee44a55cff947f0bfc09df51720710db4a5d1045b01f714
|
||||
source_path: concepts/qa-e2e-automation.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
私有 QA 栈旨在以比单个单元测试更真实、更贴近渠道形态的方式测试 OpenClaw。
|
||||
|
||||
当前组成部分:
|
||||
当前组成:
|
||||
|
||||
- `extensions/qa-channel`:合成消息渠道,包含私信、渠道、线程、回应、编辑和删除界面。
|
||||
- `extensions/qa-lab`:用于观察转录、注入入站消息并导出 Markdown 报告的调试器 UI 和 QA 总线。
|
||||
- `extensions/qa-matrix`,未来的运行器插件:实时传输适配器,在子 QA Gateway 网关内驱动真实渠道。
|
||||
- `qa/`:由仓库支持的启动任务和基线 QA 场景种子资产。
|
||||
- [Mantis](/zh-CN/concepts/mantis):用于需要真实传输、浏览器截图、VM 状态和 PR 证据的错误的前后实时验证。
|
||||
- `extensions/qa-channel`:合成消息渠道,包含私信、渠道、线程、回应、编辑和删除表面。
|
||||
- `extensions/qa-lab`:调试器 UI 和 QA 总线,用于观察转录、注入入站消息,以及导出 Markdown 报告。
|
||||
- `extensions/qa-matrix`、未来的运行器插件:实时传输适配器,会在子 QA Gateway 网关内驱动真实渠道。
|
||||
- `qa/`:由仓库托管的种子资产,用于启动任务和基线 QA 场景。
|
||||
- [Mantis](/zh-CN/concepts/mantis):用于需要真实传输、浏览器截图、VM 状态和 PR 证据的 bug,在修复前后进行实时验证。
|
||||
|
||||
## 命令界面
|
||||
## 命令表面
|
||||
|
||||
每个 QA 流程都在 `pnpm openclaw qa <subcommand>` 下运行。许多命令有 `pnpm qa:*` 脚本别名;两种形式都受支持。
|
||||
|
||||
| 命令 | 用途 |
|
||||
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `qa run` | 内置 QA 自检;写入 Markdown 报告。 |
|
||||
| `qa suite` | 针对 QA Gateway 网关通道运行由仓库支持的场景。别名:`pnpm openclaw qa suite --runner multipass`,用于一次性 Linux VM。 |
|
||||
| `qa coverage` | 打印 Markdown 场景覆盖率清单(`--json` 用于机器输出)。 |
|
||||
| `qa parity-report` | 比较两个 `qa-suite-summary.json` 文件并写入智能体对等报告。 |
|
||||
| `qa character-eval` | 跨多个实时模型运行角色 QA 场景,并生成评审报告。参见[报告](#reporting)。 |
|
||||
| `qa manual` | 针对选定的提供商/模型通道运行一次性提示。 |
|
||||
| `qa suite` | 针对 QA Gateway 网关通道运行仓库托管的场景。别名:`pnpm openclaw qa suite --runner multipass`,用于一次性 Linux VM。 |
|
||||
| `qa coverage` | 打印 Markdown 场景覆盖率清单(使用 `--json` 输出机器可读内容)。 |
|
||||
| `qa parity-report` | 比较两个 `qa-suite-summary.json` 文件,并写入智能体奇偶性报告。 |
|
||||
| `qa character-eval` | 跨多个实时模型运行角色 QA 场景,并生成带评判的报告。参见[报告](#reporting)。 |
|
||||
| `qa manual` | 针对所选提供商/模型通道运行一次性提示。 |
|
||||
| `qa ui` | 启动 QA 调试器 UI 和本地 QA 总线(别名:`pnpm qa:lab:ui`)。 |
|
||||
| `qa docker-build-image` | 构建预制 QA Docker 镜像。 |
|
||||
| `qa docker-scaffold` | 为 QA 仪表板 + Gateway 网关通道写入 docker-compose 脚手架。 |
|
||||
| `qa up` | 构建 QA 站点,启动由 Docker 支持的栈,打印 URL(别名:`pnpm qa:lab:up`;`:fast` 变体会添加 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`)。 |
|
||||
| `qa aimock` | 仅启动 AIMock 提供商服务器。 |
|
||||
| `qa mock-openai` | 仅启动具备场景感知能力的 `mock-openai` 提供商服务器。 |
|
||||
| `qa credentials doctor` / `add` / `list` / `remove` | 管理共享 Convex 凭据池。 |
|
||||
| `qa docker-scaffold` | 为 QA 仪表盘 + Gateway 网关通道写入 docker-compose 脚手架。 |
|
||||
| `qa up` | 构建 QA 站点,启动由 Docker 支撑的栈,打印 URL(别名:`pnpm qa:lab:up`;`:fast` 变体会添加 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`)。 |
|
||||
| `qa aimock` | 仅启动 AIMock 提供商服务器。 |
|
||||
| `qa mock-openai` | 仅启动感知场景的 `mock-openai` 提供商服务器。 |
|
||||
| `qa credentials doctor` / `add` / `list` / `remove` | 管理共享的 Convex 凭据池。 |
|
||||
| `qa matrix` | 针对一次性 Tuwunel homeserver 的实时传输通道。参见 [Matrix QA](/zh-CN/concepts/qa-matrix)。 |
|
||||
| `qa telegram` | 针对真实私有 Telegram 群组的实时传输通道。 |
|
||||
| `qa discord` | 针对真实私有 Discord 公会渠道的实时传输通道。 |
|
||||
| `qa discord` | 针对真实私有 Discord guild 渠道的实时传输通道。 |
|
||||
| `qa slack` | 针对真实私有 Slack 渠道的实时传输通道。 |
|
||||
| `qa mantis` | 用于实时传输错误的前后验证运行器,包含 Discord 状态回应证据、Crabbox 桌面/浏览器冒烟测试,以及 Slack-in-VNC 冒烟测试。参见 [Mantis](/zh-CN/concepts/mantis)。 |
|
||||
| `qa mantis` | 用于实时传输 bug 的修复前后验证运行器,包含 Discord 状态回应证据、Crabbox 桌面/浏览器冒烟测试,以及 Slack-in-VNC 冒烟测试。参见 [Mantis](/zh-CN/concepts/mantis)。 |
|
||||
|
||||
## 操作员流程
|
||||
## 操作者流程
|
||||
|
||||
当前 QA 操作员流程是一个双窗格 QA 站点:
|
||||
当前 QA 操作者流程是一个双窗格 QA 站点:
|
||||
|
||||
- 左侧:带有智能体的 Gateway 网关仪表板(Control UI)。
|
||||
- 左侧:带智能体的 Gateway 网关仪表盘(Control UI)。
|
||||
- 右侧:QA Lab,显示类似 Slack 的转录和场景计划。
|
||||
|
||||
使用以下命令运行:
|
||||
运行方式:
|
||||
|
||||
```bash
|
||||
pnpm qa:lab:up
|
||||
```
|
||||
|
||||
这会构建 QA 站点,启动由 Docker 支持的 Gateway 网关通道,并公开 QA Lab 页面,操作员或自动化 loop 可以在其中给智能体分配 QA 任务、观察真实渠道行为,并记录哪些有效、失败或仍然受阻。
|
||||
这会构建 QA 站点,启动由 Docker 支撑的 Gateway 网关通道,并暴露 QA Lab 页面;操作者或自动化循环可以在该页面给智能体分配 QA 任务,观察真实渠道行为,并记录哪些有效、失败或仍被阻塞。
|
||||
|
||||
为了更快地迭代 QA Lab UI,而不必每次都重建 Docker 镜像,请使用绑定挂载的 QA Lab bundle 启动栈:
|
||||
为了更快迭代 QA Lab UI,而不必每次都重建 Docker 镜像,可使用绑定挂载的 QA Lab 包启动栈:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa docker-build-image
|
||||
@ -74,27 +74,27 @@ pnpm qa:lab:up:fast
|
||||
pnpm qa:lab:watch
|
||||
```
|
||||
|
||||
`qa:lab:up:fast` 会让 Docker 服务使用预构建镜像,并将 `extensions/qa-lab/web/dist` 绑定挂载到 `qa-lab` 容器中。`qa:lab:watch` 会在变更时重建该 bundle,并且浏览器会在 QA Lab 资产哈希变化时自动重新加载。
|
||||
`qa:lab:up:fast` 会让 Docker 服务使用预构建镜像,并将 `extensions/qa-lab/web/dist` 绑定挂载到 `qa-lab` 容器中。`qa:lab:watch` 会在变更时重建该包,而浏览器会在 QA Lab 资产哈希变更时自动重新加载。
|
||||
|
||||
要进行本地 OpenTelemetry trace 冒烟测试,请运行:
|
||||
对于本地 OpenTelemetry 跟踪冒烟测试,运行:
|
||||
|
||||
```bash
|
||||
pnpm qa:otel:smoke
|
||||
```
|
||||
|
||||
该脚本会启动本地 OTLP/HTTP trace 接收器,在启用 `diagnostics-otel` 插件的情况下运行 `otel-trace-smoke` QA 场景,然后解码导出的 protobuf spans,并断言发布关键形态:必须存在 `openclaw.run`、`openclaw.harness.run`、`openclaw.model.call`、`openclaw.context.assembled` 和 `openclaw.message.delivery`;成功轮次中的模型调用不得导出 `StreamAbandoned`;原始诊断 ID 和 `openclaw.content.*` 属性必须留在 trace 之外。它会在 QA 套件工件旁写入 `otel-smoke-summary.json`。
|
||||
该脚本会启动本地 OTLP/HTTP 跟踪接收器,在启用 `diagnostics-otel` 插件的情况下运行 `otel-trace-smoke` QA 场景,然后解码导出的 protobuf span,并断言发布关键形态:必须存在 `openclaw.run`、`openclaw.harness.run`、`openclaw.model.call`、`openclaw.context.assembled` 和 `openclaw.message.delivery`;成功轮次上的模型调用不得导出 `StreamAbandoned`;原始诊断 ID 和 `openclaw.content.*` 属性必须留在跟踪之外。它会在 QA 套件工件旁写入 `otel-smoke-summary.json`。
|
||||
|
||||
可观测性 QA 仅保留在源码 checkout 中。npm tarball 会有意省略 QA Lab,因此包 Docker 发布通道不会运行 `qa` 命令。修改诊断 instrumentation 时,请从已构建的源码 checkout 运行 `pnpm qa:otel:smoke`。
|
||||
可观测性 QA 仅限源码检出。npm tarball 会有意省略 QA Lab,因此包 Docker 发布通道不会运行 `qa` 命令。更改诊断 instrumentation 时,请从已构建的源码检出运行 `pnpm qa:otel:smoke`。
|
||||
|
||||
要运行真实 Matrix 传输冒烟通道,请运行:
|
||||
对于使用真实传输的 Matrix 冒烟通道,运行:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa matrix --profile fast --fail-fast
|
||||
```
|
||||
|
||||
该通道的完整 CLI 参考、profile/场景目录、环境变量和工件布局位于 [Matrix QA](/zh-CN/concepts/qa-matrix)。简要来说:它会在 Docker 中预配一次性 Tuwunel homeserver,注册临时的驱动/SUT/观察者用户,在限定到该传输的子 QA Gateway 网关内运行真实 Matrix 插件(不使用 `qa-channel`),然后在 `.artifacts/qa-e2e/matrix-<timestamp>/` 下写入 Markdown 报告、JSON 摘要、observed-events 工件和组合输出日志。
|
||||
该通道的完整 CLI 参考、profile/场景目录、环境变量和工件布局位于 [Matrix QA](/zh-CN/concepts/qa-matrix)。简要来说:它会在 Docker 中预配一次性 Tuwunel homeserver,注册临时 driver/SUT/observer 用户,在限定到该传输的子 QA Gateway 网关内运行真实 Matrix 插件(不使用 `qa-channel`),然后在 `.artifacts/qa-e2e/matrix-<timestamp>/` 下写入 Markdown 报告、JSON 摘要、observed-events 工件和合并输出日志。
|
||||
|
||||
要运行真实传输的 Telegram、Discord 和 Slack 冒烟通道:
|
||||
对于使用真实传输的 Telegram、Discord 和 Slack 冒烟通道:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa telegram
|
||||
@ -102,9 +102,9 @@ pnpm openclaw qa discord
|
||||
pnpm openclaw qa slack
|
||||
```
|
||||
|
||||
它们会针对一个预先存在的真实渠道,并使用两个 bot(driver + SUT)。所需环境变量、场景列表、输出工件和 Convex 凭据池记录在下方的 [Telegram、Discord 和 Slack QA 参考](#telegram-discord-and-slack-qa-reference)中。
|
||||
它们会面向一个预先存在的真实渠道,并使用两个机器人(driver + SUT)。所需环境变量、场景列表、输出工件和 Convex 凭据池记录在下方的 [Telegram、Discord 和 Slack QA 参考](#telegram-discord-and-slack-qa-reference)中。
|
||||
|
||||
要运行带有 VNC 救援的完整 Slack 桌面 VM,请运行:
|
||||
对于带 VNC 救援的完整 Slack 桌面 VM 运行,运行:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa mantis slack-desktop-smoke \
|
||||
@ -113,62 +113,62 @@ pnpm openclaw qa mantis slack-desktop-smoke \
|
||||
--keep-lease
|
||||
```
|
||||
|
||||
该命令会租用一台 Crabbox 桌面/浏览器机器,在 VM 内运行 Slack 实时通道,在 VNC 浏览器中打开 Slack Web,捕获桌面,并将 `slack-qa/` 以及 `slack-desktop-smoke.png` 复制回 Mantis 工件目录。通过 VNC 手动登录 Slack Web 后,可复用 `--lease-id <cbx_...>`。使用 `--gateway-setup` 时,Mantis 会在 VM 内的端口 `38973` 上保留一个持久运行的 OpenClaw Slack Gateway 网关;不使用时,该命令会运行普通的 bot 到 bot Slack QA 通道,并在捕获工件后退出。
|
||||
该命令会租用一台 Crabbox 桌面/浏览器机器,在 VM 内运行 Slack 实时通道,在 VNC 浏览器中打开 Slack Web,捕获桌面,并将 `slack-qa/` 以及 `slack-desktop-smoke.png` 复制回 Mantis 工件目录。通过 VNC 手动登录 Slack Web 后,可复用 `--lease-id <cbx_...>`。使用 `--gateway-setup` 时,Mantis 会在 VM 内留下一个持久运行的 OpenClaw Slack Gateway 网关,端口为 `38973`;不使用时,该命令会运行普通的机器人到机器人 Slack QA 通道,并在捕获工件后退出。
|
||||
|
||||
使用池化实时凭据前,请运行:
|
||||
使用池化实时凭据之前,运行:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa credentials doctor
|
||||
```
|
||||
|
||||
Doctor 会检查 Convex 代理环境,验证端点设置,并在存在维护者 secret 时验证 admin/list 可达性。它只报告 secret 的已设置/缺失状态。
|
||||
Doctor 会检查 Convex broker 环境、验证端点设置,并在存在维护者 secret 时验证 admin/list 可达性。它只报告 secret 的已设置/缺失状态。
|
||||
|
||||
## 实时传输覆盖率
|
||||
|
||||
实时传输通道共享一份契约,而不是各自发明自己的场景列表形态。`qa-channel` 是广泛的合成产品行为套件,不属于实时传输覆盖率矩阵。
|
||||
实时传输通道共享一个契约,而不是各自发明自己的场景列表形态。`qa-channel` 是广泛的合成产品行为套件,不属于实时传输覆盖率矩阵。
|
||||
|
||||
| 通道 | Canary | 提及门控 | Bot 到 bot | 允许列表拦截 | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | 回应观察 | 帮助命令 | 原生命令注册 |
|
||||
| -------- | ------ | -------- | ---------- | ------------ | -------- | -------- | -------- | -------- | -------- | -------- | ------------ |
|
||||
| Matrix | x | x | x | x | x | x | x | x | x | | |
|
||||
| Telegram | x | x | x | | | | | | | x | |
|
||||
| Discord | x | x | x | | | | | | | | x |
|
||||
| Slack | x | x | x | | | | | | | | |
|
||||
| 通道 | Canary | Mention gating | Bot-to-bot | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command | Native command registration |
|
||||
| -------- | ------ | -------------- | ---------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | --------------------------- |
|
||||
| Matrix | x | x | x | x | x | x | x | x | x | | |
|
||||
| Telegram | x | x | x | | | | | | | x | |
|
||||
| Discord | x | x | x | | | | | | | | x |
|
||||
| Slack | x | x | x | | | | | | | | |
|
||||
|
||||
这会将 `qa-channel` 保持为广泛的产品行为套件,同时让 Matrix、Telegram 和未来的实时传输共享一份明确的传输契约清单。
|
||||
这会将 `qa-channel` 保持为广泛的产品行为套件,同时让 Matrix、Telegram 和未来的实时传输共享一个明确的传输契约清单。
|
||||
|
||||
要运行一次性 Linux VM 通道而不把 Docker 带入 QA 路径,请运行:
|
||||
对于无需把 Docker 带入 QA 路径的一次性 Linux VM 通道,运行:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline
|
||||
```
|
||||
|
||||
这会启动一个全新的 Multipass 来宾系统,在来宾系统内安装依赖、构建 OpenClaw、运行 `qa suite`,然后把标准 QA 报告和摘要复制回宿主机的 `.artifacts/qa-e2e/...`。
|
||||
它复用与宿主机上 `qa suite` 相同的场景选择行为。
|
||||
默认情况下,宿主机和 Multipass 套件运行会使用隔离的 Gateway 网关 worker 并行执行多个选定场景。`qa-channel` 默认并发数为 4,并受选定场景数量限制。使用 `--concurrency <count>` 调整 worker 数量,或使用 `--concurrency 1` 进行串行执行。
|
||||
当任一场景失败时,该命令会以非零状态退出。如果你想获取产物但不想产生失败退出码,请使用 `--allow-failures`。
|
||||
实时运行会转发对来宾系统实用且受支持的 QA 认证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。将 `--output-dir` 保持在仓库根目录下,这样来宾系统才能通过挂载的工作区写回。
|
||||
这会启动一个全新的 Multipass 客机,安装依赖,在客机内构建 OpenClaw,运行 `qa suite`,然后把普通 QA 报告和摘要复制回主机上的 `.artifacts/qa-e2e/...`。
|
||||
它会复用与主机上 `qa suite` 相同的场景选择行为。
|
||||
主机和 Multipass 套件运行默认会使用隔离的 Gateway 网关 worker 并行执行多个已选场景。`qa-channel` 默认并发数为 4,并受已选场景数量限制。使用 `--concurrency <count>` 调整 worker 数量,或使用 `--concurrency 1` 进行串行执行。
|
||||
当任何场景失败时,该命令会以非零状态退出。如果你想获得工件但不希望退出码失败,请使用 `--allow-failures`。
|
||||
实时运行会转发对客机实用的受支持 QA 凭证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。请将 `--output-dir` 保持在仓库根目录下,这样客机才能通过挂载的工作区写回。
|
||||
|
||||
## Telegram、Discord 和 Slack QA 参考
|
||||
|
||||
Matrix 因为场景数量以及基于 Docker 的 homeserver 供应,有一个[专用页面](/zh-CN/concepts/qa-matrix)。Telegram、Discord 和 Slack 更小,每个只有少量场景,没有配置文件系统,并且针对预先存在的真实渠道,所以它们的参考内容放在这里。
|
||||
Matrix 有一个[专用页面](/zh-CN/concepts/qa-matrix),因为它的场景数量较多,并且需要基于 Docker 的 homeserver 预配。Telegram、Discord 和 Slack 更小,每个只有少量场景,没有配置文件系统,并针对预先存在的真实渠道运行,因此它们的参考内容放在这里。
|
||||
|
||||
### 共享 CLI 标志
|
||||
|
||||
这些 lane 通过 `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts` 注册,并接受相同的标志:
|
||||
这些通道通过 `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts` 注册,并接受相同的标志:
|
||||
|
||||
| 标志 | 默认值 | 描述 |
|
||||
| 标志 | 默认值 | 描述 |
|
||||
| ------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--scenario <id>` | — | 只运行此场景。可重复。 |
|
||||
| `--output-dir <path>` | `<repo>/.artifacts/qa-e2e/{telegram,discord,slack}-<timestamp>` | 报告、摘要、已观察消息和输出日志的写入位置。相对路径会根据 `--repo-root` 解析。 |
|
||||
| `--repo-root <path>` | `process.cwd()` | 从中立 cwd 调用时的仓库根目录。 |
|
||||
| `--sut-account <id>` | `sut` | QA Gateway 网关配置中的临时账号 id。 |
|
||||
| `--provider-mode <mode>` | `live-frontier` | `mock-openai` 或 `live-frontier`(旧版 `live-openai` 仍可使用)。 |
|
||||
| `--model <ref>` / `--alt-model <ref>` | 提供商默认值 | 主模型/备用模型引用。 |
|
||||
| `--fast` | 关闭 | 支持时启用提供商快速模式。 |
|
||||
| `--credential-source <env\|convex>` | `env` | 请参阅 [Convex 凭证池](#convex-credential-pool)。 |
|
||||
| `--credential-role <maintainer\|ci>` | CI 中为 `ci`,否则为 `maintainer` | 使用 `--credential-source convex` 时采用的角色。 |
|
||||
| `--scenario <id>` | — | 仅运行此场景。可重复使用。 |
|
||||
| `--output-dir <path>` | `<repo>/.artifacts/qa-e2e/{telegram,discord,slack}-<timestamp>` | 报告、摘要、观测到的消息和输出日志的写入位置。相对路径会按 `--repo-root` 解析。 |
|
||||
| `--repo-root <path>` | `process.cwd()` | 从中立 cwd 调用时的仓库根目录。 |
|
||||
| `--sut-account <id>` | `sut` | QA Gateway 网关配置内的临时账号 id。 |
|
||||
| `--provider-mode <mode>` | `live-frontier` | `mock-openai` 或 `live-frontier`(旧版 `live-openai` 仍可使用)。 |
|
||||
| `--model <ref>` / `--alt-model <ref>` | 提供商默认值 | 主/备用模型引用。 |
|
||||
| `--fast` | 关闭 | 在支持的地方启用提供商快速模式。 |
|
||||
| `--credential-source <env\|convex>` | `env` | 参见 [Convex 凭证池](#convex-credential-pool)。 |
|
||||
| `--credential-role <maintainer\|ci>` | CI 中为 `ci`,否则为 `maintainer` | `--credential-source convex` 时使用的角色。 |
|
||||
|
||||
任一场景失败时,每个 lane 都会以非零状态退出。`--allow-failures` 会写入产物,但不会设置失败退出码。
|
||||
任何场景失败时,每个通道都会以非零状态退出。`--allow-failures` 会写入工件,但不会设置失败退出码。
|
||||
|
||||
### Telegram QA
|
||||
|
||||
@ -176,9 +176,9 @@ Matrix 因为场景数量以及基于 Docker 的 homeserver 供应,有一个[
|
||||
pnpm openclaw qa telegram
|
||||
```
|
||||
|
||||
目标是一个真实的私有 Telegram 群组,并使用两个不同的 bot(driver + SUT)。SUT bot 必须有 Telegram 用户名;当两个 bot 都在 `@BotFather` 中启用 **Bot-to-Bot Communication Mode** 时,bot 到 bot 的观测效果最好。
|
||||
目标是一个真实的私有 Telegram 群组,并使用两个不同的机器人(driver + SUT)。SUT 机器人必须有 Telegram 用户名;当两个机器人都在 `@BotFather` 中启用 **Bot 到 Bot 通信模式** 时,机器人到机器人观测效果最佳。
|
||||
|
||||
使用 `--credential-source env` 时必需的环境变量:
|
||||
当 `--credential-source env` 时需要的环境变量:
|
||||
|
||||
- `OPENCLAW_QA_TELEGRAM_GROUP_ID` — 数字聊天 id(字符串)。
|
||||
- `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`
|
||||
@ -186,7 +186,7 @@ pnpm openclaw qa telegram
|
||||
|
||||
可选:
|
||||
|
||||
- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` 会在已观察消息产物中保留消息正文(默认会脱敏)。
|
||||
- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` 会在观测消息工件中保留消息正文(默认会脱敏)。
|
||||
|
||||
场景(`extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts:44`):
|
||||
|
||||
@ -198,12 +198,14 @@ pnpm openclaw qa telegram
|
||||
- `telegram-tools-compact-command`
|
||||
- `telegram-whoami-command`
|
||||
- `telegram-context-command`
|
||||
- `telegram-long-final-reuses-preview`
|
||||
- `telegram-long-final-three-chunks`
|
||||
|
||||
输出产物:
|
||||
输出工件:
|
||||
|
||||
- `telegram-qa-report.md`
|
||||
- `telegram-qa-summary.json` — 从 canary 开始,包含每条回复的 RTT(driver 发送 → 观察到 SUT 回复)。
|
||||
- `telegram-qa-observed-messages.json` — 除非设置 `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`,否则正文会被脱敏。
|
||||
- `telegram-qa-summary.json` — 包含从 canary 开始的每条回复 RTT(driver 发送 → 观测到 SUT 回复)。
|
||||
- `telegram-qa-observed-messages.json` — 正文会脱敏,除非设置了 `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`。
|
||||
|
||||
### Discord QA
|
||||
|
||||
@ -211,28 +213,28 @@ pnpm openclaw qa telegram
|
||||
pnpm openclaw qa discord
|
||||
```
|
||||
|
||||
目标是一个真实的私有 Discord guild 渠道,并使用两个 bot:一个由 harness 控制的 driver bot,以及一个由子 OpenClaw Gateway 网关通过内置 Discord 插件启动的 SUT bot。它会验证渠道提及处理、SUT bot 是否已向 Discord 注册原生 `/help` 命令,以及选择启用的 Mantis 证据场景。
|
||||
目标是一个真实的私有 Discord guild 频道,并使用两个机器人:由 harness 控制的 driver 机器人,以及由子 OpenClaw Gateway 网关通过内置 Discord 插件启动的 SUT 机器人。它会验证频道提及处理、SUT 机器人是否已在 Discord 注册原生 `/help` 命令,以及选择加入的 Mantis 证据场景。
|
||||
|
||||
使用 `--credential-source env` 时必需的环境变量:
|
||||
当 `--credential-source env` 时需要的环境变量:
|
||||
|
||||
- `OPENCLAW_QA_DISCORD_GUILD_ID`
|
||||
- `OPENCLAW_QA_DISCORD_CHANNEL_ID`
|
||||
- `OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN`
|
||||
- `OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN`
|
||||
- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — 必须与 Discord 返回的 SUT bot 用户 id 匹配(否则该 lane 会快速失败)。
|
||||
- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — 必须匹配 Discord 返回的 SUT 机器人用户 id(否则该通道会快速失败)。
|
||||
|
||||
可选:
|
||||
|
||||
- `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` 会在已观察消息产物中保留消息正文。
|
||||
- `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` 会在观测消息工件中保留消息正文。
|
||||
|
||||
场景(`extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts:36`):
|
||||
|
||||
- `discord-canary`
|
||||
- `discord-mention-gating`
|
||||
- `discord-native-help-command-registration`
|
||||
- `discord-status-reactions-tool-only` — 选择启用的 Mantis 场景。该场景会单独运行,因为它会将 SUT 切换为始终开启、仅工具模式的 guild 回复,并设置 `messages.statusReactions.enabled=true`,然后捕获 REST reaction 时间线以及 HTML/PNG 视觉产物。
|
||||
- `discord-status-reactions-tool-only` — 选择加入的 Mantis 场景。它会单独运行,因为它会将 SUT 切换为始终开启、仅工具的 guild 回复,并设置 `messages.statusReactions.enabled=true`,然后捕获 REST reaction 时间线以及 HTML/PNG 可视工件。
|
||||
|
||||
显式运行 Mantis status-reaction 场景:
|
||||
显式运行 Mantis Status reaction 场景:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa discord \
|
||||
@ -243,12 +245,12 @@ pnpm openclaw qa discord \
|
||||
--fast
|
||||
```
|
||||
|
||||
输出产物:
|
||||
输出工件:
|
||||
|
||||
- `discord-qa-report.md`
|
||||
- `discord-qa-summary.json`
|
||||
- `discord-qa-observed-messages.json` — 除非设置 `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1`,否则正文会被脱敏。
|
||||
- 运行 status-reaction 场景时会生成 `discord-qa-reaction-timelines.json` 和 `discord-status-reactions-tool-only-timeline.png`。
|
||||
- `discord-qa-observed-messages.json` — 正文会脱敏,除非设置了 `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1`。
|
||||
- 运行 Status reaction 场景时会生成 `discord-qa-reaction-timelines.json` 和 `discord-status-reactions-tool-only-timeline.png`。
|
||||
|
||||
### Slack QA
|
||||
|
||||
@ -256,9 +258,9 @@ pnpm openclaw qa discord \
|
||||
pnpm openclaw qa slack
|
||||
```
|
||||
|
||||
目标是一个真实的私有 Slack 渠道,并使用两个不同的 bot:一个由 harness 控制的 driver bot,以及一个由子 OpenClaw Gateway 网关通过内置 Slack 插件启动的 SUT bot。
|
||||
目标是一个真实的私有 Slack 频道,并使用两个不同的机器人:由 harness 控制的 driver 机器人,以及由子 OpenClaw Gateway 网关通过内置 Slack 插件启动的 SUT 机器人。
|
||||
|
||||
使用 `--credential-source env` 时必需的环境变量:
|
||||
当 `--credential-source env` 时需要的环境变量:
|
||||
|
||||
- `OPENCLAW_QA_SLACK_CHANNEL_ID`
|
||||
- `OPENCLAW_QA_SLACK_DRIVER_BOT_TOKEN`
|
||||
@ -267,35 +269,35 @@ pnpm openclaw qa slack
|
||||
|
||||
可选:
|
||||
|
||||
- `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` 会在已观察消息产物中保留消息正文。
|
||||
- `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` 会在观测消息工件中保留消息正文。
|
||||
|
||||
场景(`extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts:39`):
|
||||
|
||||
- `slack-canary`
|
||||
- `slack-mention-gating`
|
||||
|
||||
输出产物:
|
||||
输出工件:
|
||||
|
||||
- `slack-qa-report.md`
|
||||
- `slack-qa-summary.json`
|
||||
- `slack-qa-observed-messages.json` — 除非设置 `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1`,否则正文会被脱敏。
|
||||
- `slack-qa-observed-messages.json` — 正文会脱敏,除非设置了 `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1`。
|
||||
|
||||
#### 设置 Slack 工作区
|
||||
|
||||
该 lane 需要在一个工作区中有两个不同的 Slack 应用,以及一个两个 bot 都是成员的渠道:
|
||||
该通道需要在一个工作区中有两个不同的 Slack 应用,以及一个两个机器人都已加入的频道:
|
||||
|
||||
- `channelId` — 两个 bot 都已被邀请加入的渠道的 `Cxxxxxxxxxx` id。请使用专用渠道;该 lane 每次运行都会发帖。
|
||||
- `driverBotToken` — **Driver** 应用的 bot token(`xoxb-...`)。
|
||||
- `sutBotToken` — **SUT** 应用的 bot token(`xoxb-...`),它必须是与 driver 分离的 Slack 应用,这样它的 bot 用户 id 才会不同。
|
||||
- `sutAppToken` — SUT 应用的应用级 token(`xapp-...`),带有 `connections:write`,供 Socket Mode 使用,使 SUT 应用能够接收事件。
|
||||
- `channelId` — 两个机器人都被邀请加入的频道的 `Cxxxxxxxxxx` id。请使用专用频道;该通道每次运行都会发帖。
|
||||
- `driverBotToken` — **Driver** 应用的机器人令牌(`xoxb-...`)。
|
||||
- `sutBotToken` — **SUT** 应用的机器人令牌(`xoxb-...`),它必须是与 driver 分开的 Slack 应用,以便其机器人用户 id 不同。
|
||||
- `sutAppToken` — SUT 应用的应用级令牌(`xapp-...`),带有 `connections:write`,供 Socket Mode 使用,以便 SUT 应用可以接收事件。
|
||||
|
||||
相比复用生产工作区,更推荐使用专门用于 QA 的 Slack 工作区。
|
||||
建议使用专用于 QA 的 Slack 工作区,而不是复用生产工作区。
|
||||
|
||||
下面的 SUT manifest 映射了内置 Slack 插件的生产安装(`extensions/slack/src/setup-shared.ts:10`)。关于用户看到的生产渠道设置,请参阅 [Slack 渠道快速设置](/zh-CN/channels/slack#quick-setup);QA Driver/SUT 对有意分开,因为该 lane 需要在同一个工作区中有两个不同的 bot 用户 id。
|
||||
下面的 SUT 清单与内置 Slack 插件的生产安装保持一致(`extensions/slack/src/setup-shared.ts:10`)。关于用户看到的生产频道设置,请参见 [Slack 频道快速设置](/zh-CN/channels/slack#quick-setup);QA Driver/SUT 组合是有意分开的,因为该通道需要在同一工作区中有两个不同的机器人用户 id。
|
||||
|
||||
**1. 创建 Driver 应用**
|
||||
|
||||
前往 [api.slack.com/apps](https://api.slack.com/apps) → _Create New App_ → _From a manifest_ → 选择 QA 工作区,粘贴以下 manifest,然后点击 _Install to Workspace_:
|
||||
前往 [api.slack.com/apps](https://api.slack.com/apps) → _Create New App_ → _From a manifest_ → 选择 QA 工作区,粘贴以下清单,然后 _Install to Workspace_:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -320,11 +322,11 @@ pnpm openclaw qa slack
|
||||
}
|
||||
```
|
||||
|
||||
复制 _Bot User OAuth Token_(`xoxb-...`)— 它会成为 `driverBotToken`。driver 只需要发布消息并识别自身;不需要事件,也不需要 Socket Mode。
|
||||
复制 _Bot User OAuth Token_(`xoxb-...`)— 它会成为 `driverBotToken`。driver 只需要发送消息并识别自己;不需要事件,也不需要 Socket Mode。
|
||||
|
||||
**2. 创建 SUT 应用**
|
||||
|
||||
在同一个工作区中重复 _Create New App → From a manifest_。scope 集合映射了内置 Slack 插件的生产安装(`extensions/slack/src/setup-shared.ts:10`):
|
||||
在同一工作区中重复 _Create New App → From a manifest_。scope 集合与内置 Slack 插件的生产安装保持一致(`extensions/slack/src/setup-shared.ts:10`):
|
||||
|
||||
```json
|
||||
{
|
||||
@ -395,12 +397,12 @@ pnpm openclaw qa slack
|
||||
}
|
||||
```
|
||||
|
||||
Slack 创建应用后,在其设置页面执行两项操作:
|
||||
Slack 创建应用后,在其设置页面执行两件事:
|
||||
|
||||
- _Install to Workspace_ → 复制 _Bot User OAuth Token_ → 它会成为 `sutBotToken`。
|
||||
- _Basic Information → App-Level Tokens → Generate Token and Scopes_ → 添加 scope `connections:write` → 保存 → 复制 `xapp-...` 值 → 它会成为 `sutAppToken`。
|
||||
|
||||
通过对每个 token 调用 `auth.test` 来验证这两个机器人具有不同的用户 ID。运行时通过用户 ID 区分 driver 和 SUT;如果两者复用同一个应用,提及门控会立即失败。
|
||||
通过对每个 token 调用 `auth.test`,确认两个机器人具有不同的用户 ID。运行时通过用户 ID 区分驱动端和 SUT;两者复用同一个应用会导致提及门控立即失败。
|
||||
|
||||
**3. 创建渠道**
|
||||
|
||||
@ -411,13 +413,13 @@ Slack 创建应用后,在其设置页面执行两项操作:
|
||||
/invite @OpenClaw QA SUT
|
||||
```
|
||||
|
||||
从 _渠道信息 → 关于 → 渠道 ID_ 复制 `Cxxxxxxxxxx` ID,这会成为 `channelId`。公共渠道可用;如果你使用私有渠道,两个应用都已经有 `groups:history`,因此 harness 的历史读取仍会成功。
|
||||
从 _channel info → About → Channel ID_ 复制 `Cxxxxxxxxxx` ID,这会成为 `channelId`。公开渠道可用;如果你使用私有渠道,两个应用已经具有 `groups:history`,因此 harness 的历史读取仍会成功。
|
||||
|
||||
**4. 注册凭证**
|
||||
|
||||
有两种选择。单机调试时使用环境变量(设置四个 `OPENCLAW_QA_SLACK_*` 变量并传入 `--credential-source env`),或者为共享 Convex 池播种,让 CI 和其他维护者可以租用它们。
|
||||
有两个选项。单机调试使用环境变量(设置四个 `OPENCLAW_QA_SLACK_*` 变量并传入 `--credential-source env`),或者填充共享 Convex 池,以便 CI 和其他维护者可以租用它们。
|
||||
|
||||
对于 Convex 池,将四个字段写入 JSON 文件:
|
||||
对于 Convex 池,将四个字段写入一个 JSON 文件:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -428,7 +430,7 @@ Slack 创建应用后,在其设置页面执行两项操作:
|
||||
}
|
||||
```
|
||||
|
||||
在你的 shell 中导出 `OPENCLAW_QA_CONVEX_SITE_URL` 和 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 后,注册并验证:
|
||||
在 shell 中导出 `OPENCLAW_QA_CONVEX_SITE_URL` 和 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 后,注册并验证:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa credentials add \
|
||||
@ -439,11 +441,11 @@ pnpm openclaw qa credentials add \
|
||||
pnpm openclaw qa credentials list --kind slack --status all --json
|
||||
```
|
||||
|
||||
预期 `count: 1`、`status: "active"`,且没有 `lease` 字段。
|
||||
预期结果为 `count: 1`、`status: "active"`,且没有 `lease` 字段。
|
||||
|
||||
**5. 端到端验证**
|
||||
|
||||
在本地运行该 lane,确认两个机器人可以通过 broker 互相通信:
|
||||
在本地运行该 lane,确认两个机器人可以通过 broker 彼此通信:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa slack \
|
||||
@ -452,19 +454,19 @@ pnpm openclaw qa slack \
|
||||
--output-dir .artifacts/qa-e2e/slack-local
|
||||
```
|
||||
|
||||
绿色运行会在远少于 30 秒内完成,并且 `slack-qa-report.md` 会显示 `slack-canary` 和 `slack-mention-gating` 的 Status 都是 `pass`。如果该 lane 挂起约 90 秒后以 `Convex credential pool exhausted for kind "slack"` 退出,说明池为空或每一行都已被租用,`qa credentials list --kind slack --status all --json` 会告诉你是哪种情况。
|
||||
绿色运行会在远少于 30 秒内完成,并且 `slack-qa-report.md` 会显示 `slack-canary` 和 `slack-mention-gating` 的状态均为 `pass`。如果该 lane 挂起约 90 秒后退出,并显示 `Convex credential pool exhausted for kind "slack"`,则说明池为空或每一行都已被租用,`qa credentials list --kind slack --status all --json` 会告诉你具体是哪种情况。
|
||||
|
||||
### Convex 凭证池
|
||||
|
||||
Telegram、Discord 和 Slack lane 可以从共享 Convex 池租用凭证,而不是读取上面的环境变量。传入 `--credential-source convex`(或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`);QA Lab 会获取独占租约,在运行期间发送 Heartbeat,并在关闭时释放。池种类是 `"telegram"`、`"discord"` 和 `"slack"`。
|
||||
Telegram、Discord 和 Slack lane 可以从共享 Convex 池租用凭证,而不是读取上面的环境变量。传入 `--credential-source convex`(或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`);QA Lab 会获取一个独占租约,在运行期间发送 Heartbeat,并在关闭时释放它。池类型为 `"telegram"`、`"discord"` 和 `"slack"`。
|
||||
|
||||
broker 在 `admin/add` 上验证的 payload 形状:
|
||||
|
||||
- Telegram(`kind: "telegram"`):`{ groupId: string, driverToken: string, sutToken: string }` —— `groupId` 必须是数字聊天 ID 字符串。
|
||||
- Telegram(`kind: "telegram"`):`{ groupId: string, driverToken: string, sutToken: string }`,`groupId` 必须是数字聊天 ID 字符串。
|
||||
- Discord(`kind: "discord"`):`{ guildId: string, channelId: string, driverBotToken: string, sutBotToken: string, sutApplicationId: string }`。
|
||||
- Slack(`kind: "slack"`):`{ channelId: string, driverBotToken: string, sutBotToken: string, sutAppToken: string }` —— `channelId` 必须匹配 `^[A-Z][A-Z0-9]+$`(类似 `Cxxxxxxxxxx` 的 Slack ID)。有关应用和 scope 配置,请参阅 [设置 Slack 工作区](#setting-up-the-slack-workspace)。
|
||||
- Slack(`kind: "slack"`):`{ channelId: string, driverBotToken: string, sutBotToken: string, sutAppToken: string }`,`channelId` 必须匹配 `^[A-Z][A-Z0-9]+$`(类似 `Cxxxxxxxxxx` 的 Slack ID)。请参阅[设置 Slack 工作区](#setting-up-the-slack-workspace),了解应用和 scope 配置。
|
||||
|
||||
操作环境变量和 Convex broker 端点契约位于 [测试 → 通过 Convex 共享 Telegram 凭证](/zh-CN/help/testing#shared-telegram-credentials-via-convex-v1)(该章节名称早于 Discord 支持;两种类型的 broker 语义相同)。
|
||||
操作环境变量和 Convex broker 端点契约位于[测试 → 通过 Convex 共享 Telegram 凭证](/zh-CN/help/testing#shared-telegram-credentials-via-convex-v1)(该章节名称早于 Discord 支持;两种类型的 broker 语义相同)。
|
||||
|
||||
## 仓库支持的种子
|
||||
|
||||
@ -473,102 +475,102 @@ broker 在 `admin/add` 上验证的 payload 形状:
|
||||
- `qa/scenarios/index.md`
|
||||
- `qa/scenarios/<theme>/*.md`
|
||||
|
||||
这些内容有意放在 git 中,让 QA 计划对人类和智能体都可见。
|
||||
这些内容有意放在 git 中,以便 QA 计划同时对人类和智能体可见。
|
||||
|
||||
`qa-lab` 应保持为通用的 Markdown runner。每个场景 Markdown 文件都是一次测试运行的事实来源,并应定义:
|
||||
`qa-lab` 应保持为通用 Markdown 运行器。每个场景 Markdown 文件都是一次测试运行的事实来源,并应定义:
|
||||
|
||||
- 场景元数据
|
||||
- 可选的类别、能力、lane 和风险元数据
|
||||
- 文档和代码引用
|
||||
- 可选插件要求
|
||||
- 可选 Gateway 网关配置 patch
|
||||
- 可选的插件要求
|
||||
- 可选的 Gateway 网关配置补丁
|
||||
- 可执行的 `qa-flow`
|
||||
|
||||
支撑 `qa-flow` 的可复用运行时表面可以保持通用且跨领域。例如,Markdown 场景可以将传输侧 helper 与浏览器侧 helper 组合起来,后者通过 Gateway 网关 `browser.request` seam 驱动嵌入式 Control UI,而不需要添加特例 runner。
|
||||
支撑 `qa-flow` 的可复用运行时表面允许保持通用且横切。例如,Markdown 场景可以将传输侧 helper 与浏览器侧 helper 结合使用,通过 Gateway 网关 `browser.request` 接缝驱动嵌入式 Control UI,而无需添加特例运行器。
|
||||
|
||||
场景文件应按产品能力分组,而不是按源码树文件夹分组。文件移动时保持场景 ID 稳定;使用 `docsRefs` 和 `codeRefs` 实现实现可追溯性。
|
||||
场景文件应按产品能力分组,而不是按源码树文件夹分组。文件移动时保持场景 ID 稳定;使用 `docsRefs` 和 `codeRefs` 实现实现可追踪性。
|
||||
|
||||
基线列表应保持足够宽,以覆盖:
|
||||
基线列表应保持足够广泛,以覆盖:
|
||||
|
||||
- 私信和渠道聊天
|
||||
- 线程行为
|
||||
- 消息操作生命周期
|
||||
- cron 回调
|
||||
- 记忆召回
|
||||
- 记忆回忆
|
||||
- 模型切换
|
||||
- subagent handoff
|
||||
- 子智能体交接
|
||||
- 仓库读取和文档读取
|
||||
- 一个小型构建任务,例如 Lobster Invaders
|
||||
|
||||
## 提供商 mock lane
|
||||
## 提供商模拟 lane
|
||||
|
||||
`qa suite` 有两个本地提供商 mock lane:
|
||||
`qa suite` 有两个本地提供商模拟 lane:
|
||||
|
||||
- `mock-openai` 是感知场景的 OpenClaw mock。它仍是仓库支持的 QA 和 parity gate 的默认确定性 mock lane。
|
||||
- `aimock` 会启动一个 AIMock 支持的提供商服务器,用于实验性协议、fixture、录制/回放和 chaos 覆盖。它是增量补充,不会替代 `mock-openai` 场景 dispatcher。
|
||||
- `mock-openai` 是具备场景感知能力的 OpenClaw 模拟。它仍然是仓库支持 QA 和一致性门禁的默认确定性模拟 lane。
|
||||
- `aimock` 会启动一个 AIMock 支持的提供商服务器,用于实验性协议、fixture、录制/回放和 chaos 覆盖。它是增量能力,不会替代 `mock-openai` 场景调度器。
|
||||
|
||||
提供商 lane 实现位于 `extensions/qa-lab/src/providers/` 下。每个提供商拥有自己的默认值、本地服务器启动、Gateway 网关模型配置、auth-profile 暂存需求,以及 live/mock 能力标志。共享 suite 和 Gateway 网关代码应通过提供商 registry 路由,而不是按提供商名称分支。
|
||||
提供商 lane 实现位于 `extensions/qa-lab/src/providers/` 下。每个提供商拥有自己的默认值、本地服务器启动、Gateway 网关模型配置、auth-profile 暂存需求,以及 live/mock 能力标志。共享 suite 和 Gateway 网关代码应通过提供商注册表进行路由,而不是按提供商名称分支。
|
||||
|
||||
## 传输适配器
|
||||
|
||||
`qa-lab` 为 Markdown QA 场景拥有一个通用传输 seam。`qa-channel` 是该 seam 上的第一个适配器,但设计目标更广:未来的真实或合成渠道应接入同一个 suite runner,而不是添加传输专用的 QA runner。
|
||||
`qa-lab` 为 Markdown QA 场景拥有一个通用传输接缝。`qa-channel` 是该接缝上的第一个适配器,但设计目标更广:未来真实或合成渠道应接入同一个 suite 运行器,而不是添加传输特定的 QA 运行器。
|
||||
|
||||
在架构层面,拆分如下:
|
||||
在架构层面,划分如下:
|
||||
|
||||
- `qa-lab` 负责通用场景执行、worker 并发、artifact 写入和报告。
|
||||
- 传输适配器负责 Gateway 网关配置、就绪状态、入站和出站观察、传输操作,以及规范化传输状态。
|
||||
- `qa-lab` 拥有通用场景执行、worker 并发、artifact 写入和报告。
|
||||
- 传输适配器拥有 Gateway 网关配置、就绪状态、入站和出站观察、传输操作以及归一化传输状态。
|
||||
- `qa/scenarios/` 下的 Markdown 场景文件定义测试运行;`qa-lab` 提供执行它们的可复用运行时表面。
|
||||
|
||||
### 添加渠道
|
||||
|
||||
向 Markdown QA 系统添加一个渠道只需要两件事:
|
||||
向 Markdown QA 系统添加渠道只需要两件事:
|
||||
|
||||
1. 该渠道的传输适配器。
|
||||
2. 覆盖渠道契约的场景包。
|
||||
|
||||
当共享的 `qa-lab` host 可以拥有该流程时,不要添加新的顶层 QA 命令根。
|
||||
当共享 `qa-lab` 宿主能够拥有该流程时,不要添加新的顶层 QA 命令根。
|
||||
|
||||
`qa-lab` 拥有共享 host 机制:
|
||||
`qa-lab` 拥有共享宿主机制:
|
||||
|
||||
- `openclaw qa` 命令根
|
||||
- suite 启动和 teardown
|
||||
- suite 启动和清理
|
||||
- worker 并发
|
||||
- artifact 写入
|
||||
- 报告生成
|
||||
- 场景执行
|
||||
- 旧版 `qa-channel` 场景的兼容别名
|
||||
|
||||
Runner 插件拥有传输契约:
|
||||
运行器插件拥有传输契约:
|
||||
|
||||
- `openclaw qa <runner>` 如何挂载在共享 `qa` 根之下
|
||||
- Gateway 网关如何为该传输配置
|
||||
- 如何将 `openclaw qa <runner>` 挂载到共享 `qa` 根下
|
||||
- 如何为该传输配置 Gateway 网关
|
||||
- 如何检查就绪状态
|
||||
- 如何注入入站事件
|
||||
- 如何观察出站消息
|
||||
- 如何暴露 transcript 和规范化传输状态
|
||||
- 如何暴露 transcript 和归一化传输状态
|
||||
- 如何执行传输支持的操作
|
||||
- 如何处理传输专用 reset 或清理
|
||||
- 如何处理传输特定的重置或清理
|
||||
|
||||
新渠道的最低采纳门槛:
|
||||
新渠道的最低采用标准:
|
||||
|
||||
1. 保持 `qa-lab` 作为共享 `qa` 根的所有者。
|
||||
2. 在共享 `qa-lab` host seam 上实现传输 runner。
|
||||
3. 将传输专用机制保留在 runner 插件或渠道 harness 内。
|
||||
4. 将 runner 挂载为 `openclaw qa <runner>`,而不是注册一个竞争性的根命令。Runner 插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。保持 `runtime-api.ts` 轻量;惰性 CLI 和 runner 执行应留在单独入口点之后。
|
||||
5. 在主题化的 `qa/scenarios/` 目录下编写或改编 Markdown 场景。
|
||||
6. 为新场景使用通用场景 helper。
|
||||
7. 保持现有兼容别名可用,除非仓库正在进行有意的迁移。
|
||||
2. 在共享 `qa-lab` 宿主接缝上实现传输运行器。
|
||||
3. 将传输特定机制保留在运行器插件或渠道 harness 内。
|
||||
4. 将运行器挂载为 `openclaw qa <runner>`,而不是注册竞争性的根命令。运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。保持 `runtime-api.ts` 轻量;惰性 CLI 和运行器执行应位于单独入口点之后。
|
||||
5. 在按主题划分的 `qa/scenarios/` 目录下编写或改写 Markdown 场景。
|
||||
6. 对新场景使用通用场景 helper。
|
||||
7. 除非仓库正在进行有意迁移,否则保持现有兼容别名可用。
|
||||
|
||||
决策规则很严格:
|
||||
|
||||
- 如果行为可以在 `qa-lab` 中表达一次,就放到 `qa-lab` 中。
|
||||
- 如果行为依赖某一个渠道传输,就将它保留在对应 runner 插件或插件 harness 中。
|
||||
- 如果某个场景需要一个可被多个渠道使用的新能力,则添加通用 helper,而不是在 `suite.ts` 中添加渠道专用分支。
|
||||
- 如果某个行为只对一个传输有意义,则保持该场景为传输专用,并在场景契约中明确说明。
|
||||
- 如果行为可以在 `qa-lab` 中表达一次,就放入 `qa-lab`。
|
||||
- 如果行为依赖于某一个渠道传输,就将其保留在该运行器插件或插件 harness 中。
|
||||
- 如果某个场景需要一个可被多个渠道使用的新能力,请添加通用 helper,而不是在 `suite.ts` 中添加渠道特定分支。
|
||||
- 如果某个行为只对一种传输有意义,请保持该场景传输特定,并在场景契约中明确这一点。
|
||||
|
||||
### 场景 helper 名称
|
||||
|
||||
新场景的首选通用 helper:
|
||||
新场景首选的通用 helper:
|
||||
|
||||
- `waitForTransportReady`
|
||||
- `waitForChannelReady`
|
||||
@ -583,20 +585,21 @@ Runner 插件拥有传输契约:
|
||||
- `formatTransportTranscript`
|
||||
- `resetTransport`
|
||||
|
||||
现有场景仍可使用兼容别名:`waitForQaChannelReady`、`waitForOutboundMessage`、`waitForNoOutbound`、`formatConversationTranscript`、`resetBus`,但新场景编写应使用通用名称。这些别名用于避免一次性迁移,而不是未来的模型。
|
||||
现有场景仍可使用兼容别名:`waitForQaChannelReady`、`waitForOutboundMessage`、`waitForNoOutbound`、`formatConversationTranscript`、`resetBus`,但新场景编写应使用通用名称。这些别名的存在是为了避免一次性迁移,而不是未来的模型。
|
||||
|
||||
## 报告
|
||||
|
||||
`qa-lab` 会根据观察到的 bus timeline 导出 Markdown 协议报告。报告应回答:
|
||||
`qa-lab` 会从观察到的 bus 时间线导出 Markdown 协议报告。
|
||||
该报告应回答:
|
||||
|
||||
- 哪些内容有效
|
||||
- 哪些内容失败
|
||||
- 哪些内容仍被阻塞
|
||||
- 哪些有效
|
||||
- 哪些失败
|
||||
- 哪些仍被阻塞
|
||||
- 哪些后续场景值得添加
|
||||
|
||||
如需查看可用场景清单(在评估后续工作规模或接入新传输时很有用),运行 `pnpm openclaw qa coverage`(添加 `--json` 可获得机器可读输出)。
|
||||
要查看可用场景清单,这在评估后续工作规模或接入新传输时很有用,请运行 `pnpm openclaw qa coverage`(添加 `--json` 可获得机器可读输出)。
|
||||
|
||||
如需进行角色和风格检查,请在多个 live 模型引用上运行同一个场景,并写入经过评审的 Markdown 报告:
|
||||
对于角色和风格检查,请在多个 live 模型引用上运行同一场景,并写入经过评审的 Markdown 报告:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa character-eval \
|
||||
@ -615,16 +618,16 @@ pnpm openclaw qa character-eval \
|
||||
--judge-concurrency 16
|
||||
```
|
||||
|
||||
该命令运行本地 QA Gateway 网关子进程,而不是 Docker。角色评测场景应通过 `SOUL.md` 设置 persona,然后运行普通用户轮次,例如聊天、工作区帮助和小文件任务。不应告知候选模型它正在接受评测。该命令会保留每份完整 transcript,记录基本运行统计,然后以快速模式请求 judge models,并在支持的情况下使用 `xhigh` reasoning,按自然度、氛围和幽默感对运行结果排序。比较提供商时使用 `--blind-judge-models`:judge prompt 仍会获取每份 transcript 和运行状态,但候选引用会替换为中性标签,例如 `candidate-01`;报告会在解析后将排名映射回真实引用。
|
||||
候选运行默认使用 `high` thinking,GPT-5.5 使用 `medium`,较旧且支持的 OpenAI eval 引用使用 `xhigh`。可用 `--model provider/model,thinking=<level>` 内联覆盖特定候选。`--thinking <level>` 仍会设置全局 fallback,较旧的 `--model-thinking <provider/model=level>` 形式会保留以兼容。
|
||||
OpenAI 候选引用默认使用快速模式,因此在提供商支持时会使用 priority processing。当单个候选或 judge 需要覆盖时,可内联添加 `,fast`、`,no-fast` 或 `,fast=false`。仅当你想为每个候选模型强制开启快速模式时,才传入 `--fast`。候选和 judge 的耗时会记录在报告中以便基准分析,但 judge prompt 会明确说明不要按速度排名。
|
||||
候选和 judge 模型运行都默认并发数为 16。当提供商限制或本地 Gateway 网关压力导致运行噪声过大时,降低 `--concurrency` 或 `--judge-concurrency`。
|
||||
如果未传入候选 `--model`,角色评测在未传入 `--model` 时默认使用 `openai/gpt-5.5`、`openai/gpt-5.2`、`openai/gpt-5`、`anthropic/claude-opus-4-6`、`anthropic/claude-sonnet-4-6`、`zai/glm-5.1`、`moonshot/kimi-k2.5` 和 `google/gemini-3.1-pro-preview`。
|
||||
如果未传入 `--judge-model`,judge 默认使用 `openai/gpt-5.5,thinking=xhigh,fast` 和 `anthropic/claude-opus-4-6,thinking=high`。
|
||||
该命令会运行本地 QA Gateway 网关子进程,而不是 Docker。角色评估场景应通过 `SOUL.md` 设置 persona,然后运行普通用户轮次,例如聊天、工作区帮助和小型文件任务。不应告知候选模型它正在接受评估。该命令会保留每份完整 transcript,记录基本运行统计信息,然后让 judge 模型在快速模式下使用支持时的 `xhigh` 推理,根据自然度、vibe 和幽默感对运行结果进行排名。比较提供商时使用 `--blind-judge-models`:judge 提示仍会获得每份 transcript 和运行状态,但候选 ref 会替换为中性标签,例如 `candidate-01`;报告会在解析后将排名映射回真实 ref。
|
||||
候选运行默认使用 `high` thinking,GPT-5.5 使用 `medium`,较旧且支持它的 OpenAI eval ref 使用 `xhigh`。使用 `--model provider/model,thinking=<level>` 为特定候选进行内联覆盖。`--thinking <level>` 仍会设置全局 fallback,旧版 `--model-thinking <provider/model=level>` 形式会保留以保持兼容性。
|
||||
OpenAI 候选 ref 默认使用快速模式,因此在提供商支持时会使用优先处理。单个候选或 judge 需要覆盖时,可内联添加 `,fast`、`,no-fast` 或 `,fast=false`。仅当你想为每个候选模型强制开启快速模式时,才传入 `--fast`。候选和 judge 的耗时会记录在报告中用于 benchmark 分析,但 judge 提示会明确说明不要按速度排名。
|
||||
候选和 judge 模型运行默认并发数均为 16。当提供商限制或本地 Gateway 网关压力导致运行噪声过大时,请降低 `--concurrency` 或 `--judge-concurrency`。
|
||||
未传入候选 `--model` 时,角色评估默认使用 `openai/gpt-5.5`、`openai/gpt-5.2`、`openai/gpt-5`、`anthropic/claude-opus-4-6`、`anthropic/claude-sonnet-4-6`、`zai/glm-5.1`、`moonshot/kimi-k2.5` 和 `google/gemini-3.1-pro-preview`。
|
||||
未传入 `--judge-model` 时,judge 默认使用 `openai/gpt-5.5,thinking=xhigh,fast` 和 `anthropic/claude-opus-4-6,thinking=high`。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Matrix QA](/zh-CN/concepts/qa-matrix)
|
||||
- [QA Channel](/zh-CN/channels/qa-channel)
|
||||
- [测试](/zh-CN/help/testing)
|
||||
- [仪表板](/zh-CN/web/dashboard)
|
||||
- [仪表盘](/zh-CN/web/dashboard)
|
||||
|
||||
@ -1,34 +1,34 @@
|
||||
---
|
||||
read_when:
|
||||
- 更改 OpenClaw 更新、Doctor、软件包验收或插件安装行为
|
||||
- 准备或批准发布候选版本
|
||||
- 调试包更新、插件依赖清理或插件安装回归问题
|
||||
- 更改 OpenClaw 更新、Doctor、包验收或插件安装行为
|
||||
- 准备或批准候选版本
|
||||
- 调试软件包更新、插件依赖清理或插件安装回归问题
|
||||
sidebarTitle: Update and plugin tests
|
||||
summary: OpenClaw 如何验证更新路径、包迁移以及插件安装/更新行为
|
||||
summary: OpenClaw 如何验证更新路径、包迁移和插件安装/更新行为
|
||||
title: 更新和插件测试
|
||||
x-i18n:
|
||||
generated_at: "2026-05-04T20:59:52Z"
|
||||
generated_at: "2026-05-05T04:26:56Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: e83a847c76f424199b5fccbd9a2b30d0bf01e4f466c4f9822bf7693d1c2ad286
|
||||
source_hash: 3e5dbc85d567b9aec07d13e309d45da45d9088fb41dcbb2a07dae69dca6b09af
|
||||
source_path: help/testing-updates-plugins.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
这是更新和插件验证的专用检查清单。目标很简单:证明可安装包能够更新真实用户状态,通过 `doctor` 修复过时的旧版状态,并且仍然能从受支持来源安装、加载、更新和卸载插件。
|
||||
这是更新和插件验证的专用检查清单。目标很简单:证明可安装包可以更新真实用户状态,通过 `doctor` 修复过时的旧版状态,并且仍然可以从受支持的来源安装、加载、更新和卸载插件。
|
||||
|
||||
如需更广泛的测试运行器映射,请参阅[测试](/zh-CN/help/testing)。如需实时提供商密钥和会触达网络的套件,请参阅[实时测试](/zh-CN/help/testing-live)。
|
||||
关于更广泛的测试运行器映射,请参阅[测试](/zh-CN/help/testing)。关于 live 提供商密钥和会访问网络的套件,请参阅 [live 测试](/zh-CN/help/testing-live)。
|
||||
|
||||
## 我们保护什么
|
||||
|
||||
更新和插件测试保护这些契约:
|
||||
更新和插件测试保护以下契约:
|
||||
|
||||
- 包 tarball 完整,包含有效的 `dist/postinstall-inventory.json`,并且不依赖未打包的仓库文件。
|
||||
- 用户可以从较旧的已发布包迁移到候选包,而不会丢失配置、智能体、会话、工作区、插件允许列表或渠道配置。
|
||||
- `openclaw doctor --fix --non-interactive` 负责旧版清理和修复路径。启动过程不应为过时插件状态增加隐藏的兼容性迁移。
|
||||
- 包 tarball 是完整的,包含有效的 `dist/postinstall-inventory.json`,且不依赖未打包的仓库文件。
|
||||
- 用户可以从较旧的已发布包迁移到候选包,而不会丢失配置、智能体、会话、工作区、插件 allowlist 或渠道配置。
|
||||
- `openclaw doctor --fix --non-interactive` 负责旧版清理和修复路径。启动流程不应为过时的插件状态增加隐藏的兼容性迁移。
|
||||
- 插件安装可从本地目录、git 仓库、npm 包和 ClawHub 注册表路径正常工作。
|
||||
- 插件 npm 依赖安装在受管理的 npm 根目录中,在信任前会被扫描,并在卸载期间通过 npm 移除,因此提升安装的依赖不会残留。
|
||||
- 当没有任何变化时,插件更新保持稳定:安装记录、解析后的来源、已安装依赖布局和启用状态都保持完整。
|
||||
- 插件 npm 依赖会安装到托管 npm 根目录,在信任前被扫描,并在卸载时通过 npm 移除,以免提升安装的依赖残留。
|
||||
- 当没有变化时,插件更新保持稳定:安装记录、解析后的来源、已安装依赖布局和启用状态都保持不变。
|
||||
|
||||
## 开发期间的本地证明
|
||||
|
||||
@ -40,23 +40,23 @@ pnpm check:changed
|
||||
pnpm test:changed
|
||||
```
|
||||
|
||||
对于插件安装、卸载、依赖或包清单变更,还要运行覆盖已编辑边界的聚焦测试:
|
||||
对于插件安装、卸载、依赖或包清单变更,还要运行覆盖已编辑接缝的聚焦测试:
|
||||
|
||||
```bash
|
||||
pnpm test src/plugins/uninstall.test.ts src/infra/package-dist-inventory.test.ts test/scripts/package-acceptance-workflow.test.ts
|
||||
```
|
||||
|
||||
在任何包 Docker 通道消费 tarball 之前,先证明包构件:
|
||||
在任何包 Docker 通道消费 tarball 之前,先证明包产物:
|
||||
|
||||
```bash
|
||||
pnpm release:check
|
||||
```
|
||||
|
||||
`release:check` 会运行配置/文档/API 漂移检查,写入包 dist 清单,运行 `npm pack --dry-run`,拒绝被禁止打包的文件,将 tarball 安装到临时前缀中,运行 postinstall,并对内置渠道入口点执行冒烟测试。
|
||||
`release:check` 会运行配置/文档/API 漂移检查,写入包 dist 清单,运行 `npm pack --dry-run`,拒绝被禁止的打包文件,将 tarball 安装到临时 prefix,运行 postinstall,并对内置渠道入口点做冒烟测试。
|
||||
|
||||
## Docker 通道
|
||||
|
||||
Docker 通道是产品级证明。它们会在 Linux 容器内安装或更新真实包,并通过 CLI 命令、Gateway 网关启动、HTTP 探测、RPC Status 和文件系统状态断言行为。
|
||||
Docker 通道是产品级证明。它们会在 Linux 容器中安装或更新真实包,并通过 CLI 命令、Gateway 网关启动、HTTP 探测、RPC 状态和文件系统状态断言行为。
|
||||
|
||||
迭代时使用聚焦通道:
|
||||
|
||||
@ -71,14 +71,14 @@ pnpm test:docker:update-migration
|
||||
|
||||
重要通道:
|
||||
|
||||
- `test:docker:plugins` 验证插件安装冒烟测试、本地文件夹安装、本地文件夹更新跳过行为、带预安装依赖的本地文件夹、`file:` 包安装、带 CLI 执行的 git 安装、git 移动引用更新、带提升传递依赖的 npm 注册表安装、npm 更新空操作、本地 ClawHub fixture 安装和更新空操作、marketplace 更新行为,以及 Claude 包启用/检查。设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可让 ClawHub 区块保持封闭/离线。
|
||||
- `test:docker:plugin-lifecycle-matrix` 在裸容器中安装候选包,让一个 npm 插件经过安装、检查、禁用、启用、显式升级、显式降级,以及删除插件代码后的卸载。它会记录每个阶段的 RSS 和 CPU 指标。
|
||||
- `test:docker:plugin-update` 验证未变更的已安装插件在 `openclaw plugins update` 期间不会重新安装或丢失安装元数据。
|
||||
- `test:docker:upgrade-survivor` 将候选 tarball 安装到脏的旧用户 fixture 之上,运行包更新和非交互式 Doctor,然后启动 local loopback Gateway 网关并检查状态保留情况。
|
||||
- `test:docker:published-upgrade-survivor` 首先安装一个已发布基线,通过内置的 `openclaw config set` 配方对其进行配置,将其更新到候选 tarball,运行 Doctor,检查旧版清理,启动 Gateway 网关,并探测 `/healthz`、`/readyz` 和 RPC Status。
|
||||
- `test:docker:update-migration` 是清理密集型的已发布更新通道。它从已配置的 Discord/Telegram 风格用户状态开始,运行基线 Doctor,让已配置的插件依赖有机会落地,为已配置的打包插件植入旧版插件依赖残留,更新到候选 tarball,并要求更新后的 Doctor 移除旧版依赖根目录。
|
||||
- `test:docker:plugins` 验证插件安装冒烟、本地文件夹安装、本地文件夹更新跳过行为、带预装依赖的本地文件夹、`file:` 包安装、带 CLI 执行的 git 安装、git 移动引用更新、带提升安装的传递依赖的 npm 注册表安装、npm 更新空操作、本地 ClawHub fixture 安装和更新空操作、市场更新行为,以及 Claude bundle 启用/检查。设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可让 ClawHub 块保持 hermetic/离线。
|
||||
- `test:docker:plugin-lifecycle-matrix` 在裸容器中安装候选包,运行一个 npm 插件,覆盖安装、检查、禁用、启用、显式升级、显式降级,以及删除插件代码后的卸载。它会记录每个阶段的 RSS 和 CPU 指标。
|
||||
- `test:docker:plugin-update` 验证未变化的已安装插件在 `openclaw plugins update` 期间不会重新安装或丢失安装元数据。
|
||||
- `test:docker:upgrade-survivor` 将候选 tarball 安装到脏旧用户 fixture 之上,运行包更新和非交互式 doctor,然后启动 local loopback Gateway 网关并检查状态保留。
|
||||
- `test:docker:published-upgrade-survivor` 首先安装已发布基线,通过内置的 `openclaw config set` 配方进行配置,将其更新到候选 tarball,运行 doctor,检查旧版清理,启动 Gateway 网关,并探测 `/healthz`、`/readyz` 和 RPC 状态。
|
||||
- `test:docker:update-migration` 是清理密集型的已发布更新通道。它从已配置的 Discord/Telegram 风格用户状态开始,运行基线 doctor,使已配置插件依赖有机会物化,为已配置的打包插件植入旧版插件依赖碎片,更新到候选 tarball,并要求更新后 doctor 移除旧版依赖根目录。
|
||||
|
||||
有用的已发布升级幸存者变体:
|
||||
实用的已发布升级 survivor 变体:
|
||||
|
||||
```bash
|
||||
OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=openclaw@2026.4.23 \
|
||||
@ -90,9 +90,9 @@ OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=bootstrap-persona \
|
||||
pnpm test:docker:published-upgrade-survivor
|
||||
```
|
||||
|
||||
可用场景包括 `base`、`feishu-channel`、`bootstrap-persona`、`plugin-deps-cleanup`、`configured-plugin-installs`、`stale-source-plugin-shadow`、`tilde-log-path` 和 `versioned-runtime-deps`。在聚合运行中,`OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues` 会展开为所有呈现为已报告问题形态的场景,包括已配置插件安装迁移。
|
||||
可用场景包括 `base`、`feishu-channel`、`bootstrap-persona`、`plugin-deps-cleanup`、`configured-plugin-installs`、`stale-source-plugin-shadow`、`tilde-log-path` 和 `versioned-runtime-deps`。在聚合运行中,`OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues` 会扩展为所有报告问题形态的场景,包括已配置插件安装迁移。
|
||||
|
||||
完整更新迁移有意与完整发布 CI 分离。当发布问题是“从 `2026.4.23` 起每个已发布稳定版本是否都能更新到此候选版本并清理插件依赖残留?”时,请使用手动 `Update Migration` workflow:
|
||||
完整更新迁移有意与 Full Release CI 分开。当发布问题是“从 2026.4.23 起的每个已发布稳定版本是否都能更新到此候选版本并清理插件依赖碎片?”时,请使用手动 `Update Migration` workflow:
|
||||
|
||||
```bash
|
||||
gh workflow run update-migration.yml \
|
||||
@ -103,38 +103,40 @@ gh workflow run update-migration.yml \
|
||||
-f scenarios=plugin-deps-cleanup
|
||||
```
|
||||
|
||||
## 包验收
|
||||
## Package Acceptance
|
||||
|
||||
包验收是 GitHub 原生包门禁。它会将一个候选包解析为 `package-under-test` tarball,记录版本和 SHA-256,然后针对该精确 tarball 运行可复用 Docker E2E 通道。workflow harness 引用与包源码引用分离,因此当前测试逻辑可以验证较旧的受信任版本。
|
||||
Package Acceptance 是 GitHub 原生包关卡。它会将一个候选包解析为 `package-under-test` tarball,记录版本和 SHA-256,然后针对该精确 tarball 运行可复用的 Docker E2E 通道。workflow harness ref 与包来源 ref 分离,因此当前测试逻辑可以验证较旧的受信任版本。
|
||||
|
||||
候选来源:
|
||||
|
||||
- `source=npm`:验证 `openclaw@beta`、`openclaw@latest` 或精确的已发布版本。
|
||||
- `source=ref`:使用选定的当前 harness 打包受信任的分支、标签或提交。
|
||||
- `source=ref`:使用选定的当前 harness 打包受信任分支、标签或提交。
|
||||
- `source=url`:验证 HTTPS tarball,并要求提供 `package_sha256`。
|
||||
- `source=artifact`:复用另一个 Actions 运行上传的 tarball。
|
||||
|
||||
完整发布验证默认使用 `source=artifact`,基于解析后的发布 SHA 构建。对于发布后证明,传入 `package_acceptance_package_spec=openclaw@YYYY.M.D`,让同一升级矩阵以已发布的 npm 包为目标。
|
||||
Full Release Validation 默认使用 `source=artifact`,从解析出的发布 SHA 构建。对于发布后证明,传入 `package_acceptance_package_spec=openclaw@YYYY.M.D`,让同一升级矩阵改为目标已发布 npm 包。
|
||||
|
||||
发布检查会用包/更新/插件集合调用包验收:
|
||||
发布检查会使用包/更新/插件集合调用 Package Acceptance:
|
||||
|
||||
```text
|
||||
doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update
|
||||
```
|
||||
|
||||
它们还会传入:
|
||||
启用发布 soak 时,它们还会传入:
|
||||
|
||||
```text
|
||||
published_upgrade_survivor_baselines=all-since-2026.4.23
|
||||
published_upgrade_survivor_baselines=last-stable-4 2026.4.23 2026.5.2 2026.4.15
|
||||
published_upgrade_survivor_scenarios=reported-issues
|
||||
telegram_mode=mock-openai
|
||||
```
|
||||
|
||||
这会让包迁移、更新渠道切换、过时插件依赖清理、离线插件覆盖、插件更新行为和 Telegram 包 QA 使用同一个解析后的构件。
|
||||
这样会让包迁移、更新渠道切换、过时插件依赖清理、离线插件覆盖、插件更新行为和 Telegram 包 QA 保持在同一个已解析产物上,同时不会让默认发布包关卡遍历每个已发布版本。
|
||||
|
||||
`all-since-2026.4.23` 是完整发布 CI 升级样本:从 `2026.4.23` 到 `latest` 的每个已发布到 npm 的稳定版本。对于穷尽式已发布更新迁移覆盖,请在单独的更新迁移 workflow 中使用 `all-since-2026.4.23`,而不是完整发布 CI。`release-history` 仍可用于手动更宽采样,适用于你还想包含旧版日期前锚点的情况。
|
||||
`last-stable-4` 会解析为最新四个已发布到 npm 的稳定 OpenClaw 版本。发布包验收将 `2026.4.23` 固定为第一个插件更新兼容性边界,将 `2026.5.2` 固定为插件架构变动边界,并将 `2026.4.15` 固定为较旧的 2026.4.1x 已发布更新基线;解析器会去重已包含在最新四个版本中的固定版本。对于穷尽式已发布更新迁移覆盖,请在单独的 Update Migration workflow 中使用 `all-since-2026.4.23`,而不是 Full Release CI。当你还想要旧版日期前锚点时,`release-history` 仍可用于手动更宽采样。
|
||||
|
||||
在发布前验证候选包时,手动运行包 profile:
|
||||
当选择多个已发布升级 survivor 基线时,可复用 Docker workflow 会将每个基线分片到自己的目标 runner job。每个基线分片仍会运行选定场景集合,但日志和产物会按基线保留,整体耗时受最慢分片限制,而不是一个大型串行 job。
|
||||
|
||||
发布前验证候选版本时,手动运行包 profile:
|
||||
|
||||
```bash
|
||||
gh workflow run package-acceptance.yml \
|
||||
@ -143,54 +145,54 @@ gh workflow run package-acceptance.yml \
|
||||
-f source=npm \
|
||||
-f package_spec=openclaw@beta \
|
||||
-f suite_profile=package \
|
||||
-f published_upgrade_survivor_baselines=all-since-2026.4.23 \
|
||||
-f published_upgrade_survivor_baselines="last-stable-4 2026.4.23 2026.5.2 2026.4.15" \
|
||||
-f published_upgrade_survivor_scenarios=reported-issues \
|
||||
-f telegram_mode=mock-openai
|
||||
```
|
||||
|
||||
当发布问题包含 MCP 渠道、cron/subagent 清理、OpenAI web search 或 OpenWebUI 时,使用 `suite_profile=product`。只有在需要完整 Docker 发布路径覆盖时,才使用 `suite_profile=full`。
|
||||
当发布问题包含 MCP 渠道、cron/subagent 清理、OpenAI web search 或 OpenWebUI 时,使用 `suite_profile=product`。仅在需要完整 Docker 发布路径覆盖时使用 `suite_profile=full`。
|
||||
|
||||
## 发布默认值
|
||||
## 发布默认项
|
||||
|
||||
对于候选发布版本,默认证明栈是:
|
||||
|
||||
1. `pnpm check:changed` 和 `pnpm test:changed`,用于源码级回归。
|
||||
2. `pnpm release:check`,用于包构件完整性。
|
||||
3. 包验收 `package` profile 或发布检查自定义包通道,用于安装/更新/插件契约。
|
||||
4. 跨 OS 发布检查,用于特定 OS 的安装器、新手引导和平台行为。
|
||||
5. 只有当变更表面触及提供商或托管服务行为时,才运行实时套件。
|
||||
1. `pnpm check:changed` 和 `pnpm test:changed` 用于源代码级回归。
|
||||
2. `pnpm release:check` 用于包产物完整性。
|
||||
3. Package Acceptance `package` profile 或 release-check 自定义包通道用于安装/更新/插件契约。
|
||||
4. Cross-OS release checks 用于特定操作系统的安装器、新手引导和平台行为。
|
||||
5. 仅当变更表面触及提供商或托管服务行为时,才运行 live 套件。
|
||||
|
||||
在维护者机器上,宽范围门禁和 Docker/包产品证明应在 Testbox 中运行,除非明确要做本地证明。
|
||||
在维护者机器上,广泛关卡和 Docker/包产品证明应在 Testbox 中运行,除非明确要做本地证明。
|
||||
|
||||
## 旧版兼容性
|
||||
|
||||
兼容宽容范围很窄并且有时限:
|
||||
兼容性宽容范围很窄且有时间限制:
|
||||
|
||||
- 到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,在包验收中可以容忍已经发布的包元数据缺口。
|
||||
- 到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,可以容忍 Package Acceptance 中已发布的包元数据缺口。
|
||||
- 已发布的 `2026.4.26` 包可以对已经发布的本地构建元数据戳文件发出警告。
|
||||
- 后续包必须满足现代契约。同样的缺口会失败,而不是警告或跳过。
|
||||
- 后续包必须满足现代契约。相同缺口会失败,而不是警告或跳过。
|
||||
|
||||
不要为这些旧形态添加新的启动迁移。添加或扩展 Doctor 修复,然后用 `upgrade-survivor` 或 `published-upgrade-survivor` 证明它。
|
||||
不要为这些旧形态添加新的启动迁移。添加或扩展 doctor 修复,然后用 `upgrade-survivor` 或 `published-upgrade-survivor` 证明它。
|
||||
|
||||
## 添加覆盖
|
||||
|
||||
更改更新或插件行为时,在能因正确原因失败的最低层添加覆盖:
|
||||
|
||||
- 纯路径或元数据逻辑:源码旁的单元测试。
|
||||
- 包清单或打包文件行为:`package-dist-inventory` 或 tarball 检查器测试。
|
||||
- 纯路径或元数据逻辑:在源文件旁添加单元测试。
|
||||
- 包清单或打包文件行为:`package-dist-inventory` 或 tarball checker 测试。
|
||||
- CLI 安装/更新行为:Docker 通道断言或 fixture。
|
||||
- 已发布版本迁移行为:`published-upgrade-survivor` 场景。
|
||||
- 注册表/包来源行为:`test:docker:plugins` fixture 或 ClawHub fixture 服务器。
|
||||
- 依赖布局或清理行为:同时断言运行时执行和文件系统边界。npm 依赖可能会被提升到受管理的 npm 根目录下,因此测试应证明该根目录被扫描/清理,而不是假设存在包本地的 `node_modules` 树。
|
||||
- 依赖布局或清理行为:同时断言运行时执行和文件系统边界。npm 依赖可能会提升安装到托管 npm 根目录下,因此测试应证明根目录会被扫描/清理,而不是假设存在包本地 `node_modules` 树。
|
||||
|
||||
默认保持新的 Docker fixture 封闭。除非测试目的就是实时注册表行为,否则使用本地 fixture 注册表和假包。
|
||||
默认保持新的 Docker fixture hermetic。使用本地 fixture 注册表和假包,除非测试重点是真实注册表行为。
|
||||
|
||||
## 失败分诊
|
||||
|
||||
从构件身份开始:
|
||||
从产物身份开始:
|
||||
|
||||
- 包验收 `resolve_package` 摘要:来源、版本、SHA-256 和构件名称。
|
||||
- Docker 构件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志和重新运行命令。
|
||||
- 升级幸存者摘要:`.artifacts/upgrade-survivor/summary.json`,包括基线版本、候选版本、场景、阶段耗时和配方步骤。
|
||||
- Package Acceptance `resolve_package` 摘要:来源、版本、SHA-256 和产物名称。
|
||||
- Docker 产物:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志和重跑命令。
|
||||
- Upgrade survivor 摘要:`.artifacts/upgrade-survivor/summary.json`,包括基线版本、候选版本、场景、阶段耗时和配方步骤。
|
||||
|
||||
优先使用同一个包构件重新运行失败的精确通道,而不是重新运行整个发布总括任务。
|
||||
优先使用同一包产物重跑失败的精确通道,而不是重跑整个发布总控流程。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,15 @@
|
||||
---
|
||||
read_when:
|
||||
- 正在查找公开发布渠道定义
|
||||
- 运行发布验证或软件包验收
|
||||
- 运行发布验证或包验收
|
||||
- 查找版本命名和发布节奏
|
||||
summary: 发布通道、操作员检查清单、验证环境、版本命名和发布节奏
|
||||
title: 发布策略
|
||||
x-i18n:
|
||||
generated_at: "2026-05-05T01:33:45Z"
|
||||
generated_at: "2026-05-05T04:26:58Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 41886d3bb2f970e6a86944e5ff207b1b29b1b64b1f234d45f626fed19cf032b3
|
||||
source_hash: e5f380b106fb304c932715d7b2ec5f92715b2572e7c582d7cfa9786a766730fd
|
||||
source_path: reference/RELEASING.md
|
||||
workflow: 16
|
||||
---
|
||||
@ -17,140 +17,130 @@ x-i18n:
|
||||
OpenClaw 有三个公开发布通道:
|
||||
|
||||
- stable:带标签的发布,默认发布到 npm `beta`,或在明确请求时发布到 npm `latest`
|
||||
- beta:发布到 npm `beta` 的预发布标签
|
||||
- beta:预发布标签,发布到 npm `beta`
|
||||
- dev:`main` 的移动头部
|
||||
|
||||
## 版本命名
|
||||
|
||||
- 稳定版发布版本:`YYYY.M.D`
|
||||
- 稳定发布版本:`YYYY.M.D`
|
||||
- Git 标签:`vYYYY.M.D`
|
||||
- 稳定版修正发布版本:`YYYY.M.D-N`
|
||||
- 稳定修正发布版本:`YYYY.M.D-N`
|
||||
- Git 标签:`vYYYY.M.D-N`
|
||||
- Beta 预发布版本:`YYYY.M.D-beta.N`
|
||||
- Git 标签:`vYYYY.M.D-beta.N`
|
||||
- 月份或日期不要补零
|
||||
- `latest` 表示当前已提升的稳定版 npm 发布
|
||||
- 月和日不要补零
|
||||
- `latest` 表示当前已提升的稳定 npm 发布
|
||||
- `beta` 表示当前 beta 安装目标
|
||||
- 稳定版和稳定版修正发布默认发布到 npm `beta`;发布操作员可以明确指定 `latest`,或稍后提升经过验证的 beta 构建
|
||||
- 每个稳定版 OpenClaw 发布都会同时交付 npm 包和 macOS 应用;
|
||||
beta 发布通常会先验证并发布 npm/包路径,而 mac 应用构建/签名/公证保留给稳定版,除非明确请求
|
||||
- 稳定版和稳定修正版默认发布到 npm `beta`;发布操作员可以明确指定 `latest`,或稍后提升一个已验证的 beta 构建
|
||||
- 每个稳定 OpenClaw 发布都会同时交付 npm 包和 macOS 应用;
|
||||
beta 发布通常先验证并发布 npm/包路径,Mac 应用构建/签名/公证保留给稳定版,除非明确请求
|
||||
|
||||
## 发布节奏
|
||||
|
||||
- 发布先进入 beta
|
||||
- 只有在最新 beta 验证通过后,才会进入稳定版
|
||||
- 维护者通常从基于当前 `main` 创建的 `release/YYYY.M.D` 分支切出发布,
|
||||
- 发布按 beta 优先推进
|
||||
- 只有在最新 beta 验证通过后才跟进稳定版
|
||||
- 维护者通常从当前 `main` 创建的 `release/YYYY.M.D` 分支切出发布,
|
||||
这样发布验证和修复不会阻塞 `main` 上的新开发
|
||||
- 如果某个 beta 标签已经推送或发布并需要修复,维护者会切出下一个 `-beta.N` 标签,而不是删除或重新创建旧的 beta 标签
|
||||
- 如果 beta 标签已经推送或发布并需要修复,维护者会切出下一个
|
||||
`-beta.N` 标签,而不是删除或重新创建旧的 beta 标签
|
||||
- 详细发布流程、审批、凭证和恢复说明仅限维护者使用
|
||||
|
||||
## 发布操作员检查清单
|
||||
|
||||
此检查清单是发布流程的公开形态。私有凭证、
|
||||
签名、公证、dist-tag 恢复和紧急回滚详情保留在
|
||||
仅限维护者使用的发布运行手册中。
|
||||
此检查清单是发布流程的公开形态。私有凭证、签名、公证、dist-tag 恢复和紧急回滚细节保留在仅限维护者的发布运行手册中。
|
||||
|
||||
1. 从当前 `main` 开始:拉取最新内容,确认目标提交已推送,
|
||||
并确认当前 `main` 的 CI 状态足够健康,可以从它创建分支。
|
||||
并确认当前 `main` CI 足够健康,可以从它创建分支。
|
||||
2. 使用 `/changelog` 根据真实提交历史重写顶部 `CHANGELOG.md` 章节,
|
||||
保持条目面向用户,提交并推送它,然后在创建分支前再次 rebase/pull。
|
||||
3. 检查
|
||||
保持条目面向用户,提交并推送,然后在创建分支前再 rebase/pull 一次。
|
||||
3. 查看
|
||||
`src/plugins/compat/registry.ts` 和
|
||||
`src/commands/doctor/shared/deprecation-compat.ts` 中的发布兼容性记录。只有当升级路径仍被覆盖时才移除过期兼容性,
|
||||
或记录为什么有意继续保留。
|
||||
4. 从当前 `main` 创建 `release/YYYY.M.D`;不要直接在 `main` 上执行常规发布工作。
|
||||
5. 为预期标签更新每个必需的版本位置,运行
|
||||
`pnpm plugins:sync`,使可发布的插件包共享发布版本和兼容性元数据,然后运行本地确定性预检:
|
||||
`src/commands/doctor/shared/deprecation-compat.ts` 中的发布兼容性记录。只有在升级路径仍然被覆盖时才移除过期兼容性,否则记录为什么有意继续保留。
|
||||
4. 从当前 `main` 创建 `release/YYYY.M.D`;不要直接在 `main` 上做常规发布工作。
|
||||
5. 为目标标签更新所有必需的版本位置,运行
|
||||
`pnpm plugins:sync`,让可发布的插件包共享发布版本和兼容性元数据,然后运行本地确定性预检:
|
||||
`pnpm check:test-types`、`pnpm check:architecture`、
|
||||
`pnpm build && pnpm ui:build`、`pnpm plugins:sync:check` 和
|
||||
`pnpm release:check`。
|
||||
6. 使用 `preflight_only=true` 运行 `OpenClaw NPM Release`。在标签存在之前,
|
||||
允许使用完整 40 字符的发布分支 SHA 进行仅验证预检。保存成功的 `preflight_run_id`。
|
||||
7. 针对发布分支、标签或完整提交 SHA,使用 `Full Release Validation` 启动所有预发布测试。这是四个大型发布测试盒子的唯一手动入口点:Vitest、Docker、QA Lab 和 Package。
|
||||
8. 如果验证失败,在发布分支上修复,并重新运行能证明修复的最小失败文件、通道、工作流作业、包配置、提供商或模型允许列表。只有当变更范围使先前证据失效时,才重新运行完整总控流程。
|
||||
9. 对于 beta,标记 `vYYYY.M.D-beta.N`,然后从匹配的 `release/YYYY.M.D` 分支运行 `OpenClaw Release Publish`。它会验证 `pnpm plugins:sync:check`,
|
||||
先将所有可发布的插件包发布到 npm,再将同一组以 ClawPack npm-pack tarball 的形式发布到 ClawHub,
|
||||
然后使用匹配的 dist-tag 提升已准备好的 OpenClaw npm 预检产物。发布后,针对已发布的 `openclaw@YYYY.M.D-beta.N` 或
|
||||
`openclaw@beta` 包运行发布后包验收。如果已推送或已发布的预发布需要修复,
|
||||
切出下一个匹配的预发布编号;不要删除或重写旧的预发布。
|
||||
10. 对于稳定版,只有在已验证的 beta 或候选发布具备所需验证证据后才继续。
|
||||
稳定版 npm 发布也通过
|
||||
`OpenClaw Release Publish`,并通过
|
||||
`preflight_run_id` 复用成功的预检产物;稳定版 macOS 发布就绪还需要 `main` 上的
|
||||
打包 `.zip`、`.dmg`、`.dSYM.zip` 和更新后的 `appcast.xml`。
|
||||
11. 发布后,运行 npm 发布后验证器,在需要发布后渠道证明时运行可选的独立已发布 npm Telegram E2E,
|
||||
在需要时进行 dist-tag 提升,根据完整匹配的 `CHANGELOG.md` 章节生成 GitHub 发布/预发布说明,
|
||||
并执行发布公告步骤。
|
||||
6. 运行带 `preflight_only=true` 的 `OpenClaw NPM Release`。在标签存在之前,
|
||||
允许使用完整的 40 字符发布分支 SHA 进行仅验证预检。保存成功的 `preflight_run_id`。
|
||||
7. 对发布分支、标签或完整提交 SHA 运行 `Full Release Validation`,启动所有预发布测试。这是四个大型发布测试盒子的唯一手动入口点:Vitest、Docker、QA Lab 和 Package。
|
||||
8. 如果验证失败,在发布分支上修复,并重新运行能证明修复的最小失败文件、通道、工作流作业、包配置、提供商或模型 allowlist。只有当变更表面让先前证据失效时,才重新运行完整总控流程。
|
||||
9. 对 beta,标记 `vYYYY.M.D-beta.N`,然后从匹配的 `release/YYYY.M.D` 分支运行 `OpenClaw Release Publish`。它会验证 `pnpm plugins:sync:check`,先将所有可发布的插件包发布到 npm,再将同一组包作为 ClawPack npm-pack tarball 发布到 ClawHub,随后用匹配的 dist-tag 提升已准备好的 OpenClaw npm 预检制品。发布后,针对已发布的 `openclaw@YYYY.M.D-beta.N` 或 `openclaw@beta` 包运行发布后包验收。如果已推送或已发布的预发布需要修复,切出下一个匹配的预发布编号;不要删除或重写旧预发布。
|
||||
10. 对稳定版,只有在已验证的 beta 或发布候选版本具备所需验证证据后才继续。稳定版 npm 发布也通过
|
||||
`OpenClaw Release Publish` 进行,并通过
|
||||
`preflight_run_id` 复用成功的预检制品;稳定版 macOS 发布就绪还要求 `main` 上有打包后的 `.zip`、`.dmg`、`.dSYM.zip` 和更新后的 `appcast.xml`。
|
||||
11. 发布后,运行 npm 发布后验证器;在需要发布后渠道证明时,可选运行独立的已发布 npm Telegram E2E;在需要时进行 dist-tag 提升;根据完整匹配的 `CHANGELOG.md` 章节生成 GitHub 发布/预发布说明;并执行发布公告步骤。
|
||||
|
||||
## 发布预检
|
||||
|
||||
- 在发布预检前运行 `pnpm check:test-types`,这样测试 TypeScript 会在更快的本地 `pnpm check` 门禁之外继续被覆盖
|
||||
- 在发布预检前运行 `pnpm check:architecture`,这样更广泛的导入循环和架构边界检查会在更快的本地门禁之外保持绿色
|
||||
- 在 `pnpm release:check` 前运行 `pnpm build && pnpm ui:build`,这样预期的 `dist/*` 发布产物和 Control UI 包会存在,可供打包验证步骤使用
|
||||
- 在根版本号提升后、打标签前运行 `pnpm plugins:sync`。它会更新可发布插件包版本、OpenClaw peer/API 兼容性元数据、构建元数据和插件 changelog 存根,使其匹配核心发布版本。`pnpm plugins:sync:check` 是非变更型发布保护检查;如果忘记了此步骤,发布工作流会在任何注册表变更前失败。
|
||||
- 在发布批准前运行手动 `Full Release Validation` 工作流,从一个入口点启动所有预发布测试盒。它接受分支、标签或完整提交 SHA,分发手动 `CI`,并为安装冒烟、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram lane 分发 `OpenClaw Release Checks`。稳定版/默认运行会将详尽的 live/E2E 和 Docker 发布路径 soak 保持在 `run_release_soak=true` 之后;`release_profile=full` 会强制启用 soak。使用 `release_profile=full` 和 `rerun_group=all` 时,它还会针对来自发布检查的 `release-package-under-test` 产物运行包 Telegram E2E。发布后,如果同一个 Telegram E2E 也应验证已发布的 npm 包,请提供 `npm_telegram_package_spec`。发布后,如果 Package Acceptance 应针对已发布的 npm 包而不是按 SHA 构建的产物运行其包/更新矩阵,请提供 `package_acceptance_package_spec`。当私有证据报告应证明验证匹配已发布的 npm 包但不强制运行 Telegram E2E 时,请提供 `evidence_package_spec`。示例:
|
||||
- 在发布预检前运行 `pnpm check:test-types`,以便测试 TypeScript 在更快的本地 `pnpm check` 门禁之外仍保持覆盖
|
||||
- 在发布预检前运行 `pnpm check:architecture`,以便更广泛的导入循环和架构边界检查在更快的本地门禁之外保持绿色
|
||||
- 在 `pnpm release:check` 前运行 `pnpm build && pnpm ui:build`,以便打包验证步骤所需的 `dist/*` 发布产物和 Control UI 包存在
|
||||
- 在根版本提升之后、打标签之前运行 `pnpm plugins:sync`。它会更新可发布插件包版本、OpenClaw peer/API 兼容性元数据、构建元数据和插件变更日志存根,使其与核心发布版本匹配。`pnpm plugins:sync:check` 是非变更式发布守卫;如果忘记此步骤,发布工作流会在任何 registry 变更之前失败。
|
||||
- 在发布批准前运行手动 `Full Release Validation` 工作流,从一个入口点启动所有预发布测试盒。它接受分支、标签或完整提交 SHA,分发手动 `CI`,并分发 `OpenClaw Release Checks`,覆盖安装 smoke、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram 通道。稳定版/默认运行会把详尽的 live/E2E 和 Docker 发布路径 soak 保留在 `run_release_soak=true` 后面;`release_profile=full` 会强制启用 soak。使用 `release_profile=full` 和 `rerun_group=all` 时,它还会针对发布检查中的 `release-package-under-test` 产物运行包 Telegram E2E。发布后提供 `npm_telegram_package_spec`,当同一个 Telegram E2E 也应验证已发布的 npm 包时使用。发布后提供 `package_acceptance_package_spec`,当 Package Acceptance 应针对已发货的 npm 包而非按 SHA 构建的产物运行其包/更新矩阵时使用。提供 `evidence_package_spec`,当私有证据报告应证明验证匹配已发布的 npm 包,而不强制运行 Telegram E2E 时使用。示例:
|
||||
`gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.D`
|
||||
- 当你希望在发布工作继续进行时,为包候选版本获取旁路证明,请运行手动 `Package Acceptance` 工作流。对 `openclaw@beta`、`openclaw@latest` 或精确发布版本使用 `source=npm`;使用 `source=ref` 以当前 `workflow_ref` harness 打包可信的 `package_ref` 分支/标签/SHA;对带必需 SHA-256 的 HTTPS tarball 使用 `source=url`;或对另一个 GitHub Actions 运行上传的 tarball 使用 `source=artifact`。该工作流会将候选版本解析为 `package-under-test`,针对该 tarball 复用 Docker E2E 发布调度器,并可通过 `telegram_mode=mock-openai` 或 `telegram_mode=live-frontier` 针对同一个 tarball 运行 Telegram QA。当所选 Docker lane 包含 `published-upgrade-survivor` 时,包产物就是候选版本,`published_upgrade_survivor_baseline` 会选择已发布的基线。
|
||||
- 当你想在发布工作继续进行时为包候选项获取旁路证明,运行手动 `Package Acceptance` 工作流。对 `openclaw@beta`、`openclaw@latest` 或精确发布版本使用 `source=npm`;用 `source=ref` 通过当前 `workflow_ref` harness 打包受信任的 `package_ref` 分支/标签/SHA;对带必需 SHA-256 的 HTTPS tarball 使用 `source=url`;或对另一个 GitHub Actions 运行上传的 tarball 使用 `source=artifact`。该工作流会将候选项解析为 `package-under-test`,针对该 tarball 复用 Docker E2E 发布调度器,并且可用 `telegram_mode=mock-openai` 或 `telegram_mode=live-frontier` 针对同一 tarball 运行 Telegram QA。当选中的 Docker 通道包含 `published-upgrade-survivor` 时,包产物就是候选项,`published_upgrade_survivor_baseline` 选择已发布的基线。
|
||||
示例:`gh workflow run package-acceptance.yml --ref main -f workflow_ref=main -f source=npm -f package_spec=openclaw@beta -f suite_profile=product -f published_upgrade_survivor_baseline=openclaw@2026.4.26 -f telegram_mode=mock-openai`
|
||||
常见配置档:
|
||||
- `smoke`:安装/渠道/智能体、Gateway 网关网络和配置重载 lane
|
||||
- `package`:无需 OpenWebUI 或 live ClawHub 的产物原生包/更新/插件 lane
|
||||
- `product`:包配置档加上 MCP 渠道、cron/subagent 清理、OpenAI web search 和 OpenWebUI
|
||||
常见配置:
|
||||
- `smoke`:安装/渠道/智能体、Gateway 网关网络和配置重载通道
|
||||
- `package`:产物原生的包/更新/插件通道,不含 OpenWebUI 或 live ClawHub
|
||||
- `product`:包配置加上 MCP 渠道、cron/subagent 清理、OpenAI web 搜索和 OpenWebUI
|
||||
- `full`:带 OpenWebUI 的 Docker 发布路径分块
|
||||
- `custom`:用于聚焦重跑的精确 `docker_lanes` 选择
|
||||
- 当你只需要发布候选版本的完整常规 CI 覆盖时,直接运行手动 `CI` 工作流。手动 CI 分发会绕过 changed 作用域并强制运行 Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python skills、Windows、macOS、Android 和 Control UI i18n lane。
|
||||
- 当你只需要发布候选项的完整常规 CI 覆盖时,直接运行手动 `CI` 工作流。手动 CI 分发会绕过变更范围限定,并强制运行 Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建 smoke、文档检查、Python Skills、Windows、macOS、Android 和 Control UI i18n 通道。
|
||||
示例:`gh workflow run ci.yml --ref release/YYYY.M.D`
|
||||
- 验证发布遥测时运行 `pnpm qa:otel:smoke`。它会通过本地 OTLP/HTTP receiver 演练 QA-lab,并验证导出的 trace span 名称、有界属性以及内容/标识符脱敏,无需 Opik、Langfuse 或其他外部 collector。
|
||||
- 验证发布 telemetry 时运行 `pnpm qa:otel:smoke`。它通过本地 OTLP/HTTP receiver 运行 QA-lab,并验证导出的 trace span 名称、有界属性以及内容/标识符脱敏,无需 Opik、Langfuse 或其他外部 collector。
|
||||
- 每次打标签发布前运行 `pnpm release:check`
|
||||
- 标签存在后,运行 `OpenClaw Release Publish` 执行会产生变更的发布序列。从 `release/YYYY.M.D` 分发它(或在发布 main 可达标签时从 `main` 分发),传入发布标签和成功的 OpenClaw npm `preflight_run_id`,并保留默认插件发布范围 `all-publishable`,除非你在有意执行聚焦修复。该工作流会串行化插件 npm 发布、插件 ClawHub 发布和 OpenClaw npm 发布,确保核心包不会早于其外置插件发布。
|
||||
- 标签存在后,运行 `OpenClaw Release Publish` 执行会产生变更的发布序列。从 `release/YYYY.M.D` 分发它(或在发布 main 可达标签时从 `main` 分发),传入发布标签和成功的 OpenClaw npm `preflight_run_id`,并保持默认插件发布范围 `all-publishable`,除非你是在有意运行聚焦修复。该工作流会串行化插件 npm 发布、插件 ClawHub 发布和 OpenClaw npm 发布,确保核心包不会在其外部化插件之前发布。
|
||||
- 发布检查现在在单独的手动工作流中运行:
|
||||
`OpenClaw Release Checks`
|
||||
- `OpenClaw Release Checks` 还会在发布批准前运行 QA Lab mock parity lane,以及快速 live Matrix 配置档和 Telegram QA lane。live lane 使用 `qa-live-shared` 环境;Telegram 还使用 Convex CI 凭证租约。当你希望并行获取完整 Matrix 传输、媒体和 E2EE 清单时,请使用 `matrix_profile=all` 和 `matrix_shards=true` 运行手动 `QA-Lab - All Lanes` 工作流。
|
||||
- `OpenClaw Release Checks` 还会在发布批准前运行 QA Lab mock parity 通道,以及快速 live Matrix 配置和 Telegram QA 通道。live 通道使用 `qa-live-shared` 环境;Telegram 还使用 Convex CI 凭证租约。当你想并行获取完整 Matrix 传输、媒体和 E2EE 清单时,运行手动 `QA-Lab - All Lanes` 工作流,并设置 `matrix_profile=all` 和 `matrix_shards=true`。
|
||||
- 跨 OS 安装和升级运行时验证是公开 `OpenClaw Release Checks` 和 `Full Release Validation` 的一部分,它们会直接调用可复用工作流 `.github/workflows/openclaw-cross-os-release-checks-reusable.yml`
|
||||
- 此拆分是有意的:保持真实 npm 发布路径简短、确定且聚焦产物,同时将较慢的 live 检查保留在自己的 lane 中,避免它们拖慢或阻塞发布
|
||||
- 带 secret 的发布检查应通过 `Full Release Validation` 分发,或从 `main`/release workflow ref 分发,这样工作流逻辑和 secret 都保持受控
|
||||
- 只要解析出的提交可从 OpenClaw 分支或发布标签到达,`OpenClaw Release Checks` 就接受分支、标签或完整提交 SHA
|
||||
- `OpenClaw NPM Release` 仅验证预检也接受当前完整 40 字符 workflow-branch 提交 SHA,无需已推送标签
|
||||
- 此拆分是有意的:让真实 npm 发布路径保持短、确定且聚焦产物,同时较慢的 live 检查保留在自己的通道中,避免拖慢或阻塞发布
|
||||
- 带密钥的发布检查应通过 `Full Release Validation` 分发,或从 `main`/release 工作流 ref 分发,以便工作流逻辑和密钥保持受控
|
||||
- `OpenClaw Release Checks` 接受分支、标签或完整提交 SHA,只要解析出的提交可从 OpenClaw 分支或发布标签到达
|
||||
- `OpenClaw NPM Release` 仅验证预检也接受当前完整 40 字符工作流分支提交 SHA,无需已推送标签
|
||||
- 该 SHA 路径仅用于验证,不能提升为真实发布
|
||||
- 在 SHA 模式下,工作流仅为包元数据检查合成 `v<package.json version>`;真实发布仍然需要真实发布标签
|
||||
- 两个工作流都会把真实发布和提升路径保留在 GitHub 托管 runner 上,而非变更型验证路径可以使用更大的 Blacksmith Linux runner
|
||||
- 该工作流使用 `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`,并同时使用 `OPENAI_API_KEY` 和 `ANTHROPIC_API_KEY` 工作流 secret
|
||||
- npm 发布预检不再等待单独的发布检查 lane
|
||||
- 在批准前运行 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`(或匹配的 beta/correction 标签)
|
||||
- npm 发布后,运行 `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`(或匹配的 beta/correction 版本),以在全新的临时 prefix 中验证已发布注册表安装路径
|
||||
- beta 发布后,运行 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live`,使用共享租约 Telegram 凭证池,针对已发布 npm 包验证已安装包新手引导、Telegram 设置和真实 Telegram E2E。本地维护者的一次性运行可以省略 Convex 变量,并直接传入三个 `OPENCLAW_QA_TELEGRAM_*` 环境变量凭证。
|
||||
- 若要从维护者机器运行完整的发布后 beta 冒烟,请使用 `pnpm release:beta-smoke -- --beta betaN`。该 helper 会运行 Parallels npm 更新/全新目标验证,分发 `NPM Telegram Beta E2E`,轮询精确工作流运行,下载产物并打印 Telegram 报告。
|
||||
- 维护者可以通过手动 `NPM Telegram Beta E2E` 工作流,在 GitHub Actions 中运行同一发布后检查。它有意仅手动运行,不会在每次 merge 时运行。
|
||||
- 在 SHA 模式下,工作流只为包元数据检查合成 `v<package.json version>`;真实发布仍需要真实发布标签
|
||||
- 两个工作流都把真实发布和提升路径保留在 GitHub-hosted runners 上,而非变更式验证路径可以使用更大的 Blacksmith Linux runners
|
||||
- 该工作流会使用 `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`,并同时使用 `OPENAI_API_KEY` 和 `ANTHROPIC_API_KEY` 工作流密钥
|
||||
- npm 发布预检不再等待单独的发布检查通道
|
||||
- 在批准前运行 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`(或匹配的 beta/修正版标签)
|
||||
- npm 发布后,运行 `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`(或匹配的 beta/修正版版本),以在全新的临时前缀中验证已发布 registry 安装路径
|
||||
- beta 发布后,运行 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live`,使用共享租约 Telegram 凭证池,针对已发布的 npm 包验证已安装包的新手引导、Telegram 设置和真实 Telegram E2E。本地维护者临时单次运行可以省略 Convex 变量,并直接传入三个 `OPENCLAW_QA_TELEGRAM_*` 环境变量凭证。
|
||||
- 要从维护者机器运行完整的发布后 beta smoke,请使用 `pnpm release:beta-smoke -- --beta betaN`。该 helper 会运行 Parallels npm 更新/全新目标验证,分发 `NPM Telegram Beta E2E`,轮询精确工作流运行,下载产物,并打印 Telegram 报告。
|
||||
- 维护者可以通过手动 `NPM Telegram Beta E2E` 工作流,从 GitHub Actions 运行同样的发布后检查。它有意仅支持手动运行,不会在每次合并时运行。
|
||||
- 维护者发布自动化现在使用先预检后提升:
|
||||
- 真实 npm 发布必须通过成功的 npm `preflight_run_id`
|
||||
- 真实 npm 发布必须从与成功预检运行相同的 `main` 或 `release/YYYY.M.D` 分支分发
|
||||
- 稳定版 npm 发布默认使用 `beta`
|
||||
- 稳定版 npm 发布可以通过工作流输入显式指定 `latest`
|
||||
- 基于 token 的 npm dist-tag 变更现在位于 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` 以确保安全,因为 `npm dist-tag add` 仍需要 `NPM_TOKEN`,而公开仓库保持仅 OIDC 发布
|
||||
- 公开 `macOS Release` 仅用于验证;当标签仅存在于 release 分支上但工作流从 `main` 分发时,请设置 `public_release_branch=release/YYYY.M.D`
|
||||
- 基于 token 的 npm dist-tag 变更现在位于 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`,出于安全原因,因为 `npm dist-tag add` 仍需要 `NPM_TOKEN`,而公开仓库保持仅 OIDC 发布
|
||||
- 公开 `macOS Release` 仅用于验证;当标签只存在于发布分支上,但工作流从 `main` 分发时,设置 `public_release_branch=release/YYYY.M.D`
|
||||
- 真实私有 mac 发布必须通过成功的私有 mac `preflight_run_id` 和 `validate_run_id`
|
||||
- 真实发布路径会提升已准备好的产物,而不是再次重建它们
|
||||
- 对于像 `YYYY.M.D-N` 这样的稳定版修正发布,发布后验证器还会检查从 `YYYY.M.D` 到 `YYYY.M.D-N` 的同一临时 prefix 升级路径,确保发布修正不会静默地让较旧的全局安装停留在基础稳定版 payload 上
|
||||
- 除非 tarball 同时包含 `dist/control-ui/index.html` 和非空 `dist/control-ui/assets/` payload,否则 npm 发布预检会封闭失败,避免我们再次发布空的浏览器 dashboard
|
||||
- 发布后验证还会检查已发布插件入口点和包元数据是否存在于已安装注册表布局中。缺少插件运行时 payload 的发布会导致 postpublish verifier 失败,且不能提升为 `latest`。
|
||||
- `pnpm test:install:smoke` 还会对候选更新 tarball 执行 npm pack `unpackedSize` 预算限制,因此安装器 e2e 会在发布发布路径前捕获意外的打包膨胀
|
||||
- 如果发布工作触及 CI planning、插件 timing manifest 或插件测试矩阵,请在批准前重新生成并审查由 planner 拥有的 `.github/workflows/plugin-prerelease.yml` 中的 `plugin-prerelease-extension-shard` 矩阵输出,确保发布说明不会描述过时的 CI 布局
|
||||
- 稳定版 macOS 发布就绪状态还包括 updater surface:
|
||||
- GitHub release 最终必须包含打包后的 `.zip`、`.dmg` 和 `.dSYM.zip`
|
||||
- 对于类似 `YYYY.M.D-N` 的稳定修正版发布,发布后验证器还会检查同一临时前缀下从 `YYYY.M.D` 到 `YYYY.M.D-N` 的升级路径,确保发布修正不会悄悄让旧的全局安装停留在基础稳定版 payload 上
|
||||
- npm 发布预检默认失败关闭,除非 tarball 同时包含 `dist/control-ui/index.html` 和非空 `dist/control-ui/assets/` payload,以避免再次发布空的浏览器 dashboard
|
||||
- 发布后验证还会检查已发布插件入口点和包元数据是否存在于已安装的 registry 布局中。缺少插件运行时 payload 的发布会导致 postpublish 验证器失败,且不能提升到 `latest`。
|
||||
- `pnpm test:install:smoke` 还会对候选更新 tarball 强制执行 npm pack `unpackedSize` 预算,因此安装器 e2e 会在发布路径发布前捕获意外的打包膨胀
|
||||
- 如果发布工作触及 CI 规划、插件时序清单或插件测试矩阵,请在批准前重新生成并审查由规划器拥有的 `.github/workflows/plugin-prerelease.yml` 中的 `plugin-prerelease-extension-shard` 矩阵输出,确保发布说明不会描述过时的 CI 布局
|
||||
- 稳定版 macOS 发布就绪还包括 updater 表面:
|
||||
- GitHub release 最终必须包含打包的 `.zip`、`.dmg` 和 `.dSYM.zip`
|
||||
- 发布后,`main` 上的 `appcast.xml` 必须指向新的稳定版 zip
|
||||
- 打包后的 app 必须保留非 debug bundle id、非空 Sparkle feed URL,以及不低于该发布版本规范 Sparkle 构建下限的 `CFBundleVersion`
|
||||
- 打包后的应用必须保持非调试 bundle id、非空 Sparkle feed URL,以及不低于该发布版本规范 Sparkle 构建下限的 `CFBundleVersion`
|
||||
|
||||
## 发布测试盒
|
||||
|
||||
`Full Release Validation` 是操作者从一个入口点启动所有预发布测试的方式。若要在快速变动分支上获得固定提交证明,请使用 helper,让每个子工作流都从固定到目标 SHA 的临时分支运行:
|
||||
`Full Release Validation` 是操作者从一个入口点启动所有预发布测试的方式。对于快速移动分支上的固定提交证明,使用该 helper,确保每个子工作流都从固定在目标 SHA 的临时分支运行:
|
||||
|
||||
```bash
|
||||
pnpm ci:full-release --sha <full-sha>
|
||||
```
|
||||
|
||||
该 helper 会推送 `release-ci/<sha>-...`,从该分支分发 `Full Release Validation` 并传入 `ref=<sha>`,验证每个子工作流的 `headSha` 都匹配目标,然后删除临时分支。这可以避免意外证明更新的 `main` 子运行。
|
||||
该 helper 会推送 `release-ci/<sha>-...`,从该分支分发 `Full Release Validation` 并传入 `ref=<sha>`,验证每个子工作流的 `headSha` 都匹配目标,然后删除临时分支。这可以避免意外证明较新的 `main` 子运行。
|
||||
|
||||
对于 release 分支或标签验证,请从可信的 `main` workflow ref 运行,并将 release 分支或标签作为 `ref` 传入:
|
||||
对于发布分支或标签验证,请从受信任的 `main` 工作流 ref 运行,并将发布分支或标签作为 `ref` 传入:
|
||||
|
||||
```bash
|
||||
gh workflow run full-release-validation.yml \
|
||||
@ -162,39 +152,20 @@ gh workflow run full-release-validation.yml \
|
||||
-f evidence_package_spec=openclaw@YYYY.M.D-beta.N
|
||||
```
|
||||
|
||||
该工作流会解析目标 ref,调度手动 `CI` 并设置
|
||||
`target_ref=<release-ref>`,调度 `OpenClaw Release Checks`,为面向包的检查准备一个父级 `release-package-under-test` 工件,并在 `release_profile=full` 且
|
||||
`rerun_group=all` 时,或在设置了 `npm_telegram_package_spec` 时,调度独立的包 Telegram E2E。随后,`OpenClaw Release
|
||||
Checks` 会展开安装冒烟、跨 OS 发布检查、启用 soak 时的 live/E2E Docker
|
||||
发布路径覆盖、带有 Telegram
|
||||
包 QA 的 Package Acceptance、QA Lab parity、live Matrix 和 live Telegram。只有当
|
||||
`Full Release Validation`
|
||||
摘要显示 `normal_ci` 和 `release_checks` 均成功时,完整运行才可接受。在 full/all 模式下,
|
||||
`npm_telegram` 子项也必须成功;在 full/all 之外,除非提供了已发布的 `npm_telegram_package_spec`,否则会跳过它。最终验证器摘要会为每个子运行包含最慢作业表,因此发布经理无需下载日志即可看到当前关键路径。
|
||||
请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解完整阶段矩阵、精确的工作流作业名称、stable 与 full profile 的差异、工件以及聚焦重跑句柄。
|
||||
子工作流会从运行 `Full Release
|
||||
Validation` 的受信任 ref 调度,通常是 `--ref main`,即使目标 `ref` 指向较旧的发布分支或标签也是如此。没有单独的 Full Release Validation
|
||||
workflow-ref 输入;通过选择工作流运行 ref 来选择受信任 harness。
|
||||
不要使用 `--ref main -f ref=<sha>` 为移动中的 `main` 提供精确提交证明;
|
||||
原始提交 SHA 不能作为工作流调度 ref,因此请使用
|
||||
`pnpm ci:full-release --sha <sha>` 创建固定的临时分支。
|
||||
该工作流解析目标 ref,使用 `target_ref=<release-ref>` 分发手动 `CI`,分发 `OpenClaw Release Checks`,为面向软件包的检查准备父级 `release-package-under-test` 工件,并在 `release_profile=full` 且 `rerun_group=all`,或设置了 `npm_telegram_package_spec` 时,分发独立的软件包 Telegram E2E。随后,`OpenClaw Release Checks` 会扩展到安装冒烟测试、跨 OS 发布检查、启用 soak 时的 live/E2E Docker 发布路径覆盖、带 Telegram 软件包 QA 的 Package Acceptance、QA Lab parity、live Matrix 和 live Telegram。只有当 `Full Release Validation` 摘要显示 `normal_ci` 和 `release_checks` 均成功时,完整运行才可接受。在 full/all 模式下,`npm_telegram` 子项也必须成功;在 full/all 之外,除非提供了已发布的 `npm_telegram_package_spec`,否则会跳过它。最终验证器摘要包含每个子运行的最慢作业表,因此发布经理无需下载日志即可看到当前关键路径。
|
||||
请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解完整阶段矩阵、精确工作流作业名称、stable 与 full profile 的差异、工件以及聚焦重跑句柄。
|
||||
子工作流从运行 `Full Release Validation` 的可信 ref 分发,通常为 `--ref main`,即使目标 `ref` 指向较旧的发布分支或标签也是如此。没有单独的 Full Release Validation workflow-ref 输入;通过选择工作流运行 ref 来选择可信 harness。
|
||||
不要在移动的 `main` 上使用 `--ref main -f ref=<sha>` 做精确提交证明;原始提交 SHA 不能作为 workflow dispatch ref,因此请使用 `pnpm ci:full-release --sha <sha>` 创建固定的临时分支。
|
||||
|
||||
使用 `release_profile` 选择 live/provider 覆盖广度:
|
||||
使用 `release_profile` 选择 live/provider 覆盖范围:
|
||||
|
||||
- `minimum`:最快的发布关键 OpenAI/core live 和 Docker 路径
|
||||
- `stable`:minimum 加上用于发布批准的稳定 provider/backend 覆盖
|
||||
- `stable`:minimum 加上用于发布批准的 stable provider/backend 覆盖
|
||||
- `full`:stable 加上广泛的 advisory provider/media 覆盖
|
||||
|
||||
当发布阻塞 lane 为绿色,并且你希望在推广前执行详尽的 live/E2E、Docker 发布路径以及
|
||||
all-since-2026.4.23 upgrade-survivor 扫描时,请将 `run_release_soak=true` 与 `stable` 一起使用。`full` 隐含
|
||||
`run_release_soak=true`。
|
||||
当发布阻断 lane 均为绿色,并且你希望在推广前执行详尽的 live/E2E、Docker 发布路径以及有界的已发布升级幸存者 sweep 时,请将 `stable` 与 `run_release_soak=true` 一起使用。该 sweep 覆盖最新四个 stable 软件包,加上固定的 `2026.4.23` 和 `2026.5.2` 基线以及较旧的 `2026.4.15` 覆盖,会移除重复基线,并将每个基线分片到自己的 Docker runner 作业中。`full` 隐含 `run_release_soak=true`。
|
||||
|
||||
`OpenClaw Release Checks` 使用受信任 workflow ref 将目标
|
||||
ref 一次性解析为 `release-package-under-test`,并在 soak 运行时在 cross-OS、
|
||||
Package Acceptance 和 release-path Docker 检查中复用该工件。这样能让所有面向包的 box 使用相同字节,并避免重复构建包。
|
||||
当 repo/org 变量已设置时,cross-OS OpenAI 安装冒烟会使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用
|
||||
`openai/gpt-5.4`,因为此 lane 要证明的是包安装、新手引导、Gateway 网关启动以及一次 live agent 回合,而不是对最慢的默认模型进行基准测试。更广泛的 live provider
|
||||
矩阵仍然是执行模型特定覆盖的位置。
|
||||
`OpenClaw Release Checks` 使用可信工作流 ref 将目标 ref 解析一次为 `release-package-under-test`,并在运行 soak 时,在 cross-OS、Package Acceptance 和 release-path Docker 检查中复用该工件。这会让所有面向软件包的机器使用相同字节,并避免重复构建软件包。cross-OS OpenAI 安装冒烟测试在 repo/org 变量已设置时使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 `openai/gpt-5.4`,因为该 lane 证明的是软件包安装、新手引导、Gateway 网关启动以及一次 live agent 轮次,而不是对最慢默认模型做基准测试。更广泛的 live provider 矩阵仍然是模型特定覆盖的位置。
|
||||
|
||||
根据发布阶段使用这些变体:
|
||||
|
||||
@ -226,30 +197,22 @@ gh workflow run full-release-validation.yml \
|
||||
-f npm_telegram_provider_mode=mock-openai
|
||||
```
|
||||
|
||||
不要把完整 umbrella 用作聚焦修复后的第一次重跑。如果某个 box 失败,请使用失败的子工作流、作业、Docker lane、包 profile、模型提供商或 QA lane 作为下一次证明。只有当修复更改了共享发布编排,或让先前的 all-box 证据过期时,才再次运行完整 umbrella。umbrella 的最终验证器会重新检查已记录的子工作流运行 ID,因此在子工作流成功重跑后,只需重跑失败的
|
||||
`Verify full validation` 父作业。
|
||||
不要把完整总括工作流用作聚焦修复后的第一次重跑。如果一个 box 失败,请使用失败的子工作流、作业、Docker lane、软件包 profile、模型提供商或 QA lane 作为下一次证明。只有当修复更改了共享发布编排,或让先前的全 box 证据过期时,才再次运行完整总括工作流。总括工作流的最终验证器会重新检查已记录的子工作流运行 ID,因此在子工作流成功重跑后,只需重跑失败的 `Verify full validation` 父作业。
|
||||
|
||||
对于有界恢复,请将 `rerun_group` 传给 umbrella。`all` 是真正的发布候选运行,`ci` 只运行 normal CI 子项,`plugin-prerelease`
|
||||
只运行仅发布用插件子项,`release-checks` 运行每个发布
|
||||
box,更窄的发布组为 `install-smoke`、`cross-os`、
|
||||
`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 和 `npm-telegram`。
|
||||
聚焦 `npm-telegram` 重跑需要 `npm_telegram_package_spec`;带有 `release_profile=full` 的 full/all 运行会使用 release-checks 包工件。聚焦
|
||||
cross-OS 重跑可以添加 `cross_os_suite_filter=windows/packaged-upgrade` 或另一个 OS/suite 过滤器。QA release-check 失败属于 advisory;仅 QA 失败不会阻塞发布验证。
|
||||
对于有界恢复,请将 `rerun_group` 传给总括工作流。`all` 是真正的候选发布运行,`ci` 只运行普通 CI 子项,`plugin-prerelease` 只运行仅发布使用的插件子项,`release-checks` 运行每个发布 box,更窄的发布组包括 `install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 和 `npm-telegram`。聚焦 `npm-telegram` 重跑需要 `npm_telegram_package_spec`;带 `release_profile=full` 的 full/all 运行会使用 release-checks 软件包工件。聚焦 cross-OS 重跑可以添加 `cross_os_suite_filter=windows/packaged-upgrade` 或其他 OS/suite 过滤器。QA release-check 失败是 advisory;仅 QA 失败不会阻断发布验证。
|
||||
|
||||
### Vitest
|
||||
|
||||
Vitest box 是手动 `CI` 子工作流。手动 CI 会有意绕过 changed scoping,并为发布候选强制执行 normal 测试图:Linux Node 分片、内置插件分片、channel contracts、Node 22
|
||||
兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python
|
||||
Skills、Windows、macOS、Android 和 Control UI i18n。
|
||||
Vitest box 是手动 `CI` 子工作流。手动 CI 会有意绕过 changed scoping,并强制候选发布使用普通测试图:Linux Node 分片、内置插件分片、渠道合约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python Skills、Windows、macOS、Android 和 Control UI i18n。
|
||||
|
||||
使用此 box 回答“源代码树是否通过了完整 normal 测试套件?”它不同于 release-path 产品验证。需要保留的证据:
|
||||
使用此 box 回答“源代码树是否通过完整的普通测试套件?”它不同于 release-path 产品验证。需要保留的证据:
|
||||
|
||||
- 显示已调度 `CI` 运行 URL 的 `Full Release Validation` 摘要
|
||||
- 显示已分发 `CI` 运行 URL 的 `Full Release Validation` 摘要
|
||||
- 精确目标 SHA 上绿色的 `CI` 运行
|
||||
- 调查回归时来自 CI 作业的失败或慢速分片名称
|
||||
- 当运行需要性能分析时,保留 Vitest timing 工件,例如 `.artifacts/vitest-shard-timings.json`
|
||||
- 调查回归时来自 CI 作业的失败或较慢分片名称
|
||||
- 当运行需要性能分析时,保留 `.artifacts/vitest-shard-timings.json` 等 Vitest timing 工件
|
||||
|
||||
仅当发布需要确定性的 normal CI,而不需要 Docker、QA Lab、live、cross-OS 或 package box 时,才直接运行手动 CI:
|
||||
仅当发布需要确定性的普通 CI,但不需要 Docker、QA Lab、live、cross-OS 或 package box 时,才直接运行手动 CI:
|
||||
|
||||
```bash
|
||||
gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D
|
||||
@ -257,84 +220,58 @@ gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D
|
||||
|
||||
### Docker
|
||||
|
||||
Docker box 位于 `OpenClaw Release Checks` 中,通过
|
||||
`openclaw-live-and-e2e-checks-reusable.yml` 以及 release-mode
|
||||
`install-smoke` 工作流实现。它通过打包的 Docker 环境验证发布候选,而不只是源代码级测试。
|
||||
Docker box 位于 `OpenClaw Release Checks` 中,通过 `openclaw-live-and-e2e-checks-reusable.yml` 以及 release-mode 的 `install-smoke` 工作流运行。它通过打包的 Docker 环境验证候选发布,而不只是源代码级测试。
|
||||
|
||||
发布 Docker 覆盖包括:
|
||||
|
||||
- 启用慢速 Bun 全局安装冒烟的完整安装冒烟
|
||||
- 按目标 SHA 准备/复用根 Dockerfile 冒烟镜像,并将 QR、
|
||||
root/gateway 和 installer/Bun 冒烟作业作为独立 install-smoke
|
||||
分片运行
|
||||
- 仓库 E2E lanes
|
||||
- release-path Docker 分块:`core`、`package-update-openai`、
|
||||
`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、
|
||||
`plugins-runtime-services`、
|
||||
`plugins-runtime-install-a`、`plugins-runtime-install-b`、
|
||||
`plugins-runtime-install-c`、`plugins-runtime-install-d`、
|
||||
`plugins-runtime-install-e`、`plugins-runtime-install-f`、
|
||||
`plugins-runtime-install-g` 和 `plugins-runtime-install-h`
|
||||
- 请求时,`plugins-runtime-services` 分块中的 OpenWebUI 覆盖
|
||||
- 拆分的内置插件安装/卸载 lanes:
|
||||
`bundled-plugin-install-uninstall-0` 到
|
||||
`bundled-plugin-install-uninstall-23`
|
||||
- 当 release checks 包含 live suites 时,覆盖 live/E2E provider suites 和 Docker live 模型
|
||||
- 启用慢速 Bun 全局安装冒烟测试的完整安装冒烟测试
|
||||
- 按目标 SHA 准备/复用根 Dockerfile 冒烟镜像,其中 QR、root/gateway 和 installer/Bun 冒烟作业作为独立的 install-smoke 分片运行
|
||||
- 仓库 E2E lane
|
||||
- release-path Docker 分块:`core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`、`plugins-runtime-install-a`、`plugins-runtime-install-b`、`plugins-runtime-install-c`、`plugins-runtime-install-d`、`plugins-runtime-install-e`、`plugins-runtime-install-f`、`plugins-runtime-install-g` 和 `plugins-runtime-install-h`
|
||||
- 请求时,`plugins-runtime-services` 分块内的 OpenWebUI 覆盖
|
||||
- 拆分的内置插件安装/卸载 lane,从 `bundled-plugin-install-uninstall-0` 到 `bundled-plugin-install-uninstall-23`
|
||||
- 当 release checks 包含 live suite 时,包含 live/E2E provider suite 和 Docker live model 覆盖
|
||||
|
||||
重跑前先使用 Docker 工件。release-path 调度器会上传
|
||||
`.artifacts/docker-tests/`,其中包含 lane 日志、`summary.json`、`failures.json`、
|
||||
阶段耗时、调度器计划 JSON 和重跑命令。对于聚焦恢复,请在可复用 live/E2E 工作流上使用 `docker_lanes=<lane[,lane]>`,而不是重跑所有发布分块。生成的重跑命令会在可用时包含之前的
|
||||
`package_artifact_run_id` 和已准备的 Docker 镜像输入,因此失败 lane 可以复用相同的 tarball 和 GHCR 镜像。
|
||||
重跑前请先使用 Docker 工件。release-path 调度器会上传 `.artifacts/docker-tests/`,其中包含 lane 日志、`summary.json`、`failures.json`、阶段计时、scheduler plan JSON 和重跑命令。对于聚焦恢复,请在可复用 live/E2E 工作流上使用 `docker_lanes=<lane[,lane]>`,而不是重跑所有发布分块。生成的重跑命令会在可用时包含先前的 `package_artifact_run_id` 和已准备的 Docker 镜像输入,因此失败的 lane 可以复用相同 tarball 和 GHCR 镜像。
|
||||
|
||||
### QA Lab
|
||||
|
||||
QA Lab box 也是 `OpenClaw Release Checks` 的一部分。它是 agentic
|
||||
行为和 channel 级发布门禁,与 Vitest 和 Docker
|
||||
包机制分开。
|
||||
QA Lab box 也是 `OpenClaw Release Checks` 的一部分。它是智能体行为和渠道级发布门禁,与 Vitest 和 Docker 软件包机制分开。
|
||||
|
||||
发布 QA Lab 覆盖包括:
|
||||
|
||||
- 使用 agentic parity pack 将 OpenAI 候选 lane 与 Opus 4.6
|
||||
基线进行比较的 mock parity lane
|
||||
- mock parity lane,使用 agentic parity pack 将 OpenAI 候选 lane 与 Opus 4.6 基线比较
|
||||
- 使用 `qa-live-shared` 环境的快速 live Matrix QA profile
|
||||
- 使用 Convex CI 凭据租约的 live Telegram QA lane
|
||||
- 当发布遥测需要明确本地证明时运行 `pnpm qa:otel:smoke`
|
||||
- 使用 Convex CI 凭证租约的 live Telegram QA lane
|
||||
- 当发布遥测需要显式本地证明时运行 `pnpm qa:otel:smoke`
|
||||
|
||||
使用此 box 回答“发布在 QA 场景和 live channel flows 中行为是否正确?”批准发布时,请保留 parity、Matrix 和 Telegram
|
||||
lane 的工件 URL。完整 Matrix 覆盖仍可作为手动分片 QA-Lab 运行,而不是默认的发布关键 lane。
|
||||
使用此 box 回答“发布在 QA 场景和 live channel 流程中是否表现正确?”批准发布时,请保留 parity、Matrix 和 Telegram lane 的工件 URL。完整 Matrix 覆盖仍可作为手动分片 QA-Lab 运行使用,而不是默认发布关键 lane。
|
||||
|
||||
### 包
|
||||
### 软件包
|
||||
|
||||
Package box 是可安装产品门禁。它由
|
||||
`Package Acceptance` 和解析器
|
||||
`scripts/resolve-openclaw-package-candidate.mjs` 支撑。该解析器会将候选规范化为 Docker E2E 使用的 `package-under-test` tarball,验证包清单,记录包版本和 SHA-256,并让工作流 harness ref 与包源 ref 保持分离。
|
||||
Package box 是可安装产品门禁。它由 `Package Acceptance` 和解析器 `scripts/resolve-openclaw-package-candidate.mjs` 支撑。解析器会将候选项规范化为供 Docker E2E 使用的 `package-under-test` tarball,验证软件包清单,记录软件包版本和 SHA-256,并将工作流 harness ref 与软件包源 ref 分开。
|
||||
|
||||
支持的候选来源:
|
||||
|
||||
- `source=npm`:`openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本
|
||||
- `source=ref`:使用所选 `workflow_ref` harness 打包受信任的 `package_ref` 分支、标签或完整提交 SHA
|
||||
- `source=url`:下载需要 `package_sha256` 的 HTTPS `.tgz`
|
||||
- `source=artifact`:复用由另一个 GitHub Actions 运行上传的 `.tgz`
|
||||
- `source=ref`:使用选定的 `workflow_ref` harness 打包可信的 `package_ref` 分支、标签或完整提交 SHA
|
||||
- `source=url`:下载一个需要 `package_sha256` 的 HTTPS `.tgz`
|
||||
- `source=artifact`:复用另一个 GitHub Actions 运行上传的 `.tgz`
|
||||
|
||||
`OpenClaw Release Checks` 运行 Package Acceptance,并使用 `source=artifact`、已准备的发布包工件、`suite_profile=custom`、
|
||||
`docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`、
|
||||
`telegram_mode=mock-openai`。Package Acceptance 会让迁移、更新、过时插件依赖清理、离线插件 fixtures、插件更新和 Telegram
|
||||
包 QA 都针对同一个已解析 tarball 运行。阻塞发布检查使用默认的最新已发布包基线;`run_release_soak=true` 或
|
||||
`release_profile=full` 会扩展到从
|
||||
`2026.4.23` 到 `latest` 的每个稳定 npm 已发布基线,以及已报告问题的 fixtures。对已经发布的候选使用
|
||||
Package Acceptance 且 `source=npm`;对发布前由 SHA 支撑的本地 npm tarball 使用 `source=ref`/`source=artifact`。它是大多数此前需要
|
||||
Parallels 的 package/update 覆盖的 GitHub 原生替代方案。Cross-OS release checks 对 OS 特定新手引导、安装器和平台行为仍然重要,但 package/update 产品验证应优先使用 Package Acceptance。
|
||||
`OpenClaw Release Checks` 使用 `source=artifact`、已准备的发布软件包工件、`suite_profile=custom`、`docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`、`telegram_mode=mock-openai` 运行 Package Acceptance。Package Acceptance 会让迁移、更新、过期插件依赖清理、离线插件 fixture、插件更新和 Telegram 软件包 QA 都针对同一个已解析 tarball。阻断性 release checks 使用默认的最新已发布软件包基线;`run_release_soak=true` 或 `release_profile=full` 会扩展到从 `2026.4.23` 到 `latest` 的每个 stable npm 已发布基线,以及已报告问题的 fixture。对于已经发布的候选项,请使用带 `source=npm` 的 Package Acceptance;对于发布前有 SHA 支撑的本地 npm tarball,请使用 `source=ref`/`source=artifact`。它是 GitHub 原生替代方案,可替代过去大多数需要 Parallels 的 package/update 覆盖。cross-OS release checks 对 OS 特定的新手引导、安装器和平台行为仍然重要,但 package/update 产品验证应优先使用 Package Acceptance。
|
||||
|
||||
更新和插件验证的规范清单是
|
||||
[更新和插件测试](/zh-CN/help/testing-updates-plugins)。在决定哪个本地、Docker、Package Acceptance 或 release-check lane 能证明插件安装/更新、Doctor 清理或已发布包迁移变更时,请使用它。
|
||||
从每个稳定 `2026.4.23+` 包执行详尽的已发布更新迁移是一个单独的手动 `Update Migration` 工作流,不属于 Full Release CI。
|
||||
更新和插件验证的规范清单是[更新和插件测试](/zh-CN/help/testing-updates-plugins)。在决定哪个本地、Docker、Package Acceptance 或 release-check lane 可以证明插件安装/更新、Doctor 清理或已发布软件包迁移更改时,请使用它。从每个 stable `2026.4.23+` 软件包执行详尽的已发布更新迁移,是单独的手动 `Update Migration` 工作流,不属于 Full Release CI。
|
||||
|
||||
旧版 package-acceptance 宽松策略有意设置了时间限制。截至
|
||||
`2026.4.25` 的包可以对已发布到 npm 的元数据缺口使用兼容路径:tarball 中缺失的私有 QA 清单条目、缺失的
|
||||
`gateway install --wrapper`、tarball 派生 git fixture 中缺失的补丁文件、缺失的持久化 `update.channel`、旧版插件 install-record
|
||||
位置、缺失的 marketplace install-record 持久化,以及 `plugins update` 期间的配置元数据迁移。已发布的 `2026.4.26` 包可能会对已经发出的本地构建元数据戳文件发出警告。后续包必须满足现代包契约;这些相同缺口会导致发布验证失败。
|
||||
旧版包验收宽松规则被有意限定在一段时间内。直到
|
||||
`2026.4.25` 的包可以对已发布到 npm 的元数据缺口使用兼容路径:tarball 中缺失的私有 QA 库存条目、缺失的
|
||||
`gateway install --wrapper`、从 tarball 派生的 git
|
||||
fixture 中缺失的补丁文件、缺失的持久化 `update.channel`、旧版插件安装记录
|
||||
位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据
|
||||
迁移。已发布的 `2026.4.26` 包可能会针对已经发布的本地构建元数据标记文件发出
|
||||
警告。后续包必须满足现代包契约;这些相同缺口会导致发布
|
||||
验证失败。
|
||||
|
||||
当发布问题涉及实际可安装包时,请使用更广泛的 Package Acceptance profile:
|
||||
当发布问题涉及实际可安装包时,请使用更广的 Package Acceptance 配置档:
|
||||
|
||||
```bash
|
||||
gh workflow run package-acceptance.yml \
|
||||
@ -346,33 +283,33 @@ gh workflow run package-acceptance.yml \
|
||||
-f published_upgrade_survivor_baseline=openclaw@2026.4.26
|
||||
```
|
||||
|
||||
常见包配置档案:
|
||||
常用包配置档:
|
||||
|
||||
- `smoke`:快速包安装/渠道/智能体、Gateway 网关网络和配置
|
||||
- `smoke`:快速包安装/渠道/智能体、Gateway 网关网络,以及配置
|
||||
重载通道
|
||||
- `package`:不依赖实时 ClawHub 的安装/更新/插件包契约;这是发布检查的
|
||||
- `package`:安装/更新/插件包契约,不包含 live ClawHub;这是发布检查的
|
||||
默认值
|
||||
- `product`:`package` 加上 MCP 渠道、cron/子智能体清理、OpenAI Web
|
||||
搜索和 OpenWebUI
|
||||
- `full`:带 OpenWebUI 的 Docker 发布路径分块
|
||||
- `product`:`package` 加上 MCP 渠道、cron/subagent 清理、OpenAI web
|
||||
search,以及 OpenWebUI
|
||||
- `full`:包含 OpenWebUI 的 Docker 发布路径分块
|
||||
- `custom`:用于聚焦重跑的精确 `docker_lanes` 列表
|
||||
|
||||
如需包候选版本的 Telegram 证明,请在 Package Acceptance 上启用 `telegram_mode=mock-openai` 或
|
||||
`telegram_mode=live-frontier`。该 workflow 会把解析出的
|
||||
对于包候选版本的 Telegram 证明,请在 Package Acceptance 上启用 `telegram_mode=mock-openai` 或
|
||||
`telegram_mode=live-frontier`。该工作流会将解析后的
|
||||
`package-under-test` tarball 传入 Telegram 通道;独立的
|
||||
Telegram workflow 仍接受已发布的 npm 规格,用于发布后检查。
|
||||
Telegram 工作流仍然接受已发布的 npm spec,用于发布后检查。
|
||||
|
||||
## 发布发布自动化
|
||||
|
||||
`OpenClaw Release Publish` 是常规的变更型发布入口点。它会按发布所需顺序
|
||||
编排受信发布者 workflow:
|
||||
`OpenClaw Release Publish` 是常规的可变更发布入口点。它会按发布所需的顺序
|
||||
编排 trusted-publisher 工作流:
|
||||
|
||||
1. 检出发布标签并解析其提交 SHA。
|
||||
2. 验证该标签可从 `main` 或 `release/*` 到达。
|
||||
3. 运行 `pnpm plugins:sync:check`。
|
||||
4. 使用 `publish_scope=all-publishable` 和
|
||||
`ref=<release-sha>` 调度 `Plugin NPM Release`。
|
||||
5. 使用相同 scope 和 SHA 调度 `Plugin ClawHub Release`。
|
||||
5. 使用相同的 scope 和 SHA 调度 `Plugin ClawHub Release`。
|
||||
6. 使用发布标签、npm dist-tag 和
|
||||
已保存的 `preflight_run_id` 调度 `OpenClaw NPM Release`。
|
||||
|
||||
@ -406,89 +343,89 @@ gh workflow run openclaw-release-publish.yml \
|
||||
-f npm_dist_tag=latest
|
||||
```
|
||||
|
||||
仅在聚焦修复或重新发布工作中使用更底层的 `Plugin NPM Release` 和 `Plugin ClawHub Release` workflow。对于选定插件修复,将
|
||||
仅在聚焦修复或重新发布工作中使用较底层的 `Plugin NPM Release` 和 `Plugin ClawHub Release` 工作流。对于选定插件修复,请将
|
||||
`plugin_publish_scope=selected` 和 `plugins=@openclaw/name` 传给
|
||||
`OpenClaw Release Publish`;如果不得发布 OpenClaw 包,则直接调度子 workflow。
|
||||
`OpenClaw Release Publish`,或者当不得发布 OpenClaw 包时直接调度子工作流。
|
||||
|
||||
## NPM workflow 输入
|
||||
## NPM 工作流输入
|
||||
|
||||
`OpenClaw NPM Release` 接受以下由操作员控制的输入:
|
||||
`OpenClaw NPM Release` 接受这些由操作员控制的输入:
|
||||
|
||||
- `tag`:必填发布标签,例如 `v2026.4.2`、`v2026.4.2-1` 或
|
||||
`v2026.4.2-beta.1`;当 `preflight_only=true` 时,它也可以是当前
|
||||
完整 40 字符 workflow 分支提交 SHA,用于仅验证的预检
|
||||
- `tag`:必需的发布标签,例如 `v2026.4.2`、`v2026.4.2-1` 或
|
||||
`v2026.4.2-beta.1`;当 `preflight_only=true` 时,也可以是当前
|
||||
完整 40 字符工作流分支提交 SHA,用于仅验证预检
|
||||
- `preflight_only`:`true` 表示仅验证/构建/打包,`false` 表示
|
||||
真实发布路径
|
||||
- `preflight_run_id`:真实发布路径必填,用于让 workflow 复用
|
||||
- `preflight_run_id`:真实发布路径必需,这样工作流会复用
|
||||
成功预检运行中准备好的 tarball
|
||||
- `npm_dist_tag`:发布路径的 npm 目标标签;默认为 `beta`
|
||||
|
||||
`OpenClaw Release Publish` 接受以下由操作员控制的输入:
|
||||
`OpenClaw Release Publish` 接受这些由操作员控制的输入:
|
||||
|
||||
- `tag`:必填发布标签;必须已经存在
|
||||
- `preflight_run_id`:成功的 `OpenClaw NPM Release` 预检运行 ID;
|
||||
当 `publish_openclaw_npm=true` 时必填
|
||||
- `tag`:必需的发布标签;必须已经存在
|
||||
- `preflight_run_id`:成功的 `OpenClaw NPM Release` 预检运行 id;
|
||||
当 `publish_openclaw_npm=true` 时必需
|
||||
- `npm_dist_tag`:OpenClaw 包的 npm 目标标签
|
||||
- `plugin_publish_scope`:默认为 `all-publishable`;仅在聚焦修复工作中
|
||||
使用 `selected`
|
||||
- `plugins`:当 `plugin_publish_scope=selected` 时使用的逗号分隔
|
||||
`@openclaw/*` 包名
|
||||
- `publish_openclaw_npm`:默认为 `true`;仅当把该 workflow 用作
|
||||
仅插件修复编排器时设置为 `false`
|
||||
- `plugin_publish_scope`:默认为 `all-publishable`;仅在
|
||||
聚焦修复工作中使用 `selected`
|
||||
- `plugins`:当 `plugin_publish_scope=selected` 时,以逗号分隔的 `@openclaw/*` 包名
|
||||
- `publish_openclaw_npm`:默认为 `true`;仅在将该
|
||||
工作流用作仅插件修复编排器时设为 `false`
|
||||
|
||||
`OpenClaw Release Checks` 接受以下由操作员控制的输入:
|
||||
`OpenClaw Release Checks` 接受这些由操作员控制的输入:
|
||||
|
||||
- `ref`:要验证的分支、标签或完整提交 SHA。带有密钥的检查要求
|
||||
解析出的提交可从 OpenClaw 分支或发布标签到达。
|
||||
- `run_release_soak`:在稳定版/默认发布检查中选择加入穷尽式实时/E2E、Docker 发布路径和
|
||||
所有历史版本升级幸存 soak。它会被 `release_profile=full` 强制启用。
|
||||
- `ref`:要验证的分支、标签或完整提交 SHA。携带 secret 的检查
|
||||
要求解析出的提交可从 OpenClaw 分支或
|
||||
发布标签到达。
|
||||
- `run_release_soak`:在稳定版/默认发布检查中选择启用详尽的 live/E2E、Docker 发布路径,以及
|
||||
all-since upgrade-survivor soak。`release_profile=full` 会强制启用它。
|
||||
|
||||
规则:
|
||||
|
||||
- 稳定版和修正版标签可发布到 `beta` 或 `latest`
|
||||
- 稳定版和修正版标签可以发布到 `beta` 或 `latest`
|
||||
- Beta 预发布标签只能发布到 `beta`
|
||||
- 对于 `OpenClaw NPM Release`,仅当 `preflight_only=true` 时
|
||||
才允许完整提交 SHA 输入
|
||||
- 对于 `OpenClaw NPM Release`,仅当
|
||||
`preflight_only=true` 时才允许输入完整提交 SHA
|
||||
- `OpenClaw Release Checks` 和 `Full Release Validation` 始终
|
||||
仅用于验证
|
||||
- 真实发布路径必须使用预检期间使用的相同 `npm_dist_tag`;
|
||||
workflow 会在发布继续前验证该元数据
|
||||
仅执行验证
|
||||
- 真实发布路径必须使用与预检期间相同的 `npm_dist_tag`;
|
||||
工作流会在发布继续前验证该元数据
|
||||
|
||||
## 稳定版 npm 发布顺序
|
||||
|
||||
切稳定版 npm 发布时:
|
||||
当发布稳定版 npm 版本时:
|
||||
|
||||
1. 使用 `preflight_only=true` 运行 `OpenClaw NPM Release`
|
||||
- 在标签存在之前,你可以使用当前完整 workflow 分支提交
|
||||
SHA 对预检 workflow 做一次仅验证试运行
|
||||
2. 对常规先 beta 流程选择 `npm_dist_tag=beta`,或仅在你有意直接发布稳定版时
|
||||
选择 `latest`
|
||||
3. 当你希望用一个手动 workflow 获取常规 CI 加实时提示缓存、Docker、QA Lab、
|
||||
Matrix 和 Telegram 覆盖时,在发布分支、发布标签或完整
|
||||
- 在标签存在前,你可以使用当前完整的工作流分支提交
|
||||
SHA,对预检工作流执行仅验证 dry run
|
||||
2. 对于常规 beta-first 流程,选择 `npm_dist_tag=beta`;仅在
|
||||
你有意直接发布稳定版时才选择 `latest`
|
||||
3. 当你希望通过一个手动工作流获得常规 CI 加上 live prompt cache、Docker、QA Lab、
|
||||
Matrix 和 Telegram 覆盖时,请在发布分支、发布标签或完整
|
||||
提交 SHA 上运行 `Full Release Validation`
|
||||
4. 如果你确实只需要确定性的常规测试图,请改为在发布 ref 上运行
|
||||
手动 `CI` workflow
|
||||
4. 如果你有意只需要确定性的常规测试图,请改为在发布 ref 上运行
|
||||
手动 `CI` 工作流
|
||||
5. 保存成功的 `preflight_run_id`
|
||||
6. 使用相同的 `tag`、相同的 `npm_dist_tag`
|
||||
和已保存的 `preflight_run_id` 运行 `OpenClaw Release Publish`;它会先把外置插件发布到 npm
|
||||
和保存的 `preflight_run_id` 运行 `OpenClaw Release Publish`;它会先将外部化插件发布到 npm
|
||||
和 ClawHub,然后再提升 OpenClaw npm 包
|
||||
7. 如果发布落在 `beta`,请使用私有
|
||||
7. 如果发布落在 `beta`,请使用私有的
|
||||
`openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`
|
||||
workflow 将该稳定版本从 `beta` 提升到 `latest`
|
||||
8. 如果发布有意直接发布到 `latest`,且 `beta`
|
||||
应立即跟随同一稳定构建,请使用同一私有
|
||||
workflow 将两个 dist-tag 都指向该稳定版本,或让其定时
|
||||
工作流,将该稳定版本从 `beta` 提升到 `latest`
|
||||
8. 如果该发布有意直接发布到 `latest`,且 `beta`
|
||||
应立即跟随同一个稳定构建,请使用同一个私有
|
||||
工作流让两个 dist-tag 都指向该稳定版本,或让其定时
|
||||
自愈同步稍后移动 `beta`
|
||||
|
||||
dist-tag 变更位于私有仓库中是出于安全考虑,因为它仍然
|
||||
需要 `NPM_TOKEN`,而公共仓库保持仅 OIDC 发布。
|
||||
|
||||
这让直接发布路径和先 beta 后提升路径都保持
|
||||
有文档记录且对操作员可见。
|
||||
这样可以让直接发布路径和 beta-first 提升路径都
|
||||
有文档记录,并且对操作员可见。
|
||||
|
||||
如果维护者必须回退到本地 npm 身份验证,请仅在专用 tmux 会话中运行任何 1Password
|
||||
CLI (`op`) 命令。不要直接从主智能体 shell 调用 `op`;把它放在 tmux 内可以让提示、
|
||||
告警和 OTP 处理可观察,并防止重复的主机告警。
|
||||
如果维护者必须回退到本地 npm 身份验证,请只在专用 tmux 会话中运行任何 1Password
|
||||
CLI (`op`) 命令。不要直接从主智能体 shell 调用 `op`;将其保持在 tmux 内可以让提示、
|
||||
警报和 OTP 处理可观察,并防止重复的主机警报。
|
||||
|
||||
## 公共参考
|
||||
|
||||
|
||||
@ -1,59 +1,59 @@
|
||||
---
|
||||
read_when:
|
||||
- 运行或修复测试
|
||||
summary: 如何在本地运行测试(vitest),以及何时使用强制/覆盖率模式
|
||||
summary: 如何在本地运行测试(vitest),以及何时使用 force/coverage 模式
|
||||
title: 测试
|
||||
x-i18n:
|
||||
generated_at: "2026-05-04T20:59:42Z"
|
||||
generated_at: "2026-05-05T04:26:40Z"
|
||||
model: gpt-5.5
|
||||
provider: openai
|
||||
source_hash: 7e8421518d63cade24ce8c2a08fa10538b66d2332b1eb5744e47c6d5a5e84605
|
||||
source_hash: cc31ab27a63607ec5134306a0129bd164e4235f26631da4f691f657adda70eed
|
||||
source_path: reference/test.md
|
||||
workflow: 16
|
||||
---
|
||||
|
||||
- 完整测试工具包(套件、实时测试、Docker):[测试](/zh-CN/help/testing)
|
||||
- 完整测试工具包(测试套件、实时测试、Docker):[测试](/zh-CN/help/testing)
|
||||
- 更新和插件包验证:[更新和插件测试](/zh-CN/help/testing-updates-plugins)
|
||||
|
||||
- `pnpm test:force`:终止任何仍占用默认控制端口的残留 Gateway 网关进程,然后使用隔离的 Gateway 网关端口运行完整 Vitest 套件,避免服务器测试与正在运行的实例冲突。当前一次 Gateway 网关运行留下端口 18789 被占用时使用。
|
||||
- `pnpm test:coverage`:使用 V8 覆盖率运行单元套件(通过 `vitest.unit.config.ts`)。这是已加载文件的单元覆盖率门禁,不是整个仓库的全文件覆盖率。阈值为行/函数/语句 70%,分支 55%。因为 `coverage.all` 为 false,该门禁衡量单元覆盖率套件加载的文件,而不是把每个分片通道源文件都视为未覆盖。
|
||||
- `pnpm test:coverage:changed`:仅对自 `origin/main` 以来变更的文件运行单元覆盖率。
|
||||
- `pnpm test:changed`:低成本的智能变更测试运行。它会根据直接测试编辑、同级 `*.test.ts` 文件、显式源映射和本地导入图运行精确目标。广泛/config/package 变更会被跳过,除非它们映射到精确测试。
|
||||
- `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`:显式的广泛变更测试运行。当测试 harness/config/package 编辑应回退到 Vitest 更广泛的变更测试行为时使用。
|
||||
- `pnpm changed:lanes`:显示相对于 `origin/main` 的 diff 触发的架构通道。
|
||||
- `pnpm check:changed`:对相对于 `origin/main` 的 diff 运行智能变更检查门禁。它会为受影响的架构通道运行类型检查、lint 和守卫命令,但不会运行 Vitest 测试。使用 `pnpm test:changed` 或显式 `pnpm test <target>` 提供测试证明。
|
||||
- `pnpm test`:将显式文件/目录目标路由到有作用域的 Vitest 通道。无目标运行会使用固定分片组,并展开为叶级配置以进行本地并行执行;扩展组始终展开为每个扩展的分片配置,而不是一个巨大的根项目进程。
|
||||
- 测试 wrapper 运行会以简短的 `[test] passed|failed|skipped ... in ...` 摘要结束。Vitest 自己的时长行保留为每个分片的详细信息。
|
||||
- 共享 OpenClaw 测试状态:当测试需要隔离的 `HOME`、`OPENCLAW_STATE_DIR`、`OPENCLAW_CONFIG_PATH`、配置 fixture、工作区、智能体目录或 auth-profile 存储时,在 Vitest 中使用 `src/test-utils/openclaw-test-state.ts`。
|
||||
- 进程 E2E 辅助工具:当 Vitest 进程级 E2E 测试需要在一个位置管理正在运行的 Gateway 网关、CLI 环境、日志捕获和清理时,使用 `test/helpers/openclaw-test-instance.ts`。
|
||||
- Docker/Bash E2E 辅助工具:source `scripts/lib/docker-e2e-image.sh` 的通道可以将 `docker_e2e_test_state_shell_b64 <label> <scenario>` 传入容器,并用 `scripts/lib/openclaw-e2e-instance.sh` 解码;多 home 脚本可以传入 `docker_e2e_test_state_function_b64`,并在每个流程中调用 `openclaw_test_state_create <label> <scenario>`。较低层调用方可以使用 `scripts/lib/openclaw-test-state.mjs shell --label <name> --scenario <name>` 获取容器内 shell 片段,或使用 `node scripts/lib/openclaw-test-state.mjs -- create --label <name> --scenario <name> --env-file <path> --json` 生成可 source 的宿主环境文件。`create` 前面的 `--` 会阻止较新的 Node 运行时把 `--env-file` 视为 Node 标志。启动 Gateway 网关的 Docker/Bash 通道可以在容器内 source `scripts/lib/openclaw-e2e-instance.sh`,用于入口点解析、模拟 OpenAI 启动、Gateway 网关前台/后台启动、就绪探测、状态环境导出、日志转储和进程清理。
|
||||
- 完整、扩展和 include-pattern 分片运行会更新 `.artifacts/vitest-shard-timings.json` 中的本地计时数据;后续 whole-config 运行使用这些计时来平衡慢速和快速分片。Include-pattern CI 分片会把分片名称追加到计时键,这会让过滤后的分片计时保持可见,同时不替换 whole-config 计时数据。设置 `OPENCLAW_TEST_PROJECTS_TIMINGS=0` 可忽略本地计时 artifact。
|
||||
- 选定的 `plugin-sdk` 和 `commands` 测试文件现在会路由到专用轻量通道,这些通道只保留 `test/setup.ts`,而运行时较重的用例保留在现有通道中。
|
||||
- 带有同级测试的源文件会先映射到该同级测试,再回退到更宽的目录 glob。`src/channels/plugins/contracts/test-helpers`、`src/plugin-sdk/test-helpers` 和 `src/plugins/contracts` 下的辅助工具编辑会使用本地导入图运行导入它们的测试,而不是在依赖路径精确时广泛运行每个分片。
|
||||
- `auto-reply` 现在也拆分为三个专用配置(`core`、`top-level`、`reply`),这样回复 harness 不会压过较轻量的顶层 status/token/helper 测试。
|
||||
- 基础 Vitest 配置现在默认使用 `pool: "threads"` 和 `isolate: false`,并在仓库配置中启用共享的非隔离 runner。
|
||||
- `pnpm test:force`:终止任何占用默认控制端口的残留 Gateway 网关进程,然后使用隔离的 Gateway 网关端口运行完整 Vitest 套件,避免服务器测试与正在运行的实例冲突。当之前的 Gateway 网关运行导致端口 18789 被占用时使用此命令。
|
||||
- `pnpm test:coverage`:使用 V8 覆盖率(通过 `vitest.unit.config.ts`)运行单元套件。这是已加载文件的单元覆盖率门禁,不是整个仓库的全文件覆盖率。阈值为 70% 行/函数/语句,以及 55% 分支。由于 `coverage.all` 为 false,该门禁衡量由单元覆盖率套件加载的文件,而不是把每个拆分分支源文件都视为未覆盖。
|
||||
- `pnpm test:coverage:changed`:只对自 `origin/main` 以来变更的文件运行单元覆盖率。
|
||||
- `pnpm test:changed`:低成本的智能变更测试运行。它会从直接测试编辑、同级 `*.test.ts` 文件、显式源码映射和本地导入图中运行精确目标。宽泛的配置/包变更会被跳过,除非它们映射到精确测试。
|
||||
- `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`:显式的宽泛变更测试运行。当测试工具链/配置/包编辑应回退到 Vitest 更宽泛的变更测试行为时使用。
|
||||
- `pnpm changed:lanes`:显示相对于 `origin/main` 的 diff 触发的架构分支。
|
||||
- `pnpm check:changed`:对相对于 `origin/main` 的 diff 运行智能变更检查门禁。它会为受影响的架构分支运行类型检查、lint 和保护命令,但不会运行 Vitest 测试。测试证明请使用 `pnpm test:changed` 或显式的 `pnpm test <target>`。
|
||||
- `pnpm test`:将显式文件/目录目标路由到有作用域的 Vitest 分支。未指定目标的运行会使用固定分片组,并展开到叶子配置以进行本地并行执行;扩展组始终展开为按扩展划分的分片配置,而不是一个巨大的根项目进程。
|
||||
- 测试包装器运行结束时会显示一条简短的 `[test] passed|failed|skipped ... in ...` 摘要。Vitest 自身的耗时行保留为每个分片的详细信息。
|
||||
- 共享 OpenClaw 测试状态:当测试需要隔离的 `HOME`、`OPENCLAW_STATE_DIR`、`OPENCLAW_CONFIG_PATH`、配置夹具、工作区、智能体目录或认证资料存储时,请在 Vitest 中使用 `src/test-utils/openclaw-test-state.ts`。
|
||||
- 进程 E2E 辅助工具:当 Vitest 进程级 E2E 测试需要在一个地方获得正在运行的 Gateway 网关、CLI 环境、日志捕获和清理时,请使用 `test/helpers/openclaw-test-instance.ts`。
|
||||
- Docker/Bash E2E 辅助工具:引用 `scripts/lib/docker-e2e-image.sh` 的分支可以把 `docker_e2e_test_state_shell_b64 <label> <scenario>` 传入容器,并用 `scripts/lib/openclaw-e2e-instance.sh` 解码;多 home 脚本可以传入 `docker_e2e_test_state_function_b64`,并在每个流程中调用 `openclaw_test_state_create <label> <scenario>`。更底层的调用方可以使用 `scripts/lib/openclaw-test-state.mjs shell --label <name> --scenario <name>` 生成容器内 shell 片段,或使用 `node scripts/lib/openclaw-test-state.mjs -- create --label <name> --scenario <name> --env-file <path> --json` 生成可 source 的宿主环境文件。`create` 前的 `--` 会防止较新的 Node 运行时把 `--env-file` 视为 Node 标志。启动 Gateway 网关的 Docker/Bash 分支可以在容器内 source `scripts/lib/openclaw-e2e-instance.sh`,用于入口点解析、模拟 OpenAI 启动、Gateway 网关前台/后台启动、就绪探针、状态环境导出、日志转储和进程清理。
|
||||
- 完整、扩展和 include-pattern 分片运行会更新 `.artifacts/vitest-shard-timings.json` 中的本地计时数据;后续的整配置运行会使用这些计时来平衡慢速和快速分片。include-pattern CI 分片会把分片名称追加到计时键中,这样筛选后的分片计时仍然可见,而不会替换整配置计时数据。设置 `OPENCLAW_TEST_PROJECTS_TIMINGS=0` 可忽略本地计时制品。
|
||||
- 选定的 `plugin-sdk` 和 `commands` 测试文件现在会路由到专用轻量分支,这些分支只保留 `test/setup.ts`,让运行时较重的用例继续留在现有分支上。
|
||||
- 带有同级测试的源文件会先映射到该同级测试,然后再回退到更宽泛的目录 glob。`src/channels/plugins/contracts/test-helpers`、`src/plugin-sdk/test-helpers` 和 `src/plugins/contracts` 下的辅助工具编辑会使用本地导入图来运行导入它们的测试,而不是在依赖路径精确时宽泛运行每个分片。
|
||||
- `auto-reply` 现在还会拆分为三个专用配置(`core`、`top-level`、`reply`),这样 reply 测试工具链就不会压过更轻量的顶层状态/token/辅助工具测试。
|
||||
- 基础 Vitest 配置现在默认使用 `pool: "threads"` 和 `isolate: false`,并在整个仓库配置中启用共享的非隔离运行器。
|
||||
- `pnpm test:channels` 运行 `vitest.channels.config.ts`。
|
||||
- `pnpm test:extensions` 和 `pnpm test extensions` 运行所有扩展/插件分片。重型渠道插件、浏览器插件和 OpenAI 会作为专用分片运行;其他插件组保持批处理。使用 `pnpm test extensions/<id>` 运行一个内置插件通道。
|
||||
- `pnpm test:perf:imports`:启用 Vitest 导入时长 + 导入分解报告,同时仍然对显式文件/目录目标使用有作用域的通道路由。
|
||||
- `pnpm test:perf:imports:changed`:相同的导入 profiling,但仅针对自 `origin/main` 以来变更的文件。
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>`:基准测试同一已提交 git diff 下,路由后的 changed-mode 路径相对于原生根项目运行的表现。
|
||||
- `pnpm test:perf:changed:bench -- --worktree`:在无需先提交的情况下,对当前 worktree 变更集进行基准测试。
|
||||
- `pnpm test:extensions` 和 `pnpm test extensions` 运行所有扩展/插件分片。重型渠道插件、浏览器插件和 OpenAI 会作为专用分片运行;其他插件组保持批处理。对单个内置插件分支使用 `pnpm test extensions/<id>`。
|
||||
- `pnpm test:perf:imports`:启用 Vitest 导入时长和导入分解报告,同时仍然对显式文件/目录目标使用有作用域的分支路由。
|
||||
- `pnpm test:perf:imports:changed`:相同的导入分析,但只针对自 `origin/main` 以来变更的文件。
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>`:针对同一个已提交 git diff,对路由后的变更模式路径与原生根项目运行进行基准测试。
|
||||
- `pnpm test:perf:changed:bench -- --worktree`:无需先提交,即可对当前工作树变更集进行基准测试。
|
||||
- `pnpm test:perf:profile:main`:为 Vitest 主线程写入 CPU profile(`.artifacts/vitest-main-profile`)。
|
||||
- `pnpm test:perf:profile:runner`:为单元 runner 写入 CPU + heap profile(`.artifacts/vitest-runner-profile`)。
|
||||
- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`:串行运行每个 full-suite Vitest 叶级配置,并写入分组时长数据以及每个配置的 JSON/log artifact。Test Performance Agent 使用它作为尝试修复慢测试之前的基线。
|
||||
- `pnpm test:perf:profile:runner`:为单元运行器写入 CPU 和堆 profile(`.artifacts/vitest-runner-profile`)。
|
||||
- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`:串行运行每个完整套件 Vitest 叶子配置,并写入分组耗时数据以及每个配置的 JSON/日志制品。测试性能智能体在尝试修复慢测试之前会用它作为基线。
|
||||
- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`:在性能相关变更后比较分组报告。
|
||||
- Gateway 网关集成:通过 `OPENCLAW_TEST_INCLUDE_GATEWAY=1 pnpm test` 或 `pnpm test:gateway` 选择启用。
|
||||
- `pnpm test:e2e`:运行 Gateway 网关端到端 smoke 测试(多实例 WS/HTTP/node 配对)。默认使用 `threads` + `isolate: false`,并在 `vitest.e2e.config.ts` 中使用自适应 worker;用 `OPENCLAW_E2E_WORKERS=<n>` 调整,并设置 `OPENCLAW_E2E_VERBOSE=1` 输出详细日志。
|
||||
- `pnpm test:live`:运行提供商 live 测试(minimax/zai)。需要 API key 和 `LIVE=1`(或提供商特定的 `*_LIVE_TEST=1`)才能取消跳过。
|
||||
- `pnpm test:docker:all`:构建共享 live-test 镜像,将 OpenClaw 一次打包为 npm tarball,构建/复用一个裸 Node/Git runner 镜像,以及一个把该 tarball 安装到 `/app` 的功能镜像,然后通过加权调度器以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 Docker smoke 通道。裸镜像(`OPENCLAW_DOCKER_E2E_BARE_IMAGE`)用于 installer/update/plugin-dependency 通道;这些通道挂载预构建 tarball,而不是使用复制的仓库源。功能镜像(`OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`)用于普通 built-app 功能通道。`scripts/package-openclaw-for-docker.mjs` 是唯一的本地/CI package packer,并在 Docker 消费前验证 tarball 和 `dist/postinstall-inventory.json`。Docker 通道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;planner 逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 执行选定计划。`node scripts/test-docker-all.mjs --plan-json` 会输出调度器拥有的 CI 计划,包含选定通道、镜像类型、package/live-image 需求、状态场景和凭据检查,而不会构建或运行 Docker。`OPENCLAW_DOCKER_ALL_PARALLELISM=<n>` 控制进程槽位,默认值为 10;`OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>` 控制提供商敏感的 tail pool,默认值为 10。重型通道上限默认是 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;提供商上限默认通过 `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4` 设置为每个提供商一个重型通道。更大的宿主机可使用 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。如果某个通道在低并行度宿主机上超过有效权重或资源上限,它仍然可以从空池启动,并会独占运行直到释放容量。通道启动默认错开 2 秒,以避免本地 Docker daemon 创建风暴;可用 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>` 覆盖。runner 默认预检 Docker,清理陈旧的 OpenClaw E2E 容器,每 30 秒输出 active-lane 状态,在兼容通道之间共享提供商 CLI 工具缓存,默认对瞬态 live-provider 失败重试一次(`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=<n>`),并将通道计时存储在 `.artifacts/docker-tests/lane-timings.json` 中,以便后续运行按最长优先排序。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可打印通道清单而不运行 Docker,使用 `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>` 可调整状态输出,或使用 `OPENCLAW_DOCKER_ALL_TIMINGS=0` 禁用计时复用。使用 `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip` 仅运行确定性/本地通道,或使用 `OPENCLAW_DOCKER_ALL_LIVE_MODE=only` 仅运行 live-provider 通道;package 别名是 `pnpm test:docker:local:all` 和 `pnpm test:docker:live:all`。Live-only 模式会把 main 和 tail live 通道合并到一个最长优先池中,这样提供商 bucket 可以把 Claude、Codex 和 Gemini 工作打包在一起。除非设置 `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`,runner 会在第一次失败后停止调度新的 pooled 通道,并且每个通道都有一个 120 分钟的回退超时,可用 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;选定的 live/tail 通道使用更严格的每通道上限。CLI 后端 Docker 设置命令有自己的超时,通过 `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS` 控制(默认 180)。每通道日志、`summary.json`、`failures.json` 和阶段计时会写入 `.artifacts/docker-tests/<run-id>/` 下;使用 `pnpm test:docker:timings <summary.json>` 检查慢通道,使用 `pnpm test:docker:rerun <run-id|summary.json|failures.json>` 打印低成本的定向重跑命令。
|
||||
- `pnpm test:docker:browser-cdp-snapshot`:构建基于 Chromium 的 source E2E 容器,启动原始 CDP 加隔离的 Gateway 网关,运行 `browser doctor --deep`,并验证 CDP role 快照包含链接 URL、cursor-promoted clickables、iframe refs 和 frame metadata。
|
||||
- CLI 后端 live Docker 探测可以作为聚焦通道运行,例如 `pnpm test:docker:live-cli-backend:codex`、`pnpm test:docker:live-cli-backend:codex:resume` 或 `pnpm test:docker:live-cli-backend:codex:mcp`。Claude 和 Gemini 有匹配的 `:resume` 和 `:mcp` 别名。
|
||||
- `pnpm test:docker:openwebui`:启动 Docker 化的 OpenClaw + Open WebUI,通过 Open WebUI 登录,检查 `/api/models`,然后通过 `/api/chat/completions` 运行一次真实的代理聊天。需要可用的 live 模型 key(例如 `~/.profile` 中的 OpenAI),会拉取外部 Open WebUI 镜像,并且不预期像普通 unit/e2e 套件一样在 CI 中稳定。
|
||||
- `pnpm test:docker:mcp-channels`:启动一个已播种的 Gateway 网关容器和第二个客户端容器,后者会生成 `openclaw mcp serve`,然后验证路由后的对话发现、transcript 读取、附件 metadata、live event queue 行为、出站发送路由,以及通过真实 stdio bridge 发送的 Claude 风格 channel + permission notifications。Claude 通知断言会直接读取原始 stdio MCP 帧,因此该 smoke 反映 bridge 实际发出的内容。
|
||||
- `pnpm test:docker:upgrade-survivor`:将打包后的 OpenClaw tarball 安装到脏的旧用户 fixture 上,运行软件包更新和非交互式 Doctor,不使用实时提供商或渠道密钥,然后启动一个环回 Gateway 网关,并检查智能体、渠道配置、插件允许列表、工作区/会话文件、陈旧的旧版插件依赖状态、启动和 RPC 状态是否保留下来。
|
||||
- `pnpm test:docker:published-upgrade-survivor`:默认安装 `openclaw@latest`,填充不含实时提供商或渠道密钥的真实既有用户文件,使用内置的 `openclaw config set` 命令配方配置该基线,将该已发布安装更新到打包后的 OpenClaw tarball,运行非交互式 Doctor,写入 `.artifacts/upgrade-survivor/summary.json`,然后启动一个环回 Gateway 网关,并检查已配置的意图、工作区/会话文件、陈旧的插件配置和旧版依赖状态、启动、`/healthz`、`/readyz` 以及 RPC 状态是否保留下来或被干净修复。使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 覆盖一个基线,使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 展开精确矩阵,例如 `all-since-2026.4.23`,或使用 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues` 添加场景 fixture;reported-issues 集合包含 `configured-plugin-installs`,用于验证已配置的外部 OpenClaw 插件会在升级期间自动安装,还包含 `stale-source-plugin-shadow`,用于防止仅源码插件影子破坏启动。Package Acceptance 将这些暴露为 `published_upgrade_survivor_baseline`、`published_upgrade_survivor_baselines` 和 `published_upgrade_survivor_scenarios`。
|
||||
- `pnpm test:docker:update-migration`:在清理较重的 `plugin-deps-cleanup` 场景中运行已发布升级幸存者 harness,默认从 `openclaw@2026.4.23` 开始。单独的“更新迁移”工作流会用 `baselines=all-since-2026.4.23` 展开此 lane,使从 `.23` 起的每个稳定已发布软件包都更新到候选版本,并在完整发布 CI 之外证明已配置插件的依赖清理。
|
||||
- `pnpm test:docker:plugins`:针对本地路径、`file:`、带提升依赖的 npm registry 软件包、git 移动引用、ClawHub fixture、marketplace 更新,以及 Claude bundle 启用/检查运行安装/更新 smoke。
|
||||
- `pnpm test:e2e`:运行 Gateway 网关端到端冒烟测试(多实例 WS/HTTP/node 配对)。默认使用 `threads` + `isolate: false`,并在 `vitest.e2e.config.ts` 中使用自适应 worker;可用 `OPENCLAW_E2E_WORKERS=<n>` 调整,并设置 `OPENCLAW_E2E_VERBOSE=1` 启用详细日志。
|
||||
- `pnpm test:live`:运行提供商 live 测试(minimax/zai)。需要 API key,并且需要 `LIVE=1`(或提供商特定的 `*_LIVE_TEST=1`)才能取消跳过。
|
||||
- `pnpm test:docker:all`:构建共享 live-test 镜像,将 OpenClaw 打包一次为 npm tarball,构建/复用一个裸 Node/Git 运行器镜像以及一个把该 tarball 安装到 `/app` 的功能镜像,然后通过加权调度器使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 Docker 冒烟分支。裸镜像(`OPENCLAW_DOCKER_E2E_BARE_IMAGE`)用于安装器/更新/插件依赖分支;这些分支会挂载预构建 tarball,而不是使用复制的仓库源码。功能镜像(`OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`)用于普通的已构建应用功能分支。`scripts/package-openclaw-for-docker.mjs` 是单一本地/CI 包打包器,并会在 Docker 使用前验证 tarball 和 `dist/postinstall-inventory.json`。Docker 分支定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 执行所选计划。`node scripts/test-docker-all.mjs --plan-json` 会输出由调度器拥有的 CI 计划,包含所选分支、镜像类型、包/live 镜像需求、状态场景和凭据检查,而不会构建或运行 Docker。`OPENCLAW_DOCKER_ALL_PARALLELISM=<n>` 控制进程槽位,默认值为 10;`OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>` 控制对提供商敏感的尾部分支池,默认值为 10。重型分支上限默认是 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;提供商上限默认通过 `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`、`OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4` 和 `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4` 为每个提供商提供一个重型分支。更大的宿主机可使用 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。如果某个分支在低并行度宿主机上超过有效权重或资源上限,它仍然可以从空池启动,并会单独运行,直到释放容量。默认情况下,分支启动会错开 2 秒,以避免本地 Docker daemon 创建风暴;可用 `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>` 覆盖。运行器默认预检 Docker,清理陈旧的 OpenClaw E2E 容器,每 30 秒输出活动分支状态,在兼容分支之间共享提供商 CLI 工具缓存,默认对瞬时 live 提供商失败重试一次(`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=<n>`),并把分支计时存储在 `.artifacts/docker-tests/lane-timings.json`,供后续运行按最长优先排序。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可打印分支清单而不运行 Docker,使用 `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>` 可调整状态输出,或使用 `OPENCLAW_DOCKER_ALL_TIMINGS=0` 禁用计时复用。使用 `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip` 可只运行确定性/本地分支,或使用 `OPENCLAW_DOCKER_ALL_LIVE_MODE=only` 可只运行 live 提供商分支;包别名为 `pnpm test:docker:local:all` 和 `pnpm test:docker:live:all`。仅 live 模式会把主 live 分支和尾部 live 分支合并为一个最长优先池,这样提供商桶可以一起打包 Claude、Codex 和 Gemini 工作。除非设置 `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`,运行器会在首次失败后停止调度新的池化分支,并且每个分支都有一个 120 分钟的后备超时,可用 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` 覆盖;选定的 live/尾部分支使用更严格的每分支上限。CLI 后端 Docker 设置命令有自己的超时,通过 `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS` 控制(默认 180)。每个分支的日志、`summary.json`、`failures.json` 和阶段计时会写入 `.artifacts/docker-tests/<run-id>/` 下;使用 `pnpm test:docker:timings <summary.json>` 可检查慢分支,使用 `pnpm test:docker:rerun <run-id|summary.json|failures.json>` 可打印低成本的定向重跑命令。
|
||||
- `pnpm test:docker:browser-cdp-snapshot`:构建一个以 Chromium 为后端的源码 E2E 容器,启动原始 CDP 和一个隔离的 Gateway 网关,运行 `browser doctor --deep`,并验证 CDP 角色快照包含链接 URL、由光标提升的可点击项、iframe 引用和 frame 元数据。
|
||||
- CLI 后端 live Docker 探针可以作为聚焦分支运行,例如 `pnpm test:docker:live-cli-backend:codex`、`pnpm test:docker:live-cli-backend:codex:resume` 或 `pnpm test:docker:live-cli-backend:codex:mcp`。Claude 和 Gemini 有对应的 `:resume` 和 `:mcp` 别名。
|
||||
- `pnpm test:docker:openwebui`:启动 Docker 化的 OpenClaw + Open WebUI,通过 Open WebUI 登录,检查 `/api/models`,然后通过 `/api/chat/completions` 运行一次真实的代理聊天。需要可用的 live 模型 key(例如 `~/.profile` 中的 OpenAI),会拉取外部 Open WebUI 镜像,并且不预期像普通 unit/e2e 套件那样在 CI 中稳定。
|
||||
- `pnpm test:docker:mcp-channels`:启动一个已播种的 Gateway 网关容器和第二个客户端容器,后者会生成 `openclaw mcp serve`,然后验证路由后的对话设备发现、转录读取、附件元数据、live 事件队列行为、出站发送路由,以及通过真实 stdio bridge 传递的 Claude 风格渠道 + 权限通知。Claude 通知断言会直接读取原始 stdio MCP 帧,因此该冒烟测试反映 bridge 实际发出的内容。
|
||||
- `pnpm test:docker:upgrade-survivor`:在脏的旧用户 fixture 上安装打包后的 OpenClaw tarball,运行软件包更新以及不带实时提供商或渠道密钥的非交互式 Doctor,然后启动一个 loopback Gateway 网关,并检查智能体、渠道配置、插件 allowlist、工作区/会话文件、陈旧的旧版插件依赖状态、启动过程以及 RPC 状态是否能保留下来。
|
||||
- `pnpm test:docker:published-upgrade-survivor`:默认安装 `openclaw@latest`,在没有实时提供商或渠道密钥的情况下植入真实的现有用户文件,用内置的 `openclaw config set` 命令配方配置该基线,将该已发布安装更新到打包后的 OpenClaw tarball,运行非交互式 Doctor,写入 `.artifacts/upgrade-survivor/summary.json`,然后启动一个 loopback Gateway 网关,并检查已配置的 intent、工作区/会话文件、陈旧的插件配置和旧版依赖状态、启动过程、`/healthz`、`/readyz` 以及 RPC 状态是否能保留或被干净修复。可使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 覆盖一个基线,使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 扩展精确的本地矩阵,例如 `openclaw@2026.5.2 openclaw@2026.4.23 openclaw@2026.4.15`,或使用 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues` 添加场景 fixture;reported-issues 集包含 `configured-plugin-installs`,用于验证已配置的外部 OpenClaw 插件会在升级期间自动安装,以及 `stale-source-plugin-shadow`,用于避免仅源码插件 shadow 破坏启动。Package Acceptance 将这些暴露为 `published_upgrade_survivor_baseline`、`published_upgrade_survivor_baselines` 和 `published_upgrade_survivor_scenarios`,并会先解析 `last-stable-4` 或 `all-since-2026.4.23` 等元基线 token,再把精确的软件包 spec 交给 Docker lane。
|
||||
- `pnpm test:docker:update-migration`:在清理密集型 `plugin-deps-cleanup` 场景中运行已发布升级 survivor harness,默认从 `openclaw@2026.4.23` 开始。单独的 `Update Migration` workflow 会用 `baselines=all-since-2026.4.23` 扩展这个 lane,使 `.23` 及之后的每个稳定已发布软件包都更新到候选版本,并在 Full Release CI 之外证明已配置插件的依赖清理。
|
||||
- `pnpm test:docker:plugins`:针对本地路径、`file:`、带提升依赖的 npm registry 软件包、git 移动 ref、ClawHub fixture、marketplace 更新,以及 Claude bundle 的启用/检查,运行安装/更新 smoke。
|
||||
|
||||
## 本地 PR 门禁
|
||||
|
||||
@ -66,7 +66,7 @@ x-i18n:
|
||||
- `pnpm test`
|
||||
- `pnpm check:docs`
|
||||
|
||||
如果 `pnpm test` 在负载较高的主机上出现不稳定失败,请先重新运行一次,再将其视为回归问题,然后用 `pnpm test <path/to/test>` 隔离问题。对于内存受限的主机,使用:
|
||||
如果 `pnpm test` 在高负载主机上出现不稳定失败,先重新运行一次,再将其视为回归,然后用 `pnpm test <path/to/test>` 隔离问题。对于内存受限的主机,使用:
|
||||
|
||||
- `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`
|
||||
- `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-cache pnpm test:changed`
|
||||
@ -79,7 +79,7 @@ x-i18n:
|
||||
|
||||
- `source ~/.profile && pnpm tsx scripts/bench-model.ts --runs 10`
|
||||
- 可选环境变量:`MINIMAX_API_KEY`、`MINIMAX_BASE_URL`、`MINIMAX_MODEL`、`ANTHROPIC_API_KEY`
|
||||
- 默认提示词:“只回复一个单词:ok。不要标点或额外文本。”
|
||||
- 默认提示词:“只回复一个单词:好。不要标点或额外文本。”
|
||||
|
||||
上次运行(2025-12-31,20 次运行):
|
||||
|
||||
@ -114,15 +114,15 @@ x-i18n:
|
||||
- `real`:`health`、`status`、`status --json`、`sessions`、`sessions --json`、`tasks --json`、`tasks list --json`、`tasks audit --json`、`agents list --json`、`gateway status`、`gateway status --json`、`gateway health --json`、`config get gateway.port`
|
||||
- `all`:两个预设
|
||||
|
||||
输出包含每条命令的 `sampleCount`、平均值、p50、p95、最小值/最大值、退出码/信号分布,以及最大 RSS 摘要。可选的 `--cpu-prof-dir` / `--heap-prof-dir` 会为每次运行写入 V8 profile,因此计时和 profile 捕获会使用同一个 harness。
|
||||
输出包括每个命令的 `sampleCount`、平均值、p50、p95、最小/最大值、退出代码/信号分布,以及最大 RSS 摘要。可选的 `--cpu-prof-dir` / `--heap-prof-dir` 会为每次运行写入 V8 配置文件,因此计时和配置文件捕获使用同一个 harness。
|
||||
|
||||
保存输出约定:
|
||||
|
||||
- `pnpm test:startup:bench:smoke` 将目标 smoke artifact 写入 `.artifacts/cli-startup-bench-smoke.json`
|
||||
- `pnpm test:startup:bench:save` 使用 `runs=5` 和 `warmup=1` 将全套 artifact 写入 `.artifacts/cli-startup-bench-all.json`
|
||||
- `pnpm test:startup:bench:update` 使用 `runs=5` 和 `warmup=1` 刷新已签入的基线 fixture:`test/fixtures/cli-startup-bench.json`
|
||||
- `pnpm test:startup:bench:smoke` 会将目标烟雾测试产物写入 `.artifacts/cli-startup-bench-smoke.json`
|
||||
- `pnpm test:startup:bench:save` 会使用 `runs=5` 和 `warmup=1` 将完整套件产物写入 `.artifacts/cli-startup-bench-all.json`
|
||||
- `pnpm test:startup:bench:update` 会使用 `runs=5` 和 `warmup=1` 刷新签入的基线 fixture:`test/fixtures/cli-startup-bench.json`
|
||||
|
||||
已签入的 fixture:
|
||||
签入的 fixture:
|
||||
|
||||
- `test/fixtures/cli-startup-bench.json`
|
||||
- 使用 `pnpm test:startup:bench:update` 刷新
|
||||
@ -130,19 +130,19 @@ x-i18n:
|
||||
|
||||
## 新手引导 E2E(Docker)
|
||||
|
||||
Docker 是可选的;只有容器化的新手引导 smoke 测试才需要它。
|
||||
Docker 是可选的;仅容器化新手引导烟雾测试需要它。
|
||||
|
||||
在干净的 Linux 容器中执行完整冷启动流程:
|
||||
在干净的 Linux 容器中运行完整冷启动流程:
|
||||
|
||||
```bash
|
||||
scripts/e2e/onboard-docker.sh
|
||||
```
|
||||
|
||||
该脚本通过伪 tty 驱动交互式向导,验证配置/工作区/会话文件,然后启动 Gateway 网关并运行 `openclaw health`。
|
||||
此脚本通过伪 tty 驱动交互式向导,验证配置/工作区/会话文件,然后启动 Gateway 网关并运行 `openclaw health`。
|
||||
|
||||
## QR 导入 smoke(Docker)
|
||||
## QR 导入烟雾测试(Docker)
|
||||
|
||||
确保维护的 QR 运行时 helper 可以在受支持的 Docker Node 运行时中加载(Node 24 默认,Node 22 兼容):
|
||||
确保维护的 QR 运行时辅助程序可在受支持的 Docker Node 运行时下加载(Node 24 默认,Node 22 兼容):
|
||||
|
||||
```bash
|
||||
pnpm test:docker:qr
|
||||
|
||||
Loading…
Reference in New Issue
Block a user