+
    jHàj¢ì  ã                   ó¸  a € R† tm0 t R t^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIHt ^ RIt^ RIHtHtHtHtHt ^ RIHtHtHtHt ^ RIHt ^ RIHt ^ RIHt ^ RI H!t! ^ R	I"H#t# ^ R
I$H%t%H&t&H't'H(t( ^ RI)H*t*H+t+ ^ RI,H-t- ^ RI.H/t/ ]/! 4        ]P`                  ! R4      t1R R lt2R R lt3R R lt4Rt5RR/t6Rt7R R lt8R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+RR,/RR-RR.RR//RR0RR1RR2/RR3RR4RR5/.t9R‡R6 R7 llt:R8R9R:R;R<R=R>R?R@RA/t;] ^ k RBRCRDRE/t<] ^k 0 Rˆmt=0 R‰mt>0 RŠmt?0 R‹mt@RŒtARF RG ltBRH RI ltCRJ RK ltDRL RM ltERN RO ltFRP RQ ltGRR RS ltHRT RU ltIR�RV RW lltJRX RY ltKRZtL/ tM] ^k / tN] ^k ]	Pž                  ! 4       tPR[ R\ ltQ]R! 4       tS] ^k ]	Pž                  ! 4       tTR] R^ ltUR_ R` ltVRa Rb ltWRc Rd ltXRŽRe Rf lltYRg Rh ltZ]Ri 4       t[Rj Rk lt\Rl Rm lt]Rn Ro lt^Rp Rq lt_ ! Rr Rs4      t`]Rt 4       ta]	Pž                  ! 4       tbR�Ru Rv lltcRw Rx ltdRy Rz lteR{ tfR| R} ltgR~ R lth ! R€ R�4      ti]i! 4       tjR‚ Rƒ ltkR„ R… ltlR# )�zyDashboard UI assets: SPA mount, theme normalisation/bootstrap CSS, dashboard-plugin discovery and the plugins-hub merge.
N)Úcontextmanager)ÚDependsÚFastAPIÚHTTPExceptionÚRequestÚWebSocketException)ÚFileResponseÚHTMLResponseÚJSONResponseÚResponse)ÚStaticFiles)Ústatus)Úget_route_path)ÚHTTPConnection)ÚPath)ÚAnyÚDictÚListÚOptional)Úcfg_getÚget_process_hermes_home)Úenv_var_enabled)Únormalize_web_asset_mime_typeszhermes_cli.web_serverc                óF   € V ^8„  d   QhR\         \        ,          R\        /# )é   ÚrawÚreturn)r   Ústr)Úformats   "ÚD/home/ubuntu/.hermes/hermes-agent/hermes_cli/web_server_dashboard.pyÚ__annotate__r    &   s   € ÷ !ñ !œ8¤C�=ð !¬Sñ !ó    c                ó   € ^ RI Hp V! V 4      # )z Normalise an X-Forwarded-Prefix header value (single source of truth lives in
``hermes_cli.dashboard_auth.prefix`` so gate, OAuth, cookies and SPA mount agree).)Únormalise_prefix)Ú hermes_cli.dashboard_auth.prefixr#   )r   r#   s   & r   Ú_normalise_prefixr%   &   s   € õ BÙ˜CÓ Ð r!   c                ój   € V ^8„  d   QhR\         \        \        3,          R\        R\        R\        /# )r   ÚpaletteÚkeyÚdefaultr   ©Údictr   r   )r   s   "r   r    r    -   s6   € ÷ Mñ MœœS¤#˜X�ð M¬Sð M¼3ð MÄ3ñ Mr!   c                 óŒ   € V P                  V4      ;'       g    / p\        V\        4      '       d   VP                  R V4      # T# )Úhex©ÚgetÚ
isinstancer+   )r'   r(   r)   Úlayers   &&& r   Ú
_layer_hexr2   -   s:   € Ø�K‰K˜Ó×"Ð" €EÜ(2°5¼$×(?Ò(?ˆ5�9‰9�U˜GÓ$ÐLÀWÐLr!   c                ó$   € V ^8„  d   QhR\         /# ©r   r   ©r   )r   s   "r   r    r    2   s   € ÷ ,ñ ,¬Cñ ,r!   c                 ó@  a€ ^ RI Hp   \        V ! 4       RRRR7      oS'       d   \        S\        4      '       g   R# \
        ;QJ d#    V3R l\         4       F  '       g   K   RM	  R	M! V3R l\         4       4      '       d   R# \        4        Fà  pVP                  R
4      S8w  d   K  VP                  R4      ;'       g    / pVP                  R4      ;'       g    / pVP                  R4      ;'       g    \        R,          pVP                  R4      ;'       g    \        R,          pR R lpRV! \        VRR4      4       RV! \        VRR4      4       RV! V4       RV! V4       R2	u # 	  R#   \         d    \        P                  RRR7        R# i ; i)a9  Critical-CSS ``<style>`` shim for the active *user* theme, so the first paint uses the
target palette instead of flashing the bundle's default Hermes Teal until
``ThemeProvider.applyTheme()`` runs. Built-in themes return "" (the bundle owns them).

Variable names MUST match what the bundle consumes (``layerVars()`` /
``typographyVars()`` in ``web/src/themes/context.tsx``). The ``html,body`` rule
references the variables rather than literals so runtime theme switches stay live:
``applyTheme()`` writes inline styles on ``documentElement`` which outrank this block.
)Úload_configÚ	dashboardÚthemer)   ©r)   Ú c              3   ó:   <"  € T F  qR ,          S8H  x € K  	  R# 5i©ÚnameN© )Ú.0ÚbÚactives   & €r   Ú	<genexpr>Ú5_render_active_theme_bootstrap_css.<locals>.<genexpr>A   s   øé € ÐFÑ,E q��y˜FÖ"Ó,Eùs   ƒTFr>   r'   Ú
typographyÚfontSansÚbaseSizec                ó0   € V ^8„  d   QhR\         R\         /# )r   Úsr   r5   )r   s   "r   r    Ú8_render_active_theme_bootstrap_css.<locals>.__annotate__K   s   € ÷ 4ñ 4œð 4¤ñ 4r!   c                 ó8   € \        V 4      P                  R R4      # )ú</ú<\/)r   Úreplace)rI   s   &r   Ú_escÚ0_render_active_theme_bootstrap_css.<locals>._escK   s   € Ü˜1“v—~‘~ d¨FÓ3Ð3r!   z;<style id="hermes-theme-bootstrap">:root{--background-base:Ú
backgroundz#0a0a0az;--midground-base:Ú	midgroundz#e5e5e5z;--theme-font-sans:z;--theme-base-size:z�;}html,body{background-color:var(--background-base);color:var(--midground-base);font-family:var(--theme-font-sans);font-size:var(--theme-base-size);}</style>ztheme bootstrap render failed©Úexc_info)Úhermes_cli.configr7   r   r0   r   ÚanyÚ_BUILTIN_DASHBOARD_THEMESÚ_discover_user_themesr/   Ú_THEME_DEFAULT_TYPOGRAPHYr2   Ú	ExceptionÚ_logÚdebug)r7   r9   r'   ÚtypoÚ	font_sansÚ	base_sizerO   rB   s          @r   Ú"_render_active_theme_bootstrap_cssr`   2   sj  ø€ õ .ð!Ü™›¨°WÀiÔPˆßœZ¨´×4Ò4Ùß‹3ÔFÕ,EÓF�3�3Š3ÔFÕ,EÓF×FÒFÙÜ*Ö,ˆEØ�y‰y˜Ó  FÔ*ÙØ—i‘i 	Ó*×0Ð0¨bˆGØ—9‘9˜\Ó*×0Ð0¨bˆDØŸ™ Ó,×UÐUÔ0IÈ*Õ0UˆIØŸ™ Ó,×UÐUÔ0IÈ*Õ0UˆIõ4ð%á%)¬*°W¸lÈIÓ*VÓ%WÐ$Xð Y$Ù$(¬°G¸[È)Ó)TÓ$UÐ#Vð W%Ù%)¨)£_Ð$5ð 6%Ù%)¨)£_Ð$5ð 6ðòñ -ñ0 øÜô Ü�
‰
Ð2¸Tˆ
ÔBÚðúsL   ‰E7 ¥E7 ½
E7 ÁE7 Á#!E7 Â<E7 ÃE7 ÃE7 Ã:%E7 Ä AE7 Å3E7 Å7"FÆFz#public, max-age=31536000, immutableúCache-Controlz#no-store, no-cache, must-revalidateu_   Headless backend (hermes serve): web UI disabled â€” use `hermes dashboard` for the browser UI.c                ó$   € V ^8„  d   QhR\         /# )r   Úapplication)r   )r   s   "r   r    r    k   s   € ÷ O$ñ O$œ7ñ O$r!   c                ó´  a aaaaa	€ ^ RI HoHoHo	 ^ RIHo \        P                  P                  R4      R8X  d"   S P                  R4      R VV	V 3R ll4       pR# RR	 VVVV	V 3R
 llloS P                  R4      R V3R ll4       p ! R R\        4      pS P                  RV! SR,          RR7      RR7       S P                  R4      R VV3R ll4       pR# )u²  Mount the built SPA; unmatched paths fall back to index.html for client-side routing.

The session token is injected into index.html via a ``<script>`` tag so the SPA can
authenticate without a separate token-dispensing endpoint. Behind a path-prefix reverse
proxy (``X-Forwarded-Prefix: /hermes``) the served index.html is rewritten so absolute
asset URLs and the runtime ``__HERMES_BASE_PATH__`` honour that prefix without a rebuild.

A missing WEB_DIST is deliberately NOT a mount-time terminal state: every route copes
with a missing dist per-request (404 JSON / ``check_dir=False``), so a long-lived
``--skip-build`` process recovers the moment a build appears on disk â€” no restart.
)ÚWEB_DISTÚ _DASHBOARD_EMBEDDED_CHAT_ENABLEDÚapp)Ú_serverÚHERMES_SERVE_HEADLESSÚ1z/{full_path:path}c                ó$   € V ^8„  d   QhR\         /# )r   Ú	full_pathr5   )r   s   "r   r    Úmount_spa.<locals>.__annotate__   s   € ÷ 	Kñ 	K¬ñ 	Kr!   c              “   ób  <"  € \        \        SP                  R R4      4      pT;'       g!    \        \        SP                  RR4      4      pV R8X  dH   V'       g@   \        R\        P
                  ! S! 4       P                  4       R\         R2\        R7      # \        R\        /R	R
7      # 5i)Úauth_requiredFÚwithhold_session_tokenr;   zC<!doctype html><html><head><script>window.__HERMES_SESSION_TOKEN__=z=;window.__HERMES_AUTH_REQUIRED__=false;</script></head><body>z</body></html>©ÚheadersÚerroré”  ©Ústatus_code)
ÚboolÚgetattrÚstater	   ÚjsonÚdumpsÚ_SESSION_TOKENÚ_HEADLESS_MSGÚ	_NO_STOREr
   )rl   ÚgatedÚwithheldrh   rg   rc   s   &  €€€r   Úno_frontendÚmount_spa.<locals>.no_frontend~   s    øé € ô œ ×!2Ñ!2°OÀUÓKÓLˆEØ×YÐY¤¤W¨S¯Y©YÐ8PÐRWÓ%XÓ YˆHØ˜BŒ§xÜ#ð7Ü7;·z²zÁ'Ã)×BZÑBZÓ7[Ð6\ð ]-ä-:¨O¸>ðKô &ôð ô   ¬-Ð 8ÀcÔJÐJùs   ƒAB/ÁAB/Nc                ó$   € V ^8„  d   QhR\         /# )r   Úprefixr5   )r   s   "r   r    rm   ›   s   € ÷ -5ñ -5œSñ -5r!   c                óª  <€  SR,          P                  RR7      pS'       d   RMR	p\        \	        SP
                  R
R4      4      pT;'       g!    \        \	        SP
                  RR4      4      pT'       d   RMRS! 4       P                   R2p\        P                  ! \        \	        SP
                  RR4      ;'       g    R4      4      P                  RR4      p^ RIHp \        P                  ! T! 4       4      P                  RR4      pRT RT RT  RT'       d   RMR	 RT RT R2p	T '       d0   R  F)  p
TP                  YªP                  RRT  R2^4      4      pK+  	  \        4       pT'       d   TP                  RT R2^4      pTP                  RT	 R2^4      p\        T\        R7      #   \         d    \        RR/RR7      u # i ; i)!uR  index.html with the session token + base-path injected.

