diff --git a/hermes_cli/env_loader.py b/hermes_cli/env_loader.py index 4b05d363f1..60d7f7a740 100644 --- a/hermes_cli/env_loader.py +++ b/hermes_cli/env_loader.py @@ -100,11 +100,18 @@ def _record_supplied_names(report) -> set[str]: def secret_source_names() -> tuple[str, ...]: - """Every env-var name some profile's external secret source supplied (names only — the map is - process-wide, so a value must be resolved through the active profile's secret scope). Includes names - the source supplied but a pre-existing process value won (``skipped_existing``): the launch value - in ``os.environ`` is still not a routed profile's to inherit.""" - return tuple(dict.fromkeys((*_SECRET_SOURCES, *sorted(_SOURCE_SUPPLIED_NAMES)))) + """Every env-var name some profile's external secret source APPLIED (names only — the map is + process-wide, so a value must be resolved through the active profile's secret scope). Consumers that + forward source values into a child (MCP stdio env) want exactly these; see ``source_supplied_names`` + for the wider set the routed-child scrub needs.""" + return tuple(_SECRET_SOURCES) + + +def source_supplied_names() -> tuple[str, ...]: + """Every env-var name an external source supplied for any home — applied, or lost to a pre-existing + process value (``skipped_existing``). The launch value in ``os.environ`` is still not a routed + profile's to inherit, so the strip must see the skipped names too.""" + return tuple(sorted(set(_SECRET_SOURCES) | _SOURCE_SUPPLIED_NAMES)) def launch_dotenv_keys() -> frozenset[str]: diff --git a/tools/environments/local.py b/tools/environments/local.py index 5ce37a96aa..950571f357 100644 --- a/tools/environments/local.py +++ b/tools/environments/local.py @@ -354,7 +354,7 @@ def strip_launch_profile_env(env: dict, target_home: "str | Path | None" = None) if Path(target).resolve() == launch_home.resolve(): return env from hermes_cli.config import TERMINAL_CONFIG_ENV_MAP - from hermes_cli.env_loader import launch_dotenv_keys, managed_dotenv_keys, secret_source_names + from hermes_cli.env_loader import launch_dotenv_keys, managed_dotenv_keys, source_supplied_names # Current file AND every key any dotenv load put into os.environ this process lifetime: a key # removed or renamed in the launch .env after boot is still in os.environ with the old value, and # a re-parse of the file alone no longer names it (#107695 review). External secret sources @@ -364,7 +364,7 @@ def strip_launch_profile_env(env: dict, target_home: "str | Path | None" = None) # .env is NOT residue: its values are policy for every profile (``_apply_managed_env`` applies # it last, with override, so it beats the user's own .env) — leave them in place. residue = set(load_env_file(launch_home / ".env")) | set(launch_dotenv_keys()) | set(TERMINAL_CONFIG_ENV_MAP.values()) - residue |= set(secret_source_names()) + residue |= set(source_supplied_names()) residue -= set(managed_dotenv_keys()) for key in residue: if not _is_global_env(key) or key.startswith("TERMINAL_"):