Files
hermes-agent/scripts/releases/bundle_env.py
alt-glitch 65bc6727b4 feat(free-tier): send preview_full_connectors on account creation
HERMES_PREVIEW_FULL_CONNECTORS=true|false makes the free-tier mint send
{"preview_full_connectors": <bool>} in the /api/anonymous/create body, so
the account service can record the cohort on the account and gate
toolkits from it. Any other value (unset included) keeps the body {}.

The variable joins the desktop bundle-env allowlist (release script,
banner writer, channel request decoder, BUILDING.md) so a bundle can
bake it in. It is self-reported and visible in the packaged JS: the
service must treat it as a preference, not proof.
2026-10-06 18:00:58 -04:00

43 lines
1.7 KiB
Python

"""Non-secret environment defaults and explicit clears carried by a desktop bundle."""
from __future__ import annotations
from collections.abc import Sequence
import json
# Keep this list aligned with the Desktop bundle banner and channel decoder.
_ALLOWED = frozenset({
"HERMES_HOME", "HERMES_DATA_DIR_SUFFIX", "HERMES_DESKTOP_USER_DATA_DIR",
"HERMES_SHARED_AUTH_DIR", "HERMES_GUEST_ONBOARDING", "HERMES_PREVIEW_FULL_CONNECTORS",
})
def validate(values: object) -> dict[str, str | None]:
if not isinstance(values, dict):
raise ValueError("Bundle environment must be a JSON object")
for key, value in values.items():
if not isinstance(key, str) or key not in _ALLOWED:
raise ValueError(f"Bundle environment name is not permitted: {key}")
if value is not None and (not isinstance(value, str) or "\0" in value):
raise ValueError(f"Bundle environment value for {key} must be a string without NUL or null")
return values
def parse_assignments(assignments: list[str], unset: Sequence[str] = ()) -> dict[str, str | None]:
values: dict[str, str | None] = {}
for assignment in assignments:
key, separator, value = assignment.partition("=")
if not separator:
raise ValueError("--bundle-env requires NAME=VALUE")
if key in values:
raise ValueError(f"Duplicate bundle environment name: {key}")
values[key] = value
for key in unset:
if key in values:
raise ValueError(f"Duplicate bundle environment name: {key}")
values[key] = None
return validate(values)
def decode(raw: str) -> dict[str, str | None]:
return validate(json.loads(raw or "{}"))