When the OAuth auth gate is active (``app.state.auth_required``), the legacy
``_SESSION_TOKEN`` is NOT injected â€” the SPA reads identity from ``/api/auth/me`` over
cookie auth; ``__HERMES_AUTH_REQUIRED__`` tells it which scheme to use for /api/pty
and /api/ws (ticket vs token).
z
index.htmlú	utf-8-sig©Úencodingrs   z0Frontend not built. Run: cd web && npm run buildrt   ru   ÚtrueÚfalsero   Frp   r;   z!window.__HERMES_SESSION_TOKEN__="z";Úinitial_profilerL   rM   )Úserving_profile_namez<script>z*window.__HERMES_DASHBOARD_EMBEDDED_CHAT__=z;window.__HERMES_BASE_PATH__="z"";window.__HERMES_AUTH_REQUIRED__=z#;window.__HERMES_INITIAL_PROFILE__=z%;window.__HERMES_DASHBOARD_PROFILE__=z
;</script>z"/Ú"Ú/z</head>rq   )zhref="/assets/zsrc="/assets/zhref="/favicon.ico"zhref="/fonts/zhref="/ds-assets/zsrc="/ds-assets/)Ú	read_textÚOSErrorr
   rw   rx   ry   r|   rz   r{   r   rN   Úhermes_cli.web_server_profilesrŒ   r`   r	   r~   )r„   ÚhtmlÚchat_jsr   r€   Útoken_jsÚinitial_profile_jsÚ_serving_profile_nameÚserving_profile_jsÚbootstrap_scriptÚattrÚtheme_bootstrapre   rf   rh   rg   rc   s   &           €€€€€r   Ú_serve_indexÚmount_spa.<locals>._serve_index›   sâ  ø€ ð	pØ˜|Õ+×6Ñ6ÀÐ6ÓLˆD÷ =‘&À'ˆÜ”W˜SŸY™Y¨¸Ó?Ó@ˆà×UÐUœD¤¨¯©Ð4LÈeÓ!TÓUˆß!‘2Ð)JÉ7Ë9×KcÑKcÐJdÐdfÐ'gˆô "ŸZšZ¬¬G°K×4EÑ4EÐGXÐZ\Ó,]×,cÐ,cÐacÓ(dÓe×mÑmÐnrÐtzÓ{Ðõ
 	aÜ!ŸZšZÑ(=Ó(?Ó@×HÑHÈÈvÓVÐà�x�jØ8¸¸	ð B,Ø,2¨8ð 4/ß9>©vÀGÐ.Lð M1Ø1CÐ0Dð E3Ø3EÐ2Fð Gðð 	÷ óB�à—|‘| D¯,©,°t¸qÀÀÈ¸]ÈAÓ*NÓO’ñBô =Ó>ˆßØ—<‘< 	¨oÐ->¸gÐ+FÈÓJˆDØ�|‰|˜IÐ*:Ð);¸7Ð'CÀQÓGˆÜ˜D¬)Ô4Ð4øôG ô 	pä Ð*\Ð ]ÐknÔoÒoð	pús   ƒF5 Æ5GÇGz/assets/{filename}.cssc                ó0   € V ^8„  d   QhR\         R\        /# )r   ÚfilenameÚrequest©r   r   )r   s   "r   r    rm   Î   s   € ÷ 
ñ 
¤#ð 
´ñ 
r!   c           	   “   óæ  <"  € SR ,          V  R2,          pVP                  4       '       d4   VP                  4       P                  SP                  4       4      '       g   \        RR/RR7      # \	        VP
                  P                  R4      4      pVP                  RR7      pV'       d1   R F*  pR F!  pVP                  R	V V 2R	V V V 24      pK#  	  K,  	  \        VR
R\        /R7      # 5i)Úassetsz.cssrs   z	not foundrt   ru   úx-forwarded-prefixr†   r‡   zurl(ztext/cssra   )ÚcontentÚ
media_typerr   )z/fonts/z/fonts-terminal/z/ds-assets/z/assets/)r;   r�   Ú')Úis_fileÚresolveÚis_relative_tor
   r%   rr   r/   r�   rN   r   Ú_IMMUTABLE_ASSET_CACHE_CONTROL)rž   rŸ   Úcss_pathr„   ÚcssÚ	asset_dirÚquotere   s   &&     €r   Ú	serve_cssÚmount_spa.<locals>.serve_cssÍ   sì   øé € à˜hÕ&¨H¨:°TÐ):Õ:ˆØ×Ñ×!Ò!¨×)9Ñ)9Ó);×)JÑ)JÈ8×K[ÑK[ÓK]×)^Ò)^Ü ¨+Ð 6ÀCÔHÐHÜ" 7§?¡?×#6Ñ#6Ð7KÓ#LÓMˆØ× Ñ ¨+Ð Ó6ˆßÛW�	Û+�EØŸ+™+¨¨U¨G°I°;Ð&?À4ÈÀwÈvÈhÐW`ÐVaÐAbÓc’Có ,ñ Xô Ø J¸ÔJhÐ8iô
ð 	
ùs   ƒAC1Á BC1c                   óB   a a€ ] tR t^Üt oRtV3R lV 3R lltRtVtV ;t# )Ú'mount_spa.<locals>._ImmutableAssetFileszSStaticFiles that marks hashed bundle assets immutable so reloads skip revalidation.c                ó    <€ V ^8„  d   QhRS[ /# )r   Úpathr5   )r   Ú__classdict__s   "€r   r    Ú4mount_spa.<locals>._ImmutableAssetFiles.__annotate__ß   s   ø€ ÷ 	ñ 	©3ñ 	r!   c              “  óŠ   <"  € \         SV `  W4      G R j  x€L
 pVP                  ^È8X  d   \        VP                  R&   V#  L*5i)Nra   )ÚsuperÚget_responserv   rª   rr   )Úselfr´   ÚscopeÚresponseÚ	__class__s   &&& €r   r¹   Ú4mount_spa.<locals>._ImmutableAssetFiles.get_responseß   s@   øé € Ü"™WÑ1°$Ó>×>ˆHØ×#Ñ# sÔ*Ü4R�× Ñ  Ñ1ØˆOñ ?ùs   ƒA–A—+Ar?   )	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r¹   Ú__static_attributes__Ú__classdictcell__Ú__classcell__)r½   rµ   s   @@r   Ú_ImmutableAssetFilesr²   Ü   s   ù‡ € Ùa÷	÷ 	ó 	r!   rÇ   z/assetsr¢   F)Ú	directoryÚ	check_dir©r>   c                ó0   € V ^8„  d   QhR\         R\        /# )r   rl   rŸ   r    )r   s   "r   r    rm   ë   s   € ÷ $ñ $¤3ð $´ñ $r!   c              “   óº  <"  € \        VP                  P                  R 4      4      pV R8X  g   V P                  R4      '       d   \	        RRV  2/RR7      # SV ,          pV '       dk   VP                  4       P                  SP                  4       4      '       d8   VP                  4       '       d"   VP                  4       '       d   \        V4      # S! V4      # 5i)r£   Úapizapi/ÚdetailzNo such API endpoint: /rt   ru   )
r%   rr   r/   Ú
startswithr
   r¨   r©   Úexistsr§   r   )rl   rŸ   r„   Ú	file_pathre   r›   s   &&  €€r   Ú	serve_spaÚmount_spa.<locals>.serve_spaê   s»   øé € ä" 7§?¡?×#6Ñ#6Ð7KÓ#LÓMˆð ˜Ô ×!5Ñ!5°f×!=Ò!=Ü Ð-DÀYÀKÐ+PÐ QÐ_bÔcÐcØ˜yÕ(ˆ	÷ Ø×!Ñ!Ó#×2Ñ2°8×3CÑ3CÓ3E×FÒFØ× Ñ ×"Ò"Ø×!Ñ!×#Ò#ä 	Ó*Ð*Ù˜FÓ#Ð#ùs$   ƒACÁ"CÁ)2CÂCÂ2CÃC©r;   )Úhermes_cli.web_serverre   rf   rg   Úhermes_cli.web_depsrh   ÚosÚenvironr/   r   Úmount)
rc   r�   r¯   rÇ   rÒ   re   rf   r›   rh   rg   s
   f    @@@@@r   Ú	mount_sparÚ   k   sÓ   ý€ ÷ VÑUÝ+ô 
‡z�z‡~�~Ð-Ó.°#Ô5à	�‰Ð,Ó	-÷	Kñ 	Kó 
.ð	Kñ$ 	÷-5ö -5ðd ‡_�_Ð-Ó.÷
ó /ð
ôœ{ô ð ×ÑØÑ'°(¸XÕ2EÐQVÔWÐ^fð ô ð ‡_�_Ð(Ó)÷$ð $ó *ò$r!   r>   r)   ÚlabelzHermes TealÚdescriptionu/   Classic dark teal â€” the canonical Hermes lookzdefault-largezHermes Teal (Large)z1Hermes Teal with bigger fonts and roomier spacingz	nous-bluez	Nous Blueu6   Light mode â€” vivid Nous-blue accents on cream canvasÚmidnightÚMidnightz"Deep blue-violet with cool accentsÚemberÚEmberu'   Warm crimson and bronze â€” forge vibesÚmonoÚMonou'   Clean grayscale â€” minimal and focusedÚ	cyberpunkÚ	Cyberpunku'   Neon green on black â€” matrix terminalÚroseu   RosÃ©u-   Soft pink and warm ivory â€” easy on the eyesc                ó€   € V ^8„  d   QhR\         R\        R\        R\        \        \        \         3,          ,          /# )r   ÚvalueÚdefault_hexÚdefault_alphar   )r   r   Úfloatr   r+   )r   s   "r   r    r      sA   € ÷ Bñ Bœcð B´ð BÄEð BÔT\Ô]aÔbeÔgjÐbjÕ]kÕTlñ Br!   c           
     óp  € V f   RVRV/# \        V \        4      '       d   RV RV/# \        V \        4      '       g   R# V P                  RV4      p\        V\        4      '       g   R#  \	        V P                  RV4      4      pRVR\        R\        RV4      4      /#   \
        \        3 d    Tp L/i ; i)z�Normalise a theme layer spec (bare hex shorthand or ``{hex, alpha}`` dict); ``None`` on
