Ë
    âß²j“õ ã                   óî  — U d Z ddlmZ  e«        ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlZddlZddlZddlmZ ddlmZ ddlmZmZ ddlmZ ddlmZmZmZm Z m!Z!m"Z" ddl#Z#dd	l$m%Z% dd
l&m'Z'm(Z( ddl)m*Z* ddl+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9 ddl0m:Z:m;Z; ddl<m=Z=m>Z>m?Z?  ej€                  eA«      ZB eC«       ZDeCeEd<   i ZFeGeEd<    G d„ deH«      ZIddddœZJdZKdZLdeMdeNfd„ZOdeMdeNfd„ZPdd œd!edeMd"eNdeNfd#„ZQdd œd!edeMd"eNddfd$„ZRdeeN   fd%„ZS ej¨                  «       d&k(  ZU e	j¬                  d'«      ZWd(ZXeYeNd)f   eEd*<    eZh d+£«      Z[eZeN   eEd,<   dd-œd.eNd/ee\   deNfd0„Z]d.eNddfd1„Z^ ej¾                  «       Z`i ZaeeNef   eEd2<   i ZbeeNe!ecd)f   f   eEd3<   i ZdeeNe!ecd)f   f   eEd4<    eZh d5£«      Zed6d7hZf ed8«      Zgde\fd9„Zhd:ZideeN   fd;„Zj eZh d<£«      Zkd=edeeN   fd>„Zl�d�d?ee   deNfd@„Zmde\fdA„ZndBeNde\fdC„ZodDdEdFœZpdBeNdeNfdG„ZqdeNfdH„ZrdIZsdeNfdJ„Zt�dždKeNdeNfdL„Zu�dŸdKeNfdM„ZvdeeG   fdN„ZwdefdO„ZxdPdQœdRe\ddfdS„ZydefdT„ZzdefdU„Z{dV„ Z|dW„ Z}dXeddfdY„Z~ eC«       ZeCeEdZ<   d[Z€d\„ Z�dd]l‚mƒZƒm„Z„ dd^l…m†Z†m‡Z‡mˆZˆm‰Z‰mŠZŠm‹Z‹mŒZŒm�Z�mŽZŽm�Z�m�Z�m‘Z‘m’Z’m“Z“m”Z”m•Z•m–Z–m—Z—m˜Z˜m™Z™mšZšm›Z›mœZœm�Z�mžZžmŸZŸm Z m¡Z¡ dd_l¢m£Z¤m¥Z¦m§Z§m¨Z© g d`¢dadbgg dc¢ddgdegdfœZªeece eN   f   eEdg<   i Z«�d dhe\de eeNef      fdi„Z¬d.eNde­eN   fdj„Z®dkeGdle­dee!eNecf      fdm„Z¯dkeGdneNdeeN   fdo„Z°dpeNfdq„Z±drdrdPdsœdteeNef   due\dve\dwe\deeNef   f
dx„Z² e³«       Z´dle­fdy„ZµdpeNfdz„Z¶dpeNde\fd{„Z· eZh d|£«      Z¸d.eNde\fd}„Z¹d~e\deNfd„Zºde eeNef      fd€„Z»de eeNef      fd�„Z¼d‚edecfdƒ„Z½dPd„œd…e\de!ececf   fd†„Z¾h d‡£Z¿ eZ eƒ�j€                  «       «      e¿z  ZÁh dˆ£ZÂh d‰£ZÃe G dŠ„ d‹«      «       ZÄdŒe d‹   d�eNdŽeNd�eNddf
d�„ZÅ	 �d¡dŒe d‹   d‘eeNef   d’eNd“e!e!eNeNf   d)f   d”eNddfd•„ZÆd–ZÇd—ZÈd˜ZÉd™eeNef   dŒe eÄ   ddfdš„ZÊd™eeNef   dŒe eÄ   ddfd›„ZËdœe­d’eNdŒe eÄ   d�e!eNeNeNf   ddf
dž„ZÌdŸZÍd edŒe eÄ   ddfd¡„ZÎd¢edŒe eÄ   ddfd£„ZÏd™eeNef   dŒe eÄ   ddfd¤„ZÐdeeNeNf   fd¥„ZÑd™eeNef   dŒe eÄ   ddfd¦„ZÒ�d�d™eeeNef      de d‹   fd§„ZÓ�d�d™eeeNef      ddfd¨„ZÔ�d¢d©„ZÕd™eeNef   ddfdª„ZÖd«eNd¬eeNef   d­eNd®eeNef   de\f
d¯„Z×d­eNde\fd°„ZØ�d£d±e\d²e\deeNef   fd³„ZÙd®eeNef   d²e\ddfd´„ZÚd®eeNef   d²e\ddfdµ„ZÛd¶eNd·e eN   d¸eNde\fd¹„ZÜdºecd»ecd®eeNef   ddfd¼„ZÝd½e eeNef      d®eeNef   ddfd¾„ZÞd¿eGdÀeGdeGfdÁ„ZßdÂeGdÀeGdeGfdÃ„ZàdÄeGdÅeCde!eGeCf   fdÆ„Zá e	j¬                  dÇ«      Zâd«eNdeeN   fdÈ„ZãdÉe	�jÈ                  deNfdÊ„ZådËeNde\fdÌ„ZædËeNdeeN   fdÍ„ZçdÎ„ Zè�d�dÏ„ZédÐ„ Zê�d�dÑ„Zëd™eeNef   de"e!eNd)f      fdÒ„Zìeƒdfd™eeNef   deeNef   dÓee"e!eNd)f         deeNef   fdÔ„ZídÕedeYeNeNf   fdÖ„Zîd™eeNef   deeNef   fd×„Zïd™eeNef   deeNef   fdØ„Zðd™eeNef   deeNef   fdÙ„Zñe�jä                  Zó eZh dÚ£«      Zôeófd¿edÛecdecfdÜ„ZõddÝœdÄeeeNef      dÞeNdÛedefdß„ZödàeNdáe!ed)f   deeeNef      fdâ„Z÷dãe\deeNef   fdä„ZødeeNef   fdå„Zù�d�d!ee   deeNef   fdæ„ZúdeeNef   fdç„Zûd!edèeNdeMdéeNdeHf
dê„ZüdeNfdë„ZýdìZþdíZÿ�d�d!ee   deeNef   fdî„�Z ddïœd!edðeeNef   dñeeN   ddfdò„�ZdeeNef   fdó„�ZdeeNef   fdô„�ZdõeeNef   d.eNdeeNef   fdö„�ZdPd÷œdøeNdùeNd‚ed¿e\ddf
dú„�ZdûdüidýD � ci c]  } | dþ| �j                  «       › �“Œ c} ¥�Zd‚edeNfdÿ„�Zd.eNd‚ede\f�d „�Z	�dede"eN   f�d„�Z
d.eNdeeN   f�d„�ZdûeN�deNde\f�d„�Zddd�dœ�deeeNeNf      d™eeeNef      dÀee\   deeNeNf   f�d„�Zd!ede!ee!ececececf      ee!ecd)f      f   f�d	„�Zd!edàeNdeMdeeeNef      f�d
„�Z�deeNef   de!eeNef   ef   f�d„�ZdàeN�dedeeeNef      f�d„�Zdãe\deeNef   f�d„�Z�d�Z�d�Zd™eeNef   deeNef   f�d„�Z�deeNef   deeN   f�d„�ZdrddP�dœd™eeNef   �de\dÓee"e!eNd)f         �de\f�d„�ZdeeNeNf   f�d„�Z�d¢�d„�Z�de­de­f�d„�Zdecf�d„�Z�dede­f�d„�Z�de�de­�d e\ddf�d!„�Zd.eNd‚eNdeNf�d"„�Zd‚eNdeNf�d#„�Zdd-œ�d$eNd.eNd/ee\   de\f�d%„�Z d.eNd‚eeN   ddf�d&„�Z!d.eNdKeNde\f�d'„�Z"�d(eNf�d)„�Z#d.eNd‚eNf�d*„�Z$�d+eNdeNf�d,„�Z%d.eNde\f�d-„�Z&�d�dr�d.œ�d/eN�d0eN�d1e\f�d2„�Z'�d�d‚eNf�d3„�Z(�d��d4„�Z)�d�d‚eNf�d5„�Z*d.eNd‚eNdeeNef   f�d6„�Z+decf�d7„�Z,d.eNdeeN   f�d8„�Z-d.eNdeeN   f�d9„�Z.d.eNdeeN   f�d:„�Z/d.eNdeNf�d;„�Z0 eZh �d<£«      �Z1�d=�Z2�d>�Z3 e	j¬                  �d?«      �Z4d.eNde\f�d@„�Z5�d¤d‚e�dAecdef�dB„�Z6�dCeNddf�dD„�Z7�d¢�dE„�Z8�dF�Z9d™eeNef   ddf�dG„�Z:d™eeNef   ddf�dH„�Z;d™eeNef   ddf�dI„�Z<d™eeNef   ddf�dJ„�Z=d™eeNef   ddf�dK„�Z>�d¢�dL„�Z?�dM„ �Z@�dN„ �ZAdpeNf�dO„�ZB eZh �dP£«      �ZC eZh �dQ£«      �ZD eZ�dRh«      �ZE eZ�dSh«      �ZF�eC�eEz  �eDz  �ZGdeCeN   f�dT„�ZH�d¥d.eN�dUeCeN   �dV�eIdeeN   f�dW„�ZJd.eNdeYe\eeN   f   f�dX„�ZKd.eN�dYeeN   de\f�dZ„�ZLd‚eNde\f�d[„�ZMd‚eNf�d\„�ZNd‚eNf�d]„�ZOdrdrdrdPdPdPddd�d^œ	�ZPd.eNd‚eNdef�d_„�ZQ�d`�da�da�da�d`�d`�d`�dbœ�ZR eZ�dc�ddh«      �ZSd.eN�deeeNef   deeN   f�df„�ZTd.eNd‚e�deeeNef   �dge\def
�dh„�ZUd.eNdeYeNeeN   f   f�di„�ZV�djeNdeeN   f�dk„�ZWd.eNdKeNddf�dl„�ZXd.eNd‚e�deeeNef   �dge\deNf
�dm„�ZYd.eNd‚eddf�dn„�ZZ�doeNddf�dp„�Z[d!e�deeeNef   ddf�dq„�Z\d.eN�dYeeN   ddf�dr„�Z]d.eN�dYeeN   deNf�ds„�Z^�d d.eNd‚eN�dge\f�dt„�Z_dPdP�duœd.eNd~e\d¿e\f�dv„�Z`d.eNf�dw„�Za�d��dxeN�dye eN   �dzee eN      ddf�d{„�Zb�d¢�d|„�Zc�d}g �d~¢df�Zd�dg �d€¢g �d�¢f�Ze�d‚g �dƒ¢df�Zf�d„„ �Zg�d…„ �Zh�d†„ �Zid¬eeNef   �d‡eNdeNf�dˆ„�Zj�d‰eNddf�dŠ„�Zk�d‹„ �Zl�dŒ„ �Zm�d�„ �dŽ„ �d�„ �eg�eh�ei�d�„ �d‘„ �el�em�d’œ
�Zn�d“�Zo�d”„ �Zp�d¢�d•„�Zq �eq«        �d–„ �Zr�d¢�d—„�Zs �es«        �d�d?ee   def�d˜„�Zt�d�dBeNd?ee   ddf�d™„�Zu�dš�d›i�Zv�dœ„ �Zwyc c} w (¦  zˆConfiguration management for Hermes Agent: config.yaml / .env loading, saving,
validation, migration, and the ``hermes config`` command.é    )Údrop_stale_root_modulesN)Úsuppress)Ú	dataclass)ÚDecimalÚInvalidOperation)ÚPath)ÚDictÚAnyÚOptionalÚListÚTupleÚSet)Ú
line_input)ÚColorsÚcolor)Úmanaged_scope)ÚDEFAULT_SOUL_MDÚis_legacy_template_soul)Úmasked_secret_prompt)	Ú_IGNORED_MANAGED_VALUESÚ_LEGACY_MANAGED_SYSTEMÚ_MANAGED_FALSE_VALUESÚ_MANAGED_TRUE_VALUESÚ_chown_to_hermes_uidÚ_container_or_chmod_skippedÚ_resolve_hermes_uid_gidÚapply_secure_dir_policyÚget_managed_system)Úget_hermes_homeÚget_process_hermes_home)Úatomic_replaceÚfast_safe_loadÚfile_signatureÚ_CONFIG_PARSE_WARNEDÚ_CONFIG_PARSE_FAILURESc                   ó   — e Zd ZdZy)ÚInvalidUserConfigErrorzDRaised when a run that cannot repair config finds invalid user YAML.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ú6/home/ubuntu/.hermes/hermes-agent/hermes_cli/config.pyr'   r'   @   s   „ ÚNr-   r'   zqHermes is running on the settings it loaded before the edit until it is fixed, so recent changes are not applied.zbHermes is running on your last good settings until it is fixed, so recent changes are not applied.z7Nothing was written, so the existing file is preserved.)úlast-known-goodúlast-known-good-backupúrefuse-writezdHermes is running on default settings until it is fixed, so none of your saved settings are applied.zOOpen it with `hermes config edit`, fix {where}, then run `hermes config check`.ÚexcÚreturnc                 óˆ   — t        | dd«      xs t        | dd«      }t        |dd«      }t        |t        «      rd|dz   › �S dS )z@``"line 12"`` from a PyYAML problem mark (1-based), else ``""``.Úproblem_markNÚcontext_markÚlinezline é   Ú )ÚgetattrÚ
isinstanceÚint)r2   Úmarkr7   s      r.   Ú_yaml_error_locationr>   M   sK   € ä�3˜¨Ó-ÒS´¸¸nÈdÓ1S€DÜ�4˜ Ó&€DÜ!+¨D´#Ô!6ˆU�4˜!‘8�*ÐÐ>¸BÐ>r-   c                 ó–   — t        | dd«      }|r|› nt        | «      j                  «       }dj                  |j	                  «       «      S )zQSingle-line ``Details:`` text: the PyYAML problem, or the exception's first line.ÚproblemNú )r:   ÚstrÚstripÚjoinÚsplit)r2   r@   Útexts      r.   Ú_yaml_error_detailsrG   T   s;   € ä�c˜9 dÓ+€GÙ"ˆg‰Y¬¨C«¯©Ó(8€DØ�8‰8�D—J‘J“LÓ!Ð!r-   Údefaults©ÚfallbackÚconfig_pathrJ   c                ó®   — t        |«      }|rd|› �nd}t        j                  |t        «      }t        j                  |xs d¬«      }d| › d|› d|› d|› �S )	z¸User copy for an unparseable config.yaml: what happened, what Hermes is doing, how to fix.
    Only the problem line/column is printed; the raw PyYAML text goes to a ``Details:`` line.ú at r9   zthe problem)ÚwhereúYour settings file (ú) has a formatting errorú. rA   )r>   Ú_PARSE_FAILURE_FALLBACK_MSGÚgetÚ_PARSE_FAILURE_DEFAULTS_MSGÚ_PARSE_FAILURE_REPAIR_MSGÚformat)rK   r2   rJ   rN   ÚatÚfallback_msgÚrepairs          r.   Úformat_config_parse_failurerZ   [   sk   € ô ! Ó%€EÙ ˆ4�ˆw‰ b€BÜ.×2Ñ2°8Ô=XÓY€LÜ&×-Ñ-°EÒ4J¸]Ð-ÓK€FØ! + Ð.FÀrÀdÈ"È\ÈNÐZ[Ð\bÐ[cÐdÐdr-   c                ó^  — 	 | j                  «       }t        |«      }t        | «      g|¢­}g |¢t        |«      ‘­t        t        | «      <   |t
        v ryt
        j                  |«       ddlm}  || d«      }t        | ||¬«      }|�	|d|› d�z  }t        j                  d|t        |«      «       	 t        j                  j                  d	|› d
t        |«      › d�«       t        j                  j!                  «        y# t        $ r t        | «      ddddf}Y ŒÐw xY w# t"        $ r Y yw xY w)u¤  Surface a config.yaml parse failure to log and stderr (once per file signature).
    Silent fallback to ``DEFAULT_CONFIG`` drops every user override, so this must be loud.

    ``fallback`` selects the message wording: ``"defaults"`` (fresh process, nothing else to serve) or
    ``"last-known-good"`` (in-process retention of the previously loaded config â€” see the codex#31188 port
    in ``_load_config_impl``).
    r   N©Úbackup_configÚcorruptrI   z( A copy of the broken file was saved to ú.z%s Details: %su   âš ï¸�  hermes config: z
    Details: ú
)Ústatr#   rB   r%   ÚOSErrorr$   ÚaddÚhermes_cli.config_backupsr]   rZ   ÚloggerÚwarningrG   ÚsysÚstderrÚwriteÚflushÚ	Exception)	rK   r2   rJ   ÚstÚsigÚkeyr]   Úbackup_pathÚmsgs	            r.   Ú_warn_config_parse_failurerq   e   s2  € ð-Ø×ÑÓˆÜ˜RÓ ˆÜ�;ÓÐ& #Ñ&ˆØ3C°SÐ3C¼#¸c»(Ñ3CÔœs ;Ó/Ñ0ð Ô"Ñ"ØÜ×Ñ˜SÔ!Ý7Ù ¨YÓ7€KÜ
% k°3ÀÔ
J€CØÐØÐ9¸+¸ÀaÐHÑHˆÜ
‡N�NÐ# SÔ*=¸cÓ*BÔCðÜ�
‰
×ÑÐ2°3°%°ÔGZÐ[^ÓG_ÐF`Ð`bÐcÔdÜ�
‰
×ÑÕøô ò -Ü�;Ó  A q¨!Ð,Šð-ûô ò Ùðús%   ‚A
D Â3AD  ÄDÄDÄ 	D,Ä+D,c                  óª   — 	 t         t        t        «       x} «         }| j                  «       }t	        |«      |dd k(  r|d   S dS # t
        $ r Y yw xY w)z¨Return the recorded parse error while the ACTIVE config.yaml is still byte-identical
    (mtime_ns + size + ino + ctime_ns) to the file that failed to parse; else None.Né   )r%   rB   Úget_config_pathra   r#   rk   )ÚpathÚrecordrl   s      r.   Úget_active_config_parse_failurerw   …   s\   € ðÜ'¬´OÓ4EÐ,E¨DÓ(FÑGˆØ�Y‰Y‹[ˆÜ*¨2Ó.°&¸¸!°*Ò<ˆv�a‰yÐFÀ$ÐFøÜò Ùðús   ‚AA ÁA Á	AÁAÚWindowsz^[A-Za-z_][A-Za-z0-9_]*$)ÚLD_ÚDYLD_ÚGIT_CONFIG_.Ú_ENV_VAR_NAME_DENY_PREFIXES>L   ÚENVÚPATHÚPAGERÚSHELLÚEDITORÚEXINITÚVISUALÚBROWSERÚGIT_DIRÚGIT_SSHÚGOFLAGSÚPERLLIBÚRUBYLIBÚRUBYOPTÚVIMINITÚZDOTDIRÚBASH_ENVÚLD_AUDITÚLD_DEBUGÚMANPAGERÚPERL5LIBÚPERL5OPTÚ	CLASSPATHÚ	GIT_PAGERÚ	GIT_SHELLÚ	NODE_PATHÚ	RUSTFLAGSÚ
GIT_EDITORÚ
HERMES_ENVÚ
LD_PRELOADÚ
PYTHONHOMEÚ
PYTHONPATHÚGIT_ASKPASSÚHERMES_HOMEÚSSH_ASKPASSÚNODE_OPTIONSÚPYTHONCASEOKÚSUDO_ASKPASSÚGIT_EXEC_PATHÚHERMES_CONFIGÚPYTHONSTARTUPÚ_JAVA_OPTIONSÚHERMES_PROFILEÚPROMPT_COMMANDÚPYTHONUSERBASEÚGIT_SSH_COMMANDÚHERMES_ENV_PATHÚHERMES_EXEC_ASKÚLD_LIBRARY_PATHÚGIT_TEMPLATE_DIRÚHERMES_YOLO_MODEÚJDK_JAVA_OPTIONSÚPYTHONBREAKPOINTÚPYTHONEXECUTABLEÚPYTHONNOUSERSITEÚDYLD_LIBRARY_PATHÚGIT_EXTERNAL_DIFFÚGIT_PROXY_COMMANDÚJAVA_TOOL_OPTIONSÚHERMES_CONFIG_PATHÚHERMES_INTERACTIVEÚHERMES_SESSION_KEYÚDYLD_FRAMEWORK_PATHÚGIT_SEQUENCE_EDITORÚHERMES_ACCEPT_HOOKSÚHERMES_CRON_SESSIONÚHERMES_OPTIONAL_MCPSÚDYLD_INSERT_LIBRARIESÚHERMES_REDACT_SECRETSÚHERMES_GATEWAY_SESSIONÚHERMES_COPILOT_ACP_ARGSÚHERMES_SESSION_PLATFORMÚDYLD_FALLBACK_LIBRARY_PATHÚHERMES_COPILOT_ACP_COMMANDÚHERMES_SINGLE_QUERY_SESSIONÚDYLD_FALLBACK_FRAMEWORK_PATHÚ_ENV_VAR_NAME_DENYLIST©Ú
is_windowsrn   rË   c                ó>   — |€t         n|}|r| j                  «       S | S )z”Name used for env policy comparisons: Windows env names are case-insensitive, POSIX not.
    The override keeps both semantics testable on any host.)Ú_IS_WINDOWSÚupper)rn   rË   Úwindowss      r.   Ú_env_var_policy_namerÐ   Ë   s#   € ð (Ð/�k°Z€GÙ!ˆ3�9‰9‹;Ð* sÐ*r-   c                 ó¸   — t         j                  | «      st        d| ›�«      ‚t        | «      }|t        v s|j                  t        «      rt        d| ›d�«      ‚y)zTValidate an env name before a generic persistence write (exposed for batch callers).ú#Invalid environment variable name: zEnvironment variable a$   is on the writer denylist. Names that influence subprocess execution (LD_PRELOAD, PYTHONPATH, PATH, EDITOR, ...) or Hermes runtime location and security policy (HERMES_HOME, HERMES_YOLO_MODE, ...) cannot be persisted via the env writer. If you really need this, edit ~/.hermes/.env directly.N)Ú_ENV_VAR_NAME_REÚmatchÚ
ValueErrorrÐ   rÉ   Ú
startswithr|   )rn   Úpolicy_names     r.   Úvalidate_env_var_name_for_writerØ   Ò   sh   € ä×!Ñ! #Ô&ÜÐ>¸s¸gÐFÓGÐGÜ& sÓ+€KØÔ,Ñ,°×0FÑ0FÔGbÔ0cÜØ# C 7ð +ð óð 	ð 1dr-   Ú_LAST_EXPANDED_CONFIG_BY_PATHÚ_LOAD_CONFIG_CACHEÚ_RAW_CONFIG_CACHE>m   ÚIRC_PORTÚ	QQ_APP_IDÚ
IRC_SERVERÚIRC_CHANNELÚIRC_USE_TLSÚIRC_NICKNAMEÚQQ_STT_MODELÚTERMINAL_ENVÚWECOM_BOT_IDÚWECOM_SECRETÚWEIXIN_TOKENÚFEISHU_APP_IDÚWHATSAPP_MODEÚOPENAI_API_KEYÚQQ_STT_API_KEYÚSIGNAL_ACCOUNTÚANTHROPIC_TOKENÚMATRIX_PASSWORDÚOPENAI_BASE_URLÚQQ_HOME_CHANNELÚQQ_STT_BASE_URLÚSIGNAL_HTTP_URLÚWEIXIN_BASE_URLÚCOPILOT_CLI_PATHÚMATRIX_DEVICE_IDÚMATRIX_HOME_ROOMÚQQ_ALLOWED_USERSÚQQ_CLIENT_SECRETÚSMS_HOME_CHANNELÚTERMINAL_SSH_KEYÚWEIXIN_DM_POLICYÚWHATSAPP_ENABLEDÚANTHROPIC_API_KEYÚFEISHU_APP_SECRETÚLANGFUSE_BASE_URLÚMATRIX_ENCRYPTIONÚTERMINAL_SSH_PORTÚWEIXIN_ACCOUNT_IDÚDINGTALK_CLIENT_IDÚFEISHU_ENCRYPT_KEYÚMATRIX_AUTO_THREADÚQQBOT_HOME_CHANNELÚQQ_ALLOW_ALL_USERSÚSLACK_HOME_CHANNELÚWECOM_HOME_CHANNELÚFEISHU_HOME_CHANNELÚHERMES_LANGFUSE_ENVÚIRC_SERVER_PASSWORDÚLANGFUSE_PUBLIC_KEYÚLANGFUSE_SECRET_KEYÚMATRIX_RECOVERY_KEYÚQQ_MARKDOWN_SUPPORTÚSIGNAL_HOME_CHANNELÚWECOM_CALLBACK_HOSTÚWECOM_CALLBACK_PORTÚWEIXIN_CDN_BASE_URLÚWEIXIN_GROUP_POLICYÚWEIXIN_HOME_CHANNELÚBLUEBUBBLES_PASSWORDÚCOPILOT_ACP_BASE_URLÚDISCORD_HOME_CHANNELÚQQ_HOME_CHANNEL_NAMEÚSIGNAL_ALLOWED_USERSÚWECOM_CALLBACK_TOKENÚWEIXIN_ALLOWED_USERSÚYUANBAO_HOME_CHANNELÚDINGTALK_HOME_CHANNELÚHERMES_LANGFUSE_DEBUGÚIRC_NICKSERV_PASSWORDÚMATRIX_DM_AUTO_THREADÚMATTERMOST_REPLY_MODEÚSMS_HOME_CHANNEL_NAMEÚTELEGRAM_HOME_CHANNELÚBLUEBUBBLES_SERVER_URLÚDINGTALK_CLIENT_SECRETÚHERMES_ACP_AUTH_METHODÚMATRIX_REQUIRE_MENTIONÚQQ_GROUP_ALLOWED_USERSÚWECOM_CALLBACK_CORP_IDÚWEIXIN_ALLOW_ALL_USERSÚHERMES_ACP_AUTO_APPROVErÃ   ÚHERMES_LANGFUSE_CAPTUREÚHERMES_LANGFUSE_RELEASEÚMATTERMOST_HOME_CHANNELÚQQBOT_HOME_CHANNEL_NAMEÚSLACK_HOME_CHANNEL_NAMEÚWECOM_CALLBACK_AGENT_IDÚWECOM_HOME_CHANNEL_NAMEÚBLUEBUBBLES_HOME_CHANNELÚFEISHU_HOME_CHANNEL_NAMEÚSIGNAL_HOME_CHANNEL_NAMEÚWEIXIN_HOME_CHANNEL_NAMEÚDISCORD_HOME_CHANNEL_NAMEÚFEISHU_VERIFICATION_TOKENÚHERMES_LANGFUSE_MAX_CHARSÚHERMES_TOOL_PROGRESS_MODEÚYUANBAO_HOME_CHANNEL_NAMEÚDINGTALK_HOME_CHANNEL_NAMErÆ   ÚMATRIX_FREE_RESPONSE_ROOMSÚSIGNAL_GROUP_ALLOWED_USERSÚTELEGRAM_HOME_CHANNEL_NAMEÚWECOM_CALLBACK_CORP_SECRETÚWEIXIN_GROUP_ALLOWED_USERSÚHERMES_LANGFUSE_SAMPLE_RATEÚMATTERMOST_HOME_CHANNEL_NAMEÚBLUEBUBBLES_HOME_CHANNEL_NAMEÚWECOM_CALLBACK_ENCODING_AES_KEYÚnixosúhome-managerz
/nix/storec                  ó   — t        «       duS )z;Check if Hermes is running in package-manager-managed mode.N©r   r,   r-   r.   Ú
is_managedrK  .  s   € äÓ tÐ+Ð+r-   z£Update Hermes through the Nix source that installed it (e.g. nix profile upgrade, or update your flake input and rebuild with nixos-rebuild or home-manager switch)c                  ó2   — t        «       t        v rt        S dS )z;Return the preferred upgrade command for a managed install.N)r   Ú_NIX_MANAGED_SYSTEMSÚ_NIX_UPDATE_MSGr,   r-   r.   Úget_managed_update_commandrO  ;  s   € ä0Ó2Ô6JÑJŒ?ÐTÐPTÐTr-   >   ÚaptÚgitÚnixrG  ÚdockerÚunknownrH  ru   c                 ó–   — 	 | j                  d¬«      j                  «       j                  «       }|t        v r|S d S # t        $ r Y y w xY w©Núutf-8©Úencoding)Ú	read_textrC   Úlowerrb   Ú_SUPPORTED_INSTALL_METHODS)ru   Úmethods     r.   Ú_install_method_stampr^  F  sR   € ðØ—‘¨�Ó1×7Ñ7Ó9×?Ñ?ÓAˆð Ô9Ñ9ˆ6ÐC¸tÐCøô ò Ùðús   ‚.< ¼	AÁAÚproject_rootc                 ó  — | �| n	t        «       }t        |dz  «      }|r|S t        t        «       dz  «      }|r|dk(  r
t        «       r|S t	        «       }|r |j                  «       j                  dd«      S 	 |j                  «       }|t        k7  rt        |j                  v ry|dz  }	 |j                  «       s/|j                  d¬«      j                  «       j                  d	«      ry
	 y# t        $ r Y ŒSw xY w# t        $ r Y yw xY w)au  Detect how Hermes was installed: apt/docker/nix/nixos/home-manager/git/unknown.
    Order: code-scoped ``<install tree>/.install_method`` stamp (authoritative) -> legacy
    ``$HERMES_HOME/.install_method`` -> managed marker -> /nix/store path -> .git dir -> unknown.
    The stamp lives next to the code because HERMES_HOME is shared data: a container and a host
    install can bind-mount the same home, so a home-scoped ``docker`` stamp would make the host
    ``hermes update`` refuse to run. A legacy ``docker`` value is therefore ignored unless we are
    really inside a container, and being in a container alone never implies 'docker'.

    The supported installs self-identify via the code-scoped stamp: - the curl installer
    (scripts/install.sh, the README/website install command) git-clones the repo and stamps ``git`` next to
    the code; - the published ``nousresearch/hermes-agent`` image bakes a ``docker`` stamp into
    ``/opt/hermes`` at build time. An unsupported manual install dropped into a container (no stamp) falls
    through to the ``.git`` checks and behaves like any off-path install. See issue #34397.
    ú.install_methodrS  rA   ú-rR  z.gitrW  rX  zgitdir:rQ  rT  )Úget_project_rootr^  r   Ú_running_in_containerr   r[  ÚreplaceÚresolveÚ
_NIX_STOREÚparentsrb   Úis_dirrZ  rC   rÖ   )r_  Úrootr]  ÚmanagedÚresolvedÚgit_paths         r.   Údetect_install_methodrn  N  s  € ð" (Ð3‰<Ô9IÓ9K€DÜ" 4Ð*;Ñ#;Ó<€FÙØˆä"¤?Ó#4Ð7HÑ#HÓI€FÙ�v Ò)Ô2GÔ2IØˆä Ó"€GÙØ�}‰}‹×&Ñ& s¨CÓ0Ð0ðØ—<‘<“>ˆØ”zÒ!¤j°H×4DÑ4DÑ&DØð
 �f‰}€HðØ�?‰?Ô × 2Ñ 2¸GÐ 2Ó D× JÑ JÓ L× WÑ WÐXaÔ bØð !cð øô ò Ùðûô ò ØØðús$   Á7+C+ Â)?C: Ã+	C7Ã6C7Ã:	DÄDc                  ó<   — 	 ddl m}   | «       S # t        $ r Y yw xY w)z=Import-safe wrapper around ``hermes_constants.is_container``.r   ©Úis_containerF)Úhermes_constantsrq  rk   rp  s    r.   rd  rd  ~  s$   € ðÝ1á‹~ÐøÜò Ùðús   ‚ �	šr]  c                 ó    — | dk(  xs | t         v S )zHTrue for every install method Nix owns ("nix", "nixos", "home-manager").rR  )rM  ©r]  s    r.   Úis_nix_install_methodru  ˆ  s   € à�U‰?Ò<˜fÔ(<Ð<Ð<r-   z,docker pull nousresearch/hermes-agent:latestzpkg upgrade hermes-agent)rS  rP  c                 óP   — t        | «      rt        S t        j                  | d«      S )zAReturn the update command or guidance for a given install method.zhermes update)ru  rN  Ú_UPDATE_COMMAND_BY_METHODrS   rt  s    r.   Ú%recommended_update_command_for_methodrx  “  s#   € ä˜VÔ$ÜÐÜ$×(Ñ(¨°ÓAÐAr-   c                  óR   — t        «       xs t        t        t        «       «      «      S )zÎReturn the best update command for the current installation.
    Managed state wins over the code-scoped stamp: a managed install can carry a stale stamp
    naming an update path the managed guard refuses.)rO  rx  rn  rc  r,   r-   r.   Úrecommended_update_commandrz  š  s(   € ô &Ó'ò 3Ô+PÜÔ.Ó0Ó1ó,3ð 3r-   uù  âœ— ``hermes update`` doesn't apply inside the Docker container.

Hermes Agent runs as a published image (nousresearch/hermes-agent), not a
git checkout â€” the container has no working tree to pull into.  Update by
pulling a fresh image and restarting your container instead:

  docker pull nousresearch/hermes-agent:latest
  # then restart whatever started the container, e.g.:
  docker compose up -d --force-recreate hermes-agent
  # or, for ad-hoc runs, exit the current container and `docker run` again

Verify the new version after restart:
  docker run --rm nousresearch/hermes-agent:latest --version

Notes:
  â€¢ If you pinned a specific tag (e.g. ``:v0.14.0``) the ``:latest`` tag
    won't move your container â€” pull the newer tag you actually want, or
    switch to ``:latest`` / ``:main`` for rolling updates.  See available
    tags at https://hub.docker.com/r/nousresearch/hermes-agent/tags
  â€¢ Your config and session history live under ``$HERMES_HOME`` (``/opt/data``
    in the container, typically bind-mounted from the host) and persist
    across image upgrades â€” re-pulling doesn't lose any state.
  â€¢ Running a fork?  Build your own image with this repo's ``Dockerfile``
    and replace the ``docker pull`` step with your build/push pipeline.c                  ó   — t         S )zCReturn the user-facing message for ``hermes update`` inside Docker.)Ú_DOCKER_UPDATE_MESSAGEr,   r-   r.   Úformat_docker_update_messager}  À  s   € ä!Ð!r-   Úactionc                 ó0   — t        «       xs d}d| › d|› d�S )z/Build a user-facing error for managed installs.za package managerúCannot z): this Hermes installation is managed by z:.
Use your package manager to upgrade or reinstall Hermes.rJ  )r~  Úmanaged_systems     r.   Úformat_managed_messager‚  Å  s2   € ä'Ó)Ò@Ð-@€Nà
�&�ÐBÀ>ÐBRð SCð 	CðDr-   c                 óL   — t        t        | «      t        j                  ¬«       y)z+Print user-friendly error for managed mode.©ÚfileN)Úprintr‚  rg   rh   )r~  s    r.   Úmanaged_errorr‡  Í  s   € ä	Ô
  Ó
(¬s¯z©zÖ:r-   c                  ó<  — t         j                  j                  d«      dk(  ryddlm}   | «       ry	 i }t        t        «       dz  dd¬	«      5 }|D ]_  }|j                  «       }d
|v sŒ|j                  d«      rŒ*|j                  d
«      \  }}}|j                  «       ||j                  «       <   Œa 	 ddd«       |j                  dd«      |j                  dd«      |j                  dd«      |j                  dd«      dœS # 1 sw Y   ŒPxY w# t        $ r Y yw xY w)a™  Read container mode metadata from HERMES_HOME/.container-mode.
    Written by the NixOS activation script when container.enable = true; tells the host CLI to
    exec into the container instead of running locally. None when container mode is off, when
    already inside the container, or when HERMES_DEV=1 is set. Only FileNotFoundError is
    swallowed; other errors (permissions, malformed data) propagate.Ú
HERMES_DEVÚ1Nr   rp  z.container-modeÚrrW  rX  ú=ú#ÚbackendrS  Úcontainer_namezhermes-agentÚ	exec_userÚhermesÚ
hermes_binz /data/current-package/bin/hermes)rŽ  r�  r�  r’  )ÚosÚenvironrS   rr  rq  Úopenr   rC   rÖ   Ú	partitionÚFileNotFoundError)rq  ÚinfoÚfr7   rn   Ú_Úvalues          r.   Úget_container_exec_inforœ  Ò  s  € ô 
‡z�z‡~�~�lÓ# sÒ*Øå-Ù„~Øð	ØˆÜ”/Ó#Ð&7Ñ7¸ÀwÔOð 	6ÐSTØò 6�Ø—z‘z“|�Ø˜$’; t§¡°sÕ';Ø$(§N¡N°3Ó$7‘M�C˜˜EØ(-¯©«�D˜Ÿ™›Ò%ñ	6÷	6ð —8‘8˜I xÓ0ØŸ(™(Ð#3°^ÓDØ—X‘X˜k¨8Ó4Ø—h‘h˜|Ð-OÓPñ	Rð R÷	6ð 	6ûô ò Ùðús5   ³D ÁDÁ)DÁ;8DÂ4D ÄDÄD Ä	DÄDc                  ó   — t        «       dz  S )zGet the main config file path.úconfig.yaml©r   r,   r-   r.   rt   rt   ó  s   € äÓ˜}Ñ,Ð,r-   F)Úignore_user_configr   c                 ó6  — | s"t         j                  j                  d«      dk(  ryt        «       }	 t	        |d¬«      5 }t        |«      }ddd«       �t        |t        «      ryt        dt        |«      j                  › �«      }ddlm}  ||d	«      }t        |«      }d
|› d|rd|› �nd› d�}	|�	|	d|› d�z  }	|	dt!        |«      › �z  }	t"        j%                  |	«       t'        |	«      |‚# 1 sw Y   Œ¤xY w# t        $ r Y yt        $ r}|}Y d}~Œ�d}~ww xY w)a¼  Reject an existing invalid config before a non-interactive agent run.
    Interactive surfaces keep ``load_config()``'s recovery behavior so the operator can repair
    the file; a one-shot run has no such chance, and defaults there could silently pick a hosted
    provider and spend against ``.env`` credentials. Missing/empty files stay valid first-run
    states; ``--ignore-user-config`` / HERMES_IGNORE_USER_CONFIG=1 remain authoritative.ÚHERMES_IGNORE_USER_CONFIGrŠ  NrW  rX  z,top-level YAML value must be a mapping, got r   r\   r^   z+Hermes stopped because your settings file (rP   rM   r9   z‡. Fix it with `hermes config edit` and check with `hermes config check`, or add --ignore-user-config to run once with default settings.z! A copy of the broken file is at r_   ú
 Details: )r“  r”  rS   rt   r•  r"   r;   ÚdictÚ	TypeErrorÚtyper(   r—  rk   rd   r]   r>   rG   re   Úerrorr'   )
r   rK   r™  ÚdataÚparse_errorr2   r]   ro   rN   Úmessages
             r.   Úrequire_parseable_user_configr«  ø  s9  € ñ œRŸZ™ZŸ^™^Ð,GÓHÈCÒOØä!Ó#€Kð
fÜ�+¨Ô0ð 	%°AÜ! !Ó$ˆD÷	%ð ˆ<œ: d¬DÔ1ØÜÐ"NÌtÐTXËz×ObÑObÐNcÐ dÓeˆå7Ù ¨YÓ7€KÜ  Ó-€Eà
5°k°]ÐBZÙ"ˆT�%�‰>¨Ð
+ð ,`ð	`ð ð ÐØÐ6°{°mÀ1ÐEÑEˆØ�Ô/°Ó<Ð=Ð>Ñ>€GÜ
‡L�L�ÔÜ
  Ó
)¨{Ð:÷-	%ð 	%ûäò ÙÜò Ø�ûðús4   ±C9 ¾C-Á
C9 Ã-C6Ã2C9 Ã9	DÄDÄDÄDc                  ó   — t        «       dz  S )z&Get the .env file path (for API keys).ú.envrŸ  r,   r-   r.   Úget_env_pathr®    s   € äÓ˜vÑ%Ð%r-   c                  ód   — t        t        «      j                  j                  j                  «       S )z'Get the project installation directory.©r   Ú__file__Úparentrf  r,   r-   r.   rc  rc  !  s!   € ä”‹>× Ñ ×'Ñ'×/Ñ/Ó1Ð1r-   c                 ó   — t        | «      S )uÿ  chmod a directory owner-only (0700) and apply HERMES_UID/GID ownership. No-op when managed;
    in a container only an explicit HERMES_HOME_MODE is applied. HERMES_HOME_MODE (e.g. 0701)
    overrides the mode so a web server can traverse HERMES_HOME to a served subdirectory without
    directory listings.

    Also applies ``HERMES_UID``/``HERMES_GID``-based ownership when those env vars are set (#34107 â€” Docker
    deployments need this so profile subdirs created at runtime by kanban workers don't land as root:root
    and block subsequent uid-mapped workers).

    Delegates to the canonical import-safe primitive ``hermes_constants.apply_secure_dir_policy``
    so callers outside this package (``get_scratch_dir``) share one implementation (#117347).
    )r   ©ru   s    r.   Ú_secure_dirrµ  &  s   € ô # 4Ó(Ð(r-   c                 óØ   — t        «       s
t        «       ry	 t        j                  j	                  t        | «      «      rt        j                  | d«       yy# t        t        f$ r Y yw xY w)zŒchmod a file 0600. Skipped when managed (activation sets 0640 group-readable) or in a
    container (mounts often need broader permissions).Ni€  )	rK  r   r“  ru   ÚexistsrB   Úchmodrb   ÚNotImplementedErrorr´  s    r.   Ú_secure_filerº  6  sV   € ô „|Ô2Ô4ØðÜ�7‰7�>‰>œ#˜d›)Ô$Ü�H‰H�T˜5Õ!ð %øäÔ(Ð)ò Ùðús   —>A ÁA)Á(A)Úhomec                 óª  — | dz  }|j                  «       r	 |j                  d¬«      }t	        |«      sy	 |j                  t        d¬«       t#        |«       y# t        t        f$ r Y yw xY w# t        $ rÛ |j                  «       s‚ t        j                  ddt        | «      ¬«      \  }}	 t        j                  |dd¬«      5 }|j                  t        «       ddd«       n# 1 sw Y   nxY wt        j                  ||«       nG# t        $ r; t        t        «      5  t        j                   |«       ddd«       ‚ # 1 sw Y   ‚ xY ww xY wY �Œw xY w)	z�Seed DEFAULT_SOUL_MD on first run; upgrade a legacy comment-only scaffold in place.
    A SOUL.md the user actually customized is never touched.zSOUL.mdrW  rX  Nz	.SOUL.md.z.seed)ÚprefixÚsuffixÚdirÚw)r·  rZ  rb   ÚUnicodeDecodeErrorr   Ú
write_textr   Ú
is_symlinkÚtempfileÚmkstemprB   r“  Úfdopenri   re  r   Úunlinkrº  )r»  Ú	soul_pathÚexistingÚfdÚtmp_nameÚhandles         r.   Ú_ensure_default_soul_mdrÍ  B  s?  € ð �yÑ €IØ×ÑÔð	Ø ×*Ñ*°GÐ*Ó<ˆHô ' xÔ0ØðØ×Ñœ_°wÐÔ?ô& �Õøô1 Ô+Ð,ò 	Ùð	ûô ò Ø×#Ñ#Ô%Øô  ×'Ñ'¨{À7ÔPSÐTXÓPYÔZ‰ˆˆHð	Ü—‘˜2˜s¨WÔ5ð .¸Ø—‘œ_Ô-÷.÷ .ñ .úä�J‰J�x Õ+øÜò 	Üœ'Ó"ñ $Ü—	‘	˜(Ô#÷$à÷$àúð	úò ,ðúsj   —A ¶A. ÁA+Á*A+Á.>EÂ-DÃC$Ã	DÃ$C-	Ã)DÄEÄEÄD>Ä5	EÄ>EÅEÅEÅEÚ_HERMES_HOME_ENSURED)
ÚcronÚsessionsÚlogszlogs/curatorÚmemoriesÚpairingÚhooksÚimage_cacheÚaudio_cacheÚskillsc                  ó¬   — t        «       } t        | «      }ddlm}  || «       |t        v r| j                  «       ryddlm}  || t        t        «       y)zæEnsure the ~/.hermes directory skeleton exists with secure permissions.
    Memoized per home path: this runs on EVERY ``load_config()`` and the ~14 mkdir/chmod syscalls
    made repeated loads the dominant cost of hot read paths.r   )Úassert_named_profile_home_liveN)Úinitialize_home)	r   rB   rr  rÙ  rÎ  ri  Úhermes_cli.config_homerÚ  Ú_HERMES_HOME_SUBDIRS)r»  rn   rÙ  rÚ  s       r.   Úensure_hermes_homerÝ  l  sH   € ô Ó€DÜ
ˆd‹)€Cõ @Ù" 4Ô(Ø
Ô"Ñ" t§{¡{¤}ØÝ6Ù�DÔ.Ô0DÕEr-   )ÚDEFAULT_CONFIGÚOPTIONAL_ENV_VARS)Ú_API_MODE_ALIASESÚ_CAMEL_ALIASESÚ_KNOWN_PROVIDER_KEYSÚ_PROVIDER_NORMALIZE_WARNEDÚ_canonical_api_modeÚ_coerce_ssl_verifyÚ)_custom_provider_entry_to_provider_configÚ_entries_for_routeÚ _normalize_custom_provider_entryÚ_normalize_provider_modelsÚ_pick_provider_base_urlÚ_route_model_cfgÚ_warn_once_per_providerÚ4apply_custom_provider_extra_headers_to_client_kwargsÚ*apply_custom_provider_tls_to_client_kwargsÚcoerce_provider_idÚfind_provider_entryÚget_compatible_custom_providersÚget_custom_provider_api_modeÚ"get_custom_provider_context_lengthÚ!get_custom_provider_extra_headersÚ$get_custom_provider_model_capabilityÚ+get_custom_provider_session_affinity_headerÚ get_custom_provider_tls_settingsÚis_provider_enabledÚnormalize_extra_headersÚ"providers_dict_to_custom_providersÚstringify_provider_map)ÚNEUTRAL_PERSONALITY_NAMESÚprompt_textÚrender_personality_promptÚresolve_ephemeral_system_prompt)ÚFIRECRAWL_API_KEYÚBROWSERBASE_API_KEYÚBROWSERBASE_PROJECT_IDÚFAL_KEYÚVOICE_TOOLS_OPENAI_KEYÚELEVENLABS_API_KEY)rû   rè   ÚWHATSAPP_ALLOWED_USERSÚSLACK_BOT_TOKENÚSLACK_APP_TOKENÚSLACK_ALLOWED_USERSÚTAVILY_API_KEYÚTERMINAL_MODAL_MODE)é   rs   é   é
   é   ÚENV_VARS_BY_VERSIONÚrequired_onlyc           
      óÞ   — t         dfg}| s|j                  t        df«       |D ����cg c]2  \  }}|j                  «       D ]  \  }}t	        |«      s
d|i|¥d|i¥‘Œ Œ4 c}}}}S c c}}}}w )z.Check which environment variables are missing.TFÚnameÚis_required)ÚREQUIRED_ENV_VARSÚappendrß  ÚitemsÚget_env_value)r  ÚgroupsÚtabler  Úvar_namer˜  s         r.   Úget_missing_env_varsr  ¤  s‡   € ä  $Ð'Ð(€FÙØ�‰Ô(¨%Ð0Ô1ð #)÷(ñ (áˆE�;Ø#Ÿk™k›mò(ñ ˆH�dÜ˜XÔ&ð 
�Ð>˜TÐ> =°+Ó>ð(Ø>õ(ð (ùõ (s   ª7A'
c                 óf  — g }g }d}|t        | «      k  r|| |   }|dk(  r%| |dz   |dz    dk(  r|j                  d«       |dz  }Œ=|dk(  r#|j                  dj                  |«      «       g }n|j                  |«       |dz  }|t        | «      k  rŒ||j                  dj                  |«      «       |S )a|  Split a dotted config-key path, honoring backslash-escaped dots (``a\.b`` -> ``a.b``).
    Backslashes before any other character are preserved verbatim.

    ``hermes config set`` uses ``.`` as the nesting separator, so a key that itself contains a literal dot
    (e.g. provider names like ``qwen3.5-397b-wafer``) was silently split into bogus nested segments
    (#84064).
    r   ú\r8   é   r_   r9   )Úlenr  rD   )rn   ÚpartsÚcurrentÚiÚchs        r.   Ú_split_key_pathr%  °  s»   € ð €EØ€GØ	€AØ
Œc�#‹hŠ,Ø�‰VˆØ�Š:˜#˜a !™e A¨¡EÐ*¨cÒ1Ø�N‰N˜3ÔØ�‰FˆAØØ�Š9Ø�L‰L˜Ÿ™ Ó)Ô*Ø‰Gà�N‰N˜2ÔØ	ˆQ‰ˆð Œc�#‹h‹,ð 
‡L�L�—‘˜Ó!Ô"Ø€Lr-   Ú	containerr!  c                 ó€   ‡ ‡— t        ‰ t        «      r‰syt        ˆ ˆfd„t        t	        ‰«      dd«      D «       d«      S )uË  Return ``(literal_key, n_consumed)`` for the longest dotted literal key present in
    *container*, or None. With no multi-segment literal this is the historic plain-split walk.

    Dots in config key names are the norm, not the exception â€” model IDs (``grok-4.6``, ``glm-5.3``), Matrix
    room IDs (``!room:chat.example.cc``), and versioned provider names all embed dots. Users typing
    ``providers.myprov.models.grok-4.6.context_length`` do not know the escape syntax exists, so when
    navigating an EXISTING mapping we prefer an existing literal key equal to the dot-join of the next N
    path segments (longest match wins) over blindly splitting. See #84064 / #80006 / 91095 / #91607 /
    #99124.
    Nc              3   óx   •K  — | ]1  }d j                  ‰d| «      ‰v sŒd j                  ‰d| «      |f–— Œ3 y­w)r_   N)rD   )Ú.0Únr&  r!  s     €€r.   ú	<genexpr>z(_greedy_literal_match.<locals>.<genexpr>Ù  s@   øè ø€ Òh aÀsÇxÁxÐPUÐVXÐWXÐPYÓGZÐ^gÒGgˆ#�(‰(�5˜˜!�9Ó
˜qÔ	!Ñhùs   ƒ:Ÿ:r   éÿÿÿÿ)r;   r¤  ÚnextÚranger   )r&  r!  s   ``r.   Ú_greedy_literal_matchr/  Ë  s9   ù€ ô �i¤Ô&©eØÜÜh¬5´°U³¸QÀÓ+CÔhØóð r-   Úpartc                 óZ   ‡— t        | t        «      sy|dz   Št        ˆfd„| D «       d«      S )uO  Existing literal dotted key that creating an intermediate mapping ``part`` would shadow
    (``grok-4`` beside ``grok-4.5``) â€” the write would produce a phantom sibling the runtime never
    reads, so callers fail loudly instead.

    Called when a write is about to CREATE a new intermediate mapping named ``part``. See #84064.
    Nr_   c              3   óh   •K  — | ])  }t        |t        «      sŒ|j                  ‰«      sŒ&|–— Œ+ y ­w©N)r;   rB   rÖ   )r)  Úkr½  s     €r.   r+  z#_phantom_sibling.<locals>.<genexpr>ç  s%   øè ø€ ÒU�q¬°A´sÕ);ÀÇÁÈVÕ@T”ÑUùs   ƒ2™2«2)r;   r¤  r-  )r&  r0  r½  s     @r.   Ú_phantom_siblingr5  Ý  s/   ø€ ô �i¤Ô&ØØ�C‰Z€FÜÓU˜IÔUÐW[Ó\Ð\r-   Ú
dotted_keyc                 ó(  — t        |«      }| }d}|t        |«      k  �rO||d }t        |«      dk(  }t        |t        «      r+|d   }|r||t	        |«      <   y	 |t	        |«         }|dz  }nðt        |t        «      r¼t        ||«      }	|	�Q|	\  }
}||z   t        |«      k(  r|||
<   yt        |j                  |
«      t        t        f«      si ||
<   ||
   }||z  }ŒÌ|d   }|r|||<   yt        ||«      }|�*|j                  dd«      }t        d	|›d
|›d|›d|› d�	«      ‚|j                  |i «      }|dz  }n$t        dt        |«      j                  › d|›�«      ‚|t        |«      k  r�ŒNyy# t
        t        f$ r t        d|›d|›d�«      ‚w xY w)a   Set a value at a dotted key path, creating intermediate dicts on demand.
    Numeric segments index lists; the index must already exist (lists are never grown).

    Guards against #17876: before this fix the code unconditionally replaced any non-dict value (including
    lists) with ``{}``, silently destroying list-typed config like ``custom_providers`` whenever a caller
    used an indexed path.
    Dotted key names (#84064 family): when navigating an existing mapping, an existing literal key equal to
    the dot-join of the next N segments is preferred over blind splitting (see ``_greedy_literal_match``),
    so ``models.grok-4.6.supports_vision`` lands on the real ``grok-4.6`` entry. And when a write WOULD
    create a new intermediate mapping that shadows an existing dotted sibling (``grok-4`` beside
    ``grok-4.5``), it raises ``ValueError`` instead of silently writing a phantom the runtime never reads.
    r   Nr8   z!Cannot navigate into list at key z
: segment z is not a numeric indexr_   z\.zRefusing to create nested key ú in z-: the mapping already contains a literal key zT that contains a dot. If you meant that key, escape its dots with a backslash (e.g. z).zCannot navigate into z at key )r%  r   r;   Úlistr<   r¥  rÕ   r¤  r/  rS   r5  re  Ú
setdefaultr¦  r(   )Úconfigr6  r›  r!  r"  r#  Ú	remainingÚat_leafr0  rÔ   rn   ÚconsumedÚshadowedÚescapeds                 r.   Ú_set_nestedrA  ê  s  € ô ˜JÓ'€EØ€GØ	€AØ
Œc�%‹j‹.Ø˜!˜"�Iˆ	Ü�i“. AÑ%ˆÜ�gœtÔ$Ø˜Q‘<ˆDÙØ%*�œ˜D›	Ñ"Øð@Ø!¤# d£)Ñ,�ð
 �‰F‰AÜ˜¤Ô&Ü)¨'°9Ó=ˆEØÐ Ø %‘��XØ�x‘<¤3 u£:Ò-Ø#(�G˜C‘LØä! '§+¡+¨cÓ"2´T¼4°LÔAØ#%�G˜C‘LØ! #™,�Ø�X‘�ØØ˜Q‘<ˆDÙØ %�˜‘ØÜ'¨°Ó6ˆHØÐ#Ø"×*Ñ*¨3°Ó6�Ü Ø4°T°H¸DÀÀð O6Ø6>°\ð BNØNUÈYÐVXðZó[ð [ð ×(Ñ(¨¨rÓ2ˆGØ�‰F‰AäÐ3´D¸³M×4JÑ4JÐ3KÈ8ÐT^ÐSaÐbÓcÐcðU Œc�%‹jŽ.øô œzÐ*ò @ÜØ7¸
°~ð FØ#˜hÐ&=ð?ó@ð @ð@ús   ÁE/ Å/"FT)Úclear_api_keyÚclear_api_modeÚclear_base_urlÚ	model_cfgrB  rC  rD  c                ó  — t        | t        «      s| S |rH| j                  dd«       | j                  dd«       | j                  dd«       | j                  dd«       |r| j                  dd«       |r| j                  dd«       | S )a%  Remove stale inline endpoint credentials from a model config.
    ``model.api_key`` is valid only for explicit custom endpoints; built-in providers resolve
    credentials from env/auth.json/the pool. Leftovers keep secrets in config.yaml and can
    contaminate later custom resolution paths.Úapi_keyNÚapiÚkey_envÚapi_key_envÚapi_modeÚbase_url)r;   r¤  Úpop)rE  rB  rC  rD  s       r.   Ú clear_model_endpoint_credentialsrN  '  sy   € ô �i¤Ô&ØÐÙØ�‰�i Ô&Ø�‰�e˜TÔ"ð 	�‰�i Ô&Ø�‰�m TÔ*ÙØ�‰�j $Ô'ÙØ�‰�j $Ô'ØÐr-   c                 óJ  — g }| }d}	 ||d }t        |t        «      r	 t        |d   «      }||    d}n&t        |t        «      rt        ||«      }|€y|\  }}ny||z  }|t        |«      k(  r|||fS |j                  ||f«       ||   }Œƒ# t        t        t
        f$ r Y yw xY w)az  Walk *parts* through nested dicts/lists (escape-aware, greedy-literal like ``_set_nested``).
    Returns ``(parents, container, key)`` where ``container[key]`` is the addressed leaf and
    ``parents`` lists the ``(container, key)`` hops above it, or ``None`` when any hop is missing,
    a list index is non-numeric/out of range, or a scalar is hit before the path is consumed.r   Nr8   )
r;   r9  r<   r¥  rÕ   Ú
IndexErrorr¤  r/  r   r  )	r;  r!  rh  r"  r#  r<  rn   r>  rÔ   s	            r.   Ú_locate_nestedrQ  D  sÐ   € ð
 €GØ€GØ	€AØ
Ø˜!˜"�Iˆ	Ü�gœtÔ$ðÜ˜) A™,Ó'�Ø˜’ð ‰HÜ˜¤Ô&Ü)¨'°9Ó=ˆEØˆ}ØØ!‰MˆC‘àØ	ˆX‰ˆØ”�E“
Š?Ø˜G SÐ(Ð(Ø�‰˜ �~Ô&Ø˜#‘,ˆð) øô œz¬:Ð6ò Ùðús   žB ÂB"Â!B"c                 óR   — t        | t        |«      «      }|€t        S |\  }}}||   S )aÉ  Return a dotted-path value (``_MISSING`` when absent); same navigation as ``_set_nested``
    so ``models.grok-4.6.context_length`` reads the real ``grok-4.6`` entry.

    Mirrors ``_set_nested``'s navigation: honors backslash-escaped dots and prefers an existing literal
    dotted key over blind splitting, so ``config get providers.p.models.grok-4.6.context_length`` reads the
    real ``grok-4.6`` entry instead of reporting the key unset (#84064).
    )rQ  r%  Ú_MISSING)r;  r6  Úlocrš  r&  rn   s         r.   Ú_get_nestedrU  c  s5   € ô ˜¤°Ó!<Ó
=€CØ
€{ÜˆØÑ€A€y�#Ø�S‰>Ðr-   c                 ó„   — t        | t        |«      «      }|€y|\  }}}||= t        |«      D ]  \  }}|i k7  r y||= |}Œ y)az  Remove a dotted-path value; True if it existed. Empty dict containers left behind are
    dropped, while user-authored empty lists and non-empty sibling branches are preserved.

    Same escape-aware, greedy-literal navigation as ``_set_nested`` / ``_get_nested`` (#84064): unsetting an
    unescaped dotted key removes the real literal entry rather than a phantom sibling.
    FT)rQ  r%  Úreversed)r;  r6  rT  rh  r"  rn   r²  r0  s           r.   Ú_unset_nestedrX  r  sj   € ô ˜¤°Ó!<Ó
=€CØ
€{ØØÑ€GˆW�cØ�ˆä  Ó)ò ‰ˆ�Ø�bŠ=Øð ð �4ˆLØ‰ð	ð
 r-   >   r  ÚEXA_API_KEYÚGITHUB_TOKENÚSUDO_PASSWORDÚAPI_SERVER_KEYÚHONCHO_API_KEYré   r
  r  r  ÚPARALLEL_API_KEYrù   ÚTOOL_GATEWAY_URLrü   ÚDISCORD_BOT_TOKENr   ÚFIRECRAWL_API_URLÚTERMINAL_SSH_HOSTÚTERMINAL_SSH_USERÚOPENROUTER_API_KEYÚPERPLEXITY_API_KEYÚTELEGRAM_BOT_TOKENr  ÚBROWSER_USE_API_KEYÚTOOL_GATEWAY_DOMAINÚTOOL_GATEWAY_SCHEMEÚCONNECTOR_GATEWAY_URLÚFIRECRAWL_GATEWAY_URLr  r  ÚTOOL_GATEWAY_USER_TOKENc                 óˆ   — d| v ry| j                  «       }|t        v xs$ |j                  d«      xs |j                  d«      S )a  Return whether `hermes config set` routes this credential-shaped key to .env through the
    provider credential lifecycle. Non-secret env settings (``*_HOME_CHANNEL``, ``*_ALLOWED_USERS``)
    are ``config_env_routing.is_env_setting_key`` and take the plain ``.env`` path.r_   F)Ú_API_KEYÚ_TOKENÚ_SECRETÚTERMINAL_SSH)rÎ   Ú_ENV_CONFIG_KEYSÚendswithrÖ   )rn   Ú	key_uppers     r.   Ú_is_env_config_keyru  ”  sN   € ð ˆc�zØØ—	‘	“€IàÔ%Ð%ò 	0Ø×ÑÐ?Ó@ò	0à×Ñ Ó/ð1r-   Úas_jsonc                óò   — |rt        j                  | d¬«      S t        | t        «      r| rdS dS | €yt        | t        t
        f«      r%t        j                  | d¬«      j                  «       S t        | «      S )z.Format a config value for command-line output.F)Úensure_asciiÚtrueÚfalseÚnull)Ú	sort_keys)
ÚjsonÚdumpsr;   Úboolr¤  r9  ÚyamlÚ	safe_dumpÚrstriprB   )r›  rv  s     r.   Ú_format_config_get_valuerƒ  ¡  sg   € áÜ�z‰z˜%¨eÔ4Ð4Ü�%œÔÙˆvÐ+ GÐ+Ø€}ØÜ�%œ$¤˜Ô&Ü�~‰~˜e¨uÔ5×<Ñ<Ó>Ð>Üˆu‹:Ðr-   c                  ól   ‡ ‡— g Šddt         dt         dt        fˆ ˆfd„Š  ‰ t        t        «       «       ‰S )z>Check which config fields are missing or outdated (recursive).rH   r"  r½  c                 ó&  •— | j                  «       D ]}  \  }}|j                  d«      rŒ|s|n|› d|› �}||vr‰j                  ||d|› �dœ«       Œ@t        |t        «      sŒQt        |j                  |«      t        «      sŒq ‰|||   |«       Œ y )Nrš  r_   zNew config option: )rn   ÚdefaultÚdescription)r  rÖ   r  r;   r¤  rS   )rH   r"  r½  rn   Údefault_valueÚfull_keyÚ_checkÚmissings         €€r.   rŠ  z)get_missing_config_fields.<locals>._check²  s—   ø€ Ø"*§.¡.Ó"2ò 	>ÑˆC�Ø�~‰~˜cÔ"ØÙ"(‘s°°¸¸#¸Ð.?ˆHØ˜'Ñ!Ø—‘ x¸MØ1DÀXÀJÐ/Oñ Qõ Rä˜M¬4Õ0´ZÀÇÁÈCÓ@PÔRVÕ5WÙ�} g¨c¡l°HÕ=ñ	>r-   ©r9   )r¤  rB   rÞ  Úload_config)rŠ  r‹  s   @@r.   Úget_missing_config_fieldsrŽ  ®  s5   ù€ à€Gñ	>œð 	>¬ð 	>´cö 	>ñ Œ>œ;›=Ô)Ø€Nr-   c                  óX  ‡‡— 	 ddl m} mŠ 	  | «       }|sg S t        «       Šˆˆfd„|D «       }|D ��cg c]+  \  }}|�"t        |t        «      sŒ|j                  «       rŒ*|‘Œ- c}}S # t        $ r g cY S w xY w# t        $ r"}t        j                  d|«       g cY d}~S d}~ww xY wc c}}w )zVReturn skill-declared config vars (``skills.config.<key>``) that are missing or empty.r   )Údiscover_all_skill_config_varsÚSKILL_CONFIG_PREFIXz)discover_all_skill_config_vars failed: %sNc           	   3   óh   •K  — | ])  }|t        ‰g‰› d |d   › �j                  d «      ¢­Ž f–— Œ+ y­w)r_   rn   N)Úcfg_getrE   )r)  Úvarr‘  r;  s     €€r.   r+  z0get_missing_skill_config_vars.<locals>.<genexpr>Ò  s>   øè ø€ ÒlÐ\_ˆs”G˜FÐVÐ(;Ð'<¸A¸cÀ%¹j¸\Ð%J×%PÑ%PÐQTÓ%UÒVÔWÑlùs   ƒ/2)
Úagent.skill_utilsr�  r‘  rk   re   Údebugr�  r;   rB   rC   )r�  Úall_varsÚeÚvaluesr”  Úvr‘  r;  s         @@r.   Úget_missing_skill_config_varsr›  Á  s¢   ù€ ðßYðÙ1Ó3ˆñ
 Øˆ	ä‹]€FÜlÐckÔl€FØ$×\‘F�C˜¨¨	´jÀÄCÕ6HÐQR×QXÑQXÕQZŠCÓ\Ð\øô ò ØŠ	ðûô
 ò ä�‰Ð@À!ÔDØ�	ûðüó ]s?   „A' �A8 ³B&ÁB&ÁB&Á'A5Á4A5Á8	B#ÂBÂB#ÂB#r›  c                 ó~   — t        | t        «      ry	 t        | «      }t        |d«      S # t        t        f$ r Y yw xY w)zHReturn a safe integer config version, treating invalid values as legacy.r   )r;   r  r<   r¥  rÕ   Úmax)r›  Úversions     r.   Ú_coerce_config_versionrŸ  Ö  sD   € ä�%œÔØðÜ�e“*ˆô ˆw˜‹?Ðøô ”zÐ"ò Ùðús   “* ª<»<©Úraise_on_parse_errorr¡  c                 ó  — t        t        j                  dd«      «      xs d}t        «       }|j	                  «       s||fS 	 t        |d¬«      5 }t        |«      }ddd«       €i }t        |t        «      s(| r$t        d|› d	t        |«      j                  › �«      ‚i }t        |j                  d«      «      |fS # 1 sw Y   ŒaxY w# t        $ r/}t        ||«       | rt        d|› d|› d�«      |‚||fcY d}~S d}~ww xY w)
aT  Return ``(current_version, latest_version)`` from the raw on-disk config.
    Reads the raw file rather than ``load_config()``: the deep-merge would make a file lacking
    ``_config_version`` inherit the latest version, hiding that the schema was never migrated.
    Invalid YAML gets a parse warning, not an automatic schema rewrite. Tolerant runtime status
    callers keep the historical latest/latest fallback for malformed YAML; mutation and explicit
    validation paths set ``raise_on_parse_error`` so a parse failure or a non-mapping root cannot
    be mistaken for an up-to-date config.Ú_config_versionr8   rW  rX  NzCannot inspect z!: config.yaml is not valid YAML (ú)z5: config.yaml top-level value must be a mapping, got )rŸ  rÞ  rS   rt   r·  r•  r"   rk   rq   r'   r;   r¤  r¦  r(   )r¡  ÚlatestrK   r™  r;  r˜  s         r.   Úcheck_config_versionr¦  á  s'  € ô $¤N×$6Ñ$6Ð7HÈ!Ó$LÓMÒRÐQR€FÜ!Ó#€KØ×ÑÔØ�vˆ~Ðð	Ü�+¨Ô0ð 	'°AÜ# AÓ&ˆF÷	'ð €~ØˆÜ�fœdÔ#ñ  Ü(Ø! + ð /"Ü"& v£,×"7Ñ"7Ð!8ð:óð ð ˆÜ! &§*¡*Ð->Ó"?Ó@À&ÐHÐH÷+	'ð 	'ûäò Ü" ;°Ô2ÙÜ(Ø! + Ð.OÐPQÈsÐRSÐTóàðð �vˆ~Õûðús6   ÁC ÁB<ÁC Â<CÃC Ã	D Ã$C;Ã5D Ã;D >   ÚsignalÚpluginsÚtimeoutsÚ	image_genÚ	platformsÚ	video_genÚmcp_serversÚfallback_modelÚprofile_routesÚreset_triggersÚallow_all_usersÚrequire_mentionÚalways_log_localÚcustom_providersÚplatform_toolsetsÚmultiplex_profilesÚsmart_model_routingÚstt_echo_transcriptsÚknown_plugin_toolsetsÚknown_builtin_toolsetsÚgroup_sessions_per_userÚfilter_silence_narrationÚthread_sessions_per_userÚunauthorized_dm_behaviorÚtool_gateway_declined_tools>   r  ÚmodelÚmodelsrG  rI  rK  rL  Ú
extra_bodyÚ
ssl_verifyÚssl_ca_certÚcontext_lengthÚcatalog_providerÚrate_limit_delay>   rG  rK  rL  rÇ  c                   ó0   — e Zd ZU dZeed<   eed<   eed<   y)ÚConfigIssuez$A detected config structure problem.Úseverityrª  ÚhintN)r(   r)   r*   r+   rB   Ú__annotations__r,   r-   r.   rÉ  rÉ  ,  s   … á.ØƒMØƒLØ
„Ir-   rÉ  ÚissuesrÊ  rª  rË  c                 ó<   — | j                  t        |||«      «       y r3  )r  rÉ  )rÍ  rÊ  rª  rË  s       r.   Ú_issuerÏ  4  s   € Ø
‡M�M”+˜h¨°Ó6Õ7r-   ÚentryÚlabelÚfieldsr¾  c           
      óh   — |D ]-  \  }}|j                  |«      rŒt        | d|› d|› d|› �|«       Œ/ y)zdAppend a warning for every falsy ``field`` of *entry* (message: ``<label> is missing '<f>' field``).rf   z is missing 'z' fieldN)rS   rÏ  )rÍ  rÐ  rÑ  rÒ  r¾  ÚfieldrË  s          r.   Ú_require_fieldsrÕ  8  sE   € ð ò [‰ˆˆtØ�y‰y˜ÕÜ�6˜9¨¨¨}¸U¸GÀ7È6È(Ð&SÐUYÕZñ[r-   ))r  z#Add a name, e.g.: name: my-provider)rL  zDAdd the API endpoint URL, e.g.: base_url: https://api.example.com/v1)©Úproviderz/Add: provider: openrouter (or another provider))rÀ  zAdd: model: <model-name>)rÖ  )rÀ  z8Add: model: anthropic/claude-sonnet-4 (or another model)r;  c                 óþ   — | j                  d«      }t        |t        «      rd|v sy |j                  d«      }t        |t        «      r|j	                  «       j                  «       nd }|dvrt        |dd|›�d«       y y )NÚvoiceÚsubmit_mode>   ÚdraftÚdirectr§  z3voice.submit_mode must be 'direct' or 'draft', got zSSet voice.submit_mode to direct (submit immediately) or draft (edit before sending))rS   r;   r¤  rB   rC   r[  rÏ  )r;  rÍ  Ú	voice_cfgrÚ  Ú
normalizeds        r.   Ú_validate_voicerß  L  s   € Ø—
‘
˜7Ó#€IÜ�y¤$Ô'¨M¸YÑ,FØØ—-‘- Ó.€KÜ0:¸;ÌÔ0L�×"Ñ"Ó$×*Ñ*Ô,ÐRV€JØÐ,Ñ,Üˆv�wÐ"UÐVaÐUdÐ eØdõ	fð -r-   c                 óŽ  — d| vry| j                  d«      }d}|�"t        |t        «      st        |dd|›�|«       yt        |t        «      r|j	                  «       sy|j	                  «       }	 ddl}|j                  d«       	 |j                  |«       y# t        $ r Y yw xY w# t        $ r t        |dd|›d	�|«       Y yw xY w)
u¶  ``timezone`` must be an IANA name the runtime can load.

    ``hermes_time._get_zoneinfo()`` swallows an invalid name behind a single WARNING in the
    gateway log, then runs the agent clock AND every cron schedule on server-local time.
    Surface it here, where doctor and the startup check both look. Silent when the
    interpreter has no tz database at all (bare Windows without ``tzdata``) â€” nothing can be
    judged there.
    ÚtimezoneNzïUse an IANA zone name such as America/New_York or Asia/Tokyo (see `timedatectl list-timezones`). With an invalid value the agent clock and cron schedules silently fall back to server-local time. HERMES_TIMEZONE overrides this key when set.r§  z/timezone must be an IANA zone name string, got r   ÚUTCz	timezone z is not a valid IANA zone name)rS   r;   rB   rÏ  rC   ÚzoneinfoÚZoneInfork   )r;  rÍ  ÚtzrË  r  rã  s         r.   Ú_validate_timezoneræ  W  sÙ   € ð ˜ÑØØ	�‰�JÓ	€Bð!€Dð 
€~œj¨¬SÔ1Üˆv�wÐ"QÐRTÐQWÐ XÐZ^Ô_ØÜ�rœ3Ô B§H¡H¤JØØ�8‰8‹:€DðÛØ×Ñ˜%Ô ðZØ×Ñ˜$Õøô ò Ùðûô ò ZÜˆv�w )¨D¨8Ð3QÐ RÐTXÖYðZús$   Á/B ÂB& Â	B#Â"B#Â&CÃCÚentriesÚnon_dictc                óä   — |\  }}}t        | «      D ]\  \  }}	t        |	t        «      s3t        |||j	                  |t        |	«      j                  ¬«      |«       ŒIt        ||	|› d|› d�|«       Œ^ y)z Validate each list entry: ``non_dict`` = (severity, message-with-{i}-and-{type}, hint) for
    non-dict items; dict items get ``_require_fields`` with *fields*.)r#  r¦  ú[ú]N)Ú	enumerater;   r¤  rÏ  rV   r¦  r(   rÕ  )
rç  rÑ  rÍ  rÒ  rè  rÊ  rª  rË  r#  rÐ  s
             r.   Ú_validate_entry_listrí  x  st   € ð
 'Ñ€Hˆg�tÜ˜gÓ&ò D‰ˆˆ5Ü˜%¤Ô&Ü�6˜8 W§^¡^°a¼dÀ5»k×>RÑ>R ^Ó%SÐUYÕZä˜F E¨e¨W°A°a°S¸¨?¸FÕCñ	Dr-   zeChange to:
  custom_providers:
    - name: my-provider
      base_url: https://...
      api_key: ...Úcpc                 ób  — t        | t        «      rQt        |ddt        «       t	        | j                  «       «      t        z  }|rt        |ddt        |«      › d�d«       yyt        | t        «      rt        | d|t        d¬	«       yt        |dd
t        | «      j                  › d�t        «       y)uc   custom_providers must be a list of dicts â€” a dict or a scalar is silently dropped by the runtime.r§  uO   custom_providers is a dict â€” it must be a YAML list (items prefixed with '-')rf   zRoot-level keys z( look like custom_providers entry fieldszLThese should be indented under a '- name: ...' list entry, not at root levelr´  )rf   z0custom_providers[{i}] is not a dict (got {type})z1Each entry should have at minimum: name, base_url©rè  zcustom_providers is a un    â€” it must be a YAML list (items prefixed with '-'); legacy custom_providers entries are ignored until it isN)r;   r¤  rÏ  Ú_CP_LIST_HINTÚsetÚkeysÚ_CUSTOM_PROVIDER_LIKE_FIELDSÚsortedr9  rí  Ú_CP_REQUIRED_FIELDSr¦  r(   )rî  rÍ  Ú
suspiciouss      r.   Ú_validate_custom_providersrø  ˆ  sµ   € ä�"”dÔÜˆv�wØ`Ôboô	qä˜Ÿ™›“^Ô&BÑBˆ
ÙÜ�6˜9Ø%¤f¨ZÓ&8Ð%9Ð9aÐbØaõcð ô 
�BœÔ	Ü˜RÐ!3°VÔ=Pð \Aö 	Bô 	ˆv�wØ'¬¨R«×(9Ñ(9Ð':ð ;Ið IÜJWõ	Yr-   Úfbc                 óæ   — t        | t        «      rt        | d|t        d¬«       y	t        | t        «      s%t        |ddt        | «      j                  › �d«       y	| rt        || dt        d¬«       y	y	)
z5fallback_model: single dict OR list of dicts (chain).r®  )r§  z0fallback_model[{i}] should be a dict, got {type}z!Each entry needs provider + modelrð  r§  zAfallback_model should be a dict with 'provider' and 'model', got zZChange to:
  fallback_model:
    provider: openrouter
    model: anthropic/claude-sonnet-4u    â€” fallback will be disabled)r¾  N)
