+
    iHàjÂW  ã                  ó4  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
HtHt ^ RIHt ^ RIHtHtHtHtHtHt RsR]R	&   Rs]! R
RR7      tR]R
&   R R ltR R ltR R ltR R lt ! R R]4      tR R lt]! RRR7      t R]R&   ]! RRR7      t!R]R&   R R lt"R R  lt# ! R! R"]$4      t%R#R/R$ R% llt&R& R' lt'R( R) lt(R* R+ lt)]*! 0 R,kR-kR.kR/kR0kR1kR2kR3kR4kR5kR6kR7kR8kR9kR:kR;kR<kR=kR>kR?kR@kRAkRBkRCkRDkREkRFkRGkRHkRIkRJkRKkRLkRMkRNkROk4      t+Rlt,RP RQ lt-RR RS lt.RmRT RU llt/RnRV RW llt0RX RY lt1RZ R[ lt2]	! 4       t3R\]R]&   ]Ph                  ! 4       t5^@t6RmR^ R_ llt7R` Ra lt8Rb Rc lt9Rd Re lt:Rf Rg lt;Rh Ri lt<Rj Rk lt=R# )oaÓ  Profile-scoped credential resolution for multi-profile gateway multiplexing.

The multiplexing gateway serves many profiles from one process; each profile's
``.env`` keys **cannot** be unioned into ``os.environ`` (profile A's keys would
leak into profile B's turns and subprocesses). This module is a fail-closed,
context-local secret scope: ``set_secret_scope(mapping)`` installs the active
profile's secrets for the current task (a contextvar, so it propagates into the
agent's worker thread via ``copy_context()``); ``get_secret(name)`` reads from
it and, when multiplexing is active with no scope set, RAISES rather than
falling back to ``os.environ``. Design: ``website/docs/developer-guide/multiplexing-gateway.md``.
)ÚannotationsN)ÚOrderedDict)Ú
ContextVarÚToken)ÚPath)ÚCallableÚDictÚMappingÚ
NamedTupleÚOptionalÚTupleFÚboolÚ_MULTIPLEX_ACTIVEÚ_MULTIPLEX_CONTEXT)ÚdefaultzContextVar[bool]c               ó    € V ^8„  d   QhRRRR/# )é   Úactiver   ÚreturnÚNone© )Úformats   "Ú7/home/ubuntu/.hermes/hermes-agent/agent/secret_scope.pyÚ__annotate__r   '   s   € ÷ !ñ ! ð !¨$ñ !ó    c                óØ   € ^ RI HpHpHp \	        V 4      s\
        '       d%   V! 4       '       g   V! 4       sV! \        4       R# R# \        e   V! 4       \        8X  d	   V! R4       RsR# R# )u}  Mark whether the process is a profile multiplexer (get_secret fails closed).

