+
    jHàj[  ã            	       ó’  a€ R9 t>0 t R t^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	H
t
 ^ RIHt ^ RIHt ^ RIHtHtHtHtHt ^ RIHtHt ^ RIHt ^ RIHt ^ R	IHt ]P<                  ! R
4      tR R lt R R lt!]	R R l4       t"R R lt#R R lt$R R lt%R R lt&R:t'R R lt(R R lt)R R lt*R R  lt+R! R" lt,R# R$ lt-]P\                  ! 4       t/]	R% R& l4       t0]	R' R( l4       t1R; U u. uF  p ]2! ]3! R<V 4      4      NK  	  up t4] ^ k R) R* lt5R=t6R+ R, lt7R- R. lt8R/ R0 lt9R1 R2 lt:R3 R4 lt;R5 R6 lt<R>R7 R8 llt=R# u up i )?z®Profile-scoped helpers: profile discovery fallback, profile dir/MCP-server writes,
the profile/config scope context managers, skills-hub and tools/analytics catalog helpers.
N)ÚcontextmanagerÚnullcontext)ÚHTTPException)ÚPath)ÚAnyÚCallableÚDictÚListÚOptional)ÚDEFAULT_CONFIGÚget_process_hermes_home)ÚMCPServerCreate)Ú_ACTION_LOG_FILES)Ú_normalize_mcp_server_createzhermes_cli.web_serverc                óV   € V ^8„  d   QhR\         . \        3,          R\        R\        /# )é   Ú	callable_ÚdefaultÚreturn)r   r   )Úformats   "ÚC/home/ubuntu/.hermes/hermes-agent/hermes_cli/web_server_profiles.pyÚ__annotate__r      s*   € ÷ ñ ”X˜b¤#˜gÕ&ð ´ð ¼ñ ó    c                 ó8   €  V ! 4       #   \          d    Tu # i ; i©N)Ú	Exception)r   r   s   &&r   Ú_safer      s#   € ðÙ‹{ÐøÜô ØŠðús   ‚	 ‰˜c                óF   € V ^8„  d   QhR\         \        ,          R\        /# ©r   Úprofiler   ©r
   ÚstrÚbool)r   s   "r   r   r      s   € ÷ ;ñ ;¤¬#¥ð ;´4ñ ;r   c                óz   € T ;'       g    RP                  4       pV'       * ;'       g    VP                  4       R8H  # )z7None/""/"current" all mean the dashboard's own profile.Ú Úcurrent)ÚstripÚlower)r   Ú	requesteds   & r   Ú_is_current_profiler)      s2   € à—�˜B×%Ñ%Ó'€IØŒ=×:Ð:˜IŸO™OÓ-°Ñ:Ð:r   c                ó$   € V ^8„  d   QhR\         /# ©r   r   )r   )r   s   "r   r   r   &   s   € ÷ *ñ *¤ñ *r   c              #  ót   "  € ^ RI HpHp V! \        V 4      4      p Rx € V! V4       R#   T! T4       i ; i5i)z£Scope ``load_config``/``save_config`` (anything resolving ``get_hermes_home()`` at call
time) to ``path`` for the block via the context-local HERMES_HOME override.)Úset_hermes_home_overrideÚreset_hermes_home_overrideN)Úhermes_constantsr-   r.   r!   )Úpathr-   r.   Útokens   &   r   Ú_hermes_home_scoper2   %   s2   é € ÷ VÙ$¤S¨£YÓ/€Eð*Ûá" 5Ö)øÑ" 5Õ)üs   ‚8�+ ¡
8«
5µ8c                ó$   € V ^8„  d   QhR\         /# r+   ©r!   )r   s   "r   r   r   1   s   € ÷ ñ œcñ r   c                 óî   € ^ RI Hp   V P                  4       ;'       g    RP                  4       pV'       d   VR8X  d   R# V P	                  V\        4       4      '       d   V# R#   \         d     R# i ; i)uz  This process's OWN profile name â€” but only when that name provably resolves back
to the process home.

The dashboard SPA needs an explicit scope for requests it fires before the profile
switcher has resolved: a destructive route now 400s on an unnamed profile as soon as
the host serves more than one, and "" would otherwise mean "whichever home this
process launched with" anyway. Naming it is only safe if the name cannot resolve
ELSEWHERE, so a custom HERMES_HOME outside ``profiles/`` (``get_active_profile_name()``
answers ``"custom"``) returns "" and keeps the old unnamed behaviour rather than
risking a wrong-profile write.
©Úprofilesr$   Úcustom)Ú
hermes_clir7   Úget_active_profile_namer&   Úprofile_matches_homer   r   )Úprofiles_modÚnames     r   Úserving_profile_namer>   1   sl   € õ 4ðØ×4Ñ4Ó6×<Ð<¸"×CÑCÓEˆß�t˜xÔ'ÙØ#×8Ñ8¸Ô?VÓ?X×YÒYˆtÐaÐ_aÐaøÜô Úðús'   ˆA% ŸA% ¸A% Á!A% Á#A% Á%A4Á3A4c                óF   € V ^8„  d   QhR\         \        ,          R\        /# r   r    )r   s   "r   r   r   G   s"   € ÷ Cñ Cœx¬�}ð C´ñ Cr   c                óÒ   € \        V 4      '       d   R#  \        V P                  4       4      pTP	                  4       \        4       P	                  4       8g  #   \         d     R# i ; i)zDTrue when ``profile`` names a profile other than this process's own.FT)r)   Ú_resolve_profile_dirr&   r   Úresolver   )r   Útargets   & r   Ú_is_other_profilerD   G   sZ   € ä˜7×#Ò#ÙðÜ% g§m¡m£oÓ6ˆð �>‰>ÓÔ6Ó8×@Ñ@ÓBÑBÐBøô ô Úðús   •A ÁA&Á%A&c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# )r   Úconfigr   ©Údictr!   r   )r   s   "r   r   r   R   s"   € ÷ 	*ñ 	*œd¤3¬ 8�nð 	*´ñ 	*r   c                óô   € ^ RI Hp V P                  R4      p\        P                  ! R4      ;'       g    / P                  RR4      p\	        V\
        4      '       d   VP                  RV4      MTpV! V4      # )aK  Normalize approvals.mode from an in-memory config document. Both sides of the