r;   r9  rí  Ú_FB_REQUIRED_FIELDSr¤  rÏ  r¦  r(   rÕ  Ú_FB_SINGLE_REQUIRED_FIELDS)rù  rÍ  s     r.   Ú_validate_fallback_modelrý  ž  sx   € ä�"”dÔÜ˜RÐ!1°6Ô;Nð Znö 	oä˜œDÔ!Üˆv�wØRÔSWÐXZÓS[×SdÑSdÐReÐfØnõ	pñ 
Ü˜ Ð$4Ô6PØ?ö	Að 
r-   c                 ó‚  — | j                  d«      }t        |t        «      sy	 ddlm} t        «       }dD ]x  }t        |j                  |«      xs d«      j                  «       j                  «       }|r||v rŒD|j                  |«        |d|«      }|sŒat        |dd|› d	|› d
|› d�d«       Œz y# t
        $ r Y yw xY w)z§A stale web backend selection otherwise fails only at the first web_search/web_extract
    call with a generic "no registered provider" error; warn at startup instead.ÚwebNr   )Úremoved_backend_note)rŽ  Úsearch_backendÚextract_backendr9   rf   zweb.z is set to 'z', but u9    â€” web_search/web_extract will fail until it is changedzERun 'hermes tools' and pick a different Web Search & Extract provider)rS   r;   r¤  Útools.tool_backend_helpersr   rk   rò  rB   rC   r[  rc   rÏ  )r;  rÍ  Úweb_cfgr   ÚseenÚ_keyÚ_valÚnotes           r.   Ú_validate_web_backendsr	  ¬  sÔ   € ð �j‰j˜Ó€GÜ�gœtÔ$ØðÝCô “€DØ@ò 