garbage so the caller falls back to a built-in default.Nr-   Úalphaç        ç      ð?)	r0   r   r+   r/   rê   Ú	TypeErrorÚ
ValueErrorÚmaxÚmin)rç   rè   ré   Úhex_valÚalpha_fs   &&&  r   Ú_parse_theme_layerrõ     s¸   € ð ‚}Ø�{ G¨]Ð;Ð;Ü�%œ×ÒØ�u˜g }Ð5Ð5Ü�eœT×"Ò"ÙØ�i‰i˜˜{Ó+€GÜ�gœs×#Ò#Ùð Ü˜Ÿ	™	 '¨=Ó9Ó:ˆð �7˜G¤S¨¬c°#°wÓ.?Ó%@ÐAÐAøô ”zÐ"ô  ØŠð ús   Á*B ÂB5Â4B5rF   zQsystem-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serifÚfontMonozDui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospacerG   Ú15pxÚ
lineHeightz1.55ÚletterSpacingÚ0Úradiusz0.5remÚdensityÚcomfortablec                ó€   € V ^8„  d   QhR\         \        \        3,          R\        R\         \        \        3,          /# )r   Údatar(   r   r*   )r   s   "r   r    r    A  s1   € ÷ 4ñ 4”dœ3¤˜8•nð 4¬3ð 4´4¼¼S¸µ>ñ 4r!   c                 óX   € V P                  V4      p\        V\        4      '       d   V# / # ©Nr.   )rÿ   r(   rç   s   && r   Ú_dict_fieldr  A  s&   € Ø�H‰H�S‹M€EÜ˜u¤d×+Ò+ˆ5Ð3°Ð3r!   c                ó0   € V ^8„  d   QhR\         R\        /# )r   rç   r   ©r   rw   )r   s   "r   r    r    F  s   € ÷ :ñ :œð :¤ñ :r!   c                 ód   € \        V \        4      ;'       d    \        V P                  4       4      # r  )r0   r   rw   Ústrip)rç   s   &r   Ú_nonempty_strr  F  s"   € Ü�eœSÓ!×9Ð9¤d¨5¯;©;«=Ó&9Ð9r!   c                ó0   € V ^8„  d   QhR\         R\        /# )r   r(   r   r  )r   s   "r   r    r    J  s   € ÷ Tñ T”Cð TœDñ Tr!   c                 ó’   € \        V \        4      ;'       d1    V P                  R R4      P                  RR4      P                  4       # )Ú-r;   Ú_)r0   r   rN   Úisalnum©r(   s   &r   Ú
_css_identr  J  s8   € Ü�cœ3Ó×SÐS C§K¡K°°RÓ$8×$@Ñ$@ÀÀbÓ$I×$QÑ$QÓ$SÐSr!   c                óŠ   € V ^8„  d   QhR\         \        \        3,          R\        \         \        \        3,          ,          /# )r   rÿ   r   )r+   r   r   r   )r   s   "r   r    r    N  s3   € ÷ ^ñ ^¤d¬3´¨8¥nð ^¼Ä$ÄsÌCÀxÅ.Õ9Qñ ^r!   c                ó	  aa€ \        V \        4      '       g   R# V P                  R4      p\        V4      '       g   R# \	        V R4      o\	        V R4      oR R VV3R lllpSP                  RV P                  R4      4      p Ve   \        V4      MRpR	V! R	R
R4      RV! RRR4      RV! RRR4      RSP                  R4      ;'       g    V P                  R4      ;'       g    RRV/p\	        V R4      p\        \        4      pR! F/  p\        VP                  V4      4      '       g   K%  Wh,          Wx&   K1  	  \	        V R4      p	\        \        4      p
\        V	P                  R4      4      '       d   V	R,          V
R&   V	P                  R4      p\        V\        4      '       d   VR"9   d   WºR&   \	        V R4      P                  4        UUu/ uF'  w  rÍV\        9   g   K  \        V4      '       g   K%  WÍbK)  	  ppp\	        V R4      p\         Uu/ uF.  p\        VP                  V4      4      '       g   K%  WÏV,          bK0  	  pp\	        VR4      P                  4        UUu/ uF-  w  rÍ\        V4      '       g   K  \        V4      '       g   K+  WÍbK/  	  pppV'       d   VVR&   V P                  R4      p\        V4      '       d
   VR\         MRp/ p\	        V R4      P                  4        F½  w  ppV\         9  g   \        V\        4      '       g   K)  VP                  4        UUu/ uFi  w  pp\        V4      '       g   K  \        V\        \"        \
        34      '       g   K<  \        V4      P%                  4       '       g   K]  V\        V4      bKk  	  pppV'       g   K¸  VVV&   K¿  	  V P                  R4      p\        V\        4      '       d   V\&        9   g   RpRTRV P                  R4      ;'       g    TRV P                  RR4      RVRVRV
RV/pV'       d   VVR&   V'       d   VVR&   Ve   VVR&   V'       d   VVR&   V#   \        \        3 d    Rp ELÕi ; iu uppi u upi u uppi u uppi )#u€  Normalise a user theme YAML into the wire format ``ThemeProvider`` expects; ``None`` if
unusable. Accepts the full schema and a loose form (top-level ``colors``, bare hex).

customCSS is clipped but intentionally NOT sanitised â€” themes are user-authored YAML in
~/.hermes/, the same trust level as config.yaml. Empty asset values are dropped so a
theme can explicitly clear a slot.
Nr>   r'   Úcolorsrî   c          
      ój   € V ^8„  d   QhR\         R\         R\        R\        \         \        3,          /# )r   r(   rè   ré   r   )r   rê   r+   r   )r   s   "r   r    Ú1_normalise_theme_definition.<locals>.__annotate___  s7   € ÷ ^ñ ^”Cð ^¤cð ^¼%ð ^Ì$ÌsÔTWÈxÍ.ñ ^r!   c                 ór   <€ \        SP                  V SP                  V 4      4      W4      pVe   V# RVRV/# )Nr-   rì   )rõ   r/   )r(   rè   ré   ÚparsedÚ
colors_srcÚpalette_srcs   &&& €€r   Ú_layerÚ+_normalise_theme_definition.<locals>._layer_  s<   ø€ Ü# K§O¡O°C¸¿¹ÈÓ9LÓ$MÈ{ÓjˆØÒ+ˆvÐ]°%¸ÀgÈ}Ð1]Ð]r!   ÚnoiseOpacityrQ   z#041c1crR   z#ffe6cbÚ
foregroundz#ffffffrí   ÚwarmGlowzrgba(255, 189, 56, 0.35)rE   Úlayoutrû   rü   ÚcolorOverridesr¢   ÚcustomÚ	customCSSÚcomponentStylesÚlayoutVariantÚstandardrÛ   rÜ   r;   ©rî   )rF   rö   ÚfontDisplayÚfontUrlrG   rø   rù   >   ÚcompactÚspaciousrý   )r0   r+   r/   r  r  rê   rï   rð   rY   Ú_THEME_DEFAULT_LAYOUTr   ÚitemsÚ_THEME_OVERRIDE_KEYSÚ_THEME_NAMED_ASSET_KEYSr  Ú_THEME_CUSTOM_CSS_MAXÚ_THEME_COMPONENT_BUCKETSÚintr  Ú_THEME_LAYOUT_VARIANTS)rÿ   r>   r  Ú	raw_noiseÚnoiser'   Útypo_srcrE   r(   Ú
layout_srcr  rü   ÚkÚvÚcolor_overridesÚ
assets_srcÚ
assets_outÚcustom_assetsÚcustom_css_valÚ
custom_cssÚcomponent_stylesÚbucketÚpropsÚproprç   ÚcleanÚlayout_variantÚresultr  r  s   &                           @@r   Ú_normalise_theme_definitionrD  N  s.  ù€ ô �dœD×!Ò!ÙØ�8‰8�FÓ€DÜ˜×ÒÙä˜d IÓ.€KÜ˜T 8Ó,€J÷^ó ^ð —‘ °·±¸Ó0HÓI€IðØ$-Ò$9”�iÔ ¸sˆð 	‘f˜\¨9°cÓ:Ø‘V˜K¨°CÓ8Ø‘f˜\¨9°cÓ:Ø�K—O‘O JÓ/×eÐe°4·8±8¸JÓ3G×eÐeÐKeØ˜ð€Gô ˜4 Ó.€HÜÔ/Ó0€JÛlˆÜ˜Ÿ™ cÓ*×+Ô+Ø&�mˆJ‹Oñ mô ˜T 8Ó,€JÜÔ'Ó(€FÜ�Z—^‘^ HÓ-×.Ò.Ø% hÕ/ˆˆxÑØ�n‰n˜YÓ'€GÜ�'œ3×Ò GÐ/UÔ$UØ#ˆyÑô % TÐ+;Ó<×BÑBÔDôÙD‘�ØÔ$Ñ$ô 	Ü)6°q×)9ô 	ˆŠÑDð ñ ô
 ˜T 8Ó,€JÝ<SÓ!xÑ<S°qÔWdÐeo×esÑesÐtuÓev×WwÔ"2 !°¥]Ò"2Ñ<S€JÐ!xÜ&1°*¸hÓ&G×&MÑ&MÔ&OÔvÑ&O™d˜aÔS]Ð^_×S`”TÔerÐst×eu”T�Q’TÑ&O€MÑvßØ,ˆ
�8Ñà—X‘X˜kÓ*€NÜ;HÈ×;XÒ;X�Ð 6Ô!6Ñ7Ð^b€Jà24ÐÜ$ TÐ+<Ó=×CÑCÖE‰ˆ�ØÔ1Ô1¼ÀEÌ4×9PÒ9PÙà05·±´ô
Ù0=¡  uÜ˜$×ô Ü$.¨u´s¼CÄÐ6G×$Hô ÜMPÐQVËZ×M]ÑM]×M_ô ˆD”#�e“*Ò±ð 	ñ 
÷ ‰5Ø',Ð˜VÓ$ñ Fð —X‘X˜oÓ.€NÜ�~¤s×+Ò+°ÔBXÔ0XØ#ˆð 	�Ø�—‘˜'Ó"×*Ð* dØ�t—x‘x ¨rÓ2Ø�7Ø�jØ�&Ø˜ð€F÷ Ø#2ˆÐÑ ßØ%ˆˆxÑØÒØ(ˆˆ{ÑßØ$4ˆÐ Ñ!Ø€MøôM ”zÐ"ô Ø‹ðüó0ùò "yùÛvùó
s`   ÂQ Â	Q ÇQ/Ç&Q/Ç9Q/È"Q5È=Q5É)Q:ÊQ:ÊQ:Ì1R ÍR Í/R ÎR ÑQ,Ñ+Q,c                ó$   € V ^8„  d   QhR\         /# r4   )Úlist)r   s   "r   r    r    ¯  s   € ÷ ñ œtñ r!   c                 óT  € \        4       R,          p V P                  4       '       g   . # . p\        V P                  R4      4       FL  p \        P
                  ! VP                  RR7      4      p\        T4      pTf   K;  TP                  T4       KN  	  V#   \         d     K`  i ; i)z÷Fully-normalised user themes from ``<launch home>/dashboard-themes/*.yaml``.

Uses the process launch home, not ``get_hermes_home()``, so a transient profile override
from embedded chat does not hide themes under the server's own ``HERMES_HOME``.
zdashboard-themesz*.yamlr†   r‡   )
r   Úis_dirÚsortedÚglobÚyamlÚ	safe_loadr�   rZ   rD  Úappend)Ú
themes_dirrC  Úfrÿ   Ú
normaliseds        r   rX   rX   ¯  sš   € ô )Ó*Ð-?Õ?€JØ×Ñ×ÒØˆ	Ø€FÜ�J—O‘O HÓ-Ö.ˆð	Ü—>’> !§+¡+°{ +Ó"CÓDˆDô 1°Ó6ˆ
ØÔ!Ø�M‰M˜*Ö%ñ /ð €Møô ô 	Úð	ús   Á
&BÂB'Â&B'c                óR   € V ^8„  d   QhR\         R\        R\        \        ,          /# )r   Ú	api_fieldÚdashboard_dirr   )r   r   r   r   )r   s   "r   r    r    È  s&   € ÷ ñ ¬ð ¼tð ÌÔQTÍñ r!   c               óJ  € \        V \        4      '       d   V P                  4       '       g   R# \        V 4      pVP	                  4       '       d   R#  W,          P                  4       P                  VP                  4       4       V #   \        \        \        3 d     R# i ; i)u¯  Validate the manifest's ``api`` field (later imported as a Python module â€” arbitrary
code execution by design).

An absolute path would swallow the plugin dir (``Path('safe') / '/tmp/evil.py'`` ->
``/tmp/evil.py``) and ``../`` could climb out of it (GHSA-5qr3-c538-wm9j). Returns the
original string when the resolved path stays under ``dashboard_dir``, else ``None`` so
the plugin still loads its static JS/CSS but its backend ``api`` is rejected.