broadcast comparison use in-memory documents: re-reading through the config cache after
a save can serve the pre-save document when the replacement file collides on the
(mtime_ns, size) cache key, suppressing the broadcast exactly when the mode changed.)Ú_normalize_approval_modeÚ	approvalsÚmodeÚmanual)Útools.approval_contextrJ   Úgetr   Ú
isinstancerH   )rF   rJ   rK   Údefault_moderL   s   &    r   Ú_approval_mode_ofrR   R   se   € õ
 @Ø—
‘
˜;Ó'€IÜ"×&Ò& {Ó3×9Ð9°r×>Ñ>¸vÀxÓP€LÜ2<¸YÌ×2MÒ2Mˆ9�=‰=˜ Ô.ÐS_€DÙ# DÓ)Ð)r   c                ó   € V ^8„  d   QhRR/# )r   r   N© )r   s   "r   r   r   ^   s   € ÷ 	Jñ 	J¨ñ 	Jr   c                 óÀ   € \         P                  P                  R4      p V f   R#  V P                  4        R#   \         d    \
        P                  R4        R# i ; i)z¢Broadcast session.info on the in-process gateway when it's loaded (``sys.modules``
guard, not an import: gateway never imported means no live sessions to notify).ztui_gateway.serverNz/session.info broadcast after config save failed)ÚsysÚmodulesrO   Úbroadcast_session_infor   Ú_logÚ	exception)Úservers    r   Ú_broadcast_gateway_session_infor\   ^   sO   € ô �[‰[�_‰_Ð1Ó2€FØ‚~ÙðJØ×%Ñ%Ö'øÜô JÜ�‰ÐH×IðJús   §9 ¹ AÁAc                óh   € V ^8„  d   QhR\         R\        \        \        \        3,          ,          /# ©r   Úrespr   )r   ÚlistrH   r!   )r   s   "r   r   r   m   s'   € ÷ ñ œsð ¤t¬D´´c°­NÕ';ñ r   c                ó¦  €  V P                   '       g   . # V P                  4       p\        T\        4      '       d   TP                  R4      MTp\        T\        4      '       g   . # . pT FÏ  p\        \        T\        4      '       d   TP                  R4      MT;'       g    R4      P                  4       pT'       g   KW  RT/p\        T\        4      '       dN   \         FC  p\        TP                  T4      ;'       g    R4      P                  4       pT'       g   K?  Y†T&   KE  	  TP                  T4       KÑ  	  T#   \         d    . u # i ; i)aÀ  Model rows from an OpenAI-compatible ``/v1/models`` response as ``{"id": ..}`` dicts,
keeping the alias metadata a gateway may advertise (``canonical_model``,
``reasoning_effort``). Flattening to bare ids lost that, so Desktop stored a reasoning
alias as the literal upstream model (#93622). Accepts ``{"data": [{"id": ..}]}`` or a
bare ``{"data": ["id", ..]}``; ``[]`` on any parse/HTTP error so a slightly
non-standard endpoint never hard-blocks.ÚdataÚidr$   )Ú
is_successÚjsonr   rP   rH   rO   r`   r!   r&   Ú_MODEL_ENTRY_METADATAÚappend)	r_   Úpayloadrb   ÚentriesÚitemÚmodel_idÚentryÚkeyÚvalues	   &        r   Ú_parse_model_entriesro   m   s  € ðØ��ˆØˆIØ—)‘)“+ˆô #-¨W´d×";Ò";ˆ7�;‰;�vÔÀ€DÜ�dœD×!Ò!Øˆ	Ø$&€GÛˆÜ¬*°T¼4×*@Ò*@˜Ÿ™ œÀd×QÐQÈrÓR×XÑXÓZˆßÙØ�xÐ ˆÜ�dœD×!Ò!ß,�Ü˜DŸH™H S›M×/Ð/¨RÓ0×6Ñ6Ó8�ß‘5Ø!&˜#“Jñ -ð 	�‰�uÖñ ð €Nøô# ô ØŠ	ðús   ‚E  ”E  –E  Å EÅEc                óF   € V ^8„  d   QhR\         R\        \        ,          /# r^   )r   r`   r!   )r   s   "r   r   r   Œ   s"   € ÷ Añ Aœ3ð A¤4¬¥9ñ Ar   c                óN   € \        V 4       Uu. uF  qR,          NK  	  up# u upi )zQBare model ids from a ``/v1/models`` response (see :func:`_parse_model_entries`).rc   )ro   )r_   rl   s   & r   Ú_parse_model_idsrr   Œ   s%   € ä%9¸$Ô%?Ó@Ñ%?˜E�$�KˆKÑ%?Ñ@Ð@ùÒ@s   Ž"c                óœ   € V ^8„  d   QhR\         R\        R\        R\        R\        . \        3,          R\        \         \
        3,          /# )r   r=   ÚhomeÚ
is_defaultÚhas_envÚgateway_runningr   )r!   r   r"   r   rH   r   )r   s   "r   r   r   ‘   sO   € ÷ ñ ´ð ¼4ð ÔPTð Ü%)ðÜ<DÀRÌÀXÕ<NðÜSWÔX[Ô]`ÐX`ÕSañr   c                óè   a a€ \        VV 3R  lR4      w  rgVV 3R lpRVR\        S4      RVRVRVRVR	\        VV 3R
 l^ 4      R\        VR4      RV! RR4      RV! RR4      RV! RR4      RRRRRRRR/# )c                  ó&   <€ SP                  S 4      # r   )Ú_read_config_model©rt   r<   s   €€r   Ú<lambda>Ú)_fallback_profile_entry.<locals>.<lambda>“   s   ø€  L×$CÑ$CÀDÔ$Ir   Nc                 ó.   <a a€ \        VVV V3R  lS4      # )c                  óF   <€ SP                  S4      P                  SS 4      # r   )Úread_profile_metarO   )r   rt   rm   r<   s   €€€€r   r|   Ú;_fallback_profile_entry.<locals>.<lambda>.<locals>.<lambda>•   s   ø€ �×.Ñ.¨tÓ4×8Ñ8¸¸gÔFr   )r   )rm   r   rt   r<   s   ff€€r   r|   r}   ”   s   ú€ ¤ßFÈô!Qr   r=   r0   ru   ÚmodelÚproviderrv   Úskill_countc                  ó&   <€ SP                  S 4      # r   )Ú_cached_skill_countr{   s   €€r   r|   r}   ™   s   ø€  \×%EÑ%EÀdÔ%Kr   rw   FÚdescriptionr$   Údescription_autoÚ	bot_titleÚdistribution_nameÚdistribution_versionÚdistribution_sourceÚ	has_alias)NN)r   r!   )	r<   r=   rt   ru   rv   rw   r‚   rƒ   Úmetas	   f&f$$$   r   Ú_fallback_profile_entryr�   ‘   s˜   ù€ äÕIÈ<ÓX�O€EõQ€Dð 	��fœc $›i¨°zÀ7ÈEØ�H˜i¨Ø”uÕKÈQÓOØœ5 °%Ó8Ø‘t˜M¨2Ó.Ð0BÁDÐI[Ð]bÓDcØ‘T˜+ rÓ*Ø˜TÐ#9¸4ÐAVÐX\Ø�Uðð r   c                ó\   € V ^8„  d   QhR\         \        \        \        3,          ,          /# r+   ©r`   rH   r!   r   )r   s   "r   r   r   ¡   s    € ÷ ñ ¬T´$´s¼C°xµ.Õ-Añ r   c                 ó  a aa€ . pS P                  4       oSP                  4       '       d;   VP                  \        S R SRSR,          P	                  4       VV 3R lR7      4       S P                  4       pVP                  4       '       dá   \        P                  ! V4      ;_uu_ 4       p\        VR R7      pRRR4       X F¥  p\        VP                  4      oVP                  4       '       d,   S P                  P                  VP                  4      '       g   K[  VP                  \        S VP                  SR\        V3R	 lR4      SVP                  3V 3R
 llR7      4       K§  	  V#   + '       g   i     L½; i)r   Tú.envc                  ó&   <€ SP                  S 4      # r   )Ú_check_gateway_running)Údefault_homer<   s   €€r   r|   Ú)_fallback_profile_dicts.<locals>.<lambda>¨   s   ø€  L×$GÑ$GÈÔ$Ur   )ru   rv   rw   c                 ó   € V P                   # r   )r=   )Úes   &r   r|   r—   °   s   € °·²r   )rm   NFc                  ó2   <€ S R ,          P                  4       # )r“   )Úexists)rt   s   €r   r|   r—   ·   s   ø€  t¨f¥}×&<Ñ&<Ô&>r   c                 óX   <€ SP                  V 4      ;'       g    SP                  V4      # r   )r•   Ú_served_by_running_multiplexer)rt   r=   r<   s   &&€r   r|   r—   ¸   s1   ø€ Ø ×7Ñ7¸Ó=÷ Ið IØ#×BÑBÀ4ÓHðIr   )Ú_get_default_hermes_homeÚis_dirrg   r�   r›   Ú_get_profiles_rootÚosÚscandirÚsortedr   r0   Ú_PROFILE_ID_REÚmatchr=   r   )r<   r7   Úprofiles_rootÚscanri   rl   r–   rt   s   f     @@r   Ú_fallback_profile_dictsr¨   ¡   s)  ú€ Ø%'€HØ×8Ñ8Ó:€LØ×Ñ×ÒØ�‰Ô/Ø˜) \¸dØ! FÕ*×2Ñ2Ó4ÝUôWô 	Xð
 !×3Ñ3Ó5€MØ×Ñ×Òô �ZŠZ˜×&Ô&¨$Ü˜TÑ'7Ô8ˆG÷ 'ãˆEÜ˜Ÿ