\ˆÜ�7—;‘;˜tÓ$Ò*¨Ó+×1Ñ1Ó3×9Ñ9Ó;ˆÙ�t˜t‘|ØØ�‰�ŒÙ# E¨4Ó0ˆÚÜ�6˜9Ø˜$˜˜|¨D¨6°¸¸ð ?Jð JàZõ\ñ
\øô ò Ùðús   ¤B2 Â2	B>Â=B>c                  ó–   ‡ ‡— i Š dt         t        t        f   dt        ddfˆ ˆfd„Š ‰t        d«       ‰ j	                  t
        «       ‰ S )z´Dotted key -> ``"list"``/``"mapping"`` for every slot the schema fixes to a container:
    ``DEFAULT_CONFIG`` (sections included) plus the known-container table for roots it omits.Únoder½  r3   Nc                 ó¶   •— | j                  «       D ]E  \  }}|r|› d|› �n|}t        |t        «      rd‰|<    ‰||«       Œ0t        |t        «      sŒAd‰|<   ŒG y )Nr_   Úmappingr9  )r  r;   r¤  r9  )r  r½  rn   r›  ru   ÚslotsÚwalks        €€r.   r  z_container_slots.<locals>.walkÊ  s`   ø€ ØŸ*™*›,ò 	%‰JˆC�Ù(.�f�X˜Q˜s˜eÑ$°CˆDÜ˜%¤Ô&Ø'��d‘Ù�U˜DÕ!Ü˜E¤4Õ(Ø$��d’ñ	%r-   r9   )r	   rB   r
   rÞ  ÚupdateÚ_KNOWN_CONTAINER_TYPES)r  r  s   @@r.   Ú_container_slotsr  Å  sJ   ù€ ð €Eð%”4œœS˜‘>ð %¬3ð %°4ö %ñ 	Œ˜ÔØ	‡L�LÔ'Ô(Ø€Lr-   c                 ó¸  — t        «       j                  «       D ]¦  \  }}|t        v rŒt        | g|j	                  d«      ¢­Ž }t        |t        «      rt        |«      sŒF	 t        j                  |«      }t        |t        t        f«      sŒst        |d|› d|›d|› d�d|› dt        j                  |«      › d|› d	�«       Œ¨ y
# t        j                  $ r Y Œ¿w xY w)u  A container slot holding ONE quoted string (``enabled: '["a","b"]'``) is skipped by every
    isinstance-gated reader while ``config get`` echoes it back, so plugins silently unmount and
    exclusions silently lapse (#83308, #105706). Finding only â€” the file is never rewritten.r_   rf   z is the quoted string u    â€” Hermes expects a YAML z) here and every reader ignores the stringzRun: hermes config set rA   z  (stores a real z&), or remove the quotes in config.yamlN)r  r  Ú_SCALAR_AS_ONE_ITEM_LIST_KEYSr“  rE   r;   rB   Ú_looks_structured_valuer€  Ú	safe_loadÚ	YAMLErrorr9  r¤  rÏ  ÚshlexÚquote)r;  rÍ  rn   Úkindr›  Úparseds         r.   Ú_validate_quoted_containersr  Ø  sí   € ô &Ó'×-Ñ-Ó/ò :‰	ˆˆTàÔ/Ñ/ØÜ˜Ð0 §¡¨3£Ò0ˆÜ˜%¤Ô%Ô-DÀUÔ-KØð	Ü—^‘^ EÓ*ˆFô �fœt¤T˜lÕ+Ü�6˜9Ø�UÐ0°°	Ð9TÐUYÐTZð [9ð 9à,¨S¨E°´5·;±;¸uÓ3EÐ2FÐFWÐX\ÐW]ð ^9ð 9õ:ñ:øô �~‰~ò 	Ùð	ús   Á CÃCÃCc           	      ór  — | €	 t        «       } g }t	        | |«       t        | |«       | j                  d«      }| j                  d«      }|t        f|t        ffD ]  \  }}|€Œ	 |||«       Œ t        |t        «      rd| vrd|xs i v rt        |ddd«       |r| j                  d	«      st        |d
dd«       | D ]<  }|j                  d«      rŒ|t        vsŒ|t        v sŒ't        |d
d|› d�d|› d�«       Œ> t        | |«       t!        | |«       |S # t        $ r}ddlm}  ||«      gcY d}~S d}~ww xY w)z«Validate config.yaml structure and return detected issues (accepts a pre-loaded dict).
    Catches common YAML mistakes that otherwise surface as confusing runtime errors.Nr   )Úconfig_load_issuer´  r®  r§  zGfallback_model appears inside custom_providers instead of at root levelzDMove fallback_model to the top level of config.yaml (no indentation)rÀ  rf   u[   custom_providers defined but no 'model' section â€” Hermes won't know which provider to useziAdd a model section:
  model:
    provider: custom
    default: your-model-name
    base_url: https://...rš  zRoot-level key 'uW   ' looks misplaced â€” should it be under 'model:' or inside a 'custom_providers' entry?zMove 'z' under the appropriate section)r�  rk   rÛ  r  rß  ræ  rS   rø  rý  r;   r¤  rÏ  rÖ   Ú_KNOWN_ROOT_KEYSrô  r	  r  )	r;  r2   r  rÍ  rî  rù  r›  Ú	validatorrn   s	            r.   Úvalidate_config_structurer!  ï  sx  € ð €~ð	,Ü “]ˆFð
 !#€FÜ�F˜FÔ#Ü�v˜vÔ&Ø	�‰Ð&Ó	'€BØ	�‰Ð$Ó	%€BØ Ô"<Ð=ÀÔD\Ð?]Ð^ò %ÑˆˆyØÑÙ�e˜VÕ$ð%ô �"”dÔÐ 0¸Ñ >ÐCSÐXZÒX`Ð^`ÑCaÜˆv�wÐ iØUô	Wñ 
�&—*‘*˜WÔ%Üˆv�yØlð+ô	,ð ò BˆØ�~‰~˜cÕ" sÔ2BÒ'BÀsÔNjÒGjÜ�6˜9Ø% c Uð  +Bð  CØ˜C˜5Ð ?Ð@õBðBô ˜6 6Ô*Ü ¨Ô/Ø€MøôE ò 	,Ý@Ù% cÓ*Ð+Õ+ûð	,ús   „
D Ä	D6ÄD1Ä+D6Ä1D6c                 óD  — 	 t        | «      }|sydg}|D ]6  }|j                  dk(  rdnd}|j                  d|› d|j                  › �«       Œ8 |j                  d«       t
        j                  j                  d	j                  |«      d
z   «       y# t        $ r g }Y Œ‘w xY w)zSPrint config structure warnings to stderr at startup; nothing if config is healthy.Nu3   [33mâš  Config issues detected in config.yaml:[0mr§  u   [31mâœ—[0mu   [33mâš [0mú  rA   z2  [2mRun 'hermes doctor' for fix suggestions.[0mr`   ú

)	r!  rk   rÊ  r  rª  rg   rh   ri   rD   )r;  rÍ  ÚlinesÚciÚmarkers        r.   Úprint_config_warningsr(    s¦   € ðÜ*¨6Ó2ˆñ ØàHÐI€EØò 1ˆØ)+¯©¸Ò)?Ñ%ÐEYˆØ�‰�r˜&˜  2§:¡: ,Ð/Õ0ð1ð 
‡L�LÐKÔLÜ‡J�J×Ñ�T—Y‘Y˜uÓ%¨Ñ.Õ/øô ò ØŠðús   ‚B ÂBÂBc                  óÊ  — 	 t        «       } g }dD ]I  }t        | j                  |«      xs d«      j	                  «       }|sŒ2|j                  d|› d|› d�«       ŒK |rwddlm}  |«       }|j                  dd	«       |j                  d
«       |j                  d|› d�«       t        j                  j                  dj                  |«      dz   «       yy# t        $ r Y yw xY w)zâWarn if MESSAGING_CWD / TERMINAL_CWD is set in .env (canonical: terminal.cwd in config.yaml).
    Reads the file rather than ``os.environ`` because runtime bridges and session restoration
    legitimately set ``TERMINAL_CWD``.N)ÚMESSAGING_CWDÚTERMINAL_CWDr9   u     [33mâš [0m rŒ  u&    found in .env â€” this is deprecated.r   ©Údisplay_hermes_homeu/   [33mâš  Deprecated .env settings detected:[0mzN  [2mMove to config.yaml instead:  terminal:\n    cwd: /your/project/path[0mz'  [2mThen remove the old entries from z	/.env[0mr`   r$  )Úload_envrk   rB   rS   rC   r  rr  r-  Úinsertrg   rh   ri   rD   )Úenv_mapr%  r  Úvalr-  Ú	hint_paths         r.   Úwarn_deprecated_cwd_env_varsr3  +  sè   € ðÜ“*ˆð €EØ1ò eˆÜ�'—+‘+˜dÓ#Ò) rÓ*×0Ñ0Ó2ˆÚØ�L‰LÐ0°°°a¸°uÐ<bÐcÕdðeñ Ý8á'Ó)ˆ	Ø�‰�QÐOÔPØ�‰ð=ô	>ð 	�‰ÐAÀ)ÀÈLÐYÔZÜ�
‰
×Ñ˜Ÿ™ 5Ó)¨FÑ2Õ3ð øô ò Ùðús   ‚
C Ã	C"Ã!C"c                 ó   — t        | «       y)ai  Persist a migrated config under THE migration write invariant: a migration may only
    persist values that DIFFER from the schema default, plus explicit removals/renames of user
    data. Every migration step MUST write through here (``save_config`` with default-stripping
    ON, no ``merge_existing``) so the invariant cannot regress one migration at a time.N)Úsave_config©r;  s    r.   Ú_persist_migrationr7  E  s   € ô
 �Õr-   r  r˜  ÚpromptÚresultsc                 óÐ   — |j                  d«      rt        |«      nt        |«      j                  «       }|syt	        | |«       |d   j                  | «       t        d| › �«       y)z`Prompt for one env var (masked when ``info['password']``), save it, record it; False if skipped.ÚpasswordFÚ	env_addedõ     âœ“ Saved T)rS   r   r   rC   Úsave_env_valuer  r†  )r  r˜  r8  r9  r›  s        r.   Ú_prompt_and_save_envr?  M  s^   € à,0¯H©H°ZÔ,@Ô  Ô(ÄjÐQWÓFX×F^ÑF^ÓF`€EÙØÜ�4˜ÔØˆKÑ×Ñ Ô%Ü	ˆL˜˜Ð
Ô Ør-   c                 óŽ   — 	 t        | «      j                  «       j                  «       }|dv S # t        t        f$ r d}Y |dv S w xY w)Nr*  >   ÚyÚyes)ÚinputrC   r[  ÚEOFErrorÚKeyboardInterrupt)r8  Úanswers     r.   Ú_ask_yes_norG  X  sV   € ðÜ�v“×$Ñ$Ó&×,Ñ,Ó.ˆð �\Ð!Ð!øô Ô'Ð(ò Ø‰Ø�\Ð!Ð!ðús   ‚'- ­AÁAÚinteractiveÚquietc                 óV  — g g g dœ}t        d¬«      \  }}	 t        «       }|r|st        d|› d�«       ddlm}m}m} 	 dt        «       v }	|	xr ||k  xr ||k  }
|
rO |«       }|d
   j                  |«       t        j                  j                  d|› d�«       |st        d|› �«       n
 ||||«       t        ||«       t        ||«       ||k  r|s|
st        d|› d|› �«       t        d¬«      }|r+|s)t        d«       |D ]  }t        d|d   › d|d   › �«       Œ | rs|rqt        d«       |D ]a  }|j!                  d«      rt        d|d   › �«       t#        |d   |d|d   › d�|«      s|d
   j                  d|d   › d�«       t        «        Œc | r|st%        |||«       |d   j'                  d„ t)        «       D «       «       ||k  r|
st+        «       }||d<   t-        |«       t/        «       }|r| r|st1        ||«       |S # t        $ r Y �Œáw xY w# t        $ r d	}	Y �ŒÜw xY w)zDMigrate config to latest version, prompting for new required fields.)r<  Úconfig_addedÚwarningsTr   u'     âœ“ Normalized .env line formatting (z line(s) changed)r   )ÚSUPPORT_FLOOR_VERSIONÚrun_migrationsÚsupport_floor_messager£  FrL  u   âš  hermes config: r`   õ     âš  zConfig version: õ    â†’ ©r  u0   
âš ï¸�  Missing required environment variables:u      â€¢ r  ú: r‡  z
Let's configure them now:
Úurlú  Get your key at: r#  r8  úSkipped z - some features may not workrK  c              3   ó&   K  — | ]	  }|d    –— Œ y­w)rn   Nr,   )r)  rÔ  s     r.   r+  z!migrate_config.<locals>.<genexpr>¡  s   è ø€ Ò"Y°E 5¨¥<Ñ"Yùó   ‚)r¦  Úsanitize_env_filer†  rk   Úhermes_cli.config_migrationsrM  rN  rO  Úread_user_config_rawr  rg   rh   ri   Ú_disable_suspicious_mcp_serversÚ_warn_invalid_platform_toolsetsr  rS   r?  Ú_offer_new_optional_env_varsÚextendrŽ  Úread_raw_configr7  r›  Ú_offer_skill_config_vars)rH  rI  r9  Úcurrent_verÚ
latest_verÚfixesrM  rN  rO  Úhas_explicit_versionÚfloor_refusedrp   Úmissing_envr”  r;  Úmissing_skill_configs                   r.   Úmigrate_configri  `  s}  € à°ÀÑC€Gô 3ÈÔMÑ€K�ðÜ!Ó#ˆÙ™ÜÐ;¸E¸7ÐBSÐTÔU÷Fñ Fð%Ø0Ô4HÓ4JÐJÐð 	Òa Ð/DÑ!DÒaÈÐWaÑIað áÙ#Ó%ˆØ�
Ñ×"Ñ" 3Ô'ä�
‰
×ÑÐ.¨s¨e°2Ð6Ô7ÙÜ�F˜3˜%�.Õ!á�{ G¨UÔ3ä# G¨UÔ3Ü# G¨UÔ3à�ZÒ©±mÜÐ   ¨U°:°,Ð?Ô@ä&°TÔ:€KÙ™5ÜÐAÔBØò 	AˆCÜ�G˜C ™K˜=¨¨3¨}Ñ+=Ð*>Ð?Õ@ð	Aá‘{ÜÐ-Ô.Øò 	ˆCØ�w‰w�uŒ~ÜÐ+¨C°©J¨<Ð8Ô9Ü'¨¨F©°S¸B¸sÀ8¹}¸oÈRÐ:PÐRYÔZØ˜
Ñ#×*Ñ*¨X°c¸&±k°]ÐB_Ð+`ÔaÜ�Gð	ñ ™5Ü$ [°*¸gÔFð ˆNÑ×"Ñ"Ñ"YÔ=VÓ=XÔ"YÔYà�ZÒ©Ü Ó"ˆØ$.ˆÐ Ñ!Ü˜6Ô"ä8Ó:ÐÙ¡±EÜ Ð!5°wÔ?à€NøôA ò Úðûô ò %Ø$Óð%ús"   —H	 ¿H È		HÈHÈH(È'H(c                 óª  — t        «       }|j                  d«      }t        |t        «      sy	 ddlm} d}|j                  «       D ]i  \  }}t        |t        «      r	 |||«      nd}|sŒ$d|d<   d}| d   j                  d	|› d
�«       |rŒF|D ]  }	t        d|	› �«       Œ t        d|› d�«       Œk |r||d<   t        |«       yy# t        $ r Y yw xY w)z¥Post-migration: disable exfiltration-shaped MCP stdio entries (hand-edited or from older
    installs). The stanza is preserved for auditability but marked disabled.r­  Nr   )Úvalidate_mcp_server_entryFÚenabledTrL  z Disabled suspicious MCP server 'ú'rP  u     âš  Disabled MCP server 'z' pending review)r`  rS   r;   r¤  Úhermes_cli.mcp_securityrk  rk   r  r  r†  r7  )
r9  rI  r;  Úraw_mcp_serversrk  Úmcp_touchedÚserver_namerÐ  rÍ  Úissues
             r.   r\  r\  ¯  s  € ô Ó€Fð —j‘j Ó/€OÜ�o¤tÔ,ØðÝEð €KØ-×3Ñ3Ó5ò 
OÑˆ�UÜBLÈUÔTXÔBYÑ*¨;¸Ô>Ð_cˆÙØØ ˆˆiÑØˆØ�
Ñ×"Ñ"Ð%EÀkÀ]ÐRSÐ#TÔUÚØò (�Ü˜˜u˜gÐ&Õ'ð(äÐ/°¨}Ð<LÐMÕNð
Oñ Ø /ˆˆ}ÑÜ˜6Õ"ð øô ò Ùðús   ®C Ã	CÃCc                 ó  — 	 ddl m} ddlm} ddlm}  |t        «       j                  d«      ||«      D ]'  }| d   j                  |«       |rŒt        d|› �«       Œ) y	# t        $ r }t        j                  d|«       Y d	}~y	d	}~ww xY w)
z¹Surface invalid toolset names in platform_toolsets: ``resolve_toolset()`` returns [] for an
    unknown name, silently disabling the affected tools. Best-effort; never blocks migration.r   )Úvalidate_toolset)Úvalidate_platform_toolsets)Útoolset_allowed_for_platformrµ  rL  rP  z(platform_toolsets validation skipped: %sN)Útoolsetsrt  Úhermes_cli.toolset_validationru  Úhermes_cli.toolset_scoperv  r`  rS   r  r†  rk   re   r–  )r9  rI  rt  ru  rv  rÀ  Ú_ts_val_errs          r.   r]  r]  Í  sˆ   € ðNÝ-ÝLÝIá+ÜÓ!×%Ñ%Ð&9Ó:Ð<LÐNjólò 	$ˆAà�JÑ×&Ñ& qÔ)ÚÜ˜˜q˜c�lÕ#ñ		$øô
 ò NÜ�‰Ð?À×MÑMûðNús   ‚AA  ÁA  Á 	B	Á)BÂB	Úheadingr  Úquestionc                 óš   — t        | «       |D ]  }t        d|› �«       Œ t        «        t        |«      st        d«       yt        «        y)zUPrint a bulleted offer list and ask; False (with the "set later" hint) when declined.u       â€¢ z1  Set later with: hermes config set <key> <value>FT)r†  rG  )r{  r  r|  Úitems       r.   Ú_offer_listr  Þ  sH   € ä	ˆ'„NØò !ˆÜ�˜˜ÐÕ ð!ä	„GÜ�xÔ ÜÐAÔBØÜ	„GØr-   rb  rc  c                 ó„  — t        «       }t        | dz   |dz   «      D ]'  }|j                  t        j	                  |g «      «       Œ) t        |«      D �cg c]   }t        |«      s|t        v r|t        |   f‘Œ" }}|rBt        dt        |«      › d�|D ��cg c]  \  }}|› d|j	                  dd«      › �‘Œ c}}d«      sy|D ]q  \  }}t        d	|j	                  d|«      › �«       |j	                  d
«      rt        d|d
   › �«       t        ||d	|j	                  d|«      › d�|«       t        «        Œs yc c}w c c}}w )zSInteractively offer env vars that are NEW since the user's previous config version.r8   ú
  z$ new optional key(s) in this update:õ    â€” r‡  r9   z  Configure new keys? [y/N]: Nr#  rT  rU  r8  z (Enter to skip): )rò  r.  r  r  rS   rõ  r  rß  r  r   r†  r?  )rb  rc  r9  Únew_var_namesÚverr  Únew_and_unsetr˜  s           r.   r^  r^  ë  sX  € ä›€MÜ�[ 1‘_ j°1¡nÓ5ò ?ˆØ×ÑÔ0×4Ñ4°S¸"Ó=Õ>ð?ô ˜=Ó)öBàÜ˜TÔ" tÔ/@Ñ'@ð 
Ô  Ñ&Ò'ðB€Mð Bñ ¤Ø
Œs�=Ó!Ð"Ð"FÐGØGT×U¹¸¸tˆDˆ6��t—x‘x ¨rÓ2Ð3Ò	4ÓUØ'ô!)ð 	Ø#ò ‰
ˆˆdÜ��4—8‘8˜M¨4Ó0Ð1Ð2Ô3Ø�8‰8�EŒ?ÜÐ'¨¨U© }Ð5Ô6Ü˜T 4¨2¨d¯h©h°xÀÓ.FÐ-GÐGYÐ)ZÐ\cÔdÜ�ñùòBùó 	Vs   Á%D7Â!D<rh  c                 óš  — t        dt        | «      › d�| D �cg c]#  }|d   › d|d   › d|j                  dd«      › d	�‘Œ% c}d
«      syt        «       }	 ddlm} | D ]Ì  }|j                  dd«      }|rd|› d	�nd}t        d|d   › |› d�«      j                  «       xs t        |xs d«      }|rAt        ||› d|d   › �|«       |d   j                  |d   «       t        d|d   › d|› �«       n.|d   j                  d|d   › d|j                  dd«      › d�«       t        «        ŒÎ t        |«       yc c}w # t        $ r d}Y Œïw xY w)zRPrompt for skill-declared settings that are missing/empty and persist the answers.r�  z! skill setting(s) not configured:rn   r‚  r‡  z (from skill: ÚskillrT  r¤  z#  Configure skill settings? [y/N]: Nr   )r‘  zskills.configr†  r9   z (default: r#  r8  rS  r_   rK  r=  ú = rL  rV  u    â€” skill 'ú?z' may ask for it later)r  r   rS   r`  r•  r‘  rk   r   rC   rB   rA  r  r†  r7  )	rh  r9  rš  r;  r‘  r”  r†  Údefault_hintr›  s	            r.   ra  ra    sŠ  € äØ
ŒsÐ'Ó(Ð)Ð)JÐKØauÖvÐ\]ˆAˆe‰Hˆ:�U˜1˜]Ñ+Ð,¨N¸1¿5¹5ÀÈ)Ó;TÐ:UÐUVÒ	WÒvØ-ô/ð 	ÜÓ€Fð.Ý9ð $ò ˆØ—'‘'˜) RÓ(ˆÙ3:˜ W I¨QÑ/ÀˆÜ˜R  H¡˜¨|¨n¸BÐ?Ó@×FÑFÓHÒ^ÌCÐPWÒP]Ð[]ÓL^ˆÙÜ˜Ð#6Ð"7°q¸¸U¹¸Ð EÀuÔMØ�NÑ#×*Ñ*¨3¨u©:Ô6Ü�L  U¡ ¨C°¨wÐ7Õ8à�JÑ×&Ñ&Ø˜3˜u™:˜, l°3·7±7¸7ÀCÓ3HÐ2IÐI_Ð`ôbä�ðô �vÕùò) 	wøô ò .Ø-Òð.ús   ˜(D7
ÁD< Ä<E
Å	E
ÚrawÚoverridec                 ó   — t        j                  |«      }| j                  «       D ]e  \  }}||vrt        j                  |«      ||<   Œ#t        |j	                  |«      t
        «      sŒCt        |t
        «      sŒTt        |||   «      ||<   Œg |S )uR  Merge *override* over *raw* for partial ``save_config`` writes.
    Omitted top-level sections are preserved; shared dict sections deep-merge so one nested key
    can change without dropping siblings on disk. Key REMOVALS are not supported here â€”
    migrations go through ``_persist_migration`` with a full ``read_raw_config()`` dict.)ÚcopyÚdeepcopyr  r;   rS   r¤  Ú_deep_merge)r‹  rŒ  Úresultrn   r›  s        r.   Ú_merge_partial_saver’    s{   € ô
 �]‰]˜8Ó$€FØ—i‘i“kò :‰
ˆˆUØ�fÑÜŸ-™-¨Ó.ˆF�3ŠKÜ˜Ÿ
™
 3›¬Õ.´:¸eÄTÕ3JÜ% e¨V°C©[Ó9ˆF�3ŠKð	:ð
 €Mr-   Úbasec                 óò   — | j                  «       }|j                  «       D ]S  \  }}t        |j                  |«      t        «      }|r#t        |t        «      rt        ||   |«      ||<   ŒJ|r|€ŒO|||<   ŒU |S )a¦  Recursively merge *override* into *base*: dict-over-dict recurses (so overriding one leaf
    keeps sibling defaults), and ``None`` over a dict section is ignored.

    An empty section key in config.yaml (``terminal:`` with no value) parses as YAML ``None``; treating that
    as an override would replace the entire default dict with ``None`` and crash every downstream consumer
    that expects a mapping (#58277).
    )rŽ  r  r;   rS   r¤  r�  )r“  rŒ  r‘  rn   r›  Ú	over_dicts         r.   r�  r�  *  st   € ð �Y‰Y‹[€FØ—n‘nÓ&ò  ‰
ˆˆUÜ˜vŸz™z¨#›´Ó5ˆ	Ùœ E¬4Ô0Ü% f¨S¡k°5Ó9ˆF�3ŠKÙ ¡ØˆF�3ŠKð ð €Mr-   ÚcfgÚdotted_keysc                 óÀ   — t        «       }|D ]L  }|j                  d«      �^ }}t        | g|¢­Ž }t        |t        «      sŒ4||v sŒ9||= |j                  |«       ŒN | |fS )zïRemove dotted leaf keys from *cfg* in place -> ``(cfg, keys_actually_present)``.
    ``save_config`` drops managed-scope leaves this way so a bulk write never persists a user
    value that would lose to the managed layer on the next load.r_   )rò  rE   r“  r;   r¤  rc   )r–  r—  ÚstrippedÚdottedrh  Úleafr  s          r.   Ú_strip_dotted_keysrœ  <  sj   € ô “E€HØò !ˆØŸ™ cÓ*‰ˆ�$Ü�sÐ%˜WÒ%ˆÜ�dœDÕ! d¨d¢lØ�T�
Ø�L‰L˜Õ ð!ð �ˆ=Ðr-   z\${([^}]+)}c                 óÌ   — 	 ddl m}m}  |«       €t        j
                  j                  | «      S  || «      S # t        $ r" t        j
                  j                  | «      cY S w xY w)u|  Resolve the env var behind a ``${VAR}`` / ``${env:VAR}`` ref â€” plain ``os.environ`` outside
    a profile secret scope (legacy behavior for the default profile).

    Inside a scope (a multiplexed gateway turn, a secondary profile's config load, a cron job) the read goes
    through ``agent.secret_scope.get_secret`` so the ref resolves against *that* profile's ``.env``: under
    multiplexing a miss is a miss, never another profile's ``os.environ`` value (#84079 â€” every profile
    "had" the default profile's ``${MATRIX_ACCESS_TOKEN}`` and fanned out). Same policy as
    ``gateway.config._getenv`` and ``get_env_value``.
    r   )Úcurrent_secret_scopeÚ
get_secret)Úagent.secret_scoperž  rŸ  rk   r“  r”  rS   )r  rž  Ú_get_secrets      r.   Ú_env_ref_lookupr¢  M  sW   € ð$ßVñ ÓÐ%Ü�z‰z�~‰~˜dÓ#Ð#Ù�tÓÐøô	 ò $Ü�z‰z�~‰~˜dÓ#Ò#ð$ús   ‚8 ¸(A#Á"A#Úmc                 ó~  — | j                  d«      }| j                  d«      j                  «       }t        |«      }|€H|j                  d«      s5t	        |«      r*t
        j                  d||j                  dd«      d   «       |S t        |«      }|�|S |j                  d«      rt
        j                  d||«       |S )a‡  Expand one ``${VAR}`` (legacy bare name) or ``${env:VAR}`` (Cursor-style SecretRef).
    Other SecretRef sources (``file:``, ``bitwarden:``, ``vault:``...) are NOT resolved here:
    external backends inject their values into the environment at startup (the ``secrets:``
    block), so a config ref only ever needs the env shape. Unresolved refs stay verbatim so
    callers can detect them.r   r8   úenv:u¬   Config ref %r uses source %r which is not resolvable in config.yaml â€” external secret sources inject env vars at startup, so reference the variable as ${env:NAME} insteadú:zTConfig ref %r: %s is not set (check ~/.hermes/.env); keeping the literal placeholder)	ÚgrouprC   Ú_env_ref_var_namerÖ   Ú_is_non_env_secret_refre   rf   rE   r¢  )r£  r‹  Úinnerr  r1  s        r.   Ú_env_expand_matchr«  `  s»   € ð �'‰'�!‹*€CØ�G‰G�A‹J×ÑÓ€EÜ˜UÓ#€DØ€|Ø×Ñ Ô'Ô,BÀ5Ô,IÜ�N‰NðLð �U—[‘[  aÓ(¨Ñ+ô	-ð
 ˆ
Ü
˜$Ó
€CØ
€Øˆ
Ø×Ñ˜ÔÜ�‰ð.Ø/2°Dô	:ð €Jr-   Úrefc                 ó>   — d| v xr t        j                  d| «      duS )zWTrue for a SecretRef body with a non-``env`` source (``bitwarden:FOO``, ``vault:...``).r¦  z^[a-z][a-z0-9_-]*:N)ÚrerÔ   ©r¬  s    r.   r©  r©  {  s"   € à�#ˆ:ÒJœ"Ÿ(™(Ð#8¸#Ó>ÀdÐJÐJr-   c                 ó    — | j                  «       } | j                  d«      r | t        d«      d j                  «       xs dS t        | «      ry| S )zTEnv-var name a ``${...}`` body reads, or None for a non-env source / empty ``env:``.r¥  N)rC   rÖ   r   r©  r¯  s    r.   r¨  r¨  €  sH   € à
�)‰)‹+€CØ
‡~�~�fÔØ”3�v“;�<Ð ×&Ñ&Ó(Ò0¨DÐ0Ü˜cÔ"ØØ€Jr-   c                 ó<  — t        | t        «      rt        j                  t        | «      S t        | t
        «      r-| j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}S t        | t        «      r| D �cg c]  }t        |«      ‘Œ c}S | S c c}}w c c}w )z]Recursively expand ``${VAR}`` / ``${env:VAR}`` in string values (keys/non-strings untouched).)	r;   rB   Ú_ENV_REF_REÚsubr«  r¤  r  Ú_expand_env_varsr9  )Úobjr4  rš  r~  s       r.   r´  r´  Š  s}   € ä�#”sÔÜ�‰Ô0°#Ó6Ð6Ü�#”tÔØ36·9±9³;×?©4¨1¨a�Ô# AÓ&Ñ&Ó?Ð?Ü�#”tÔØ36Ö7¨4Ô  Õ&Ò7Ð7Ø€Jùó @ùâ7s   ÁBÁ<Bc                 óJ  — |€i }t        | t        «      r8t        j                  | «      D ]  }t	        |«      }|€Œt        |«      ||<   Œ  |S t        | t        «      r#| j                  «       D ]  }t        ||«       Œ |S t        | t        «      r| D ]  }t        ||«       Œ |S )uP  Map each env-sourced ``${...}`` ref in *obj* to its current value.
    Stored with cached ``load_config()`` results so a cache hit can detect that the expansion was
    made against a different environment (load before ``load_hermes_dotenv()``, in-process
    rotation) â€” file mtime/size alone cannot see either.

    See #58514.
    )
r;   rB   r²  Úfindallr¨  r¢  r¤  r™  Ú_env_ref_snapshotr9  )rµ  Úsnapshotr‹  r  r›  r~  s         r.   r¸  r¸  •  s´   € ð ÐØˆÜ�#”sÔÜ×&Ñ& sÓ+ò 	7ˆCÜ$ SÓ)ˆDØÑÜ!0°Ó!6�˜’ð	7ð €Oô 
�CœÔ	Ø—Z‘Z“\ò 	/ˆEÜ˜e XÕ.ð	/ð
 €Oô 
�CœÔ	Øò 	.ˆDÜ˜d HÕ-ð	.à€Or-   c                 ó¼   — t        | t        «      syi }| D ]C  }t        |t        «      rt        |j                  d«      t        «      s y|d   }||v r y|||<   ŒE |S )zHReturn a name-indexed dict only when all items have unique string names.Nr  )r;   r9  r¤  rS   rB   )r  Úindexedr~  r  s       r.   Ú_items_by_unique_namer¼  ­  se   € ä�eœTÔ"ØØ€GØò ˆÜ˜$¤Ô%¬Z¸¿¹ÀÓ8HÌ#Ô-NÙØ�F‰|ˆØ�7‰?ÙØˆ�Šðð €Nr-   c                 ó¾  — t        | t        «      r=t        |t        «      r-t        j                  |«      r| ||fv st	        |«      | k(  r|S | S t        | t
        «      rot        |t
        «      r_| j                  «       D ��ci c]C  \  }}|t        ||j                  |«      t        |t
        «      r|j                  |«      nd«      “ŒE c}}S t        | t        «      rït        |t        «      rßt        | «      }t        |«      }t        |«      }|�]|�[| D �cg c]O  }t        ||j                  |j                  d«      «      |� |j                  |j                  d«      «      nd«      ‘ŒQ c}S t        | «      D �	�cg c]H  \  }	}t        ||	t        |«      k  r||	   ndt        |t        «      r|	t        |«      k  r||	   nd«      ‘ŒJ c}}	S | S c c}}w c c}w c c}}	w )z°Restore raw ``${VAR}`` templates where the value is otherwise unchanged, so persisting a
    loaded (expanded) config never writes the plaintext secret back to ``config.yaml``.Nr  )r;   rB   r²  Úsearchr´  r¤  r  Ú_preserve_env_ref_templatesrS   r9  r¼  rì  r   )
r"  r‹  Úloaded_expandedrn   r›  Úcurrent_by_nameÚraw_by_nameÚloaded_by_namer~  Úindexs
             r.   r¿  r¿  ¼  sÓ  € ô �'œ3Ô¤J¨s´CÔ$8¼[×=OÑ=OÐPSÔ=TØ�s˜OÐ,Ñ,Ô0@ÀÓ0EÈÒ0PØˆJØˆä�'œ4Ô ¤Z°´TÔ%:ð
 &Ÿm™m›o÷	/ñ ��Uð Ô,Ø�s—w‘w˜s“|Ü,6°ÌÔ,M�×#Ñ# CÔ(ÐSWóYñ Yó/ð 	/ô �'œ4Ô ¤Z°´TÔ%:ô 0°Ó8ˆÜ+¨CÓ0ˆÜ.¨Ó?ˆØÐ&¨;Ð+Bð
 $ö	%ð ô ,Ø˜+Ÿ/™/¨$¯(©(°6Ó*:Ó;Ø<JÐ<V�N×&Ñ& t§x¡x°Ó'7Ô8Ð\`õbò%ð %ô  )¨Ó1÷3ñ ��tô (ØØ#¤c¨#£hÒ.��E’
°Dä˜o¬tÔ4¸ÄÀ_ÓAUÒ9Uð   Ò&àõó3ð 	3ð €Nùó7/ùò%ùó
3s   ÂAGÄAGÅ;AGc                 ól   ‡‡— t        «       Šdt        dt        t        df   ddfˆˆfd„Š ‰| d«       ‰S )z­Leaf paths explicitly present in a RAW (un-normalized) config, so values injected by
    normalisation are never mistaken for user-set ones. Feeds ``_strip_default_values``.r›  ru   .r3   Nc                 óš   •— t        | t        «      r&| j                  «       D ]  \  }} ‰|||fz   «       Œ y |r‰j                  |«       y y r3  )r;   r¤  r  rc   )r›  ru   rn   ÚchildÚ_walkÚpathss       €€r.   rÈ  z%_explicit_config_paths.<locals>._walkè  sI   ø€ Ü�eœTÔ"Ø#Ÿk™k›mò ,‘
��UÙ�e˜T S F™]Õ+ñ,áØ�I‰I�d�Oð r-   r,   ©rò  r
   r   rB   )r;  rÈ  rÉ  s    @@r.   Ú_explicit_config_pathsrË  ã  s?   ù€ ô #&£%€Eð”Sð ¤¤c¨3 h¡ð °Dö ñ 
ˆ&�"ÔØ€Lr-   Úpreserve_keysc                 ó˜   ‡‡— dht        ‰xs d«      z  Šdt        dt        dt        t        df   dt        fˆˆfd„Š ‰| |d«      xs i S )	a-  Return *config* without keys whose values match *defaults*.
    Paths in *preserve_keys* (explicitly present in the user's raw config) are always kept even
    when equal to the default. Dicts whose every child is stripped are removed entirely so
    default-only subtrees never bloat ``config.yaml``.)r£  r,   r›  r†  ru   .r3   c                 ó¤  •— |‰v rt        j                  | «      S t        | t        «      r| r}t        |t        «      r|ni }| j	                  «       D ��ci c]#  \  }}| ‰||j                  |«      ||fz   «      “Œ% }}}|j	                  «       D ��ci c]  \  }}|€Œ	||“Œ c}}xs d S | |k(  rd S t        j                  | «      S c c}}w c c}}w r3  )rŽ  r�  r;   r¤  r  rS   )	r›  r†  ru   Údefault_dictr4  rš  r™  Ú_striprÌ  s	          €€r.   rÐ  z%_strip_default_values.<locals>._stripü  sÂ   ø€ Ø�=Ñ Ü—=‘= Ó'Ð'Ü�eœTÔ"¡uÜ&0°¼$Ô&?™7ÀRˆLØSX×S^ÑS^ÓS`×aÉ4È1Èa˜™6 ! \×%5Ñ%5°aÓ%8¸$À!À¹+ÓFÑFÐaˆHÑaØ%-§^¡^Ó%5×G™T˜Q ¸¹�A�q‘DÓGÒOÈ4ÐOØ Ò'ˆtÐA¬T¯]©]¸5Ó-AÐAùó bùÛGs   Á(CÂ
CÂCrÊ  )r;  rH   rÌ  rÐ  s     `@r.   Ú_strip_default_valuesrÑ  ó  s`   ù€ ð *Ð*¬S°Ò1DÀ"Ó-EÑE€MðB”cð B¤Cð B¬u´S¸#°X©ð BÄ3ö Bñ �&˜( BÓ'Ò-¨2Ð-r-   Úraw_defaultc                 ó>  — t        | t        «      rot        | j                  d«      xs d«      j	                  «       }| j                  d«      xs | j                  d«      }t        |xs d«      j	                  «       |fS t        | xs d«      j	                  «       dfS )z�Canonicalize ``model.default``/``model.model`` -> ``(model, provider)``; a dict value pairs
    the model string with the provider it must be routed through.r×  r9   rÀ  r†  )r;   r¤  rB   rS   rC   )rÒ  r×  rÀ  s      r.   Úsplit_model_config_defaultrÔ    s†   € ô �+œtÔ$Ü�{—‘ zÓ2Ò8°bÓ9×?Ñ?ÓAˆØ—‘ Ó(ÒF¨K¯O©O¸IÓ,FˆÜ�E’K˜RÓ ×&Ñ&Ó(¨(Ð3Ð3Ü�Ò!˜rÓ"×(Ñ(Ó*¨BÐ/Ð/r-   c                 óT  ‡ ‡— ‰ j                  d«      Št        ‰t        «      r‰j                  d«      nd}|duxr t        |t        «       xs_ t        ‰t        «      xrM ‰j                  d«      xs: ‰j                  d«      xs' ‰j                  d«      xs t	        ˆfd„dD «       «      }t	        ˆ fd„d	D «       «      }|s|s‰ S t        ‰ «      Š ‰ j                  d«      }t        |t        «      rt        |«      n|rd
|ini }|‰ d<   dD ]Ð  }|j                  |«      }t        |t        «      sŒ%|j                  d«      xs |j                  d
«      }t        |j                  d«      xs d«      j                  «       }t        |xs d«      j                  «       ||<   |sŒ˜t        |j                  d«      xs d«      j                  «       }	|	r|	dk(  sŒÌ||d<   ŒÒ dD ]=  }
‰ j                  |
«      }|r|j                  |
«      s|||
<   ‰ j                  |
d«       Œ? |j                  d«      �t        |j                  d«      «      |d<   ‰ j                  d«      |j                  d«      fD ]  }|sŒ|j                  d«      rŒ||d<   Œ ‰ j                  dd«       |j                  dd«       |j                  d«      xs |j                  d«      }|j                  d
«      s|r||d
<   |j                  d
«      r$|j                  dd«       |j                  dd«       ‰ S )uÍ  Canonicalize the ``model`` section at the single load/save chokepoint.
    Root-level ``provider``/``base_url``/``context_length`` (older layouts) are moved under
    ``model`` only when the corresponding ``model.*`` key is empty â€” never overriding. ``api_base``
    (the OpenAI-SDK/LiteLLM name users reach for) is an alias for ``base_url``; the runtime reads
    only ``model.base_url``. A dict-valued ``default``/``model``/``name`` is flattened so no reader
    sees a nested dict, and the id is canonicalized to ``default``.

    Also aliases ``api_base`` â†’ ``base_url`` (issue #8919). ``api_base`` is the intuitive name OpenAI-SDK /
    LiteLLM users reach for, and ``hermes config set`` blindly accepts any dotted key â€” so
    ``model.api_base`` got written, confirmed, and then silently ignored by the runtime resolver (which
    reads only ``model.base_url``), causing requests to fall back to OpenRouter. We migrate the alias to the
    canonical key (fallback-only â€” never override an explicit ``base_url``) and drop the alias so it can't
    confuse later loads.
    Finally, canonicalizes the model-id key to ``model.default`` (issue #34500). The runtime resolver and
    ~14 other readers select the chat model via ``model.default``; ``model.model`` was already aliased
    inline at some sites but ``model.name`` was not, so a custom-provider config like ``model: {name: <id>,
    provider: <custom>}`` resolved to an empty model and the API request went out with ``model=`` (HTTP 400
    from OpenAI-compatible backends) â€” while display paths (``hermes status``/``dump``) read ``name`` and
    *showed* the model, making the failure silent. Normalizing here (the single load/save chokepoint) means
    every reader, present and future, sees a populated ``default`` and the stale alias is migrated out of
    config.yaml on the next save. Precedence: ``default`` > ``model`` > ``name`` (never overrides an
    explicit ``default``, so existing configs are unaffected).
    rÀ  r×  NÚapi_baser  c              3   ó\   •K  — | ]#  }t        ‰j                  |«      t        «      –— Œ% y ­wr3  )r;   rS   r¤  )r)  r4  Úmodel_ins     €r.   r+  z-_normalize_root_model_keys.<locals>.<genexpr>0  s    øè ø€ Ò[¸”:˜hŸl™l¨1›o¬t×4Ñ[ùs   ƒ),)r†  rÀ  r  c              3   ó@   •K  — | ]  }‰j                  |«      –— Œ y ­wr3  ©rS   )r)  r4  r;  s     €r.   r+  z-_normalize_root_model_keys.<locals>.<genexpr>1  s   øè ø€ Òa Q�6—:‘:˜a—=Ñaùs   ƒ)r×  rL  rÅ  rÖ  r†  r9   Úauto)r×  rL  rÅ  rL  )rS   r;   r¤  rB   ÚanyrC   rM  rï  )r;  Úmodel_providerÚneeds_model_workÚhas_rootrÀ  r  r  Ú_nested_modelÚ_nested_providerÚ_outer_providerrn   Úroot_valÚ	alias_valÚaliasrØ  s   `             @r.   Ú_normalize_root_model_keysræ    så  ù€ ð0 �z‰z˜'Ó"€HÜ1;¸HÄdÔ1K�X—\‘\ *Ô-ÐQU€NØ&¨dÐ2ÒZ¼:ÀnÔVYÓ;ZÐ7Zò ^Ü�8œTÓ"ò 	]Ø�L‰L˜Ó$ò \Ø�|‰|˜GÓ$ò\Ø(0¯©°VÓ(<ò\äÓ[Ð>ZÔ[Ó[ð	 ô
 ÓaÐ*`ÔaÓa€HÙÑ,Øˆä�&‹\€FØ�J‰J�wÓ€EÜ% e¬TÔ2ŒD�ŒKÉe¸ÀEÑ8JÐY[€EØ€Fˆ7�Oð -ò 	9ˆØ�y‰y˜‹ˆÜ�dœDÕ!Ø ŸH™H WÓ-ÒD°·±¸)Ó1DˆMÜ" 4§8¡8¨JÓ#7Ò#=¸2Ó>×DÑDÓFÐÜ˜mÒ1¨rÓ2×8Ñ8Ó:ˆE�$‰KÚÜ"% e§i¡i°
Ó&;Ò&A¸rÓ"B×"HÑ"HÓ"J�Ù&¨/¸VÓ*CØ(8�E˜*Ò%ð	9ð :ò ˆØ—:‘:˜c“?ˆÙ˜EŸI™I cœNØ!ˆE�#‰JØ�
‰
�3˜Õð	ð ‡y�y�ÓÐ(Ü.¨u¯y©y¸Ó/DÓEˆˆjÑà—j‘j Ó,¨e¯i©i¸
Ó.CÐDò *ˆ	Ú˜UŸY™Y zÕ2Ø )ˆE�*Òð*ð ‡J�Jˆz˜4Ô Ø	‡I�Iˆj˜$Ôð �I‰I�gÓÒ3 %§)¡)¨FÓ"3€EØ�9‰9�YÔ¡EØ ˆˆiÑØ‡y�y�ÔØ�	‰	�'˜4Ô Ø�	‰	�&˜$Ôà€Mr-   c                 ó¦   — t        | «      } t        | j                  d«      xs i «      }d| v rd|vr| d   |d<   || d<   | j                  dd«       | S )z«Move legacy root-level ``max_turns`` under ``agent``; the schema default is injected only
    when the user set max_turns somewhere (so save_config can otherwise omit it).ÚagentÚ	max_turnsN)r¤  rS   rM  )r;  Úagent_configs     r.   Ú_normalize_max_turns_configrë  g  s_   € ô �&‹\€FÜ˜Ÿ
™
 7Ó+Ò1¨rÓ2€LØ�fÑ °LÑ!@Ø$*¨;Ñ$7ˆ�[Ñ!Ø"€Fˆ7�OØ
‡J�Jˆ{˜DÔ!Ø€Mr-   c                 ó*   — t        t        | «      «      S )zUThe load/save normalization pipeline: max_turns relocation, then model-section canon.)ræ  rë  r6  s    r.   Ú_canonicalize_configrí  s  s   € ä%Ô&AÀ&Ó&IÓJÐJr-   >	   õ   âˆžú-1Ú0ÚinfÚnoner{  ÚinfiniteÚinfinityÚ	unlimitedr†  c                 ó  — | �t        | t        «      r|S t        | t        t        f«      rt        | «      }nzt        | t        «      r=| j                  «       j                  «       }|s|S |t        v rt        S 	 t        |«      }n-t        j                  dt        | «      j                  | |«       |S |dk  rt        S |S # t        $ rC 	 t        t        |«      «      }n*# t        $ r t        j                  d| |«       |cY cY S w xY wY ŒXw xY w)zRNormalize a raw ``agent.max_turns`` value into an int iteration cap (always >= 1).u7   resolve_turn_limit: unparseable value %r â†’ default %du;   resolve_turn_limit: unsupported type %s (%r) â†’ default %dr   )r;   r  r<   ÚfloatrB   rC   r[  Ú_UNLIMITED_SPELLINGSÚTURN_LIMIT_UNLIMITEDrÕ   re   r–  r¦  r(   )r‹  r†  r*  Úss       r.   Úresolve_turn_limitrû  ‚  sû   € ð €{”j ¤dÔ+ØˆÜ�#œœU�|Ô$Ü�‹H‰Ü	�CœÔ	Ø�I‰I‹K×ÑÓˆÙØˆNØÔ$Ñ$Ü'Ð'ð	Ü�A“‰Aô 	�‰ÐRÔTXÐY\ÓT]×TfÑTfÐhkÐmtÔuØˆØ#$¨¢6ÔÐ0¨qÐ0øô ò 	ðÜœ˜a›“M‘øÜò Ü—‘ÐVÐX[Ð]dÔeØ”ðúñ ð	ús6   Á8B> Â>	D
ÃCÃD
Ã"DÃ?D
ÄDÄD
Ä	D
)r†  ró  c                óv   — t        | t        «      s|S | }|D ]  }t        |t        «      r||vr|c S ||   }Œ! |S )a  Traverse nested dict keys safely, returning ``default`` on any miss.
    Explicit ``None`` values are returned as-is (``dict.get`` semantics: ``default`` only when the
    key is absent). Named ``cfg_get`` to avoid shadowing the ubiquitous ``cfg_path`` local.)r;   r¤  )r–  r†  ró  r  rn   s        r.   r“  r“  ž  sL   € ô �cœ4Ô ØˆØ€DØò ˆÜ˜$¤Ô%¨°D©ØŠNØ�C‰y‰ðð €Kr-   Úpath_keyÚ	cache_keyc                 óp   — t         j                  | «      }|�|dt        |«       |k(  r|t        |«         S y)zôPure lookup: the cached raw config for ``path_key`` if its signature equals ``cache_key``,
    else ``None``. Shared by the lock-free fast path and the locked re-check of
    ``_read_raw_config_impl`` so the predicate cannot drift between them.N)rÛ   rS   r   )rý  rþ  Úcacheds      r.   Ú_raw_config_cache_hitr  ¬  s>   € ô ×"Ñ" 8Ó,€FØÐ˜f _¤c¨)£nÐ5¸ÒBØ”c˜)“nÑ%Ð%Ør-   Úwant_deepcopyc                 ó8  — 	 t        «       }t        |j                  «       «      }t        t	        |«      |«      }|�| rt        j                  |«      S |S 	 t        5  	 t        «       }|j                  «       }t        |«      }t	        |«      }t        ||«      }|�"| rt        j                  |«      n|cd d d «       S 	 t        |d¬«      5 }t        |«      xs i }d d d «       t        t        «      si }t        j                  |«      }	g |¢|	‘­t         |<   | r|n|	cd d d «       S # t        $ r Y ŒÝw xY w# t        t        f$ r i cY cd d d «       S w xY w# 1 sw Y   Œ|xY w# t        $ r!}t        ||«       i cY d }~cd d d «       S d }~ww xY w# 1 sw Y   y xY wrV  )rt   r#   ra   r  rB   rŽ  r�  rk   Ú_CONFIG_LOCKr—  rb   r•  r"   rq   r;   r¤  rÛ   )
r  rK   rþ  Úhitrl   rý  r™  r¨  r˜  Úcached_copys
             r.   Ú_read_raw_config_implr  ¶  s   € ðÜ%Ó'ˆÜ" ;×#3Ñ#3Ó#5Ó6ˆ	Ü#¤C¨Ó$4°iÓ@ˆØˆ?Ù)6”4—=‘= Ó%Ð?¸CÐ?ð ô
 
ñ 6ð	Ü)Ó+ˆKØ×!Ñ!Ó#ˆBÜ& rÓ*ˆIô �{Ó#ˆÜ# H¨iÓ8ˆØˆ?Ù)6”4—=‘= Ô%¸C÷6ñ 6ð	Ü�k¨GÔ4ð /¸Ü% aÓ(Ò.¨B�÷/ô ˜$¤Ô%ØˆDô —m‘m DÓ)ˆØ&?¨	Ð&?°;Ñ&?Ô˜(Ñ#Ù$‰t¨+÷56ñ 6øô ò Ùðûô "¤7Ð+ò 	Ø‰I÷6ñ 6ð
	ú÷/ð /ûäò 	Ü& {°AÔ6ØŒI÷%6ñ 6ûð 	ú÷!6ð 6ús�   ‚AD( ÁD( ÁFÁ%D7Â1FÂ?E#ÃEÃE#Ã$:FÄ(	D4Ä3D4Ä7EÅFÅEÅFÅE 	ÅE#Å#	FÅ,FÅ9FÅ:FÆFÆFÆFc                  ó   — t        d¬«      S )zÝRead config.yaml as-is (no defaults merged, no migration); ``{}`` if missing/unparseable.
    Cached on the file signature (mtime_ns, size, ino, ctime_ns); returns a deepcopy since callers mutate before ``save_config()``.T©r  ©r  r,   r-   r.   r`  r`  â  s   € ô !¨tÔ4Ð4r-   c                 óÈ   — | €
t        «       } 	 t        | d¬«      5 }t        |«      xs i }ddd«       t	        t
        «      r|S i S # 1 sw Y   ŒxY w# t        $ r i cY S w xY w)uä   Read a user ``config.yaml`` EXACTLY as written (no defaults/overlay/expansion, no cache).
    ONLY legal for write-back round-trips and raw-file diagnostics â€” behavioral reads must use
    load_config()/load_config_readonly().NrW  rX  )rt   r•  r"   r—  r;   r¤  )rK   r™  r¨  s      r.   r[  r[  è  sp   € ð ÐÜ%Ó'ˆðÜ�+¨Ô0ð 	+°AÜ! !Ó$Ò*¨ˆD÷	+ô ˜d¤DÔ)ˆ4Ð1¨rÐ1÷		+ð 	+ûäò ØŠ	ðús'   ŽA ›A«A ÁAÁA ÁA!Á A!c                  ó   — t        d¬«      S )a	  ``read_raw_config()`` without the per-call deepcopy, for callers that ONLY READ.
    **Mutating the result corrupts the in-process cache for every subsequent caller.** Meant for
    per-turn policy checks that were paying a full config deepcopy 2-3x per agent turn.Fr	  r
  r,   r-   r.   Úread_raw_config_readonlyr  ö  s   € ô !¨uÔ5Ð5r-   ÚreasonÚfixc                 óp   — t        |«      }|rd|› d�nd}t        d| › d|› |› d|› dt        |«      › �	«      S )z[Error for a write that must not replace an existing config.yaml. Plain lead + ``Details:``.ú (r¤  r9   rO   z) z , so this change was not saved. r£  )r>   ÚRuntimeErrorrG   )rK   r  r2   r  rN   rW   s         r.   Ú_refuse_overwriter  ý  sZ   € ä  Ó%€EÙˆ2ˆeˆW�A‰ R€BÜØ
˜{˜m¨2¨f¨X°b°TÐ9YÐZ]ÐY^ð _Ü'¨Ó,Ð-ð	/ó0ð 0r-   c                  ó"   — ddl m}   | «       › d�S )Nr   r,  z/backups/config/)rr  r-  r,  s    r.   Ú_backups_dir_displayr    s   € Ý4Ù!Ó#Ð$Ð$4Ð5Ð5r-   z0Fix the file permissions or move it aside first.z„Fix it with `hermes config edit` and check with `hermes config check`, or copy the newest good file from {backups} over config.yaml.c           
      óÖ  — | €
t        «       } 	 | j                  «        	 t        | d¬«      5 }t        |«      }ddd«       €i S t        |t        «      spt        d
t!        |«      j"                  › �«      }t        | |d¬«       t	        | dt!        |«      j"                  › �|t        j                  t        «       ¬	«      «      |‚|S # t        $ r i cY S t        $ r}t	        | d|t
        «      |‚d}~ww xY w# 1 sw Y   Œ¿xY w# t        $ r}t	        | d|t
        «      |‚d}~wt        $ r>}t        | |d¬«       t	        | d|t        j                  t        «       ¬	«      «      |‚d}~ww xY w)uÒ  Refuse to replace an existing config.yaml that cannot be read or parsed; return the mapping.
    Guards two collapse-to-empty failure modes that would let a read-then-write caller silently
    wipe user overrides: an unreadable file (permissions / broken mount) and an unparseable or
    non-mapping root â€” bare-``except`` loaders treat both as ``{}``, so a subsequent write would
    replace the recoverable file with only the caller's partial dict. Fails closed.Nzcannot be accessedrW  rX  zcannot be readr1   rI   zhas a formatting error)Úbackupsz&top-level YAML must be a mapping, got z7must start with settings names, but its top level is a )rt   ra   r—  rb   r  Ú
_FIX_PERMSr•  r"   rk   rq   Ú	_FIX_YAMLrV   r  r;   r¤  r¥  r¦  r(   )rK   r2   r™  Úloadeds       r.   Ú$require_readable_config_before_writer    s  € ð ÐÜ%Ó'ˆð]Ø×ÑÔðsÜ�+¨Ô0ð 	'°AÜ# AÓ&ˆF÷	'ð €~Øˆ	Ü�fœdÔ#ÜÐ@ÄÀfÃ×AVÑAVÐ@WÐXÓYˆÜ" ;°¸nÕMÜØÐRÔSWÐX^ÓS_×ShÑShÐRiÐjØ”×!Ñ!Ô*>Ó*@Ð!ÓAóCàHKð	Lð €Møô- ò ØŠ	Üò ]Ü Ð-AÀ3Ì
ÓSÐY\Ð\ûð]ú÷	'ð 	'ûäò YÜ Ð-=¸sÄJÓOÐUXÐXûÜò sÜ" ;°¸nÕMÜØÐ1°3¼	×8HÑ8HÔQeÓQgÐ8HÓ8hójØorð	sûðsúsV   ŽC ŸD ¬C6¸D ÃC3ÃC3ÃC.Ã.C3Ã6C?Ã;D Ä	E(ÄDÄE(Ä*9E#Å#E(©Úextra_content_on_creater¨  r  c                ó&   — ddl m}  || ||¬«       y)uÍ  THE ``config.yaml`` writer: fail-closed (``require_readable_config_before_write``) and
    comment-preserving (ruamel round-trip merge of *data* onto the on-disk document). Every code
    path that persists a config.yaml â€” ``save_config``, ``config set``, migrations, plugin
    bookkeeping, gateway/TUI RPCs, auth resets â€” goes through here; a PyYAML dump of a config
    path anywhere else is rejected by ``scripts/check_config_yaml_writers.py`` (#92554).r   )Úatomic_roundtrip_yaml_saver  N)Úutilsr  )rK   r¨  r  r  s       r.   Úatomic_config_writer!  4  s   € õ 1á˜{¨DÐJaÖbr-   c                  ó   — t        d¬«      S )a  Load the merged configuration (DEFAULT_CONFIG + config.yaml + managed scope, env-expanded).
    Cached on the file signature; returns a deepcopy since most call sites mutate the result.
    Read-only hot paths should use ``load_config_readonly()`` to skip the deepcopy.Tr	  ©Ú_load_config_implr,   r-   r.   r�  r�  ?  s   € ô ¨4Ô0Ð0r-   c                  ó   — t        d¬«      S )u  ``load_config()`` without the defensive deepcopy (~half of the 265us cache-hit cost).
    **Mutating the returned dict (or any nested structure) corrupts the in-process cache for
    every subsequent caller** â€” only for code paths that never write to the result.Fr	  r#  r,   r-   r.   Úload_config_readonlyr&  F  s   € ô ¨5Ô1Ð1r-   r²  c                 óV   — | j                  |«      }t        |t        «      si }|| |<   |S )zTReturn ``parent[key]`` as a dict, replacing a missing or non-dict value with ``{}``.)rS   r;   r¤  )r²  rn   rÇ  s      r.   Ú_ensure_dictr(  M  s,   € à�J‰J�s‹O€EÜ�eœTÔ"ØˆØˆˆs‰Ø€Lr-   )r‹  Úplatform_keyÚ	field_keyc                ó|   — |r
t        «       n	t        «       }t        |d«      }|t        || «      |<   t        |«       y)zîPersist one scalar field under ``platforms.<platform_key>``.
    ``raw=True`` (CLI setup flows) edits only the user's raw file; dashboard routes use the
    default loaded-config path to keep their profile-scoped ``load_config`` behavior.r«  N)r`  r�  r(  r5  )r)  r*  r›  r‹  r;  r«  s         r.   Úwrite_platform_config_fieldr,  V  s7   € ñ
 #&Œ_Ô¬;«=€FÜ˜V [Ó1€IØ7<„L�˜LÓ)¨)Ñ4Ü�Õr-   rŽ  rã   )!Ú