Activation also pins the launch home for routed-profile decisions
(``hermes_constants.pin_process_hermes_home``) unless an embedding host already pinned one:
from here on "is this task routed" compares the override against the home the process was
launched with, not against whatever a host later mirrors into ``os.environ["HERMES_HOME"]``.
Deactivation releases only the pin activation itself created â€” a transient toggle
(``gateway_migrate._multiplex_read_mode``, a cron worker restoring the caller's mode) must not
drop the host's explicit pin (#119242).)Úget_routing_process_hermes_homeÚpin_process_hermes_homeÚprocess_hermes_home_is_pinnedN)Úhermes_constantsr   r   r   r   r   Ú_AUTO_PINNED_HOME)r   r   r   r   s   &   r   Úset_multiplex_activer!   '   se   € ÷ñ ô
 ˜V›ÐßÓÙ,×.Ò.Ù ?Ó AÐÙ#Ô$5Ö6ñ /ô 
Ò	&Ù*Ó,Ô0AÔAÙ# DÔ)Ø Òñ 
'r   c               ó    € V ^8„  d   QhRRRR/# )r   r   r   r   r   r   )r   s   "r   r   r   B   s   € ÷ 0ñ 0 $ð 0¨5ñ 0r   c                ó>   € \         P                  \        V 4      4      # )z¡Run the current task under multiplex semantics regardless of the process flag.
Returns a reset token; pair with :func:`reset_multiplex_context` in a ``finally``.)r   Úsetr   )r   s   &r   Úset_multiplex_contextr%   B   s   € ô ×!Ñ!¤$ v£,Ó/Ð/r   c               ó    € V ^8„  d   QhRRRR/# ©r   Útokenr   r   r   r   )r   s   "r   r   r   H   ó   € ÷ $ñ $ 5ð $¨Tñ $r   c                ó0   € \         P                  V 4       R # ©N)r   Úreset©r(   s   &r   Úreset_multiplex_contextr.   H   ó   € Ü×Ñ˜UÖ#r   c               ó   € V ^8„  d   QhRR/# ©r   r   r   r   )r   s   "r   r   r   L   s   € ÷ 9ñ 9˜Tñ 9r   c                 óF   € \         ;'       g    \        P                  4       # )zPTrue in a multiplexing process, or for a task running under multiplex semantics.)r   r   Úgetr   r   r   Úis_multiplex_activer4   L   s   € ä×8Ð8Ô 2× 6Ñ 6Ó 8Ð8r   c                  ó0   € ] tR t^Qt$ RtR]R&   R]R&   RtR# )Ú_BoundScopeuó   An installed secret scope plus the home it was built for, when the binder
declared one â€” the provenance ``serves_routed_profile`` needs when the binding
deliberately skips the HERMES_HOME override (kanban spawn-env builds, MCP
owner scopes).zMapping[str, str]ÚmappingúOptional[str]Úprofile_homer   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__Ú__static_attributes__r   r   r   r6   r6   Q   s   ‡ ñð
 ÓØ×r   r6   c               ó   € V ^8„  d   QhRR/# r1   r   )r   s   "r   r   r   [   s   € ÷ Eñ E˜tñ Er   c                 ó  € \        4       '       d   R# ^ RIHp HpHp V! V! 4       4      p\
        P                  4       pVe,   VP                  '       d   V! VP                  4      V8w  d   R# V ! 4       pVRJ;'       d    V! V4      V8g  # )aG  True when the current task runs for a profile other than the process's own: always under