The web server later imports this file as a Python module via ``importlib.util.spec_from_file_location``
(arbitrary code execution by design â€” that's how plugins extend the backend). Pre-#29156 the field was
used as-is, which meant:
N)
r0   r   r  r   Úis_absoluter¨   Úrelative_tor�   ÚRuntimeErrorrð   )rR  rS  Ú	candidates   &$ r   Ú_safe_plugin_api_relpathrY  È  s†   € ô �i¤×%Ò%¨Y¯_©_×->Ò->ÙÜ�Y“€IØ×Ñ×ÒÙðØ	Õ	"×+Ñ+Ó-×9Ñ9¸-×:OÑ:OÓ:QÔRð Ðøô ”\¤:Ð.ô Úðús   Á3B ÂB"Â!B"c                ó:   € V ^8„  d   QhR\         \        ,          /# r4   )rF  Útuple)r   s   "r   r    r    á  s   € ÷ (ñ (¤t¬E¥{ñ (r!   c                 óÌ  € ^ RI Hp  ^ RIHp V ! 4       p\	        4       R,          .pV! 4       R,          pVP                  RR7      V^ ,          P                  RR7      8w  d   VP                  V4       V Uu. uF  qUR3NK  	  ppWbR,          R3VR3.,          p\        R	4      '       d5   VP                  \        P                  ! 4       R
,          R,          R34       V# u upi )u±  ``(root, source)`` pairs to scan, in priority order (first name wins).

User dashboard plugins are a dashboard-owned asset (like theme YAML): resolved from the
process launch home so they don't vanish when a request is scoped to another profile.
When the process itself is profile-scoped (``HERMES_HOME=<root>/profiles/<name>``) the
launch home has no ``plugins/`` â€” user plugins live in the hermes root â€” so the default
root is scanned too; profile-local plugins stay authoritative over same-named root ones.
The project source is gated on shared truthy semantics (``1``/``true``/``yes``/``on``):
a bare non-empty check let ``=0``/``=false`` silently enable it (GHSA-5qr3-c538-wm9j).
)Úget_bundled_plugins_dir)Úget_default_hermes_rootÚpluginsF)ÚstrictÚuserÚmemoryÚbundledÚHERMES_ENABLE_PROJECT_PLUGINSz.hermesÚproject)
Úhermes_cli.pluginsr]  Úhermes_constantsr^  r   r¨   rM  r   r   Úcwd)r]  r^  Úbundled_rootÚuser_plugin_rootsÚroot_pluginsÚdÚsearch_dirss          r   Ú_dashboard_plugin_search_dirsrn  á  sÛ   € õ ;Ý8á*Ó,€Lô 1Ó2°YÕ>Ð?ÐÙ*Ó,¨yÕ8€LØ×Ñ 5ÐÓ)Ð->¸qÕ-A×-IÑ-IÐQVÐ-IÓ-WÔWØ× Ñ  Ô.Ù(9Ó:Ñ(9 1�v“;Ñ(9€KÐ:Ø HÕ,¨iÐ8¸<ÈÐ:SÐTÕT€Kô Ð6×7Ò7Ø×ÑœDŸHšH›J¨Õ2°YÕ>À	ÐJÔKØÐùò ;s   Á7C!c                ó˜   € V ^8„  d   QhR\         \        \        3,          R\        R\        R\        R\         \        \        3,          /# )r   rÿ   r>   rS  Úsourcer   )r+   r   r   r   )r   s   "r   r    r      sE   € ÷ &ñ &¤$¤s¬C x¥.ð &¼ð &ÌDð &ÔZ]ð &ÔbfÔgjÔloÐgoÕbpñ &r!   c                 óð  € \        V P                  R 4      \        4      '       d   V P                  R / 4      M/ pRVP                  RRV 24      RVP                  RR4      /pVP                  R4      p\        V\        4      '       d   VP	                  R4      '       d   WeR&   \        VP                  R4      4      '       d   RVR&   V P                  R4      p\        V\        4      '       d5   V Uu. uF'  p\        V\        4      '       g   K  V'       g   K%  VNK)  	  upM. p	V P                  R	4      p
\        W¢R
7      pV
'       d   Vf   \        P                  RW4       RVRV P                  RV4      RV P                  RR4      RV P                  RR4      RV P                  RR4      R VRV	RV P                  RR4      RV P                  R4      R\        V4      RVR\        V4      RV/# u upi )Útabr´   rŽ   ÚpositionÚendÚoverrideÚhiddenTÚslotsrÍ   )rS  zžPlugin %s: refusing unsafe api path %r (must be a relative file inside the plugin's dashboard/ directory); backend routes from this plugin will not be mountedr>   rÛ   rÜ   r;   ÚiconÚPuzzleÚversionz0.0.0Úentryzdist/index.jsr¬   Úhas_apirp  Ú_dirÚ	_api_file)
r0   r/   r+   r   rÏ   rw   rF  rY  r[   Úwarning)rÿ   r>   rS  rp  Úraw_tabÚtab_infoÚoverride_pathÚ	slots_srcrI   rw  Úraw_apiÚsafe_apis   &&&&        r   Ú_dashboard_plugin_entryr†    s·  € ô &0°·±¸³Ä×%FÒ%Fˆd�h‰h�u˜bÔ!ÈB€GØ˜Ÿ™ F¨a°¨v¨JÓ7¸ÀWÇ[Á[ÐQ[Ð]bÓEcÐd€HØ—K‘K 
Ó+€MÜ�-¤×%Ò%¨-×*BÑ*BÀ3×*GÒ*GØ,�ÑÜˆG�K‰K˜Ó!×"Ò"Ø!ˆ�Ñà—‘˜Ó!€IÜBLÈYÔX\×B]ÒB]™	Ó>™	�1¤Z°´3×%7ŒQ¼A�QˆQ™	Ò>Ðce€Eà�h‰h�u‹o€GÜ'¨ÔM€Hß�8Ò#Ü�‰ðð ô	
ð 	�Ø�—‘˜' 4Ó(Ø�t—x‘x ¨rÓ2Ø�—‘˜ Ó*Ø�4—8‘8˜I wÓ/ØˆxØ�Ø�—‘˜' ?Ó3Øˆt�x‰x˜‹Ø”4˜“>Ø�&Ø”�MÓ"Ø�Xðð ùò ?s   Ã5G3ÄG3ÄG3c                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r   rm  r   )r   rF  )r   s   "r   r    r    5  s   € ÷ ñ ¬X´d­^ð Ätñ r!   c           
     óÆ  € . p\        4       pV f   \        4       MT  EF!  w  r4 VP                  4       '       g   K  \        P                  ! V4      ;_uu_ 4       p\        R V 4       R R7      pRRR4       X FÀ  pTR,          R,          p	 TP                  4       '       d   T	P                  4       '       g   KB  \        P                  ! T	P                  RR	7      4      p
T
P                  R
TP                  4      pY²9   d   KŒ  TP                  T4       TP!                  \#        Y«TR,          T4      4       KÂ  	  EK$  	  V#   + '       g   i     LÝ; i  \         d#   p\        P                  RY74        Rp?EKc  Rp?ii ; i  \         d#   p\        P                  RY—4        Rp?EK6  Rp?i\$         d#   p\        P                  RY—4        Rp?EKa  Rp?ii ; i)u³   Scan ``<plugins root>/*/dashboard/manifest.json`` across user, bundled and (opt-in)
project plugin sources â€” same three sources as ``hermes_cli.plugins`` â€” or ``search_dirs``.Nc              3   óL   "  € T F  p\        VP                  4      x € K  	  R # 5ir  )r   r´   )r@   Úes   & r   rC   Ú._discover_dashboard_plugins.<locals>.<genexpr>?  s   é € Ð">¹°A¤4¨¯©§< <»ùs   ‚"$c                 ó   € V P                   # r  rÊ   )Úps   &r   Ú<lambda>Ú-_discover_dashboard_plugins.<locals>.<lambda>?  s   € ÈaÏfÊfr!   r  z0Skipping unreadable dashboard plugin root %s: %sr8   úmanifest.jsonr†   r‡   r>   z+Skipping unreadable dashboard plugin %s: %sz$Bad dashboard plugin manifest %s: %s)Úsetrn  rH  r×   ÚscandirrI  r�   r[   r  rÐ   rz   Úloadsr�   r/   r>   ÚaddrM  r†  rZ   )rm  r_  Ú
seen_namesÚplugins_rootrp  ÚscanÚchildrenÚexcÚchildÚmanifest_filerÿ   r>   s   &           r   Ú_discover_dashboard_pluginsrœ  5  sy  € ð €GÜ“e€JØDOÒDWÔ!>Ô!@Ð]hÓ!hÑˆð	Ø×&Ñ&×(Ò(ÙÜ—’˜L×)Ô)¨TÜ!Ñ">¹Ó">ÑDTÔU�÷ *ó
 ˆEØ! KÕ/°/ÕAˆMðØ—|‘|—~’~¨]×-AÑ-A×-CÒ-CÙÜ—z’z -×"9Ñ"9À;Ð"9Ó"OÓP�Ø—x‘x ¨¯
