Files
autman-plugins/docs/autman-plugin-rules.md
T

593 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Autman 插件开发规则与仓库约定
> 来源:已参考 BOSS 上传到本仓库的插件示例,以及 autMan 官方论坛教程:<https://bbs.autman.cn/>。重点参考帖子:插件编写规则、插件编程-头注篇、插件编写概论、微服务插件编写、Python 简单插件编写、消息类型说明、实时 IM 消息监听、适配器插件编写指南。
## 1. 仓库用途
本仓库统一存放 BOSS 的 Autman 插件、参考示例、文档和模板。以后新增插件优先按下面目录组织:
```text
js/ # ECMAScript5 / 内置 JS 插件,通常放 autMan plugin/replies
py/ # Python 插件,通常放 autMan plugin/scripts
plugins/ # 我们新写的正式插件;按功能再分目录或命名
examples/ # 调用示例、配置示例
templates/ # 可复制的插件模板
docs/ # 规则、接口说明、研究记录
```
已有历史插件可保留原路径。新开发插件建议优先放到 `plugins/`,稳定后可按 Autman 实际导入目录复制到 `js/``py/`
## 2. 插件类型
Autman 支持多种插件/脚本形态:
| 类型 | 说明 | 常见位置/用途 |
|---|---|---|
| HTML 插件 | 由 Autman Web 服务托管页面 | `plugin/web`,主要自用 |
| ES5 插件 | Autman 内置 ES5 环境运行,内置大量函数 | `plugin/replies`,适合关键词、路由、轻量集成 |
| Python/Node/TS/PHP/Shell/Go 等外部脚本 | Autman 调用宿主系统环境运行,通过 `middleware` 与 Autman 交互 | `plugin/scripts`,适合复杂逻辑、依赖第三方库 |
| 微服务路由插件 | 使用 `router` / `method` 头注暴露 HTTP 接口 | 对外接收 Webhook/API 调用 |
| 适配器插件 | 对接新的社交媒体/IM,将外部消息转换为 Autman 消息格式 | 需要处理 HTTP/WS 通信和消息格式转换 |
注意:除 HTML 插件外,其他插件运行通常要求 Autman 授权有效。
## 3. 头注规则
头注必须放在插件文件头部,用于生成插件元数据和触发条件。
### 3.1 市场/基础元数据
JS 示例:
```js
//[open_source: true]
//[create_at: 2026-01-01 12:00:00]
//[title: 插件名称]
//[author: 作者]
//[service: 售后联系方式]
//[class: 工具类]
//[version: 1.0.0]
//[platform: qq,wx,tg,tb,web]
//[public: false]
//[price: 0]
//[disable: false]
//[description: 插件说明,尽量写清楚用法]
//[icon: https://example.com/icon.png]
```
Python 示例:
```python
# [title: 插件名称]
# [language: python]
# [service: 售后联系方式]
# [disable: false]
# [admin: true]
# [rule: ^指令$]
# [platform: qq,wx,tg,tb]
# [open_source: true]
# [version: 1.0.0]
# [public: false]
# [price: 0]
# [description: 插件说明]
```
字段说明:
| 字段 | 说明 |
|---|---|
| `title` | 插件标题 |
| `author` | 作者 |
| `service` | 售后/联系方式;上架通常必填 |
| `class` | 分类,如工具类、查询类、娱乐类、生活类、图片类等 |
| `platform` | 适用平台,多个用英文逗号分隔 |
| `public` | 是否公开显示到市场;开发测试建议 `false` |
| `disable` | `true` 禁用,`false` 启用 |
| `version` | 版本号 |
| `price` | 价格 |
| `description` | 说明,建议写清楚指令、参数、注意事项 |
| `icon` | 图标 URL,建议 48px 正方形,支持 http/https |
### 3.2 关键词/命令触发
```js
//[rule: ^菜单$]
//[rule: ^菜单管理$]
//[admin: true]
//[priority: 300]
//[cron: 0 7 * * *]
//[bypass: false]
```
规则:
- `rule` 支持正则,可写多行表示多个触发规则。
- `cron` 支持 5 位或 6 位 cron 表达式。
- `admin: true` 表示仅管理员可执行。
- `priority` 数字越大优先级越高。
- `bypass: true` 常用于全拦截规则,例如 `[rule: ?]`,表示旁路并行处理。
- 可用 `imType+` / `imType-``userId+` / `userId-``groupId+` / `groupId-` 做白名单/黑名单。
示例:
```js
//[rule: ^sim状态$]
//[rule: ^sim短信\s+(.+?)\s+([\s\S]+)$]
//[admin: true]
//[platform: qq,wx,tg,tb]
//[priority: 100]
```
### 3.3 微服务路由触发
微服务插件通过 HTTP 路由触发,新增/修改这类插件后通常需要重启 Autman 才生效。
```js
//[router: /simadmin/status]
//[method: get]
//[method: post]
```
规则:
- `router` 路径必须以 `/` 开头。
- `method` 可写多个,常见为 `get``post`,也可支持 `put/delete`
- GET 参数从 `getRouterParams()` 取。
- POST body 从 `getRouterData()` / `getRouterBody()` 取。
- 最终必须用 `response(obj)` 或兼容方式返回,避免请求挂起。
### 3.4 配参头注
用于让 Autman 后台渲染插件配置项。
```js
//[param: {"required":true,"key":"otto.simadmin_base_url","bool":false,"placeholder":"http://192.168.1.10:3000","name":"SimAdmin地址","desc":"不要以 / 结尾"}]
//[param: {"required":true,"key":"otto.simadmin_token","bool":false,"placeholder":"访问Token","name":"接口鉴权Token","desc":"外部请求必须携带 access_token"}]
//[param: {"required":false,"key":"otto.simadmin_push_master","bool":true,"placeholder":"","name":"是否推送管理员","desc":""}]
//[param: {"spliter":true}]
```
约定:
- `key` 建议使用统一前缀,例如 `otto.simadmin_xxx``otto.<插件名>_xxx`
- 密钥/token 不要写死在源码里,放到配参或环境变量。
- `bool: true` 用于开关项。
- `required` 只表示配置 UI 要求,不等于运行期一定存在;代码里仍需校验。
## 4. 常见平台/消息类型
论坛中整理的常见类型:
| 类型 | 含义 |
|---|---|
| `qq` | QQ 框架 |
| `qb` | QQ 频道机器人 |
| `wx` | 微信外接框架 |
| `wb` | 内置微信机器人 |
| `tg` | Telegram 客户端 |
| `tb` | Telegram 官方机器人 |
| `wm` | 微信订阅号 |
| `wv` | 微信服务号 |
| `wk` | 微信客服 |
| `dd` | 钉钉机器人 |
| `dc` | Discord 机器人 |
| `sk` | Slack 机器人 |
| `fs` | 飞书机器人 |
| `kk` | Kook 机器人 |
| `qh` | 群晖 Synology Chat |
| `we` | 页面对话 |
| `rt` | router 消息 / 微信服务插件消息 |
| `terminal` | 交互模式终端对话 |
## 5. ES5 插件内置函数与用法
### 5.1 基础信息
```js
var name = call("name")()
var port = call("port")()
var version = call("version")()
var machineId = call("machineId")()
var id = call("uuid")()
var sign = call("md5")("text")
var now = call("timeFormat")("yyyy-MM-dd hh:mm:ss")
var textTime = call("unixTimeFormat")(second, nanosecond, "yyyy-MM-dd hh:mm:ss")
var ok = cancall("someFunc")
var coffeeOk = coffee()
```
### 5.2 消息上下文
常见函数/对象:
```js
var content = GetContent()
var is_admin = isAdmin()
sendText("回复文本")
var msg = input() // 等待用户输入,适合交互式插件
sender.reply({ok:true, msg:"success"})
Debug("调试日志")
console.log("普通日志")
```
建议:
- 管理类指令必须先判断 `isAdmin()`
- `input()` 应处理 `null/undefined/空字符串/q退出`
- JSON 返回优先用对象,便于 Web/API 调用方解析。
### 5.3 数据桶
```js
bucketSet("bucket", "key", "value")
var value = bucketGet("bucket", "key")
bucketDel("bucket", "key")
var keys = bucketKeys("bucket")
```
约定:
- 桶名和 key 统一前缀,避免和其他插件冲突。
-`bucketGet` 读出的复杂对象需要 `JSON.parse`,必须 try/catch。
- 写入复杂对象用 `JSON.stringify`
### 5.4 获取配置参数
配参 key 形如 `otto.simadmin_base_url` 时,代码中通常按后半段读取:
```js
var baseUrl = get("simadmin_base_url")
var token = get("simadmin_token")
```
实际以 BOSS 上传的插件为准:`qlck.js``key: "otto.vhook_qlck_token"`,读取为 `get("vhook_qlck_token")`
### 5.5 网络请求
回调风格:
```js
request({
useproxy: false,
url: "https://example.com/api",
headers: {"Content-Type":"application/json"},
method: "post",
dataType: "json",
body: {a: 1},
timeOut: 10000
}, function(error, response, header, body) {
// 处理结果
})
```
同步/直接返回风格(BOSS 上传的 `js/qlck.js` 已使用):
```js
var resp = request({
url: baseUrl + "/api/health",
method: "get",
dataType: "json",
timeOut: 10000
})
```
约定:
- HTTP API 插件优先使用 `dataType: "json"`
- 外部服务业务失败时不一定是 HTTP 非 200,要检查返回 JSON 内的状态字段。
- 请求外部服务前清理 URL 尾部 `/``baseUrl.replace(/\/+$/, "")`
- 超时必须设置,避免插件卡死。
### 5.6 推送消息
```js
push({
imType: "qq",
groupCode: "123456",
content: "群消息"
})
push({
imType: "wx",
userID: "user-id",
content: "私聊消息"
})
```
字段:
- 群组:`groupCode` 或部分平台使用 `chatID`
- 私聊:`userID`
- 平台:`imType`
## 6. 微服务插件运行规则
官方示例提到的微服务函数:
```js
getRouterPath()
getRouterMethod()
getRouterHeaders()
getRouterCookies()
getRouterParams()
getRouterBody()
response(obj)
```
BOSS 上传插件和论坛示例中也常见兼容函数名:
```js
var method = getMethod()
var params = getRouterParams() || {}
var data = getRouterData()
```
建议写法:
```js
function jsonResponse(obj) {
if (typeof response === "function") {
response(obj)
} else if (typeof sender !== "undefined" && sender.reply) {
sender.reply(obj)
} else {
sendText(JSON.stringify(obj))
}
}
```
外部 API 插件必须注意:
1. 先做 token 鉴权,鉴权失败后立即 `return`
2. GET/POST 都支持时,参数读取顺序建议:query 参数 -> POST JSON 覆盖。
3. POST JSON 解析必须 try/catch。
4. 对发短信、重启、开关网络等敏感操作必须管理员或 token 控制。
5. 返回统一 JSON
```json
{"ok":true,"status":"ok","retcode":0,"msg":"success","data":{}}
```
错误:
```json
{"ok":false,"status":"fail","retcode":-1,"msg":"token错误"}
```
## 7. Python 插件规则
Python 插件通过 `middleware` 与 Autman 交互。常见头注:
```python
# [title: 测试]
# [language: python]
# [disable: false]
# [platform: qq,wx]
# [rule: ^测试(.*)$]
# [admin: false]
# [version: 1.0.0]
```
常见初始化:
```python
import middleware
sender_id = middleware.getSenderID()
sender = middleware.Sender(sender_id)
message = sender.getMessage()
user_id = sender.getUserID()
user_name = sender.getUserName()
im_type = sender.getImtype()
chat_id = sender.getChatID()
is_admin = sender.isAdmin()
```
回复/监听:
```python
sender.reply("请输入内容,q退出")
user_input = sender.listen(120000) # 毫秒
if user_input == "q":
sender.reply("退出")
exit(0)
```
数据桶:
```python
middleware.bucketSet("bucket", user_id, "value")
value = middleware.bucketGet("bucket", user_id)
middleware.bucketDel("bucket", user_id)
```
依赖:
- Python 插件可自动安装依赖,但要谨慎,避免每次运行都安装。
- 建议在代码里先 `importlib.import_module` 检测,再提示管理员安装或自动安装。
- 网络请求可用 `requests` / `aiohttp`,但要设置 timeout。
## 8. 适配器插件要点
适配器用于接入新 IM/社交平台。官方建议:
1. 选择不冲突的 `im_type`,尽量 2 个字母,如 `tt`
2. HTTP 回调地址一般为:
```text
http://<autman-host>:<port>/<im_type>/receive
```
3. Autman 与适配器通信的 WS 地址一般为:
```text
http://<autman-host>:<port>/<im_type>/adapter
```
4. 适配器需要把外部平台消息转换为 Autman 消息格式:
```json
{
"event": "message",
"event_data": {},
"guild_id": "",
"guild_name": "",
"bot_id": "",
"bot_name": "",
"chat_id": "",
"chat_name": "",
"user_id": "",
"user_name": "",
"im_type": "tt",
"message_id": "",
"content": "消息内容"
}
```
5. Autman 返回动作格式:
```json
{
"aut_action": "send_msg",
"aut_echo": "",
"aut_params": {}
}
```
适配器要把 Autman 动作翻译成外部平台 API 调用,并在需要时回执消息 ID。
## 9. 实时 IM 消息监听
Autman 支持本地 SSE 监听实时 IM 消息,官方接口:
```text
POST /otto/msghook
Accept: text/event-stream
Content-Type: application/json
```
请求 body 示例:
```json
{"imtype":"qq","chatid":"11543756","userid":"282617666"}
```
处理要点:
- 仅限本地访问更安全。
- SSE 数据按行读取,关注 `event:``data:`
- 需要处理断线重连。
- 解析 `data:` 后再做业务逻辑。
## 10. 安全与质量约定
开发新插件时必须遵守:
1. **不要硬编码密钥**token、cookie、API key 放配参、环境变量或本地不提交文件。
2. **外部路由必须鉴权**:尤其是发短信、推送、修改配置、重启、网络开关。
3. **鉴权失败必须 return**:避免只回复错误但继续执行后续逻辑。
4. **敏感操作默认管理员限定**:聊天指令使用 `[admin:true]` 或代码内判断。
5. **统一 JSON 返回**:便于外部系统调用和排错。
6. **请求设置 timeout**:避免 Autman 插件阻塞。
7. **兼容 GET/POST**:微服务接口可同时支持 query 和 JSON body,但 POST JSON 优先。
8. **严格校验参数**:手机号、URL、路径、开关布尔值、枚举值都要校验。
9. **日志不要打印密钥**token/cookie/API key 必须脱敏。
10. **插件说明写清楚**:头注 description 和 README 中都要写指令、参数、示例。
## 11. 新插件开发流程
1. 先在 `plugins/<plugin-name>/` 下写源码和 README。
2. 根据插件类型复制 `templates/` 里的模板。
3. 本地检查头注、鉴权、参数校验和错误返回。
4. 如需适配 BOSS 已有插件风格,优先参考:
- `js/qlck.js`:微服务 API + 配参 + token 鉴权 + request 调外部 API。
- `py/nazha.py`Python middleware 初始化、依赖检测、平台/用户上下文。
5. 提交前确认没有 `.env`、token、cookie、日志、运行时数据。
6. 推送后验证 raw 文件可访问。
## 12. SimAdmin 插件专项约定
后续实现 SimAdmin 插件时建议:
- 配参:
- `otto.simadmin_base_url`
- `otto.simadmin_access_token`
- `otto.simadmin_timeout_ms`
- 路由:
- `/simadmin/status`
- `/simadmin/sms/send`
- `/simadmin/sms/list`
- 聊天指令:
- `sim状态`
- `sim短信 <手机号> <内容>`
- SimAdmin API 业务失败要检查 JSON 内 `status === "error"`
- 发送短信必须 token 或管理员控制。
- Base URL 默认不带尾部 `/`,代码内统一 trim。
## 13. 账号/Cookie 类插件菜单设计经验(QDReader 复盘)
最近制作 `plugins/qdreader/qdreader_sign_autman.js` 时沉淀出一套适用于账号/Cookie 管理类插件的交互与数据规则,后续新插件优先复用:
### 13.1 交互结构
- 优先做“一级菜单 + 二级编号选择”,不要堆很多平铺子命令。
- 账号管理和执行查询分离:
- `xxx账号`:只做账号列表、添加/更新、详情/备注、删除、清空。
- `xxx查询`:只做最后执行日志/最近记录、单账号最近记录、立即执行等执行侧动作;除非明确实现实时接口,否则不要伪装成实时查询。
- 高频输入可以保留快速通道,例如 `xxxck <cookie>`,但快速通道只做快速提交,不再混入查询/导出/批量导入。
- 用户选择账号时展示编号列表,让用户回复编号;不要让用户手动复制/输入 UID。
- 添加/更新账号成功后立刻询问是否添加备注;备注修改放在账号详情里,不单独做一个割裂的备注菜单。
### 13.2 数据结构
账号/Cookie 类插件不要把 Cookie、用户绑定、备注、执行状态混在一起,建议拆成独立 map:
```json
// cookie_json
{ "uid": "full cookie" }
// user_bind_json
{ "uid": "sender.getUserID()" }
// remark_json
{ "uid": "主号" }
// last_result_json:单账号最后执行结果
{ "uid": "{\"ok\":true,\"msg\":\"成功\",\"time\":\"...\",\"source\":\"cron\",\"runId\":\"...\"}" }
// last_run_json:最近一次执行批次日志
{ "source": "cron", "finishedAt": "...", "okCount": 1, "failCount": 0, "total": 1, "items": [] }
```
这样删除、过滤、展示和权限校验更安全。
### 13.3 数据桶
- 新插件应创建自己的 bucket,例如 `hermes_qidian`,不要所有插件都塞进 `otto`
- 如需兼容旧数据,读顺序建议:
```text
bucketGet("插件专属bucket", key)
↓ fallback
get(key)
↓ fallback
bucketGet("otto", key)
```
- 写入新数据时写到专属 bucket,可同时写普通 `set(key)` 保持兼容。
### 13.4 多用户隔离
- 保存账号时绑定当前用户 ID。
- 账号列表、详情、删除、手动执行只处理当前用户绑定的账号。
- `删除全部` 只删除当前用户账号,不清空全局数据。
- cron/系统触发通常没有用户上下文,是否执行全部账号要显式传 `allUsers` 参数,并在代码和测试里说明。
### 13.5 安全与测试
- `xxx查询` 的数据来源必须写清楚:如果没有实时接口,就命名为“最近签到记录/最后执行日志”,读取 `last_run_json``last_result_json`,不要让用户误以为是实时查询。
- 执行动作要同时写批次日志和单账号日志;成功、业务失败、请求异常都要落日志,异常不能只显示在当次回复里。
- 普通回复永远不要输出完整 Cookie;只展示脱敏 UID、备注、Cookie key 摘要或长度。
- 高风险的导出/批量导入功能默认不做,除非 BOSS 明确需要。
- Node VM 测试应模拟:`sender.reply``sender.listen``sender.getUserID``get/set``bucketGet/bucketSet``request`
- 测试必须覆盖:快速提交、菜单添加、备注提示、详情改备注、编号选择删除/查询、旧 bucket 兼容、新 bucket 写入、用户隔离、手动执行只跑当前用户、cron 跑全部账号。