svrnty-hermes-webui-plugin/plugin.py
Svrnty c1e3fa1af0
All checks were successful
plugin-tests / test (push) Successful in 25s
feat(plugin): Phase 2 partial — vault_status migrated + brand skin moved + eval suite (P2.B/C, P3.A/B)
Lands the easy migrations + the automation skeleton. STT migration deferred
to Phase 2.1 (it touches the streaming engine + bootstrap JS — needs a new
streaming_hook public-API method OR forced-internal CONNECTION-MAP entries).

Migrated to plugin:
  routes/vault_status.py    GET /api/vault/status (from fork commit 3e2c74f3)
  static/{app.js,app.css,fonts/}  brand skin (from hermes-ext/)

Plugin auto-loaded by hermes-webui when HERMES_WEBUI_PYTHON_PLUGIN is set;
register_static + inject_stylesheet + inject_script wire the URL contract at
/plugins/svrnty/{app.css,app.js} per protocol §14 (Q5).

Automation skeleton:
  Makefile                          one-liner targets: test · map · sync-upstream · smoke
  scripts/boot-smoke.py             start upstream+plugin, curl every endpoint
  scripts/upstream-sync.py          fetch tags + run matrix + JSON report
  tests/evals/test_features.py      4 evals (loader contract · vault payload · brand URL contract · forced-internal=0)
  tests/unit/test_brand_skin.py     4 asset-presence + wiring tests
  tests/unit/test_vault_status.py   3 handler tests (register, success, error)

CONNECTION-MAP.md: 0 forced-internal dependencies; plugin uses only public API.
AST script timestamp removed so map-check is deterministic.

Tests: 11/11 PASS (4 evals + 7 unit). Integration tests deferred until
boot-smoke runs against a live hermes-webui (Phase 2.D + 2.E gate).

Deferred to next session:
  P2.A  STT migration (needs streaming_hook design — see routes/transcribe.py)
  P2.D  Revert 4 fork feature commits — needs STT migration first
  P2.E  Archive hermes-ext repo — gated on P2.D
  P2.F  Live boot smoke against real webui

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 10:02:47 -04:00

65 lines
2.7 KiB
Python

"""svrnty-hermes-webui-plugin — entry point.
Called by hermes-webui's plugin loader at startup (after the env var
HERMES_WEBUI_PYTHON_PLUGIN points the loader at this module).
The loader passes a single `api` argument exposing 6 methods (see CLAUDE.md +
protocol PRD §5.1). This module's job is to wire every route + static dir +
asset injection that defines the Svrnty surface on hermes-webui.
Keep this file thin. Route logic lives in `routes/<feature>.py`. Static lives
in `static/`. The map of every upstream dependency is in CONNECTION-MAP.md
(AST-generated by scripts/ast-connection-map.py).
"""
import os
from pathlib import Path
# Static + asset URL prefix (per protocol §12, decision Q5: /plugins/svrnty/<asset>)
STATIC_PREFIX = "svrnty"
STATIC_DIR = Path(__file__).resolve().parent / "static"
def register(api):
"""Wire every Svrnty modification to hermes-webui.
`api` is the loader-provided extension surface (6 methods). Treat it as the
ONLY public contract. Touching anything else in hermes-webui requires a
`CONNECTION-MAP.md` forced-internal entry with justification.
"""
log = api.logger("svrnty.plugin")
log.info("svrnty-hermes-webui-plugin: registering")
# Brand skin: serve static dir + inject CSS/JS into every page load.
if STATIC_DIR.exists():
api.register_static(STATIC_PREFIX, str(STATIC_DIR))
api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/app.css")
api.inject_script(f"/plugins/{STATIC_PREFIX}/app.js")
log.info("static + assets wired at /plugins/%s/", STATIC_PREFIX)
# Routes — each feature lives in its own module under routes/.
# Phase 2 will populate these. Import-and-register pattern; failures are
# logged but don't take down the rest of the plugin.
for route_module in _phase2_routes():
try:
mod = __import__(f"routes.{route_module}", fromlist=["register"])
mod.register(api)
log.info("route module loaded: %s", route_module)
except ImportError as e:
log.warning("route module %s not yet implemented (Phase 2): %s", route_module, e)
except Exception as e:
log.error("route module %s failed to register: %s", route_module, e)
log.info("svrnty-hermes-webui-plugin: registration complete")
def _phase2_routes():
"""Routes to attempt loading. Returns module names under routes/.
Phase 2 migrates the existing fork commits into these modules. Until then,
ImportError is logged + swallowed so the plugin loads cleanly.
"""
return [
# "transcribe", # P2.A — STT (deferred — needs streaming.py integration refactor)
"vault_status", # P2.B — vault connections status ✓
]