™
Ó#ˆDØ—<‘<—>’>¨×)DÑ)D×)JÑ)JÈ5Ï:É:×)VÒ)VÙØ�O‰OÔ3Ø˜eŸj™j¨$¸5ÜÔ>ÀÓFØ,0°u·z±zö !JôKö Lñ	 ð €O÷ '×&ús   Â*E.Å.E>	c                ó0   € V ^8„  d   QhR\         R\        /# )r   r=   r   )r!   r   )r   s   "r   r   r   ¾   s   € ÷ 	.ñ 	.œsð 	.¤tñ 	.r   c                óö   € ^ RI Hp  VP                  V 4       TP                  T 4      '       g   \	        RRT  R2R7      hTP                  T 4      #   \         d   p\	        R\        T4      R7      hRp?ii ; i)zIValidate ``name`` and resolve to its directory or raise an HTTPException.r6   i�  )Ústatus_codeÚdetailNi”  z	Profile 'z' does not exist.)r9   r7   Úvalidate_profile_nameÚ
ValueErrorr   r!   Úprofile_existsÚget_profile_dir)r=   r<   r™   s   &  r   rA   rA   ¾   sv   € å3ð<Ø×*Ñ*¨4Ô0ð ×&Ñ& t×,Ò,Ü¨°iÀ¸vÐEVÐ4WÔXÐXØ×'Ñ'¨Ó-Ð-øô	 ô <Ü¨´C¸³FÔ;Ð;ûð<ús   ˆA ÁA8ÁA3Á3A8c                óR   € V ^8„  d   QhR\         R\        \        ,          R\        /# )r   Úprofile_dirÚserversr   )r   r`   r   Úint)r   s   "r   r   r   Ê   s'   € ÷ ñ ¬Dð ¼4ÄÕ;Pð ÔUXñ r   c           	     ó@  € ^ RI HpHp ^ RIHp ^ p\        V 4      ;_uu_ 4        V! 4       pVP                  R/ 4      pV F.  p \        V4      w  ršpTe   T! Y›4      T
R&   Y§T	&   T^,          pK0  	  V'       d
   V! V4       M"V'       g   VP                  RR4       V! V4       RRR4       V#   \         dP   pTP                  ;'       g    RP                  4       ;'       g    Rp\        P                  RYÜ4        Rp?KÄ  Rp?ii ; i  + '       g   i     T# ; i)	z÷Write MCP server entries into ``profile_dir``'s config.yaml (HERMES_HOME-scoped).

