Harness Engineering 指南
本文档描述了 zhin.js 项目的 harness engineering 实践,包括自动化检查、架构约束和代码质量标准。
概述
Harness engineering 是通过自动化工具和检查来强制执行项目架构、代码质量和开发规范的实践。在 zhin.js 中,我们使用以下工具:
- ESLint — 代码风格和质量检查
- TypeScript — 类型安全检查
- 自定义脚本 — 架构约束和规范检查
- CI/CD — 持续集成中的自动化检查
快速开始
运行所有检查
bash
pnpm check:all运行单个检查
bash
pnpm check:harness-paths # 检查发送链路绕过
pnpm check:no-koa # 检查 koa 导入
pnpm check:prod # 检查生产配置
pnpm check:plugin # 检查插件规范
pnpm check:architecture # 检查架构层级
pnpm check:doc-links # 检查文档相对链接(AGENTS、architecture 等)
pnpm check:adapter-docs # 适配器 README 与 docs/adapters 是否同步
pnpm sync:adapter-docs # 从 plugins/adapters/*/README 生成 docs/adapters/*
pnpm check:stable # Stable smoke(Sandbox + minimal-bot 契约,无 LLM)代码质量检查
bash
pnpm lint # ESLint 检查
pnpm type-check # TypeScript 类型检查架构层级规则
依赖层级(从低到高)
1. basic/ (logger, schema, database, cli)
↓
2. packages/im/kernel (无 IM 概念)
↓
3. packages/im/ai (providers, agents, memory)
↓
4. packages/im/core (Plugin, Adapter, Bot, Command)
↓
5. packages/im/agent (ZhinAgent, security policies)
↓
6. packages/im/zhin (主入口)允许的导入关系
| 层级 | 可以导入 |
|---|---|
| basic/ | 无(基础层) |
| packages/im/kernel | basic/ |
| packages/im/ai | basic/, packages/im/kernel |
| packages/im/core | basic/, packages/im/kernel, packages/im/ai |
| packages/im/agent | basic/, packages/im/kernel, packages/im/ai, packages/im/core |
| packages/im/zhin | 所有 IM 层级 + 按需 re-export |
禁止的导入
- ❌
packages/im/kernel不能导入packages/im/core或更高层 - ❌
packages/im/ai不能导入packages/im/core或更高层 - ❌
packages/im/core不能导入packages/im/agent - ❌ 插件不能直接导入
packages/im/kernel(应通过@zhin.js/core/zhin.js)
发送链路保护
标准发送链路
所有消息发送必须通过以下链路:
Message.$reply / Adapter.sendMessage
↓
renderSendMessage
↓
root plugin before.sendMessage
↓
platform Bot.$sendMessage禁止的绕过方式
typescript
// ❌ 错误:直接调用 bot.$sendMessage()
bot.$sendMessage(target, message);
// ✓ 正确:使用 adapter.sendMessage()
await adapter.sendMessage({
target,
content: message,
});
// ✓ 正确:使用 message.$reply()
await message.$reply(message);检查范围
packages/im/zhin/srcpackages/im/agent/srcplugins/featurespackages/hostplugins/utilsplugins/games
插件规范
必需文件
每个插件必须包含:
plugin-name/
├── package.json # 包配置
├── README.md # 使用说明
├── src/
│ └── index.ts # 入口文件
└── tests/
└── index.test.ts # 测试文件package.json 要求
json
{
"name": "@zhin.js/plugin-name",
"main": "./lib/index.js",
"exports": {
".": {
"development": "./src/index.ts",
"default": "./lib/index.js"
}
}
}测试要求
- 至少一个测试文件在
tests/目录 - 测试文件必须以
.test.ts结尾 - 建议覆盖率 > 70%
代码质量标准
ESLint 配置
项目使用 ESLint flat config 格式(eslint.config.mjs):
javascript
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
},
);TypeScript 规范
- 严格模式(
strict: true) - 禁止使用
any类型(警告) - 必须处理未使用的变量(错误)
- 导入路径必须使用
.js扩展名
AsyncLocalStorage 使用
typescript
// ✓ 正确:在模块顶层调用
const plugin = usePlugin();
// ❌ 错误:在异步函数中调用
async function setup() {
const plugin = usePlugin(); // 会导致错误
}CI/CD 集成
GitHub Actions 工作流
CI 工作流在 PR 到 main 分支时自动运行:
- 安装依赖 —
pnpm install - 检查 changeset —
pnpm changeset status - 构建包 —
pnpm build - 运行 harness 检查 — 所有
check:*命令 - 运行测试 —
pnpm test:reporter - 生成覆盖率 —
pnpm test:coverage
检查失败处理
如果任何 harness 检查失败:
- CI 会显示详细的错误信息
- PR 会被标记为失败
- 必须修复问题后才能合并
例外处理
何时可以例外
在极少数情况下,可能需要绕过某些检查:
- 第三方库限制 — 某些库可能需要特定的导入方式
- 性能优化 — 某些优化可能需要绕过常规规则
- 兼容性需求 — 旧代码可能需要渐进式改进
如何添加例外
代码中添加注释
typescript// harness-disable-next-line check:harness-paths bot.$sendMessage(target, message);在 PR 描述中说明理由
markdown## 例外说明 绕过 `check:harness-paths` 检查的原因: - 需要直接调用底层 API 进行性能优化 - 已获得维护者批准获得维护者审批
- 至少一位维护者必须批准例外
- 例外应该有明确的过期时间或条件
最佳实践
开发流程
- 本地开发 — 运行
pnpm check:all确保所有检查通过 - 提交前 — 运行
pnpm lint和pnpm type-check - PR 提交 — CI 会自动运行所有检查
- 代码审查 — 审查者会检查 harness 检查结果
常见问题解决
1. 架构层级违规
错误信息:
Layer "packages/im/kernel" cannot import from "packages/im/core"解决方案:
- 将共享代码移动到更低层级
- 使用依赖注入或接口抽象
- 重新设计模块边界
2. 发送链路绕过
错误信息:
direct bot.$sendMessage() bypasses Adapter.sendMessage / before.sendMessage chain解决方案:
- 使用
adapter.sendMessage()或message.$reply() - 如果确实需要直接调用,添加例外注释
3. 插件规范不达标
错误信息:
Missing package.json
No test files found解决方案:
- 创建必需的文件和目录
- 参考现有插件的结构
工具扩展
添加新的检查
- 创建检查脚本 —
scripts/check-新检查名.mjs - 更新 package.json — 添加
check:新检查名命令 - 更新 CI — 在
.github/workflows/ci.yml中添加步骤 - 更新文档 — 在本文档中添加说明
检查脚本模板
javascript
#!/usr/bin/env node
/**
* Harness: 检查描述
*/
import * as fs from 'node:fs';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, '..');
const violations = [];
// 检查逻辑...
if (violations.length) {
console.error('Harness check: FAILED\n');
for (const v of violations) {
console.error(` ${v.file}:${v.line}: ${v.issue}`);
}
process.exit(1);
}
console.log('Harness check: OK');参考资料
获取帮助
如果遇到 harness 检查问题:
- 查看本文档的常见问题部分
- 搜索 GitHub Issues
- 在 Discussions 中提问
- 联系维护者