modal_modeÚdegraded_modeÚcwdÚtemp_dirÚtimeoutÚlifetime_secondsÚdocker_imageÚdocker_forward_envÚsingularity_imageÚmodal_imageÚdaytona_imageÚvercel_runtimeÚssh_hostÚssh_userÚssh_portÚssh_keyÚcontainer_cpuÚcontainer_memoryÚcontainer_diskÚcontainer_persistentÚdocker_volumesÚ
docker_envÚdocker_mount_cwd_to_workspaceÚdocker_networkÚdocker_extra_argsÚdocker_shm_sizeÚdocker_run_as_host_userÚdocker_snap_compatÚdocker_persist_across_processesÚdocker_shared_container_keyÚdocker_orphan_reaperÚsandbox_dirÚpersistent_shellÚ	TERMINAL_c                 ón   — t        | t        t        f«      rt        j                  | «      S t        | «      S r3  )r;   r9  r¤  r}  r~  rB   ©r›  s    r.   Ú_terminal_env_valuerQ  r  s'   € Ü *¨5´4¼°,Ô ?Œ4�:‰:�eÓÐOÄSÈÃZÐOr-   c                 óP   — | dk(  xr t        |xs d«      j                  «       dv  S )zAReturn whether a terminal config value owns its mirrored env var.r/  r9   >   r/  rÛ  r_   )rB   rC   )rn   r›  s     r.   Ú$_terminal_config_value_is_bridgeablerS  v  s,   € à�u‘ÒQ¤ U¢[¨bÓ!1×!7Ñ!7Ó!9Ð=QÐ!QÐRÐRr-   Úterminal_configc           	      ó¶   — t        | t        «      s
t        «       S t        j	                  «       D ��ch c]  \  }}|| v rt        || |   «      r|’Œ c}}S c c}}w )zFReturn env vars explicitly owned by a raw ``terminal`` config section.)r;   r¤  rò  ÚTERMINAL_CONFIG_ENV_MAPr  rS  )rT  rn   Úenv_vars      r.   Úterminal_config_owned_env_varsrX  {  s]   € ä�o¤tÔ,Ü‹uˆô 4×9Ñ9Ó;÷MáˆC�Ø�/Ñ!Ü0°°oÀcÑ6JÔKò 	óMð Mùó Ms   ²Ac                 ój   — | j                  d«      r!t        j                  | t        d«      d «      S dS )z;Return the env var mirrored by a ``terminal.*`` config key.z	terminal.N)rÖ   rV  rS   r   ©rn   s    r.   Úterminal_config_env_var_for_keyr[  †  s3   € àBEÇ.Á.ÐQ\ÔB]Ô"×&Ñ& s¬3¨{Ó+;Ð+<Ð'=Ó>ÐgÐcgÐgr-   r/  c                 ó€   — | xs dj                  «       j                  «       dk(  xr |dk(  xs |j                  d«      S )zšWhether the remote SSH shell must expand *cwd* itself: ``~`` expanded on the Hermes host
    would name the host/container home instead of the SSH user's.r9   ÚsshÚ~z~/)rC   r[  rÖ   )rŽ  r/  s     r.   Ú_is_ssh_remote_tilde_cwdr_  ‹  s=   € ð ŠM�r× Ñ Ó"×(Ñ(Ó*¨eÑ3Ò\¸À¹Ò9[ÀsÇ~Á~ÐVZÓG[Ð\r-   )Úenvr;  rŒ  r`  c                 óH  — | €t         j                  n| }t        «       j                  d«      }t	        |t
        «      }|r|ni }|€|n|}|�|n	t        «       }t	        |t
        «      r|j                  di «      ni }t	        |t
        «      s|S |�|j                  «       n|j                  «       }	|j                  d«      |j                  d«      f}
|€d|v s|
ddd…   }
t        |
d   xs	 |
d   xs d«      }t        j                  «       D ]’  \  }}||vrŒ||   }t        ||«      sŒ|d	k(  rXt        |xs d«      j                  «       }t	        |t        «      r+t        ||«      st         j                  j                  |«      }|r||	v s||vsŒ…t!        |«      ||<   Œ” |S )
aª  Bridge ``terminal.*`` config into the env vars terminal tools read.
    ``tools.terminal_tool`` is environment-driven because it also runs in child processes (TUI,
    dashboard PTY, gateway workers); this gives those launch paths the same bridge as the CLI
    without importing ``cli.py``. Explicit keys in the user's raw ``terminal`` section override
    matching env values; merged defaults only backfill missing env vars.NÚterminalrŽ  rã   r,  r   r8   r9   r/  )r“  r”  r`  rS   r;   r¤  r&  ró  rB   rV  r  rS  rC   r_  ru   Ú
expanduserrQ  )r`  r;  rŒ  ÚtargetÚraw_terminal_cfgÚfile_has_terminal_configÚshould_overrider–  Úterminal_cfgÚexplicit_keysÚbackend_sourcesÚterminal_backendÚcfg_keyrW  r›  Úraw_cwds                   r.   Úapply_terminal_config_to_envrn  ‘  s¯  € ð ˜;ŒR�ZŠZ¨C€Fä&Ó(×,Ñ,¨ZÓ8ÐÜ)Ð*:¼DÓAÐÙ+CÑ'ÈÐØ2:Ð2BÑ.È€OàÐ&‰&Ô,@Ó,B€CÜ.8¸¼dÔ.C�3—7‘7˜: rÔ*È€LÜ�l¤DÔ)Øˆð ,2Ð+=�L×%Ñ%Ô'ÐCS×CXÑCXÓCZ€MØ#×'Ñ'¨	Ó2°F·J±J¸~Ó4NÐO€OØÐ )Ð/?Ñ"?Ø)©$¨B¨$Ñ/ˆÜ˜?¨1Ñ-ÒI°ÀÑ1CÒIÀrÓJÐä3×9Ñ9Ó;ò 9Ñˆ�Ø˜,Ñ&ØØ˜WÑ%ˆÜ3°G¸UÔCØØ�eÒÜ˜%š+ 2Ó&×,Ñ,Ó.ˆGÜ˜%¤Ô%Ô.FÐGWÐY`Ô.aÜŸ™×*Ñ*¨5Ó1�Ù ¨=Ñ 8¸WÈFÒ=RÜ1°%Ó8ˆF�7ŠOð9ð €Mr-   c                 ó  — 	 | j                  «       }t        |«      }t        j                  «       }	 |r|dz  j                  «       nd}|rt        |«      nd}|€|dk(  ry|g |xs d¢|¢­fS # t        $ r d}Y Œ]w xY w# t
        $ r d}Y Œ3w xY w)a  Return ``(user_sig, cache_sig)`` for ``_LOAD_CONFIG_CACHE``.
    The managed config file's signature is folded in ((0, 0, 0, 0) = none) so editing it invalidates
    the merged result. ``cache_sig`` is None only when neither file exists (nothing to cache on).Nrž  )r   r   r   r   )NN)ra   r#   r—  r   Úget_managed_dirrb   )rK   rl   Úuser_sigÚmanaged_dirÚmstÚmanaged_sigs         r.   Ú_load_config_cache_sigru  ¼  s±   € ðØ×ÑÓˆÜ8FÀrÓ8Jˆô  ×/Ñ/Ó1€Kð#Ù6Aˆ{˜]Ñ*×0Ñ0Ô2ÀtˆÙ-0”n SÔ)°lˆð Ð˜K¨<Ò7ØØÐ@˜Ò0 LÐ@°KÑ@Ð@Ð@øô ò ØŠðûô ò #Ø"Šð#ús"   ‚A- ²&A> Á-A;Á:A;Á>BÂBc                 óp  — t         j                  |«      }d}|€Wddlm}  || «      }|�Gt	        t        t        j                  t        «      |«      «      }t        |«      }	t        |	«      \  }}
d}t        | ||�|nd¬«       |€yt        t        j                  |«      «      }|�g |¢|‘i ‘­t        |<   |S )uv  Warn about a parse failure and return the last-known-good config, or None (-> defaults).
    A parse failure must not silently replace the effective config with defaults â€” that drops
    EVERY user override, including security-critical ``approvals.deny`` rules, when a gateway
    user mid-edits config.yaml into broken YAML. Keep serving the last good config until fixed.r/   Nr   )Úload_newest_good_backupr0   rH   rI   )rÙ   rS   rd   rw  rí  r�  rŽ  r�  rÞ  r´  Ú_merge_managed_overlayrq   rÚ   )rK   rý  Ú	cache_sigr2   ÚlkgrJ   rw  Úraw_goodrÞ  Úexpanded_goodrš  Úlkg_copys               r.   Ú_last_known_good_fallbackr~  Ð  sÇ   € ô (×
+Ñ
+¨HÓ
5€CØ €HØ
€{õ
 	FÙ*¨;Ó7ˆØÐÜ-¬k¼$¿-¹-ÌÓ:WÐYaÓ.bÓcˆJÜ,<¸ZÓ,HˆMÜ+¨MÓ:‰FˆC�Ø/ˆHÜØ�S¨s¨¡8ÀJõPà
€{Øô  0´·±¸cÓ0BÓC€HØÐð (B¨Ð'A°HÐ'A¸bÑ'AÔ˜8Ñ$Ø€Or-   Úexpandedc                 óâ   — t        j                  «       }|s| |fS t        |«      }t        |j	                  d«      t
        «      rt        |«      }d|d   i|d<   t        | t        |«      «      |fS )u—  Apply the managed-scope overlay; returns ``(merged, managed_config_or_falsy)``.
    Managed wins at the leaf and is applied AFTER user expansion so a user ``${VAR}`` cannot shadow
    a managed literal: managed values expand only against the process environment. This
    deliberately inverts the usual env-over-config precedence for the keys the managed layer pins
    (docs/design/managed-scope.md Â§4.1).rÀ  r†  )	r   Úload_managed_configræ  r;   rS   rB   r¤  r�  r´  )r  Úmanaged_configÚmanaged_normalizeds      r.   rx  rx  õ  s~   € ô #×6Ñ6Ó8€NÙØ˜Ð'Ð'ô 4°NÓCÐÜÐ$×(Ñ(¨Ó1´3Ô7Ü!Ð"4Ó5ÐØ'0Ð2DÀWÑ2MÐ&NÐ˜7Ñ#Ü�xÔ!1Ð2DÓ!EÓFÈÐVÐVr-   ry  c                 ó¼   — t         j                  | «      }|�
|�|dd |k7  ryt        |«      dkD  r|d   ni }t        d„ |j	                  «       D «       «      r|d   S y)aÉ  Pure lookup: the cached expanded config for ``path_key`` if its signature equals
    ``cache_sig`` AND every ``${VAR}`` it was expanded against still has the same value, else
    ``None``. Signatures matching is not enough: a load before load_hermes_dotenv() would otherwise
    pin unexpanded literals (e.g. auxiliary.<task>.api_key) for the process lifetime (#58514).
    Shared by the lock-free fast path and the locked re-check of ``_load_config_impl``.Né   é	   c              3   ó>   K  — | ]  \  }}t        |«      |k(  –— Œ y ­wr3  )r¢  ©r)  r4  rš  s      r.   r+  z)_load_config_cache_hit.<locals>.<genexpr>	  s   è ø€ Ò
D¡t q¨!Œ?˜1Ó Õ"Ñ
Dùs   ‚)rÚ   rS   r   Úallr  )rý  ry  r   Úenv_snapshots       r.   Ú_load_config_cache_hitr‹  	  sg   € ô  ×#Ñ# HÓ-€FØ€~˜Ð*¨f°R°a¨j¸IÒ.EØÜ # F£¨a¢�6˜!’9°R€LÜ
Ñ
D¨|×/AÑ/AÓ/CÔ
DÔDØ�a‰yÐØr-   c                 ó  — 	 t        «       }t        |«      }|t        v r5t        |«      \  }}t	        ||«      }|�| rt        j                  |«      S |S t        5  t        «        t        «       }t        |«      }t        |«      \  }}t	        ||«      }|�"| rt        j                  |«      n|cd d d «       S t        j                  t        «      }|�“	 t        |d¬«      5 }	t        |	«      xs i }
d d d «       d
v rNt        |
j                  d«      xs i «      }|j                  d«      €|
d   |d<   ||
d<   |
j                  dd «       t!        ||
«      }ddlm}  ||d«       t)        |«      }t+        t-        |«      «      \  }}t        j                  |«      t.        |<   |�Kt        j                  |«      }t1        |«      }|rt1        ||«       g |¢|‘|‘­t        |<   | s!|cd d d «       S t        j                  |d «       |cd d d «       S # t        $ r Y �ŒÊw xY w# 1 sw Y   �Œ3xY w# t        $ rB}t'        ||||«      }|�'| rt        j                  |«      n|cY d }~cd d d «       S Y d }~�Œd }~ww xY w# 1 sw Y   y xY w)NrW  rX  ré  rè  r   r\   Úgood)rt   rB   rÚ   ru  r‹  rŽ  r�  rk   r  rÝ  rÞ  r•  r"   r¤  rS   rM  r�  rd   r]   r~  rí  rx  r´  rÙ   r¸  )r  rK   rý  rš  Úfast_sigr  rq  ry  r;  r™  Úuser_configÚagent_user_configr]   r˜  r}  rÞ  r  r‚  r  rŠ  s                       r.   r$  r$  	  s”  € ð
Ü%Ó'ˆÜ�{Ó#ˆØÔ)Ñ)Ü0°Ó=‰KˆAˆxÜ(¨°8Ó<ˆCØˆÙ-:”t—}‘} SÓ)ÐCÀÐCô 
ñ 6ÜÔÜ%Ó'ˆÜ�{Ó#ˆä4°[ÓAÑˆ�)ä$ X¨yÓ9ˆØˆ?Ù)6”4—=‘= Ô%¸C÷6ñ 6ô —‘œ~Ó.ˆàÐðRÜ˜+°Ô8ð :¸AÜ"0°Ó"3Ò"9°r�K÷:ð  +Ñ-Ü(,¨[¯_©_¸WÓ-EÒ-KÈÓ(LÐ%Ø(×,Ñ,¨[Ó9ÐAØ9DÀ[Ñ9QÐ)¨+Ñ6Ø+<�K Ñ(Ø—O‘O K°Ô6ä$ V¨[Ó9�õ DÙ˜k¨6Ô2ô *¨&Ó1ˆ
Ü#9Ô:JÈ:Ó:VÓ#WÑ ˆ�.Ü26·-±-ÀÓ2IÔ% hÑ/ØÐ ô Ÿ-™-¨Ó1ˆKÜ,¨ZÓ8ˆLÙÜ! .°,Ô?Ø+R¨YÐ+R¸Ð+RÀ\Ñ+RÔ˜xÑ(á Ø"÷e6ñ 6ôh ×"Ñ" 8¨TÔ2à÷m6ñ 6øô ò ò 	ðú÷(:ñ :ûô  ò RÜ4°[À(ÈIÐWXÓY�ØÐ'Ù6Cœ4Ÿ=™=¨Ô2ÈÔQ÷E6ñ 6õB (ûðRú÷?6ð 6ús�   ‚AH ÁH ÁAI=Â8I=ÃH/Ã!H"Ã1A5H/Å&BI=Ç1I=È	HÈHÈ"H,	È'H/È/	I:È8(I5É I:É!I=É/I=É5I:É:I=É=Ju-  
# â”€â”€ Security â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
# Secret redaction is ON by default â€” strings that look like API keys,
# tokens, and passwords are masked in tool output, logs, and chat
# responses before the model or user ever sees them. Set redact_secrets
# to false to disable (e.g. when developing the redactor itself).
# tirith pre-exec scanning is enabled by default when the tirith binary
# is available. Configure via security.tirith_* keys or env vars
# (TIRITH_ENABLED, TIRITH_BIN, TIRITH_TIMEOUT, TIRITH_FAIL_OPEN).
#
# security:
#   redact_secrets: true
#   tirith_enabled: true
#   tirith_path: "tirith"
#   tirith_timeout: 5
#   tirith_fail_open: true
u@  
# â”€â”€ Fallback Model â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
# Automatic provider failover when primary is unavailable.
# Uncomment and configure to enable. Triggers on rate limits (429),
# overload (529), service errors (503), or connection failures.
#
# Supported providers:
#   openrouter   (OPENROUTER_API_KEY)  â€” routes to any model
#   openai-codex (OAuth â€” hermes auth) â€” OpenAI Codex
#   nous         (OAuth â€” hermes auth) â€” Nous Portal
#   zai          (ZAI_API_KEY)         â€” Z.AI / GLM
#   kimi-coding  (KIMI_API_KEY)        â€” Kimi / Moonshot
#   kimi-coding-cn (KIMI_CN_API_KEY)   â€” Kimi / Moonshot (China)
#   minimax      (MINIMAX_API_KEY)     â€” MiniMax
#   minimax-cn   (MINIMAX_CN_API_KEY)  â€” MiniMax (China)
#   bedrock      (AWS IAM / boto3)     â€” AWS Bedrock (Converse API)
#
# For custom OpenAI-compatible endpoints, add base_url and key_env.
#
# fallback_model:
#   provider: openrouter
#   model: anthropic/claude-sonnet-4
c           
      ó  — t        j                  «       }|s| S t        t        j                  | «      |«      \  } }|rBt        dt        |«      › ddj                  t        |«      «      › �t        j                  ¬«       | S )zŠDrop every leaf the managed layer pins (bulk safety net; single-key ``config set``
    hard-rejects) and tell the user what was not saved.zNote: zD managed setting(s) were not saved (managed by your administrator): ú, r„  )r   Úmanaged_config_keysrœ  rŽ  r�  r†  r   rD   rõ  rg   rh   )r;  Úmanaged_keysÚ	_strippeds      r.   Ú_strip_managed_keys_for_saver–  Œ	  s{   € ô !×4Ñ4Ó6€LÙØˆÜ*¬4¯=©=¸Ó+@À,ÓOÑ€FˆIÙÜØ”S˜“^Ð$ð %0Ø04·	±	¼&ÀÓ:KÓ0LÐ/MðOÜUX×U_ÑU_õ	að €Mr-   rÞ  c                 ó>  — g }| j                  d«      xs i j                  d«      €|j                  t        «       | j                  di «      }t        |t        «      r|n|g}t        d„ |D «       «      s|j                  t        «       dj                  |«      xs dS )zDCommented-out example blocks for features that are off/unconfigured.ÚsecurityÚredact_secretsNr®  c              3   óˆ   K  — | ]:  }t        |t        «      xr$ |j                  d «      xr |j                  d«      –— Œ< y­w)r×  rÀ  N)r;   r¤  rS   )r)  r˜  s     r.   r+  z/_commented_sections_for_save.<locals>.<genexpr>¡	  s6   è ø€ Ò`ÐPQŒz˜!œTÓ"ÒK q§u¡u¨ZÓ'8ÒK¸Q¿U¹UÀ7»^ÓKÑ`ùs   ‚A Ar9   )rS   r  Ú_SECURITY_COMMENTr;   r9  rÜ  Ú_FALLBACK_COMMENTrD   )rÞ  r!  rù  Ú
fb_entriess       r.   Ú_commented_sections_for_saverž  š	  s†   € à€EØ�‰�zÓ"Ò( b×-Ñ-Ð.>Ó?ÐGØ�‰Ô&Ô'Ø	�‰Ð(¨"Ó	-€BÜ! "¤dÔ+‘°"°€JÜÑ`ÐU_Ô`Ô`Ø�‰Ô&Ô'Ø�7‰7�5‹>Ò!˜TÐ!r-   )Ústrip_defaultsrÌ  Úmerge_existingrŸ  r   c          
      ó˜  — t         5  t        «       rt        d«       	 ddd«       yt        | «      } t	        «        t        «       }t        |«      }|r|rt        || «      } t        | «      }|}|r2t        |t        |«      t        j                  t        |«      «      «      }|r-t        |«      t        |xs d«      z  }t        |t         |¬«      }t#        ||t%        |«      ¬«       t'        |«       t(        j+                  t        |«      d«       t-        j.                  |«      t        t        |«      <   ddd«       y# 1 sw Y   yxY w)a�  Save configuration to ~/.hermes/config.yaml.
    Schema defaults are not written unless the user explicitly set them (the path exists in the
    raw config before normalisation), so config.yaml is never contaminated with defaults that
    would hide future default changes. ``merge_existing`` deep-merges the on-disk raw config
    under *config* so partial callers cannot drop sections they omitted.zsave configurationNr,   )rÌ  r  )r  rK  r‡  r–  rÝ  rt   r  r’  rí  r¿  rÙ   rS   rB   rË  rò  rÑ  rÞ  r!  rž  rº  rÛ   rM  rŽ  r�  )	r;  rŸ  rÌ  r   rK   Ú_raw_for_pathsÚcurrent_normalizedrÞ  Úeffective_preserve_keyss	            r.   r5  r5  ¦	  s+  € ô 
ñ !\ÜŒ<ÜÐ.Ô/Ø÷!\ð !\ô
 .¨fÓ5ˆäÔÜ%Ó'ˆô >¸kÓJˆÙ™nÜ(¨¸Ó@ˆFä1°&Ó9ÐØ'ˆ
ÙÜ4ØÔ0°Ó@Ü-×1Ñ1´#°kÓ2BÓCóEˆJñ ä&<¸^Ó&LÌsÐS`ÒSfÐdfÓOgÑ&gÐ#Ü.¨z¼>ÐYpÔqˆJä˜K¨ÔMiÐjtÓMuÕvÜ�[Ô!Ü×Ñœc +Ó.°Ô5Ü:>¿-¹-ÐHZÓ:[Ô%¤c¨+Ó&6Ñ7÷C!\÷ !\ñ !\ús   ‡E §DE Å E	c                  ó.   — ddl m}   | t        «       «      S )zÑLoad ~/.hermes/.env as a dict. Memoised inside ``load_env_file`` (``get_env_value()`` runs
    hundreds of times per interactive menu render). Each assignment's value is opaque data for
    boundary discovery.r   ©Úload_env_file)r   r§  r®  r¦  s    r.   r.  r.  Ò	  s   € õ 1áœ›Ó(Ð(r-   c                  ó   — ddl m}   | «        y)z¦Drop the ``.env`` memo so the next ``load_env()`` sees a write even on coarse-mtime filesystems
    (save_env_value / remove_env_value / sanitize_env_file call this).r   ©Úinvalidate_env_file_cacheN)r   rª  r©  s    r.   Úinvalidate_env_cacher«  Û	  s   € õ =áÕr-   r%  c                 ó¬   — g }| D ]L  }|j                  d«      }|j                  «       }|j                  |r|j                  d«      r|n|dz   «       ŒN |S )a  Normalize .env line endings/whitespace without changing assignment semantics.
    Content after the first ``=`` is opaque value data: a known variable name embedded in a value
    must never be reinterpreted as another assignment, so concatenated lines stay on one line.z
r�  r`   )r‚  rC   r  rÖ   )r%  Ú	sanitizedr7   r‹  r™  s        r.   Ú_sanitize_env_linesr®  ã	  s`   € ð €IØò aˆØ�k‰k˜&Ó!ˆØ—9‘9“;ˆà×Ñ¡X°×1DÑ1DÀSÔ1I™#ÈxÐ[_Ñ_Õ`ð	að
 Ðr-   c                  óp  — t        «       } | j                  «       syt        | dd¬«      5 }|j                  «       }ddd«       t	        «      }||k(  ryt        t        |«      t        |«      z
  «      xs t        d„ t        ||«      D «       «      }t        | |d¬«       t        «        |S # 1 sw Y   ŒrxY w)	z\Rewrite ~/.hermes/.env with normalized line formatting; returns the number of changed lines.r   ú	utf-8-sigre  ©rY  ÚerrorsNc              3   ó2   K  — | ]  \  }}||k7  sŒd –— Œ y­w)r8   Nr,   )r)  ÚaÚbs      r.   r+  z$sanitize_env_file.<locals>.<genexpr>ú	  s!   è ø€ ò =@Ùˆa�¸¸Q»Œñ=@ùs   ‚�F©Úpreserve_mode)r®  r·  r•  Ú	readlinesr®  Úabsr   ÚsumÚzipÚ_write_env_linesr«  )Úenv_pathr™  Úoriginal_linesr­  rd  s        r.   rY  rY  ð	  s¬   € ä‹~€HØ�?‰?ÔØÜ	ˆh °YÔ	?ð 'À1ØŸ™›ˆ÷'ä# NÓ3€IØ�NÒ"ØÜ”�I“¤ ^Ó!4Ñ4Ó5ò @¼ñ =@Ü˜.¨)Ó4ô=@ó :@€Eä�X˜y¸Õ>ÜÔØ€L÷'ð 'ús   ªB,Â,B5r½  c                 ó|   — t        | dd¬«      5 }t        |j                  «       «      cddd«       S # 1 sw Y   yxY w)zwRead ``.env`` lines, normalized. Explicit UTF-8 (Windows defaults to cp1252) with BOM
    tolerance (Notepad adds one).r°  re  r±  N)r•  r®  r¸  )r½  r™  s     r.   Ú_read_env_linesrÀ  
  s5   € ô 
ˆh °YÔ	?ð 2À1Ü" 1§;¡;£=Ó1÷2÷ 2ò 2ús   �2²;r·  c                ó°  — d}	 |r-t        j                  | j                  «       j                  «      nd}t	        j
                  t        | j                  «      dd¬«      \  }}	 t        j                  |dd¬«      5 }|j                  |«       |j                  «        t        j                  |j                  «       «       ddd«       t        || «       |�	 t        j"                  | |«       yt%        | «       y# t        $ r Y ŒÑw xY w# 1 sw Y   ŒJxY w# t        $ r' 	 t        j                   |«       ‚ # t        $ r Y ‚ w xY ww xY w# t        $ r Y yw xY w)zçAtomically replace ``.env`` (tmp file + fsync + rename).
    ``preserve_mode`` keeps the original file mode (e.g. 0640 for Docker volume mounts) instead of
    letting ``_secure_file`` tighten to 0600; a new file is always secured.Nz.tmpz.env_)r¿  r¾  r½  rÀ  rW  rX  )ra   ÚS_IMODEÚst_moderb   rÄ  rÅ  rB   r²  r“  rÆ  Ú
writelinesrj   ÚfsyncÚfilenor!   ÚBaseExceptionrÇ  r¸  rº  )r½  r%  r·  Úoriginal_moderÊ  Útmp_pathr™  s          r.   r¼  r¼  
  s9  € ð €MðÙANœŸ™ X§]¡]£_×%<Ñ%<Ô=ÐTXˆô ×#Ñ#¬¨H¯O©OÓ(<ÀVÐT[Ô\�L€BˆðÜ�Y‰Y�r˜3¨Ô1ð 	!°QØ�L‰L˜ÔØ�G‰GŒIÜ�H‰H�Q—X‘X“ZÔ ÷	!ô 	�x Ô*ð Ð ð	Ü�H‰H�X˜}Õ-ô 	�XÕøô+ ò Ùðú÷	!ð 	!ûô
 ò ð	Ü�I‰I�hÔð 	øô ò 	ØØð	úðûô ò 	Ùð	úsl   „1C; Á$D Á<AD
ÃD ÃE	 Ã;	DÄDÄ
DÄD Ä	EÄ D6Ä5EÄ6	EÄ?EÅEÅEÅ		EÅEc                 óœ  — |j                  «       r|S t        |«      D ��cg c]*  \  }}t        |«      dkD  sŒd|› d|›dt        |«      d›d�‘Œ, }}}|j                  dd¬	«      j	                  d«      }t        d
| › d�dj                  d„ |dd D «       «      z   t        |«      dkD  rdndz   dz   t        j                  ¬«       |S c c}}w )z±Strip non-ASCII characters from a credential (HTTP header values must be ASCII) and warn.
    Lookalike glyphs typically come from copy-pasting out of a PDF or rich-text editor.é   z  position rS  z (U+Ú04Xr¤  ÚasciiÚignore)r²  z
  Warning: zÐ contains non-ASCII characters that will break API requests.
  This usually happens when copy-pasting from a PDF, rich-text editor,
  or web page that substitutes lookalike Unicode glyphs for ASCII letters.

r`   c              3   ó&   K  — | ]	  }d |› �–— Œ y­w)r#  Nr,   )r)  r7   s     r.   r+  z._check_non_ascii_credential.<locals>.<genexpr>4
  s   è ø€ Ò: D�b˜˜”KÑ:ùrX  Nr  z
  ... and morer9   z‰

  The non-ASCII characters have been stripped automatically.
  If authentication fails, re-copy the key from the provider's dashboard.
r„  )
Úisasciirì  ÚordÚencodeÚdecoder†  rD   r   rg   rh   )rn   r›  r#  r$  Ú	bad_charsr­  s         r.   Ú_check_non_ascii_credentialrÕ  '
  së   € ð ‡}�}„ØˆäJSÐTYÓJZ×lÁÀÀBÔ^aÐbdÓ^eÐhkÓ^k�;˜q˜c  B 6¨¬c°"«g°c¨]¸!Ò<Ðl€IÑlØ—‘˜W¨X�Ó6×=Ñ=¸gÓF€Iä	Ø
˜�uð Yð 	Zð �)‰)Ñ:¨I°b°q¨MÔ:Ó
:ñ	;ô "% Y£°!Ò!3Ñ¸ñ		=ð
Vñ	Vô �Z‰Zõð Ðùó ms
   ¡C¸Cc                 ó    — | dk(  r| S d| v sd| v sd| v st        d„ | D «       «      s| S | j                  dd«      j                  dd«      }d|› d�S )	z´Quote .env values containing characters with special dotenv meaning. Any whitespace
    (including internal runs) is quoted so ``set -a; . file`` word-splitting keeps paths intact.r9   r�  ú"rm  c              3   ó<   K  — | ]  }|j                  «       –— Œ y ­wr3  )Úisspace)r)  Úcs     r.   r+  z#_quote_env_value.<locals>.<genexpr>A
  s   è ø€ Ò?[ÐPQÀÇ	Á	ÇÑ?[ùs   ‚r  z\\z\")rÜ  re  )r›  r@  s     r.   Ú_quote_env_valuerÛ  <
  sa   € ð �‚{ØˆØ�5‰L˜C 5™L¨C°5©L¼CÑ?[ÐUZÔ?[Ô<[ØˆØ�m‰m˜D &Ó)×1Ñ1°#°uÓ=€GØˆwˆi�qˆ>Ðr-   r7   c                óì   — | j                  «       }|j                  d«      r|dd j                  «       }|j                  d«      \  }}}|syt	        |j                  «       |¬«      t	        ||¬«      k(  S )u§  True when a .env line assigns ``key`` â€” plain, ``export``-prefixed, or ``KEY = value``.
    Must match exactly the shapes ``load_env()`` parses; otherwise a hand-added line is invisible
    to save (duplicate appended) and remove (line survives -> the value resurrects on next load).

    ``load_env()`` accepts the bash-compatible ``export KEY=value`` form (#6659), so the writers must
    recognise the same shape.
    zexport é   NrŒ  FrÊ   )rC   rÖ   Úlstripr–  rÐ   )r7   rn   rË   r™  Úassigned_keyÚ	separatorÚ_values          r.   Ú_env_line_defines_keyrâ  G
  sz   € ð �z‰z‹|€HØ×Ñ˜9Ô%Ø˜A˜B�<×&Ñ&Ó(ˆØ&.×&8Ñ&8¸Ó&=Ñ#€L�)˜VÙØô  Ø×ÑÓ¨ôä	˜c¨jÔ	9ñ:ð :r-   c                 ó,  — 	 ddl m}m}  |«        |«       }}t	        |t
        «      r|gng }|s1|�t	        |t
        «      r|j                  t        j                  «       |D ]  }|€|j                  | d«       Œ||| <   Œ y# t        $ r d\  }}Y Œzw xY w)a?  Publish a just-persisted ``.env`` change to the live process.
    Under a multiplexed gateway a routed profile's write must not land in the SHARED
    ``os.environ`` where every profile sees it; the installed scope mapping is updated instead so
    same-turn reads see the change. All other callers keep the legacy ``os.environ`` publish.

    ``save_env_value`` / ``remove_env_value`` already target the right file (``get_env_path()`` honors the
    profile-home override), but the in-process mirror historically went straight to ``os.environ``. See
    #77490, #88441.
    r   )rž  Úserves_routed_profile)NFN)
r   rž  rä  rk   r;   r¤  r  r“  r”  rM  )rn   r›  rž  rä  ÚscopeÚroutedÚtargetsrd  s           r.   Ú_publish_env_valuerè  ]
  s“   € ð$ßRá,Ó.Ñ0EÓ0Gˆvˆô $ E¬4Ô0ˆu‰g°b€GÙ�u�}¬
°5¼$Ô(?Ø�‰”r—z‘zÔ"Øò  ˆØˆ=Ø�J‰J�s˜DÕ!àˆF�3ŠKñ	 øô ò $Ø#‰ˆŠvð$ús   ‚B ÂBÂBc           
      óÂ   — t        «       rt        |› d| › �«       yt        j                  | «      r/t	        d|› d| › dt        d«      › d�t        j                  ¬«       yy)	u  Shared write-lock check for ``.env`` writers; prints the refusal and returns True when blocked.
    Two distinct locks: ``is_managed()`` (package-manager install) and the managed *scope*
    (administrator-pinned env key â€” the managed .env wins at load anyway).rA   Tr€  z': it is managed by your administrator (r­  z) and cannot be changed.r„  F)rK  r‡  r   Úis_env_managedr†  Ú_managed_sourcerg   rh   ©rn   r~  s     r.   Ú_env_write_blockedrí  z
  sj   € ô „|Ü˜˜  # Ð'Ô(Øä×#Ñ# CÔ(ÜØ�f�X˜Q˜s˜eÐ#JÌ?Ð[aÓKbÐJcð d%ð &Ü,/¯J©Jõ	8ð Ør-   Úfilenamec                 ó<   — t        j                  «       }|r|| z  S dS )z\``<managed dir>/<filename>`` for refusal messages, or a generic label without a managed dir.zthe managed scope)r   rp  )rî  rr  s     r.   rë  rë  Š
  s#   € ä×/Ñ/Ó1€KÙ'2ˆK˜(Ñ"ÐKÐ8KÐKr-   c                 ó:  ‡ — t        ‰ d«      ryt        ‰ «       |j                  dd«      j                  dd«      }t        ‰ |«      }t	        «        t        «       }|j                  «       rt        |«      ng }t        |«      }t        ˆ fd„t        |«      D «       d«      }|�‰ › d|› d�||<   n:|r!|d   j                  d«      s|dxx   dz  cc<   |j                  ‰ › d|› d�«       t        |||j                  «       ¬	«       t        ‰ |«       t        «        y)