Mirrors the per-server shape ``POST /api/mcp/servers`` builds, batched so the whole
profile-create write is one config save. Returns the number of servers written.
)Úload_configÚsave_config)Ú_save_bearer_auth_tokenÚmcp_serversr$   z	<unnamed>z,Profile-create: skipping MCP server '%s': %sNÚheaders)Úhermes_cli.configr¶   r·   Úhermes_cli.mcp_configr¸   r2   Ú
setdefaultr   r®   r=   r&   rY   ÚwarningÚpop)r²   r³   r¶   r·   r¸   ÚwrittenÚcfgÚmcpr[   r=   rl   Úbearer_tokenÚexcÚdisplay_names   &&            r   Ú_write_profile_mcp_serversrÆ   Ê   sþ   € ÷ ;Ý=Ø€GÜ	˜K×	(Õ	(Ù‹mˆØ�n‰n˜]¨BÓ/ˆÛˆFðÜ,HÈÓ,PÑ)�˜\ð
 Ò'Ù#:¸4Ó#N��iÑ Ø�‰IØ�q�LŠGñ ÷ Ù˜Õßà�G‰G�M 4Ô(Ù˜Ô÷' 
)ð( €Nøô ô Ø &§¡× 1Ð 1¨r×8Ñ8Ó:×IÐI¸k�Ü—‘ÐKÈ\Ô_Ýûðú÷ 
)Ö	(ð( €NúsG   ¤DÁB/Á'DÁ:DÂDÂ/D		Â:*D	Ã%D	Ã>DÄD		Ä	DÄD	c                ó:   € V ^8„  d   QhR\         \        ,          /# ©r   r   ©r
   r!   )r   s   "r   r   r   ó   s   € ÷ Cñ CœH¤S�Mñ Cr   c           
   #  óB  "  € ^ RI Hp ^ RIHp ^ RIHp \        V 4      ;_uu_ 4       pVf   V! 4       MTpW#3p\        ;_uu_ 4        V Uu. uF  qwP                  VP                  3NK  	  ppV F  pWUR,          uVn        Vn        K  	   Vx € \        Wh4       F  w  pw  ršWšuVn        Vn        K  	   RRR4       RRR4       R# u upi   \        Yh4       F  w  pw  ršYšuTn        Tn        K  	  i ; i  + '       g   i     LI; i  + '       g   i     R# ; i5i)a�  Scope config + skill-directory resolution to ``profile`` for one request.

Two seams: (1) ``load_config``/``save_config`` resolve ``get_hermes_home()`` at call
time, so the contextvar override reaches them; (2) ``tools.skills_tool`` /
``tools.skill_manager_tool`` bind ``SKILLS_DIR`` at import time, so both are retargeted
under a lock and restored after. For the dashboard's own profile config resolution is
untouched, but the skill-module globals are still retargeted to the *current*
``get_hermes_home()`` so writes land in the live home even when the import-time binding
is stale (test isolation, late HERMES_HOME override). Yields the profile dir for a named
profile, None for the current one.

``tools.skills_sync`` (reset/diff/list-modified/opt-in/opt-out/ repair-official) needs NO retargeting:
since #65828 its directory lookups resolve at call time through the same contextvar override set in step
1.
)Úget_hermes_home)Úskills_tool)Úskill_manager_toolNÚskills)
r/   rË   ÚtoolsrÌ   rÍ   Ú_config_profile_scopeÚ_SKILLS_PROFILE_LOCKÚHERMES_HOMEÚ
SKILLS_DIRÚzip)r   rË   Ú_skills_toolÚ
_skill_mgrÚscopedr²   rW   ÚmÚsavedrt   Ú
skills_dirs   &          r   Ú_profile_scoperÛ   ò   s÷   é € õ" 1Ý1Ý6Ü	˜w×	'Ô	'¨6Ø+1ª>‘oÔ'¸vˆØÐ,ˆß!Ö!Ù<CÓD¹G°q—m‘m Q§\¡\Ó2¹GˆEÐDÛ�Ø.9ÈÕ;QÐ+�”˜qž|ñ ðCØ’ä-0°Ö-@Ñ)�AÑ)˜Ø26Ð/�A”M 1¦<ò .A÷ "÷ 
(Ñ	'ùò Eøô .1°Ö-@Ñ)�AÑ)˜Ø26Ð/�A”M 1¦<ò .Aú÷ "×!ú÷ 
(×	'Ð	'üs^   ‚&D¨DÁC8	Á C	Á, C8	ÂCÂ%C8	Â7DÂ?
DÃ	C8	Ã'C5Ã5C8	Ã8DÄDÄD	Ä	Dc                ó:   € V ^8„  d   QhR\         \        ,          /# rÈ   rÉ   )r   s   "r   r   r     s   € ÷ /&ñ /&¤8¬C¥=ñ /&r   c           	   #  ón  "  € ^ RI HpHpHp ^ RIHp ^ RIHpHp ^ RI	H
pHp \        4       p	\        V 4      '       d   V! 4       '       d   V! 4       MRp
M\        V P                  4       4      p
V
e$   V
P!                  4       V	P!                  4       8X  d   RMT
pVe   V! 4        V! V4       V! V4      pMV! V	4      pV
e   \#        V
4      M	\%        4       ;_uu_ 4        T! T\'        T
;'       g    T	4      R7      p Vx € V! V4        RRR4       R#   T! T4       i ; i  + '       g   i     R# ; i5i)aD  Await-safe profile scope: the task-local HERMES_HOME contextvar PLUS the profile's secret
scope, never the process-global skills-module attributes ``_profile_scope`` swaps (holding
those across an ``await`` lets a concurrent request restore THIS request's dir on its
``finally``). None/""/"current" = no override.

Home alone left ``get_secret`` on the dashboard process's ``os.environ`` - the DEFAULT
profile's values - so ``GET /api/config?profile=B`` expanded B's ``${VAR}`` refs to the default
profile's plaintext credentials and ``load_gateway_config()`` under B's home bridged B's YAML
settings into the shared process env (``yaml_env_setter`` skips only under a secret scope).
A request for another profile's home also flips this process to fail-closed multi-profile
hosting (``tui_gateway/launch_profile_policy.py``), so any remaining unscoped read raises
instead of borrowing; the dashboard's own profile then runs under its frozen-launch-env scope.

Explicit names resolving to the process home retain current-profile semantics.
Still enter the requested home so a nested scope cannot retain another profile.
None/""/"current" mean the request's EFFECTIVE home: a task-local override (a secondary
profile's native ticket, ``native_profile_scope``) is that profile, so it gets that profile's
secret scope rather than the launch profile's.
)Úbuild_profile_secret_scopeÚreset_secret_scopeÚset_secret_scope)Úhydrate_profile_secret_sources)rË   Úget_hermes_home_override)Úactivate_multi_profile_hostingÚlaunch_secret_scopeN)Úprofile_home)Úagent.secret_scoperÞ   rß   rà   Úhermes_cli.env_loaderrá   r/   rË   râ   Ú!tui_gateway.launch_profile_policyrã   rä   r   r)   rA   r&   rB   r2   r   r!   )r   rÞ   rß   rà   rá   rË   râ   rã   rä   Úprocess_homer²   r×   Úsecretsr1   s   &             r   rÐ   rÐ     s   é € ÷* dÑcÝDßJßeä*Ó,€LÜ˜7×#Ò#Ù+C×+EÒ+E‘oÔ'È4‰ä*¨7¯=©=«?Ó;ˆØ Ò(¨K×,?Ñ,?Ó,AÀ\×EYÑEYÓE[Ô,[‰TÐal€FØÒÙ&Ô(Ù& vÔ.Ù,¨VÓ4‰ñ & lÓ3ˆØ-8Ò-DÔ
˜[Ô
)Ì+Ë-×
WÑ
WÙ  ´s¸;×;VÐ;VÈ,Ó7WÔXˆð	&ØŠLá˜uÕ%÷ XÑ
Wøñ
 ˜uÕ%ú÷ X×