multiplexing, else when a HERMES_HOME override names another home (dashboard/desktop backend,
per-profile cron ticker) or a secret scope stamped with a foreign home is bound. The MCP
registry scope and the check_fn cache key both follow this predicate so a served profile's
view never aliases the launch profile's (#111151). A host that mirrors the turn's profile into
``HERMES_HOME`` pins its own home with ``hermes_constants.pin_process_hermes_home`` so the
mirror cannot flip this predicate.T)Úget_hermes_home_overrider   Úhermes_home_keyN)r4   r   rC   r   rD   Ú_SECRET_SCOPEr3   r9   )rC   r   rD   ÚownÚboundÚoverrides         r   Úserves_routed_profilerI   [   s~   € ô ×ÒÙßkÑkÙ
Ñ9Ó;Ó
<€CÜ×ÑÓ€EØÒ˜U×/×/Ð/±OÀE×DVÑDVÓ4WÐ[^Ô4^ÙÙ'Ó)€HØ˜4Ð×DÐD¡O°HÓ$=ÀÑ$DÐDr   rE   z!ContextVar[Optional[_BoundScope]]Ú_LAUNCH_BODY_SCOPEz5ContextVar[Optional[Callable[[], Mapping[str, str]]]]c               ó    € V ^8„  d   QhRRRR/# )r   ÚresolverzCallable[[], Mapping[str, str]]r   r   r   )r   s   "r   r   r   v   s   € ÷ ,ñ ,Ð$Cð ,Èñ ,r   c                ó,   € \         P                  V 4      # r+   )rJ   r$   )rL   s   &r   Úset_launch_body_scoperN   v   s   € Ü×!Ñ! (Ó+Ð+r   c               ó    € V ^8„  d   QhRRRR/# r'   r   )r   s   "r   r   r   z   r)   r   c                ó0   € \         P                  V 4       R # r+   )rJ   r,   r-   s   &r   Úreset_launch_body_scoperQ   z   r/   r   c                  ó6   a € ] tR t^~tRtRR V 3R llltRtV ;t# )ÚUnscopedSecretErrorak  A secret was read in multiplex mode with no scope installed.

The fix is to wrap the call path in ``set_secret_scope(...)`` (the per-turn
/ per-adapter profile scope), not to widen the global allowlist.

``str(exc)`` is the ONE sentence an end user can act on; the developer diagnosis
(which secret, which doc) rides ``__notes__`` so tracebacks and logs keep it.
c               ó    € V ^8„  d   QhRRRR/# )r   Úsecret_nameÚstrÚdeveloper_detailr   )r   s   "r   r   Ú UnscopedSecretError.__annotate__ˆ   s   € ÷ ,ñ , Cð ,Àñ ,r   c                	ó4  <€ V'       dF   V'       g>   \         ;QJ d    R  V 4       F  '       g   K   RM	  RM! R  V 4       4      '       d   RTr!V'       d   RV 2MRp\        SV `	  RV R24       Wn        W n        V'       d   V P                  V4       R# R# )	c              3  ó@   "  € T F  qP                  4       x € K  	  R # 5ir+   )Úisspace)Ú.0Úchs   & r   Ú	<genexpr>Ú/UnscopedSecretError.__init__.<locals>.<genexpr>Œ   s   é € Ð7[É{È¿
¹
¿¸Ë{ùs   ‚TFÚ zthis profile's zthis profile's API keyzHermes could not read z° (an internal profile-scoping bug on the multiplexed gateway, not your configuration). Run `hermes gateway restart`; if it keeps happening, report it with `hermes debug share`.N)ÚanyÚsuperÚ__init__rU   rW   Úadd_note)ÚselfrU   rW   ÚwhatÚ	__class__s   &&& €r   rc   ÚUnscopedSecretError.__init__ˆ   s…   ø€ ÷ ×/·C³CÑ7[É{Ó7[·C·C²CÑ7[É{Ó7[×4[Ò4[Ø,.°Ð)ß2=�  Ñ.ÐC[ˆÜ‰ÑØ$ T Fð +3ð 3ô	
ð
 'ÔØ 0ÔßØ�M‰MÐ*Ö+ñ r   )rW   rU   )r`   r`   )r:   r;   r<   r=   r>   rc   r@   Ú__classcell__)rg   s   @r   rS   rS   ~   s   ø† ñ÷,÷ ,ð ,r   rS   r9   c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚsecretsúOptional[Mapping[str, str]]r9   r8   r   r   r   )r   s   "r   r   r   š   s(   € ÷ `ñ `Ð9ð `ÈMð `Ðejñ `r   c               ó¦   € V f   \         P                  R4      # \         P                  \        Y'       d   \        V4      4      4      # R4      4      # )a  Install the active profile's secret mapping; ``None`` clears. Returns a reset token.

``profile_home`` stamps the home the mapping was built for so
``serves_routed_profile`` detects a foreign-home scope even when the binder
deliberately skips the HERMES_HOME override.N)rE   r$   r6   rV   )rk   r9   s   &$r   Úset_secret_scopern   š   sE   € ð ‚Ü× Ñ  Ó&Ð&Ü×Ñœ[¨Æ|´#°lÓ2CÓ^Ó_Ð_ÐY]Ó^Ó_Ð_r   c               ó    € V ^8„  d   QhRRRR/# r'   r   )r   s   "r   r   r   ¥   s   € ÷ ñ ˜eð ¨ñ r   c                ó0   € \         P                  V 4       R # r+   )rE   r,   r-   s   &r   Úreset_secret_scoperq   ¥   s   € Ü×Ñ˜Ör   c               ó   € V ^8„  d   QhRR/# )r   r   rl   r   )r   s   "r   r   r   ©   s   € ÷ 8ñ 8Ð9ñ 8r   c                 óN   € \         P                  4       p V e   V P                  # R# )z>The active secret mapping, or None when no scope is installed.N)rE   r3   r7   ©rG   s    r   Úcurrent_secret_scoperu   ©   s$   € ä×ÑÓ€EØ!Ò-ˆ5�=‰=Ð7°4Ð7r   c               ó   € V ^8„  d   QhRR/# )r   r   r8   r   )r   s   "r   r   r   ¯   s   € ÷ =ñ = =ñ =r   c                 óN   € \         P                  4       p V e   V P                  # R# )zKThe home the active scope was stamped with, or None when unstamped/unbound.N)rE   r3   r9   rt   s    r   Úcurrent_secret_scope_homerx   ¯   s&   € ä×ÑÓ€EØ!&Ò!2ˆ5×ÑÐ<¸Ð<r   ÚHERMES_HOMEÚHERMES_PROFILEÚHERMES_GATEWAY_LOCK_DIRÚHERMES_MAX_ITERATIONSÚHERMES_API_TIMEOUTÚHERMES_REDACT_SECRETSÚHERMES_NOUS_TIMEOUT_SECONDSÚ_HERMES_GATEWAYÚPATHÚHOMEÚUSERÚLANGÚLC_ALLÚTZÚPWDÚSHELLÚTMPDIRÚVIRTUAL_ENVÚ
PYTHONPATHÚSSL_CERT_FILEÚHERMES_KANBAN_DBÚHERMES_KANBAN_WORKSPACES_ROOTÚHERMES_KANBAN_BOARDÚAPI_SERVER_ENABLEDÚAPI_SERVER_HOSTÚAPI_SERVER_PORTÚAPI_SERVER_CORS_ORIGINSÚGATEWAY_RELAY_URLÚGATEWAY_RELAY_ENDPOINTÚ$GATEWAY_RELAY_ALLOW_DIRECT_PLATFORMSÚGATEWAY_RELAY_PLATFORMSÚGATEWAY_RELAY_BOT_IDSÚGATEWAY_RELAY_ROUTE_KEYSÚGATEWAY_RELAY_INSTANCE_IDÚGATEWAY_RELAY_WAKE_URLÚGATEWAY_RELAY_DISPLAY_NAMEc               ó    € V ^8„  d   QhRRRR/# )r   ÚnamerV   r   r   r   )r   s   "r   r   r   Ü   s   € ÷ Nñ N˜ð N ñ Nr   c                óN   € V \         9   ;'       g    V P                  \        4      # )z@True for genuinely process-global (non-profile-secret) env vars.)Ú_GLOBAL_ENV_EXACTÚ
startswithÚ_GLOBAL_ENV_PREFIXES)rž   s   &r   Ú_is_global_envr£   Ü   s    € àÔ$Ñ$×MÐM¨¯©Ô8LÓ(MÐMr   c               ó$   € V ^8„  d   QhRRRRRR/# ©r   rž   rV   r   r8   r   r   )r   s   "r   r   r   á   s!   € ÷ /ñ /�cð / Mð /°mñ /r   c                óP   € \         P                  P                  V 4      pVe   V# T# r+   )ÚosÚenvironr3   ©rž   r   Úvals   && r   Ú_environ_orr«   á   s#   € Ü
�*‰*�.‰.˜Ó
€CØ’/ˆ3Ð. wÐ.r   c               ó$   € V ^8„  d   QhRRRRRR/# r¥   r   )r   s   "r   r   r   æ   s!   € ÷ &ñ &�Sð & =ð &¸Mñ &r   c                óš  € \        V 4      '       d   \        W4      # \        P                  4       pVe?   VP                  P                  V 4      pVe   V# \        4       '       d   V# \        W4      # \        4       '       d@   \        P                  4       pVe   V! 4       P                  W4      # \        V RV : R24      h\        W4      # )u  Resolve a credential by env-var name, honoring the active profile scope.

Global vars always read ``os.environ``. With a scope installed, a miss returns
``default`` under multiplexing (never another profile's ``os.environ`` value)
but falls through to ``os.environ`` otherwise â€” single-profile deployments
inject credentials via the process env (systemd, ``op run``), so the scope
must stay a ``.env`` overlay, not a blindfold (otherwise cron 401s). With no
scope: multiplex INACTIVE reads ``os.environ``; ACTIVE raises (fail closed).
zget_secret(aB  ) called with no profile secret scope active while multiplexing is on. This credential read must run inside a set_secret_scope(...) block (the per-turn / per-adapter profile scope). Reading os.environ here would risk leaking another profile's value. See website/docs/developer-guide/multiplexing-gateway.md (Workstream A).)	r£   r«   rE   r3   r7   rI   r4   rJ   rS   )rž   r   rG   rª   Úlaunch_scopes   &&   r   Ú
get_secretr¯   æ   sÂ   € ô �d×ÒÜ˜4Ó)Ð)Ü×ÑÓ€EØÒØ�m‰m×Ñ Ó%ˆØŠ?ØˆJÜ/×1Ò1ˆwÐQ´{À4Ó7QÐQÜ×ÒÜ)×-Ñ-Ó/ˆØÒ#Ù“>×%Ñ% dÓ4Ð4Ü!ØØ˜$™ð "ð ó
ð 	
ô �tÓ%Ð%r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rž   rV   r   r   r   )r   s   "r   r   r     s!   € ÷ +ñ +˜ð + sð +°Cñ +r   c                ó(   € \        W4      pVf   V# T# )u³   ``get_secret`` for callers that want a ``str``: ``default`` only when the secret is genuinely
unset. Still raises ``UnscopedSecretError`` â€” swallowing it hides a spawn-site bug.)r¯   r©   s   && r   Úget_secret_strr²     s   € ô �TÓ
#€CØ’kˆ7Ð* sÐ*r   c               ó    € V ^8„  d   QhRRRR/# )r   ÚvaluerV   r   r   )r   s   "r   r   r     s   € ÷ ;ñ ; ð ;¨ñ ;r   c                ó¶  € V P                  4       p V '       g   V # V ^ ,          pVR9   dƒ   ^pV\        V 4      8  do   W,          pVR8X  d   VR8X  d   V^,          pK1  W18X  d=   W^,           R P                  4       P                  R4      '       d   V RV^,            # T # V^,          pK~  V # \        P
                  ! RV ^R7      ^ ,          P                  4       # )u:  Strip a dotenv-style inline comment (python-dotenv semantics): quoted values
scan to the matching close quote (backslash-aware for double quotes) and drop a
trailing ``# ...``, else stay untouched; unquoted values truncate only at a
``#`` PRECEDED BY WHITESPACE (``foo#bar`` survives, ``value # c`` â†’ ``value``).Ú"Ú\NÚ#z\s+#)Úmaxsplit)Ú'r¶   )ÚstripÚlenÚlstripr¡   ÚreÚsplit)r´   ÚquoteÚir]   s   &   r   Ú_strip_inline_commentrÂ     sÃ   € ð
 �K‰K‹M€EßØˆØ�!�H€EØ�
ÔØˆØ”#�e“*ŒnØ•ˆBØ˜Œ|  d¤
Ø�Q•�ÙØŒ{Ø).°1­u¨v¨×)=Ñ)=Ó)?×)JÑ)JÈ3×)OÒ)O�u˜W˜q 1�u�~ÐZÐUZÐZØ��FŠAØˆÜ�8Š8�G˜U¨QÔ/°Õ2×8Ñ8Ó:Ð:r   c               ó    € V ^8„  d   QhRRRR/# )r   Ú	raw_valuerV   r   r   )r   s   "r   r   r   &  s   € ÷ ñ  ð ¨ñ r   c                ó  € V P                  4       p\        V4      ^8¼  dµ   V^ ,          VR,          u;8X  d   R8X  d˜   M M”V^R p. p^ pV\        V4      8  dk   W$,          R8H  ;'       d    W$^,           V^,            R9   pTP                  V'       d   W$^,           ,          MW$,          4       YE'       d   ^M^,          pKz  RP                  V4      # \        V4      ^8¼  d'   V^ ,          VR,          u;8X  d   R8X  d
   M V# V^R # V# )zrParse the small .env value subset Hermes writes itself (bare, 'single', or "double" with
