+
    jHàj¡  ã                  óÂ   € R t ^ RIHt ^ RIt^ RIHt ^ RIHt ]P                  ! ]	4      t
R R ltRR R lltR	 R
 ltR R ltRR R lltRR R lltRR/R R lltR# )aL  Which profiles does the LIVE default multiplexer serve? One answer for every CLI/dashboard surface.

``gateway/run_adapters.py::_record_served_profiles`` writes ``served_profiles`` into the default
home's ``gateway_state.json`` at startup. That record is the truth about the running process; the
default ``config.yaml`` plus ``GATEWAY_MULTIPLEX_PROFILES`` as seen by the *CLI* process is only a
guess (``hermes -p coder ...`` loads coder's ``.env``, so an env-only opt-in on the default profile
is invisible to it, and an allowlist edited after start flips the guess before the restart).
)ÚannotationsN)ÚPath)ÚOptionalc               ó   € V ^8„  d   QhRR/# )é   ÚreturnzOptional[int]© )Úformats   "ÚH/home/ubuntu/.hermes/hermes-agent/hermes_cli/gateway_multiplex_served.pyÚ__annotate__r      s   € ÷ @ñ @ -ñ @ó    c                 ó4   € ^ RI Hp  ^ RIHp V! V ! 4       4      # )a'  PID of the default profile's gateway when a VERIFIED live process owns it, else None.

``gateway.status.live_gateway_pid_for_home``: pid file + lock, then the runtime record the gateway
itself writes, each proven against the live process (start time, gateway command line, home). A
launch-service gateway can be live with no ``gateway.pid`` at all, and a stale record whose PID was
recycled by an unrelated process must not make its ``served_profiles`` authoritative. Never key this
off the record's ``updated_at``: an idle gateway never advances it.
©Úget_default_hermes_root)Úlive_gateway_pid_for_home)Úhermes_constantsr   Úgateway.statusr   )r   r   s     r
   Úlive_default_gateway_pidr      s   € õ 9Ý8Ù$Ñ%<Ó%>Ó?Ð?r   c               ó    € V ^8„  d   QhRRRR/# )r   Údefault_rootzOptional[Path]r   úOptional[list[str]]r   )r	   s   "r
   r   r   !   s   € ÷ 