zžSave or update a value in ~/.hermes/.env (also matching ``export KEY=`` lines, so a save
    never appends a second line that a later delete would resurrect).rò  Nr`   r9   úc              3   óB   •K  — | ]  \  }}t        |‰«      sŒ|–— Œ y ­wr3  )râ  )r)  r#  r7   rn   s      €r.   r+  z!save_env_value.<locals>.<genexpr>ž
  s    øè ø€ ÒV‘g�a˜Ô5JÈ4ÐQTÕ5U”ÑVùs   ƒ˜rŒ  r,  r¶  )rí  rØ   re  rÕ  rÝ  r®  r·  rÀ  rÛ  r-  rì  rs  r  r¼  rè  r«  )rn   r›  r½  r%  Úserialized_valueÚidxs   `     r.   r>  r>  �
  s  ø€ ô ˜#˜uÔ%ØÜ# CÔ(Ø�M‰M˜$ Ó#×+Ñ+¨D°"Ó5€EÜ'¨¨UÓ3€EÜÔÜ‹~€Hà)1¯©Ô):ŒO˜HÔ%À€EÜ'¨Ó.Ðä
ÓV¤¨5Ó!1ÔVÐX\Ó
]€CØ
€Ø�u˜AÐ.Ð/¨rÐ2ˆˆcŠ
á˜˜r™×+Ñ+¨DÔ1Ø�"‹I˜Ñ‹IØ�‰˜�u˜AÐ.Ð/¨rÐ2Ô3ä�X˜u°H·O±OÓ4EÕFÜ�s˜EÔ"ÜÕr-   Úidentityc                 ó˜   — t        j                  ddt        | xs d«      j                  «       «      j	                  d«      }|rd|› d�S dS )aP  Env var name holding a custom endpoint's API key.
    ``identity`` is the endpoint's own id (Desktop endpoint id, or ``host:port`` for CLI setup),
    so two endpoints on one host get separate slots. The fixed ``HERMES_CUSTOM_`` prefix keeps the
    name POSIX-valid when the slug starts with a digit (``save_env_value`` rejects those).z
[^A-Z0-9]+rš  r9   ÚHERMES_CUSTOM_rn  ÚHERMES_CUSTOM_API_KEY)r®  r³  rB   rÎ   rC   )rõ  Úslugs     r.   Úcustom_endpoint_key_envrú  «
  sJ   € ô
 �6‰6�- ¤c¨(ª.°bÓ&9×&?Ñ&?Ó&AÓB×HÑHÈÓM€DÙ.2ˆ^˜D˜6 Ð*ÐOÐ8OÐOr-   c                 ó†  — t        | d«      ryt        j                  | «      st        d| ›�«      ‚t	        «       }|j                  «       st        | d«       yt        |«      }|D �cg c]  }t        || «      rŒ|‘Œ }}t        |«      t        |«      k  }|rt        ||d¬«       t        | d«       t        «        |S c c}w )zRRemove a key from ~/.hermes/.env and os.environ; True if it was found and removed.ÚremoveFrÒ   NTr¶  )rí  rÓ   rÔ   rÕ   r®  r·  rè  rÀ  râ  r   r¼  r«  )rn   r½  r%  r7   Ú	new_linesÚfounds         r.   Úremove_env_valuerÿ  ´
  s±   € ä˜#˜xÔ(ØÜ×!Ñ! #Ô&ÜÐ>¸s¸gÐFÓGÐGÜ‹~€HØ�?‰?ÔÜ˜3 Ô%Øä˜HÓ%€EØ"'ÖP˜$Ô/DÀTÈ3Õ/O’ÐP€IÐPÜ�	‹NœS ›ZÑ'€EÙÜ˜ 9¸DÕAÜ�s˜DÔ!ÜÔØ€Lùò Qs   Á'B>Á9B>©Útoken_firstÚtokenrG  r  c                óh   — |xs t         }d| fd|ff}|r|n
t        |«      D ]  \  }} |||«       Œ y)zRWrite both Anthropic credential slots (one holds the value, the other is cleared).rì   rü   N)r>  rW  )r  rG  Úsave_fnr  ÚwriterÚorderr  r›  s           r.   Ú_write_anthropic_slotsr  É
  sF   € àÒ&œ€FØ Ð'Ð*=¸wÐ)GÐH€EÙ +‘u´¸%³ò ‰ˆˆeÙˆt�UÕñr-   c                 ó   — t        | d|«       y)zBPersist an Anthropic OAuth/setup token and clear the API-key slot.r9   N©r  ©r›  r  s     r.   Úsave_anthropic_oauth_tokenr  Ñ
  s   € ä˜5 " gÕ.r-   c                 ó   — t        dd| «       y)zHUse Claude Code's own credential files instead of persisting env tokens.r9   Nr	  )r  s    r.   Ú%use_anthropic_claude_code_credentialsr  Ö
  s   € ä˜2˜r 7Õ+r-   c                 ó"   — t        d| |d¬«       y)zBPersist an Anthropic API key and clear the OAuth/setup-token slot.r9   Fr   Nr	  r
  s     r.   Úsave_anthropic_api_keyr  Û
  s   € ä˜2˜u g¸5ÖAr-   c                 ó,   — ddl m}  || |«       d| ddœS )z�Save via the unified credential lifecycle (also refreshes any config.yaml mirror of the old
    value and lifts a prior env-source suppression).r   ©Úsave_provider_env_credentialTF)ÚsuccessÚ	stored_asÚ	validated)Úhermes_cli.credential_lifecycler  )rn   r›  r  s      r.   Úsave_env_value_securer  à
  s!   € õ Mñ
 !  eÔ,Ø¨#¸EÑBÐBr-   c                  ód  — t        «       } d}| j                  «       D ]@  \  }}t        j                  j	                  |«      |k7  sŒ)|t        j                  |<   |dz  }ŒB t        t        «      t        z  t        | «      z
  D ]+  }|t        j                  v sŒt        j                  |= |dz  }Œ- |S )zÒRe-read ~/.hermes/.env into os.environ; returns count of vars changed.
    Removes deleted vars only when known to Hermes (OPTIONAL_ENV_VARS and _EXTRA_ENV_KEYS) so
    unrelated environment is never clobbered.r   r8   )r.  r  r“  r”  rS   rò  rß  Ú_EXTRA_ENV_KEYS)Úenv_varsÚcountrn   r›  s       r.   Ú
reload_envr  ì
  s¡   € ô ‹z€HØ€EØ—n‘nÓ&ò ‰
ˆˆUÜ�:‰:�>‰>˜#Ó %Ó'Ø#ŒB�J‰J�s‰OØ�Q‰J‰Eðô Ô%Ó&¬Ñ8¼CÀ»MÑIò ˆØ”"—*‘*ÒÜ—
‘
˜3�Ø�Q‰J‰Eðð €Lr-   c                 óè   — 	 ddl m}m} 	  || «      S # t        $ r" t        j
                  j                  | «      cY S w xY w# |$ r ‚ t        $ r" t        j
                  j                  | «      cY S w xY w)a  Read ``key`` from ``os.environ`` through ``agent.secret_scope.get_secret`` so an active
    profile scope (multiplexed gateway turn) never leaks another profile's raw value. Falls back to
    a plain environ read when the scope module is unavailable; ``UnscopedSecretError`` propagates.r   )ÚUnscopedSecretErrorrŸ  )r   r  rŸ  rk   r“  r”  rS   )rn   r  r¡  s      r.   Ú_scoped_environ_getr  ý
  sl   € ð#ßUð#Ù˜3ÓÐøô ò #Ü�z‰z�~‰~˜cÓ"Ò"ð#ûð ò ØÜò #Ü�z‰z�~‰~˜cÓ"Ò"ð#ús   ‚ ‹A “(>½>Á-A1Á0A1c                 óR   — t        | «      }|€t        «       j                  | «      S |S )uÏ  Get a value from ``os.environ`` (scope-aware) or ``~/.hermes/.env``.

    The ``os.environ`` read routes through ``agent.secret_scope.get_secret`` so that, under an active
    profile scope (multiplexed gateway turn), this is scope-checked rather than leaking another profile's
    raw ``os.environ`` value. ``get_secret`` encodes the whole policy: global vars pass through; scope is
    authoritative under multiplexing (miss -> None, no environ fallthrough); when multiplexing is off it
    behaves exactly like the legacy ``os.environ`` read. Its siblings ``get_env_value_prefer_dotenv`` and
    ``gateway.config._getenv`` already work this way â€” this was the last scope-blind reader of the trio
    (#67027).
    )r  r.  rS   )rn   r1  s     r.   r  r    s(   € ô ˜cÓ
"€CØ"% +Œ8‹:�>‰>˜#ÓÐ6°3Ð6r-   c                 óN   — t        «       j                  | «      xs t        | «      S )z©Resolve a Hermes-managed credential preferring ``~/.hermes/.env`` over ``os.environ``, so a
    deliberate .env edit beats a stale value inherited from the parent shell.)r.  rS   r  rZ  s    r.   Úget_env_value_prefer_dotenvr"    s    € ô ‹:�>‰>˜#ÓÒ:Ô"5°cÓ":Ð:r-   c                 óR   — ddl m}  || t        dt        j                  «      ¬«      S )zRedact an API key for display.r   ©Úmask_secretú	(not set))Úempty)Úagent.redactr%  r   r   ÚDIM)rn   r%  s     r.   Ú
redact_keyr*  $  s   € å(Ù�s¤%¨´V·Z±ZÓ"@ÔAÐAr-   >   Újwtrn   r  ÚapikeyÚbearerÚpasswdÚsecretrG  Úid_tokenr;  Úprivate_keyÚaccess_tokenÚauthorizationÚclient_secretÚrefresh_token)Ú_api_keyÚ_tokenÚ_secretÚ	_passwordr  Ú_access_key)Ú_urlÚ_hostÚ_userÚ_idÚ_domainÚ_schemez^\$\{[A-Za-z_][A-Za-z0-9_]*\}$c                 óè   — | j                  dd«      d   j                  «       j                  dd«      }t        | «      r|j	                  t
        «       S |t        v xs |j	                  t        «      S )z¥Whether the LAST segment of a config key names a credential value. Header names
    (``mcp_servers.<s>.headers.X-API-Key``) are folded to snake_case before matching.r_   r8   r,  rb  rš  )Úrsplitr[  re  ru  rs  Ú_NON_SECRET_KEY_SUFFIXESÚ_SECRET_CONFIG_KEYSÚ_SECRET_CONFIG_KEY_SUFFIXES)rn   r›  s     r.   Ú_is_secret_config_keyrF  :  se   € ð �:‰:�c˜1Ó˜bÑ!×'Ñ'Ó)×1Ñ1°#°sÓ;€DÜ˜#ÔØ—=‘=Ô!9Ó:Ð:Ð:ØÔ&Ð&ÒT¨$¯-©-Ô8SÓ*TÐTr-   Ú_depthc           
      ó¦  — ddl m} |dkD  r| S t        | t        «      r{| j	                  «       D ��ci c]_  \  }}|t        |t
        «      r:t        |«      r/t        |t
        «      r|rt        j                  |«      s ||«      nt        ||dz   «      “Œa c}}S t        | t        «      r| D �cg c]  }t        ||dz   «      ‘Œ c}S | S c c}}w c c}w )z¶Copy of ``value`` with credential-shaped keys masked. ``print`` bypasses the logging
    redactor and opaque tokens miss the vendor-prefix regexes, so structural masking is required.r   r$  é   r8   )r(  r%  r;   r¤  r  rB   rF  Ú_ENV_PLACEHOLDER_RErÔ   Úredact_config_valuer9  )r›  rG  r%  r4  rš  s        r.   rK  rK  C  sÊ   € õ )à�‚{ØˆÜ�%œÔð Ÿ™›÷'ñ
 ��1ð	 Ü˜!œSÔ!Ô&;¸AÔ&>Ä:ÈaÔQTÔCUÑZ[Ü'×-Ñ-¨aÔ0ñ ˜1Œ~ô % Q¨°©
Ó3ñ4ó'ð 	'ô �%œÔØ<AÖB°qÔ# A v°¡zÕ2ÒBÐBØ€Lùó'ùò Cs   ±A$CÂ-CÚtitlec                 ó‚   — t        «        t        t        d| › �t        j                  t        j                  «      «       y )Nu   â—† ©r†  r   r   ÚCYANÚBOLD)rL  s    r.   Ú_sectionrQ  V  s&   € Ü	„GÜ	Œ%�$�u�g�¤§¡¬V¯[©[Ó
9Õ:r-   c                  óª  — t        j                  «       } t        j                  «       }| s|syt        «        t        t	        dt        j
                  «       › d�t        j                  t        j                  «      «       d| fd|ffD ]I  \  }}|sŒ	t        t	        d|› ddj                  t        |«      «      › �t        j                  «      «       ŒK y)	zqSurface administrator-pinned settings so the user knows why a config.yaml value may not
    be the effective one.Nu7     âš· Some settings are managed by your administrator (z) and cannot be changedr;  r`  z    Managed z keys: r’  )r   r“  Úload_managed_envr†  r   rp  r   ÚYELLOWrP  rD   rõ  )r”  Úmanaged_envrÑ  ró  s       r.   Ú_show_managed_bannerrV  [  s¿   € ô !×4Ñ4Ó6€LÜ×0Ñ0Ó2€KÙ¡ØÜ	„GÜ	Œ%Ø
AÄ-×B_ÑB_ÓBaÐAbð c ð 	!Ü"(§-¡-´·±ó>ô ?ð " <Ð0°5¸+Ð2FÐGò `‰ˆˆtÚÜ”%˜, u g¨W°T·Y±Y¼vÀd»|Ó5LÐ4MÐNÔPV×P]ÑP]Ó^Õ_ñ`r-   )
)rd  Ú
OpenRouter)r  zOpenAI (STT/TTS))rY  ÚExa)r^  ÚParallel)r   Ú	Firecrawl)r
  ÚTavily)re  Ú
Perplexity)r  ÚBrowserbase)rg  zBrowser Use)r  ÚFALc           	      óî  — t        d«       t        dt        | j                  dd«      «      › �«       | j                  di «      j                  dt        d   d   «      }t        d|› �«       	 t        «       j                  d«      }|�\t        |«      j                  «       t        |«      j                  «       k7  r(t        t        d	|› d
�t        j                  «      «       y y y # t        $ r d }Y Œlw xY w)NÚModelú  Model:        rÀ  znot setrè  ré  z  Max turns:    ÚHERMES_MAX_ITERATIONSu9                   âš  .env has stale HERMES_MAX_ITERATIONS=z& (run 'hermes doctor --fix' to remove))rQ  r†  rK  rS   rÞ  r.  rk   rB   rC   r   r   rT  )r;  Úcfg_max_turnsÚ	env_ghosts      r.   Ú_show_model_sectionre  x  sî   € ÜˆWÔÜ	ÐÔ0°·±¸GÀYÓ1OÓPÐQÐ
RÔSØ—J‘J˜w¨Ó+×/Ñ/°¼^ÈGÑ=TÐU`Ñ=aÓb€MÜ	Ð˜]˜OÐ
,Ô-ðÜ“J—N‘NÐ#:Ó;ˆ	ð Ð¤ Y£×!5Ñ!5Ó!7¼3¸}Ó;M×;SÑ;SÓ;UÒ!UÜŒeÐOÐPYÈ{ð [<ð =Ü>D¿m¹móMõ 	Nð "VÐøô ò ØŠ	ðús   Á.C& Ã&C4Ã3C4c                 ó@  — t        d«       | j                  di «      }	 ddlm}  || «      xs d}d„ }t        d|› �«       t        d	 ||j                  d
d«      «      › �«       t        d ||j                  dd«      «      › d ||j                  dd«      «      › �«       |j                  di «      }t        |t        «      r|ni }t        d|j                  dd«      › d|j                  dd«      › d�«       y # t        $ r |j                  d«      xs d}Y Œëw xY w)NÚDisplayÚdisplayr   )Úactive_personality_namerò  Úpersonalityc                 ó   — | rdS dS )NÚonÚoffr,   )Úflags    r.   ú<lambda>z'_show_display_section.<locals>.<lambda>�  s   € ¡$˜$€ ¨E€ r-   z  Personality:  z  Reasoning:    Úshow_reasoningTz  Bell:         complete=Úbell_on_completeFz	, prompt=Úbell_on_promptÚuser_message_previewz  User preview: first Úfirst_linesr  z line(s), last Ú
last_linesz line(s))rQ  rS   Úhermes_cli.personalityri  rk   r†  r;   r¤  )r;  rh  ri  Úactive_personalityÚon_offÚumps         r.   Ú_show_display_sectionrz  ˆ  s0  € ÜˆYÔØ�j‰j˜ BÓ'€GðBÝBÙ4°VÓ<ÒFÀÐñ 2€FÜ	ÐÐ/Ð0Ð
1Ô2Ü	Ð™V G§K¡KÐ0@À$Ó$GÓHÐIÐ
JÔKÜ	Ø
#¡F¨7¯;©;Ð7IÈ5Ó+QÓ$RÐ#Sð TÙ˜Ÿ™Ð%5°uÓ=Ó>Ð?ð	AôBð �+‰+Ð,¨bÓ
1€CÜ˜C¤Ô&‰#¨B€CÜ	Ð" 3§7¡7¨=¸!Ó#<Ð"=¸_ÈSÏWÉWÐUaÐcdÓMeÐLfÐfnÐ
oÕpøô ò BØ$Ÿ[™[¨Ó7ÒA¸6ÒðBús   ŸC< Ã<DÄDc                 ó¶  ‡‡‡— t        d«       | j                  di «      Št        d‰j                  dd«      › �«       t        d‰j                  dd«      › �«       t        d	‰j                  d
d«      › d�«       d„ ŠdŠˆˆfd„ˆˆfd„ˆˆˆfd„ˆˆˆfd„ˆfd„d„ dœ} |j                  ‰j                  d«      t        «      «       D ]  }t        |«       Œ y )NÚTerminalrb  z  Backend:      rŽ  Úlocalz  Working dir:  r/  r_   z  Timeout:      r1  é<   rú  c                  ó.   — t        d„ | D «       «      rdS dS )Nc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wr3  ©r  )r)  r*  s     r.   r+  z;_show_terminal_section.<locals>.<lambda>.<locals>.<genexpr>¢  s   è ø€ Ò3TÈ´MÀ!×4DÑ3Tùs   ‚Ú
configuredr&  )r‰  )Únamess    r.   ro  z(_show_terminal_section.<locals>.<lambda>¢  s   € ´Ñ3TÈeÔ3TÔ0T € ÐZe€ r-   z*nikolaik/python-nodejs:python3.11-nodejs20c                  ó0   •— d‰j                  d‰ «      › �gS )Nz  Docker image: r3  rÚ  ©Údefault_imgrb  s   €€r.   ro  z(_show_terminal_section.<locals>.<lambda>¥  s   ø€ Ð-¨h¯l©l¸>È;Ó.WÐ-XÐYÐZ€ r-   c                  ó6   •— d‰j                  dd‰ z   «      › �gS )Nz  Image:        r5  z	docker://rÚ  r…  s   €€r.   ro  z(_show_terminal_section.<locals>.<lambda>¦  s&   ø€ Ð"2°8·<±<Ð@SÐU`ÐcnÑUnÓ3oÐ2pÐ qÐr€ r-   c                  óD   •— d‰j                  d‰«      › �d ‰ d«      › �gS )Nz  Modal image:  r6  z  Modal token:  ÚMODAL_TOKEN_IDrÚ  ©r‚  r†  rb  s   €€€r.   ro  z(_show_terminal_section.<locals>.<lambda>§  s1   ø€ Ø˜xŸ|™|¨M¸;ÓGÐHÐIØ™zÐ*:Ó;Ð<Ð=ð?€ r-   c                  óD   •— d‰j                  d‰«      › �d ‰ d«      › �gS )Nz  Daytona image: r7  z  API key:      ÚDAYTONA_API_KEYrÚ  rŠ  s   €€€r.   ro  z(_show_terminal_section.<locals>.<lambda>ª  s2   ø€ Ø §¡¨_¸kÓ JÐKÐLØ™zÐ*;Ó<Ð=Ð>ð@€ r-   c                  óš   •— d‰ j                  dd«      › �dt        d«      s!t        d«      rt        d«      rt        d«      rd	› �gS d
› �gS )Nz  Vercel runtime: r8  Únode24z  Vercel auth:    ÚVERCEL_OIDC_TOKENÚVERCEL_TOKENÚVERCEL_PROJECT_IDÚVERCEL_TEAM_IDr‚  r&  )rS   r  )rb  s   €r.   ro  z(_show_terminal_section.<locals>.<lambda>­  s‡   ø€ Ø  §¡Ð.>ÀÓ!IÐ JÐKØ ´Ð?RÔ1SÔXeÐftÔXuô  {Hð  I\ô  {]ô  boð  p@ô  bA ð  !Tð  Uð#
€ ð HSð  !Tð  Uð#
€ r-   c                  óJ   — dt        d«      xs d› �dt        d«      xs d› �gS )Nz  SSH host:     rb  r&  z  SSH user:     rc  r�  r,   r-   r.   ro  z(_show_terminal_section.<locals>.<lambda>±  s6   € Øœ}Ð-@ÓAÒPÀ[ÐQÐRØœ}Ð-@ÓAÒPÀ[ÐQÐRðT€ r-   )rS  ÚsingularityÚmodalÚdaytonaÚvercel_sandboxr]  )rQ  rS   r†  r9  )r;  Úbackend_linesr7   r‚  r†  rb  s      @@@r.   Ú_show_terminal_sectionr™  ›  sÓ   ú€ ÜˆZÔØ�z‰z˜* bÓ)€HÜ	Ð˜XŸ\™\¨)°WÓ=Ð>Ð
?Ô@Ü	Ð˜XŸ\™\¨%°Ó5Ð6Ð
7Ô8Ü	Ð˜XŸ\™\¨)°RÓ8Ð9¸Ð
;Ô<áe€JØ>€KäZÜrõ?õ@ó
ñTñU€Mð  A�×!Ñ! (§,¡,¨yÓ"9¼4Ó@ÓBò ˆÜˆd�ñr-   c                 ó  — t        d«       | j                  di «      }|j                  dd«      }t        d|rdnd› �«       |sy t        d|j                  d	d
«      dz  d›d�«       |j                  d«      }	 |�'t        |«      dkD  rt        dt        |«      d›d�«       t        d|j                  dd«      dz  d›d�«       t        d|j                  dd«      › d�«       t        d|j                  dd«      › d�«       | j                  di «      j                  di «      }t        d |j                  d!d"«      xs d#› �«       |j                  d$d%«      }|r|d%k7  rt        d&|› �«       y y y # t        t
        f$ r Y Œàw xY w)'NzContext CompressionÚcompressionrl  Tz  Enabled:      rB  Únoz  Threshold:    Ú	thresholdg      à?éd   z.0fú%Úthreshold_tokensr   z  Token cap:    ú,z* tokens (takes lower of ratio vs absolute)z  Target ratio: Útarget_ratiogš™™™™™É?z% of threshold preservedz  Protect last: Úprotect_last_nrI  z	 messagesz  Protect first: Úprotect_first_nr  z non-system head messagesÚ	auxiliaryra  rÀ  r9   z(auto)r×  rÛ  z  Provider:     )rQ  rS   r†  r<   r¥  rÕ   )r;  r›  rl  ÚttÚaux_compÚcomp_providers         r.   Ú_show_compression_sectionr©  ¸  s–  € ÜÐ"Ô#Ø—*‘*˜]¨BÓ/€KØ�o‰o˜i¨Ó.€GÜ	Ð¡g™U°4Ð8Ð
9Ô:ÙØÜ	Ð˜[Ÿ_™_¨[¸$Ó?À#ÑEÀcÐJÈ!Ð
LÔMØ	�‰Ð+Ó	,€BðØˆ>œc "›g¨škÜÐ$¤S¨£W¨Q KÐ/YÐZÔ[ô 
Ð˜[Ÿ_™_¨^¸TÓBÀSÑHÈÐMÐMeÐ
fÔgÜ	Ð˜[Ÿ_™_Ð-=¸rÓBÐCÀ9Ð
MÔNÜ	Ð˜kŸo™oÐ.?ÀÓCÐDÐD]Ð
^Ô_Ø�z‰z˜+ rÓ*×.Ñ.¨}¸bÓA€HÜ	Ð˜XŸ\™\¨'°2Ó6ÒB¸(ÐCÐ
DÔEØ—L‘L ¨VÓ4€MÙ˜¨&Ò0ÜÐ   Ð0Õ1ð 1€}øô ”zÐ"ò Ùðús   Á:)E2 Å2FÆFc           
      óæ  — d| j                  di «      j                  di «      i}|j                  «       D ��ci c]Q  \  }}|j                  dd«      dk7  s|j                  dd«      r%||j                  dd«      |j                  dd«      f“ŒS }}}|sy t        d«       |j                  «       D ]:  \  }\  }}d	|› �g|rd
|› �gng z   }t        d|d›ddj	                  |«      › �«       Œ< y c c}}w )NÚVisionr¥  Úvisionr×  rÛ  rÀ  r9   zAuxiliary Models (overrides)z	provider=zmodel=r#  Ú12sr’  )rS   r  rQ  r†  rD   )r;  Ú	aux_tasksrÑ  ÚtÚ	overridesÚprovÚmdlr!  s           r.   Ú_show_aux_overridesr³  Ð  s	  € Ø˜6Ÿ:™: k°2Ó6×:Ñ:¸8ÀRÓHÐI€Ið "Ÿ™Ó)÷FáˆE�1Ø�5‰5�˜VÓ$¨Ò.°!·%±%¸ÀÔ2Dð 	�—‘�j &Ó)¨1¯5©5°¸"Ó+=Ð>Ñ>ðF€Iñ Fñ ØÜÐ+Ô,Ø'Ÿo™oÓ/ò 4Ñˆ‰{��cØ˜T˜FÐ#Ð$¹C¨6°#°¨Ñ(8ÀRÑHˆÜ��5˜�+˜R §	¡	¨%Ó 0Ð1Ð2Õ3ñ4ùóFs   ¸AC-c            	      ó€  — 	 ddl m} m}  | «       }|sy  ||«      }t        d«       |D ]„  }|j	                  |d   d«      }|rt        |«      nt        dt        j                  «      }t        d|j	                  dd«      › d	�t        j                  «      }t        d
|d   d›d|› d
|› �«       Œ† y # t        $ r Y y w xY w)Nr   )r�  Úresolve_skill_config_valueszSkill Settingsrn   r9   r&  rê  r‡  rë  r#  z<20srA   )r•  r�  rµ  rQ  rS   rB   r   r   r)  r†  rk   )r�  rµ  Ú
skill_varsrl  r”  r›  Údisplay_valÚ	skill_tags           r.   Ú_show_skill_settingsr¹  Þ  sÃ   € ðßaÙ3Ó5ˆ
ÙØÙ.¨zÓ:ˆÜÐ!Ô"Øò 	EˆCØ—L‘L  U¡¨RÓ0ˆEÙ(-œ#˜eœ*´5¸ÄfÇjÁjÓ3QˆKÜ  #§'¡'¨'°2Ó"6Ð!7°qÐ9¼6¿:¹:ÓFˆIÜ�B�s˜5‘z $Ð' q¨¨°R¸	°{ÐCÕDñ		Eøô
 ò Ùðús   ‚B1 ”BB1 Â1	B=Â<B=c                  ód  — t        «       } t        «        t        t        dt        j                  «      «       t        t        dt        j                  «      «       t        t        dt        j                  «      «       t        «        t        d«       t        dt        «       › �«       t        dt        «       › �«       t        dt        «       › �«       t        d«       t        D ])  \  }}t        d	|d
›dt        t        |«      «      › �«       Œ+ ddlm} t        d	dd
›dt         |«       «      › �«       t        | «       t!        | «       t#        | «       t        d«       | j%                  dd«      }t        d|xs t        dt        j&                  «      › �«       t)        | «       t+        | «       t        d«       dD ]A  \  }}t        |«      rdnt        dt        j&                  «      }t        d	|dz   d›d|› �«       ŒC t-        «        t        «        t        t        dt        j&                  «      «       t        t        dt        j&                  «      «       t        t        dt        j&                  «      «       t        t        dt        j&                  «      «       t        «        y)zDisplay current configuration.u±   â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”�u@   â”‚              â˜¤ Hermes Configuration                    â”‚u±   â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜ÚPathsz  Config:       z  Secrets:      z  Install:      zAPI Keysr#  z<14rA   r   )Úget_anthropic_keyÚ	AnthropicÚTimezonerá  r9   z  Timezone:     z(server-local)zMessaging Platforms))ÚTelegramrf  )ÚDiscordr`  r‚  znot configuredr¦  z<13u´   â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€z+  hermes config edit     # Edit config filez!  hermes config set <key> <value>z+  hermes setup           # Run setup wizardN)r�  r†  r   r   rO  rV  rQ  rt   r®  rc  Ú_SHOW_CONFIG_API_KEYSr*  r  Úhermes_cli.authr¼  re  rz  r™  rS   r)  r©  r³  r¹  )r;  Úenv_keyr  r¼  rå  rÑ  Ústates          r.   Úshow_configrÅ  ï  sC  € ä‹]€Fä	„GÜ	Œ%ð  Dô  FL÷  FQñ  FQó  Rô  SÜ	Œ%ÐRÔTZ×T_ÑT_Ó
`ÔaÜ	Œ%ð  Dô  FL÷  FQñ  FQó  Rô  SÜÔäˆWÔÜ	Ðœ_Ó.Ð/Ð
0Ô1Ü	Ðœ\›^Ð,Ð
-Ô.Ü	ÐÔ-Ó/Ð0Ð
1Ô2äˆZÔÜ.ò D‰ˆ�Ü��4˜�*˜Aœj¬°wÓ)?Ó@ÐAÐBÕCðDå1Ü	ˆBˆ{˜3Ð˜q¤Ñ,=Ó,?Ó!@Ð AÐ
BÔCä˜ÔÜ˜&Ô!Ü˜6Ô"äˆZÔØ	�‰�J Ó	#€BÜ	Ð˜RÒF¤5Ð)9¼6¿:¹:Ó#FÐGÐ
HÔIä˜fÔ%Ü˜ÔäÐ"Ô#Ø`ò .‰ˆˆwÜ -¨gÔ 6‘¼EÐBRÔTZ×T^ÑT^Ó<_ˆÜ��5˜3‘;˜sÐ# 1 U GÐ,Õ-ð.ô Ôä	„GÜ	Œ%�
œFŸJ™JÓ
'Ô(Ü	Œ%Ð=¼v¿z¹zÓ
JÔKÜ	Œ%Ð3´V·Z±ZÓ
@ÔAÜ	Œ%Ð=¼v¿z¹zÓ
JÔKÜ	…Gr-   c                  óö  — t        «       rt        d«       yt        «       } | j                  «       st	        t
        d¬«       t        d| › �«       t        j                  dk(  rg d¢ng d¢}t        j                  d	«      xs* t        j                  d
«      xs t        d„ |D «       d«      }|st        d«       t        d| › �«       yt        d| › d|› d�«       t        j                  |t        | «      g«       y)z"Open config file in user's editor.zedit configurationNF)rŸ  zCreated Úwin32)ÚnotepadÚcodeÚvimÚviÚnano)rÌ  rÊ  rË  rÉ  rÈ  r�   rƒ   c              3   óL   K  — | ]  }t        j                  |«      sŒ|–— Œ y ­wr3  )ÚshutilÚwhich)r)  Úcmds     r.   r+  zedit_config.<locals>.<genexpr>-  s   è ø€ Ò8�¤f§l¡l°3Õ&7ŒÑ8ùs   ‚$�$z#No editor found. Config file is at:r#  zOpening r8  z...)rK  r‡  rt   r·  r5  rÞ  r†  rg   Úplatformr“  Úgetenvr-  Ú
subprocessÚrunrB   )rK   Ú
candidatesÚeditors      r.   Úedit_configr×    sÜ   € ä„|ÜÐ*Ô+ØÜ!Ó#€KØ×ÑÔÜ”N°5Õ9Ü�˜˜Ð&Ô'ô ?B¿l¹lÈgÒ>UÓ:Ú?ð ä�Y‰Y�xÓ ò @¤B§I¡I¨hÓ$7ò @¼4Ù8˜
Ô8¸$ó<@€FáÜÐ3Ô4Ü��;�-Ð Ô!Øä	ˆH�[�M  f X¨SÐ
1Ô2Ü‡N�N�FœC Ó,Ð-Õ.r-   c                 ó\   — t        t        gt        | «      ¢­Ž }t        |t        «      rdS |S )z^Return the leaf value declared for *dotted_key* in ``DEFAULT_CONFIG`` (None for dicts/misses).N)r“  rÞ  r%  r;   r¤  )r6  r  s     r.   Ú_default_value_for_keyrÙ  7  s*   € ä”>Ð@¤O°JÓ$?Ò@€DÜ˜d¤DÔ)ˆ4Ð3¨tÐ3r-   >   ÚgoalsrÔ  ÚloopsÚsecretsÚ	providersr­  Úmodel_catalogÚpersonalitiesÚquick_commandsÚserver_actionsÚchannel_promptsÚcommand_allowlistÚcredential_pool_strategies>   ÚsmsÚemailÚqqbotÚslackÚwecomÚfeishuÚmatrixr§  ÚweixinÚdiscordr¨  ÚyuanbaoÚdingtalkrÐ  ÚtelegramÚwhatsappÚ
mattermostÚbluebubblesÚcheckpointsr´  r«  c                  ó<   — t        t        «      t        z  t        z  S )a^  Return the union of known top-level config keys for validation.

    ``_EXTRA_KNOWN_ROOT_KEYS`` are roots the runtime reads but DEFAULT_CONFIG deliberately
    omits (``platform_toolsets``, ``smart_model_routing``, ...); without them every path under
    such a root was flagged "not a recognized config key" with a difflib near-miss suggestion.
    )rò  rÞ  Ú_EXTRA_KNOWN_ROOT_KEYSÚ_OPEN_SUBKEY_TOP_LEVEL_KEYSr,   r-   r.   Ú_known_top_level_keysrø  ^  s   € ô Œ~ÓÔ!7Ñ7Ô:UÑUÐUr-   rÕ  Úcutoffc           
      ól   — t        t        t        j                  | t	        |«      d|¬«      «      d«      S )z9Closest candidate key name for a typo'd ``key``, or None.r8   )r*  rù  N)r-  ÚiterÚdifflibÚget_close_matchesrõ  )rn   rÕ  rù  s      r.   Ú_suggest_closest_keyrþ  h  s,   € ä””W×.Ñ.¨s´F¸:Ó4FÈ!ÐTZÔ[Ó\Ð^bÓcÐcr-   c                 óÈ  — | syt        | «      }|d   }|j                  d«      s|t        v ryt        «       }||vr1t	        ||«      }|€ydj                  |dd «      }d|r|› d|› �fS |fS |t        v ryt        j                  |«      }|g}|dd D ]Í  }|t        v st        |t        «      r|s y||vr•dj                  |t        |«      d «      }t        |«      d   t        t        «      t        z  v rt        |«      d   rd|fc S t	        |t        |j                  «       «      «      }	|	�ddj                  ||	gz   «      fc S  y|j                  |«       ||   }ŒÏ y)	aø  Validate a dotted config-key path against the known schema -> ``(is_known, suggestion)``.

    Headline case from #34067: ``gateway.discord.gateway_restart_notification`` was silently written, even
    though ``gateway`` only has 4 known sub-keys (``strict``, ``media_delivery_allow_dirs``,
    ``trust_recent_files``, ``trust_recent_files_seconds``). The correct path is
    ``discord.gateway_restart_notification`` (platform configs live at the top level, not under a
    ``platforms`` namespace).
    )FNr   rš  )TNNr_   r8   F)r%  rÖ   Ú_PLATFORM_CONTAINER_KEYSrø  rþ  rD   r÷  rÞ  rS   r;   r¤  r   rò  Ú_validate_config_keyró  r  )
