531 lines
17 KiB
Markdown
531 lines
17 KiB
Markdown
# JWeBot
|
||
|
||
[中文](#中文说明) | [English](#english)
|
||
|
||
## 中文说明
|
||
|
||
JWeBot 是运行于 Linux 的单群微信自动回复系统。它通过本地 OCR
|
||
观察选定的微信窗口,将消息写入持久化 Edge 账本,调用经过审核的命令插件,
|
||
并通过带视觉确认的 GUI 发送链路回复。
|
||
|
||
当前版本:`beta 1.0.5.1016`,更新时间:2026-10-16 16:30:44。
|
||
|
||
1.0 Beta 收口了当前稳定功能:本地命令插件、人物与上下文索引、
|
||
Steam 状态与时长查询、虚拟摩拉游戏、多人彩票、21 点、CS Major
|
||
自走棋、生产部署与回滚门禁。CS Major 自走棋的选手、教练、叙事和规则
|
||
已经外置为包内 JSON,虚拟摩拉支持转账、贷款、还款和群内排行榜。
|
||
|
||
完整命令见[命令目录](docs/command-catalog.md)。历史版本记录见
|
||
[CHANGELOG](CHANGELOG.md)。
|
||
|
||
### 运行流程
|
||
|
||
```text
|
||
微信窗口
|
||
-> 自适应 XDamage 截图
|
||
-> 本地 OCR 与群指纹校验
|
||
-> 持久化 Edge 账本
|
||
-> 已审核的本地插件
|
||
-> DeepSeek 直接对话
|
||
-> 可选云端智能体
|
||
-> 带优先级的 GUI 队列
|
||
-> 输入草稿、发送与视觉确认
|
||
```
|
||
|
||
运行时绑定一个可见群聊。插件不能选择群聊、操作 GUI、读取环境密钥、
|
||
打开任意网络连接、执行 shell 命令或直接访问 SQLite。
|
||
|
||
### 快速开始
|
||
|
||
运行环境:
|
||
|
||
- Linux 与 systemd 用户服务;
|
||
- 已登录的桌面微信,以及 X11/VNC 显示会话 `:1`;
|
||
- Python 3.9 或更新版本;
|
||
- `xdotool`、`scrot`、`xclip`、OpenCV、Pillow、NumPy 和 RapidOCR;
|
||
- Steam 功能所需的本机回环 Mihomo HTTP 代理。
|
||
|
||
创建并激活私有配置:
|
||
|
||
```sh
|
||
./tools/jwebot-config.py init personal --activate
|
||
```
|
||
|
||
编辑 `~/.config/jwebot/profiles/personal/` 下的配置,然后重新激活并验证:
|
||
|
||
```sh
|
||
./tools/jwebot-config.py activate personal
|
||
PATH="$PWD/.venv/bin:$PATH" ./tools/check-local.sh
|
||
```
|
||
|
||
服务读取激活时生成的配置,不直接读取源 profile。激活过程先校验配置,
|
||
再原子生成以下文件:
|
||
|
||
```text
|
||
~/.config/jwebot/current/generated/
|
||
runtime.env
|
||
root.env
|
||
private-context.json
|
||
notification.json
|
||
manifest.json
|
||
```
|
||
|
||
导入、脱敏导出、旧配置迁移、调试归档和 root 部署设置见
|
||
[配置系统说明](config/README.md);完整安装步骤见
|
||
[从零部署指南](docs/runbooks/zero-to-running.md)。
|
||
|
||
### 常用命令
|
||
|
||
内置命令清单由经过审核的插件描述文件生成:
|
||
|
||
```text
|
||
/功能列表
|
||
/上下文 [100|200|300](/context)
|
||
/人物列表 [页码](/people);/人物 [名称或别名](/person)
|
||
/摩拉(兼容 /金币、/wallet);/抽奖 [金额](/draw)
|
||
/大富翁榜(/摩拉排行,兼容 /金币排行)
|
||
/转账 对方 金额(/transfer name amount)
|
||
/贷款 [金额](/loan amount);/还款 [金额|全部](/repay)
|
||
/彩票 开始|报名|当前状态|开奖|取消(/lottery)
|
||
/21点 开始 [1~500];开局后 /21点 要牌|停牌|状态|结束
|
||
/21点 多人 启动;/21点 加入;/21点 多人 开始;/21点 放200
|
||
/摩拉(兼 /原石);/原石祈愿;/原石榜;/扫码加权 人名;/Taffy发话 内容
|
||
/游戏记录 [页码](/gamehistory)
|
||
/游戏记录 [页码](/gamehistory)
|
||
/游戏帮助(/games)
|
||
/自走棋开始|报名|开赛|状态|档案
|
||
/自走棋加AI战队(两名或三名真人测试模式)
|
||
/选1~6(教练轮为 /选1~10);/刷新;/锁定
|
||
/战术 火力|稳定|残局;/阵容;/上阵 备战编号 [首发位];/出售 备战编号;/结束回合
|
||
/丢骰子 [NdM]
|
||
/猜数字 开始 [上限]
|
||
/石头剪刀布 [开始|加入|出|状态|结算|结束]
|
||
/记住 内容
|
||
/人物记忆 显示名
|
||
/扫码排行
|
||
/复读榜
|
||
/查记录 关键词
|
||
/状态
|
||
/version
|
||
/debug
|
||
/steam [在线|游戏|全部|刷新]
|
||
/steam时长 游戏名[、玩家名]
|
||
```
|
||
|
||
Steam 时长查询允许省略空格,以兼容 OCR。指定玩家时使用明确的分隔符:
|
||
|
||
```text
|
||
/steam 时长 Dota 2
|
||
/steam时长Dota2
|
||
/steam时长Dota2、玩家名
|
||
/steam时长Dota2人=玩家名
|
||
```
|
||
|
||
Steam 优先使用当前私有 profile 中的人物 SteamID 映射,显示对应的群内名称,
|
||
并支持群内别名。配置了人物名单时,查询仅覆盖名单内账号;未配置名单时,
|
||
才在运行时发现配置账号的公开好友列表。游戏名和玩家名支持模糊匹配;
|
||
全员查询限制并发数,指定玩家只查询该账号的游戏库。所有 Steam 请求必须
|
||
经过配置的本机回环代理。源码不包含真实 SteamID、人物名称、别名或固定名单。
|
||
|
||
### 独立配置
|
||
|
||
每个 profile 按插件配置包组织:
|
||
|
||
```text
|
||
manifest.toml
|
||
components/
|
||
bot.toml
|
||
providers.toml
|
||
runtime.toml
|
||
debug.toml
|
||
notification.toml
|
||
deployment.toml
|
||
context/
|
||
people.json
|
||
secrets/
|
||
runtime.env
|
||
overrides/
|
||
runtime.env
|
||
root.env
|
||
```
|
||
|
||
真实配置放在 Git 外:目录权限为 `0700`,文件权限为 `0600`。
|
||
事故、调试、遥测和迁移后的 root 操作资料放在
|
||
`~/.local/state/jwebot/profiles/<profile>/`。
|
||
字段和配置流程见 [配置指南](docs/configuration-guide.md)。
|
||
|
||
### 插件与 SDK
|
||
|
||
公共 SDK 位于 `packages/jwebot-sdk/`,最小示例位于
|
||
`examples/hello-command/`。插件注册在启动期完成,运行前冻结命令所有权。
|
||
|
||
创建插件:
|
||
|
||
```sh
|
||
./tools/create-plugin.py weather-command /weather \
|
||
--author example \
|
||
--description "Query approved weather data" \
|
||
--help-entry "/weather city"
|
||
```
|
||
|
||
校验、打包并签名:
|
||
|
||
```sh
|
||
./tools/validate-plugin.py extensions/friends/weather-command/plugin.toml
|
||
./tools/package-plugin.py extensions/friends/weather-command --output /tmp/release
|
||
./tools/sign-release.py /tmp/release/*.release.json \
|
||
--private-key /protected/path/publisher \
|
||
--publisher example
|
||
```
|
||
|
||
签名完成后,按 [文档目录](docs/) 中的扩展发布与激活流程安装。
|
||
|
||
### 部署
|
||
|
||
新机器请按 [从零部署指南](docs/runbooks/zero-to-running.md) 操作。
|
||
已有安装使用协调部署脚本;切换前会保留旧运行时、用户服务、生成配置、
|
||
SQLite 状态和 systemd 服务结构:
|
||
|
||
```sh
|
||
sudo ./deploy/scripts/deploy-jwebot-production.sh /path/to/JWeBot jwebot
|
||
```
|
||
|
||
部署必须通过微信窗口就绪、队列清空、Edge 健康、SQLite 完整性和自适应
|
||
录制服务重启稳定性检查。切换成功后,部署器按版本幂等地向每个既有账户
|
||
发放 200 摩拉、写入账户流水,并使用当前 changelog 的第一条摘要发布群公告;
|
||
本次 `beta 1.0.5.1016` 额外发放 1 原石。
|
||
旧 OCR 服务保留安装,但保持禁用。
|
||
|
||
### 仓库结构
|
||
|
||
| 路径 | 用途 |
|
||
|---|---|
|
||
| `packages/jwebot-config/` | 配置校验、生成、导入导出、激活与旧配置迁移。 |
|
||
| `packages/jwebot-sdk/` | 权限受限的公共插件接口。 |
|
||
| `packages/jwebot-kernel/` | 路由、账本、策略、发布校验与 Edge 运行时。 |
|
||
| `packages/jwebot-extension-host/` | 隔离运行已签名扩展的进程宿主。 |
|
||
| `packages/jwebot-official-extensions/` | 已审核的命令引擎与生成适配器。 |
|
||
| `extensions/official/` | 官方 service-profile 适配器。 |
|
||
| `extensions/jwebot/` | 内置命令插件。 |
|
||
| `extensions/friends/` | 贡献者插件目录。 |
|
||
| `config/` | 公开模板与 schema,不存放真实配置。 |
|
||
| `deploy/` | 初始化、协调部署与 systemd 单元。 |
|
||
| `docs/` | 架构、SDK、配置与运行指南。 |
|
||
| `tests/` | 单元、行为一致性、打包、安全与部署契约测试。 |
|
||
| `tools/` | 校验、打包、签名、激活、隐私扫描与配置工具。 |
|
||
|
||
根目录 Python 文件是部署服务使用的兼容入口,实际实现位于 `packages/`。
|
||
|
||
### 项目进度
|
||
|
||
```text
|
||
独立配置与私有资料迁移 [####################] 100%
|
||
插件所有权与 SDK 边界 [####################] 100%
|
||
Steam 状态与时长查询 [####################] 100%
|
||
本地单元与行为一致性 [####################] 100%
|
||
从零部署自动化 [################----] 80%
|
||
跨发行版 staging 验证 [########------------] 40%
|
||
```
|
||
|
||
进度描述仓库中已完成、可测试的交付内容。实际运行效果仍取决于目标桌面、
|
||
微信版本、OCR 模型、代理和操作者提供的凭据。
|
||
|
||
### 验证与隐私
|
||
|
||
运行完整本地检查:
|
||
|
||
```sh
|
||
PATH="$PWD/.venv/bin:$PATH" ./tools/check-local.sh
|
||
```
|
||
|
||
检查当前文件及全部 Git 对象历史:
|
||
|
||
```sh
|
||
./tools/check-secrets.py
|
||
./tools/check-secrets.py --history
|
||
```
|
||
|
||
扫描器只报告类别、路径、行号、对象哈希和单向指纹,不输出匹配到的敏感值。
|
||
不要提交已填写的 profile、生成环境、人物上下文、截图、OCR 历史、调试内容、
|
||
事故归档、SQLite 文件、发布者私钥、API 密钥、SteamID 或真实主机路径。
|
||
|
||
仓库只提供公开模板与 schema。默认配置导出会脱敏;私有导出需要显式指定
|
||
`--include-private`,导出结果应继续保存在 Git 外。
|
||
|
||
### 许可证
|
||
|
||
JWeBot 使用 Apache License 2.0,见 [LICENSE](LICENSE)。
|
||
|
||
---
|
||
|
||
## English
|
||
|
||
JWeBot is a single-group WeChat automation runtime for Linux. It observes one
|
||
selected WeChat window through local OCR, routes messages through a durable
|
||
Edge ledger, runs reviewed command plugins, and sends replies through a
|
||
visually confirmed GUI bridge.
|
||
|
||
Current version:
|
||
|
||
```text
|
||
beta 1.0.5.1016
|
||
```
|
||
|
||
Updated: 2026-10-16 16:30:44.
|
||
|
||
The 1.0 Beta baseline consolidates the stable local command set, person and
|
||
context indexes, Steam presence/playtime queries, virtual coin games,
|
||
multiplayer lottery, blackjack, CS Major autochess, and production deployment
|
||
gates. CS Major autochess game content is now packaged as JSON data, and
|
||
virtual coins support transfer, loans, repayment, and group leaderboards.
|
||
|
||
## Runtime Flow
|
||
|
||
```text
|
||
WeChat window
|
||
-> adaptive XDamage capture
|
||
-> local OCR and group fingerprint gate
|
||
-> durable Edge ledger
|
||
-> reviewed local plugin
|
||
-> DeepSeek direct chat
|
||
-> optional cloud agent
|
||
-> priority GUI queue
|
||
-> guarded draft/send/visual confirmation
|
||
```
|
||
|
||
The runtime is deliberately bound to one visible group. Plugins cannot select a
|
||
group, access the GUI, read environment secrets, open arbitrary sockets, invoke
|
||
shell commands, or access raw SQLite state.
|
||
|
||
## Quick Start
|
||
|
||
Requirements:
|
||
|
||
- Linux with systemd user services;
|
||
- a working desktop WeChat session on X11/VNC display `:1`;
|
||
- Python 3.9 or newer;
|
||
- `xdotool`, `scrot`, `xclip`, OpenCV, Pillow, NumPy, and RapidOCR;
|
||
- an optional loopback Mihomo HTTP proxy for Steam.
|
||
|
||
Create a private configuration profile:
|
||
|
||
```sh
|
||
./tools/jwebot-config.py init personal --activate
|
||
```
|
||
|
||
Edit files under:
|
||
|
||
```text
|
||
~/.config/jwebot/profiles/personal/
|
||
```
|
||
|
||
Then compile and validate:
|
||
|
||
```sh
|
||
./tools/jwebot-config.py activate personal
|
||
PATH="$PWD/.venv/bin:$PATH" ./tools/check-local.sh
|
||
```
|
||
|
||
The source profile is never read directly by services. Activation validates and
|
||
atomically generates:
|
||
|
||
```text
|
||
~/.config/jwebot/current/generated/
|
||
runtime.env
|
||
root.env
|
||
private-context.json
|
||
notification.json
|
||
manifest.json
|
||
```
|
||
|
||
See [config/README.md](config/README.md) for import, redacted export, legacy
|
||
migration, debug archives, and root deployment settings.
|
||
|
||
## Commands
|
||
|
||
The built-in command inventory is generated from reviewed plugin descriptors.
|
||
See the full [command catalog](docs/command-catalog.md). Common commands
|
||
include:
|
||
|
||
```text
|
||
/功能列表
|
||
/丢骰子 [NdM]
|
||
/猜数字 开始 [上限]
|
||
/石头剪刀布 [开始|加入|出|状态|结算|结束]
|
||
/记住 内容
|
||
/人物记忆 显示名
|
||
/扫码排行
|
||
/复读榜
|
||
/查记录 关键词
|
||
/状态
|
||
/version
|
||
/debug
|
||
/steam [在线|游戏|全部|刷新]
|
||
/steam时长 游戏名[、玩家名]
|
||
```
|
||
|
||
OCR whitespace is optional for Steam playtime queries. A player selector uses
|
||
the final separator shown below:
|
||
|
||
```text
|
||
/steam 时长 Dota 2
|
||
/steam时长Dota2
|
||
/steam时长Dota2、玩家名
|
||
/steam时长Dota2人=玩家名
|
||
```
|
||
|
||
Chinese aliases share the same implementations as their English counterparts.
|
||
Virtual coin funds, game state, transfers, loans, repayments, and replay
|
||
responses commit through the same ledger transaction path. Native WeChat
|
||
account IDs are unavailable, so accounts are scoped by OCR display identity and
|
||
configured aliases. See
|
||
[plugin rules and capture reconciliation](docs/local-plugins-0.6.1.md).
|
||
|
||
Steam prefers private per-person SteamID mappings from the active profile and
|
||
uses the corresponding group display IDs and aliases. Without a private roster,
|
||
it discovers the configured account's public friend list at runtime. No real
|
||
SteamID, display name, alias, or fixed roster is stored in source. Game and
|
||
player names support fuzzy matching; all-player requests use bounded
|
||
concurrency, while player-specific requests read only the selected account's
|
||
game library. Every request must use the configured loopback proxy.
|
||
|
||
## Configuration Profiles
|
||
|
||
Each profile is organized like a plugin package:
|
||
|
||
```text
|
||
manifest.toml
|
||
components/
|
||
bot.toml
|
||
providers.toml
|
||
runtime.toml
|
||
debug.toml
|
||
notification.toml
|
||
deployment.toml
|
||
context/
|
||
people.json
|
||
secrets/
|
||
runtime.env
|
||
overrides/
|
||
runtime.env
|
||
root.env
|
||
```
|
||
|
||
Real profiles live outside Git with `0700` directories and `0600` files.
|
||
Incidents, debug sessions, telemetry, and migrated root material live under
|
||
`~/.local/state/jwebot/profiles/<profile>/`.
|
||
|
||
## Plugins And SDK
|
||
|
||
The public SDK is in `packages/jwebot-sdk/`. A minimal extension is available
|
||
at `examples/hello-command/`.
|
||
|
||
Create a plugin:
|
||
|
||
```sh
|
||
./tools/create-plugin.py weather-command /weather \
|
||
--author example \
|
||
--description "Query approved weather data" \
|
||
--help-entry "/weather city"
|
||
```
|
||
|
||
Validate, package, sign, and activate:
|
||
|
||
```sh
|
||
./tools/validate-plugin.py extensions/friends/weather-command/plugin.toml
|
||
./tools/package-plugin.py extensions/friends/weather-command --output /tmp/release
|
||
./tools/sign-release.py /tmp/release/*.release.json \
|
||
--private-key /protected/path/publisher \
|
||
--publisher example
|
||
```
|
||
|
||
Extension registration is dynamic only during startup and freezes before
|
||
runtime routing.
|
||
|
||
## Deployment
|
||
|
||
For a new machine, follow
|
||
[docs/runbooks/zero-to-running.md](docs/runbooks/zero-to-running.md).
|
||
|
||
For an existing installation, the coordinated deployer preserves the previous
|
||
runtime, user units, generated configuration, SQLite state, and systemd
|
||
topology before cutover:
|
||
|
||
```sh
|
||
sudo ./deploy/scripts/deploy-jwebot-production.sh /path/to/JWeBot jwebot
|
||
```
|
||
|
||
The deployer refuses cutover unless the ready-window, empty-queue, Edge health,
|
||
SQLite integrity, and adaptive restart-stability gates pass. Legacy OCR units
|
||
remain installed but disabled. After cutover, version-idempotent release
|
||
settlement grants 200 Mora to every existing account, records the movement,
|
||
and sends the first changelog bullet as the guarded group announcement.
|
||
For `beta 1.0.5.1016`, the settlement also grants 1 primogem once.
|
||
|
||
## Repository Map
|
||
|
||
| Path | Purpose |
|
||
|---|---|
|
||
| `packages/jwebot-config/` | Profile validation, generation, import/export, activation, and legacy migration. |
|
||
| `packages/jwebot-sdk/` | Capability-limited public plugin contracts. |
|
||
| `packages/jwebot-kernel/` | Routing, ledger, policy, release verification, and Edge runtime. |
|
||
| `packages/jwebot-extension-host/` | Isolated signed-extension process host. |
|
||
| `packages/jwebot-official-extensions/` | Reviewed command engine and generated adapters. |
|
||
| `extensions/official/` | Official service-profile adapters. |
|
||
| `extensions/jwebot/` | Built-in reviewed command plugins. |
|
||
| `extensions/friends/` | Contributor plugin area. |
|
||
| `config/` | Public templates and schemas only. |
|
||
| `deploy/` | Bootstrap, coordinated deployment, and systemd units. |
|
||
| `docs/` | Architecture, SDK, configuration, and runbooks. |
|
||
| `tests/` | Unit, parity, packaging, safety, and deployment contract tests. |
|
||
| `tools/` | Validation, packaging, signing, activation, scanning, and config CLI. |
|
||
|
||
The root Python files are compatibility entrypoints used by deployed services;
|
||
implementation packages remain under `packages/`.
|
||
|
||
## Project Status
|
||
|
||
```text
|
||
Config profiles and private migration [####################] 100%
|
||
Plugin ownership and SDK boundaries [####################] 100%
|
||
Steam status and playtime modes [####################] 100%
|
||
Local unit and parity coverage [####################] 100%
|
||
Zero-to-running automation [################----] 80%
|
||
Cross-distribution staging [########------------] 40%
|
||
```
|
||
|
||
Percentages describe completed, testable deliverables in this repository.
|
||
Production readiness still depends on the target desktop, WeChat build, OCR
|
||
models, proxy, and operator-provided credentials.
|
||
|
||
## Verification
|
||
|
||
Run the complete local gate:
|
||
|
||
```sh
|
||
PATH="$PWD/.venv/bin:$PATH" ./tools/check-local.sh
|
||
```
|
||
|
||
Run privacy scans explicitly:
|
||
|
||
```sh
|
||
./tools/check-secrets.py
|
||
./tools/check-secrets.py --history
|
||
```
|
||
|
||
The scanner reports only category, path, line, object hash, and a one-way value
|
||
fingerprint. It never prints the matched value.
|
||
|
||
## Privacy
|
||
|
||
Do not commit populated profiles, generated environments, private context,
|
||
screenshots, OCR history, debug payloads, incident archives, SQLite files,
|
||
publisher private keys, API keys, SteamIDs, or host-specific paths.
|
||
|
||
The repository includes safe templates and schemas. Default profile export is
|
||
redacted; private export requires an explicit `--include-private` flag.
|
||
|
||
## License
|
||
|
||
JWeBot is licensed under Apache License 2.0. See [LICENSE](LICENSE).
|