# Linux-, FreeBSD-, NetBSD-, Windows-, macOS- und Android-Geräte

> HTML: https://remote.ivjn.us/docs/de/platforms/

Linux (glibc / musl), FreeBSD, NetBSD, Windows, macOS und Android verwenden gemeinsam `remote-agent`, Exchange, `remote-cli` und den mobilen Administrationsclient. Geräteprogramm und CLI verwenden allgemeine Namen; Umgebungsvariablen heißen einheitlich `REMOTE_*`.

## Installation mit einem Befehl (Windows / Linux / macOS / FreeBSD / NetBSD)

Das Skript der offiziellen Website lädt das passende geprüfte Paket herunter und legt die Programme unter `~/.local/bin` ab. Der Agent registriert mit `remote-agent install` den automatischen Start bei Anmeldung:

Wählen Sie den passenden Befehl und kopieren Sie jeden Befehl einzeln.

**Agent auf dem verwalteten Gerät installieren**

```sh
curl -fsSL https://remote.ivjn.us/install.sh | bash -s -- agent
```

**CLI auf dem Bediengerät installieren**

```sh
curl -fsSL https://remote.ivjn.us/install.sh | bash -s -- cli
```

Unter Windows in Git Bash ausführen. Die Zugangsdaten müssen hinter der Pipe stehen: `bash -s -- agent --device-id NAME --token TOKEN` (oder vorhandene `config.json` / `REMOTE_CONFIG` verwenden). Vor `curl` gesetzte Umgebungsvariablen erreichen bash nicht. Für systemweites systemd unter Linux `--system` ergänzen. Das Skript unterscheidet automatisch glibc und musl (etwa Alpine), auch Linux arm64 (aarch64) wird unterstützt. `REMOTE_LIBC=musl` erzwingt das musl-Paket. FreeBSD / NetBSD: Benutzerinstallationen bleiben in `~/.local/bin`; `sudo remote-agent install --system --config CONFIG` registriert rc.d. Desktopsteuerung benötigt eine X11-Sitzung mit `python3` und `xdotool`. Android und OpenWrt verwenden eigene Pakete.

## Befehle und Dienste

Die Geräte- und CLI-Befehle heißen `remote-agent` und `remote-cli`. `remote-cli` schreibt standardmäßig nach `remote-cli/config.toml`; ein explizites `REMOTE_CLI_CONFIG` hat Vorrang.

OpenWrt-Paket, UCI-Datei und init-Dienst heißen `remote-agent`. Die Statusdatei ist `/var/run/remote-agent.state`, die Konfigurationsdatei `/etc/config/remote-agent`. Das LuCI-Plugin `luci-app-remote` benötigt dieses Paket. `REMOTE_AGENT_SRC` legt den Quellpfad für den Build fest.

| Gerät | Befehlsausführung | Interaktives Terminal | Dauerbetrieb | ubus |
|---|---|---|---|---|
| Linux | `/bin/sh -c` | Unix PTY | systemd oder Vordergrundprozess | Nur OpenWrt |
| Linux musl (Alpine 3.x usw.), x64 / arm64 | `/bin/sh -c` | Unix PTY | Vordergrundprozess oder eigener OpenRC-Dienst (kein systemd) | Nicht unterstützt |
| FreeBSD 14+, amd64 / arm64 | `/bin/sh -c` | Unix PTY | rc.d (root/System); Vordergrund (Benutzer) | Nicht unterstützt |
| NetBSD 10+, amd64 | `/bin/sh -c` | Unix PTY | rc.d (root/System); Vordergrund (Benutzer) | Nicht unterstützt |
| Windows 10 1809+/11, Server 2019+ | Windows PowerShell 5.1 | ConPTY + PowerShell | Anmeldeaufgabe oder Vordergrundprozess | Nicht unterstützt |
| macOS 11+, Apple Silicon / Intel | `/bin/sh -c` | Unix PTY | launchd LaunchAgent oder Vordergrundprozess | Nicht unterstützt |
| Android 8.0+, arm64 / x86_64 | `/system/bin/sh -c` | Unix PTY | Vordergrunddienst der eigenständigen APK | Nicht unterstützt |

## Allgemeine Konfiguration

Zuerst mit `remote-cli device add <id>` das Gerät registrieren und das Gerätetoken beziehen. Unter Linux/Windows eine nur für das ausführende Konto lesbare `config.json` erstellen:

```json
{
  "server": "wss://mgmt.example.com",
  "device_id": "my-device",
  "token": "REPLACE_WITH_DEVICE_TOKEN"
}
```

```sh
remote-agent --config /path/to/config.json
```

Vorrang haben Kommandozeile bzw. `REMOTE_SERVER`, `REMOTE_DEVICE_ID`, `REMOTE_TOKEN`, danach JSON und zuletzt ausschließlich unter OpenWrt UCI. JSON unterstützt `state_file`; `--state-file` / `REMOTE_STATE_FILE` überschreiben dies. Ohne explizite Statusdatei verwendet OpenWrt `/var/run/remote-agent.state`; andere Plattformen `remote-agent/agent.state` unter dem ersten verfügbaren Verzeichnis aus `LOCALAPPDATA`, `XDG_STATE_HOME`, `$HOME/.local/state`, ohne Benutzerverzeichnis ersatzweise das temporäre Verzeichnis. Mehrere Instanzen benötigen getrennte Statuspfade.

Für produktive Verbindungen `wss://` verwenden. `ws://127.0.0.1` in Beispielen dient nur lokalen Prüfungen.

### Benachrichtigungen zur Agent-Verbindung

JSON unterstützt `"notify_urls": ["https://example.invalid/notify"]`, alternativ `remote-agent --notify-url https://example.invalid/notify` (wiederholbar). `REMOTE_NOTIFY_URL` akzeptiert kommagetrennte Adressen. Nicht leere Kommandozeilen-/Umgebungslisten ersetzen JSON; andernfalls gilt JSON und zuletzt, nur unter OpenWrt, der kommagetrennte UCI-Wert `remote-agent.main.notify_url`. Sind alle Quellen leer oder ausgelassen, ist POST deaktiviert.

Nach erfolgreicher Registrierung wird `agent.connected` gesendet, beim Ende einer bestehenden Sitzung einmal `agent.disconnected`, bei ausdrücklicher Ablehnung nur `agent.rejected`. Netzwerkfehler vor Registrierung lösen keine Benachrichtigung aus. POST verwendet dasselbe JSON-Objekt wie Exchange Web Push (`title`, `body`, `url`, `event`, `device_id`, `occurred_at`), beschreibt aber die Agent-Verbindung statt des Geräte-Onlinestatus: Präfix `agent.` statt `device.` in `event`, `url` ist `""` (kein Web-Push-Konsolenpfad), kein `tag`. Trennungs-/Ablehnungstexte enthalten eine kurze sichere Begründung ohne Gerätetoken; Zeitangaben sind RFC3339 UTC.

Benachrichtigungen laufen im Hintergrund; bei Fehlern wird nur der Ereignisname protokolliert, keine Zieladresse, und die Wiederverbindung nicht blockiert. Wie bei Exchange Web Push höchstens 5 Versuche, Wiederholungen bei Netzwerkfehlern und HTTP 408/429/5xx, Verwerfen bei 404/410 und anderen nicht wiederholbaren 4xx. Ganzzahlige Sekunden aus `Retry-After` haben Vorrang, sonst exponentielles Backoff ab 5 Sekunden, begrenzt auf 1–900 Sekunden. Nur HTTP/HTTPS, keine Weiterleitungen. Keine Benutzernamen, Passwörter oder sonstigen Zugangsdaten in URLs; Adressen mit Benutzername/Passwort werden abgelehnt.

### Ausgehende Proxys und Verbindungserhaltung

