release: public alpha 0.6.0 baseline
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# Edge Runbook
|
||||
|
||||
JWeBot Edge is the local source of truth for accepted events, command state,
|
||||
provider work, acknowledgements, and final delivery.
|
||||
|
||||
## Routes
|
||||
|
||||
| Input after mention removal | Route | Execution |
|
||||
|---|---|---|
|
||||
| `/...` | Local | Kernel command or reviewed plugin |
|
||||
| ordinary text | Chat | Direct DeepSeek client |
|
||||
| `#...` | Cloud | Optional configured cloud agent |
|
||||
|
||||
The bot mention is read from the active profile. The public default is
|
||||
`@JWeBot`.
|
||||
|
||||
## Steam
|
||||
|
||||
Commands:
|
||||
|
||||
```text
|
||||
/steam
|
||||
/steam在线
|
||||
/steam游戏
|
||||
/steam全部
|
||||
/steam刷新
|
||||
/steam时长 游戏名
|
||||
/steam时长游戏名
|
||||
/steam时长游戏名、玩家名
|
||||
/steam时长游戏名人=玩家名
|
||||
```
|
||||
|
||||
The configured Steam account supplies the owner ID and API key. At runtime the
|
||||
provider:
|
||||
|
||||
1. uses private per-person SteamID mappings when configured, otherwise fetches
|
||||
the public friend list;
|
||||
2. batches public player summaries in groups of 100;
|
||||
3. labels mapped accounts with their group display IDs and accepts their
|
||||
private Steam query aliases;
|
||||
4. fuzzy matches the requested game against the owner's public library;
|
||||
5. falls back to scoped public libraries if the owner has no match;
|
||||
6. requests the selected AppID for every scoped account with bounded
|
||||
concurrency;
|
||||
7. sorts public playtime descending and summarizes private/unavailable data.
|
||||
|
||||
For a player-specific query, `、`, `,`, `,`, `@`, or `人=` explicitly separates
|
||||
the game from the player. The provider matches the live persona name and only
|
||||
requests that account's game library; ambiguous matches are rejected instead
|
||||
of guessed.
|
||||
|
||||
Steam access is fixed to `api.steampowered.com` through the configured loopback
|
||||
Mihomo HTTP proxy. There is no direct-network fallback.
|
||||
|
||||
## Config
|
||||
|
||||
Inspect active profile metadata without printing values:
|
||||
|
||||
```sh
|
||||
./tools/jwebot-config.py status
|
||||
```
|
||||
|
||||
Validate and atomically regenerate:
|
||||
|
||||
```sh
|
||||
./tools/jwebot-config.py activate <profile>
|
||||
```
|
||||
|
||||
Services read:
|
||||
|
||||
```text
|
||||
~/.config/jwebot/current/generated/runtime.env
|
||||
```
|
||||
|
||||
Private context, debug state, incidents, and root evidence live outside Git as
|
||||
documented in `config/README.md`.
|
||||
|
||||
## Health
|
||||
|
||||
```sh
|
||||
runtime_python=${JWEBOT_RUNTIME_PYTHON:-/opt/jwebot/venv/bin/python}
|
||||
|
||||
printf '%s\n' '{"op":"health"}' |
|
||||
"$runtime_python" ~/.local/lib/wechat-health-watch/jwebot_edge.py respond
|
||||
|
||||
"$runtime_python" ~/.local/lib/wechat-health-watch/jwebot_edge.py status
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- Edge and adaptive recorder active;
|
||||
- `NRestarts=0` after the settle window;
|
||||
- OCR queues empty;
|
||||
- direct/cloud outboxes empty or actively progressing;
|
||||
- SQLite `PRAGMA quick_check` returns `ok`;
|
||||
- legacy OCR services disabled and inactive.
|
||||
|
||||
## Delivery Contract
|
||||
|
||||
- Fast ACK is persisted before GUI delivery.
|
||||
- Final work starts independently from final GUI delivery.
|
||||
- A final reply is not delivered until its ACK is visibly confirmed.
|
||||
- Steam uses a dedicated progress ACK.
|
||||
- ACK/local work may pass a queued final that has not started.
|
||||
- Active GUI work is non-preemptive.
|
||||
- The GUI sender remains strictly serial.
|
||||
- Every final send rechecks the selected group fingerprint.
|
||||
|
||||
## Failure Handling
|
||||
|
||||
Provider failure:
|
||||
|
||||
- keep credentials and provider payloads out of logs;
|
||||
- record only bounded error classes;
|
||||
- retry through durable queue policy;
|
||||
- do not bypass the configured proxy.
|
||||
|
||||
GUI uncertainty:
|
||||
|
||||
- never blindly replay a send after `send_started`;
|
||||
- preserve the uncertain artifact in private incident state;
|
||||
- require visual/operator confirmation before retry.
|
||||
|
||||
Group mismatch:
|
||||
|
||||
- skip delivery;
|
||||
- keep the event ledgered;
|
||||
- do not select or navigate to another group automatically.
|
||||
|
||||
## Telemetry
|
||||
|
||||
Telemetry may include step name, status, elapsed time, queue state, retry count,
|
||||
and hashed event/group IDs. It must never include message bodies, sender names,
|
||||
reply text, environment values, credentials, SteamIDs, or provider payloads.
|
||||
@@ -0,0 +1,115 @@
|
||||
# Production Deployment
|
||||
|
||||
Use this runbook only after a target host has passed the zero-to-running
|
||||
bootstrap and staging gate.
|
||||
|
||||
## Inputs
|
||||
|
||||
- clean repository snapshot;
|
||||
- active validated profile for the target runtime user;
|
||||
- configured production Python;
|
||||
- operator-provided SSH alias and local privilege elevation;
|
||||
- ready WeChat main window on display `:1`.
|
||||
|
||||
Do not place hostnames, addresses, usernames, passwords, private keys, or
|
||||
profile values in the repository or command history.
|
||||
|
||||
## Local Gate
|
||||
|
||||
```sh
|
||||
PATH="$PWD/.venv/bin:$PATH" ./tools/check-local.sh
|
||||
./tools/check-secrets.py --history
|
||||
```
|
||||
|
||||
## Staging
|
||||
|
||||
Transfer a clean snapshot without `.git`, local profiles, virtualenvs, debug
|
||||
state, captures, databases, or archives. On the target:
|
||||
|
||||
```sh
|
||||
JWEBOT_RUNTIME_PYTHON=/opt/jwebot/venv/bin/python \
|
||||
PATH="/opt/jwebot/venv/bin:$PATH" \
|
||||
./tools/check-local.sh
|
||||
```
|
||||
|
||||
Verify the active profile:
|
||||
|
||||
```sh
|
||||
/opt/jwebot/venv/bin/python -m jwebot_config status
|
||||
/opt/jwebot/venv/bin/python -m jwebot_config validate <profile>
|
||||
```
|
||||
|
||||
## Pre-Cutover
|
||||
|
||||
Confirm:
|
||||
|
||||
1. WeChat main window is visible and meets minimum geometry.
|
||||
2. Edge and adaptive recorder are active with stable restart counts.
|
||||
3. Adaptive and legacy OCR queues are empty.
|
||||
4. Edge direct/cloud outboxes have no failed backlog.
|
||||
5. Edge SQLite `quick_check` is `ok`.
|
||||
6. Legacy OCR services are disabled and inactive.
|
||||
7. A restorable baseline exists.
|
||||
|
||||
## Coordinated Cutover
|
||||
|
||||
Elevate locally on the target and run:
|
||||
|
||||
```sh
|
||||
JWEBOT_RUNTIME_PYTHON=/opt/jwebot/venv/bin/python \
|
||||
./deploy/scripts/deploy-jwebot-production.sh \
|
||||
/path/to/staged/JWeBot \
|
||||
jwebot
|
||||
```
|
||||
|
||||
The deployer prints an eight-stage progress bar and:
|
||||
|
||||
- records root and user service topology;
|
||||
- copies root and user runtime files;
|
||||
- backs up generated configuration;
|
||||
- creates a SQLite online backup and runs `quick_check`;
|
||||
- refuses non-empty queues or an unready WeChat window;
|
||||
- installs the runtime;
|
||||
- leaves legacy OCR disabled;
|
||||
- verifies Edge health and adaptive restart stability;
|
||||
- writes and verifies backup SHA-256 checksums;
|
||||
- rolls back files, state, and unit topology on failure.
|
||||
|
||||
## Post-Cutover
|
||||
|
||||
```sh
|
||||
systemctl --user is-active jwebot-edge.service
|
||||
systemctl --user is-active wechat-ocr-adaptive-recorder.service
|
||||
systemctl --user show wechat-ocr-adaptive-recorder.service \
|
||||
-p NRestarts --value
|
||||
```
|
||||
|
||||
```sh
|
||||
printf '%s\n' '{"op":"health"}' |
|
||||
/opt/jwebot/venv/bin/python \
|
||||
~/.local/lib/wechat-health-watch/jwebot_edge.py respond
|
||||
```
|
||||
|
||||
```sh
|
||||
/opt/jwebot/venv/bin/python - <<'PY'
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
path = Path.home() / ".local/state/jwebot-edge/edge.sqlite3"
|
||||
print(sqlite3.connect(f"file:{path}?mode=ro", uri=True)
|
||||
.execute("pragma quick_check").fetchone()[0])
|
||||
PY
|
||||
```
|
||||
|
||||
Player-visible acceptance must use deliberate synthetic messages in the
|
||||
configured group and confirm exactly one ACK and one final response.
|
||||
|
||||
## Rollback
|
||||
|
||||
If any gate fails:
|
||||
|
||||
1. stop further cutover attempts;
|
||||
2. verify the coordinated deployer's rollback result;
|
||||
3. confirm unit topology and SQLite integrity;
|
||||
4. archive privacy-safe evidence under the active profile;
|
||||
5. fix and rerun staging before another production attempt.
|
||||
@@ -0,0 +1,138 @@
|
||||
# Zero To Running
|
||||
|
||||
This runbook prepares a new apt-based Linux host without embedding any private
|
||||
host, account, group, or provider value in the repository.
|
||||
|
||||
JWeBot does not install desktop WeChat itself. Install a compatible client,
|
||||
create an X11/VNC desktop on display `:1`, sign in manually, and keep the main
|
||||
window visible before deployment.
|
||||
|
||||
## 1. Obtain A Clean Snapshot
|
||||
|
||||
Clone or unpack the public repository. Before using a fork:
|
||||
|
||||
```sh
|
||||
./tools/check-secrets.py --history
|
||||
```
|
||||
|
||||
## 2. Prepare The Host
|
||||
|
||||
Run as root:
|
||||
|
||||
```sh
|
||||
./deploy/scripts/bootstrap-jwebot.sh \
|
||||
prepare \
|
||||
/path/to/JWeBot \
|
||||
jwebot \
|
||||
default
|
||||
```
|
||||
|
||||
The six-stage prepare flow:
|
||||
|
||||
1. installs OS packages for Python, X11 interaction, screenshots, clipboard,
|
||||
and OCR fallback;
|
||||
2. creates the runtime account when absent;
|
||||
3. creates `/opt/jwebot/venv`;
|
||||
4. installs runtime Python dependencies and JWeBot packages;
|
||||
5. generates a private config profile;
|
||||
6. creates private state directories.
|
||||
|
||||
## 3. Configure
|
||||
|
||||
Edit:
|
||||
|
||||
```text
|
||||
/home/jwebot/.config/jwebot/profiles/default/
|
||||
```
|
||||
|
||||
At minimum:
|
||||
|
||||
- set the bot mention and provider URLs in component TOML;
|
||||
- put API keys only in `secrets/runtime.env`;
|
||||
- configure Steam owner ID and loopback proxy when using `/steam`;
|
||||
- put person aliases only in `context/people.json`;
|
||||
- configure a notification argv adapter or leave it disabled;
|
||||
- verify deployment paths.
|
||||
|
||||
Activate as the runtime user:
|
||||
|
||||
```sh
|
||||
sudo -u jwebot -H /opt/jwebot/venv/bin/python \
|
||||
-m jwebot_config activate default
|
||||
```
|
||||
|
||||
## 4. Prepare The Desktop
|
||||
|
||||
The runtime expects:
|
||||
|
||||
- an X11 desktop at `DISPLAY=:1`;
|
||||
- the runtime user's `.Xauthority`;
|
||||
- a visible WeChat main window named `Weixin`;
|
||||
- a maximized window large enough for the adaptive layout gate;
|
||||
- loopback VNC on port `5901` for guarded input;
|
||||
- no second process controlling the same GUI.
|
||||
|
||||
VNC/noVNC must remain loopback-only or be reached through an authenticated SSH
|
||||
tunnel. Never expose it directly.
|
||||
|
||||
## 5. Verify
|
||||
|
||||
```sh
|
||||
./deploy/scripts/bootstrap-jwebot.sh \
|
||||
verify \
|
||||
/path/to/JWeBot \
|
||||
jwebot \
|
||||
default
|
||||
```
|
||||
|
||||
Verify checks runtime imports, required executables, profile validation,
|
||||
repository config/privacy gates, and the visible WeChat window.
|
||||
|
||||
## 6. Deploy
|
||||
|
||||
```sh
|
||||
./deploy/scripts/bootstrap-jwebot.sh \
|
||||
deploy \
|
||||
/path/to/JWeBot \
|
||||
jwebot \
|
||||
default
|
||||
```
|
||||
|
||||
This invokes the coordinated production deployer. It does not bypass queue,
|
||||
ready-window, health, SQLite, or restart-stability gates.
|
||||
|
||||
## 7. Acceptance
|
||||
|
||||
```sh
|
||||
systemctl --user is-active jwebot-edge.service
|
||||
systemctl --user is-active wechat-ocr-adaptive-recorder.service
|
||||
```
|
||||
|
||||
```sh
|
||||
printf '%s\n' '{"op":"health"}' |
|
||||
/opt/jwebot/venv/bin/python \
|
||||
~/.local/lib/wechat-health-watch/jwebot_edge.py respond
|
||||
```
|
||||
|
||||
Send synthetic messages in the configured group:
|
||||
|
||||
```text
|
||||
@JWeBot /version
|
||||
@JWeBot /steam
|
||||
@JWeBot /steam时长Dota2
|
||||
```
|
||||
|
||||
Confirm one ACK, one final reply, no duplicate delivery, empty queues, stable
|
||||
restart counts, and SQLite `quick_check=ok`.
|
||||
|
||||
## Non-Apt Hosts
|
||||
|
||||
Use `prepare` as a dependency manifest:
|
||||
|
||||
- install equivalent X11, OCR, Python, and clipboard packages;
|
||||
- create the same runtime user and virtualenv;
|
||||
- run `jwebot_config init/activate`;
|
||||
- run the verify and coordinated deployment gates manually.
|
||||
|
||||
Do not translate package names into an unreviewed installer and run it directly
|
||||
on production.
|
||||
Reference in New Issue
Block a user