``\"`` / ``\\`` escapes).r¶   r·   r`   rº   éÿÿÿÿ)r¶   r·   )r»   r¼   ÚappendÚjoin)rÄ   r´   ÚquotedÚparsedrÁ   Úescapeds   &     r   Ú_parse_env_valuerÌ   &  sà   € ð �O‰OÓ€EÜ
ˆ5ƒz�Q„˜5 �8 u¨R¥yÖ7°C×7Ø�q˜�ˆØˆØˆØ”#�f“+ŒoØ•i 4Ñ'×NÐN¨F°qµ5¸¸Q½Ð,?À;Ñ,NˆGØ�M‰M¯7˜& Q¥ž-¸½	ÔBØ–g‘ 1Õ$ŠAØ�w‰w�v‹ÐÜ
ˆ5ƒz�Q„˜5 �8 u¨R¥yÖ7°CÖ7à€Lð �Q�rˆ{ÐØ€Lr   z.OrderedDict[str, tuple[bytes, dict[str, str]]]Ú_ENV_FILE_CACHEc               ó    € V ^8„  d   QhRRRR/# )r   Úenv_pathzOptional[Path]r   r   r   )r   s   "r   r   r   I  s   € ÷ 5ñ 5¨ð 5À$ñ 5r   c                óÌ   € \         ;_uu_ 4        V f   \        P                  4        M\        P                  \	        V 4      R4       RRR4       R#   + '       g   i     R# ; i)z@Drop one path from the ``load_env_file()`` memo, or all of them.N)Ú_ENV_FILE_CACHE_LOCKrÍ   ÚclearÚpoprV   )rÏ   s   &r   Úinvalidate_env_file_cacherÔ   I  s=   € ç	Ö	ØÒÜ×!Ñ!Õ#ä×Ñ¤ H£¨tÔ4÷	 
×	×	Ò	ús   �9AÁA#	c               ó    € V ^8„  d   QhRRRR/# )r   ÚrawÚbytesr   rV   r   )r   s   "r   r   r   R  s   € ÷ %ñ %˜5ð % Sñ %r   c                ó¨   € V P                  \        P                  4      p  V P                  R4      #   \         d    T P                  R4      u # i ; i)z‡BOM stripped; invalid UTF-8 falls back to latin-1 exactly as
``env_loader._load_dotenv_with_fallback`` installs it into ``os.environ``.zutf-8zlatin-1)ÚremoveprefixÚcodecsÚBOM_UTF8ÚdecodeÚUnicodeDecodeError)rÖ   s   &r   Ú_decode_env_bytesrÞ   R  sJ   € ð ×
Ñ
œ6Ÿ?™?Ó
+€Cð%Ø�z‰z˜'Ó"Ð"øÜô %Ø�z‰z˜)Ó$Ò$ð%ús   ¡2 ²AÁAc               ó    € V ^8„  d   QhRRRR/# )r   ÚtextrV   r   údict[str, str]r   )r   s   "r   r   r   \  s   € ÷ ñ ˜#ð  .ñ r   c                óœ  € / pV P                  4        Fµ  pVP                  4       pV'       d   VP                  R4      '       d   K4  VP                  R4      '       d   V\        R4      R P	                  4       pVP                  R4      w  rEpVP                  4       pV'       g   K•  V'       g   KŸ  \        \        V4      4      W&   K·  	  V# )z?Tokenize already-read ``.env`` text. See :func:`load_env_file`.r¸   zexport NÚ=)Ú
splitlinesr»   r¡   r¼   r½   Ú	partitionrÌ   rÂ   )rà   rk   Úraw_lineÚlineÚkeyÚsepr´   s   &      r   Ú_parse_env_textrê   \  sŸ   € à €GØ—O‘OÖ%ˆØ�~‰~Óˆß�t—‘ s×+Ò+ÙØ�?‰?˜9×%Ò%Øœ˜I›˜Ð(×/Ñ/Ó1ˆDØŸ.™.¨Ó-‰ˆ�%Ø�i‰i‹kˆß‰3—3‘3Ü+Ô,AÀ%Ó,HÓIˆG‹Lñ &ð €Nr   c               ó    € V ^8„  d   QhRRRR/# )r   rÏ   r   r   rá   r   )r   s   "r   r   r   l  s   € ÷  ñ  ˜Dð   ^ñ  r   c                ó  € \        V 4      p \        V R4      ;_uu_ 4       pVP                  4       pRRR4       \
        ;_uu_ 4        \        P                  T4      pTe@   T^ ,          X8X  d2   \        P                  T4       \        T^,          4      uuRRR4       # RRR4       \        \        X4      4      p\
        ;_uu_ 4        T\        T4      3\        T&   \        P                  T4       \        \        4      \        8”  d   \        P                  RR7       K0   RRR4       T#   + '       g   i     EL; i  \         d    \	        T 4       / u # i ; i  + '       g   i     LÉ; i  + '       g   i     T# ; i)uö  THE ``.env`` tokenizer: every reader (profile scope, ``hermes_cli.config.load_env``, the dashboard
scrub, skill secret capture, managed .env, setup prompts) parses through here so no two boundaries
disagree on which keys/values a file defines. Dict only â€” never touches ``os.environ``. ``export``
prefix, ``#`` comments, quote escapes reversed; a BOM is stripped so it doesn't prefix the first key.
Invalid UTF-8 decodes as latin-1, exactly like ``env_loader._load_dotenv_with_fallback`` installs it
into ``os.environ``. Absent/unreadable â†’ ``{}``.