rn   ÚsegmentsÚtopÚknownÚ
suggestionÚrestr  r>  ÚsegÚsiblings
             r.   r  r  m  sŒ  € ñ Øä˜sÓ#€HØ
�1‰+€Cð ‡~�~�cÔ˜cÔ%=Ñ=Øä!Ó#€EØ
�%ÑÜ)¨#¨uÓ5ˆ
ØÐØØ�x‰x˜  ˜Ó%ˆØ±˜˜ A d VÐ,ÐDÐD¸*ÐDÐDà
Ô)Ñ)Øô ×"Ñ" 3Ó'€DØˆu€HØ˜˜ˆ|ò ˆØÔ*Ñ*´*¸TÄ4Ô2HÑPTÙØ�d‰?ð —8‘8˜H¤S¨£] ^Ð4Ó5ˆDä Ó% aÑ(¬C´Ó,?ÔB]Ñ,]Ñ]Ü(¨Ó.¨qÒ1à˜d�{Ò"Ü*¨3´°D·I±I³KÓ0@ÓAˆGØÐ"Ø˜cŸh™h x°7°)Ñ';Ó<Ð<Ò<ÙØ�‰˜ÔØ�C‰y‰ð/ð0 r-   r  c                 óª   — |syt        | «      }t        |«      }t        |«      t        |«      k  xr" |t        |«       d |k(  xr t        |«      d   S )a   Whether *suggestion* proves that *key* has only an extra prefix.

    ``DEFAULT_CONFIG`` is not a complete registry of runtime-read settings, so a
    sibling spelling suggestion alone cannot prove an unseeded path is a typo.
    A known suffix, such as ``gateway.discord.gateway_restart_notification``
    -> ``discord.gateway_restart_notification``, is the narrow case where the
    pre-write refusal is safe.
    FNr   )r%  r   r  )rn   r  Úkey_segmentsÚsuggestion_segmentss       r.   Ú_is_wrong_prefix_suggestionr  ®  sh   € ñ ØÜ" 3Ó'€LÜ)¨*Ó5ÐäÐÓ ¤3 |Ó#4Ñ4ò 	0Øœ#Ð1Ó2Ð2Ð3Ð4Ð8KÑKò	0ä  Ó,¨QÑ/ðr-   c                 óZ  — | j                  «       }|dd dv ryd| vry| j                  «       D ]{  }|j                  «       }|dk(  s|j                  d«      r y|j	                  d	«      \  }}}|r|rd
|vr|j                  d«      s y|j                  d«      sŒmd
|dd vsŒu|dd sŒ{ y y)z­True when *value* plausibly encodes a YAML/JSON list or mapping. Deliberately conservative:
    a bare leading ``-`` is not a trigger (``-5``, ``--flag`` must stay strings).Nr8   )rê  ú{Tr`   Frb  z- rS  rA   r�  r¦  r,  )rÞ  Ú
splitlinesrC   rÖ   r–  rs  )r›  r™  r7   r~  ÚheadÚsepÚ_rests          r.   r  r  Â  sº   € ð �|‰|‹~€HØ��€|�zÑ!ØØ�5ÑØØ× Ñ Ó"ò 	ˆØ�z‰z‹|ˆØ�3Š;˜$Ÿ/™/¨$Ô/ÙàŸ>™>¨$Ó/Ñˆˆc�5Ù‘4˜C t™O°D·O±OÀCÔ4HÙØ�=‰=˜Õ #¨T°#°2¨YÒ"6¸4ÀÀº9Ùð	ð r-   c                 óD   — 	 t        | «      S # t        t        f$ r Y yw xY w)zTint(value) for a clean integer literal (signs/whitespace/underscores OK), else None.N)r<   r¥  rÕ   rP  s    r.   Ú_coerce_intr  ×  s(   € ðÜ�5‹zÐøÜ”zÐ"ò Ùðús   ‚
 �žc                 óÐ   — 	 t        | «      }||k7  s8|t        d«      t        d«      fv s t        | «      t        t        |«      «      k7  ry	 |S # t        t        t
        f$ r Y yw xY w)z¬``float(value)`` only when the conversion preserves its decimal value; NaN/inf rejected.
    Decimal-looking identifiers more precise than a binary float must stay strings.rñ  z-infN)r÷  r   rB   r¥  rÕ   r   )r›  r™  s     r.   Ú_coerce_floatr  ß  sm   € ðÜ�%‹LˆØ�Š6�Qœ5 ›<¬¨v«Ð7Ñ7¼7À5»>ÌWÔUXÐYZÓU[Ë_Ò;\Øð <]ð €Høô ”zÔ#3Ð4ò Ùðús   ‚AA ÁA%Á$A%)	ry  rB  rl  rz  rœ  rm  r{  rò  r^  c                 ó  — t        t        | «      t        «      r|S |j                  «       }|j	                  «       }|t
        v r	t
        |   S t        t        fD ]  } ||«      }|€Œ|c S  t        |«      s|S 	 t        j                  |«      }t        t        t         f«      r|S |S # t        j                  $ rG}t        t        |dd«      xs |«      j                  «       d   }t        d| › d|› d�«       Y d}~Œod}~ww xY w)aU  Auto-coerce a ``hermes config set`` string to bool/None/int/float/list/dict.
    String-typed settings (per ``DEFAULT_CONFIG``) are preserved verbatim so enum members such as
    ``approvals.mode="off"`` never become booleans. List/mapping literals are parsed so
    isinstance-gated readers see real structures; the trigger is conservative.Nr@   r   u   âœ— Value for 'z8' looks like a list/mapping but is not valid YAML/JSON (uc   ) â€” nothing was written.
  Fix the literal, or quote it (e.g. "'[text'") to store a plain string.)r;   rÙ  rB   rC   r[  Ú_SCALAR_WORDSr  r  r  r€  r  r  r:   r  Ú_exit_invalidr9  r¤  )	rn   r›  r™  r[  ÚcoerceÚcoercedr  r2   Údetails	            r.   Ú_coerce_config_set_valuer  ó  s  € ô
 Ô(¨Ó-¬sÔ3ØˆØ�{‰{‹}€HØ�N‰NÓ€EØ”ÑÜ˜UÑ#Ð#Ü¤Ð.ò ˆÙ˜Ó"ˆØÑØŠNðô # 5Ô)Øˆð	ZÜ—‘ Ó&ˆô �&œ4¤˜,Ô'Øˆà€Løô �>‰>ò Zô ”W˜S )¨TÓ2Ò9°cÓ:×EÑEÓGÈÑJˆÜØ˜c˜Uð #Øˆxð YðY÷	Zñ 	Zûð	Zús   Á:B) Â)DÂ<=C>Ã>Dr9  r  )r´  rÝ  zmodel.aliasesÚmodel_aliaseszplugins.enabledzplugins.disabledz model_catalog.excluded_providerszagent.disabled_toolsetszskills.disabledr�  c                 ó(  — t        | «      }t        t        g|¢­Ž }t        |«      dk(  rt	        |t
        «      rd}t        || «      }|t        j                  | «      |fD ]0  }t	        |t
        «      s|dk(  r yt	        |t        «      s|dk(  sŒ0 y y)a„  ``"list"`` / ``"mapping"`` when the schema (``DEFAULT_CONFIG``, the known-container table,
    or the value already on disk) fixes *key* to a container; ``None`` for scalars and open paths.
    A single-segment key that is a mapping *section* in the schema skips the lookup: replacing a
    whole section is ``_guard_section_overwrite``'s call (``--force``, the bare ``model`` shorthand).r8   Nr  r9  )
r%  r“  rÞ  r   r;   r¤  rU  r  rS   r9  )rn   r�  r!  Úschema_noderÉ  r  s         r.   Ú_expected_container_typer!  %  s�   € ô
 ˜CÓ €EÜœ.Ð1¨5Ò1€KÜ
ˆ5ƒz�Q‚œ: k´4Ô8ØˆÜ˜;¨Ó,€HØÔ4×8Ñ8¸Ó=¸xÐHò ˆÜ�dœDÔ! T¨YÒ%6ÙÜ�dœDÔ! T¨V£^Ùð	ð
 r-   Úforcec                 óZ  — t        | |«      }|€|S |dk(  rt        |t        «      r| t        v r|gS |dk(  rt        |t        «      nt        |t
        «      }|s|dk(  r|r|S t        |t        «      st        |«      j                  nd}|dk(  rdnd}t        d| › d|› d	|› d
| › d|› d�«       y)uµ  Hard guardrail: never store a value of the wrong shape where the schema wants a list or a
    mapping â€” every reader would ignore it while ``config get`` echoed it back. ``--force`` keeps
    its documented meaning (replace a whole mapping section); a non-list in a list slot is never
    readable, so it has no override. Returns the value to store: a bare name for a
    ``parse_config_string_list``-read slot becomes a one-item list.Nr9  r  Ústringz[item, ...]z{key: value}õ   âœ— Cannot set 'z': it must be a z, got a uR    â€” nothing was written.
  Pass a YAML/JSON literal, e.g.:
    hermes config set ú 'z!'
  or edit config.yaml directly.)	r!  r;   rB   r  r9  r¤  r¦  r(   r  )rn   r›  r�  r"  ÚexpectedÚokÚgotÚliterals           r.   Ú_refuse_container_type_mismatchr+  7  sÉ   € ô (¨¨[Ó9€HØÐØˆØ�6Òœj¨´Ô4¸Ô@]Ñ9]ØˆwˆØ$,°Ò$6Œ�Eœ4Ô	 ¼JÀuÌdÓ<S€BÙ	ˆh˜)Ò#©ØˆÜ&0°¼Ô&<Œ$ˆu‹+×
Ò
À(€CØ'¨6Ò1‰m°~€GÜØ
˜3˜%Ð/°¨z¸À#Àð GDØDGÀ5ÈÈ7È)ð T*ð	*õ+r-   c                 óF  — t        | «      }d}t        |«      dk\  r2|d   dk(  r*|d   dk(  r"|dd }dj                  |«      } d|d   › d	| › d
�}t        |«      dk7  s|d   dk7  r| |fS 	 ddlm} |d   |vr| |fS d|d   › d|d   › �}|d|› d
�fS # t
        $ r | |fcY S w xY w)u^  Canonicalize ``platforms.<name>.<display_setting>`` -> ``display.platforms.<name>.<setting>``.
    The gateway resolves per-platform display settings (streaming, show_reasoning, ...) from
    ``display.platforms``; the top-level ``platforms.<name>`` block holds only connection config.
    Only known display settings (``OVERRIDEABLE_KEYS``) are redirected. Returns ``(key, note)``;
    the gateway import is guarded so the CLI works where the gateway package is unavailable.

    Before #71047 a write such as ``hermes config set platforms.telegram.streaming false`` landed on a key
    the gateway never reads: ``config get`` echoed the new value back while the runtime kept the old
    ``display.platforms`` one â€” a silent no-op that looks like a duplicated key to the user.

    ``gateway.platforms.<name>.<field>`` is canonicalized to the top-level ``platforms.<name>.<field>``
    first (#115212): ``merge_platform_sections`` reads both blocks but the top-level one wins on
    shared keys, so a nested write beside an existing top-level value printed ``âœ“ Set`` while the
    gateway kept the old value.
    Nr  r   Úgatewayr8   r«  r_   z!  (note: the top-level platforms.u/    block outranks gateway.platforms â€” saved as r¤  )ÚOVERRIDEABLE_KEYSr  zdisplay.platforms.u3     (note: per-platform display setting â€” saved as )r%  r   rD   Úgateway.display_configr.  rk   )rn   Úsegsr  Ú_display_keysÚ	canonicals        r.   Ú_redirect_platform_display_keyr3  M  só   € ô  ˜3Ó€DØ€DÜ
ˆ4ƒy�A‚~˜$˜q™' YÒ.°4¸±7¸kÒ3IØ�A�BˆxˆØ�h‰h�t‹nˆØ2°4¸±7°)Ð;jÐknÐjoÐopÐqˆÜ
ˆ4ƒy�A‚~˜˜a™ KÒ/Ø�DˆyÐðÝMð ˆA�w�mÑ#Ø�DˆyÐØ$ T¨!¡W I¨Q¨t°A©w¨iÐ8€IØÐKÈIÈ;ÐVWÐXÐXÐXøô ò Ø�DˆyÒðús   Á)B ÂB ÂB Úrequested_keyc                 óx   — t        | «      }t        |«      dk\  r!|d   dk(  r|d   dk(  rdj                  |«      S y)aW  The ``gateway.platforms.<name>.<field>`` spelling the user typed, when that is what they typed.
    ``merge_platform_sections`` still honours a value that lives only there, so ``get`` must fall
    back to it and ``unset``/``set`` must clear it, or the CLI reports "not set" / writes a value
    while the gateway keeps reading the nested one.r  r   r-  r8   r«  r_   N)r%  r   rD   )r4  r0  s     r.   Ú_legacy_gateway_platforms_keyr6  o  s@   € ô
 ˜=Ó)€DÜ
ˆ4ƒy�A‚~˜$˜q™' YÒ.°4¸±7¸kÒ3IØ�x‰x˜‹~ÐØr-   c           
      ó¶   — t        j                  | «      rDt        d|› d| › dt        d«      › d�t        j
                  ¬«       t	        j                  d«       yy)	zêA key pinned by the managed layer cannot be set/unset (the next load would reinstate it):
    hard-reject and name the source. Distinct from ``is_managed()``; env-shaped keys route to the
    .env writers, which carry their own guard.r€  r&  z(': it is managed by your administrator (rž  zA) and cannot be changed. Contact your administrator to modify it.r„  r8   N)r   Úis_key_managedr†  rë  rg   rh   Úexitrì  s     r.   Ú_exit_if_key_managedr:  z  s^   € ô ×#Ñ# CÔ(ÜØ�f�X˜R ˜uÐ$LÌ_Ð]jÓMkÐLlð mNð OÜUX×U_ÑU_õ	aô 	�‰��ð	 )r-   c                 ó–  — |j                  | «      }d| v st        |t        «      s| S | dk(  r5|rt        dt	        |«      › d�«       | S t        dt	        |«      › d�«       y|r| S |D �cg c]  }t        |t
        «      sŒ|‘Œ }}d| › d	| › d
t	        |«      › d�g}|rU|j                  ddj                  |dd «      › �«       t	        |«      dkD  r!|j                  dt	        |«      dz
  › d�«       |dd| › d�dd| › d|›�gz  }t        dj                  |«      t        j                  ¬«       t        j                  d«       yc c}w )uë   Refuse (or with ``force`` allow) a single-segment key overwriting a mapping with a scalar.
    Bare ``model`` is a documented shorthand â€” redirected to ``model.default`` so siblings survive.
    Returns the (possibly redirected) key.r_   rÀ  u?   âš  Replacing entire 'model' section with a scalar (discarding z existing sub-key(s))u<   âœ“ Redirecting bare 'model' to 'model.default' (preserving z existing model sub-key(s))zmodel.defaultr%  u   ' to a scalar â€” 'z"' is a configuration section with z sub-key(s).z  Sub-keys: r’  Nr…  z
  ... and z morez/  Use a dotted path to set a specific leaf key:z    hermes config set z.<sub-key> <value>z/  Or use --force to replace the entire section:z    hermes config set --force rA   r`   r„  r8   )rS   r;   r¤  r†  r   rB   r  rD   rg   rh   r9  )rn   r›  r�  r"  rÉ  r4  r³  Úerrs           r.   Ú_guard_section_overwriter=  …  su  € ð �‰˜sÓ#€HØ
ˆc�zœ H¬dÔ3Øˆ
Ø
ˆg‚~ÙÜðÜ" 8›}˜oÐ-BðDôEð ˆJÜðÜ˜x›=˜/Ð)DðFô	Gð ÙØˆ
ØÖ
5�¤*¨Q´Õ"4Š1Ð
5€CÐ
5à
˜3˜%Ð2°3°%ð 8&Ü&)¨#£h Z¨|ð	=ð>€Cñ Ø�
‰
�\ $§)¡)¨C°°¨GÓ"4Ð!5Ð6Ô7Üˆs‹8�aŠ<Ø�J‰J˜¤C¨£H¨q¡L >°Ð7Ô8ØØ9Ø
   Ð%7Ð8Ø9Ø
(¨¨¨Q¨u¨iÐ8ð	:ñ :€Cô
 
ˆ$�)‰)�C‹.œsŸz™zÕ*Ü‡H�HˆQ…Kùò 6s   Á*EÂ Ec                 óÀ   — | dk(  rJt        |t        «      r9|r6	 t        «       dz  |› d�z  }|j                  «       r|j	                  «        yyyyy# t
        $ r Y yw xY w)z«``display.skin`` set means "apply NOW": bump the skin file's mtime so the gateway watcher's
    (name, mtime) signature moves even when the name is unchanged. Best-effort.zdisplay.skinÚskinsz.yamlN)r;   rB   r   r·  Útouchrk   )rn   r›  Ú	skin_files      r.   Ú_touch_skin_filerB  ©  so   € ð ˆnÒ¤¨E´3Ô!7¹Eð	Ü'Ó)¨GÑ3¸¸¸u°oÑEˆIØ×ÑÔ!Ø—‘Õ!ð "ð =BÐ!7Ðøô
 ò 	Ùð	ús   ™3A Á	AÁArp   c                 ód   — t        | t        j                  ¬«       t        j                  d«       y )Nr„  r8   )r†  rg   rh   r9  )rp   s    r.   r  r  µ  s   € Ü	ˆ#”C—J‘JÕÜ‡H�HˆQ…Kr-   c                 ó0   — t        «        t        | |«       y)zBWrite only the user's raw config back (never the merged defaults).N)rÝ  r!  )rK   r�  s     r.   Ú_write_user_configrE  º  s   € äÔÜ˜ [Õ1r-   c                 ó^  — t        t        d| › d�t        j                  «      «       |r&t        t        d|› �t        j                  «      «       t	        t        | «      «      dk(  r$t        t        dt        j                  «      «       y t        t        dt        j                  «      «       y )Nõ   âš  'uU   ' is not a recognized config key â€” it was saved anyway, but Hermes may not read it.ú  Did you mean: r8   z‚  (Custom top-level keys are supported and bridged to the environment for skills/external tools. Use --force to skip this notice.)z$  (Use --force to skip this notice.))r†  r   r   rT  r   r%  r)  )rn   r  s     r.   Ú_print_unknown_key_noticerI  À  sŽ   € Ü	Œ%Ø
�ˆuð &ð 	&Ü'-§}¡}ó6ô 7ñ ÜŒeÐ& z lÐ3´V·]±]ÓCÔDô Œ?˜3ÓÓ  AÒ%ÜŒeðä#ŸZ™Zó)õ 	*ô
 	ŒeÐ:¼F¿J¹JÓGÕHr-   c                 ó  — t        d| › d�t        j                  «      g}|r,|j                  t        d|› �t        j                  «      «       |j                  t        dt        j
                  «      «       dj                  |«      S )Nu   âœ— 'u9   ' is not a recognized config key â€” nothing was written.rH  zO  (Custom top-level keys are supported; use --force to write this path anyway.)r`   )r   r   ÚREDr  rT  r)  rD   )rn   r  r%  s      r.   Ú_unknown_subkey_refusalrL  Ñ  st   € Ü�U˜3˜%ÐXÐYÔ[a×[eÑ[eÓfÐg€EÙØ�‰”UÐ-¨j¨\Ð:¼F¿M¹MÓJÔKØ	‡L�L”ØYÔ[a×[eÑ[eógô hà�9‰9�UÓÐr-   c                 ó�  — t        «       rt        d«       y| | j                  «       k7  s| j                  «       st        d| ›d�«       dt	        | «      v rt        d| ›d�«       t        | d«       t        | «      r7dd	lm}  || j                  «       |«       t        d
| › dt        «       › �«       yddlm}m}  || «      r2	  || |«       t        d
| j                  «       › dt        «       › �«       yt!        | «      }t#        | «      \  } }|rt        |«       t%        | «      \  }	}
|	s#|s!t'        | |
«      rt        t)        | |
«      «       t+        «       }t-        |«      }t/        | |«      }|j1                  d«      }| j                  «       j3                  «       j5                  d«      rt7        |t8        «      r	|rd|i|d<   t;        | |||«      } t=        | |||«      }t7        |t>        «      r|j1                  d«      nd}	 tA        || |«       |rtC        ||«      rt        d|› d�«       d}t9        |xs d«      j                  «       xs d}| dk(  rÎ|j3                  «       t9        |«      j                  «       j3                  «       k7  r–ddl"m#}  ||j1                  d«      ||«      \  }}|r7ddjI                  d„ |jK                  «       D «       «      z   d|› d|› d|› d�z   }n;|r9tM        d|d   j1                  d«      › d |› d!|› d"|› d#�	tN        jP                  «      }| j                  «       j3                  «       d$v rtS        |«      }d%} t        d&«       tU        ||«       tW        | «      }|r| d'k7  rtY        |t[        |«      «       t]        | |«       |}t_        | «      r t7        |t8        «      r|rdd(l0m1}  ||«      }t        d
| › d)|› d|› �«       |rt        |«       |	s|ste        | |
«       yyy# t        $ r}t        d|› �«       Y d}~�ŒNd}~ww xY w# t        $ r}t        d|› �«       Y d}~�Œ-d}~ww xY w)*u  Set a configuration value at a dotted ``key``; ``value`` is auto-coerced to bool/int/float.
    ``force`` writes a known key given under the wrong prefix (``gateway.discord.foo`` where
    ``discord.foo`` is known; otherwise refused â€” any other unknown path under a known section
    is written with a did-you-mean notice), skips the unknown-top-level-key notice AND
    authorizes replacing a mapping section with a scalar. Without it, scalar writes over mappings are refused and bare ``model`` is redirected
    to ``model.default``.zset configuration valuesNu   âœ— Invalid config key: z# (empty or surrounding whitespace).r9   uH    â€” contains an empty path segment (leading, trailing, or doubled '.').rò  r   r  u   âœ“ Set r8  )Úis_env_setting_keyÚsave_env_settingõ   âœ— rÀ  úmodel.r†  r×  z  (removed the shadowed z duplicate)zthe previous providerzmodel.provider)Údrop_stale_model_routez
  Cleared r’  c              3   ó4   K  — | ]  \  }}d |› d|› d�–— Œ y­w)rQ  r  r¤  Nr,   rˆ  s      r.   r+  z#set_config_value.<locals>.<genexpr>-  s#   è ø€ Ò(XÁÀÀ1¨6°!°°B°q°c¸Ô);Ñ(Xùs   ‚u    â€” that route belonged to z, not rQ   z\'s endpoint resolves automatically; set model.base_url again if you meant a custom endpoint.u   âš  model.base_url (rL  z) was set under z and still applies to u%    â€” requests go there. If it is not zG's endpoint: `hermes config unset model.base_url` (and model.api_mode).)zmodel.api_baserÖ  zmodel.base_urlu<     (note: 'api_base' is an alias â€” saved as model.base_url)úterminal.cwdr$  rˆ  )3rK  r‡  rC   r  r%  r:  ru  r  r  rÎ   r†  r®  Úhermes_cli.config_env_routingrN  rO  rÕ   r6  r3  r  r  rL  rt   r  r  rS   r[  rÖ   r;   rB   r=  r+  r¤  rA  rX  Úhermes_cli.route_identityrR  rD   r  r   r   rT  ræ  rE  r[  r>  rQ  rB  rF  r(  r%  rI  )rn   r›  r"  r  rN  rO  r2   Ú
legacy_keyÚ_redirect_noteÚis_knownr  rK   r�  Ú
_model_valÚ_old_providerr˜  Ú_route_noticerR  Ú_poppedÚ_unverifiedrW  Ú_display_valuer%  s                          r.   Úset_config_valuer`  Ú  sA  € ô „|ÜÐ0Ô1Øà
ˆc�i‰i‹kÒ §¡¤ÜÐ0°°Ð7ZÐ[Ô\Ø	Œ_˜SÓ!Ñ!ÜØ& s gð .3ð 3ô	4ô ˜˜eÔ$Ü˜#ÔÝPñ 	% S§Y¡Y£[°%Ô8Ü�˜˜˜T¤,£.Ð!1Ð2Ô3ØßRá˜#Ôð
	(Ù˜S %Ô(ô 	�˜Ÿ™›˜ T¬,«.Ð)9Ð:Ô;Øô /¨sÓ3€JÜ8¸Ó=Ñ€CˆÙÜˆnÔÜ/°Ó4Ñ€Hˆjñ ™EÔ&AÀ#ÀzÔ&RÜÔ-¨c°:Ó>Ô?ô "Ó#€KÜ6°{ÓC€KÜ$ S¨%Ó0€Eð —‘ Ó)€JØ
‡y�yƒ{×ÑÓ×%Ñ% hÔ/´J¸zÌ3Ô4OÑT^Ø )¨:Ð6ˆ�GÑÜ
" 3¨¨{¸EÓ
B€CÜ+¨C°¸ÀUÓK€EÜ2<¸ZÌÔ2N�J—N‘N :Ô.ÐTX€Mð"Ü�K  eÔ,ñ ”m K°Ô<ÜÐ(¨¨°KÐ@ÔAð €MÜ˜Ò+¨Ó,×2Ñ2Ó4ÒOÐ8O€MØ
ÐÒ =×#6Ñ#6Ó#8¼CÀ»J×<LÑ<LÓ<N×<TÑ<TÓ<VÒ#VÝDÙ5°k·o±oÀgÓ6NÐPUÐWbÓcÑˆ�Ùà˜tŸy™yÑ(XÈÏÉËÔ(XÓXÑXØ0°°¸vÀeÀWÈBÈuÈgð VZð ZñZñ ñ Ü!Ø& {°7Ñ';×'?Ñ'?À
Ó'KÐ&LÐL\Ð]jÐ\kð l$Ø$) 7Ð*OÐPUÈwð WMðMäNTÏmÉmó]ˆMð
 ‡y�yƒ{×ÑÓÐ<Ñ<ô 1°Ó=ˆØˆÜÐLÔMÜ�{ KÔ0ô .¨cÓ2€GÙ�3˜.Ò(Ü�wÔ 3°EÓ :Ô;ä�S˜%Ô ð €NÜ˜SÔ!¤j°¼Ô&<ÁÝ,Ù$ UÓ+ˆÜ	ˆH�S�E˜˜^Ð,¨D°°Ð
>Ô?ÙÜˆmÔñ ™EÜ! # zÕ2ð "ˆ8øôk ò 	(Ü˜D  ˜,×'Ò'ûð	(ûô@ ò "Ü˜˜Q˜C�j×!Ò!ûð"ús0   Ã	O> ÈP# Ï>	P ÐPÐP Ð#	QÐ,Q Ñ Q©rv  r‹  c                ól  — ddl m}m} t        | «      r$t	        | j                  «       «      }|€t        n|}n` || «      r || «      }|€t        n|}nEt        | «      }t        | «      \  } }t        «       }	t        |	| «      }|t        u r|rt        |	|«      }|t        u rt        d| › �«       ddlm}
m} |sK |
«       rDt        |t         «      r)t#        | «      r)t$        j'                  |«      s ||«      }nt)        |«      }t+        t-        ||¬«      d¬«       t/        | «      d   t1        «       v r‚t3        | «      \  }}|sqt+        t5        d	| › d
�t6        j8                  «      t:        j<                  ¬«       |r7t+        t5        d|› �t6        j8                  «      t:        j<                  ¬«       yyyy)züPrint a resolved configuration value. Credentials are masked unless ``--raw`` or
    ``security.redact_secrets: false``: ``print`` bypasses the log redactor, and the agent runs
    this command from sessions whose transcripts persist (#84106, #110758).r   )rN  Úread_env_settingNúConfig key not set: )Ú_redact_enabledr%  )rv  T)rj   rG  uq   ' is not a recognized config key â€” Hermes may not read it; the value printed above comes from your config file.r„  rH  )rU  rN  rc  ru  r  rÎ   rS  r6  r3  r�  rU  r  r(  re  r%  r;   rB   rF  rJ  rÔ   rK  r†  rƒ  r%  rø  r  r   r   rT  rg   rh   )rn   rv  r‹  rN  rc  Ú	env_valuer›  rW  rš  r;  re  r%  rY  r  s                 r.   Úget_config_valuerg  V  sŠ  € ÷ Sä˜#ÔÜ! #§)¡)£+Ó.ˆ	Ø%Ð-•°9‰Ù	˜CÔ	 Ù$ SÓ)ˆ	Ø%Ð-•°9‰ô 3°3Ó7ˆ
Ü/°Ó4‰ˆˆQÜ“ˆÜ˜F CÓ(ˆØ”HÑ¡Ü ¨
Ó3ˆEà”ÑÜÐ,¨S¨EÐ2Ô3ç9Ù‘?Ô$Ü�eœSÔ!Ü$ SÔ)Ô2E×2KÑ2KÈEÔ2RÙ# EÓ*‘ä'¨Ó.ˆEä	Ô
" 5°'Ô
:À$ÕGô �sÓ˜AÑÔ"7Ó"9Ñ9Ü3°CÓ8Ñˆ�*ÙÜ”%Ø˜�uð =ð =Ü>D¿m¹móMäSV×S]ÑS]õ_ñ Ü”eÐ.¨z¨lÐ;¼V¿]¹]ÓKÔRU×R\ÑR\Ö]ð ð	 ð :r-   c                 óò  — t        «       rt        d«       yt        | d«       t        | «      rSddlm}  || j                  «       «      j                  d«      st        d| › �«       t        d| › d	t        «       › �«       ydd
lm}m}  || «      r0 || «      st        d| › �«       t        d| › d	t        «       › �«       yt        «       }t        |«      }t!        | «      }t#        | «      \  } }|rt        |j%                  dd«      «       t'        || «      }|rt'        ||«      xs |}t)        | «      }	|	r| dk7  rt+        |	«      xs |}|st        d| › �«       t-        ||«       t        d| › d	|› �«       y)z.Remove a user-set configuration or .env value.zunset configuration valuesNÚunsetr   )Úremove_provider_env_credentialrþ  rd  u
   âœ“ Unset z from )rN  Úremove_env_settingzsaved aszresolved asrT  )rK  r‡  r:  ru  r  rj  rÎ   rS   r  r†  r®  rU  rN  rk  rt   r  r6  r3  re  rX  r[  rÿ  rE  )
rn   rj  rN  rk  rK   r�  rW  rX  ÚremovedrW  s
             r.   Úunset_config_valuerm  ‹  se  € ä„|ÜÐ2Ô3ØÜ˜˜gÔ&ä˜#Ôõ 	Sá-¨c¯i©i«kÓ:×>Ñ>¸wÔGÜÐ0°°Ð6Ô7Ü�
˜3˜%˜v¤l£nÐ%5Ð6Ô7ØßTá˜#Ôá! #Ô&ÜÐ0°°Ð6Ô7Ü�
˜3˜%˜v¤l£nÐ%5Ð6Ô7Øä!Ó#€KÜ6°{ÓC€Kä.¨sÓ3€JÜ8¸Ó=Ñ€CˆÙäˆn×$Ñ$ Z°Ó?Ô@Ü˜K¨Ó-€GÙÜ ¨ZÓ8ÒC¸Gˆä-¨cÓ2€GÙ�3˜.Ò(Ü" 7Ó+Ò6¨wˆáÜÐ,¨S¨EÐ2Ô3ä�{ KÔ0Ü	ˆJ�s�e˜6 + Ð
/Õ0r-   ÚusageÚexamplesÚextrac                 óÄ   — t        | «       t        «        t        d«       |D ]  }t        d|› �«       Œ |xs dD ]  }t        |«       Œ t        j                  d«       y )Nz	Examples:r#  r,   r8   )r†  rg   r9  )rn  ro  rp  r7   s       r.   Ú_usage_exitrr  ¾  sX   € Ü	ˆ%„LÜ	„GÜ	ˆ+ÔØò ˆÜ��4�&ˆkÕðà’˜ò ˆÜˆd�ðä‡H�HˆQ…Kr-   c                 óX   — 	  | |Ž  y# t         $ r}t        d|› �«       Y d}~yd}~ww xY w)zzRun a config writer, surfacing the fail-closed write guard's RuntimeError as a clean CLI
    error instead of a traceback.rP  N)r  r  )ÚfnÚargsr2   s      r.   Ú_run_write_commandrv  É  s/   € ð$Ù
