fix(plugin): restore native installer compatibility
This commit is contained in:
@@ -101,6 +101,7 @@ jobs:
|
||||
- name: Run focused Plugin tests
|
||||
run: |
|
||||
python -m pytest \
|
||||
plugin/tests/test_manifest_compatibility.py \
|
||||
plugin/tests/test_relay_security.py \
|
||||
plugin/tests/test_voice_routes.py \
|
||||
plugin/tests/test_session_grants.py \
|
||||
|
||||
@@ -85,6 +85,7 @@ jobs:
|
||||
- name: Run focused Plugin tests
|
||||
run: |
|
||||
python -m pytest \
|
||||
plugin/tests/test_manifest_compatibility.py \
|
||||
plugin/tests/test_relay_security.py \
|
||||
plugin/tests/test_voice_routes.py \
|
||||
plugin/tests/test_session_grants.py \
|
||||
|
||||
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Hermes-Relay Plugin installs through the native Hermes command again.** The manifest remains fully described for current hosts while avoiding the installer/runtime schema mismatch in affected Hermes releases.
|
||||
- **Android keeps completed chat text visible when Dashboard sign-in expires.** Generic and reason-coded history `401` responses settle the local turn, preserve its transcript, and surface the existing sign-in recovery without reading another profile's API history.
|
||||
- **Android keeps long-running context compaction alive.** A client-visible compaction status extends and refreshes the Gateway turn watchdog instead of interrupting healthy compression after the ordinary idle window. (Supersedes #484.)
|
||||
- **Android Bot Chats render loaded history immediately.** Route-owned chat screens observe their own handler state from first composition, including fast history loads that settle before another frame. (Supersedes #453.)
|
||||
|
||||
@@ -6,6 +6,18 @@ For shipped work, see `DEVLOG.md`. For architectural decisions, see `docs/decisi
|
||||
|
||||
---
|
||||
|
||||
## Restore the plugin manifest v2 declaration after the Hermes installer fix ships
|
||||
|
||||
Hermes installers in affected stable releases reject `manifest_version: 2`
|
||||
before the v2-capable runtime loader can inspect the plugin. Track upstream
|
||||
[PR #85893](https://github.com/NousResearch/hermes-agent/pull/85893). Restore
|
||||
`plugin/plugin.yaml` to `manifest_version: 2` only after that fix ships in a
|
||||
stable Hermes release that Hermes-Relay can treat as its minimum supported
|
||||
version. Until then, keep the v1 compatibility declaration and the additive
|
||||
metadata consumed by newer hosts.
|
||||
|
||||
---
|
||||
|
||||
## Consider hosted Android emulator execution
|
||||
|
||||
The local API 36 Gradle Managed Device lanes are intentionally on demand and
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
name: hermes-relay
|
||||
manifest_version: 2
|
||||
# Temporary v1 shim for Hermes installers that reject manifests the runtime supports; see TODO.md.
|
||||
manifest_version: 1
|
||||
api_version: 1
|
||||
version: 1.11.0
|
||||
description: "Hermes-Relay plugin for QR pairing, relay sessions, dashboard management, remote desktop/phone tooling, and optional legacy compatibility diagnostics. Standard chat, Manage, and dashboard voice remain vanilla upstream Hermes surfaces."
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Regression coverage for the temporary Hermes installer compatibility manifest."""
|
||||
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
PLUGIN_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class ManifestCompatibilityTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
cls.manifest = yaml.safe_load(
|
||||
(PLUGIN_ROOT / "plugin.yaml").read_text(encoding="utf-8")
|
||||
)
|
||||
|
||||
def test_declares_installer_compatible_manifest_version(self) -> None:
|
||||
self.assertEqual(self.manifest["manifest_version"], 1)
|
||||
|
||||
def test_retains_additive_metadata_for_current_hosts(self) -> None:
|
||||
self.assertEqual(self.manifest["api_version"], 1)
|
||||
self.assertEqual(
|
||||
self.manifest["python_dependencies"],
|
||||
[
|
||||
"requests>=2.28.0,<3",
|
||||
"aiohttp>=3.14.1,<4",
|
||||
"segno>=1.6.0,<2",
|
||||
"pyyaml>=6.0,<7",
|
||||
"httpx>=0.25.0,<1",
|
||||
"websocket-client>=1.8.0,<2",
|
||||
],
|
||||
)
|
||||
self.assertEqual(self.manifest["license"], "MIT")
|
||||
self.assertEqual(
|
||||
self.manifest["homepage"],
|
||||
"https://github.com/Codename-11/hermes-relay",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.manifest["tags"],
|
||||
["android", "dashboard", "gateway", "relay", "remote-access", "voice"],
|
||||
)
|
||||
|
||||
def test_retains_v1_hook_declarations(self) -> None:
|
||||
self.assertEqual(
|
||||
self.manifest["provides_hooks"],
|
||||
["on_session_start", "pre_llm_call", "post_llm_call"],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -29,8 +29,8 @@ Run this from the `hermes-android/` repo root, or wherever `relay_server/` is lo
|
||||
### As a Hermes plugin + relay
|
||||
|
||||
```bash
|
||||
# 1. Install the Android plugin (18 android_* tools)
|
||||
cp -r plugin ~/.hermes/plugins/hermes-relay
|
||||
# 1. Install and enable the native Hermes plugin
|
||||
hermes plugins install Codename-11/hermes-relay/plugin --enable
|
||||
|
||||
# 2. Install relay dependencies
|
||||
pip install -r relay_server/requirements.txt
|
||||
|
||||
@@ -34,7 +34,7 @@ Operators with the Hermes dashboard open can also mint the same QR from the web
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Hermes-Relay plugin installed into the Hermes venv.** Verify by running `python -m plugin.pair --help` — if it errors with `ModuleNotFoundError: No module named 'plugin'`, install it first: `pip install -e <path-to-hermes-relay-repo>`.
|
||||
1. **Hermes-Relay plugin installed and enabled.** Verify with `hermes pair --help`. If the command is unavailable, run `hermes plugins install Codename-11/hermes-relay/plugin --enable`. Use the full `install.sh` path instead only when the host also needs the relay service, editable package, and shell shims.
|
||||
2. **Hermes API server reachable** on `API_SERVER_HOST:API_SERVER_PORT` (default `127.0.0.1:8642`). `plugin.pair` auto-reads this from `~/.hermes/config.yaml` → `~/.hermes/.env` → env vars → defaults.
|
||||
3. **Relay server running** on `RELAY_HOST:RELAY_PORT` (default `0.0.0.0:8767`) if the user wants terminal/bridge channels. The Relay may stay host-internal: current Android pairing normally reaches it through the Dashboard's same-origin plugin transport. Tailscale Serve normally exposes dedicated HTTPS `10443` and proxies the host-local Dashboard on `9119`; a raw LAN/tailnet route may reach `9119` directly. Listener `443` is an advanced explicit override only when it is free. Without a live relay, the QR will configure chat only.
|
||||
4. **Host is Linux or macOS.** The relay uses a real PTY backend, which is POSIX-only. Windows hosts can generate API-only QRs but the terminal channel will not work.
|
||||
@@ -46,7 +46,7 @@ Operators with the Hermes dashboard open can also mint the same QR from the web
|
||||
2. **Generate the QR** — run via the `terminal` tool:
|
||||
|
||||
```bash
|
||||
python -m plugin.pair
|
||||
hermes pair
|
||||
```
|
||||
|
||||
When the current Hermes surface exposes an exact Dashboard origin, pass it
|
||||
@@ -65,7 +65,7 @@ Operators with the Hermes dashboard open can also mint the same QR from the web
|
||||
explicitly selects that advanced listener and confirms it is free. Never
|
||||
substitute the API server URL or infer public port `8767`.
|
||||
|
||||
If `python` resolves to the wrong interpreter (plugin not found), use the Hermes venv explicitly:
|
||||
On a full-relay or legacy editable install where an older Hermes host cannot register plugin CLI commands, use the Hermes venv explicitly:
|
||||
|
||||
```bash
|
||||
~/.hermes/hermes-agent/venv/bin/python -m plugin.pair
|
||||
@@ -156,7 +156,7 @@ Pass `--transport-hint wss` only when you know the relay is actually running beh
|
||||
## Pitfalls
|
||||
|
||||
- **Relay not running.** `plugin.pair` prints `[info] Relay not running ... QR will configure chat only` and renders an API-only QR. Terminal tab will then ask the user to paste a pairing code manually. Fix: start the relay first (`hermes relay start`) and re-run.
|
||||
- **Plugin not installed.** `ModuleNotFoundError: No module named 'plugin'`. Fix: `pip install -e <hermes-relay-repo>` into the same Python environment Hermes uses. Use `which python` / `where python` to confirm you're targeting the Hermes venv.
|
||||
- **Plugin not installed.** If `hermes pair --help` is unavailable, run `hermes plugins install Codename-11/hermes-relay/plugin --enable`. Use `install.sh` for the full relay/service/shim setup rather than constructing a manual editable install.
|
||||
- **Wrong venv.** If `hermes` CLI is global but plugin is in the Hermes venv, `python -m plugin.pair` may resolve to the wrong Python. Call the venv Python explicitly: `~/.hermes/hermes-agent/venv/bin/python -m plugin.pair`.
|
||||
- **Pairing code expired.** 10-minute TTL, one-shot. Re-run `python -m plugin.pair` to mint a fresh code; the previous code is automatically invalidated on the next run.
|
||||
- **QR won't scan on terminal.** Likely causes: terminal font too small (zoom in), dark-mode color inversion mangling the blocks, or terminal lacks Unicode half-block support. Fix: re-run with `--png` and point the camera at the saved image, or open the PNG in an image viewer on a second screen.
|
||||
|
||||
@@ -81,7 +81,7 @@ Do NOT use this skill to start or install the relay server itself — that is a
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Hermes-Relay plugin installed into the Hermes venv.** Verify by running `python -m plugin.status --help` — if it errors with `ModuleNotFoundError: No module named 'plugin'`, install it first: `pip install -e <path-to-hermes-relay-repo>`.
|
||||
1. **Hermes-Relay plugin installed and enabled.** Verify with `hermes plugins show hermes-relay`. If it is missing, run `hermes plugins install Codename-11/hermes-relay/plugin --enable`. The standalone `python -m plugin.status` fallback additionally requires the full `install.sh` editable-package path.
|
||||
2. **Relay server running** on `RELAY_HOST:RELAY_PORT` (default `0.0.0.0:8767`). Without a live relay, this skill exits with code `1` and a "relay unreachable" error.
|
||||
3. **Phone has connected at least once** since the last relay restart. The relay tracks live phone-*connection* state in memory, so a restart clears that presence — the phone **reconnects** automatically (its paired session persists across restart, so no re-pair is needed). Until then, status returns "no phone connected" with exit code `2`.
|
||||
|
||||
@@ -119,7 +119,7 @@ Do NOT use this skill to start or install the relay server itself — that is a
|
||||
## Pitfalls
|
||||
|
||||
- **Relay not running.** `status` prints `[error] Cannot reach hermes-relay on 127.0.0.1:8767` to stderr and exits `1`. Fix: start the relay first (`systemctl --user start hermes-relay` or `python -m plugin.relay --no-ssl`) and re-run.
|
||||
- **Plugin not installed.** `ModuleNotFoundError: No module named 'plugin'`. Fix: `pip install -e <hermes-relay-repo>` into the same Python environment Hermes uses. Use `which python` / `where python` to confirm you're targeting the Hermes venv.
|
||||
- **Plugin not installed.** If `hermes plugins show hermes-relay` fails, run `hermes plugins install Codename-11/hermes-relay/plugin --enable`. Use `install.sh` when the host also needs the relay service, editable package, and shell shims.
|
||||
- **Wrong venv.** If `hermes` CLI is global but plugin is in the Hermes venv, `python -m plugin.status` may resolve to the wrong Python. Call the venv Python explicitly: `~/.hermes/hermes-agent/venv/bin/python -m plugin.status`.
|
||||
- **Phone shows as disconnected immediately after a relay restart.** Expected — the relay holds phone state in memory and wipes it on restart. The phone reconnects automatically on its next ping cycle (within ~30s). If it doesn't, check the phone side: the session token may need re-pairing via `/hermes-relay-pair`.
|
||||
- **`bridge.accessibility_granted = false` but everything else looks fine.** The user has opened the Android app but not yet granted the Hermes-Relay accessibility service. Tell them: "Open Hermes-Relay → Bridge screen → the permission checklist will have Accessibility as the top row. Tap it to open Android Settings → Installed services → Hermes-Relay and flip the switch."
|
||||
|
||||
Reference in New Issue
Block a user