WÐ
Wüs=   ‚AD5ÁBD5ÃD!Ã=DÄD!Ä

D5Ä
DÄD!Ä!D2	Ä,	D5c                ó\   € V ^8„  d   QhR\         \        \        \        3,          ,          /# r+   )r`   rH   r!   )r   s   "r   r   r   Z  s    € ÷ ñ ¤t¬D´´c°­NÕ';ñ r   c            	     ó`  € . p  ^ RI Hp V! 4         ^ RIHp V! 4        FU  p V P                  RVP                  P                  4       P                  4       RVP                  RVP                  /4       KW  	  V #   \         d     Lvi ; i  \         d     Kz  i ; i  \         d    T u # i ; i)z@Picker rows for plugin-registered terminal backends (fail-soft).)Údiscover_plugins)Úlist_providersr=   Úlabelr‡   )Úhermes_cli.pluginsrí   r   Úagent.terminal_env_registryrî   rg   r=   r&   r'   rÅ   r‡   )Úrowsrí   rî   rƒ   s       r   Ú_plugin_terminal_backend_rowsró   Z  s²   € à!#€DðÝ7ÙÔð	Ý>Ù&Ö(ˆHðØ—‘˜V X§]¡]×%8Ñ%8Ó%:×%@Ñ%@Ó%BÀGÈX×MbÑMbØ*¨H×,@Ñ,@ðBö Cñ )ð €Køô ô Ùðûô ô Úðûäô ØŠðúsF   „A: ’B £ABÁ4B Á:BÂBÂBÂB ÂBÂB ÂB-Â,B-c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# )r   Úrowr   rG   )r   s   "r   r   r   s  s&   € ÷ Lñ L”tœC¤˜H•~ð L¬#ñ Lr   c                 óx   € V P                  R 4      ;'       g    ^ V P                  R4      ;'       g    ^ ,           # )Úinput_tokensÚoutput_tokens)rO   )rõ   s   &r   Ú_token_volumerù   s  s/   € Ø�G‰G�NÓ#×(Ð( q¨S¯W©W°_Ó-E×-JÐ-JÈÕKÐKr   c                óh   € V ^8„  d   QhR\         R\        \        \        \        3,          ,          /# )r   Úcutoffr   )Úfloatr`   rH   r!   r   )r   s   "r   r   r   w  s'   € ÷ ñ ¤ð ¬$¬t´C¼°H­~Õ*>ñ r   c                óÀ   €  V P                   P                  RV34      pVP                  4        Uu. uF  p\        V4      NK  	  up# u upi   \         d    . u # i ; i)zõPer-(model, task) auxiliary usage within the window: the task-dimension rows
(task != '') record_auxiliary_usage writes into session_model_usage. [] when the
table predates the task column (older DB opened read-only by newer code).

