Extract Cortex OS Hermes WebUI Host Adapter
This commit is contained in:
parent
8b6c810f4a
commit
1707a7b09d
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Upstream version:** v0.51.118
|
**Upstream version:** v0.51.118
|
||||||
**Plugin version:** 0.5.0
|
**Plugin version:** 0.5.0
|
||||||
**Total dependencies:** 61 (40 public API · 0 forced internal · 21 frontend)
|
**Total dependencies:** 62 (41 public API · 0 forced internal · 21 frontend)
|
||||||
|
|
||||||
> **Auto-generated by `scripts/ast-connection-map.py`. Do not hand-edit.**
|
> **Auto-generated by `scripts/ast-connection-map.py`. Do not hand-edit.**
|
||||||
> To change a justification, edit the `# CONNECTION:` comment above the
|
> To change a justification, edit the `# CONNECTION:` comment above the
|
||||||
@ -14,21 +14,19 @@
|
|||||||
|
|
||||||
| Plugin location | Upstream symbol | Snippet |
|
| Plugin location | Upstream symbol | Snippet |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `plugin.py:29` | `api.logger` | `log = api.logger("svrnty.plugin")` |
|
| `plugin.py:31` | `api.logger` | `log = api.logger("svrnty.plugin")` |
|
||||||
| `plugin.py:34` | `api.register_static` | `api.register_static(STATIC_PREFIX, str(STATIC_DIR))` |
|
| `plugin.py:36` | `api.register_static` | `api.register_static(STATIC_PREFIX, str(STATIC_DIR))` |
|
||||||
| `plugin.py:35` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/app.css")` |
|
| `plugin.py:37` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/app.css")` |
|
||||||
| `plugin.py:36` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/app.js")` |
|
| `plugin.py:38` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/app.js")` |
|
||||||
| `plugin.py:39` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/svrnty_nav.js")` |
|
| `plugin.py:41` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/svrnty_nav.js")` |
|
||||||
| `plugin.py:42` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/adwright.css")` |
|
| `plugin.py:44` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/adwright.css")` |
|
||||||
| `plugin.py:43` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/adwright.js")` |
|
| `plugin.py:45` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/adwright.js")` |
|
||||||
| `plugin.py:45` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/bte.css")` |
|
| `plugin.py:47` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/bte.css")` |
|
||||||
| `plugin.py:46` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/bte.js")` |
|
| `plugin.py:48` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/bte.js")` |
|
||||||
| `plugin.py:48` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/canvas.css")` |
|
| `plugin.py:50` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/canvas.css")` |
|
||||||
| `plugin.py:49` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/canvas.js")` |
|
| `plugin.py:51` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/canvas.js")` |
|
||||||
| `plugin.py:51` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/umbrella_inline.css")` |
|
| `plugin.py:53` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/umbrella_inline.css")` |
|
||||||
| `plugin.py:52` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/umbrella_inline.js")` |
|
| `plugin.py:54` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/umbrella_inline.js")` |
|
||||||
| `plugin.py:54` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.c` |
|
|
||||||
| `plugin.py:55` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.js")` |
|
|
||||||
| `routes/adwright.py:68` | `api.logger` | `log = api.logger("svrnty.routes.adwright")` |
|
| `routes/adwright.py:68` | `api.logger` | `log = api.logger("svrnty.routes.adwright")` |
|
||||||
| `routes/adwright.py:69` | `api.register_route` | `api.register_route(` |
|
| `routes/adwright.py:69` | `api.register_route` | `api.register_route(` |
|
||||||
| `routes/adwright.py:71` | `api.register_route` | `api.register_route(` |
|
| `routes/adwright.py:71` | `api.register_route` | `api.register_route(` |
|
||||||
@ -44,6 +42,9 @@
|
|||||||
| `routes/canvas.py:57` | `api.register_route` | `api.register_route("/api/canvas/command", "POST", _handle_command)` |
|
| `routes/canvas.py:57` | `api.register_route` | `api.register_route("/api/canvas/command", "POST", _handle_command)` |
|
||||||
| `routes/canvas.py:58` | `api.register_route` | `api.register_route("/api/canvas/design-context", "GET", _handle_design_context)` |
|
| `routes/canvas.py:58` | `api.register_route` | `api.register_route("/api/canvas/design-context", "GET", _handle_design_context)` |
|
||||||
| `routes/canvas.py:59` | `api.register_route` | `api.register_route("/api/canvas/events", "GET", _handle_events)` |
|
| `routes/canvas.py:59` | `api.register_route` | `api.register_route("/api/canvas/events", "GET", _handle_events)` |
|
||||||
|
| `routes/cortex_os_extension.py:17` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_extension")` |
|
||||||
|
| `routes/cortex_os_extension.py:21` | `api.inject_stylesheet` | `api.inject_stylesheet(stylesheet)` |
|
||||||
|
| `routes/cortex_os_extension.py:22` | `api.inject_script` | `api.inject_script(script)` |
|
||||||
| `routes/cortex_os_runtime_health.py:26` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_runtime_health")` |
|
| `routes/cortex_os_runtime_health.py:26` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_runtime_health")` |
|
||||||
| `routes/cortex_os_runtime_health.py:27` | `api.register_route` | `api.register_route(ROUTE_PATH, ROUTE_METHOD, _handle_runtime_health)` |
|
| `routes/cortex_os_runtime_health.py:27` | `api.register_route` | `api.register_route(ROUTE_PATH, ROUTE_METHOD, _handle_runtime_health)` |
|
||||||
| `routes/transcribe.py:37` | `api.logger` | `log = api.logger("svrnty.routes.transcribe")` |
|
| `routes/transcribe.py:37` | `api.logger` | `log = api.logger("svrnty.routes.transcribe")` |
|
||||||
|
|||||||
@ -35,12 +35,14 @@ assets:
|
|||||||
- /plugins/svrnty/bte.js
|
- /plugins/svrnty/bte.js
|
||||||
- /plugins/svrnty/canvas.js
|
- /plugins/svrnty/canvas.js
|
||||||
- /plugins/svrnty/umbrella_inline.js
|
- /plugins/svrnty/umbrella_inline.js
|
||||||
|
- /plugins/svrnty/cortex-os/runtime-health/runtime_health.js
|
||||||
stylesheets:
|
stylesheets:
|
||||||
- /plugins/svrnty/app.css
|
- /plugins/svrnty/app.css
|
||||||
- /plugins/svrnty/adwright.css
|
- /plugins/svrnty/adwright.css
|
||||||
- /plugins/svrnty/bte.css
|
- /plugins/svrnty/bte.css
|
||||||
- /plugins/svrnty/canvas.css
|
- /plugins/svrnty/canvas.css
|
||||||
- /plugins/svrnty/umbrella_inline.css
|
- /plugins/svrnty/umbrella_inline.css
|
||||||
|
- /plugins/svrnty/cortex-os/runtime-health/runtime_health.css
|
||||||
|
|
||||||
# Routes this plugin registers at load time (declarative cross-check vs runtime).
|
# Routes this plugin registers at load time (declarative cross-check vs runtime).
|
||||||
# Each row maps to a routes/<file>.py.
|
# Each row maps to a routes/<file>.py.
|
||||||
@ -59,6 +61,7 @@ routes:
|
|||||||
- { path: /api/canvas/command, method: POST, file: routes/canvas.py, status: live }
|
- { path: /api/canvas/command, method: POST, file: routes/canvas.py, status: live }
|
||||||
- { path: /api/canvas/design-context, method: GET, file: routes/canvas.py, status: seed }
|
- { path: /api/canvas/design-context, method: GET, file: routes/canvas.py, status: seed }
|
||||||
- { path: /api/canvas/events, method: GET, file: routes/canvas.py, status: seed }
|
- { path: /api/canvas/events, method: GET, file: routes/canvas.py, status: seed }
|
||||||
|
- { path: /api/cortex-os/runtime-health, method: GET, file: routes/cortex_os_extension.py, status: live }
|
||||||
|
|
||||||
# Audio-attachment processors (called by streaming.py before agent receives message).
|
# Audio-attachment processors (called by streaming.py before agent receives message).
|
||||||
audio_processors:
|
audio_processors:
|
||||||
|
|||||||
@ -14,6 +14,8 @@ in `static/`. The map of every upstream dependency is in CONNECTION-MAP.md
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from routes import cortex_os_extension
|
||||||
|
|
||||||
# Static + asset URL prefix (per protocol §12, decision Q5: /plugins/svrnty/<asset>)
|
# Static + asset URL prefix (per protocol §12, decision Q5: /plugins/svrnty/<asset>)
|
||||||
STATIC_PREFIX = "svrnty"
|
STATIC_PREFIX = "svrnty"
|
||||||
STATIC_DIR = Path(__file__).resolve().parent / "static"
|
STATIC_DIR = Path(__file__).resolve().parent / "static"
|
||||||
@ -50,11 +52,11 @@ def register(api):
|
|||||||
# Inline Umbrella graph for the Hermes Workspace right panel.
|
# Inline Umbrella graph for the Hermes Workspace right panel.
|
||||||
api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/umbrella_inline.css")
|
api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/umbrella_inline.css")
|
||||||
api.inject_script(f"/plugins/{STATIC_PREFIX}/umbrella_inline.js")
|
api.inject_script(f"/plugins/{STATIC_PREFIX}/umbrella_inline.js")
|
||||||
# Cortex OS Runtime Health slice: read-only route status display.
|
|
||||||
api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.css")
|
|
||||||
api.inject_script(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.js")
|
|
||||||
log.info("static + assets wired at /plugins/%s/", STATIC_PREFIX)
|
log.info("static + assets wired at /plugins/%s/", STATIC_PREFIX)
|
||||||
|
|
||||||
|
# Cortex OS Plugin development mount: S23 Runtime Health read-only member.
|
||||||
|
cortex_os_extension.register(api, STATIC_PREFIX)
|
||||||
|
|
||||||
# Routes — each feature lives in its own module under routes/.
|
# Routes — each feature lives in its own module under routes/.
|
||||||
# Phase 2 will populate these. Import-and-register pattern; failures are
|
# Phase 2 will populate these. Import-and-register pattern; failures are
|
||||||
# logged but don't take down the rest of the plugin.
|
# logged but don't take down the rest of the plugin.
|
||||||
@ -84,5 +86,4 @@ def _phase2_routes():
|
|||||||
"bte_proxy", # P2.D — BTE Command Center same-origin proxy (PRD §3) ✓
|
"bte_proxy", # P2.D — BTE Command Center same-origin proxy (PRD §3) ✓
|
||||||
"canvas", # Sovereign Stitch-like design canvas proxy + event seed
|
"canvas", # Sovereign Stitch-like design canvas proxy + event seed
|
||||||
"umbrella", # P2.E — cortex-os umbrella graph viz (UMBRELLA-VIZ-PRD) ✓
|
"umbrella", # P2.E — cortex-os umbrella graph viz (UMBRELLA-VIZ-PRD) ✓
|
||||||
"cortex_os_runtime_health", # S23.0-I4 — Cortex OS Runtime Health read-only slice ✓
|
|
||||||
]
|
]
|
||||||
|
|||||||
30
routes/cortex_os_extension.py
Normal file
30
routes/cortex_os_extension.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"""Cortex OS Plugin Hermes WebUI Host Adapter extraction surface."""
|
||||||
|
|
||||||
|
from routes import cortex_os_runtime_health
|
||||||
|
|
||||||
|
PACKAGE_ID = "cortex-os-extension"
|
||||||
|
MEMBER_ID = "s23-runtime-health-read-only-slice"
|
||||||
|
ACTIVE_DEVELOPMENT_MOUNT_TARGET = "hermes-webui"
|
||||||
|
SURFACE_ID = "hermes-webui-host-adapter"
|
||||||
|
RUNTIME_HEALTH_ROUTE = "/api/cortex-os/runtime-health"
|
||||||
|
RUNTIME_HEALTH_METHOD = "GET"
|
||||||
|
RUNTIME_HEALTH_STYLESHEET = "/plugins/{static_prefix}/cortex-os/runtime-health/runtime_health.css"
|
||||||
|
RUNTIME_HEALTH_SCRIPT = "/plugins/{static_prefix}/cortex-os/runtime-health/runtime_health.js"
|
||||||
|
|
||||||
|
|
||||||
|
def register(api, static_prefix):
|
||||||
|
"""Register only the Cortex OS Runtime Health member for Hermes WebUI."""
|
||||||
|
log = api.logger("svrnty.routes.cortex_os_extension")
|
||||||
|
stylesheet = RUNTIME_HEALTH_STYLESHEET.format(static_prefix=static_prefix)
|
||||||
|
script = RUNTIME_HEALTH_SCRIPT.format(static_prefix=static_prefix)
|
||||||
|
|
||||||
|
api.inject_stylesheet(stylesheet)
|
||||||
|
api.inject_script(script)
|
||||||
|
cortex_os_runtime_health.register(api)
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"cortex-os-extension mounted: %s %s via %s",
|
||||||
|
RUNTIME_HEALTH_METHOD,
|
||||||
|
RUNTIME_HEALTH_ROUTE,
|
||||||
|
SURFACE_ID,
|
||||||
|
)
|
||||||
@ -13,6 +13,7 @@ import pytest
|
|||||||
|
|
||||||
PLUGIN_REPO = Path(__file__).resolve().parents[2]
|
PLUGIN_REPO = Path(__file__).resolve().parents[2]
|
||||||
FORK_REPO = PLUGIN_REPO.parent / "hermes-webui"
|
FORK_REPO = PLUGIN_REPO.parent / "hermes-webui"
|
||||||
|
MANIFEST = PLUGIN_REPO / "manifest.yaml"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
@ -85,6 +86,15 @@ def test_loader_register_wires_our_plugin(loader, monkeypatch):
|
|||||||
assert len(loader._AUDIO_PROCESSORS) == 1
|
assert len(loader._AUDIO_PROCESSORS) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_manifest_declares_cortex_os_runtime_health_surface():
|
||||||
|
manifest = MANIFEST.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert "/api/cortex-os/runtime-health" in manifest
|
||||||
|
assert "routes/cortex_os_extension.py" in manifest
|
||||||
|
assert "/plugins/svrnty/cortex-os/runtime-health/runtime_health.css" in manifest
|
||||||
|
assert "/plugins/svrnty/cortex-os/runtime-health/runtime_health.js" in manifest
|
||||||
|
|
||||||
|
|
||||||
def test_loader_noop_when_env_unset(loader, monkeypatch):
|
def test_loader_noop_when_env_unset(loader, monkeypatch):
|
||||||
"""No env var = no plugin loaded. Upstream behavior fully preserved."""
|
"""No env var = no plugin loaded. Upstream behavior fully preserved."""
|
||||||
monkeypatch.delenv("HERMES_WEBUI_PYTHON_PLUGIN", raising=False)
|
monkeypatch.delenv("HERMES_WEBUI_PYTHON_PLUGIN", raising=False)
|
||||||
|
|||||||
51
tests/unit/test_cortex_os_extension_adapter.py
Normal file
51
tests/unit/test_cortex_os_extension_adapter.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
from routes import cortex_os_extension
|
||||||
|
|
||||||
|
|
||||||
|
def test_adapter_constants_preserve_s27_identity():
|
||||||
|
assert cortex_os_extension.PACKAGE_ID == "cortex-os-extension"
|
||||||
|
assert cortex_os_extension.MEMBER_ID == "s23-runtime-health-read-only-slice"
|
||||||
|
assert cortex_os_extension.ACTIVE_DEVELOPMENT_MOUNT_TARGET == "hermes-webui"
|
||||||
|
assert cortex_os_extension.RUNTIME_HEALTH_METHOD == "GET"
|
||||||
|
assert cortex_os_extension.RUNTIME_HEALTH_ROUTE == "/api/cortex-os/runtime-health"
|
||||||
|
|
||||||
|
|
||||||
|
def test_adapter_registers_runtime_health_route_and_assets_only():
|
||||||
|
api = Mock()
|
||||||
|
api.logger.return_value = Mock()
|
||||||
|
|
||||||
|
cortex_os_extension.register(api, "svrnty")
|
||||||
|
|
||||||
|
api.inject_stylesheet.assert_called_once_with(
|
||||||
|
"/plugins/svrnty/cortex-os/runtime-health/runtime_health.css"
|
||||||
|
)
|
||||||
|
api.inject_script.assert_called_once_with(
|
||||||
|
"/plugins/svrnty/cortex-os/runtime-health/runtime_health.js"
|
||||||
|
)
|
||||||
|
api.register_route.assert_called_once()
|
||||||
|
method, path = api.register_route.call_args.args[:2]
|
||||||
|
assert method == "/api/cortex-os/runtime-health"
|
||||||
|
assert path == "GET"
|
||||||
|
api.register_static.assert_not_called()
|
||||||
|
api.config_get.assert_not_called()
|
||||||
|
api.register_audio_attachment_processor.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_adapter_source_has_no_forbidden_runtime_discovery():
|
||||||
|
source = cortex_os_extension.__loader__.get_source(cortex_os_extension.__name__)
|
||||||
|
forbidden = [
|
||||||
|
"glob(",
|
||||||
|
"rglob(",
|
||||||
|
"subprocess",
|
||||||
|
"os.walk",
|
||||||
|
"sot/08-OUTPUTS",
|
||||||
|
"hermes_webui",
|
||||||
|
"hermes_agent",
|
||||||
|
"register_static",
|
||||||
|
"config_get",
|
||||||
|
"register_audio_attachment_processor",
|
||||||
|
"product readiness",
|
||||||
|
]
|
||||||
|
for snippet in forbidden:
|
||||||
|
assert snippet not in source
|
||||||
Loading…
Reference in New Issue
Block a user