Jñ 
J¨>ð 
JÐEXñ 
Jr   c                ó  € ^ RI Hp ^ RIHp \	        4       f   R# T! T ;'       g    V! 4       R,          4      pT;'       g    / P                  R4      p\        V\        4      '       d   V Uu. uF  p\        V4      NK  	  up# R# u upi )a  ``served_profiles`` the live default gateway recorded, or None when the key is absent (a record
from before the multiplexer recorded it, or a stopped/absent gateway). Callers fall back to config
derivation only on None: an empty list is an authoritative "serves nobody else".r   ©Úread_runtime_statusNúgateway_state.jsonÚserved_profiles)	r   r   r   r   r   ÚgetÚ
isinstanceÚlistÚstr)r   r   r   ÚruntimeÚservedÚps   &     r
   Úrecorded_served_profilesr#   !   sv   € õ 9Ý2ÜÓ!Ò)ÙÙ! <×#LÐ#LÑ3JÓ3LÐPdÕ"dÓe€GØ�mˆm˜× Ñ Ð!2Ó3€FÜ'1°&¼$×'?Ò'?™FÓ#™F�qŒC�ŽF™FÑ#ÐIÀTÐIùÒ#s   Á.Bc               ó   € V ^8„  d   QhRR/# )r   r   ú	list[str]r   )r	   s   "r
   r   r   .   s   € ÷ Sñ S¨	ñ Sr   c                 óx   € \        4       ;'       g    .  U u. uF  q '       g   K  V R8w  g   K  V NK  	  up # u up i )z[Named profiles the live default multiplexer serves (excludes ``default``); empty when none.Údefault)r#   )r"   s    r
   Úmultiplexer_served_secondariesr(   .   s6   € ä0Ó2×8Ð8°bÐ8ÓRÑ8�!»QŒAÀ1È	Á>�AˆAÑ8ÑRÐRùÒRs   —	7¥7®7c               ó    € V ^8„  d   QhRRRR/# )r   Úprofiler   r   údict[str, str]r   )r	   s   "r
   r   r   3   s   € ÷ ñ ¨sð °~ñ r   c           
     óR  € ^ RI Hp ^ RIHp V '       d   \	        4       f   / # V! V! 4       R,          4      ;'       g    / pVP                  R4      p\        V\        4      '       g   / # V  R2pVP                  4        UUu/ uF—  w  rg\        V\        4      '       g   K  VP                  V4      '       g   K6  \        V\        4      '       g   KN  VP                  R4      R
9   g   Kf  V\        V4      R \        VP                  R4      ;'       g    R	4      bK™  	  upp# u uppi )zñ``{platform: reason}`` for a served profile's platforms the multiplexer deliberately does not run
(unpaired WhatsApp or Relay shared ingress; ``gateway.run_adapters`` stamps
``<profile>:<platform>`` as ``disabled`` with a reason and remedy).r   r   Nr   Ú	platformsÚ:Ú
error_codeÚerror_messageznot served under multiplex>   Úwhatsapp_unpairedÚmultiplex_shared_ingress)r   r   r   r   r   r   r   ÚdictÚitemsr   Ú
startswithÚlen)r*   r   r   r    r-   ÚprefixÚkeyÚentrys   &       r
   Ú!served_profile_unserved_platformsr:   3   s  € õ 9Ý2ßÔ.Ó0Ò8Øˆ	Ù!Ñ"9Ó";Ð>RÕ"RÓS×YÐYÐWY€GØ—‘˜KÓ(€IÜ�i¤×&Ò&Øˆ	Øˆy˜ˆ]€Fð $Ÿ/™/Ô+ôá+‰JˆCÜ�cœ3×ô 	[à$'§N¡N°6×$:ô 	[ä?IÈ%ÔQU×?Vô 	[ð �I‰I�lÓ#Ð'XÑXô 	[ˆŒC�‹KˆLÐœ3˜uŸy™y¨Ó9×YÐYÐ=YÓZÒZÙ+òð ùó s$   ÂD#Â!D#Â:D#ÃD#Ã*)D#ÄD#c               ó    € V ^8„  d   QhRRRR/# )r   r*   zOptional[str]r   zdict[str, dict[str, str]]r   )r	   s   "r
   r   r   H   s   € ÷ ñ ¨ð ÐB[ñ r   c                ó   € ^ RI Hp ^ RIHpHp \        4       f   / # V! V! 4       R,          4      ;'       g    / pVP                  R4      p\        V\        4      '       g   / # / pVP                  4        F­  w  rx\        V\        4      '       d   RV9   d   \        V\        4      '       g   K:  VP                  R4      p	V	'       d   VP                  R4      R
9   d   Kk  VP                  R^4      w  r«V '       d	   W 8w  d   K�  \        V	4      VP                  V
/ 4      V&   K¯  	  VP                  R4      ;'       g    .  Uu. uF   qÌ'       g   K  VR	8w  g   K  \        V4      NK"  	  ppV '       g   TMV Uu. uF  qÌV 8X  g   K  VNK  	  up F`  p
V! WJ4      P                  4        FC  w  r¸VP                  R4      '       g   K  \        VR,          4      VP                  V
/ 4      V&   KE  	  Kb  	  V# u upi u upi )a&  ``{profile: {platform: url}}`` for every secondary inbound-port platform the live multiplexer
serves on its shared listener (``<profile>:<platform>`` entries carrying ``ingress_url``). This is
what the user pastes into the vendor console (Twilio, LINE, Teams, ...). ``profile`` narrows the map.r   )r   Ú shared_listener_mirror_platformsr   r-   r.   Úingress_urlÚstater   r'   )ÚfatalÚdisconnectedÚstopped)r   r   r   r   r=   r   r   r   r3   r4   r   ÚsplitÚ
setdefault)r*   r   r   r=   r    r-   Úurlsr8   r9   ÚurlÚnameÚplatformr"   r!   s   &             r
   Úserved_profile_ingress_urlsrI   H   s§  € õ 9ßTÜÓ!Ò)Øˆ	Ù!Ñ"9Ó";Ð>RÕ"RÓS×YÐYÐWY€GØ—‘˜KÓ(€IÜ�i¤×&Ò&Øˆ	Ø&(€DØ—o‘oÖ'‰