ˆDŠ	øÜò $Ü˜˜S˜E�l×#Ñ#ûð$ús   ‚ ˆ	)‘$¤)z/Usage: hermes config get <key> [--json] [--raw])zhermes config get modelz"hermes config get terminal.backendz&hermes config get skills.config --jsonz0Usage: hermes config set [--force] <key> <value>)z1hermes config set model anthropic/claude-sonnet-4z)hermes config set terminal.backend dockerz.hermes config set OPENROUTER_API_KEY sk-or-...)r9   z=  --force: skip the unknown-key notice for unrecognized keys,z@           and allow a scalar to replace a whole mapping sectionz Usage: hermes config unset <key>)zhermes config unset modelz$hermes config unset terminal.backendz&hermes config unset OPENROUTER_API_KEYc                 ó”   — t        | dd «      }|st        t        Ž  t        |t        | dd«      t	        t        | dd«      «      ¬«       y )Nrn   r}  Fr‹  ra  )r:   rr  Ú
_USAGE_GETrg  r  ©ru  rn   s     r.   Ú_cmd_config_getrz  ß  sA   € Ü
�$˜˜tÓ
$€CÙÜ”ZÑ Ü�S¤'¨$°¸Ó">ÄDÌÐQUÐW\Ð^cÓIdÓDeÖfr-   c                 ó¤   — t        | dd «      }t        | dd «      }|r|€t        t        Ž  t        t        ||t        t        | dd«      «      «       y )Nrn   r›  r"  F)r:   rr  Ú
_USAGE_SETrv  r`  r  )ru  rn   r›  s      r.   Ú_cmd_config_setr}  æ  sK   € Ü
�$˜˜tÓ
$€CÜ�D˜' 4Ó(€EÙ�%�-Ü”ZÑ ÜÔ'¨¨e´T¼'À$ÈÐQVÓ:WÓ5XÕYr-   c                 óZ   — t        | dd «      }|st        t        Ž  t        t        |«       y )Nrn   )r:   rr  Ú_USAGE_UNSETrv  rm  ry  s     r.   Ú_cmd_config_unsetr€  î  s&   € Ü
�$˜˜tÓ
$€CÙÜ”\Ñ"ÜÔ)¨3Õ/r-   Úfmtc                 ót   — | j                  dg «      }|r#|j                  dj                  |d d «      «      S dS )NÚtoolsr’  r  r9   )rS   rV   rD   )r˜  r�  rƒ  s      r.   Ú_tools_suffixr„  õ  s7   € Ø�H‰H�W˜bÓ!€EÙ/4ˆ3�:‰:�d—i‘i  b q 	Ó*Ó+Ð<¸"Ð<r-   rF   c                 ó�   — t        «        t        t        | t        j                  t        j                  «      «       t        «        y r3  rN  )rF   s    r.   Ú_print_bannerr†  ú  s%   € Ü	„GÜ	Œ%�”f—k‘k¤6§;¡;Ó
/Ô0Ü	…Gr-   c           
      óä  — t        d«       t        d¬«      }t        «       }t        d¬«      \  }}|s5|s3||k\  r.t	        t        dt        j                  «      «       t	        «        y ||k  rt	        d|› d|› �«       |rt	        d	t        |«      › d
�«       |D �cg c]  }|j                  d«      sŒ|‘Œ }}|D �cg c](  }|j                  d«      rŒ|j                  d«      rŒ'|‘Œ* }}d|dfd|dffD ]W  \  }}	}
|	sŒ
t	        d	|j                  t        |	«      «      › �«       |	D ]#  }t	        d|d   › |
rt        ||
«      nd› �«       Œ% ŒY t	        «        t        dd¬«      }t	        «        |d   s|d   r#t	        t        dt        j                  «      «       |d   r:t	        «        |d   D ](  }t	        t        d|› �t        j                  «      «       Œ* t	        «        y c c}w c c}w )Nu*   ðŸ”„ Checking configuration for updates...FrR  Tr   u    âœ“ Configuration is up to date!ú  Config version: rQ  r�  z1 new config option(s) will be added with defaultsr  Úadvancedu'   âš ï¸�  {} required API key(s) missing:r9   u.   â„¹ï¸�  {} optional API key(s) not configured:z (enables: {})u	        â€¢ r  )rH  rI  r<  rK  u   âœ“ Configuration updated!rL  u
     âš ï¸�  )r†  r  rŽ  r¦  r†  r   r   ÚGREENr   rS   rV   r„  ri  rT  )ru  rg  Úmissing_configrb  rc  rš  Úrequired_missingÚoptional_missingr{  r§  r¾  r”  r9  rf   s                 r.   Ú_cmd_config_migraterŽ     sé  € ÜÐ>Ô?ä&°UÔ;€KÜ.Ó0€NÜ2ÈÔMÑ€K�á™~°+ÀÒ2KÜŒeÐ6¼¿¹ÓEÔFÜŒØà�ZÒÜÐ" ; -¨u°Z°LÐAÔBáÜ�”S˜Ó(Ð)Ð)ZÐ[Ô\à#.ÖG˜a°!·%±%¸Õ2FšÐGÐÐGØ#.Öe˜a°a·e±e¸MÕ6JÐST×SXÑSXÐYcÕSdšÐeÐÐeà	2Ð4DÀbÐIØ	9Ð;KÐM]Ð^ð#`ò _Ñˆ�˜ò Ü�D˜Ÿ™¬¨E«
Ó3Ð4Ð5Ô6Øò _�Ü˜	 # f¡+ ÉV¬}¸SÀ&Ô/IÐY[Ð.\Ð]Õ^ñ_ð_ô 
„GÜ¨°UÔ;€GÜ	„GØˆ{Ò˜w ~Ò6ÜŒeÐ0´&·,±,Ó?Ô@ØˆzÒÜŒØ˜zÑ*ò 	@ˆGÜ”%˜* W IÐ.´·±Ó>Õ?ð	@ä	…Gùò' HùÚes   ÂG(Â3G(Â=G-ÃG-Ã&G-c           	      ó€  — t        d«       t        d¬«      \  }}||k\  rt        d|› d�«       n*t        t        d|› d|› d�t        j
                  «      «       dt        d	„ fd
t        d„ ff}|D ]q  \  }}}t        «        t        t        d|› d�t        j                  «      «       |j                  «       D ]'  \  }}t        t        |«      rd|› �n |||«      «       Œ) Œs t        «       }	|	rEt        «        t        t        dt        |	«      › d�t        j
                  «      «       t        d«       t        «        y)z)Non-interactive report of what's missing.u   ðŸ“‹ Configuration StatusTr   rˆ  u    âœ“rQ  z (update available)ÚRequiredc                 ó>   — t        d| › d�t        j                  «      S )Nu       âœ— z
 (missing))r   r   rK  ©r*  r#  s     r.   ro  z#_cmd_config_check.<locals>.<lambda>3  s   € ´U¸XÀaÀSÈ
Ð;SÔU[×U_ÑU_Ó5`€ r-   r   c                 óT   — t        d| › t        |d«      › �t        j                  «      S )Nu       â—‹ u    â†’ {})r   r„  r   r)  r’  s     r.   ro  z#_cmd_config_check.<locals>.<lambda>5  s$   € ”e˜h q c¬-¸¸9Ó*EÐ)FÐGÌÏÉÓT€ r-   r#  r¦  u       âœ“ z new config option(s) availablez+    Run 'hermes config migrate' to add themN)r†  r¦  r†  r   r   rT  r  rß  rP  r  r  rŽ  r   )
ru  rb  rc  r  rL  r  Úmissing_liner  r˜  r‹  s
             r.   Ú_cmd_config_checkr•  (  s9  € äÐ-Ô.ä2ÈÔMÑ€K�Ø�jÒ ÜÐ" ; -¨tÐ4Õ5äŒeÐ(¨¨°U¸:¸,ÐFYÐZÔ\b×\iÑ\iÓjÔkð 
Ô&Ñ(`ÐaØ	Ô&Ù	Tð	VðW€Fð '-ò fÑ"ˆˆu�lÜŒÜŒe�b˜˜˜q�M¤6§;¡;Ó/Ô0Ø#Ÿk™k›mò 	f‰NˆH�dÜ¬=¸Ô+B�H˜X˜JÑ'ÉÐU]Ð_cÓHdÕeñ	fðfô /Ó0€NÙÜŒÜŒe�bœ˜^Ó,Ð-Ð-LÐMÌvÏ}É}Ó]Ô^ÜÐ;Ô<ä	…Gr-   c                 ó   — t        «       S r3  ©rÅ  ©ru  s    r.   ro  ro  F  s   € ”{“}€ r-   c                 ó   — t        «       S r3  r—  r˜  s    r.   ro  ro  G  ó   € œ›€ r-   c                 ó   — t        «       S r3  )r×  r˜  s    r.   ro  ro  H  rš  r-   c                 ó(   — t        t        «       «      S r3  )r†  rt   r˜  s    r.   ro  ro  L  s   € œœÓ0Ó1€ r-   c                 ó(   — t        t        «       «      S r3  )r†  r®  r˜  s    r.   ro  ro  M  s   € œU¤<£>Ó2€ r-   )
NÚshowÚeditrS   rò  ri  ru   zenv-pathÚmigrateÚcheckaü  Available commands:
  hermes config           Show current configuration
  hermes config edit      Open config in editor
  hermes config get <key>          Print a resolved config value
  hermes config set <key> <value>   Set a config value
  hermes config unset <key>        Remove a config value
  hermes config check     Check for missing/outdated config
  hermes config migrate   Update config with new options
  hermes config path      Show config file path
  hermes config env-path  Show .env file pathc                 óÖ   — t        | dd«      }t        j                  |«      }|�	 || «       yt        d|› �«       t        «        t        t        «       t        j                  d«       y)zHandle config subcommands.Úconfig_commandNzUnknown config command: r8   )r:   Ú_CONFIG_SUBCOMMANDSrS   r†  Ú_CONFIG_USAGErg   r9  )ru  ÚsubcmdÚhandlers      r.   r£  r£  ]  sY   € ä�TÐ+¨TÓ2€FÜ!×%Ñ% fÓ-€GØÐÙ�ŒØÜ	Ð$ V HÐ
-Ô.Ü	„GÜ	Œ-ÔÜ‡H�HˆQ…Kr-   c            	      óT  — 	 ddl m}   | «       D ]ˆ  }|j                  dk7  rŒ|j                  D ]g  }|t        v rŒ|j                  d«       }|j                  xs |j                  }|› d|rdnd› �|› d|rdnd› �|j                  xs d	|d
ddœt        |<   Œi ŒŠ y	# t        $ r Y y	w xY w)z|Expose env_vars of every ``auth_type="api_key"`` provider in providers/ via OPTIONAL_ENV_VARS
    without editing this file.r   )Úlist_providersrG  )Ú	_BASE_URLÚ_URLrA   zAPI keyzbase URL overridez"base URL (leave empty for default)Nr×  T)r‡  r8  rT  r;  Úcategoryr‰  )
rÝ  r©  Ú	auth_typer  rß  rs  Údisplay_namer  Ú
signup_urlrk   )r©  Ú_ppÚ_varÚ_is_keyÚ_labels        r.   Ú_inject_profile_env_varsr´  l  sÎ   € ðÝ,Ù!Ó#ò 	&ˆCØ�}‰} 	Ò)ØØŸ™ò &�ØÔ,Ñ,ØØ"Ÿm™mÐ,AÓBÐB�Ø×)Ñ)Ò5¨S¯X©X�à&, X¨Q¹G©yÐI\Ð.]Ð#^Ø!' ¨±w©)ÐDhÐ)iÐjØŸ>™>Ò1¨TØ 'Ø *Ø $ñ+&Ô! $Ò'ñ&ñ	&øô ò Ùðús   ‚BB Â	B'Â&B'c               #   óò  ‡K  — t        «       dz  } t        «       dz  dz  df| dz  df| dff}|D ]©  \  }}|j                  «       sŒ|j                  «       D ]€  Št	        ˆfd„‰dz  ‰dz  fD «       d«      }|€Œ#	 t        |d	d
¬«      5 }t        |«      xs i }ddd«       t        t        «      r|r|j                  d«      dk7  rŒq‰j                  |f–— Œ‚ Œ« y# 1 sw Y   ŒExY w# t        $ r Y Œ�w xY w­w)a  Yield ``(dir_name, manifest_dict)`` for every platform plugin manifest: bundled
    ``plugins/platforms/*``, the user's ``<HERMES_HOME>/plugins/platforms/*`` category dir, and flat
    user installs ``<HERMES_HOME>/plugins/*`` that declare ``kind: platform`` (#46600).r¨  r«  FTc              3   óf   •K  — | ](  }‰j                  «       sŒ|j                  «       sŒ%|–— Œ* y ­wr3  )ri  r·  )r)  ÚprÇ  s     €r.   r+  z-_platform_plugin_manifests.<locals>.<genexpr>–  s%   øè ø€ Òk�qÈUÏ\É\Í^Ð`a×`hÑ`hÕ`j”Ñkùs   ƒ1™1ª1zplugin.yamlz
plugin.ymlNr‹  rW  rX  r  rÑ  )r   rc  ri  Úiterdirr-  r•  r"   rk   r;   r¤  rS   r  )Úuser_pluginsÚrootsrj  Úrequire_kindÚmanifest_pathr™  ÚmanifestrÇ  s          @r.   Ú_platform_plugin_manifestsr¾  ‡  s%  øè ø€ ô #Ó$ yÑ0€Lä	Ó	˜iÑ	'¨+Ñ	5°uÐ=Ø	˜Ñ	# UÐ+Ø	�tÐð€Eð
 $ò 'ÑˆˆlØ�{‰{Œ}ØØ—\‘\“^ò 	'ˆEÜ Ûk˜U ]Ñ2°E¸LÑ4HÐIÔkÐmqósˆMàÐ$ØðÜ˜-¨°wÔ?ð 7À1Ü-¨aÓ0Ò6°B�H÷7ô ˜h¬Ô-±,À8Ç<Á<ÐPVÓCWÐ[eÒCeØØ—*‘*˜hÐ&Ó&ñ	'ñ'÷7ð 7ûäò ÙðüsB   ƒA6C7Á:C(ÂCÂC(Â <C7ÃC%Ã!C(Ã(	C4Ã1C7Ã3C4Ã4C7c            	      ó  — 	 t        «       D �]d  \  } }|j                  d«      xs |j                  d«      xs | }g |j                  d«      xs g ¢|j                  d«      xs g ¢D �]  }t        |t        «      rd|int        |t        «      r|ni }|j                  d«      }|r|t
        v rŒHt        |j                  d«      xs |j                  d«      «      }|s2|j                  d«      dur|j                  «       j                  d«      }|j                  d	«      xs |› d
�|j                  d«      xs ||j                  d«      xs d||j                  d«      xs ddœt
        |<   �Œ	 �Œg y# t        $ r Y yw xY w)a÷  Populate OPTIONAL_ENV_VARS from platform plugin manifests (bundled AND user-installed) so
    Teams / IRC / Google Chat and third-party platforms are configurable in the ``hermes config`` /
    Desktop Gateway form without the core knowing they exist.

    ``requires_env`` / ``optional_env`` entries are a bare name or a dict with ``name`` plus
    optional ``description``/``url``/``password``/``prompt``/``category``. Failures are swallowed
    so a malformed plugin.yaml can't break CLI import.
    rÑ  r  Úrequires_envÚoptional_envr;  r/  F)ro  rp  Ú_KEYÚ	_PASSWORDÚ_JSONr‡  z configurationr8  rT  Nr¬  Ú	messaging)r‡  r8  rT  r;  r¬  )
r¾  rS   r;   rB   r¤  rß  r  rÎ   rs  rk   )Údir_namer½  rÑ  rÐ  Úmetar  Ú	is_secrets          r.   Ú _inject_platform_plugin_env_varsrÉ  £  sr  € ðÜ"<Ó">ó 	EÑˆH�hØ—L‘L Ó)ÒM¨X¯\©\¸&Ó-AÒMÀXˆEØg˜HŸL™L¨Ó8Ò>¸BÐgÀ8Ç<Á<ÐP^ÓC_ÒCeÐceÐgó E�Ü*4°U¼CÔ*@˜ ‘ÌzÐZ_ÔaeÔOfÁeÐln�Ø—x‘x Ó'�Ù˜tÔ'8Ñ8Øä  §¡¨*Ó!5Ò!K¸¿¹À(Ó9KÓL�	Ù ¨¯©°*Ó)=ÀÑ)FØ $§
¡
£× 5Ñ 5Ð6iÓ j�Ià#'§8¡8¨MÓ#:Ò#VÀÀÀ~Ð>VØ"Ÿh™h xÓ0Ò8°DØŸ8™8 E›?Ò2¨dØ )Ø $§¡¨Ó 4Ò C¸ñ+EÔ! $Ó'òEñ	Eøô" ò Ùðús   ‚E2E5 Å5	FÆ Fc                 ól   — | �| S t        t        «      j                  j                  j                  «       S )u„  Resolve the directory that holds the *running code* (the install tree).

    This is the parent of ``hermes_cli/`` â€” i.e. the git checkout for source
    installs, ``/opt/hermes`` inside the published image. It is a property of
    the running interpreter, NOT of ``$HERMES_HOME``, which is why a
    code-scoped stamp here is immune to two installs sharing one data
    directory.
    r°  )r_  s    r.   Ú_install_method_project_rootrË  Ê  s/   € ð ÐØÐÜ”‹>× Ñ ×'Ñ'×/Ñ/Ó1Ð1r-   c                 ó’   — t        |«      }	 |j                  dd¬«       |dz  j                  | dz   d¬«       y# t        $ r Y yw xY w)a<  Write the install method next to the running code (code-scoped stamp).

    The stamp lives in the install tree (``<install tree>/.install_method``),
    not in ``$HERMES_HOME``, so that two installs sharing one data directory
    do not overwrite each other's marker. See ``detect_install_method`` for
    the full rationale.

    Best-effort: if the install tree is read-only (e.g. the immutable
    ``/opt/hermes`` in the published image, which instead bakes the stamp at
    build time) the write silently no-ops and detection falls back to its
    other signals.
    T)rh  Úexist_okra  r`   rW  rX  N)rË  ÚmkdirrÂ  rb   )r]  r_  rj  s      r.   Ústamp_install_methodrÏ  ×  sR   € ô (¨Ó5€DðØ�
‰
˜4¨$ˆ
Ô/Ø	Ð!Ñ	!×-Ñ-¨f°t©mÀgÐ-ÕNøÜò Ùðús   �,: º	AÁAÚnormalize_route_base_url)zhermes_cli.route_identityrÐ  c                 óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncer8   )	Ú_PLUGIN_COMPAT_LAZYrS   ÚAttributeErrorr(   Ú	importlibÚhermes_cli.plugin_compatrÒ  r:   Úimport_module)r  rd  rÕ  rÒ  s       r.   Ú__getattr__rØ  ñ  se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐAr-   r3  )zmodify this Hermes installation)zmodify configuration)FrŒ  )r3   N)TF)r   )g333333ã?(x  r+   Úhermes_cli.stale_modulesr   rŽ  rü  r}  Úloggingr“  rÑ  r®  r  rÎ  ra   rÓ  rg   rÄ  Ú	threadingÚtimeÚunicodedataÚ
contextlibr   Údataclassesr   Údecimalr   r   Úpathlibr   Útypingr	   r
   r   r   r   r   r€  Úhermes_cli.cli_outputr   Úhermes_cli.colorsr   r   Ú
hermes_clir   Úhermes_cli.default_soulr   r   Úhermes_cli.secret_promptr   rr  r   r   r   r   r   r   r   r   r   r   r    r   r!   r"   r#   Ú	getLoggerr(   re   rò  r$   rÌ  r%   r¤  r  r'   rR   rT   rU   rk   rB   r>   rG   rZ   rq   rw   ÚsystemrÍ   ÚcompilerÓ   r|   ÚtupleÚ	frozensetrÉ   r  rÐ   rØ   ÚRLockr  rÙ   rÚ   r<   rÛ   r  rM  rg  rK  rN  rO  r\  r^  rn  rd  ru  rw  rx  rz  r|  r}  r‚  r‡  rœ  rt   r«  r®  rc  rµ  rº  rÍ  rÎ  rÜ  rÝ  Úhermes_cli.config_defaultsrÞ  rß  Úhermes_cli.config_providersrà  rá  râ  rã  rä  rå  ræ  rç  rè  ré  rê  rë  rì  rí  rî  rï  rð  rñ  rò  ró  rô  rõ  rö  r÷  rø  rù  rú  rû  rv  rü  Ú_NEUTRAL_PERSONALITY_NAMESrý  Ú_prompt_textrþ  rÿ  Ú+resolve_ephemeral_system_prompt_from_configr  r  r  r9  r%  r/  r5  rA  rN  ÚobjectrS  rQ  rU  rX  rr  ru  rƒ  rŽ  r›  rŸ  r¦  rö  ró  r  Ú_VALID_CUSTOM_PROVIDER_FIELDSrô  rÉ  rÏ  rÕ  rö  rû  rü  rß  ræ  rí  rñ  rø  rý  r	  r  r  r!  r(  r3  r7  r?  rG  ri  r\  r]  r  r^  ra  r’  r�  rœ  r²  r¢  ÚMatchr«  r©  r¨  r´  r¸  r¼  r¿  rË  rÑ  rÔ  ræ  rë  rí  Úmaxsizerù  rø  rû  r“  r  r  r`  r[  r  r  r  r  r  r  r!  r�  r&  r(  r,  rÎ   rV  rQ  rS  rX  r[  r_  rn  ru  r~  rx  r‹  r$  r›  rœ  r–  rž  r5  r.  r«  r®  rY  rÀ  r¼  rÕ  rÛ  râ  rè  rí  rë  r>  rú  rÿ  r  r  r  r  r  r  r  r  r"  r*  rD  rE  rC  rJ  rF  rK  rQ  rV  rÁ  re  rz  r™  r©  r³  r¹  rÅ  r×  rÙ  Ú_OPEN_DICT_TOP_LEVEL_KEYSÚ_SCHEMA_DEFINED_DICT_KEYSÚ_DYNAMIC_TOP_LEVEL_KEYSr   r÷  rø  r÷  rþ  r  r  r  r  r  r  r  r  r  r!  r+  r3  r6  r:  r=  rB  r  rE  rI  rL  r`  rg  rm  rr  rv  rx  r|  r  rz  r}  r€  r„  r†  rŽ  r•  r¤  r¥  r£  r´  r¾  rÉ  rË  rÏ  rÓ  rØ  rZ  s   0r.   ú<module>rú     s  ðò=õ =á Ô ã Û Û Û Û 	Û Û 	Û Û Û Û Û 
Û Û Û Û Ý Ý !ß -Ý ß 8× 8ã å ,ß +Ý $ß LÝ 9÷1÷ 1õ 1÷
 Fß @Ñ @à	ˆ×	Ñ	˜8Ó	$€ñ  ›EÐ �cÓ !ð  "Ð ˜Ó !ôO˜\ô Oð
 Kð CØMñOÐ ð
 kð àmÐ ð?˜ið ?¨Có ?ð"˜Yð "¨3ó "ð Waò e¨Tð e¸	ð eÐPSð eÐehó eð ;EòØðØ%ðØ47ðØIMóð@¨°#©ó ð ˆh�o‰oÓ 9Ñ,€Ø�2—:‘:Ð9Ó:Ð ð 0Ð ˜U 3¨ 8™_ó ñ *3ò  45ó  *6Ð ˜	 #™ó  6ðF DHò +˜cð +°(¸4±.ð +ÈCó +ð¨ð °ó ð* ˆy�‰Ó €ð 13Ð ˜t C¨ H™~Ó 2ð 24Ð �D˜˜e C¨ H™oÐ-Ñ.Ó 3à02Ð �4˜˜U 3¨ 8™_Ð,Ñ-Ó 2ñ ò 'Kó 'L€ðX   Ð0Ð ñ �,Ó€
ð,�Dó ,ðsð ðU H¨S¡Mó Uñ 'Ò'jÓkÐ ðD ð D¨°#©ó Dò-¨°©ð -À#ó -ð`˜tó ð= #ð =¨$ó =ð =Ø%ñÐ ðB°#ð B¸#ó Bð3 Có 3ðKÐ ð6" có "ò
D 3ð DÈsó Dò;˜#ó ;ð
R ¨$¡ó RðB-˜ó -ð
 AFò !;¸ð !;È$ó !;ðH&�dó &ð
2˜$ó 2ò
)ò 	ð $ð ¨4ó ñH  ›EÐ �cÓ !ð@Ð ò
F÷& I÷@÷ @÷ @÷ @÷ @÷ @÷ @ó @÷Tó Tò YØ Ð"6Ð7òEà	ÐØ	Ðñ-!Ð �T˜#˜t C™y˜.Ñ)ó !ð Ð ò	(¨ð 	(¸¸dÀ3ÈÀ8¹nÑ9Mó 	(ð˜ð   c¡ó ð6 Tð °$ð ¸8ÀEÈ#ÈsÈ(ÁOÑ;Tó ð$
] ð 
]¨Cð 
]°H¸S±Mó 
]ð:d Có :dð| 9=ÐUYØ òØ�C˜�H‰~ðØ15ðØNRðàðà%)¨#¨s¨(¡^óñ4 ‹8€ð $ó ð> Có ð cð ¨dó ñ* ò 
&ó 
'Ð ð
1˜Cð 
1 Dó 
1ð
°ð 
¸ó 
ð 4¨¨S°#¨X©Ñ#7ó ð&] t¨D°°c°©NÑ';ó ]ð* #ð ¨#ó ð :?ò #I°$ð #IÀ5ÈÈcÈÁ?ó #IòVÐ ñ& Ð0˜^×0Ò0Ó2Ó3Ð6LÑLÐ ò!@Ð ò  WÐ ð ÷ð ó ðð8�4˜Ñ&ð 8°#ð 8Àð 8È3ð 8ÐSWó 8ð 8:ò[Ø�Ñð[Ø(,¨S°#¨X©ð[Ø?Bð[à�%˜˜S˜‘/ 3Ð&Ñ'ð[à14ð[à>Bó[ðZÐ ð+Ð ðKÐ ð
f˜D  c ™Nð f°D¸Ñ4Eð fÈ$ó fðZ˜t C¨ H™~ð Z°t¸KÑ7Hð ZÈTó ZðB
DØð
DØð
DØ'+¨KÑ'8ð
DØOTÐUXÐZ]Ð_bÐUbÑOcð
Dà	ó
Dð |€ðY 3ð Y°°[Ñ0Að YÀdó Yð,A ð A¨d°;Ñ.?ð AÀDó Að\ 4¨¨S¨¡>ð \¸4ÀÑ;Lð \ÐQUó \ð2˜$˜s C˜x™.ó ð&:¨¨S°#¨X©ð :ÀÀ[Ñ@Qð :ÐVZó :ò.( h¨t°C¸°H©~Ñ&>ð (È$È}ÑJ]ó (òV0 (¨4°°S°©>Ñ":ð 0Àdó 0ô"4ð4˜t C¨ H™~ð °$ó ð˜sð ¨$¨s°C¨x©.ð À#ð ÐPTÐUXÐZ]ÐU]ÑP^ð Ðcgó ð"˜ð " ó "òL ð L°Dð LÀTÈ#ÈsÈ(Á^ó Lð^#¨T°#°s°(©^ð #ÀDð #ÈTó #ð<N¨T°#°s°(©^ð NÀDð NÈTó Nð"
˜ð 
 T¨#¡Yð 
¸#ð 
À$ó 
ð¨cð ¸sð ÈTÐRUÐWZÐRZÉ^ð Ð`dó ð,°4¸¸SÀ#¸X¹Ñ3Gð ÐRVÐWZÐ\_ÐW_ÑR`ð Ðeió ð6˜Tð ¨Tð °dó ð�dð  dð ¨tó ð$˜Dð ¨sð °u¸TÀ3¸YÑ7Gó ð ˆb�j‰j˜Ó(€ð˜#ð  (¨3¡-ó ð&˜Ÿšð  có ð6K ð K¨ó Kð
˜3ð  8¨C¡=ó òôò0ô$ðN 4¨¨S¨¡>ð °c¸%ÀÀSÀ¹/Ñ6Jó ð" 8FØ48ñ.Ø��c�‰Nð.Ø&*¨3°¨8¡nð.à˜C  c¨3 h¡Ñ0Ñ1ð.à=AÀ#ÀsÀ(¹^ó.ð*0¨Cð 0°E¸#¸s¸(±Oó 0ðR t¨C°¨H¡~ð R¸$¸sÀC¸x¹.ó Rðj	¨¨S°#¨X©ð 	¸4ÀÀSÀ¹>ó 	ðK  c¨3 h¡ð K°D¸¸c¸±Nó Kð —{’{Ð ñ !ò "Ró SÐ ð 1Eñ 1˜Cð 1¨#ð 1Èó 1ð8 GKò �˜$˜s C˜x™.Ñ)ð °#ð Àð Èsó ð Cð °E¸#¸s¸(±Oð ÈÐQUÐVYÐ[^ÐV^ÑQ_ÑH`ó ð)6¨Dð )6°T¸#¸s¸(±^ó )6ðX5˜˜c 3˜h™ó 5ò2 h¨t¡nð 2ÀÀSÈ#ÀXÁó 2ð6 $ s¨C x¡.ó 6ð0 4ð 0°ð 0¸9ð 0È3ð 0ÐS_ó 0ð6˜có 6ð
 @€
ð,ð 
ò
 °h¸t±nð  ÐPTÐUXÐZ]ÐU]ÑP^ô  ðF nrò c Tð c°°c¸3°h±ð cÐ]eÐfiÑ]jð cÐvzô cð1�T˜#˜s˜(‘^ô 1ð2˜d 3¨ 8™nô 2ð˜˜c 3˜h™ð ¨cð °d¸3À¸8±nô ð CHòØðØ"%ðØ.1ðØ;?ðØLPôð ˆ~ðIðGö
Hàð 	ˆy˜Ÿš›˜Ð&Ñ&ò
HðIÑ ðP˜sð P sô PðS¨cð S¸#ð SÀ$õ Sñ
M°Cð M¸CÀ¹Hõ Mðh¨ð h°¸#±õ hð
] cñ ]°ð ]¸õ ]ð (,ÐPTØ#ô(Ø�T˜#˜s˜(‘^Ñ$ð(Ø5=¸dÀ3ÈÀ8¹nÑ5Mð(à�t‰nð(à(,¨S°#¨X©õ(ðVA¨ð A°°xÀÀcÈ3ÐPSÐUXÐFXÑ@YÑ7ZÐ\dÐejÐknÐpsÐksÑetÑ\uÐ7uÑ1võ Að("¨4ð "¸3ð "ÐPYð "Ð^fÐgkÐloÐqtÐltÑguÑ^võ "ñJW T¨#¨s¨(¡^ð W¸¸dÀ3ÈÀ8¹nÈcÐ>QÑ8Rõ Wð$ Sñ °Sð ¸XÀdÈ3ÐPSÈ8ÁnÑ=Uõ ðH¨ð H°°c¸3°h±õ HñVÑ ñ$Ñ ð2¨¨c°3¨h©ð ¸DÀÀcÀ¹Nõ ñ	"¨T°#°s°(©^ð 	"ÀÈÁõ 	"ð 7;Ø48ÐQVó)\Ø��c�‰Nñ)\Ø/3ð)\à˜C  c¨3 h¡Ñ0Ñ1ñ)\àJNõ)\ðX)�$�s˜C�x‘.õ )ö ñ
˜tð 
¨õ 
ð˜3õ ñ"2˜dð 2 tõ 2ñ˜tñ ¨Dñ ÀDð ÈTõ ð> Sð °ð ¸õ ð*˜Cð  Cõ ð PTó : ð :¨#ð :¸hÀt¹nð :ÐX\õ :ð, ˜Cð  ¨°©ð  ¸$õ  ð:˜Cð ¨ð °õ ñ L˜cõ Lð˜ð  Cõ ñ6P cð P¨cõ Pð˜#ð  $õ ñ*ÐZ^ô  #ñ °ñ ÐSWõ ò/ cõ /ö
,ò
B #õ Bð
	C˜sð 	C¨3ð 	C°4¸¸S¸±>õ 	Cð�Cõ ð"#˜Sð # X¨c¡]õ #ð 7�sð 7˜x¨™}õ 7ð; Sð ;¨X°c©]õ ;ðB�Cð B˜Cõ Bñ  ó !$ó %Ñ ñ dÑ ñ SÑ Ø �b—j‘jÑ!BÓCÑ ðU˜sð U tõ Uò˜sñ ¨Cð ¸õ ñ&;�Cð ;˜Dõ ;ö
`ñ 
Ñ ðN  S¨# X¡ð N°4õ Nð q $ s¨C x¡.ð q°Tõ qð& 4¨¨S¨¡>ð °dõ ð:2 d¨3°¨8¡nð 2¸õ 2ð04  S¨# X¡ð 4°4õ 4öô",ô^/ð24 sõ 4ñ &ó '!ó "Ñ ñ &ó 'ó Ñ ñ $Ùð%ó Ñ ñ %¡k ]Ó3Ñ ñ 8Ñ:QÑQÑTmÑmÑ ðV˜s 3™xõ Vòd˜cñ d¨s°3©xñ dÁð dÐQYÐZ]ÑQ^õ dð
>˜cð > e¨D°(¸3±-Ð,?Ñ&@õ >ðB Sñ °h¸s±mð Èõ ð( 3ð ¨4õ ð*�sõ ð	˜õ 	ð ˜ TØ˜%¨ð ˜$ Tò+�ð #ð ¨cð °cõ ñH ÙÙÙñ ÙÙ(.ò
Ñ ñ !*Ñ+DÑFWÐ*XÓ YÑ ð #ñ °D¸¸c¸±Nð ÀxÐPSÁ}õ ð$+¨ð +°Sñ +ÀtÈCÐQTÈHÁ~ñ +Ð^bð +Ðgjõ +ð,Y¨ð Y°°c¸8ÀC¹=Ð6HÑ0Iõ YñD°ð ¸À#¹õ ð˜cð ¨3ð °4õ ð! #ð !¨cñ !ÀÀSÈ#ÀXÁñ !ÐW[ð !Ð`cõ !ðH	˜#ð 	 cð 	¨dõ 	ñ�sð ˜tõ ð
2 Dñ 2°t¸CÀ¸H±~ð 2È$õ 2ðI 3ñ I°H¸S±Mð IÀdõ Ið" ñ °(¸3±-ð ÀCõ òy3˜#ð y3 cñ y3°$õ y3ðx 38ÀUó 2^˜#ð 2^¨4ð 2^¸dõ 2^ðj.1˜Cõ .1óf�sñ  d¨3¡iñ ¸ÀÀcÁÑ8Kð ÐW[õ ö$ñ @ó B.à/3ð5�
ñ Aó C6ó8HðI�
ñ
 3ó 5.à/3ð5�ô
gôZô0ð=˜˜S #˜X™ñ =¨Sð =°Sõ =ñ
˜ð  õ ô%ôPò< %Ú&Ú&ÙÙÙÚ1Ú2Ù"Ùò
 Ñ ñ	1�ô
öò0 Ô ô'ö8ò> !Ô "ò2¨x¸©~ð 2Èõ 2ò ð °H¸T±Nð Èdõ ñ, Ñ YðÑ õ
BùòY<
Hs   Þu2