sx-host plan steps 1-2: defhelper + SX config + SXTP spec + nav tools

Step 1 — defhelper: SX-defined page data helpers replace Python helpers.
(defhelper name (params) body) in .sx files, using existing IO primitives
(query, action, service). Loaded into OCaml kernel as pure SX defines.

Step 2 — SX config: app-config.sx replaces app-config.yaml with (defconfig)
form. (env-get "VAR") resolves secrets from environment. Kebab-to-underscore
aliasing ensures backward compatibility with all 174 config consumers.

Also: SXTP protocol spec (applications/sxtp/spec.sx), docs article,
sx_nav move/delete modes, reactive-runtime moved to geography.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-28 15:18:45 +00:00
parent 27fd470ac8
commit 153f02c672
14 changed files with 734 additions and 43 deletions

View File

@@ -308,14 +308,30 @@ class OcamlBridge:
return
self._helpers_injected = True
try:
from .pages import get_page_helpers
from .pages import get_page_helpers, get_sx_helpers
import inspect
helpers = get_page_helpers("sx")
if not helpers:
self._helpers_injected = False
return
count = 0
# 1. Inject SX-defined helpers (defhelper) — pure SX, no Python bridge
# Load from all services since they're pure SX defines.
sx_helpers: dict[str, str] = {}
from .pages import _SX_HELPERS
for svc_helpers in _SX_HELPERS.values():
sx_helpers.update(svc_helpers)
for name, sx_source in sx_helpers.items():
try:
await self._send_command(f'(load-source "{_escape(sx_source)}")')
await self._read_until_ok(ctx=None)
count += 1
except OcamlBridgeError:
_logger.warning("Failed to inject SX helper: %s", name)
# 2. Inject Python helpers — wrapped as (helper "name" ...) IO bridge calls
helpers = get_page_helpers("sx")
for name, fn in helpers.items():
# Skip if already defined by defhelper (SX takes priority)
if name in sx_helpers:
continue
if callable(fn) and not name.startswith("~"):
try:
sig = inspect.signature(fn)
@@ -333,7 +349,12 @@ class OcamlBridge:
count += 1
except OcamlBridgeError:
pass
_logger.info("Injected %d page helpers into OCaml kernel", count)
if not count and not helpers and not sx_helpers:
self._helpers_injected = False
return
_logger.info("Injected %d page helpers into OCaml kernel (%d SX, %d Python)",
count, len(sx_helpers), count - len(sx_helpers))
except Exception as e:
_logger.warning("Helper injection failed: %s", e)
self._helpers_injected = False