See #23270.
ai  
            SELECT u.model,
                   u.task,
                   u.billing_provider,
                   SUM(u.input_tokens) as input_tokens,
                   SUM(u.output_tokens) as output_tokens,
                   SUM(u.cache_read_tokens) as cache_read_tokens,
                   SUM(u.reasoning_tokens) as reasoning_tokens,
                   COALESCE(SUM(u.estimated_cost_usd), 0) as estimated_cost,
                   COUNT(DISTINCT u.session_id) as sessions,
                   SUM(COALESCE(u.api_call_count, 0)) as api_calls,
                   MAX(u.last_seen) as last_used_at
            FROM session_model_usage u
            JOIN sessions s ON s.id = u.session_id
            WHERE s.started_at > ? AND u.task != ''
            GROUP BY u.model, u.task, u.billing_provider
            ORDER BY SUM(u.input_tokens) + SUM(u.output_tokens) DESC
        )Ú_connÚexecuteÚfetchallrH   r   )Údbrû   ÚcurÚrs   &&  r   Ú_aux_usage_rowsr  w  s_   € ðØ�h‰h×Ñð  ð" ˆYó#ˆð$ "%§¡¤Ó0¡˜A”�Q–¡Ñ0Ð0ùÒ0øÜô ØŠ	ðús"   ‚/A ±AÁA ÁA ÁAÁAc          	      óä   € V ^8„  d   QhR\         \        \        \        3,          ,          R\         \        \        \        3,          ,          R\         \        \        \        3,          ,          /# )r   Úby_modelÚaux_rowsr   r‘   )r   s   "r   r   r   –  sS   € ÷ Dñ DÜ”4œœS˜•>Õ"ðDÜ.2´4¼¼S¸µ>Õ.BðDÜGKÌDÔQTÔVYÐQYÍNÕG[ñDr   c                ó¬  € V'       g   V # V  Uu/ uF  q"P                  R4      ;'       g    RVbK   	  ppV Fñ  pVP                  R4      ;'       g    RpVP                  VRVR^ R^ R^ R^ R^ /4      p\         F@  pVP                  V4      ;'       g    ^ VP                  V4      ;'       g    ^ ,           Wg&   KB  	  VP                  R. 4      P                  R	VP                  R	4      ;'       g    R
