面向 OpenClaw.NET 用户与贡献者的
compat/public-smoke.json完整技术指南。
概述
compat/public-smoke.json 是 OpenClaw.NET 兼容性验证体系的核心清单文件。它承担着以下关键职责:
- 集中管理所有已知公开插件(NPM Plugin)和技能(ClawHub Skill)的预期行为;
- 作为自动化烟雾测试(Public Smoke Tests) 的唯一数据源;
- 通过 CLI 命令 与 REST API 暴露给运维与集成方查询;
- 在构建期作为嵌入资源 (Embedded Resource)编译进
OpenClaw.Core程序集,对 NativeAOT 完全友好,运行时无需访问文件系统。
无论是发布前的回归验证、外部集成方的兼容性自查,还是社区贡献者新增插件,都以该清单为唯一事实来源(Single Source of Truth)。
文件结构
清单顶层是一个带版本号的 JSON 对象,entries 字段为条目数组:
json
{
"version": 2,
"entries": [
{
"id": "agentseo-plugin",
"category": "ts-jiti-plugin",
"kind": "npm-plugin",
"spec": "@agentseo/openclaw-plugin@0.1.4",
"packageName": "@agentseo/openclaw-plugin",
"pluginId": "agentseo",
"expectedStatus": "compatible",
"configJson": "{\"apiKey\":\"test_key\"}",
"expectedToolNames": ["agentseo_audit", "agentseo_keywords"],
"expectedSkillNames": ["agentseo"]
}
]
}
条目字段说明
字段按用途分为三组:通用字段 、技能专用字段 、插件专用字段。
通用字段(所有条目必填)
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 场景唯一标识,须在 entries 中保持唯一 |
category |
string | 场景分类:pure-skill、js-tool-plugin、ts-jiti-plugin、config-schema-plugin、unsupported-surface-plugin |
kind |
string | 资源类型:clawhub-skill 或 npm-plugin |
技能专用字段(kind == "clawhub-skill")
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
slug |
string | ✅ | ClawHub 中的技能标识符 |
version |
string | ✅ | 技能的 SemVer 版本 |
expectedRelativePath |
string | ✅ | 安装后的预期相对路径,如 skills/my-skill/SKILL.md |
插件专用字段(kind == "npm-plugin")
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
spec |
string | ✅ | NPM 包规范,如 @agentseo/openclaw-plugin@0.1.4 |
packageName |
string | ✅ | NPM 包名 |
pluginId |
string | ✅ | 插件唯一标识 |
expectedStatus |
string | ✅ | 预期兼容性状态:compatible 或 incompatible |
configJson |
string | ⭕️ | JSON 字符串形式的示例配置 |
installExtraPackages |
string[] | ⭕️ | 需要额外安装的依赖包列表 |
expectedToolNames |
string[] | ⭕️ | 预期暴露的工具名称(仅 compatible 场景) |
expectedSkillNames |
string[] | ⭕️ | 预期提供的技能名称(仅 compatible 场景) |
expectedDiagnosticCodes |
string[] | ⭕️ | 预期的诊断错误码(仅 incompatible 场景) |
⚠️ 注意 :NPM 插件条目必须 显式指定
expectedStatus,编译期校验会拒绝缺失该字段的条目。
场景分类详解
OpenClaw.NET 共定义了 5 种 category,覆盖了从纯技能到负面用例的全部典型场景:
| Category | 说明 | 测试目的 | 典型示例 |
|---|---|---|---|
pure-skill |
独立技能包,无 NPM 依赖 | 验证 SKILL.md 格式与 ClawHub 安装流程 | pdf-form-filler |
js-tool-plugin |
JavaScript 编写的桥接插件 | 验证 JS 插件加载与工具导出 | @example/js-plugin |
ts-jiti-plugin |
TypeScript + JITI 转译的插件 | 验证 TypeScript 转译与 JITI 集成 | @agentseo/openclaw-plugin |
config-schema-plugin |
配置校验负面场景 | 验证无效配置被检测并返回诊断码 | 缺失必填字段 / 字段类型错误 |
unsupported-surface-plugin |
不支持功能的负面场景 | 验证不支持的 API 被显式拒绝 | 注册 CLI 命令 / 调用受限 API |
正面与负面场景
正面场景(expectedStatus = "compatible")
- 验证插件/技能能够成功加载;
- 验证声明的工具和技能均正确暴露到 Gateway;
- 使用
expectedToolNames与expectedSkillNames进行断言; - 任何缺失或多余的工具/技能均判定为失败。
负面场景(expectedStatus = "incompatible")
- 验证错误能被系统显式检测并拒绝,而非"部分加载"或静默忽略;
- 使用
expectedDiagnosticCodes断言错误码; - 典型诊断码:
| 诊断码 | 含义 |
|---|---|
config_one_of_mismatch |
配置不满足 oneOf 约束 |
unsupported_cli_registration |
插件尝试注册不支持的 CLI 命令 |
unsupported_surface_call |
调用了未公开/受限的 API 表面 |
schema_required_missing |
必填字段缺失 |
使用方式
CLI 查询
OpenClaw CLI 提供 compatibility catalog 子命令,便于本地查询与脚本消费:
bash
# 查看所有条目
openclaw compatibility catalog
# 按状态过滤
openclaw compatibility catalog --status compatible
openclaw compatibility catalog --status incompatible
# 按类型与分类过滤
openclaw compatibility catalog --kind npm-plugin --category ts-jiti-plugin
# JSON 格式输出(适用于程序化消费)
openclaw compatibility catalog --json
# 简写形式
openclaw compat catalog
REST API
Gateway 通过 /api/integration/compatibility 路由族对外暴露:
http
GET /api/integration/compatibility/catalog
GET /api/integration/compatibility/catalog?compatibilityStatus=compatible
GET /api/integration/compatibility/catalog?kind=npm-plugin&category=ts-jiti-plugin
GET /api/integration/compatibility/export
/catalog端点支持compatibilityStatus、kind、category三个查询参数过滤;/export端点返回完整的兼容性报告,包含运行时模式(AOT / JIT)、安全态势(Security Posture)、通道就绪状态(Channel Readiness)等额外维度,适合在 CI 中归档或对接外部门户。
自动化测试
测试类 PublicCompatibilitySmokeTests 在运行时自动读取清单并迭代执行:
- 触发开关 :环境变量
OPENCLAW_PUBLIC_SMOKE=1必须设置,否则测试整体跳过; - ClawHub 技能 :通过
npx clawhub安装并校验expectedRelativePath文件存在; compatible插件 :执行安装、加载、然后断言expectedToolNames/expectedSkillNames完整暴露;incompatible插件 :执行安装、加载,断言加载失败且诊断码集合至少包含expectedDiagnosticCodes中的全部条目。
CI/CD 集成
在 GitHub Actions 中,public-compatibility-smoke 作业承担清单的回归验证:
- 触发条件 :定时执行(
schedule)或手动派发(workflow_dispatch); - 依赖环境 :Node.js 20(用于
npm与clawhub命令链路); - 执行流程 :
dotnet test+--filter Category=PublicSmoke; - 报告产物:生成 TRX 格式测试报告并作为 artifact 上传;
- 失败语义:任意条目断言失败即视为整个作业失败,需在合并前修复。
如何贡献新条目
添加新技能
json
{
"id": "my-new-skill",
"category": "pure-skill",
"kind": "clawhub-skill",
"slug": "my-new-skill",
"version": "1.0.0",
"expectedRelativePath": "skills/my-new-skill/SKILL.md"
}
添加兼容插件(正面场景)
json
{
"id": "my-plugin",
"category": "js-tool-plugin",
"kind": "npm-plugin",
"spec": "@my-org/openclaw-plugin@1.0.0",
"packageName": "@my-org/openclaw-plugin",
"pluginId": "my-plugin",
"expectedStatus": "compatible",
"configJson": "{\"apiKey\":\"test_key\"}",
"expectedToolNames": ["my_tool_1", "my_tool_2"],
"expectedSkillNames": ["my-skill"]
}
添加不兼容场景(负面场景)
json
{
"id": "broken-plugin-example",
"category": "config-schema-plugin",
"kind": "npm-plugin",
"spec": "@my-org/broken-plugin@1.0.0",
"packageName": "@my-org/broken-plugin",
"pluginId": "broken-plugin",
"expectedStatus": "incompatible",
"configJson": "{\"wrongField\": 123}",
"expectedDiagnosticCodes": ["config_one_of_mismatch"]
}
贡献流程
-
在
compat/public-smoke.json的entries数组末尾追加条目; -
确保必填字段完整:
- NPM 插件 :必须包含
expectedStatus、spec、packageName、pluginId; - 技能 :必须包含
slug、version、expectedRelativePath;
- NPM 插件 :必须包含
-
本地设置
OPENCLAW_PUBLIC_SMOKE=1并执行:bashdotnet test OpenClaw.Net.slnx --filter Category=PublicSmoke -
如引入了新的
category或kind,需同步:- 升级清单顶层
version字段; - 更新
PublicCompatibilityCatalog中的枚举与转换逻辑; - 更新本文档的场景分类详解表格。
- 升级清单顶层
数据转换逻辑
清单在运行时通过 PublicCompatibilityCatalog.CreateCatalog() 转换为富目录(Rich Catalog),以便 CLI 与 REST API 直接消费。核心映射规则如下:
| 源字段 | 生成字段 | 转换逻辑 |
|---|---|---|
slug / packageName / pluginId / id |
Subject |
按优先级取第一个非空值 |
kind + spec / slug |
InstallCommand |
技能:openclaw clawhub install {slug} 插件:openclaw plugins install {spec} --dry-run |
category + expectedStatus |
Summary |
根据场景性质生成人类可读描述 |
expectedStatus |
ScenarioType |
compatible → "positive" incompatible → "negative" |
| 多字段组合 | Guidance[] |
上下文相关的操作建议(如"配置 schema 错误,请参考插件文档") |
与 NativeAOT 的关系
OpenClaw.NET 的 NativeAOT 约束直接影响清单的加载与序列化方式:
- 嵌入资源 :
compat/public-smoke.json在.csproj中以<EmbeddedResource>方式编译进OpenClaw.Core.dll,运行时无任何文件 I/O; - JSON 源生成 :使用
CoreJsonContext(基于JsonSerializerContext的 source generator)反序列化清单,完全规避反射; - 桥接协议 :插件通过
plugin-bridge.mjs走 JSON-RPC over stdio,避免在主进程中动态加载托管程序集; - AOT/JIT 一致性:清单驱动的烟雾测试同时覆盖 AOT 与 JIT 两种发布模式,确保行为一致。
故障排查
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 测试报告 "plugin failed to load" | configJson 格式错误或字段类型不匹配 |
检查 JSON 是否符合插件实际 schema,使用 --dry-run 先行验证 |
| "expected tool not found" | 插件未声明该工具或工具名拼写错误 | 校对 expectedToolNames 与插件运行时实际暴露的工具名 |
| 编译期错误 "npm-plugin must declare expectedStatus" | 新条目缺少 expectedStatus 字段 |
明确指定 "compatible" 或 "incompatible" |
| 烟雾测试整体未运行 | 环境变量未设置 | 设置 OPENCLAW_PUBLIC_SMOKE=1 后重试 |
clawhub 安装失败 |
Node.js 未安装或版本过低 | 安装 Node.js 20+ 并确保 npx 可用 |
expectedDiagnosticCodes 不匹配 |
错误码命名变更或新增 | 查阅最新诊断码列表,必要时同步更新清单 |
| AOT 模式启动报缺少元数据 | 新增字段未在 CoreJsonContext 中声明 |
在源生成上下文中添加对应类型 |