Memoised per path on the file's exact bytes (see the cache comment above). Always
returns a fresh dict: callers mutate what they get back (``build_profile_secret_scope`` layers
external secrets over it).
ÚrbNF)Úlast)rV   ÚopenÚreadÚOSErrorrÔ   rÑ   rÍ   r3   Úmove_to_endÚdictrê   rÞ   r¼   Ú_ENV_FILE_CACHE_MAXÚpopitem)rÏ   rè   ÚhandlerÖ   Úcachedrk   s   &     r   Úload_env_filerø   l  s'  € ô ˆh‹-€CðÜ�(˜D×!Ô! VØ—+‘+“-ˆC÷ "÷ 
Ö	Ü ×$Ñ$ SÓ)ˆØÒ &¨¥)¨sÔ"2Ü×'Ñ'¨Ô,Ü˜˜q�	“?÷	 
×	Ò	ô
 Ô/°Ó4Ó5€Gß	Ö	Ø #¤T¨'£]Ð3Œ˜ÑÜ×#Ñ# CÔ(Ü”/Ó"Ô%8Ô8Ü×#Ñ#¨Ð#Ö/ð 9÷ 
ð
 €N÷% "×!Ð!ûäô ä! (Ô+ØŠ	ðú÷
 
×	ú÷ 
Ö	ð
 €NúsG   �E ¡D0²E ÁAE"ÃAE5Ä0E	Ä;E ÅE ÅEÅEÅ"E2	Å5F	c               ó    € V ^8„  d   QhRRRR/# )r   Úhermes_homer   r   rá   r   )r   s   "r   r   r   �  s   € ÷ ñ ¨Dð °^ñ r   c                ó¨  € \        \        V 4      R,          4      p ^ RIHp V! \        V 4      4      pTP                  R VP                  4        4       4       ^ RIHp V! 4       pVe$   \        V 4      '       d   VP                  RV4       ^ RIHp VP                  R V! 4       P                  4        4       4       V#   \         d    / p Lœi ; i)uÕ   Build a profile's secret mapping from ``<home>/.env`` plus its external
