Files
JWeBot/docs/command-routing.md
T
JWeBot Contributors afc71e63a7
check / local-gate (push) Failing after 1m35s
Release beta 1.0.0 baseline
2026-10-16 01:07:07 +08:00

156 lines
5.4 KiB
Markdown

# Command Registration And Execution Paths
Status: authoritative local registration and routing contract for
`beta 1.0.x`.
## Three Execution Paths
Every accepted message resolves to exactly one named execution path:
| Execution path | Input | Runtime | Reply behavior |
|---|---|---|---|
| `local-command` | Registered `/command` | Kernel command or reviewed plugin | Synchronous local reply, except explicitly asynchronous Steam |
| `deepseek` | Ordinary `@JWeBot` message | Direct DeepSeek client | Fast ACK, background generation, ACK-gated final reply |
| `openclaw` | `@JWeBot #task` | OpenClaw cloud runner | Fast ACK, durable cloud outbox, ACK-gated final reply |
The compatibility `route` values remain `local`, `chat`, and `cloud` in stored
events. API responses and telemetry also include the explicit
`execution_path`, so operators and plugin authors do not need to infer the
actual provider from a legacy storage label.
Unknown slash commands remain on `local-command` and fail with a local command
error. They never fall through to DeepSeek or OpenClaw.
## Fast Local Ingress
The local command path is:
1. XDamage reports a relevant message-region change, or a two-second idle
reconciliation capture detects a missed final drawing.
2. OpenCV segments incoming bubbles without running OCR over the whole screen.
3. The OCR engine reuses exact visual-fingerprint matches from a bounded LRU.
4. Only new or changed sender/body crops use RapidOCR.
5. Both recognition-only and detection fallback paths are prewarmed at startup.
6. A command event is written to an atomic, fsynced spool file.
7. The in-process responder is signalled immediately after durable replacement.
8. Edge durably records and executes the local command.
9. The guarded GUI sender revalidates the selected group and sends the reply.
The queue directory remains the recovery source of truth. The wake signal is
only a latency optimization; a separate responder process or a missed signal
still discovers work through the bounded one-second fallback scan.
Exact image bytes, crop dimensions, and sender pixels participate in the OCR
cache key. Identical repeated messages remain separate visible occurrences
because each bubble position still produces its own `IncomingMessage`.
Changed pixels force fresh OCR. The cache is bounded and periodically
revalidated.
For the local plugins introduced during the 0.6.x line, including bilingual
commands, person identity limitations and atomic single-player game settlement,
see [local plugin rules](local-plugins-0.6.1.md).
## Bundled Plugin Registration
Bundled command metadata has one source:
```text
packages/jwebot-official-extensions/
src/jwebot_official_extensions/descriptors.py
```
Each `LocalExtensionDescriptor` declares:
- `extension_id`;
- `author`;
- user-visible `description`;
- user-visible `help_entries`;
- owned internal `command_kinds`.
Aliases are resolved from the same inventory. Run:
```sh
./tools/sync-local-extensions.py
```
The generator writes matching:
- `plugin.toml`;
- SDK adapter source;
- package README;
- package registration test;
- in-process compatibility adapter.
`--check` is part of the repository gate and rejects generated drift.
## Friend Plugin Registration
Create a command plugin with explicit user-facing metadata:
```sh
./tools/create-plugin.py weather-command /weather \
--author FriendName \
--description "查询指定城市天气" \
--help-entry "/weather 城市"
```
The command must also be registered in the plugin entrypoint:
```python
def plugin(context):
context.commands.register("/weather", handle)
```
Startup fails if registered commands differ from signed manifest commands.
The catalog freezes after startup, so command ownership cannot change during
request processing.
## Automatic Help
`/功能列表`, `/帮助`, and `/help` are Kernel commands. Their visible output is
generated from:
- Kernel command descriptors;
- each bundled plugin's `description`;
- each bundled plugin's `help_entries`;
- the fixed DeepSeek and OpenClaw path descriptions.
There is no separate hand-maintained help list. Adding or changing a bundled
plugin command without updating its descriptor changes generated files and
fails the sync gate.
Signed Host health responses include description and help metadata. Edge
compares them with the startup inventory together with author, commands, and
service profiles before activating the Host.
## Manifest Metadata
Command manifests must declare:
```toml
description = "查询指定城市天气"
help = ["/weather 城市"]
```
`description` and `help` must be declared together. Help entries are bounded,
single-line command usage strings beginning with `/`. Bundled plugins require
both fields.
User-visible help text is metadata only. It grants no capability and cannot
change routing ownership.
## Official Operational Plugins
Operational slash commands are implemented through official reviewed plugin
descriptors unless they are strictly Kernel-only. The current official
operational commands are:
- `/状态` and `/status`: server, Edge, OCR, and queue status.
- `/version`: installed JWeBot package versions plus the latest changelog date
and summary.
- `/debug`: recent privacy-safe telemetry p50/p95/max summary.
These commands delegate to Kernel-owned service profiles through generated
adapters. They do not give plugin code direct access to raw SQLite, systemd,
journal, GUI, shell, or secrets.