/\         Uu/ uF  qwVP                  V4      ;'       g    ^ bK   	  upC4       Kó  	  \	        VP                  4       \        RR7      # u upi u upi )zùFold aux usage rows into the sessions-derived per-model list. Aux usage lives only in
session_model_usage (never in the sessions counters), so this cannot double-count;
models that ONLY appear via aux calls (e.g. a vision model) get their own entry.r‚   Úunknownr÷   rø   Úestimated_costÚsessionsÚ	api_callsÚ	aux_tasksÚtaskr$   T©rm   Úreverse©rO   r½   Ú_AUX_COUNTERSrg   r£   Úvaluesrù   )r  r  rõ   ÚmergedÚauxr‚   rC   rm   s   &&      r   Ú_merge_aux_into_by_modelr  –  sB  € ÷
 ØˆÙW_Ó(`ÑW_ÐPS¯©°Ó)9×)FÐ)F¸YÈÒ)KÑW_€FÐ(`ÛˆØ—‘˜Ó ×-Ð- IˆØ×"Ñ" 5¨7°E¸>È1ÈoÐ_`Ø+;¸QÀ
ÈAÈ{Ð\]ð+_ó `ˆç ˆCØ!Ÿ:™: c›?×/Ð/¨a°C·G±G¸C³L×4EÐ4EÀAÕFˆF‹Kñ !à×Ñ˜+ rÓ*×1Ñ1Ø�S—W‘W˜V“_×*Ð*¨Ð`ÕQ^Ó._ÑQ^È#°C·G±G¸C³L×4EÐ4EÀAÒ/EÑQ^Ñ._Ð`ö	bñ ô �&—-‘-“/¤}¸dÔCÐCùò )aùò /`s   �E«EÃ<EÄEc                ó    € V ^8„  d   QhR\         \        \        \        3,          ,          R\         \        \        \        3,          ,          /# )r   r  r   r‘   )r   s   "r   r   r   ©  s8   € ÷ Eñ E¤¤T¬#¬s¨(¥^Õ 4ð E¼¼dÄ3ÌÀ8½nÕ9Mñ Er   c                óÂ  € / pV  F¸  pVP                  R4      ;'       g    RpVP                  VRVR^ R^ R^ R^ R. /4      p\         F0  pYE;;,          VP                  V4      ;'       g    ^ ,          uu&   K2  	  VP                  R4      ;'       g    R	pWdR,          9  g   K   VR,          P                  V4       Kº  	  \	        VP                  4       \        R
R7      # )z?Aggregate aux usage rows across models into a per-task summary.r  r$   r÷   rø   r
  r  Úmodelsr‚   r	  Tr  r  )r  Úby_taskr  r  Údrm   r‚   s   &      r   Ú_aux_task_summaryr  ©  sÊ   € à)+€GÛˆØ�w‰w�v‹×$Ð$ "ˆØ×Ñ˜t f¨d°NÀAÀÐXYØ&6¸¸;ÈÈ8ÐUWð&Yó Zˆç ˆCØ�F�c—g‘g˜c“l×'Ð' aÕ'�Fñ !à—‘˜Ó ×-Ð- IˆØ˜(�Ö#Øˆh�K×Ñ˜uÖ%ñ ô �'—.‘.Ó"¬¸tÔDÐDr   c                ó\   € V ^8„  d   QhR\         \        ,          R\        \        ,          /# r   )r
   r!   r`   )r   s   "r   r   r   ¸  s&   € ÷ Bñ Bœx¬�}ð B´´cµñ Br   c                ó¼   € T ;'       g    RP                  4       pV'       d   VP                  4       R8X  d   . # ^ RIHp \	        V4       RVP                  V4      .# )uð  ``["-p", <name>]`` for a validated named profile, else ``[]``. Hub actions run in
a fresh ``hermes`` subprocess whose ``_apply_profile_override()`` reads ``-p`` from argv â€”
the only mechanism that reaches import-time-bound globals like ``skills_hub.SKILLS_DIR``.
``default`` is a real named target, not an alias for the dashboard's own profile:
selector-less argv would make the child resolve the ambient ``HERMES_HOME`` (the launch
profile under a pooled ``-p X serve``), not the default home.r$   r%   r6   z-p)r&   r'   r9   r7   rA   Únormalize_profile_name)r   r(   r<   s   &  r   Ú_profile_cli_argsr   ¸  sO   € ð —�˜B×%Ñ%Ó'€Iß˜	Ÿ™Ó)¨YÔ6Øˆ	Ý3Ü˜Ô#Ø�,×5Ñ5°iÓ@ÐAÐAr   c                ó<   € V ^8„  d   QhR\         R\         R\         /# )r   Úverbrm   r   r4   )r   s   "r   r   r   Ç  s!   € ÷ ñ œ3ð ¤Sð ¬Sñ r   c                óP  € \         P                  ! RRVP                  4       4      P                  R4      R,          ;'       g    Rp\        P
                  ! VP                  4       4      P                  4       R,          pRV  RV RV 2p\        P                  ! VRV R24       V# )	zøUnique per-skill hub action name (+ registered log file): ``_spawn_hermes_action``