secret sources. Global vars are NOT copied in â€” ``get_secret`` reads those
from ``os.environ`` â€” so the scope holds only profile secrets.z.env)Úget_secret_source_valuesc              3  óR   "  € T F  w  r\        V4      '       d   K  W3x € K  	  R # 5ir+   ©r£   ©r\   ÚkÚvs   &  r   r^   Ú-build_profile_secret_scope.<locals>.<genexpr>™  s    é € ÐXÑ&>™d˜aÄnÐUV×FW”6�A•6Ó&>ùó   ‚'œ')Úbridged_allow_all_usersÚGATEWAY_ALLOW_ALL_USERS)Úload_managed_envc              3  óR   "  € T F  w  r\        V4      '       d   K  W3x € K  	  R # 5ir+   rþ   rÿ   s   &  r   r^   r  ª  s    é € ÐZÑ&@™d˜aÌÐWX×HY”6�A•6Ó&@ùr  )rø   r   Úhermes_cli.env_loaderrü   Ú	ExceptionÚupdateÚitemsÚgateway.config_loaderr  Ú_is_process_homeÚ
setdefaultÚhermes_cli.managed_scoper  )rú   rk   rü   Úexternal_secretsr  Úbridgedr  s   &      r   Úbuild_profile_secret_scoper  �  s½   € ô œD Ó-°Õ6Ó7€GðÝBÙ3´D¸Ó4EÓFÐð ‡N�NÑXÐ&6×&<Ñ&<Ô&>ÓXÔXõ >Ù%Ó'€GØÒÔ/°×<Ò<Ø×ÑÐ4°gÔ>õ :à‡N�NÑZÑ&6Ó&8×&>Ñ&>Ô&@ÓZÔZØ€Nøô) ô ØÒðús   �C ÃCÃCc               ó    € V ^8„  d   QhRRRR/# ©r   rú   r   r   r   r   )r   s   "r   r   r   ®  s   € ÷ ñ  $ð ¨4ñ r   c                ó’   € ^ RI Hp  \        V 4      P                  4       V! 4       P                  4       8H  #   \         d     R# i ; i)a  Is *hermes_home* the profile this process serves as its own? Same launch-home identity as
``serves_routed_profile()``: a host that mirrors a served profile into ``HERMES_HOME`` would
otherwise seed the launch profile's bridged allow-all grant into that profile's scope.)r   F)r   r   r   Úresolverñ   )rú   r   s   & r   r  r  ®  sE   € õ AðÜ�KÓ ×(Ñ(Ó*Ñ.MÓ.O×.WÑ.WÓ.YÑYÐYøÜô Úðús   ˆ.7 ·AÁAc               ó    € V ^8„  d   QhRRRR/# r  r   )r   s   "r   r   r   ¹  s   € ÷ ñ °ð ¸ñ r   c                ó*  € \         P                  4       pVe   VP                  MRp\        V\        4      '       g   R# \        V 4      pVP                  V4       V Uu. uF  qDV9  g   K  VNK  	  up F  pVP                  VR4       K  	  R# u upi )a  Fold a fresh build of *hermes_home*'s secrets into the INSTALLED scope, in place.

A scope is frozen when installed, but a fire can learn of new values afterwards: a routed cron
fire's first agent build discovers plugin secret sources, and under multiplex semantics the
reload that follows is hydrate-only (never ``os.environ``), so nothing else would carry those
values into the scope this fire already holds. The caller names the home the installed scope
was built for. True when a scope was updated; False when none is installed.NFT)rE   r3   r7   Ú
isinstanceró   r  r
  rÓ   )rú   rG   ÚscopeÚrebuiltÚnrž   s   &     r   Úrefresh_installed_secret_scoper  ¹  s€   € ô ×ÑÓ€EØ"Ò.ˆE�MŠM°D€EÜ�eœT×"Ò"Ùô )¨Ó5€Gà	‡L�L�ÔÙ!Ó6™E�q¨gÑ%5—�™EÔ6ˆØ�	‰	�$˜Öñ 7áùò 7s   ÁBÁ,B)ÚHERMES_KANBAN_ÚHERMES_TELEGRAM_Ú	TERMINAL_r+   )r`   )>Ú__conditional_annotations__r>   Ú