©
Ó3�ØÔ%ÙØ—‘˜tÔ$Ø—‘Ô6°tÀ5È;ÕCVÐX^Ó_Ö`ô ñ "ið4 €N÷- *×)ûäô 	Ü�L‰LÐKÈ\Ô_Þûð	ûô ô Ü—‘ÐJÈMÔ_ÞûÜô Ü—‘ÐCÀ]ÔXÞûðúsq   ¤E¼EÁEÁ0EÂ+FÂ<AFÄ4FÅEÅEÅEÅFÅ#F Æ FÆG ÆF0Æ0G Æ=G Æ>GÇG c                ót   € V ^8„  d   QhR\         \        \        3,          R\         \        \        3,          /# )r   r�  r   r*   )r   s   "r   r    r    W  s.   € ÷ Añ A¤¤c¬3 h¥ð A´D¼¼c¸µNñ Ar!   c                 óˆ   € V P                  4        UUu/ uF   w  rVP                  R 4      '       d   K  WbK"  	  upp# u uppi )r  )r*  rÏ   )r�  r5  r6  s   &  r   Ú_strip_dashboard_manifestrŸ  W  s1   € ØŸW™WœYÔ@™Y‘T�Q¨a¯l©l¸3×.?ŒDˆAŠD™YÒ@Ð@ùÓ@s   ”>´>g      @c                ó   € V ^8„  d   QhRR/# ©r   r   Nr?   )r   s   "r   r    r    a  s   € ÷ .ñ . tñ .r!   c                  ó¬   € \         ;_uu_ 4        \        P                  4        \        P                  4        R R R 4       R #   + '       g   i     R # ; ir  )Ú_plugins_hub_cache_lockÚ_plugins_hub_cacheÚclearÚ_plugins_hub_cache_expires_atr?   r!   r   Ú_invalidate_plugins_hub_cacher§  a  s/   € ß	 Ö	 Ü× Ñ Ô"Ü%×+Ñ+Ô-÷ 
!×	 ×	 Ò	 ús   �)AÁA	c                óN   € V ^8„  d   QhR\         \        P                  ,          /# r4   )r   Ú	threadingÚThread)r   s   "r   r    r    k  s   € ÷ ñ ¤H¬Y×-=Ñ-=Õ$>ñ r!   c                ó  a € \         ;_uu_ 4        S \        9   d    RRR4       R# \        P                  S 4       RRR4       V 3R lp\        P                  ! VRRR7      pVP                  4        V#   + '       g   i     LA; i)u°  Warm a cold ``check_fn`` verdict off the request path.

The hub read path only consumes cached availability; the only other warmer is the
tool-schema build, which a dashboard-only session never runs â€” so a cold cache would
report ``auth_required=False`` forever. Daemon-thread probe, deduplicated per function;
the short hub TTL surfaces the verdict on the next fetch. Returns ``None`` when a probe
for *fn* is already in flight.
Nc            	      óP  <€  ^ RI Hp  V ! S4       \        ;_uu_ 4        \        P                  S4       RRR4       R#   \         d     L;i ; i  + '       g   i     R# ; i  \        ;_uu_ 4        \        P                  S4       RRR4       i   + '       g   i     i ; i; i)é    )Ú_check_fn_cachedN)Útools.registryr®  rZ   Ú_plugins_hub_probe_lockÚ_plugins_hub_probe_inflightÚdiscard)r®  Úfns    €r   Ú_probeÚ(_schedule_check_fn_probe.<locals>._probey  st   ø€ ð	8Ý7á˜RÔ ÷ )Ö(Ü+×3Ñ3°BÔ7÷ )Ñ(øô ô 	Ùð	ú÷ )×(Ð(û×(Ö(Ü+×3Ñ3°BÔ7÷ )×(×(Ð(ýsD   ƒ? ŸA¿AÁ
A$ ÁAÁA$ ÁA!	Á$B%Á3B	Â		B%ÂB"ÂB%zplugins-hub-checkfn-probeT)Útargetr>   Údaemon)r°  r±  r”  r©  rª  Ústart)r³  r´  Úthreads   f  r   Ú_schedule_check_fn_proberº  k  sh   ø€ ÷ 
!Ö	 ØÔ,Ô,Ø÷ 
!Ñ	 ô 	$×'Ñ'¨Ô+÷ 
!õ
	8ô ×Ò VÐ2MÐVZÔ[€FØ
‡L�L„NØ€M÷% 
!×	 ús   �A5§A5Á5B	c                ó0   € V ^8„  d   QhR\         R\         /# ©r   r>   r   r5   )r   s   "r   r    r    ‰  s   € ÷ sñ s¤ð s¬ñ sr!   c                óB   a € ^ RI Hp \        V 3R lV 4       RS  24      # )zkA plugin that left core with its own login command (``hermes spotify login``), else ``hermes auth <name>``.)Ú	LEFT_COREc              3   ó�   <"  € T F;  qP                   S8X  g   K  VP                  '       g   K)  R VP                   R2x € K=  	  R# 5i)zhermes z loginN)ÚpluginÚcli)r@   rO  r>   s   & €r   rC   Ú(_plugin_login_command.<locals>.<genexpr>Œ  s6   øé € ÐZ±)¨Q¿x¹xÈ4Ñ?OÔ(ÐTU×TYÕTYÔ(�7˜1Ÿ5™5˜' Õ(³)ùs   ƒAšA®Azhermes auth )Úhermes_cli.left_core_migrationr¾  Únext)r>   r¾  s   f r   Ú_plugin_login_commandrÅ  ‰  s#   ø€ å8ÜÔZ±)ÓZÐ^jÐkoÐjpÐ\qÓrÐrr!   c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r   r>   Úprovides_toolsr   )r   rF  r[  )r   s   "r   r    r    �  s!   € ÷ ñ œCð ´ð ¼%ñ r!   c                ó,  €  ^ RI HpHp V Fr  pVP                  V4      pV'       d   VP                  '       g   K0  V! VP                  4      pVf   \        VP                  4       K]  VRJ g   Ke  R\        V 4      3u # 	  R#   \         d     R# i ; i)zù``(auth_required, auth_command)`` from last-known cached tool availability only.

A missing cache entry is "unknown": schedule a background probe rather than probing
inline (which would starve the root event loop), so the short hub TTL picks it up.
)Úget_cached_check_fn_resultÚregistryFT©Fr;   )r¯  rÉ  rÊ  Ú	get_entryÚcheck_fnrº  rÅ  rZ   )r>   rÇ  rÉ  rÊ  Útnamer{  Úcached_results   &&     r   Ú_plugin_auth_hintrÐ  �  s�   € ðßGÛ#ˆEØ×&Ñ& uÓ-ˆEß §§ ÙÙ6°u·~±~ÓFˆMØÒ$Ü(¨¯©Ö8Ø %Õ'ØÔ2°4Ó8Ð8Ò8ñ $ð Ðøô ô ØØÐðús"   ‚7B º2B Á1B Â B ÂBÂBc                óH   € V ^8„  d   QhR\         R\         R\         R\        /# )r   ÚaliasesÚenabled_setÚdisabled_setr   )r‘  r   )r   s   "r   r    r    ¥  s/   € ÷ hñ h¤Cð h´cð hÌð hÔQTñ hr!   c                óF   € W,          '       d   R# W,          '       d   R# R# )zPenabled / disabled / inactive for a plugin's name+key alias set (disabled wins).ÚdisabledÚenabledÚinactiver?   )rÒ  rÓ  rÔ  s   &&&r   Ú_plugin_runtime_statusrÙ  ¥  s#   € à ×/Ô/ˆ:ÐgÀ'×BWÔBW°YÐgÐ]gÐgr!   c                óR   € V ^8„  d   QhR\         R\        \        \        3,          /# )r   Úforce_refreshr   )rw   r+   r   r   )r   s   "r   r    r    ª  s&   € ÷ qñ q¤tð q¼¼SÄ#¸X½ñ qr!   c           #     ó®  € ^ RI HpHp ^ RIHp ^ RIHpHp ^ RIH	p V! V! 4       4      p\        P                  ! 4       pV '       gX   \        ;_uu_ 4        \        P                  V4      p	V	e(   V\        P                  VR4      8  d   V	uuRRR4       # RRR4       \        P                  ! 4       p
^ RIHpHpHpHpHpHpHpHpHp ^ RIHp ^ R	IHp V! 4       pV Uu/ uF  p\=        VR
,          4      VbK  	  ppV! 4       pV! 4       p\?        V! 4       RR. R7      ;'       g    . pV! 4       R,          PA                  4       p. pV! 4       pV! 4       pV! 4        EFh  w  p p!p"p#p$p%V! V VVV%V#V$VR7      p&V&R8X  d   Rp&\C        V$4      p'VP                  V 4      p( V'PA                  4       PE                  V4       Rp)V#R-9   ;'       d    T);'       d    V'PI                  4       p*V! V'4      P                  R4      ;'       g    . p+V+'       d   \K        V V+4      MR.w  p,p-TPM                  R
T RT!;'       g    RRT";'       g    RRT#RT&RV(RJ;'       g    V'R,          R,          PO                  4       RV('       d   \Q        V(4      MRRT$RT*RT*;'       d    V'R ,          PO                  4       R!V,R"V-R#V V9   R$V! V V$V4      /4       EKk  	  V U.u0 uF  p.V.R
,          kK  	  p/p.V Uu. uF'  p\=        VR
,          4      V/9  g   K  \Q        V4      NK)  	  p0pV! 4       p1 V! 4        U2U3u. uF  w  p2p3R
V2RV3/NK  	  p4p2p3RVR%V0R&R'V! V! 4       4      R(V1R)V! 4       R*V4//p5\        P                  ! 4       V
,
          p6V6R+8¼  d+   \T        PW                  R,V6\Y        V4      \Y        V14      4       \        ;_uu_ 4        V5\        V&   \        P                  ! 4       \Z        ,           \        V&   RRR4       V5#   + '       g   i     ELe; iu upi   \F         d    Rp) EL]i ; iu up.i u upi u up3p2i   \R         d    . p4 ELi ; i  + '       g   i     T5# ; i)/uƒ  Agent discovery + dashboard manifests + provider picker metadata.

IMPORTANT: powers a dashboard request path, so it must stay read-only and cheap â€” never
execute tool ``check_fn`` probes here (imports, auth/network checks would starve the root
event loop). Only cached availability is consumed and the payload is memoized briefly to
collapse the dashboard's bursty duplicate fetches.
)Ú"_discover_memory_provider_statusesÚ_normalize_memory_provider_name©Ú_get_dashboard_plugins)Úget_hermes_homer7   )Úhermes_home_keyNrí   )	Ú_category_active_namesÚ_discover_all_pluginsÚ_get_current_context_engineÚ_get_current_memory_providerÚ_discover_context_enginesÚ_get_disabled_setÚ_get_enabled_setÚ_plugin_statusÚ_read_manifest)Úremoved_annotation)Úresolved_removed_entriesr>   r8   Úhidden_pluginsr:   r_  )r(   rp  Údir_pathrB   znot enabledrØ  TFrÇ  r;   rz  rÜ   rp  Úruntime_statusÚhas_dashboard_manifestr�  Údashboard_manifestr´   Ú
can_removeÚcan_update_gitz.gitro   Úauth_commandÚuser_hiddenÚremoved_reasonÚorphan_dashboard_pluginsÚ	providersÚmemory_providerÚmemory_optionsÚcontext_engineÚcontext_optionsg      Ð?z;plugins/hub rebuilt in %.3fs (plugins=%d memory_options=%d)>   Úgitra  rË  ).Úhermes_cli.web_server_memoryrÝ  rÞ  rÕ   rà  rU   rá  r7   rg  râ  ÚtimeÚ	monotonicr£  r¤  r/   r¦  Úhermes_cli.plugins_cmdrã  rä  rå  ræ  rç  rè  ré  rê  rë  Úhermes_cli.plugins_cmd_catalogrì  Úhermes_cli.plugin_catalogrí  r   r   r¨   r   rV  rð   rH  rÐ  rM  rÐ   rŸ  rZ   r[   ÚinfoÚlenÚ_PLUGINS_HUB_CACHE_TTL_SECONDS)7rÛ  rÝ  rÞ  rà  rá  r7   râ  Ú	cache_keyÚnowÚcachedÚ
started_atrã  rä  rå  ræ  rç  rè  ré  rê  Ú_read_plugin_manifest_atrì  rí  Údashboard_listr�  Údash_by_namerÔ  rÓ  rî  Úplugins_root_resolvedÚrowsÚremoved_entriesrB   r>   rz  rÜ   rp  Údir_strr(   rð  rï  ÚdmÚunder_user_treeÚcan_remove_updaterÇ  ro   rõ  ÚrÚagent_namesÚorphan_dashboardÚmemory_providersÚnÚdescÚcontext_enginesÚpayloadÚdurations7   &                                                      r   Ú_merged_plugins_hubr  ª  s7  € ÷ qÝ<ß>Ý0á¡Ó 1Ó2€IÜ
�.Š.Ó
€Cßß$Ö$Ü'×+Ñ+¨IÓ6ˆFØÒ! cÔ,I×,MÑ,MÈiÐY\Ó,]Ô&]Ø÷ %×$Ò$ô
 —’Ó!€J÷
÷ 
õ 
õ BÝBá+Ó-€NÙ/=Ó>©~¨!”C˜˜&�	“N AÒ%©~€LÐ>Ù$Ó&€LÙ"Ó$€KÜ"¡;£=°+Ð?OÐY[Ô\×bÐbÐ`b€NÙ,Ó.°Õ:×CÑCÓEÐØ!#€Dñ /Ó0€OÙ#Ó%€Fá<Q×<SÑ8ˆˆg�{ F¨G°Sñ (Ø�+˜|°¸VÈgÐ^dôfˆà˜]Ô*Ø'ˆNä˜“=ˆØ×Ñ˜dÓ#ˆð	$Ø×ÑÓ×*Ñ*Ð+@ÔAØ"ˆOð # oÑ5×_Ð_¸/×_Ð_ÈhÏoÉoÓN_Ðá1°(Ó;×?Ñ?Ð@PÓQ×WÐWÐUWˆßQ_Ô&7¸¸nÔ&MÐepÑ#ˆ�|à�‰Ø�DØ�w—}�} "Ø˜;×,Ð,¨"Ø�fØ˜nØ$ b° n×&kÐ&k¸ÀKÕ9OÐRaÕ9a×8iÑ8iÓ8kØ Ç2Ô";¸BÔ"?È4Ø�GØÐ+ØÐ/×PÐP°XÀÕ5F×4NÑ4NÓ4PØ˜]Ø˜LØ˜4 >Ñ1ØÑ0°°wÀÓPð
÷ 	ñ+ =TñL '+Ó+¡d �1�V—9�9¡d€KÐ+Ù>LÓr¹n¸ÔPSÐTUÐV\ÕT]ÓP^ÐfqÑPqÔ4Ô1°!Ö4¹nÐÐrÙ9Ó;ÐðÙKdÔKfÔgÑKfÁÀÀ4˜F A }°dÓ;ÑKfˆÑgð
 	�4Ø"Ð$4ØØÑ>Ñ?[Ó?]Ó^ØÐ.ØÑ9Ó;Ø˜ð	
ð	€Gô �~Š~Ó *Õ,€HØ�4ÔÜ�	‰	ØIÈ8ÔUXÐY]ÓU^Ô`cÐdtÓ`uô	
÷ 
!Ö	 Ø(/Ô˜9Ñ%Ü37·>²>Ó3CÔFdÕ3dÔ% iÑ0÷ 
!ð €N÷C %×$Ð$üò* ?øô4 ô 	$Ø#‹Oð	$üò0 ,ùÚrùó høÜô Ø‹ðú÷$ 
!Ö	 ð €Núsf   Á6O2Ã PÆ!PËPË&P$ÌP$Ì
P/ Ì'P)Ì9P/ Î71QÏ2P	ÐPÐPÐ)P/ Ð/Q Ð?Q ÑQ	c          	      ó€   € V ^8„  d   QhR\         \        \        3,          R\        R\        R\        \        ,          /# ©r   rÀ  rÓ  rÔ  r   )r+   r   r   r‘  r   )r   s   "r   r    r      s8   € ÷ ñ ¬$¬s´C¨x­.ð Äsð ÔZ]ð ÔbjÔknÕboñ r!   c                ó†   € V P                  R4      V P                  RR4      rCVR9   d	   WB9   d   R# VR8X  d	   WA9  d   R# R# )	u¨  Why a plugin's backend ``api`` must NOT be imported, or None when it may be.

User plugins must be in ``plugins.enabled`` and not ``plugins.disabled`` before their
Python runs (GHSA-mcfc-hp25-cjv7); bundled plugins are trusted but respect an explicit
disable; project plugins (``./.hermes/plugins/``) ship with the CWD and are
attacker-controlled when opening a malicious repo â€” never auto-imported (GHSA-5qr3-c538-wm9j).
rp  r>   r;   ra  zexplicitly disabledznot in plugins.enabledN)ra  rc  ©r/   )rÀ  rÓ  rÔ  rp  Úplugin_names   &&&  r   Ú_plugin_api_mount_skip_reasonr%    sC   € ð !Ÿ*™* XÓ.°·
±
¸6À2Ó0FˆKØÐ$Ô$¨Ô)DÙ$Ø�Ô˜KÔ:Ù'Ùr!   c               #  óÆ   "  € ^ RI Hp Hp ^ RIHp V! R4      p V! R4      ;_uu_ 4        Rx € RRR4       V ! V4       R#   + '       g   i     L; i  T ! T4       i ; i5i)zåResolve config as the launch profile's, whichever profile the request is scoped to: home and
secrets switch together, so the launch config's ``${VAR}`` refs (and its last-good copy) never
expand through another profile's secrets.)Úreset_hermes_home_overrideÚset_hermes_home_override©Ú_config_profile_scopeN)rg  r'  r(  r‘   r*  )r'  r(  r*  Útokens       r   Ú_launch_profile_scoper,  .  sM   é € ÷
 VÝDÙ$ TÓ*€Eð*Ù" 4×(Õ(Û÷ )ñ 	# 5Ö)÷ )×(ûñ 	# 5Õ)üs1   ‚A!šA ªA¯A ·