tracks one process/log per name, so a shared "skills-install" would make concurrent
row-level actions overwrite each other. Slug (readable) + hash (collision-proof).z
[^a-z0-9]+Ú-:Né0   NÚskill:Né   Nzskills-zaction-z.log)
ÚreÚsubr'   r&   ÚhashlibÚsha1ÚencodeÚ	hexdigestr   r½   )r"  rm   ÚslugÚdigestr=   s   &&   r   Ú_hub_action_namer0  Ç  sŒ   € ô �6Š6�-  c§i¡i£kÓ2×8Ñ8¸Ó=¸cÕB×MÐMÀg€DÜ�\Š\˜#Ÿ*™*›,Ó'×1Ñ1Ó3°BÕ7€FØ�T�F˜!˜D˜6  6 (Ð+€DÜ× Ò  ¨°°°dÐ';Ô<Ø€Kr   c                óF   € V ^8„  d   QhR\         \        ,          R\        /# r   )r
   r!   rH   )r   s   "r   r   r   Ò  s   € ÷ ñ ¬´­ð Äñ r   c                óÆ  €  ^ RI Hp \        V 4      '       d	   V! 4       pM6\        V P	                  4       4      pV! VR,          R,          R,          4      pRpVP                  4        UUu/ uFD  qUP                  R4      '       g   K  VR,          V Uu/ uF  qfVP                  V4      bK  	  upbKF  	  upp# u upi u uppi   \         d    h \         d    / u # i ; i)u  identifier -> installed lock entry for hub-installed skills (UI marks installed search
results). Scoped to ``profile``'s skills/.hub/lock.json when given â€” HubLockFile takes an
explicit path, sidestepping the import-time LOCK_FILE binding. {} when unreadable.)ÚHubLockFilerÎ   z.hubz	lock.jsonÚ
identifier)r=   Útrust_levelÚscan_verdict)	Útools.skills_hubr3  r)   rA   r&   Úlist_installedrO   r   r   )r   r3  Úlockr²   Úkeysrl   Úks   &      r   Ú_installed_hub_identifiersr<  Ò  sÍ   € ðÝ0Ü˜w×'Ò'Ù“=‰Dä.¨w¯}©}«Ó?ˆKÙ˜{¨XÕ5¸Õ>ÀÕLÓMˆDØ6ˆà!×0Ñ0Ô2ôOÙ2�E·i±iÀ×6Mô E��lÕ#¹tÓ%D¹t¸!¨¯©°1«¢o¹tÑ%DÒDÙ2òOð 	OùÒ%Dùó Oøäô ØÜô ØŠ	ðúsB   ‚A*C Á,B?Â	B?ÂB:Â/B?Â6C Â:B?Â?C ÃC ÃC ÃC c                óx   € V ^8„  d   Qh/ ^ \         9   d&   \        \        \        \        3,          ,          ;R&   # )r   Ú_TERMINAL_BACKENDS)Ú__conditional_annotations__r`   rH   r!   )r   s   "r   r   r      s4   € ÷ ñ ÷^
Dò D”Dœœc¤3˜h�Õ(ñ Dò_
r   )Úcanonical_modelÚreasoning_effort))ÚlocalÚLocalz4Run commands directly on this machine. No isolation.)ÚdockerzDocker / PodmanzSRun commands in an isolated Docker or Podman container with a persistent workspace.)ÚmodalÚModalz&Run commands in a Modal cloud sandbox.)ÚdaytonaÚDaytonaz(Run commands in a Daytona cloud sandbox.)ÚsshÚSSHz'Run commands on a remote host over SSH.)r=   rï   r‡   )r÷   rø   r
  r  r   )?r?  Ú__doc__Úloggingr*  r¡   r(  rV   Ú	threadingÚ
contextlibr   r   Úfastapir   Úpathlibr   Útypingr   r   r   r	   r
   r»   r   r   Úhermes_cli.web_modelsr   Úhermes_cli.web_server_gatewayr   Úhermes_cli.web_server_mcpr   Ú	getLoggerrY   r   r)   r2   r>   rD   rR   r\   rf   ro   rr   r�   r¨   rA   rÆ   ÚRLockrÑ   rÛ   rÐ   rH   rÔ   r>  ró   r  rù   r  r  r  r   r0  r<  r   )rõ   r?  s   0@r   Ú<module>rW     sa  øðöó Û Û 	Û 	Û 
Û ß 2Ý !Ý ß 6Õ 6ß EÝ 1Ý ;Ý Bð ×ÒÐ0Ó1€õõ;ð ô*ó ð*õõ,Cõ	*õ	Jð @Ð õõ>Aõ
õ õ:	.õðJ !—’Ó(Ð ð ôCó ðCðB ô/&ó ð/&ñxACó,DñAC¸�D‰Ð-¨sÓ	3Ö4ñ ACñ,DÐ ó Dõð, Q€õLõõ>Dõ&EõBõ÷ñ ùòE,Ds   Ã/E