Headless und `--ui` verbinden über dasselbe `client::run` mit Exchange. WebSocket liest geerbte Proxyvariablen des Agent-Prozesses: erster nicht leerer Wert aus `HTTPS_PROXY` / `https_proxy`, `ALL_PROXY` / `all_proxy`, `HTTP_PROXY` / `http_proxy`. Hosts passend zu `NO_PROXY` / `no_proxy` umgehen den Proxy. `remote-cli` verwendet dieselben Regeln (#36/#37, #39). Anmeldestart und Hintergrunddienste benötigen diese Variablen in ihrer Laufzeitumgebung; Setzen in einem anderen Terminal erreicht gestartete Prozesse nicht.

WSS über Proxy baut zuerst einen **HTTP CONNECT**-Tunnel und verbindet dann das Ziel mit rustls. ALPN im TLS ClientHello meldet wie die CLI **nur `http/1.1`**. Aushandeln von `h2` beschädigt den aktuellen HTTP/1.1-WebSocket-Upgrade-Pfad. Bei hängendem Verbindungsaufbau mit Proxys wie Clash CONNECT-Unterstützung prüfen und Builds mit #39/#42 verwenden. Geräte- und CLI-WebSocket unterstützen kein SOCKS; HTTP-CONNECT-Proxy verwenden (etwa `HTTPS_PROXY=http://127.0.0.1:7890`).

Nach direktem Aufbau oder CONNECT aktiviert der Agent `TCP_NODELAY` und TCP-Keepalive nach 30 Sekunden Leerlauf. Jeder JSON-Heartbeat sendet auch WebSocket-Ping; auf Ping wird das automatisch eingereihte Pong ausdrücklich geflusht. Verbindungsaufbau und Registrierungsantwort haben jeweils 45 Sekunden Zeitlimit, Senden und Pong-Flush nach Registrierung 30 Sekunden. Siehe [Verbindungserhaltung und Zeitlimits](/docs/de/websocket-protocol.md#verbindungserhaltung-und-zeitlimits) (#42).

Windows-Builds mit `desktop-ui` verwenden auch headless eine mehrthreadige Tokio-Laufzeit, die axum, das lokale Tray und den Geräte-WebSocket parallel ausführt. Auf anderen Plattformen mit diesem Feature nutzt die lokale UI (explizites `--ui` oder Start ohne Argumente) ebenfalls mehrere Threads. Builds ohne das Feature und Headless-Aufrufe mit expliziter Konfiguration auf anderen Plattformen verwenden das für kleine Geräte geeignete `current_thread`.

## Konfigurationsoberfläche für Linux / Windows / macOS

Builds aktivieren `desktop-ui` standardmäßig. Desktop-Veröffentlichungen müssen die lokale Konfigurationsoberfläche enthalten. Verwenden Sie `--no-default-features` nur für Server ohne Oberfläche oder eingebettete Systeme. Bei bestehender Verbindung sind die Eingaben für Verwaltungsserver, Geräte-ID und Token ausgeblendet. Nach dem Stoppen des Fernzugriffs erscheinen sie wieder. Verbindungsstatus, LAN-Einstellungen und Autostart bleiben sichtbar.

```sh
cargo build --locked -p agent --release
# Linux / macOS
./target/release/remote-agent --ui
```

```powershell
# Windows
.\target\release\remote-agent.exe --ui
```

Bei Start ohne Verbindungsparameter unter Linux / Windows / macOS (etwa Doppelklick auf `remote-agent.exe`) mit `desktop-ui` wird bei fehlender nutzbarer Konfiguration eine Standard-`config.json` geschrieben (nur Standard-Exchange vorbelegt, device_id/token leer) und die Browserkonfiguration geöffnet. Bei vorhandener Konfiguration verwendet Windows das Tray ohne erzwungenes Browseröffnen; Linux/macOS geben die lokale URL aus (macOS hat zusätzlich ein Symbol in der Menüleiste). Interaktiver parameterloser Start ohne `desktop-ui` erstellt die Standardkonfiguration, gibt ihren Pfad aus und beendet sich, statt nur `Missing device_id` anzuzeigen. OpenWrt / systemd / geplante Aufgaben verwenden weiterhin `--config`, UCI oder `REMOTE_*`.

Ein Start ohne Argumente und explizites `--ui` verwenden dieselbe Regel: Der Standardbrowser öffnet sich nur, wenn die gespeicherte Konfiguration keinen nichtleeren `device_id`/`token`-Wert enthält. Konfigurierte Agenten verbinden sich im Hintergrund, ohne bei der Anmeldung erneut den Browser zu öffnen. Windows behält den Tray-Eintrag zum manuellen Öffnen; Linux/macOS verwenden die lokale URL im Terminal. `--ui --no-open` verhindert das automatische Öffnen auch bei der Ersteinrichtung. `--ui-port 8765` setzt einen festen Port; sonst wird ein freier Port zufällig gewählt. Die UI lauscht ausschließlich auf `127.0.0.1`. Alle Ressourcen sind eingebettet, ohne externe Schriftarten oder CDNs.

Das Windows-Tray und die macOS-Menüleiste bieten Einträge für die Konfiguration, den Bildschirmschoner, die Aufgabenverwaltung und Zwischenablageaktionen. Die Aufgabenverwaltung öffnet direkt das lokale Aufgabenpanel. Linux verwendet die Konfigurationsseite im Browser.

Mit `remote-cli device add <id>` Geräte-ID und Token beziehen, dann Server, Geräte-ID und Token unter **Connection settings** eintragen:

- **Save only**: Speichern ohne Serververbindung.
- **Save and connect**: Speichern und verbinden; Änderungen im Betrieb trennen die alte und starten eine neue Verbindung.
- **Stop remote access**: Trennen und aktuelle Fernausführungen und Terminalsitzungen abbrechen; Konfiguration bleibt erhalten.
- Die Statusleiste zeigt nach Registrierung **Connected**, sonst Verbindungsaufbau, Wiederverbindung oder gestoppt sowie den letzten Verbindungsfehler.

Die UI schreibt beim Verbindungsbeginn zuerst **Connecting** in ihre Statusdatei und startet danach `client::run`, damit die Seite nicht beim Standardwert einer fehlenden Statusdatei stehen bleibt (#42).

Gespeicherte Token werden nicht an die Webseite zurückgesendet; leer bedeutet bisherigen Token behalten. Die Konfiguration wird über eine temporäre Datei atomar ersetzt, unter Linux mit `0600`, unter Windows mit ACL nur für den aktuellen Benutzer. Beschädigtes oder unlesbares JSON führt zur Reparaturaufforderung ohne Überschreiben der Originaldatei. Nur ein UI-Prozess kann dieselbe Konfiguration öffnen.

Standardpfad unter Linux/macOS ist `$XDG_CONFIG_HOME/remote-agent/config.json` (sonst `~/.config/remote-agent/config.json`), unter Windows `%LOCALAPPDATA%\remote-agent\config.json`. `--ui --config <path>` oder `REMOTE_CONFIG` wählen vorhandenes JSON. Die UI akzeptiert keine Überschreibungen per `--server`, `--device-id`, `--token`, `--state-file` und entsprechenden Umgebungsvariablen, damit gespeicherte Werte und Verbindung übereinstimmen. JSON `state_file` gilt auch für die UI; ohne Angabe wird derselbe dauerhafte Standardpfad wie bei headless verwendet, damit versiegelte Identität und Vertrauen erhalten bleiben.

Die Seite bietet **Start at login / Start bei Anmeldung** (`autostart: { supported, enabled, detail }` in `GET /api/status`; `POST /api/autostart` erhält `{ "enabled": true|false }`). Keine Rechteerhöhung nötig:

- **macOS**: Installiert/entfernt `~/Library/LaunchAgents/us.ivjn.remote-agent.plist` (Vorlage wie `install/macos/install.sh`), mit `launchctl bootstrap` / `bootout`. Programm bevorzugt nach `~/.local/bin/remote-agent`, Konfiguration standardmäßig `~/.config/remote-agent/config.json` (vorhandene bleibt erhalten).
- **Windows**: Registriert/entfernt Benutzeraufgabe `RemoteAgent` (AtLogOn), entsprechend `install/windows/install.ps1`, Installationsverzeichnis `%LOCALAPPDATA%\remote-agent`.
- **Linux**: Installiert/entfernt systemd-Benutzereinheit (`install/linux/remote-agent.service`), `systemctl --user enable --now` / `disable`.

Beim Aktivieren wird das aktuelle Programm bei Bedarf zum vereinbarten Installationspfad kopiert, vorhandene `config.json` bleibt erhalten. Antworten und Logs geben keine Token aus. Die UI verwaltet den aktuellen Prozess; nach Autostartaktivierung und Verlassen der UI startet LaunchAgent / Aufgabenplanung / systemd den Hintergrundagenten bei nächster Anmeldung.

**Das Schließen des Browsertabs stoppt den Agenten nicht; das Beenden des Agent-Prozesses trennt die Verbindung. Eine konfigurierte UI verbindet sich beim Start automatisch; die Ersteinrichtung benötigt Save and connect.** Die UI verwaltet den aktuellen Prozess und kann den Anmeldestart ein- oder ausschalten. Vor einer weiteren UI-Instanz für dasselbe Gerät den vorhandenen Hintergrunddienst stoppen. Nach Konfiguration und Autostartaktivierung kann der Tab geschlossen werden. Fernaktionen verwenden die Rechte des Agent-Kontos.

Die lokale URL enthält einen zufälligen Zugriffsschlüssel dieser UI-Sitzung, nicht teilen. Die API prüft auch Host und Origin und lehnt externe Webseitenaufrufe ab. Das Gerätetoken liegt unverschlüsselt in der Konfiguration; aktueller lokaler Benutzer und Administratoren können es lesen. Schlanke Builds ohne `desktop-ui` behalten das bisherige Kommandozeilenverhalten; OpenWrt und Android verwenden ihre eigenen Oberflächen.

## FreeBSD

Die Website bietet `remote-freebsd-x64.tar.gz` und `remote-freebsd-arm64.tar.gz` (unter Linux mit `cargo zigbuild` crosskompiliert, gegen FreeBSD 14 libc gelinkt). Nach dem Entpacken:

```sh
mkdir -p ~/.local/bin
cp remote-agent remote-cli ~/.local/bin/
sudo remote-agent install --system --device-id NAME --token TOKEN
```

Der aktuelle Quellcode unterstützt rc.d-Systeminstallation, sysctl-Metriken, Schnittstellenzähler mit `netstat -ibn`, FreeBSD-Temperatur/Lüfter und NetBSD `envstat`. X11-Steuerung wird bei vorhandenem `DISPLAY`, `python3` und `xdotool` gemeldet; Screenshots benötigen zusätzlich Pillow. Medien und Systemeinstellungen bleiben nicht verfügbar. Selbstaktualisierung erkennt BSD-x64/arm64-Archive, wenn ein geprüftes Paket im Veröffentlichungsmanifest vorhanden ist. Neue Pakete und native BSD-Laufzeittests sind erforderlich.

## NetBSD

Die Website bietet `remote-netbsd-x64.tar.gz` (amd64, unter Linux mit zig gegen NetBSD 10 libc crosskompiliert; dynamische Abhängigkeiten nur libc / libpthread / libutil). Verwendung wie FreeBSD:

```sh
mkdir -p ~/.local/bin
cp remote-agent remote-cli ~/.local/bin/
sudo remote-agent install --system --device-id NAME --token TOKEN
```

Fähigkeiten: Exchange-Verbindung, `exec` / PTY / Dateiübertragung; Metriken über sysctl (`kern.cp_time`, `hw.physmem64`, `vm.uvmexp2`); Desktop-GUI-Steuerung nur als Platzhalter, nicht gemeldet. Plattformmeldung `netbsd`. Selbstupdate und rc.d-Neustart funktionieren wie unter FreeBSD (`remote-netbsd-x64.tar.gz` / `remote-netbsd-arm64.tar.gz`), sofern das Manifest das Archiv enthält.

## Offizielle OpenWrt-25.12-Pakete

Die Website bietet `remote-agent`, paketiert mit dem offiziellen OpenWrt 25.12.5 SDK (apk-tools, Paketversion `0.1.29-r1`, enthält Agent 0.1.29):

| target | Paketarchitektur | Datei |
|---|---|---|
| ipq40xx/generic | arm_cortex-a7_neon-vfpv4 | `remote-agent-openwrt-ipq40xx-official.apk` |
| x86/64 | x86_64 | `remote-agent-openwrt-x86_64-official.apk` |
| armsr/armv8 | aarch64_generic | `remote-agent-openwrt-armsr-armv8-official.apk` |
| mediatek/filogic | aarch64_cortex-a53 | `remote-agent-openwrt-mediatek-filogic-official.apk` |
| bcm27xx/bcm2711 | aarch64_cortex-a72 | `remote-agent-openwrt-bcm27xx-bcm2711-official.apk` |
| ramips/mt7621 | mipsel_24kc | `remote-agent-openwrt-ramips-mt7621-official.apk` |
| ath79/generic | mips_24kc | `remote-agent-openwrt-ath79-official.apk` |

Universelle LuCI-Oberfläche: `luci-app-remote-openwrt-official.apk`. Mit `apk --print-arch` Architektur prüfen, dann `apk add --allow-untrusted ./文件.apk`. MIPS benötigt zusätzlich `libgcc1` (in offiziellen Images enthalten).

## Linux musl (Alpine) und arm64

- `remote-linux-arm64.tar.gz`: aarch64, glibc 2.28+ (Debian 10+/Ubuntu 18.04+/RHEL 8+, Raspberry Pi mit 64-Bit-System usw.), unterstützt systemd-Registrierung per `remote-agent install` und Selbstaktualisierung.
- `remote-linux-musl-x64.tar.gz` / `remote-linux-musl-arm64.tar.gz`: statisch gegen musl gelinkt für Distributionen ohne glibc wie Alpine. Alpine hat standardmäßig kein systemd; mit `remote-agent install --no-start` konfigurieren und einen eigenen OpenRC-Dienst (`/etc/init.d/remote-agent`) schreiben oder im Vordergrund starten. musl-Builds unterstützen `update self` und Desktop-Auto-Updates und installieren nur das musl-Archiv; nach einem einmaligen Update versuchen sie systemd, dann OpenRC (`rc-service remote-agent restart`), dann einen Prozessneustart. Ein musl-Archiv auf einem OpenWrt-Host wird weiter über opkg/apk aktualisiert.

## Linux

Empfohlen ist der integrierte Unterbefehl (kopiert das aktuelle Programm, schreibt private Konfiguration und registriert systemd, ohne `install/`-Dateien aus dem Repository):

```sh
cargo build --locked -p agent --no-default-features --profile release-small
# 用户级（默认，非 root）
./target/release-small/remote-agent install \
  --config /path/to/config.json
# 或直接传凭证（无需先有文件；安装过程不访问网络）
./target/release-small/remote-agent install \
  --device-id NAME --token TOKEN

# 系统级（root 或 --system）：/usr/local/bin + /etc/remote-agent + multi-user.target
sudo ./target/release-small/remote-agent install --system \
  --device-id NAME --token TOKEN

remote-agent status                    # 安装布局、服务、进程、连接（不打印令牌）
systemctl --user status remote-agent   # 用户级
# systemctl status remote-agent        # 系统级
remote-agent uninstall                 # 卸服务；加 --force 同时删二进制与配置
```

Gleichwertige manuelle Schritte (weiterhin möglich):

```sh
install -Dm755 target/release-small/remote-agent ~/.local/bin/remote-agent
install -Dm600 /path/to/config.json ~/.config/remote-agent/config.json
install -Dm644 install/linux/remote-agent.service ~/.config/systemd/user/remote-agent.service
systemctl --user daemon-reload
systemctl --user enable --now remote-agent
```

Benutzerdienste laufen standardmäßig mit der Anmeldesitzung. Für Dauerbetrieb ab Boot lässt ein Administrator `loginctl enable-linger <user>` ausführen oder verwendet die obige `--system`-Einheit (`RuntimeDirectory=remote-agent`, `WantedBy=multi-user.target`). Fernbefehle verwenden Dienstkontorechte. Stoppen beendet alle Prozesse im Dienst. `install/linux/install.sh` ist ein dünner Wrapper um `remote-agent install --force`.

## Windows

Nach Installation der Rust-MSVC-Toolchain und Visual Studio C++ Build Tools:

```powershell
cargo build --locked -p agent --release
.\target\release\remote-agent.exe --config C:\path\config.json

# 推荐：为当前登录用户安装常驻计划任务
.\target\release\remote-agent.exe install --config C:\path\config.json
# 已存在任务/文件时加 --force；仅注册不启动加 --no-start
Get-ScheduledTaskInfo -TaskName RemoteAgent
remote-agent status
remote-agent uninstall
remote-agent uninstall --force   # 同时删除 %LOCALAPPDATA%\remote-agent 下的文件
```

`install` kopiert Programme und Konfiguration nach `%LOCALAPPDATA%\remote-agent`, beschränkt Konfigurations-ACL und registriert die Anmeldeaufgabe `RemoteAgent`. Vorhandene Aufgabe oder Zieldateien verursachen standardmäßig Fehler; `--force` stoppt und entfernt zuerst die alte Aufgabe und überschreibt dann. Dieser Modus benötigt Benutzeranmeldung und ist kein Windows-SCM-Systemdienst. `install/windows/install.ps1` ist ein dünner Wrapper um `remote-agent install` (optional `-Force`).

Wurde die Konfiguration über die UI erstellt, kann `--config` auf einen separaten Pfad zeigen (etwa die Datei aus `--ui --config .\device-config.json`).

Windows-Befehle verwenden PowerShell-Syntax wie `Get-Process`, Ausgabe als UTF-8. Jede Ausführungssitzung und jedes Terminal hat ein eigenes Job Object; Timeout, Abbruch, Trennung und Agent-Ende bereinigen den jeweiligen Kindprozessbaum.

## macOS

Benötigt wird die Rust-Toolchain (`rustup`, mit Standardtarget `aarch64-apple-darwin` oder `x86_64-apple-darwin`). Metriken kommen aus sysctl, `getloadavg(3)` und mach `host_statistics`; statische Informationen (Modell, Kernel, Systemversion) aus `sysctl` und `sw_vers`. Plattformmeldung `macos`.

Sensoren werden auf Abruf (nicht im Heartbeat) bestmöglich ohne sudo und zusätzliche SMC-Abhängigkeit gelesen: Batterie per `pmset -g batt` (Notebooks), CPU_Speed_Limit / Scheduler / Available CPUs und thermischer Druck per `pmset -g therm`, AppleSmartBattery-`Temperature` und Lüfter-RPM per `ioreg` (falls Firmware sie bereitstellt). Desktops wie Mac mini haben oft keine Batterie; Apple Silicon möglicherweise keinen numerischen CPU_Speed_Limit. CPU-die-/proximity-Temperaturen benötigen private IOKit/SMC und werden derzeit nicht ausgelesen. Sobald thermischer Druck, Drosselung oder Lüfterwerte vorliegen, gilt `thermal` nicht als unavailable. Mit `desktop-ui` kann `remote-agent --ui` konfigurieren und Anmeldestart (LaunchAgent) umschalten.

```sh
cargo build --locked -p agent --release

# 推荐：安装为随登录会话运行的 LaunchAgent（无需 sudo）
./target/release/remote-agent install --config ~/.config/remote-agent/config.json
# 或：install/macos/install.sh ~/.config/remote-agent/config.json
remote-agent status
launchctl print gui/$(id -u)/us.ivjn.remote-agent | grep state
```

`remote-agent install` kopiert das aktuelle Programm nach `~/.local/bin/remote-agent`, schreibt `~/.config/remote-agent/config.json` (Rechte 600), erzeugt `~/Library/LaunchAgents/us.ivjn.remote-agent.plist`, führt `codesign -s - --force` aus (macOS beendet unsignierte direkt ersetzte Programme) und dann `launchctl bootstrap` / `kickstart`. `RunAtLoad` + `KeepAlive` starten bei Anmeldung und lassen launchd nach Absturz oder Trennung neu starten. Logs: `~/Library/Logs/remote-agent.log`. `install/macos/install.sh` ist ein dünner Wrapper. Ohne explizite Statusdatei gilt `$HOME/.local/state/remote-agent/agent.state`. Fernbefehle laufen mit Rechten des angemeldeten Benutzers.

Stoppen/deinstallieren:

```sh
remote-agent uninstall
# 或手动：
# launchctl bootout gui/$(id -u)/us.ivjn.remote-agent
# rm ~/Library/LaunchAgents/us.ivjn.remote-agent.plist
```

Für Dauerbetrieb ab Boot ohne Anmeldung einen LaunchDaemon unter `/Library/LaunchDaemons` als root laden. Fernbefehle laufen dann mit root-Rechten; Risiko entsprechend bewerten.

## Eigenständige Android-APK

Geräteprojekt: `android-agent/`. `mobile/` bleibt Administrationsclient; beide sind getrennt installierbar, ohne Expo Go, Termux oder root.

Standardadresse aller Agenten ist `wss://exchange.ivjn.us`. Unter Android **Connect with a six-digit code** wählen; nach Freigabe des sechsstelligen Codes durch die Administrator-CLI erhält das Gerät automatisch seine Identität. Native Agenten (lokale Windows/macOS-Seite, OpenWrt LuCI „Gerät hinzufügen“, `remote-agent pair` / `remote-agent join <邀请>`) können sechsstelligen Code und QR-Code zur Freigabe durch Console-Scan anzeigen oder über eine eingefügte einmalige Einladung beitreten. Siehe [Initialisierung und Kopplung](/docs/de/pairing-and-enrollment.md).

### Erste Verbindung und Startseite

1. Öffnen Sie **Remote Agent** auf dem Android-Gerät, das verwaltet werden soll. Wählen Sie zuerst **Mit einem sechsstelligen Code verbinden** oder **Verbindungs-QR-Code scannen** und lassen Sie den Zugriff durch einen Administrator genehmigen. Die Abläufe für Konten, QR-Codes und sechsstellige Codes stehen unter [Initialisierung und Kopplung](/docs/de/pairing-and-enrollment.md).
2. Wenn Geräte-ID und Gerätetoken vorliegen, öffnen Sie **Einstellungen → Verbindungseinstellungen**, tragen Server und Zugangsdaten ein und wählen **Speichern und verbinden**. Bei aktivierter Verbindung sind die Eingabefelder ausgeblendet. Trennen Sie die Verbindung auf der Startseite, bevor Sie die Geräteidentität ändern.
3. Die Startseite zeigt Verbindungsstatus, Bildschirmfreigabe und Verwalterliste. Bei gespeicherter Konfiguration und deaktivierter Verbindung wählen Sie **Gerät verbinden**. Beim erneuten Öffnen der App wird eine aktivierte Verbindung wiederhergestellt.

Android 12 und neuer verwenden den Systemstartbildschirm; Android 8–11 zeigen einen Start-Hintergrund mit denselben Markenfarben. Sobald das erste Bild bereitsteht, öffnet sich die Startseite, ohne auf die Netzwerkverbindung zu warten oder eine Mindestanzeigedauer einzufügen. Bei deaktivierten Systemanimationen entfallen die Übergänge. Einstellungen werden bei Bedarf geladen. Das Öffnen der Startseite erteilt keine Berechtigung für Bedienungshilfen oder Bildschirmfreigabe. Dies beschreibt den aktuellen Quellcode; prüfen Sie bei öffentlichen Downloads die installierte Version.

### Hintergrundbetrieb, Benachrichtigungen und Beenden

Der Wechsel in den Hintergrund oder das Schließen der Oberfläche beendet den Vordergrunddienst nicht. Nach einem Netzwerkausfall verbindet sich der Agent erneut. Bei aktivierter Verbindung versucht er, den Dienst nach Geräteneustart und Entsperren oder nach einem App-Update wiederherzustellen. Nach erzwungenem Beenden muss die App manuell geöffnet werden. Energiesparregeln des Herstellers können eine zusätzliche Freigabe für den Hintergrundbetrieb verlangen.

Bei erlaubten Benachrichtigungen führt **Verbindung verwalten** zurück zur App. Während einer Freigabe beendet **Freigabe beenden** in der Benachrichtigung nur die Bildschirmfreigabe. Um den Fernzugriff zu trennen und die automatische Wiederherstellung zu deaktivieren, wählen Sie auf der Startseite **Trennen** und bestätigen. Die Konfiguration bleibt für eine spätere Verbindung über **Gerät verbinden** erhalten. Auch **Bildschirmfreigabe beenden** auf der Startseite beendet nur die Freigabe, nicht den Fernzugriff.

Das Gerätetoken wird mit Android Keystore AES-GCM verschlüsselt gespeichert. Die Konfiguration ist von Sicherungen ausgeschlossen; exportierte Activities oder Services geben keine Token weiter. Fernbefehle laufen unter der Anwendungs-UID der APK und unterliegen Android-Sandbox und SELinux. Sie gewähren weder Zugriff auf Daten anderer Apps noch Root-Rechte. Systemeinstellungen, Bedienungshilfen und Bildschirmfreigabe benötigen jeweils eigene Berechtigungen.

Bei aktiviertem Fernzugriff hält der Vordergrunddienst CPU- und Bildschirm-Wake-Locks. Der Bildschirm bleibt dadurch auch im Hintergrund und bei erneuter Verbindung an, was mehr Strom benötigt. Beim Trennen oder Beenden des Dienstes werden die Sperren freigegeben und die normale Bildschirmabschaltung wiederhergestellt. Die Ein-/Aus-Taste sperrt das Gerät weiterhin regulär und umgeht keine Anmeldung. Benachrichtigungen zeigen Verbindungs- oder Freigabestatus; die Startseite bietet die Trennfunktion.

### Aus dem Quellcode bauen

Beginnen Sie jedes folgende Debug- oder Release-Beispiel im Repository-Stamm. Prüfen Sie vor der Installation die Geräteliste und ersetzen Sie DEVICE_SERIAL durch die Seriennummer des Zielgeräts. Paketbau, Unit-Tests und vollständiges Lint sind getrennte Prüfungen. Bei Lint-Fehlern den Bericht prüfen und die Ursache beheben oder dokumentieren. Überspringen gilt nicht als Bestehen.

Buildvoraussetzungen: JDK 17+, Android SDK Platform 36, NDK `28.2.13676358`, Python 3 und Rust. `ANDROID_HOME` (oder `ANDROID_SDK_ROOT`) setzen; eigenen NDK-Pfad mit `ANDROID_NDK_HOME`. Vollbild-`.Aran` benötigt Metafile Android SDK: Repository `Metafile` neben `remote-control` ablegen (Gradle referenziert `:aran` über `../../Metafile/android-sdk/aran`).

```sh
rustup target add aarch64-linux-android x86_64-linux-android
cd android-agent
./gradlew :app:assembleDebug :app:testDebugUnitTest
# Windows: .\gradlew.bat :app:assembleDebug :app:testDebugUnitTest
./gradlew :app:lintDebug
# Windows: .\gradlew.bat :app:lintDebug
adb devices -l
adb -s DEVICE_SERIAL install -r app/build/outputs/apk/debug/remote-agent-debug.apk
```

Gradle ruft automatisch `scripts/build-android-agent.py` auf und packt die Rust-Programme beider ABIs ins native Bibliotheksverzeichnis der APK. Nach Installation starten sie aus diesem schreibgeschützten Verzeichnis und erfüllen Androids Ausführungsverbot im App-Datenverzeichnis. debug-APK dient Entwicklungsprüfungen; zur Veröffentlichung release mit organisations eigener Signaturkonfiguration bauen und Schlüssel für spätere Upgrades aufbewahren.

Release-Builds lesen `android-agent/keystore.properties` (Git-ignoriert) oder externe Konfiguration aus `REMOTE_AGENT_SIGNING_PROPERTIES`. Felder siehe `android-agent/keystore.properties.example`, Schlüssel außerhalb des Repositorys aufbewahren. Ohne Signaturkonfiguration scheitert Release, ohne Rückfall auf Debug-Signatur.

```powershell
cd android-agent
$env:REMOTE_AGENT_SIGNING_PROPERTIES = "$env:USERPROFILE/.remote-control/signing/remote-agent.properties"
.\gradlew.bat :app:assembleRelease :app:lintRelease :app:testReleaseUnitTest --no-daemon
# Output: app/build/outputs/apk/release/remote-agent-release.apk
```

Veröffentlichungsschlüssel und Passwort sicher sichern; Upgrades müssen denselben Schlüssel verwenden. Debug und Release sind verschieden signiert, vorhandene Debug-Installationen nicht direkt überschreibbar. Deinstallation löscht lokale Konfiguration und Gerätezugangsdaten; erneute Kopplung einplanen. `scripts/build-site-downloads.py` verwendet die signierte Release-APK als Agent-Download. Release-Signierung garantiert keine Aufhebung einer Play-Protect-Sperre.

### Android-Verbindung per QR-Code

**Scan connection QR code** auf der Remote-Agent-Startseite erkennt Verbindungscodes offline per Kamera, ohne Google Play-Dienste. Beim ersten Mal Kamera erlauben; Abbrechen ändert nichts. Nach Scan erscheinen Server und Geräte-ID, Token bleibt verborgen. Erst **Connect** speichert verschlüsselt und startet die Verbindung. Bestehende Verbindung vor Konfigurationsimport stoppen. Scannen aktiviert weder Bildschirmsteuerung noch Bedienungshilfen automatisch.

Separates Gerät in Exchange registrieren und dessen **Gerätetoken** beziehen, dann QR-Code lokal am Computer erzeugen (kein Operator-Kontotoken oder fremder Online-QR-Dienst):

```powershell
python -m pip install qrcode==8.2
python scripts/connection-qr.py --server wss://exchange.example.com --device-id android-phone --output "$env:TEMP\android-phone-connection.svg"
# 按提示输入设备令牌，输入不会显示。也可用 --token-stdin 从标准输入读取。
```

Erzeugtes SVG am Computer öffnen und mit Remote Agent scannen. Es enthält das Gerätetoken, muss vertraulich behandelt und anschließend gelöscht werden; nicht in Git einchecken. Bestehende Dateien werden nicht überschrieben.

QR-Inhalt ist UTF-8-JSON mit höchstens 2048 Byte Gesamtlänge:

```json
{"type":"remote-agent","version":1,"server":"wss://exchange.example.com","device_id":"android-phone","token":"DEVICE_TOKEN"}
```

Scannen akzeptiert nur `wss://`, optional `/ws/device`, ohne URL-Benutzerinformationen, Queryparameter oder Fragment. `server`, `device_id`, `token` müssen nicht leere Strings mit höchstens 512, 128, 512 Zeichen ohne Steuerzeichen oder führende/nachgestellte Leerzeichen sein. Manuelle Konfiguration unterstützt lokale `ws://`-Tests.

### Android-Bedienungshilfen, Screenshots und Texteingabe

Die folgenden Befehle verwenden `remote-cli`. Das Gerät meldet `android_control` über die APK-Brücke; Berechtigungen zeigt `status`.

1. Verbinden Sie das Gerät, öffnen Sie **Einstellungen → Bildschirm und Interaktion** und aktivieren Sie **Bildschirmfernsteuerung erlauben** (standardmäßig aus).
2. Wählen Sie **Einstellungen zur Bedienungshilfe** und aktivieren Sie Remote Agent in den Android-Einstellungen. Dies erlaubt das Lesen zugänglicher UI-Bäume, Tippen, Wischen, Systemnavigation und Ersetzen des Textes im fokussierten Eingabefeld.
3. Android 11+ kann über aktivierte Bedienungshilfen Screenshots aufnehmen. Unter Android 8–10 oder für reine Bildschirmaufnahme wählen Sie **Bildschirm freigeben** auf der Startseite oder **Standard-Bildschirmfreigabe** in den Einstellungen und bestätigen den Systemdialog. Nach Ende der Freigabe oder Prozessneustart ist eine neue Bestätigung nötig.

```sh
remote-cli ui my-device status
remote-cli ui my-device tree
remote-cli ui my-device xml > screen.xml
remote-cli ui my-device click --view-id com.example:id/search
remote-cli ui my-device click --text "Search" --description "Open search"
remote-cli ui my-device screenshot --output screen.jpg
remote-cli ui my-device tap 300 500
remote-cli ui my-device swipe 500 1500 500 500 --duration-ms 400
# 多段滑动（折线，2-64 个点）
remote-cli ui my-device swipe-path 300,1500 300,800 900,800 --duration-ms 800
remote-cli ui my-device key back
remote-cli ui my-device text "Hello"
remote-cli ui my-device text --stdin < message.txt
remote-cli ui my-device type --stdin < message.txt
```

`text` **ersetzt den gesamten Text des fokussierten Eingabefeldes** mit Android `ACTION_SET_TEXT`, unterstützt Chinesisch, Emoji und mehrere Zeilen, höchstens 8192 UTF-8-Byte ohne NUL. Zuerst editierbares Feld antippen; ohne Fokus, Editierbarkeit oder Aktionsunterstützung wird ein Fehler gemeldet. `--stdin` liest UTF-8 mit Zeilenumbrüchen und vermeidet Texte im Kommandoverlauf. `key` unterstützt `back`, `home`, `recents`, `notifications`, `quick-settings`.

`xml` liefert verschachtelten `<hierarchy><node ...>`-Baum mit `resource-id`, `text`, `content-desc`, `bounds` und Elementzustand; höchstens 200 Knoten, 50 Ebenen, 256 Zeichen pro Attribut. Antwort und Wurzel melden Kürzung. `click` verwendet **exakte vollständige Attributwerte** (kein XPath): `--view-id` entspricht `resource-id`, `--description` entspricht `content-desc`; mehrere Bedingungen sind UND-verknüpft. Nur sichtbare aktivierte Elemente, kein oder mehrere Treffer sind Fehler. Bei Traversierungslimit kein Klick. Textlabels suchen anklickbare Eltern; sonst `tap X Y`. Nach Änderungen XML neu abrufen, lange Attribute durch Ressourcen-ID ersetzen.

Für die Eingabemethode öffnen Sie **Einstellungen → Remote Input**. Aktivieren Sie Remote Input in Android über **Remote Input aktivieren** und wählen Sie es anschließend über **Eingabemethode auswählen** aus. Nach Fokus im Zielfeld fügt `type` über `InputConnection.commitText` Text am Cursor/in Auswahl ein, unterstützt Chinesisch, Emoji und mehrere Zeilen mit gleichem 8192-UTF-8-Byte-Limit wie `text`. Kein automatisches Senden oder Formularabsenden, keine Änderung eigener Agent-Konfiguration. **Switch keyboard** stellt Alltagstastatur wieder her. `status` liefert `ime_enabled`, `ime_selected` und `ime_connected`. Vor Lesen, Klicken und Eingeben Bildschirm einschalten und lokal entsperren.

Remote Consoles **Gerätebildschirm** bietet Koordinatentippen, XML-Abruf und Attributklicks, Remote-Input-Texteingabe. Fehlende Berechtigungen oder Bildschirmzustände deaktivieren Schaltflächen. Erfolgreiche Eingabe leert Text; Hintergrundwechsel löscht Screenshots, XML und ausstehende Eingaben.

### Systemfähigkeiten

Systemeinstellungen verwenden vom Gerät gemeldete Anbieter; Namensräume sind Strings statt fester Enumerationen. Android verwendet `android_settings` mit `system`, `secure`, `global`. Linux ohne OpenWrt und macOS verwenden `system_settings`: gsettings des aktuellen Linux-Benutzers bzw. `/usr/bin/defaults` des macOS-Benutzers. Browsererweiterungen verwenden `browser_settings`, lesen/schreiben `privacy.network`, `privacy.services`, `privacy.websites` verschlüsselt. Windows/OpenWrt bieten diese Einstellungen nicht. Neue Schlüssel/Wert-Einstellungen benötigen nur Anbieterregistrierung im Agenten/Erweiterung; der Client rendert die Liste.

Androids drei Namensräume sind unabhängig von Bildschirmschalter, Display und Sperrzustand, Zugriff über ContentResolver statt Shellzusammensetzung. Normale APKs benötigen zum Schreiben von `system` die Freigabe über **Ändern von Systemeinstellungen erlauben** im Agenten; `secure/global` benötigt zusätzlich `WRITE_SECURE_SETTINGS`. Status liefert Berechtigungen und `providers`; Android-/Herstellerrichtlinien können einzelne Zugriffe weiter ablehnen.

`settings list --prefix` filtert unter Android Einstellungsnamen. Linux/macOS liefern ohne prefix nur Schema-/Domainnamen, mit prefix deren oberste String-, Integer- und Booleanwerte. `settings clear` akzeptieren derzeit nur Browserdatenschutzeinstellungen; andere Anbieter melden ausdrücklichen Fehler. Audit erfasst Namensraum, Name, Zeichenzahl, keine Werte.

```sh
remote-cli ui realmev5 settings
remote-cli ui realmev5 settings list --namespace system --limit 100
remote-cli ui realmev5 settings get screen_off_timeout
remote-cli ui realmev5 settings set screen_off_timeout 600000
remote-cli ui realmev5 screen-timeout 600
remote-cli ui realmev5 settings get device_name --namespace global
remote-cli ui realmev5 settings set vendor.custom_setting --stdin
```

`settings set` verwendet Strings; `--stdin` erhält Zeilenumbrüche, Werte werden nicht auditiert. Höchstens 8192 UTF-8-Byte ohne NUL; Namen höchstens 256 ASCII-Zeichen (Buchstaben, Ziffern, Unterstrich, Punkt, Doppelpunkt, Bindestrich). Listen höchstens 500 Einträge/512 KiB, sonst `truncated`; Einzelwerte höchstens 64 KiB. Fehlende Einstellung liefert `value: null`. Eingeschränkte Einstellungen werden nicht stillschweigend erzwungen; jeder Schreibvorgang wird erneut gelesen und Fehler ausdrücklich gemeldet. Änderungen bleiben bestehen, Trennen stellt alte Werte nicht wieder her. `screen-timeout` verwendet Sekunden (15–86400), `screen_off_timeout` Millisekunden. Ausschaltzeit und anschließende Sperrverzögerung sind verschieden.

### Medienwiedergabe (media)

Sprache, Audio, Bilder samt Vollbildtext, Video und Webseiten verwenden `media`, von Android- und Windows/Linux/macOS-Agenten gemeldet, nicht OpenWrt. Drei Protokollaktionen: `media_play` (mit `media`-Objekt), `media_stop`, `media_status`; alle liefern denselben `media`-Status.

| `media.type` | Felder | Kanal |
| --- | --- | --- |
| `speech` | `text`, optional `language` (BCP-47, etwa `zh-CN`) | Ton |
| `audio` | Genau eines aus `url` oder `path`, optional `loop` | Ton |
| `image` | Genau eines aus `url`, `path`, `text`, optional `p2p` (nicht mit `text`) | Bild |
| `video` | Genau eines aus `url` oder `path`, optional `p2p` | Bild |
| `web` | `url` (nur https) | Bild |

Zwei unabhängige Kanäle: **Ton** (Sprache, Audio) und **Bild** (Bilder, Text, Video, Webseiten). Neuer Inhalt ersetzt nur laufenden Inhalt desselben Kanals, sodass Hintergrundmusik und Bildfolge gleichzeitig möglich sind. `channel` bei `media_stop`: `sound`, `screen`, `all` (Standard).

```sh
remote-cli ui realmev5 media speak "Remote 连接正常" --language zh-CN
remote-cli ui realmev5 media speak --stdin --language zh-CN
remote-cli ui realmev5 media audio --path /sdcard/Music/doorbell.mp3
remote-cli ui realmev5 media audio --url https://cdn.example.com/notice.mp3 --loop
remote-cli ui realmev5 media image --text "值班中"
remote-cli ui realmev5 media image --url https://example.com/poster.jpg
remote-cli ui realmev5 media video --path /sdcard/loop.mp4
remote-cli ui realmev5 media video --url https://files.example.org/library/clip.Aran --p2p-group library --p2p-discovery https://p2p.ivjn.us --p2p-token secret --p2p-peer 192.0.2.10:7300
remote-cli ui realmev5 media web https://status.example.com/board
remote-cli ui realmev5 media status
remote-cli ui realmev5 media stop sound      # 或 screen；不写则两个通道都停
remote-cli ui laptop media audio --path 'C:\Users\me\Music\alert.wav'
remote-cli ui laptop media image --text "Kiosk"
```

`media status` liefert:

```json
{"kind":"media",
 "sound":{"type":"audio","id":"…","state":"playing","language":null,"loop":true},
 "screen":{"type":"web","keep_awake":true},
 "speech_available":true,"media_volume":7,"media_volume_max":15}
```

`sound` ist der letzte Toneintrag (bleibt nach Ende zur Ergebnisprüfung), Zustand `queued` / `speaking` / `loading` / `playing` / `completed` / `stopped` / `error`, ohne bisherige Wiedergabe `null`. `screen` erscheint nur bei aktiver Anzeige, sonst `null`. `speech_available=false` bedeutet keine Sprachengine. Medienlautstärke hat nur unter Android Werte, am Desktop 0.

Validierung und Audit: Text (Sprache/Bildtext) höchstens 4000 UTF-8-Byte ohne NUL; URL nur `https`, höchstens 2048 Byte ohne Leer-/Steuerzeichen; Pfade höchstens 4096 Byte ohne Steuerzeichen. Audit erfasst Typ, Quellenart (`url` / `path` / `text`), Zeichenzahl, Schleife und P2P, niemals URL, Pfad oder Text (URLs können Signaturtoken enthalten). `readonly` darf keine Medienaktionen ausführen.

#### Ton: Sprachausgabe und Audio

- Sprache: Android verwendet System-TTS, Windows `System.Speech`, macOS `say`, Linux `spd-say` / `espeak-ng` / `espeak` (ohne diese `speech_available=false` und ausdrücklicher Fehler). Desktop versucht Sprachkennungen lokalen Stimmen zuzuordnen. Android antwortet erst nach Tonbeginn; Engineinitialisierung oder fehlende Sprachdaten liefern Fehler. Agent-Stopp gibt TTS frei.
- Audio: Absoluter Gerätepfad oder https-URL. Fehlende Dateien vorher mit `remote-cli files upload` übertragen und per Pfad abspielen. `loop` wiederholt bis zum Stopp.
  - Android verwendet `MediaPlayer` mit Medienlautstärke, streamt URL direkt, antwortet nach Tonbeginn und meldet Fehler, falls kein Start innerhalb 10 Sekunden.
  - Desktop lädt URL ins temporäre Statusverzeichnis des aktuellen Benutzers (höchstens 50 MB, Weiterleitungen nur https), löscht nach Ende, Stopp oder Fehler. Antwort nach Start des Wiedergabeprozesses; Download-/Dekodierfehler erscheinen als `sound.state=error` in `media status`. Windows verwendet `MediaPlayer` (mp3, wav, m4a, aac, wma, flac), macOS `afplay`, Linux sucht `mpv`, `ffplay`, `paplay`, `pw-play`, `aplay`; fehlen alle, Fehler (`paplay` / `aplay` ohne mp3).
  - Pfad muss vorhandene lesbare reguläre Datei sein; Windows lehnt Netzwerkpfade wie `\\server\share` ab, um keine Zugangsdaten an SMB-Server zu senden.
- Gerätelautstärke null kann unhörbare Wiedergabe bewirken.

#### Bild: Bilder, Text, Video und Webseiten

- **image**: Lokaler `path`, `https`-URL oder `text` (großer UTF-8-Text auf dunklem Hintergrund, als statisches Bild). Android entschlüsselt `.Aran` mit Metafile Android SDK vor Anzeige.
- **video**: Lokaler `path` oder `https`-URL, Schleife. Android behandelt `.Aran` nicht als normalen HTTPS-Medienstream: Ohne Cache blockweise Entschlüsselung während Download/Wiedergabe, Klartext lokal für spätere direkte Wiedergabe gespeichert. HTTP-Blöcke unter `/meta/<SHA1>` an der Origin-Wurzel; lokale Dateien lesen `meta/` neben Manifest. Standardmäßig eingebetteter Manifestschlüssel oder SDK-Standard. Optional P2P: Quellenfolge lokales `meta/`, UDP P2P (`LOOKUP_ONLY`, keine metastore-Registrierung), HTTP-Rückfall. Discovery und statische Peers aus `media.p2p`, etwa `--p2p-group library --p2p-discovery https://p2p.ivjn.us`; fehlgeschlagener P2P-Start nutzt HTTP/lokal ohne Wiedergabeabbruch.
- **web**: Vollbild-`https`-Seite. Android verwendet WebView in Vollbild-Activity (JavaScript/DOM storage an, Navigation nur https; Renderabsturz beendet Anzeige ohne Agent-Auswirkung). Desktop startet separaten Kioskbrowser mit temporärem Profil, beim Stopp mitsamt Browser beendet: Windows sucht Edge, Chrome, Firefox; macOS Chrome, Edge, Chromium, Firefox (Safari ohne Kiosk); Linux Chromium, Chrome, Edge, Firefox. Ohne Browser ausdrücklicher Fehler.

Android verwendet für `.Aran`-Manifeste/-Blöcke von `https://cdn.ivjn.cn` und `https://cdn.ivjn.us` automatisch die andere Domain als Ersatzquelle; Manifestpfad bleibt, Blöcke weiter aus `/meta/<SHA1>` jeder Quelle. Keine automatische Abbildung anderer Domains. Bei temporären Fehlern (auch HTTP 554), Timeout oder fehlgeschlagener Blockprüfung zuerst Ersatzquelle, dann 250/500 ms Backoff, höchstens 3 Runden; erfolgreiche Quelle danach bevorzugt. Verbindungstimeout 5 Sekunden, Lesen 30 Sekunden; permanente 403/404 usw. führen im selben Lesen nicht zu erneuter Anfrage derselben Quelle. Blockgröße und SHA-1 bleiben geprüft, keine Weiterleitungen oder gelockerte HTTPS-Prüfung. Benötigt Metafile `ab2b92f` oder neueres Android SDK mit `MirroredHttpSource`.

Der Bildkanal zeigt einen Inhalt, neuer ersetzt vorherigen. Bildschirm bleibt an (Android: `FLAG_KEEP_SCREEN_ON` + `turnScreenOn` / `showWhenLocked`; Windows: `SetThreadExecutionState`; macOS: `caffeinate -d`; Linux: `systemd-inhibit` oder `xdg-screensaver inhibit`). Statische Bilder/Texte verschieben sich langsam pixelweise gegen Einbrennen; Videos laufen in Schleife, Webseiten ohne Verschiebung. Kein statischer heller Rahmen. Android nutzt separate Vollbild-Activity ohne Bedienungshilfe. Linux benötigt entsperrte X11-Sitzung, Video lokal `mpv` oder `ffplay`; macOS bevorzugt mpv, sonst `open`.

#### Steuerung: Fortschritt und Webseiten

`media_control` steuert laufenden Kanalinhalt und liefert denselben `media`-Status. `channel` muss `sound` oder `screen` sein; `op` aus folgender Tabelle:

| `op.type` | Parameter | Anwendbar auf |
| --- | --- | --- |
| `pause` / `resume` | — | Audio (sound), Video (screen) |
| `seek` | `position_ms` (absolute Position, höchstens 7 Tage) | Audio, Video |
| `navigate` | `url` (https) | Webseiten |
| `reload` / `back` / `forward` | — | Webseiten |
| `scroll` | `dx`, `dy` (Pixel, ungleich null, jeweils höchstens 100000) | Webseiten |
| `eval` | `script` (höchstens 16 KiB) | Webseiten, liefert `script_result` (JSON-kodiertes Ergebnis, höchstens 64 KiB) |

```sh
remote-cli ui realmev5 media pause sound
remote-cli ui realmev5 media seek 1:30 screen      # 也接受 90、1:02:03.5
remote-cli ui realmev5 media resume screen
remote-cli ui realmev5 media web go https://status.example.com/next
remote-cli ui realmev5 media web back
remote-cli ui realmev5 media web scroll 0 800
remote-cli ui realmev5 media web eval "document.title"
```

Status ergänzt `position_ms`, `duration_ms`, `paused` unter `sound` / `screen` (Audio/Video, soweit Player meldet), bei Webseiten `url`, `title` unter `screen`. Sprache, Bilder, Text sind nicht steuerbar; unpassender Kanalinhalt liefert ausdrücklichen Fehler. Audit erfasst Kanal, Aktionstyp, Skriptzeichenzahl, keine URLs/Skriptinhalte.

- Android: Audio/Video steuern `MediaPlayer` / `VideoView`, Webseiten WebView der Vollbild-Activity.
- Windows: Audio über mitgelieferten `MediaPlayer`-Worker, Video mit mpv über IPC-Pipe, auch WPF-Ersatzplayer steuerbar, ffplay nicht.
- Linux / macOS: Audio/Video nur mit mpv steuerbar (JSON IPC), sonst „Install mpv to pause or seek desktop media“. macOS verwendet bei vorhandenem mpv auch für Audio mpv.
- Desktop-Webseiten: Chrome / Edge / Chromium starten Kiosk mit `--remote-debugging-port=0` (nur 127.0.0.1, zufälliger Port, temporäres Profil), Steuerung über DevTools. Firefox unterstützt nur `navigate` (Kiosk mit neuer Adresse neu öffnen).

Die mobile Remote Console bietet unter **Systemfähigkeiten** in Gerätedetails „Systemeinstellungen“ und „Medien“. Medien liest beide Kanäle, stoppt Ton/Bild getrennt, spielt Sprache, Audio-URL, Text, Bilder, Video und Webseiten und steuert Audio-/Videofortschritt sowie Webseiten (Navigation, vor/zurück, neu laden, scrollen, JS). Hintergrundwechsel leert Einstellungsergebnisse, ausstehende Werte, Sprachtext und Anzeigeeingaben. Webkonsole bietet dieselben Einstellungsformulare; Browsereinstellungen verwenden bestehende verschlüsselte Sitzung. Keine separate Web-Medienseite.

### Android-Textsuche und XML

```sh
remote-cli ui realmev5 xml
remote-cli ui realmev5 find-text "设置"
remote-cli ui realmev5 find-text "Settings" --exact --ignore-case
```

Textsuche vergleicht Text/Beschreibung sichtbarer Knoten, standardmäßig Teilzeichenfolge, optional exakt oder ohne Groß-/Kleinschreibung. Jeder Treffer liefert `bounds`, `center` (ursprüngliche Bildschirmpixel, nutzbar mit `tap X Y`), Ressourcen-ID, Text und Aktivierungszustand. Mittelpunkt aus Schnittfläche mit Bildschirm vermeidet externe Koordinaten. Höchstens 200 Knoten, Kürzung gemeldet. Passwortknoten und eigener Agent-Konfigurationsunterbaum ausgeschlossen. Selbst gezeichneter Text eventuell nicht für Android-Bedienungshilfen lesbar; kein OCR. Nach Änderungen erneut suchen.

Screenshots sind JPEG, längste Seite höchstens 1600 Pixel; CLI überschreibt keine Dateien. CLI zeigt Bild- und Originalbildschirmmaße. Tippen, Wischen, `bounds` verwenden Originalpixel. Vorschaukoordinaten umrechnen mit `屏幕坐标 = 图像坐标 × screen_width / width` (vertikal Höhenverhältnis). Nach Drehung Maße neu lesen. Baum höchstens 200 Knoten, Strings höchstens 256 UTF-16-Einheiten, `truncated` zeigt Knotenlimit. Selbst gezeichnete Apps eventuell ohne zugängliche Knoten.

Text/Beschreibungen von Passwortknoten und eigener Konfigurationsunterbaum werden nicht geliefert; Ferneingabe ändert eigene Konfiguration nicht. Android-`FLAG_SECURE`-Fenster erscheinen schwarz oder liefern Systemfehler; Android 15 schwärzt beim Teilen möglicherweise Apps mit Passwortfeldern oder sensiblen Inhalten. Bildschirmsteuerung verwendet vorhandene Operatorauthentifizierung, `readonly` darf sie nicht starten. Audit erfasst Aktionen, Koordinaten, Eingabezeichenzahl, keine Texte, Bäume oder Screenshots.

**Stop screen sharing** beendet MediaProjection; aktivierte Android-11+-Bedienungshilfen können weiter Screenshots liefern. **Allow remote screen controls** ausschalten blockiert alle weiteren Bildschirmaktionen und beendet Freigabe; **Stop remote access** trennt auch den Agenten. Ausgeführte Eingaben sind nicht rückgängig zu machen. Android verwaltet Bedienungshilfeberechtigungen separat; sie bleiben bei Schalter-Aus oder Dienststopp erhalten, ohne Annahme von Fernaktionen.

Die lokale Brücke verwendet zufälligen Unix-Socketnamen und prüft gleiche UID von Aufrufer und APK. Das schützt gegenüber anderen gewöhnlichen Apps. Autorisierte Fernshell teilt App-UID; der Schalter ist keine Berechtigungsisolation gegenüber dieser Shell oder Geräteadministratoren.

## Systeminformationen und Metriken

`DeviceInfo.platform`: `linux`, `freebsd`, `netbsd`, `windows`, `android`, `macos`, `openwrt`; `os_version` ist allgemeine Systemversion, `capabilities` beschreibt `exec`, `pty`, `ubus`, `android_control`. OpenWrt meldet `openwrt_version`.

Linux/OpenWrt lesen `/proc`; Android behält bei SELinux-Einschränkungen andere lesbare Metriken, Betriebszeit über `CLOCK_BOOTTIME`. Windows liest Speicher, CPU, Betriebszeit und Netzwerkkartenzähler über native APIs. Fehlende Metriken stehen in `unavailable`, CLI/mobile Clients zeigen Lücken. Windows hat keinen Unix load average, `load` ist immer nicht verfügbar.

## Prüfung

```sh
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo test -p agent --features desktop-ui
cargo clippy -p agent --features desktop-ui --all-targets -- -D warnings
cd mobile && npm run typecheck && npm run lint && npm test
```

`scripts/agent-smoke.py` ist ein lokales Testrelay mit Python `websockets`, prüft echte Agent-Registrierung, Metriken, Ausführung, Timeout, Abbruch, PTY, resize und nicht unterstütztes ubus. Kein Ersatz für Exchange-Authentifizierungs-/Datenbanktests. Feste Testzugangsdaten nach Anleitung, keine produktiven Geräte/Dienste verbinden. Windows/Linux führen jeweilige native Tests aus; Android nach Installation zusätzlich Vordergrund, Hintergrund, Stopp, Wiederverbindung real prüfen.

`scripts/agent-ui-smoke.py --agent <binary> --platform linux|windows` prüft Erstkonfiguration, Authentifizierung/Herkunftsbeschränkungen, private Speicherung, Tokenbeibehaltung, echte Registrierung/Ausführung, Stoppbereinigung, Wiederverbindung, erneutes Öffnen. Benötigt Python 3.11+ und `websockets`, Agent zuerst mit `desktop-ui` bauen. Browsertests auch für Speichern, Fehler, Tokensichtbarkeit, Neuladewiederherstellung, schmale Layouts.

`scripts/android-control-smoke.py` prüft Bildschirmaktionen mit echtem Exchange, CLI und separater Android-Test-App. Nur dedizierten wegwerfbaren Emulator verwenden: Skript löscht Remote-Agent-Daten und ändert Bedienungshilfen. Zuerst `:app:assembleDebug` und `:control-fixture:assembleDebug` bauen/installieren, separates Exchange/Datenbank vorbereiten, Gerät registrieren, Token und CLI-Konfiguration speichern. Benötigt Python 3.11+, Pillow, `adb`.

```sh
adb -s emulator-5580 install -r android-agent/app/build/outputs/apk/debug/remote-agent-debug.apk
adb -s emulator-5580 install -r -t android-agent/control-fixture/build/outputs/apk/debug/control-fixture-debug.apk
python scripts/android-control-smoke.py --serial emulator-5580 \
  --cli target/debug/remote-cli --cli-config /private/qa-cli.toml \
  --device-token /private/qa-device-token.txt \
  --device-id android-control-qa --device-server ws://10.0.2.2:18820/ws/device
```

Windows: CLI-Pfad `target/debug/remote-cli.exe`. Standardartefakte: `target/android-control-qa/screenshots/`. fixture nur für Tests, nicht in Geräte-APK.

### Android-Logs, Bildschirmstatus und Aufwecken

Remote Console ergänzt **Gerätelogs** und **Gerätebildschirm** in Details. Bildschirmseite zeigt Displayvorhandensein, Strom-/Sperrzustand, Maße, Berechtigungen, JPEG-Vorschau auf Abruf und **Bildschirm aufwecken**. Ohne Display oder Android-Schnittstelle sind Bildschirmaktionen deaktiviert; fehlende Aufnahmeberechtigung separat. Ausgeschaltete Displays lassen sich bei lokal aktivierter Steuerung wecken. Die Tastensperre wird nie aufgehoben.

Android-Agent bietet lokal **Bildschirmstatus und Gerätelogs**. Bei Fernzugriff sind Verbindungsfelder, QR-Registrierung und Code-Schaltflächen verborgen. Trennen benötigt Bestätigung und behält Zugangsdaten. Autorisierung und aktive Bindung der Bedienungshilfen werden separat gemeldet; bei Autorisierung ohne Bindung nur Remote Agent in System-Bedienungshilfen umschalten.

```powershell
remote-cli ui realmev5 status
remote-cli ui realmev5 logs --limit 100
remote-cli ui realmev5 wake
remote-cli ui realmev5 screenshot --output screen.jpg
```

`open_android` akzeptiert `{action:"logs",limit:100}` (1–300 Einträge) und `{action:"wake"}`. Optionaler Status: `display_present`, `screen_on`, `locked`, `screen_width`, `screen_height`, `accessibility_authorized`; `accessibility_enabled` bedeutet weiterhin verbundener Dienst. Native Android-Bildschirm-APIs benötigen APK; andere Agenten melden diese Schnittstelle nicht.

Logs kommen aus `logcat -b all`, ohne PID-/Paket-/Tagfilter: System-, App-, Ereignis-, Absturzpuffer von Android logd. Abruf liefert bis 100 UI-Einträge oder 1–300 per CLI mit Zeitstempeln, Stufen, Puffernamen, PID/TID, Tags, Originalnachrichten. Aktuelle logcat-Historie, kein Archiv beliebiger Dateien oder rotierter Logs.

Systemlogberechtigung über autorisierte ADB-Verbindung erteilen:

```sh
adb shell pm grant com.remote.agent android.permission.READ_LOGS
```

Bei Android mit Freigabe je Zugriff Agent-Diagnoseseite öffnen, Systemdialog bestätigen und Fernanfrage wiederholen. Hintergrundzugriff kann verweigert werden, Freigabe nach Android-/OEM-Richtlinie ablaufen. Android liefert nach Ablehnung möglicherweise still nur Aufrufer-UID; daher prüft der Collector UID-Metadaten der letzten 301 logcat-Einträge vor Auswahl des gewünschten Endes. Ohne andere UID (auch leere Logs) meldet er fehlende Bestätigung geräteweiten Zugriffs statt App-only-Aufnahme. Fehlende Berechtigung/logcat-Fehler liefern ausdrücklichen Fehler, kein Rückfall auf Agent-Ereignisring. Erfassung außerhalb UI-Thread, Abbruch bei Stornierung, sechs Sekunden Zeitlimit und begrenzte Ausgabe; Übergröße meldet Kürzung/Fehler. Bestehende authentifizierte Operatorsitzungen, Mandantenrouting und Rollenbeschränkungen gelten. Logs können Inhalte anderer Apps enthalten. Web-/Mobilansichten leeren sich bei Verlassen/Hintergrund und speichern nicht auf Datenträger; Remote Console löscht dann auch Screenshots.

**Transparente Vollbildfreigabe:** Im Android-Agent **Share full screen with transparent overlay** wählen, Android-Anzeige-über-Apps und Bildschirmfreigabe erlauben. Agent wechselt in Hintergrund und legt Vollbild-`TYPE_APPLICATION_OVERLAY` mit Deckkraft null und `FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE` an: Berührungen gehen an darunterliegende App. MediaProjection erfasst ganzes Display (Android 14+ fordert Standarddisplay explizit an). Stopp über Agent-Seite/Benachrichtigung trennt Agent nicht. Overlay wird bei Ende oder Dienststopp entfernt.

Bildschirmvorschau und verbundene Agent-Statusseiten erlauben Aufnahmen. Verbindungseinrichtung, Anmeldetickets und Token-QR-Seiten bleiben geschützt. Sichere Fenster anderer Apps können weiter schwarz erscheinen; transparentes Overlay umgeht deren Schutz nicht.

Vor Aufnahme prüft der Agent Displayzustand und interaktiven PowerManager-Zustand. Nur ausgeschaltetes Display wird geweckt, interaktiver Zustand geprüft, bei Tastensperre Aufnahme verweigert. MediaProjection-Reader leert kontinuierlich Frames und behält ein aktuelles zusammengesetztes Bild statt Surface pro Screenshot neu anzulegen. Bei ganz schwarzen Frames wartet er auf brauchbaren Frame und liefert bei Timeout handlungsorientierten Fehler statt erfolgreiches schwarzes JPEG.

## Vergleich der Agent-Modi

Startmodus und Geräteplattform sind getrennte Aspekte. Nativer headless-Betrieb, lokale UI und Systemdienste teilen den Verbindungskern; `desktop-ui` ergänzt nur die lokale Konfiguration und erteilt keine Fernzugriffsrechte.

| Modus/Plattform | Funktionen | Voraussetzungen und Grenzen |
|---|---|---|
| headless / lokale UI | Gleiches natives Protokoll, Befehle, Terminal, Dateien, Metriken, Benachrichtigungen, optionales LAN | UI nur auf Linux/Windows/macOS; Windows mit Tray; Desktop-Aktionen benötigen eine nutzbare grafische Benutzersitzung |
| Systemdienst / Anmeldestart | Derselbe native Agent | Übernimmt Dienstkonto und Umgebung; Startparameter werden nicht in andere Dienste kopiert |
| OpenWrt | Nativer Kern, ubus | Meldet ubus nur bei Verfügbarkeit; procd überwacht; keine Desktop-Steuerung gemeldet |
| Linux / Windows / macOS | Nativer Kern, Desktop-Steuerung, Systemprotokolle, Medien | OS-Rechte/Werkzeuge erforderlich; Systemeinstellungen nur auf Linux/macOS gemeldet |
| FreeBSD / NetBSD | Nativer Kern, Terminal, Dateien, Netzwerk, Metriken, optionales LAN | Keine Batterie; X11-Abhängigkeiten; keine Medien/Systemeinstellungen |
| Android APK | Rust-Kern + Java-Brücke, Bildschirm, Einstellungen, Medien, OTA | App-UID und OS-Berechtigungen; eigenständiges Rust-Programm ohne APK-Steuerbrücke |
| Chromium-Erweiterung | URL, Cookies, Webseiten, Browsereinstellungen, CDP, Metriken | Keine OS-Befehle/PTY/beliebigen Hostdateien/LAN-Listener; vollständiges CDP benötigt lokale Erlaubnis |

UI und headless nutzen dieselbe Auflösung der Laufzeitkonfiguration: CLI/Umgebung haben für LAN, watchdog, TLS und Benachrichtigungen Vorrang vor JSON; automatische Updates bleiben bei CLI > JSON > `REMOTE_AUTO_UPDATE` > standardmäßig aktiviert. `REMOTE_WATCHDOG=1` sowie 0, true/false, yes/no und on/off werden akzeptiert. Die UI lehnt Startüberschreibungen für Verbindungsdaten und Zustandspfade weiterhin ab. Laufzeitüberschreibungen werden nicht in JSON gespeichert; Autostart-Prozesse müssen separat konfiguriert werden. Der LAN-Status zeigt wirksame Werte; Speichern entfernt keine Startüberschreibungen.

UI und headless nutzen JSON `state_file`, sonst denselben dauerhaften Systemstandardpfad; separate Geräteinstanzen benötigen separate Pfade. Beim Verbinden wird connecting, beim Stoppen stopped angezeigt. Stoppen bricht das Auto-Update-Future dieser Verbindung ab und gibt den watchdog-Zustand frei; Hintergrundprüfer enden bei der nächsten Prüfung. Abgeschlossene Vorgänge lassen sich nicht rückgängig machen. Jede neue Verbindung lädt Geräteidentität und Vertrauensrichtlinie erneut; schlägt das Laden fehl, wird die vorherige Identität gelöscht, statt die alte Geräteautorisierung beizubehalten.

Alle Geräteoperationen erfordern versiegelte Sitzungen und eine Autorisierung durch den Workspace-Stammschlüssel. Die Einzelbestätigung/unbeaufsichtigte Freigabe für vollständiges Browser-CDP wird nicht durch typisierte Cookie-Bereiche isoliert und kann Chrome-Richtlinien nicht umgehen. Nach Schließen oder Verbindungsabbruch ist ein neuer Handshake nötig. Desktop-Updatearchive sind Windows x64, Linux glibc x64/arm64 und macOS arm64 zugeordnet; andere native Plattformen verwenden Installer/Paketmanager, Android APK OTA und Browser Erweiterungspakete. Eine gemeldete Fähigkeit garantiert keine verfügbare Hardware, Berechtigung oder Veröffentlichung.

## Automatischer Bildschirmschoner

Die Einstellungen des lokalen Agents und der Browsererweiterung bieten Leerlauf (Standard: 300 Sekunden), Steuerungsbeginn/-ende und Sofortstart. Inhalte: Text, HTTPS-Bilder/-Videos oder isoliertes statisches HTML. Videos laufen stumm in Schleife; Text und Bilder können sich weiträumig bewegen. Desktop und Android bieten ein Beenden-Passwort. Das Browser-Vollbild hat kein Passwort und endet per Taste, Mausbewegung oder Fensterschließen. Nur der aktive Bildschirm wird abgedeckt; keine Betriebssystemsperre. Linux benötigt X11 und xprintidle. OpenWrt ohne Desktop, Wayland und BSD unterstützen derzeit keine Bildschirmanzeige.

Einfarbiger Modus ohne Text oder Medien: Hintergrundfarbe #RRGGBB und Helligkeit 0–100% (0% ist schwarz). Android dimmt auch die Fensterbeleuchtung und stellt bei Eingabe die Systemhelligkeit wieder her. Andere Plattformen dimmen nur das Bild; LCD-Einsparungen hängen von der Beleuchtung ab. Der Beenden-Dialog bleibt lesbar.

Ab 0.1.34 bewegen sich nur Text und Bilder über einen großen Bereich des Hintergrunds. Große Inhalte werden bei Bedarf auf höchstens 44% der verfügbaren Breite und Höhe verkleinert, damit gegenüberliegende Eckpositionen nicht überlappen. HTML, Video und Vollfarben bleiben still; reduzierte Bewegung pausiert die Animation. Alle Modi verbergen den Mauszeiger ab dem ersten Bild, zeigen ihn im Beenden-Dialog und verbergen ihn nach Abbrechen erneut. Windows aktualisiert den Zeiger im Schonerfenster alle 100 ms, ohne den Systemcursor zu ändern. Zuerst verfügbar in Windows und Browser Agent 0.1.34; andere Plattformversionen stehen im Download-Manifest.