A!ÁA	ÁA Á
AÁA!c                óF   € V ^8„  d   QhR\         \        \        3,          /# r4   )r[  r‘  )r   s   "r   r    r    =  s   € ÷ 
Dñ 
D¤%¬¬S¨¥/ñ 
Dr!   c                 ó  a€ ^ RI Hp   V ! 4       oV3R lR 4       w  r\        V\        4      '       d   \        V4      M	\        4       \        V\        4      '       d   \        V4      3# \        4       3#   \         d    / o Lti ; i)z°``(plugins.enabled, plugins.disabled)`` of the active profile scope from one cached read-only
config read: the gates run on the event loop for every plugin request and upgrade.)Úload_config_readonlyc              3   óB   <"  € T F  p\        SR V. R7      x € K  	  R# 5i)r_  r:   N)r   )r@   r(   Úconfigs   & €r   rC   Ú+_plugin_enable_sets_here.<locals>.<genexpr>E  s!   øé € ÐhÑPgÈœ ¨°CÀ×DÑDÓPgùs   ƒ)r×  rÖ  )rU   r/  rZ   r0   rF  r‘  )r/  r×  rÖ  r1  s      @r   Ú_plugin_enable_sets_herer3  =  sƒ   ø€ õ 7ðÙ%Ó'ˆô iÑPgÓhÑ€GÜ& w´×5Ò5ŒC�ŒL¼3»5Ü'¨´$×7Ò7ŒC�‹MðDð DÜ=@»UðDð Døô ô ØŠðús   ‰A5 Á5BÂBc                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# )r   rÀ  r   )r+   r   r   rw   )r   s   "r   r    r    J  s&   € ÷ Zñ Z¤T¬#¬s¨(¥^ð Z¼ñ Zr!   c                ó0   € \        V .\        4       O5!  RJ# )a¥  Whether a request must not reach ``plugin``'s backend or assets (#46435, GHSA-mcfc-hp25-cjv7).

``plugin`` is the active scope's own copy (a secondary profile's plugins are discovered under
its home and run in its plugin host, :mod:`hermes_cli.web_server_plugin_profiles`), so the
profile the request acts for decides alone: a native ticket's profile, a ``?profile=``
selection, else the launch profile (#134889, PLG-3).
N)r%  r3  )rÀ  s   &r   Ú_plugin_consent_withheldr6  J  s   € ô )¨ÐMÔ2JÓ2LÓMÐUYÐYÐYr!   c                ó$   € V ^8„  d   QhR\         /# r4   r5   )r   s   "r   r    r    U  s   € ÷ Tñ Tœsñ Tr!   c                óž   € \        V 4      pVP                  R4      pVP                  R4      '       d   \        V4      ^8¼  d
   V^,          # R# )z```<name>`` of an ``/api/plugins/<name>/...`` request (the path the router matches), else ``""``.rŽ   ú/api/plugins/r;   )r   ÚsplitrÏ   r  )r»   r´   Úpartss   &  r   Ú_plugin_api_namer<  U  sA   € ä˜%Ó €DØ�J‰J�s‹O€EØ—‘ ×7Ò7¼CÀ»JÈ!¼Oˆ5��8ÐSÐQSÐSr!   c                ó0   € V ^8„  d   QhR\         R\        /# r¼  ©r   rw   )r   s   "r   r    r    \  s   € ÷ Pñ P¬Cð P´Dñ Pr!   c              ƒ  óð   a "  € ^ RI Hp ^ RIHpHp \        V 3R lV! 4        4       R4      pV! 4       pVf$   Ve    \        P                  ! W%S 4      G Rj  x€L
 p\        T;'       g    RS RR/4      #  L5i)aA  The runtime gate for one ``/api/plugins/<name>/`` request, HTTP and WebSocket alike.

:func:`_mount_plugin_api_routes` gates at import time; a plugin disabled while the server runs
keeps its router mounted until restart, so every request is checked again. An unknown name
counts as a user plugin (safe default: refused).
rß  )Úrescanned_pluginÚsecondary_profile_homec              3   óV   <"  € T F  qP                  R 4      S8X  g   K  Vx € K   	  R# 5ir=   r#  ©r@   r�  r>   s   & €r   rC   Ú._plugin_api_request_refused.<locals>.<genexpr>e  s"   øé € ÐPÑ6˜¿%¹%À»-È4Ñ:O—1’1Ó6ùó   ƒ)Ÿ
)Nr>   rp  ra  )	rÕ   rà  Ú%hermes_cli.web_server_plugin_profilesr@  rA  rÄ  ÚasyncioÚ	to_threadr6  )r>   rà  r@  rA  rÀ  Úhomes   f     r   Ú_plugin_api_request_refusedrJ  \  so   øé € õ =ß^ÜÔPÑ4Ô6ÓPÐRVÓW€FÙ!Ó#€DØ‚~˜$Ò*Ü×(Ò(Ð)9ÀÓF×FˆÜ# F×$NÐ$N¨v°t¸XÀvÐ.NÓOÐOñ Gùs   ƒAA6ÁA4ÁA6Á)A6c                   óH   a € ] tR tRt o RtV 3R lR ltV 3R lR ltRtV tR# )	ÚPluginApiWebSocketGateil  ag  :func:`_plugin_api_request_refused` for WebSocket upgrades. ``_plugin_api_runtime_gate`` is
HTTP middleware and never sees one, so a plugin disabled at runtime kept accepting connections
on its websocket routes until restart (#134889).

It refuses before the route's own credential check, which is the disabled plugin's code, so it
cannot wait for auth (a gated-mode ticket is single-use: only the route may redeem it). That is
no plugin-name oracle: a close before accept reaches the client as the same 403 handshake
answer whether the plugin is disabled, unknown, or the credential was refused.

A Desktop's native grant is the exception: it names the profile the socket acts for, so it is
redeemed here, once (:func:`_native_ws_scope`), and consent is checked in that profile. A
secondary profile's socket to a plugin its own host serves is answered here too (PLG-3).
c                ó   <€ V ^8„  d   QhRR/# r¡  r?   )r   rµ   s   "€r   r    Ú#PluginApiWebSocketGate.__annotate__{  s   ø€ ÷ ñ ˜tñ r!   c                ó   € Wn         R # r  ©rg   )rº   rg   s   &&r   Ú__init__ÚPluginApiWebSocketGate.__init__{  s   € ØŽr!   c                ó   <€ V ^8„  d   QhRR/# r¡  r?   )r   rµ   s   "€r   r    rN  ~  s   ø€ ÷ Yñ Y°dñ Yr!   c           
   ƒ  ór  "  € ^ RI HpHp VR,          R8X  d   \        V4      MRpV'       g   V P	                  WV4      G Rj  x€L
  R# \        V4      ;_uu_ 4       qt! V4      ;_uu_ 4        V'       d^   \        V4      G Rj  x€L
 '       gE   V! WW64      G Rj  x€L
 '       g   V P	                  WV4      G Rj  x€L
   RRR4       RRR4       R# RRR4       RRR4       V! RRR\        P                  /4      G Rj  x€L
  R#  LÃ L„ Lo LQ  + '       g   i     LD; i  + '       g   i     LO; i L45i)r­  )Úplugin_request_scopeÚrefuse_secondary_plugin_socketÚtypeÚ	websocketr;   Nzwebsocket.closeÚcode)	rF  rU  rV  r<  rg   Ú_native_ws_scoperJ  r   ÚWS_1008_POLICY_VIOLATION)rº   r»   ÚreceiveÚsendrU  rV  r>   Úadmitteds   &&&&    r   Ú__call__ÚPluginApiWebSocketGate.__call__~  sä   é € ßnØ*/°­-¸;Ô*FÔ Ô&ÈBˆßØ—(‘(˜5¨4Ó0×0Ð0ÙÜ˜e×$Ô$¨Ð2FÀu×2MÕ2MßÔ&AÀ$Ó&G× GÖ GÙ;¸EÈDÓW×WÖWØŸ(™( 5°4Ó8×8Ð8Ø÷	 3N×$Ñ$×2M×$ñ
 �FÐ-¨v´v×7VÑ7VÐWÓX×XÒXñ 1ñ !HÙWÙ8÷ 3N×2Mú×$×$úñ
 	Yùs    ‚+D7®D7ÁDÁD7ÁD"Á-D	ÂD	Â	D	ÂD	ÂDÂ	D	Â&D	Â;DÂ<D	ÃD"Ã	
D7ÃD"Ã%D7Ä D5ÄD7Ä	D	ÄD	ÄD	ÄDÄD"Ä"D2	Ä-	D7rP  N)	r¿   rÀ   rÁ   rÂ   rÃ   rQ  r_  rÄ   rÅ   ©rµ   s   @r   rL  rL  l  s    ø‡ € ñ÷ð ÷Yö Yr!   rL  c           	   #  ón  "  € ^ RI HpHpHp ^ RIHp \        V 4      pWP                  9  d   Rx € R# V! V4      pVf   Rx € R# WeP                  n	        V! V4      ;_uu_ 4        V! R4      ;_uu_ 4        Rx € RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i5i)aÙ  Yield whether a plugin socket's native grant (``X-Hermes-Gateway-Ticket``) was admitted,
with that grant's home and secret scope bound for the rest of the connection; without the
header, True and the ambient scope. The grant is redeemed here only: the route's credential
check reads the principal stamped on the connection, and its scope dependency resolves the
same profile, so consent, home and ``get_secret`` all follow the grant, as on HTTP
(``native_profile_scope``).
)ÚHEADERÚnative_profile_scopeÚredeem_native_wsr)  TNF)
Ú%hermes_cli.dashboard_auth.native_httprc  rd  re  r‘   r*  r   rr   ry   Únative_http_principal)r»   rc  rd  re  r*  ÚconnÚgrants   &      r   rZ  rZ  Œ  s…   é € ÷ eÑdÝDÜ˜%Ó €DØ—\‘\Ô!ØŠ
ÙÙ˜TÓ"€EØ‚}ØŠÙØ',‡J�JÔ$Ù	˜d×	#Õ	#Ñ%:¸4×%@Õ%@ØŠ
÷ &A×	#Ñ	#×%@×%@ú×	#×	#Ð	#üs6   ‚A$B5Á&B!Á7B	Á<B!Â
B5ÂBÂB!Â!B2	Â,	B5c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   rh  Úprofile)r   r   r   )r   s   "r   r    r    ©  s   € ÷ ñ ¬>ð ÄHÌSÅMñ r!   c               ó¤  "  € ^ RI Hp ^ RIHpHp \        V P                  4      pV! V4      ;_uu_ 4        V! V4      '       g   \        V4      G Rj  x€L
 '       g   V! V4      '       d@   V P                  R,          R8X  d   \        \        P                  R7      h\        RRR	7      hR5x € RRR4       R#  Lf  + '       g   i     R# ; i5i)
uÍ  Home + secret scope for one ``/api/plugins/<name>/`` request: the launch profile's, or the
``?profile=``-requested one â€” the same ``_config_profile_scope`` seam the built-in routers use.
Without it plugin handlers ran unscoped, so under multi-profile hosting every ``get_secret``
/ ``resolve_runtime_provider`` failed closed with ``UnscopedSecretError`` (#120310; the bundled
kanban plugin's Decompose / Specify / Estimate aux-LLM calls, #123372). ``async`` on purpose:
a sync yield-dependency's setup and teardown run on different threadpool threads, so the
scope token would be reset in a foreign context; sync handlers still see the scope because
``run_in_threadpool`` copies the request context into the worker.)Úin_process_router_refused)r*  Ú_is_current_profileNrW  rX  )rY  rt   zPlugin not found)rv   rÎ   )rF  rm  r‘   r*  rn  r<  r»   rJ  r   r   r[  r   )rh  rk  rm  r*  rn  r>   s   &&    r   Ú_plugin_route_secret_scopero  ©  s›   é € õ PßYÜ˜DŸJ™JÓ'€DÙ	˜w×	'Õ	'ñ $ G×,Ò,Ô7RÐSWÓ7X×1XÖ1XÑ]vÐw{×]|Ò]|Ø�z‰z˜&Õ! [Ô0Ü(¬f×.MÑ.MÔNÐNÜ¨CÐ8JÔKÐKÜ÷ 
(Ñ	'ñ 2Y÷ 
(×	'Ð	'üs;   ‚4C¶B<ÁB:Á	B<ÁB<Á,AB<Â0
CÂ:B<Â<C	Ã	Cc                ó4   € V ^8„  d   QhR\         R\        RR/# )r   rÀ  Úapi_file_namer   N)r+   r   )r   s   "r   r    r    ¿  s&   € ÷ Wñ W¬$ð W¼sð WÀtñ Wr!   c           	     ó°   a€ VR,          oR
R V3R lllpV P                  RS R2VR. RO\        \        4      .R7       \        P	                  RS4       R	# )a  ``plugins.isolation: host``: the plugin's router runs in the requesting profile's plugin host;
this process only forwards each ``/api/plugins/<name>/`` request to it (auth and the profile
scope still apply here first). Responses are buffered: streaming and websockets need in-process.r>   c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r   rŸ   r´   r   )r   r   r   )r   s   "r   r    Ú._mount_hosted_plugin_api.<locals>.__annotate__Å  s!   € ÷ ;ñ ;œwð ;¬cð ;¼8ñ ;r!   c              “   ó  <a aaaa	a
aaa"  € \         P                  ! \        S4      G R j  x€L
 pVf   \        RRS: R2/RR7      # Tw  oo
o^ RIHp S P                  P                  S P                  P                  4        UUu. uF  w  rEVP                  4       R8w  g   K  WE3NK!  	  uppuooS P                  4       G R j  x€L
 o	^ RIHp V! S 4      oV! SP                  SVVV	V
