Add HeXi bot codebase: custom plugins, web frontends, tests

- hexi core: message handling, rate limiting, cooldown, plugin manager
- Custom plugins: BF stats, daily check-in, quotes, persona cards, etc.
- Community plugins vendored under hexi/plugins with local fixes
- Web admin frontends (learning-chat, persona-admin), unified hexi/web
- Tests for rate_limit/cooldown/memes/persona; poetry.lock

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-01 13:13:40 +08:00
co-authored by Claude
parent 1783c60afa
commit b61d09f09f
3201 changed files with 160436 additions and 171 deletions
@@ -0,0 +1,42 @@
# 插件模板(MTSS 结构)
按《插件结构标准 + 插件配置文件标准》编写的可复制插件骨架,含配置标准 + Web 子应用样例。
## 结构(MTSS)
```text
nonebot_plugin_template/
├── __init__.py # 入口(薄): require + meta + 导入 + config.register_config() + register_web_plugin
├── config.py # 配置注册(register_model_config / register_config_items / register_object_set)
├── handlers/ # Trigger 层
│ ├── __init__.py
│ └── entry.py # on_command 示例
├── services/ # Service 层(不 import nonebot)
│ └── main.py
├── models.py # 模型/异常
├── repository.py # Model 数据访问(唯一读写入口)
├── web/ # 可选: 插件自带 Web 子应用(FastAPI)
│ ├── __init__.py
│ └── admin.py # build_admin_app() → 挂载到 /api/template
├── data/ # 运行时数据
└── utils/ # 纯工具
```
## 使用
1. 把 `nonebot_plugin_template` 目录复制到 `hexi/plugins/nonebot_plugin_<name>`。
2. 全局搜索替换 `nonebot_plugin_template` → `nonebot_plugin_<name>`,包括 `_PLUGIN_ID` 相关说明。
3. 在 `__init__.py` 改 `__plugin_meta__` 的 name/description/usage,并把 `register_web_plugin("template", ...)` 的 id/name/icon 改掉;Web id 只能使用安全的短标识,不要直接使用带点的模块名。
4. 在 `config.py` 改成你要的配置项;在 `handlers/entry.py` 改成你的命令/触发。
5. 重启 bot;/hub 插件页能看到配置,点「打开 Web 页面」进入 `/hub/template`(子应用挂在 `/api/template`)。
## Web 子应用
- `web/admin.py::build_admin_app()` 返回一个 FastAPI 实例,经 `register_web_plugin` 由 hub 挂载到 `/api/template`。
- 鉴权统一 `hexi.web_auth.require_admin`;示例端点:`GET /ping`、`GET /config`(读插件配置)。
- 想要更丰富的管理页:前端放 `web/dist/`,在 admin.py 里挂 `StaticFiles` + SPA 兜底即可(参考 `nonebot_plugin_web_hub`)。
## 约定
- `plugin_id` = 模块名(自动取 `__package__`;web 子应用用 `__package__.rsplit(".", 1)[0]`)。
- Trigger/View 可 import nonebot;Service/Model/repository 尽量不 import nonebot。
- 配置默认值写进 schema,Web 自动回填;敏感字段 `secret=True`。GET 只显示 `****`;保存配置时带上 GET 返回的 `revision`,修改冲突会返回 409。
- 同一 `plugin_id` 多次注册会自动合并(getter/apply 组合),但字段 key 应由单一注册者负责,避免定义冲突。
- Service 中的文件/数据库访问应使用异步 repository 或 `asyncio.to_thread`,不要阻塞事件循环。