__future__r   rÚ   r§   r¾   Ú	threadingÚcollectionsr   Úcontextvarsr   r   Úpathlibr   Útypingr   r   r	   r
   r   r   r   r?   r    r   r!   r%   r.   r4   r6   rI   rE   rJ   rN   rQ   ÚRuntimeErrorrS   rn   rq   ru   rx   Ú	frozensetr    r¢   r£   r«   r¯   r²   rÂ   rÌ   rÍ   ÚLockrÑ   rô   rÔ   rÞ   rê   rø   r  r  r  )r!  s   @r   Ú<module>r+     sÉ  øðô
õ #ã Û 	Û 	Û Ý #ß )Ý ß G× Gð
  Ð �4Ó àÐ ñ (2Ð2FÐPUÔ'VÐ Ð$Ó Võ!õ60õ$õ9ô
 �*ô  õEñ& 4>¸oÐW[Ô3\€Ð0Ó \ñ MWØ $ôM(Ð ÐIó (õ,õ$ô,˜,ô ,ð8`Ð\`÷ `õõ8õ=ñ ð àðà#ðà%>ðð ðð 2ðð ð	ð ;ð	ð
 ðð ðð ðð ðð #ðð %-ðð /3ðð 5:ðð <Cðð EMðð ðð  ðð "1ðð ðð 8ðð :Oðð ðð ,ðð .?ðð  ð!ð, ð-ð, 2ð-ð. +ð/ð0 ð1ð0  7ð1ð2 ð3ð2 !<ð3ð4 ð5ð4 ;ð5ó Ð ð8Ð õNõ
/÷
&÷D+õ;õ.ñ< CNÃ-€Ð?Ó OØ —~’~Ó'Ð ØÐ ÷5õ%õõ  õFõ>÷r   