VVVVVV 3
R	 l4      G R j  x€L
 #  LÔu uppi  LC L5i)
NrÎ   zplugin z is not enabled in this profilert   ru   )Úrun_hosted_requestÚhost)Úadmitted_for_sensitive_routec                 ó\   <
€ SP                  SSSS
P                  R S,           S	SSV SR7
      # )rŽ   )ÚtimeoutÚauthenticated)Úasgi_requestÚmethod)rz  Úapi_filer{  ÚbodyrS  rr   rw  r>   r´   ÚqueryrŸ   s   &€€€€€€€€€€r   rŽ  Ú;_mount_hosted_plugin_api.<locals>.forward.<locals>.<lambda>Ò  s7   ø€ È×IZÑIZØ�- ¨7¯>©>¸3À½:ÀuÈgÐW[Ø¨=ð J[ô J:r!   )rG  rH  Ú_hosted_plugin_for_requestr
   rF  rv  Úurlr€  rr   r*  Úlowerr  Ú hermes_cli.plugin_host_http_authrx  rI  )rŸ   r´   r¶  rv  r5  r6  rx  r~  r{  r  rS  rr   rw  r€  r>   s   ff     @@@@@@@€r   ÚforwardÚ)_mount_hosted_plugin_api.<locals>.forwardÅ  sî   ÿùé € ô ×(Ò(Ô)CÀTÓJ×JˆØŠ>Ü ¨W°T±HÐ<[Ð+\Ð ]ÐknÔoÐoØ(.Ñ%ˆˆm˜XÝLØ Ÿ™×*Ñ*ÀÇÁ×@UÑ@UÔ@WÔ,oÑ@W¹¸Ð[\×[bÑ[bÓ[dÐhnÑ[n¬V¨a«VÑ@WÒ,oˆˆˆwØ—\‘\“^×#ˆÝQÙ4°WÓ=ˆÙ'¨¯	©	°4÷ ::õ ::ó ;÷ ;ð 	;ñ Kùó
 -pÙ#ñ;ùsF   ŒD«D ¬ADÂDÂ$DÂ+DÃDÃ6DÃ;D
Ã<DÄDÄ
Dr9  z/{path:path}F)Úinclude_in_schemaÚmethodsÚdependenciesz?Mounted plugin API routes via the plugin host: /api/plugins/%s/NrÔ   ©ÚGETÚPOSTÚPUTÚPATCHÚDELETEÚOPTIONSÚHEAD)Úadd_api_router   ro  r[   r  )rg   rÀ  rq  r†  r>   s   &&& @r   Ú_mount_hosted_plugin_apir”  ¿  s_   ø€ ð �&�>€D÷;ò ;ð" ×Ñ˜ d V¨>Ð:¸GÐW\ÚZÜ$+Ô,FÓ$GÐ#Hð ô Jô 	‡I�IÐOÐQUÖVr!   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# r¼  )r   r   r[  )r   s   "r   r    r    Ü  s   € ÷ ñ ¤Sð ¬X´e­_ñ r!   c                ó|  € ^ RI Hp ^ RIHpHp \        4        FŸ  pVP                  R4      V 8w  g.   VP                  R4      '       d   VP                  R4      R8w  d   KH  \        WC! 4       V! 4       4      '       d    R# V! 4       P                  4       \        VR,          4      \        VR,          4      3u # 	  R# )	z�``(plugin host, dashboard dir, api file)`` for plugin ``name`` in the active profile, or None
when that profile has no enabled user copy of it.)Úget_plugin_manager©rè  ré  r>   r~  rp  ra  Nr}  )
rf  r—  r  rè  ré  rœ  r/   r%  Ú_plugin_hostr   )r>   r—  rè  ré  rÀ  s   &    r   r‚  r‚  Ü  s—   € õ 6ßJÜ-Ö/ˆØ�:‰:�fÓ Ô%¨V¯Z©Z¸×-DÒ-DÈÏ
É
ÐS[ÓH\Ð`fÔHfÙÜ(¨Ð1AÓ1CÑEVÓEX×YÒYÚÙ!Ó#×0Ñ0Ó2´C¸¸v½Ó4GÌÈVÐT_ÕM`ÓIaÐaÒañ 0ñ r!   c            	     ó.  € ^ RI Hp Hp  ^ RIHpHp V! 4       pV! 4       pV ! 4        F&  p\        ;_uu_ 4        \        WWE4       RRR4       K(  	  \        V4       R#   \         d    \        4       p\        4       p L_i ; i  + '       g   i     Km  ; i)uÃ  Import and mount backend API routes from plugins that declare them.

Each plugin's ``api`` file must expose a ``router`` (FastAPI APIRouter), mounted under
``/api/plugins/<name>/``. See ``_plugin_api_mount_skip_reason`` for the trust gates.

Backend import is restricted to ``bundled`` and ``user`` sources. Project plugins
(``./.hermes/plugins/``) ship with the CWD and are therefore attacker-controlled in any threat model
where the user opens a malicious repo; they can extend the dashboard UI via static JS/CSS but their
Python ``api`` file is never auto-imported by the web server. See GHSA-5qr3-c538-wm9j (#29156).
Additionally, user plugins must be explicitly enabled via the ``plugins.enabled`` allow-list in
config.yaml before their backend code is imported. Without this gate, an installed-but-not-enabled
plugin's Python code would execute at dashboard startup â€” a code execution vector that bypasses the
user's intent. (#46435, GHSA-mcfc-hp25-cjv7)
©rà  rg   )ré  rè  N)rÕ   rà  rg   r  ré  rè  rZ   r‘  Ú_plugin_api_mount_lockÚ_mount_one_plugin_apiÚ_register_plugin_api_fallback)rà  rg   ré  rè  rÓ  rÔ  rÀ  s          r   Ú_mount_plugin_api_routesrŸ  ê  s|   € ÷ BðßNÙ&Ó(ˆÙ(Ó*ˆñ
 )Ö*ˆß#Ö#Ü! #¨{ÔI÷ $Ñ#ñ +ô " #Ö&øô ô Ü“eˆÜ“uŠðú÷
 $×#Ð#ús   ŠA ¸BÁB Á?B ÂBc                ó0   € V ^8„  d   QhR\         R\        /# r¼  r>  )r   s   "r   r    r      s   € ÷ 'ñ '¤Cð '¬Dñ 'r!   c                ó2  a € S '       dH   \         ;QJ d    V 3R lR 4       F  '       g   K   RM	  RM! V 3R lR 4       4      '       g   S R8X  d   R# ^ RIHpHp ^ RIHpHp ^ RIHpH	pH
p V! 4       R	JV! S 4      \        4       r©p\        4       ;_uu_ 4        \        ;_uu_ 4        V! 4       V! 4       rË\        VS 4      '       d    R	R	R	4       R	R	R	4       R# \        V 3R
 lV! RR7       4       R	4      pV'       dE   V	e*   V	P!                  R4      R8w  g   V! V4      V! V	4      8w  d    R	R	R	4       R	R	R	4       R# V
w  r¼VP"                  P$                  p\'        V4      pVe   \)        WMW¼4      '       g    R	R	R	4       R	R	R	4       R# WïR	 VR	V pp\        R \+        V4       4       \'        V4      4      pVR	V V,           VVR	 ,           VR&    R	R	R	4       R	R	R	4       R#   + '       g   i     M; iR	R	R	4       R	#   + '       g   i     R	# ; i)aP  Mount plugin ``name``'s backend API on the running app; True when new routes went live.

A plugin installed or enabled after server start had no route until restart: the startup
sweep is the only other caller of ``_mount_one_plugin_api``. Discovery is re-run (the plugin
dir may not have existed at startup) and the decision is the launch profile's, exactly as at
startup (its enable sets and its ``plugins.isolation``), so a plugin the launch profile did not
enable is never imported or forwarded (#134889); a secondary profile's request (its grant or a
``?profile=`` selection) may mount only its own bundled copy, by its own lists (PLG-3). New
routes are spliced in just ahead of the hot-mount fallback, which sits before the SPA
catch-all: appended at the end they would land behind ``/{full_path:path}`` and every GET
would keep missing them.
c              3   ó,   <"  € T F	  qS9   x € K  	  R # 5ir  r?   )r@   Úcr>   s   & €r   rC   Ú,_try_hot_mount_plugin_api.<locals>.<genexpr>  s   øé € Ð2©' Q˜D–y«'ùs   ƒz/\{}TFz..r˜  r›  )Úplugin_api_pathÚsecondary_pluginrA  Nc              3   óV   <"  € T F  qP                  R 4      S8X  g   K  Vx € K   	  R# 5ir=   r#  rC  s   & €r   rC   r¤  !  s$   øé € ÐeÑ"K˜QÏuÉuÐU[Ë}Ð`dÑOd—q’qÓ"KùrE  )Úforce_rescanrp  rc  c              3   óX   "  € T F   w  r\        VR R4      \        J g   K  Vx € K"  	  R# 5i©ÚendpointN©rx   Ú_plugin_api_hot_mount)r@   Úir  s   &  r   rC   r¤  +  s%   é € Ðj¡™˜´G¸A¸zÈ4Ó4PÔTiÐ4i—1’1£ùs   ‚* 
*:NNN)rV   r  rè  ré  rÕ   rà  rg   rF  r¥  r¦  rA  r3  r,  rœ  Ú_plugin_api_mountedrÄ  r/   ÚrouterÚroutesr  r�  Ú	enumerate)r>   rè  ré  rà  rg   r¥  r¦  rA  Ú	secondaryÚownÚrequester_setsrÓ  rÔ  rÀ  r±  ÚbeforeÚfreshÚrestÚats   f                  r   Ú_try_hot_mount_plugin_apirº    s¡  ø€ ÷ —3“3Ô2©'Ó2—3—3’3Ô2©'Ó2×2Ò2°d¸d´lÙßJßAßoÑoñ &<Ó%=ÀTÐ%IÑK[Ð\`ÓKaÔc{Óc}�N€IÜ	×	 Õ	 ×"8Ö"8Ù$4Ó$6Ñ8IÓ8K�\Ü˜s D×)Ò)Ø÷ #9×	 Ñ	 ô ÔeÑ"8ÀdÕ"KÓeÐgkÓlˆßØŠ{˜cŸg™g hÓ/°9Ô<ÁÐPVÓ@WÑ[jÐknÓ[oÔ@oØ÷ #9×	 Ñ	 ð )7Ñ%ˆKØ—‘×"Ñ"ˆÜ�V“ˆØŠ>Ô!6°sÀK×!^Ò!^Ø÷ #9×	 Ñ	 ð ˜W�o v¨g¨v ˆtˆÜÑj¤¨4¤ÓjÔloÐptÓluÓvˆð ˜˜"�I Õ%¨¨R¨S¨	Õ1ˆˆq‰	Ø÷% #9×	 Ñ	 ×"8×"8ú×	 ×	 ×	 Ò	 úsJ   ÂHÂ(!G(	Ã	HÃAG(	Ä.HÅ <G(	Å<HÆAG(	ÇHÇ(G8Ç3HÈH	c                ó0   € V ^8„  d   QhR\         R\        /# r¼  r>  )r   s   "r   r    r    2  s   € ÷ 	ñ 	¤3ð 	¬4ñ 	r!   c                óÒ   a€ RV 2o\         ;QJ d3    V3R lV P                  P                   4       F  '       g   K   R# 	  R# ! V3R lV P                  P                   4       4      # )uá   Whether ``app`` already serves ``/api/plugins/<name>/`` â€” read from the route table itself,
so anything that rebuilds the routes (a test restoring its snapshot) cannot leave a stale
"mounted" record that blocks the remount.r9  c              3   óÐ   <"  € T F[  p\        VR R4      \        J;'       d<    \        VRR4      S8H  ;'       g$    \        VRR4      P                  SR,           4      x € K]  	  R# 5i)r«  Nr´   r;   rŽ   )rx   r­  rÏ   )r@   r  r„   s   & €r   rC   Ú&_plugin_api_mounted.<locals>.<genexpr>7  so   øé € ð ñ #ˆAô 	��:˜tÓ$Ô,AÐA÷ 	bð 	bÜ�Q˜ Ó# vÑ-×`Ð`´¸¸FÀBÓ1G×1RÑ1RÐSYÐ\_ÕS_Ó1`ô	bã"ùs   ƒA&¢A&º,A&TF)rV   r°  r±  )rg   r>   r„   s   &&@r   r¯  r¯  2  sd   ø€ ð ˜T˜FÐ#€Fß‹3ô ð —‘×"Ò"ó�3Œ3ð Š3ð ˆ3ô ð —‘×"Ò"óó ð r!   c                   ó6   a € ] tR tRt o RtV 3R lR ltRtV tR# )Ú_PluginApiHotMounti>  ue  ASGI fallback for ``/api/plugins/{name}/{path}`` requests no mounted router matched.

Registered after every startup router, so it only sees plugins that are not mounted yet
(auth and ``_plugin_api_runtime_gate`` already ran). On a successful hot mount the SAME
request is re-routed to the fresh routes in-process â€” no redirect: Desktop's transport
never follows a 3xx and would fail the first poll. A second miss lands back here, finds the
plugin mounted and gets the plain 404, so re-routing cannot loop. A class instance, not a
function: Starlette wraps plain functions as ``request -> response`` endpoints.
c                ó   <€ V ^8„  d   QhRR/# r¡  r?   )r   rµ   s   "€r   r    Ú_PluginApiHotMount.__annotate__I  s   ø€ ÷ 
[ñ 
[°dñ 
[r!   c              ƒ  óì  "  € ^ RI Hp ^ RIHp \	        VP                  R/ 4      P                  RR4      4      pV! V4      ;_uu_ 4        \        P                  ! \        V4      G Rj  x€L
 pRRR4       X'       d>   \        P                  RV4       VP                  \        V/ R7      W#4      G Rj  x€L
  R# \        R	R
/RR7      ! WV4      G Rj  x€L
  R#  Lq  + '       g   i     Lw; i L; L5i)r­  rP  )rU  Úpath_paramsr>   r;   Nz@Hot-mounted plugin API routes on first request: /api/plugins/%s/)rÄ  rÎ   z	Not Foundrt   ru   )rÕ   rg   rF  rU  r   r/   rG  rH  rº  r[   r  r°  r+   r
   )rº   r»   r\  r]  rg   rU  r>   Úmounteds   &&&&    r   r_  Ú_PluginApiHotMount.__call__I  s¹   é € Ý-ÝNÜ�5—9‘9˜]¨BÓ/×3Ñ3°F¸BÓ?Ó@ˆÙ! %×(Õ(Ü#×-Ò-Ô.GÈÓN×NˆG÷ )çÜ�I‰IÐXÐZ^Ô_Ø—*‘*œT %°RÔ8¸'ÓH×HÐHÙÜ˜H kÐ2ÀÕDÀUÐUYÓZ×ZÒZñ O÷ )×(úñ IáZùsT   ‚AC4Á
CÁ)CÁ*CÁ.C4Á>6C4Â4C0Â5C4ÃC2ÃC4ÃCÃC-	Ã(	C4Ã2C4r?   N)r¿   rÀ   rÁ   rÂ   rÃ   r_  rÄ   rÅ   ra  s   @r   rÀ  rÀ  >  s   ø‡ € ñ÷
[ö 
[r!   rÀ  c                ó   € V ^8„  d   QhRR/# r¡  r?   )r   s   "r   r    r    Y  s   € ÷ 2ñ 2¨$ñ 2r!   c                ó  € \         ;QJ d0    R V P                  P                   4       F  '       g   K   RM%	  RM!! R V P                  P                   4       4      '       d   R# V P                  P                  R\        . RORR7       R# )z�Register the hot-mount fallback once, after the startup plugin routers (so a mounted
router always matches first) and before the SPA catch-all.c              3   óH   "  € T F  p\        VR R4      \        J x € K  	  R# 5irª  r¬  )r@   r  s   & r   rC   Ú0_register_plugin_api_fallback.<locals>.<genexpr>\  s!   é € Ð
\ÑJ[ÀQŒ7�1�j $Ó'Ô+@Õ@ÓJ[ùs   ‚ "TFNz/api/plugins/{name}/{path:path})r‰  rˆ  r‹  )rV   r°  r±  Ú	add_router­  rP  s   &r   rž  rž  Y  s_   € ÷ ƒsÑ
\È#Ï*É*×J[ÒJ[Ó
\‡s‡s‚sÑ
\È#Ï*É*×J[ÒJ[Ó
\×\Ò\ÙØ‡J�J×ÑÐ:Ô<QÚ!]Ø+0ð ö 2r!   c                ój   € V ^8„  d   QhR\         \        \        3,          R\        R\        R\        /# r!  )r+   r   r   r‘  rw   )r   s   "r   r    r    c  s8   € ÷ Gñ G¤t¬C´¨H¥~ð GÄCð GÔWZð GÔ_cñ Gr!   c                ó*  € VP                  R4      pV'       g   R# \        WP                  RR4      4      '       d   R# \        WV4      pV'       d*   \        P	                  RVP                  RR4      V4       R# VP                  R4      R9  d#   ^ RIHpHp V! 4       V8X  d   \        WV4       R	# VP                  R4      R8X  d!   \        P                  R
VR,          V4       R# \        VR,          4      pW„,          p	 V	P                  4       P                  VP                  4       4       T	P!                  4       '       g!   \        P                  RTR,          T4       R#  RTR,           2p
\"        P$                  P'                  Y©4      pTe   TP(                  f   R# \"        P$                  P+                  T4      pT\,        P.                  T
&    TP(                  P1                  T4       \7        TRR4      pTf    \        P                  RTR,          4       R# T P9                  TRTR,           2\;        \<        4      .R7       \        P?                  RTR,          4       R	#   \        \        \        3 d#    \        P                  RTR,          T	4        R# i ; i  \2         d#    \,        P.                  P5                  T
R4       h i ; i  \2         d,   p\        P                  RTR,          TR	R7        Rp?R# Rp?ii ; i)a.  Mount one plugin's backend API routes on ``app`` if its trust gates pass.

Returns True when routes were added. Callers must hold ``_plugin_api_mount_lock``.
Shared by the import-time sweep and the hot-mount fallback so both paths
apply the exact same gates (GHSA-mcfc-hp25-cjv7, GHSA-5qr3-c538-wm9j).
r~  Fr>   r;   z"Plugin %s: skipping API mount (%s)rp  re  )ÚISOLATION_HOSTÚisolation_modeTz‹Plugin %s: ignoring backend api=%s (project plugins may not auto-import Python code; move the plugin to ~/.hermes/plugins/ if you trust it)r}  zKPlugin %s: refusing to import api file outside its dashboard directory (%s)z,Plugin %s declares api=%s but file not foundÚhermes_dashboard_plugin_Nr°  z,Plugin %s api file has no 'router' attributer9  )r„   rŠ  z+Mounted plugin API routes: /api/plugins/%s/z'Failed to load plugin %s API routes: %srS   )rc  re  ) r/   r¯  r%  r[   r\   Úhermes_cli.plugin_isolationrÎ  rÏ  r”  r  r   r¨   rV  r�   rW  rð   rÐ   Ú	importlibÚutilÚspec_from_file_locationÚloaderÚmodule_from_specÚsysÚmodulesÚexec_modulerZ   Úpoprx   Úinclude_routerr   ro  r  )rg   rÀ  rÓ  rÔ  rq  ÚskiprÎ  rÏ  rS  Úapi_pathÚmodule_nameÚspecÚmodr°  r™  s   &&&&           r   r�  r�  c  s›  € ð —J‘J˜{Ó+€MßÙÜ˜3§
¡
¨6°2Ó 6×7Ò7ÙÜ(¨¸lÓK€DßÜ�
‰
Ð7¸¿¹ÀFÈBÓ9OÐQUÔVÙØ‡z�z�(ÓÐ#9Ô9ßNÙÓ˜~Ô-Ü$ S°-Ô@ÙØ‡z�z�(Ó˜yÔ(Ü�‰ð2ð �6�N˜Mô		
ñ Ü˜ �Ó(€MØÕ,€Hð	Ø×ÑÓ×&Ñ& }×'<Ñ'<Ó'>Ô?ð �?‰?×ÒÜ�‰ÐCÀVÈFÅ^ÐUbÔcÙðØ0°¸µÐ0@ÐAˆÜ�~‰~×5Ñ5°kÓLˆØŠ<˜4Ÿ;™;Ò.ÙÜ�n‰n×-Ñ-¨dÓ3ˆð $'Œ�‰�KÑ ð	Ø�K‰K×#Ñ# CÔ(ô ˜˜h¨Ó-ˆØŠ>Ü�L‰LÐGÈÐPVÍÔXÙØ×ÑØØ" 6¨&¥>Ð"2Ð3Ü!Ô"<Ó=Ð>ð 	ô 	
ô
 	�	‰	Ð?ÀÈÅÔPÙøôG ”\¤:Ð.ô ô 	�‰ð'Ø(.¨v­¸ô	
ò ðûô, ô 	Ü�K‰K�O‰O˜K¨Ô.Øð	ûô ô Ü�‰Ð>ÀÀvÅÐPSÐ^bˆÔcÝûðúsO   Ä-I1 Å)=K Æ(2K ÇJ, Ç6.K È&A	K É14J)Ê(J)Ê,-KËK ËLË' LÌLc                óŠ  € V ^8„  d   Qh/ ^ \         9   d   \        \        \        3,          ;R&   ^\         9   d   \        \        \        3,          ;R&   ^\         9   d,   \        \        \        \        \        3,          3,          ;R&   ^\         9   d   \        \        \        3,          ;R&   ^\         9   d
   \
        ;R&   # )r   rY   r)  r¤  r¦  r±  )Ú__conditional_annotations__r+   r   r   rê   r‘  )r   s   "r   r    r       s£   € ÷ ñ ÷@	ò œ4¤¤S �>ñ ñA	÷N	ò ”tœC¤˜H•~ñ ñO	÷v 3Ò 2”Dœœd¤3¬ 8�nÐ,Õ-Ñ 2ñw÷x 5Ò 4œt¤C¬ JÕ/Ñ 4ñy÷L )Ò (œSÑ (òMr!   r$  >   ÚcardÚringÚinputÚmutedÚaccentÚborderÚpopoverÚprimaryÚsuccessr  r³  ÚdestructiveÚcardForegroundÚmutedForegroundÚaccentForegroundÚpopoverForegroundÚprimaryForegroundÚsecondaryForegroundÚdestructiveForeground>   ÚbgÚheroÚlogoÚcrestÚheaderÚsidebar>	   rr  rã  ÚpageÚbadgeÚfooterrø  rù  ÚbackdropÚprogress>   ÚtiledÚcockpitr#  i €  r  )F)nrâ  rÃ   rG  ÚloggingÚimportlib.utilrÒ  rz   r×   r×  r©  r   Ú
contextlibr   Úhermes_yamlrK  Úfastapir   r   r   r   r   Úfastapi.responsesr   r	   r
   r   Úfastapi.staticfilesr   Ú	starletter   Ústarlette._utilsr   Ústarlette.requestsr   Úpathlibr   Útypingr   r   r   r   rU   r   r   Úutilsr   Úhermes_cli.web_asset_mime_typesr   Ú	getLoggerr[   r%   r2   r`   rª   r~   r}   rÚ   rW   rõ   rY   r)  r+  r,  r.  r0  r-  r  r  r  rD  rX   rY  rn  r†  rœ  rŸ  r  r¤  r¦  ÚLockr£  r§  r‘  r±  r°  rº  rÅ  rÐ  rÙ  r  r%  r,  r3  r6  r<  rJ  rL  rZ  rœ  ro  r”  r‚  rŸ  rº  r¯  rÀ  r­  rž  r�  r    )râ  s   @r   Ú<module>r     sø  øðöó Û Û Û Û 	Û 
Û Û Ý %Û ß PÕ Pß PÓ PÝ +Ý Ý +Ý -Ý ß ,Ó ,ç >Ý !õ Ká Ô  ð ×ÒÐ0Ó1€õ!õMõ
,ðb "GÐ ØÐCÐD€	ð-ð õO$ðp ˆY˜g }¸mÐM~ÐØˆ_˜gÐ'<¸mð  NAð  BØˆ[˜g {¸mð  NFð  GØˆZ˜g z¸mÐMqÐrØˆW˜' 7°]ÐDmÐnØˆV˜' 6°]ÐDmÐnØˆ[˜' ;°]ÐDmÐnØˆV˜' 7°mÐEtÐuð	Ð ÷Bð( ÐcØÐVØ�Ø�&Ø�Sð-Ð ó ð ˆh˜	 =ð)Ð ó òÐ ò OÐ òÐ ò :Ð ð "Ð õ4õ
:õTõ^õBõ2õ2(õV&÷RõDAð "%Ð Ø02Ð Ó 2Ø24Ð Ó 4Ø#Ÿ.š.Ó*Ð õ.ñ $'£5Ð Ó (Ø#Ÿ.š.Ó*Ð õõ<sõõ,h÷
qõhð  ñ*ó ð*õ
DõZõTõP÷ Yñ Yð@ ñó ðð2 #ŸšÓ)Ð ÷õ,Wõ:ò'õ<'õT	÷[ñ [ñ0 +Ó,Ð õ2÷Gr!   