ˆÜ˜3¤×$Ò$¨°¬¼
À5Ì$×8OÒ8OÙØ�i‰i˜Ó&ˆß�e—i‘i Ó(Ð,PÔPÙØŸ™ 3¨Ó*‰ˆß�t”ÙÜ.1°#«hˆ�‰˜˜bÓ! (Ó+ñ (ð  'Ÿ{™{Ð+<Ó=×CÐCÀÐCÓ]ÑC˜ËŒfÈaÐS\ÉnŒfŒc�!ŽfÑC€FÐ]ß%‘±vÓ+N±v°!ÀgÁ¯A¨A±vÑ+NÒNˆÙ?ÀÓN×TÑTÖV‰OˆHØ�y‰y˜×'Ô'Ü69¸%ÀÕ:NÓ6O�—‘  bÓ)¨(Ó3ó  Wñ Oð €Kùò ^ùÚ+Ns   Å	G6ÅG6ÅG6Å:G;ÆG;c               ó$   € V ^8„  d   QhRRRRRR/# )r   rE   r+   Úindentr   r   r%   r   )r	   s   "r
   r   r   h   s&   € ÷ Tñ T >ð T¸3ð TÈ)ñ Tr   c                óv   € \        V P                  4       4       UUu. uF  w  r#V V RV 2NK  	  upp# u uppi )z<One ``<indent><platform>: <url>`` line per platform, sorted.z: )Úsortedr4   )rE   rK   rH   rF   s   &&  r
   Úformat_ingress_url_linesrN   h   s8   € ä>DÀTÇZÁZÃ\Ô>RÔSÑ>R©]¨Xˆvˆh�x�j  3 %Ó(Ñ>RÒSÐSùÓSs   �5Útimeoutg       @c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úprofile_namer   rO   Úfloatr   r   r   )r	   s   "r
   r   r   m   s'   € ÷ Jñ J°cð JÀuð JÐWjñ Jr   c               ó–  €  ^ RI Hp ^ RIHp \	        4       f   R# V! V! 4       VR7      p\        T\        4      '       d   TP                  R4      R	J d   R# TP                  R
4      p\        T\        4      '       d   T Uu. uF  p\        T4      NK  	  up# R#   \
         d    \        P                  RT RR7        R# i ; iu upi )as  Tell the live default multiplexer that ``profiles/`` changed (``profile_name`` was created or
deleted) so it hot-serves / unroutes it now instead of at its next periodic rescan. Returns the
served-profile list the gateway answered with, or None when no multiplexer answered (no live default
gateway, single-profile gateway, or a gateway predating the verb). Never raises.r   )Úrescan_gateway_profilesN)rO   z-multiplexer rescan notification failed for %rT)Úexc_infoÚ	multiplexFr   )r   r   Úgateway.control_socketrT   r   Ú	ExceptionÚloggerÚdebugr   r3   r   r   r   )rQ   rO   r   rT   Úanswerr!   r"   s   &$     r
   Ú#notify_multiplexer_profiles_changedr\   m   s°   € ð
Ý<ÝBÜ#Ó%Ò-ÙÙ(Ñ)@Ó)BÈGÔTˆô �fœd×#Ò# v§z¡z°+Ó'>À%Ó'GÙØ�Z‰ZÐ)Ó*€FÜ'1°&¼$×'?Ò'?™FÓ#™F�qŒC�ŽF™FÑ#ÐIÀTÐIøô ô Ü�‰ÐDÀlÐ]aˆÔbÚðüò $s   ‚B œB ÂCÂ#CÃC)N)z  )Ú__doc__Ú
__future__r   ÚloggingÚpathlibr   Útypingr   Ú	getLoggerÚ__name__rY   r   r#   r(   r:   rI   rN   r\   r   r   r
   Ú<module>rd      s_   ðñõ #ã Ý Ý à	×	Ò	˜8Ó	$€õ@÷
JõSõ
÷*÷@Tð
JÈs÷ Jñ Jr   