
    epjS                       d Z ddlZddlZddlZddlZddlZddlZddlZ ej                    dk    Z	ddl
mZ ddlmZmZmZ ddlmZ ddlmZmZmZ d7d	ed
edefdZ ej        e          ZdZdedefdZdeddfdZdedede fdZ!deddfdZ"dededdfdZ#ddde ddfdZ$ddl%Z%e%j&        '                    d e ee(          )                                j*        d                              ddl+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9 ddl:m;Z; d ede fd!Z<d"edefd#Z=de fd$Z> G d% d&e/e3          Z?h d'Z@h d(ZAh d)ZBd*ed+e d,e defd-ZCddddd.d/ZDd8d0ZEd1eFd2eFdeFdz  fd3ZGde fd4ZHd5 ZId8d6ZJdS )9aG  
WhatsApp platform adapter.

WhatsApp integration is more complex than Telegram/Discord because:
- No official bot API for personal accounts
- Business API requires Meta Business verification
- Most solutions use web-based automation

This adapter supports multiple backends:
1. WhatsApp Business API (requires Meta verification)
2. whatsapp-web.js (via Node.js subprocess) - for personal accounts
3. Baileys (via Node.js subprocess) - alternative for personal accounts

For simplicity, we'll implement a generic interface that can work
with different backends via a bridge pattern.
    NWindows)Path)DictOptionalAny)windows_detach_popen_kwargs)find_node_executableget_hermes_dirwith_hermes_node_path namedefaultreturnc                 v    ddl m}m} 	  ||           }n# |$ r t          j        |           }Y nw xY w||n|S )a  Read a WHATSAPP_* env var through the profile secret scope.

    Under multiplexing, ``os.getenv`` bypasses the per-profile ``.env`` and
    returns the process-global value (often unset), causing the bridge to
    silently fall back to ``"self-chat"`` and reject all messages.
    ``get_secret`` honors the active ``_profile_runtime_scope`` so secondary
    profiles see their own credentials.
    r   )UnscopedSecretError
get_secret)agent.secret_scoper   r   osgetenv)r   r   r   r   vals        H/home/thesage/.hermes/hermes-agent/plugins/platforms/whatsapp/adapter.py_wenvr   %   sq     CBBBBBBBj    ioo /33w.s    22z[owner reply] portc                 B   g }	 t          j        ddd|  dgddddd	          }|j                                                                        D ]5}	 |                    t          |                     &# t          $ r Y 2w xY w|r|S n# t          $ r Y nw xY w	 t          j        d
dd|  gddddd	          }t          j
        d|j                  D ]7}|                    t          |                    d                               8n# t          $ r Y nw xY w|S )u  PIDs of processes *listening* on ``port`` (POSIX) — never clients.

    This must match only LISTEN sockets. A bare ``lsof -i :PORT`` (or
    ``fuser PORT/tcp``) also returns *clients* whose connection merely involves
    that port number — e.g. a browser with a tab open on a local dev server
    sharing the port. SIGTERMing those closed the user's browser at irregular
    intervals. Restricting to LISTEN state frees the port for a new bridge
    without ever touching an unrelated client.
    lsofz-tiztcp:z-sTCP:LISTENTutf-8replace   capture_outputtextencodingerrorstimeoutssz-ltnHpz	sport = :z	pid=(\d+)   )
subprocessrunstdoutstrip
splitlinesappendint
ValueErrorFileNotFoundErrorrefinditergroup)r   pidsresultlinems        r   _listener_pids_on_portr7   A   s    DUM4MM>:dWYXY
 
 
 M''))4466 	 	DCII&&&&    	K	   8///0dWYXY
 
 
 \6=99 	) 	)AKKAGGAJJ((((	)   KsI   AB "A65B 6
B B BB 
BBA2D 
DDc           
         	 t           rddlm} t          j        g dddddd |                      }|j                                        D ]}|                                }t          |          dk    rm|d	         d
k    ra|d         }|	                    d|            rA	 t          j        dd|d         dgdd |                       # t          j
        $ r Y w xY wdS t          |           D ]?}	 t          j        |t          j                   ## t           t"          t$          f$ r Y <w xY wdS # t&          $ r Y dS w xY w)zDKill any process *listening* on the given TCP port (a stale bridge).r   )windows_hide_flags)netstatz-anoz-pTCPTr   r   r   )r    r!   r"   r#   r$   creationflags   	LISTENINGr&   :taskkill/PID   /F)r    r$   r<   N)_IS_WINDOWShermes_cli._subprocess_compatr9   r'   r(   r)   r+   splitlenendswithSubprocessErrorr7   r   killsignalSIGTERMProcessLookupErrorPermissionErrorOSError	Exception)r   r9   r4   r5   parts
local_addrpids          r   _kill_port_processrT   g   s   ! 	HHHHHH  ^000#$\]0022  F
 0022 ! !

u::??uQx;'>'>!&qJ!**:t::66 !!&N!+VU1Xt D/3Q.@.@.B.B    
  *9 ! ! ! D!! !" .d33  GC0000*OWE   D 
    s`   B D7 #*CD7 C D7 C  D7 &D7 8DD7 D2/D7 1D22D7 7
EErS   session_pathc                     ddl m}  ||           sdS |ddl m}  ||           |k    S ddl m}  ||           }|sdS d|v ot	          |          |v S )u  True only if ``pid`` is alive AND still our node bridge for this session.

    The PID is read from a file written by a previous run.  Once that process
    exits and is reaped the kernel can recycle the number onto an unrelated
    process — observed in the wild landing on a desktop browser's main process,
    which a bare-liveness ``os.kill`` then SIGTERMed, closing the whole browser
    at irregular intervals (every time the flapping bridge restarted).

    Identity is confirmed two ways: the kernel start time captured when we wrote
    the pidfile (definitive), and — for legacy pidfiles with no baseline — the
    command line, which must contain ``node`` and this session's unique path.
    A recycled PID (different start time / different cmdline) is never ours.
    r   _pid_existsFNget_process_start_time)_read_process_cmdlinenode)gateway.statusrX   rZ   r[   str)rS   rU   expected_startrX   rZ   r[   cmdlines          r   _bridge_pid_is_oursra      s     +*****;s u!999999%%c**n<< 544444##C((G ugAC$5$5$@A    c                    | dz  }|                                 sdS d}d}	 |                    d                              d          }t          |d                                                   }t          |          dk    rA|d                                         r't          |d                                                   }nJ# t          t          t          t          f$ r* 	 |
                                 n# t          $ r Y nw xY wY dS w xY wt          || |          rY	 t          j        |t          j                   t                               d|           nI# t$          t&          t          f$ r Y n0w xY wdd	lm}  ||          rt                               d
|           	 |
                                 dS # t          $ r Y dS w xY w)u  Kill a bridge process recorded in a PID file from a previous run.

    The bridge writes ``bridge.pid`` into the session directory when it
    starts.  If the gateway crashed without a clean shutdown the old bridge
    process becomes orphaned — this helper finds and kills it.

    Critically, the recorded PID is re-validated against the live process
    (:func:`_bridge_pid_is_ours`) before any signal, so a recycled PID that now
    names an unrelated process (e.g. the user's browser) is never killed.
    
bridge.pidNr   r"   
r   r&   z2[whatsapp] Killed stale bridge PID %d from pidfilerW   z[whatsapp] Not killing pidfile PID %d: it is no longer the bridge (recycled onto an unrelated process); skipping to avoid killing a stranger.)exists	read_textrF   r-   r*   rG   r.   rO   	TypeError
IndexErrorunlinkra   r   rJ   rK   rL   loggerinforM   rN   r]   rX   warning)rU   pid_filerS   recorded_startlinesrX   s         r   _kill_stale_bridge_by_pidfilerr      s    l*H?? 
CN ""G"44::4@@%(..""##u::>>eAhnn..> q!1!122NJ7   	OO 	 	 	D	 3n== 	GC(((KKLcRRRR"OW= 	 	 	D	 	/.....;s 	NN&'*  
   sZ   B$C D$C98D9
DDDDD":E E76E7'F= =
G
Gc                     	 ddl m}  ||          }|t          |          nd                    ||          }| dz                      |d           dS # t
          $ r Y dS w xY w)a'  Write the bridge PID (and its kernel start time) for later cleanup.

    The start time on line 2 lets a future run prove the PID still names this
    exact process before signalling it, so a recycled PID can never be killed
    as a "stale bridge". Older single-line files remain readable.
    r   rY   Nz{}
{}rd   r   re   )r]   rZ   r^   format
write_textrO   )rU   rS   rZ   startr!   s        r   _write_bridge_pidfilerw      s    999999&&s++ =s3xxxhooc5.I.I		$000HHHHH   s   AA 
A$#A$Fforcery   c                >   t           rddt          | j                  dg}|r|                    d           	 t	          j        |ddddd	          }n<# t          $ r/ |r|                                  n|                                  Y d
S w xY w|j	        dk    r;|j
        p|j        pd                                }t          |p	d| j                   d
S dd
l}	 |                    | j                  }|                    d          }|r@|D ]'}	 |                                 # |j        $ r Y $w xY w|                                 d
S |D ]'}	 |                                 # |j        $ r Y $w xY w|                                 d
S # |j        $ r Y d
S w xY w)zITerminate the bridge process using process-tree semantics where possible.r@   rA   z/TrC   Tr   r   
   r   Nr   r   ztaskkill failed for PID )	recursive)rD   r^   rS   r,   r'   r(   r/   rJ   	terminate
returncodestderrr)   r*   rO   psutilProcesschildrenNoSuchProcess)	procry   cmdr4   detailsr   parentr   childs	            r   _terminate_bridge_processr      s    63tx==$7 	JJt	^#GI	  FF ! 	 	 	 !		   FF	 !!};;BBDDG'J%J%J%JKKKMMM))??T?22 	!  JJLLLL+   DKKMMMMM!  OO%%%%+   D   sq   A 5BB6F D('F (
D52F 4D55F F E('F (
E52F 4E55F 
FFr=   )PlatformPlatformConfig)WhatsAppBehaviorMixin)to_whatsapp_jid)BasePlatformAdapterMessageEventMessageType
SendResultSUPPORTED_DOCUMENT_TYPEScache_image_from_urlcache_audio_from_url)env_inturlc                    	 t          |                                           }n# t          t          f$ r Y dS w xY wddlm}m}m}m}  |             |             |             |            fD ]Q}	 |	                    t          |                                                    r dS ;# t          t          f$ r Y Nw xY wdS )u~  Return True only when an absolute path from the bridge resolves inside a
    known Hermes media cache directory.

    The Baileys bridge is a local subprocess that downloads inbound media and
    hands back absolute file paths. A compromised or buggy bridge could hand
    back an arbitrary path (e.g. ``/etc/passwd``) which would otherwise be
    attached verbatim and sent to the model. Resolve the path (following any
    symlinks) and require it to live under one of the real cache roots — this
    covers both the canonical ``cache/<kind>`` layout and the legacy
    ``<kind>_cache`` layout that ``get_hermes_dir`` may return.
    Fr   )get_audio_cache_dirget_document_cache_dirget_image_cache_dirget_video_cache_dirT)
r   resolverO   r.   gateway.platforms.baser   r   r   r   is_relative_to)r   resolvedr   r   r   r   roots          r   _is_allowed_bridge_pathr   -  s)   99$$&&Z    uu            	  	 
 
	&&tDzz'9'9';';<< tt$ 	 	 	H	5s   !$ 9914B))B=<B=pathc                     ddl }	 |                    |                                                                           dd         S # t          $ r Y dS w xY w)a  Return the first 16 hex chars of the SHA-256 of *path*'s contents.

    Used for the bridge staleness handshake: bridge.js reports its own
    source hash in ``/health`` (``scriptHash``), and the adapter compares
    it against the hash of bridge.js currently on disk.  A mismatch means
    a long-lived bridge process is serving code from before an update.
    Returns ``""`` when the file can't be read.
    r   N   r   )hashlibsha256
read_bytes	hexdigestrO   )r   r   s     r   _file_content_hashr   V  se     NNN~~doo//00::<<SbSAA   rrs   A A 
AAc                      t          d          } | sdS 	 t          j        | dgddddd          }|j        d	k    S # t          $ r Y dS w xY w)
z}
    Check if WhatsApp dependencies are available.
    
    WhatsApp requires a Node.js bridge for most implementations.
    r\   Fz	--versionTr   r   r   r   r   )r	   r'   r(   r~   rP   )_noder4   s     r   check_whatsapp_requirementsr   f  s     !((E u	K 		
 
 
  A%%   uus   &< 
A
	A
c                   6    e Zd ZdZdZdZdef fdZdede	de	fd	Z
d
ddedefdZdCdZdee         fdZdCdZ	 	 dDdededee         deeeef                  def
dZd
ddededededef
dZ	 	 dDdedededee         dee         defdZdd ded!ed"ee         d#edef
d$Z	 dEded!ed%ee         d&ed'edeeeef                  def fd(Zddddd)ded*e	d+e	d,ee         d-ee         dee         deeeef                  defd.Z	 	 	 dFded/edee         dee         deeeef                  def fd0Z	 	 dDded1edee         dee         def
d2Z	 	 dDded3edee         dee         def
d4Z	 	 dDded5edee         dee         def
d6Z	 	 	 dFdededee         dee         dee         defd7Z dEdeddfd8Z!dedeeef         fd9Z"dCd:Z#d;eeef         ddfd<Z$d=Z%d>e&defd?Z'd>e&ddfd@Z(deddfdAZ)d;eeef         dee&         fdBZ* xZ+S )GWhatsAppAdapteru  
    WhatsApp adapter.
    
    This implementation uses a simple HTTP bridge pattern where:
    1. A Node.js process runs the WhatsApp Web client
    2. Messages are forwarded via HTTP/IPC to this Python adapter
    3. Responses are sent back through the bridge
    
    The actual Node.js bridge implementation can vary:
    - whatsapp-web.js based
    - Baileys based
    - Business API based
    
    Configuration:
    - bridge_script: Path to the Node.js bridge script
    - bridge_port: Port for HTTP communication (default: 3000)
    - session_path: Path to store WhatsApp session data
    - dm_policy: "open" | "allowlist" | "disabled" | "pairing" — how DMs are handled (default: "pairing")
    - allow_from: List of sender IDs allowed in DMs (when dm_policy="allowlist")
    - group_policy: "open" | "allowlist" | "disabled" | "pairing" — which groups are processed (default: "pairing")
    - group_allow_from: List of group JIDs allowed (when group_policy="allowlist")
    - send_read_receipts: Mark accepted inbound WhatsApp messages as read

    Behavior (gating, mention parsing, markdown conversion, chunking) is
    provided by ``WhatsAppBehaviorMixin`` so the Cloud API adapter can
    share it. Only transport-specific code lives here.
    NTconfigc           	      z   t                                          |t          j                   t          j        ddlm}  |            t          _        d | _        |j	        
                    dd          | _        |j	        
                    dt          | j        dz                      | _        t          |j	        
                    dt          dd	                              | _        |j	        
                    d
          | _        t          |j	        
                    d          pt%          dd                                                                                    | _        d|j	        v r"d| _        |j	        
                    d          }nZd|j	        v r"d| _        |j	        
                    d          }n/t%          d          rd| _        t%          d          }n	d | _        d }|                     |          | _        t          |j	        
                    d          pt%          dd                                                                                    | _        |                     |j	        
                    d          p|j	        
                    d                    | _        |j	        
                    dd          }t7          |t8                    r|n6t          |pd                                                                          dv | _        |                                 | _        tA          j!                    | _"        d | _#        d | _$        d | _%        d | _&        d| _'        | (                    dd          | _)        | (                    dd          | _*        i | _+        i | _,        d S )Nr   )resolve_whatsapp_bridge_dirbridge_port  bridge_scriptz	bridge.jsrU   zplatforms/whatsapp/sessionzwhatsapp/sessionreply_prefix	dm_policyWHATSAPP_DM_POLICYpairing
allow_fromr   	allowFromWHATSAPP_ALLOWED_USERSgroup_policyWHATSAPP_GROUP_POLICYgroup_allow_fromgroupAllowFromsend_read_receiptsFr   >   1onyestruetext_batch_delay_secondsg      @text_batch_split_delay_secondsg      $@)-super__init__r   WHATSAPPr   _DEFAULT_BRIDGE_DIR!gateway.platforms.whatsapp_commonr   _bridge_processextraget_bridge_portr^   _bridge_scriptr   r
   _session_path_reply_prefixr   r*   lower
_dm_policy_dm_allowlist_source_coerce_allow_list_allow_from_group_policy_group_allow_from
isinstancebool_send_read_receipts_compile_mention_patterns_mention_patternsasyncioQueue_message_queue_bridge_log_fh_bridge_log
_poll_task_http_session_shutting_down_coerce_float_extra_text_batch_delay_seconds_text_batch_split_delay_seconds_pending_text_batches_pending_text_batch_tasks)selfr   r   	allow_rawread_receipts	__class__s        r   r   zWhatsAppAdapter.__init__  s   !2333.6UUUUUU2M2M2O2OO/;?!'!1!1-!F!F-3\-=-=(;677.
 .
 $((8(879KLL)
 )
 $ $ -3L,<,<^,L,Lfl..{;;euEY[d?e?effllnnttvv 6<''(0D%((66IIFL(((0D%((55II+,, 	(@D%677II(,D%I229== !1!1.!A!A!nUKbdmEnEnoouuww}}!%!8!89I9IJ\9]9]  :Dagamaqaq  sC  bD  bD  "E  "E(()=uEE't<< XMM](b))//117799=WW 	  "&!?!?!A!A-4]__"+/26@D %* *.)A)A&*
 *
& 04/G/G,d0
 0
, ?A"BD&&&rb   keyr   r   c                 `   ddl }t          | j        dd          r| j        j                            |          nd}|t          |          S 	 t          |          }n&# t          t          f$ r t          |          cY S w xY w|                    |          r|dk     rt          |          S |S )zRead a float from ``config.extra``, guarding against bad/non-finite values.

        The result is fed directly to ``asyncio.sleep()``, so NaN/Inf and
        unparseable values fall back to ``default``.
        r   Nr   )	mathgetattrr   r   r   floatri   r.   isfinite)r   r   r   r   valueparseds         r   r   z#WhatsAppAdapter._coerce_float_extra  s     	.5dk7D.Q.Q[!%%c***W[=>>!	"5\\FF:& 	" 	" 	">>!!!	"}}V$$ 	"

>>!s   A  B BF)is_reconnectr   c                  K   t                      s:t                              d| j                   |                     ddd           dS t          | j                  }|                                s?t                              d| j        |           |                     dd| d	d           dS | j        d
z  }|                                s;t                              d| j        |           |                     ddd           dS t          	                    d| j        |           d}	 | 
                    dt          | j                  d          sdS d}n8# t          $ r+}t                              d| j        |           Y d}~nd}~ww xY w	 |j        }|dz  }|dz  dz  }t          |          }	d}
|dz                                  rO	 |                    d                                          |	k    ot#          |	          }
n# t$          $ r d}
Y nw xY w|
s{t'          d| j         d           t)          d          pd}	 t+          dd          }t-          j        |ddgt          |          dddd |t1                      !          }|j        d"k    rUt'          d| j         d#|j                    	 | j        s,|r|                                  |                                  dS dS t'          d| j         d$           |	r)	 |                    |	d           n# t$          $ r Y nw xY wne# t          $ rX}t'          d| j         d%|            Y d}~| j        s,|r|                                  |                                  dS dS d}~ww xY w| j                            dd&           d"dl }	 |!                                4 d{V }|"                    d'| j#         d(|$                    d)*          +          4 d{V 	 }|j%        d,k    r|&                                 d{V }|"                    d-d.          }|d/k    r_|"                    d0d1          }t          |          }t#          |"                    d2d                    }|| j'        k    }|r|r||k    r|rt'          d| j         d3| d4           | (                                 d| _)        |!                                | _*        tW          j,        | -                                          | _.        	 ddd          d{V  ddd          d{V  | j        s,|r|                                  |                                  dS dS ||k    r
d5|pd6 d7| nd8}t'          d| j         d9| d:           nt'          d| j         d;| d:           ddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   n# t          $ r Y nw xY wt_          | j                   ta          | j#                   tW          j1        d<           d{V  te          d=d>          }| j        j        d?z  | _3        ti          | j3        d@d          }|| _5        t1                      }| j6        
| j6        |dA<   | j'        rdBndC|dD<   te          d=d>          }|r||d=<   dED ]}te          |          }|r|||<   d"dFl7m8}m9}m:}  t           |                       |dG<   t           |                      |dH<   t           |                      |dI<   t-          j;        t)          dJ          pdJt          |          dKt          | j#                  dLt          | j                  dM|gf|||dNty                      | _)        t{          | j        | j)        j>                   d"dl }d}!i }t          dO          D ]}"tW          j1        d<           d{V  | j)        @                                t'          d| j         dP| j)        j         d4           t'          d| j         dQ| j3                    |                                   | j        s,|r|                                  |                                  dS dS 	 |!                                4 d{V }|"                    d'| j#         d(|$                    d)*          +          4 d{V 	 }|j%        d,k    rrd}!|&                                 d{V }|"                    d-          d/k    r=t'          d| j         dR           	 ddd          d{V  ddd          d{V   nYddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   # t          $ r Y w xY w|!st'          d| j         dS           t'          d| j         dQ| j3                    |                                  	 | j        s,|r|                                  |                                  dS dS |"                    d-          d/k    rYt'          d| j         dT           t          dO          D ]}"tW          j1        d<           d{V  | j)        @                                t'          d| j         dU           t'          d| j         dQ| j3                    |                                   | j        s,|r|                                  |                                  dS dS 	 |!                                4 d{V }|"                    d'| j#         d(|$                    d)*          +          4 d{V 	 }|j%        d,k    rp|&                                 d{V }|"                    d-          d/k    r=t'          d| j         dR           	 ddd          d{V  ddd          d{V   nddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   # t          $ r Y w xY wt'          d| j         dV           t'          d| j         dW| j3                    t'          d| j         dX           |!                                | _*        tW          j,        | -                                          | _.        | (                                 t'          d| j         dY| j#                    	 | j        s,|r|                                  |                                  dS dS # t          $ ra}t          A                    dZ| j        |d[           Y d}~| j        s,|r|                                  |                                  dS dS d}~ww xY w# | j        s+|r|                                  |                                  w w xY w)\z
        Start the WhatsApp bridge.
        
        This launches the Node.js bridge process and waits for it to be ready.
        z2[%s] Node.js not found. WhatsApp requires Node.js.whatsapp_node_missinguI   Node.js is not installed — install Node.js and re-run `hermes gateway`.F	retryablez [%s] Bridge script not found: %swhatsapp_bridge_missingz"WhatsApp bridge script missing at .z
creds.jsonz[%s] WhatsApp is enabled but not paired (no creds.json at %s). Pair from the dashboard or run `hermes whatsapp`; remove WHATSAPP_ENABLED from your .env to disable.whatsapp_not_paireduU   WhatsApp enabled but not paired — pair from the dashboard or run `hermes whatsapp`.z[%s] Bridge found at %szwhatsapp-sessionzWhatsApp sessionTz3[%s] Could not acquire session lock (non-fatal): %sNzpackage.jsonnode_modulesz.hermes-pkg-hashr   re   [z,] Installing WhatsApp bridge dependencies...npmWHATSAPP_NPM_INSTALL_TIMEOUTi,  installz--silentr   )cwdr    r!   r"   r#   r$   envr   z] npm install failed: z] Dependencies installedz"] Failed to install dependencies: )parentsexist_okhttp://127.0.0.1:z/health   totalr$      statusunknown	connected
scriptHashr   sendReadReceiptsz!] Using existing bridge (status: )zrunning=unversionedz, disk=z!send_read_receipts config changedz] Running bridge is stale (z), restartingz*] Bridge found but not connected (status: r&   WHATSAPP_MODEz	self-chatz
bridge.logaWHATSAPP_REPLY_PREFIXr   falseWHATSAPP_SEND_READ_RECEIPTS)r   WHATSAPP_ALLOW_FROMr   r   WHATSAPP_GROUP_ALLOWED_USERSWHATSAPP_GROUP_ALLOW_FROMWHATSAPP_REQUIRE_MENTIONWHATSAPP_MENTION_PATTERNSWHATSAPP_FREE_RESPONSE_CHATSWHATSAPP_DEBUGWHATSAPP_FORWARD_OWNER_MESSAGESr  WHATSAPP_MAX_MESSAGE_LENGTHWHATSAPP_CHUNK_DELAY_MSWHATSAPP_SEND_TIMEOUT_MS)r   r   r   HERMES_IMAGE_CACHE_DIRHERMES_AUDIO_CACHE_DIRHERMES_DOCUMENT_CACHE_DIRr\   z--portz	--sessionz--mode)r)   r   r     z!] Bridge process died (exit code z] Check log: z"] Bridge ready (status: connected)z)] Bridge HTTP server did not start in 15sz7] Bridge HTTP ready, waiting for WhatsApp connection...z'] Bridge process died during connectionu&   ] ⚠ WhatsApp not connected after 30sz]   Bridge log: z0]   If session expired, re-pair: hermes whatsappz] Bridge started on port z[%s] Failed to start bridge: %s)exc_info)Br   rl   rn   r   _set_fatal_errorr   r   rg   r   rm   _acquire_platform_lockr^   rP   r   r   rh   r*   r   rO   printr	   r   r'   r(   r   r~   r   _running_release_platform_lock_close_bridge_logru   mkdiraiohttpClientSessionr   r   ClientTimeoutr  jsonr   _mark_connectedr   r   r   create_task_poll_messagesr   rr   rT   sleepr   r   openr   r   r   r   r   r   Popenr   rw   rS   rangepollerror)#r   r   bridge_path
creds_pathlock_acquirede
bridge_dir	_pkg_json
_dep_stamp	_pkg_hash_deps_fresh_npm_binnpm_install_timeoutinstall_resultr2  sessionrespdatabridge_statusrunning_hash	disk_hashrunning_read_receiptsconfig_matchesstale_reasonwhatsapp_modebridge_log_fh
bridge_env_profile_wa_mode_key_v_get_audio_dir_get_doc_dir_get_img_dir
http_readyattempts#                                      r   connectzWhatsAppAdapter.connect  s      +,, 	NNOQUQZ[[[!!'[ "   
 54.//!!## 	NN=ty+VVV!!)C[CCC "   
 5 ',6
  "" 	NN> 	:	   !!%g "   
 5-ty+FFF 	`../A3tGYCZCZ\noo u MM 	` 	` 	`NNPRVR[]^________	`	)
 %+J"^3I#n47IIJ*955IK^+3355 ((",,g,>>DDFF)S#*y//  K  ( ( ("'KKK( !Q$)QQQRRR 066?%! +22PRU*V*V'%/^!9j9
OO'+!GI 3133& & &N &0A55Z$)ZZ>CXZZ[[[$p = )  2//111&&((((() )o AdiAAABBB  !!&11)g1NNNN& ! ! ! D!  ! ! !NdiNN1NNOOO 555^ = )  2//111&&((((() )c!
 $$TD$AAA NNN,"0022 )} )} )} )} )} )} )}g&{{FD,=FFF ' 5 5A 5 > >  +     (} (} (} (} (} (} (} (} ;#--)-#4#4#4#4#4#4D,0HHXy,I,IM,;; 04xxb/I/I,>{,K,K	8<TXXFXZ_=`=`8a8a 51F$Jb1b$0!0(1!0 )5	(A(A(6 )B %**jdi*j*jZg*j*j*j$k$k$k$($8$8$:$:$:;?D$89@9N9N9P9PD$66=6I$J]J]J_J_6`6`DO+/A(} (} (} (} (} (} (} (} (} (} (} (})} )} )} )} )} )} )} )} )} )} )} )}N = )  2//111&&((((() )G (4y'@'@ %a|/L}$`$`U^$`$`$`)L !-
 !&&k$)&k&kP\&k&k&k l l l l %&{$)&{&{_l&{&{&{ | | |Q(} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (} (})} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )} )}T     *$*<===t0111-"""""""""
 "/;??M#18<GD !13IIIM"/D /00J!-6:6H
232? 45  %_kBB ?.>
?+ * * 4[[ *')Jt$
         
 47||~~3F3FJ/036~~7G7G3H3HJ/069,,..6I6IJ23#-#3(00:F$$c$"344T%7!8!8m$ %$$ $ .//$ $D  "$"4d6J6NOOO
 NNNJD 99  mA&&&&&&&&&',,..:ldill$J^JilllmmmHdiHHd6FHHIII**,,, F = )  2//111&&((((() )E&4466 
* 
* 
* 
* 
* 
* 
*'#*;;J0AJJJ$+$9$9$9$B$B $/ $ $ 	* 	* 	* 	* 	* 	* 	* 	* "#{c11-1
-1YY[['8'8'8'8'8'8#'88H#5#5#D#D$)*[di*[*[*[$\$\$\$)	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	*
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
*	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	*
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* 
* !   H  N$)NNNOOOD$)DD$2BDDEEE&&(((^ = )  2//111&&((((() )W xx!![00\$)\\\]]]$Ryy [ [G!-*********+0022>T$)TTTUUUL$)LL$:JLLMMM..000$F = )  2//111&&((((() )E!#*#8#8#:#: 	. 	. 	. 	. 	. 	. 	.g'.{{ ND4E N N N(/(=(=A(=(F(F (3 ( ( . . . . . . . . "&#';##5#515+<+<+<+<+<+<D'+xx'9'9['H'H(-._$)._._._(`(`(`(-. . . . . . . . . . . .	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.. . . . . . . . . . . . . . . . . . . . . . . . . . .	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. % ! ! ! !
 OdiOOOPPPKdiKK9IKKLLLYdiYYYZZZ ")!6!6!8!8D &1$2E2E2G2GHHDO  """MdiMM$:KMMNNN = )  2//111&&((((() )	  	 	 	LL:DIqSWLXXX555= )  2//111&&((((() )		 = )  2//111&&(((()sI  /)E E 
F'!FF<v  ;H v  Hv  H/v  A2L: 6L: L) (L: )
L63L: 5L66L: 9v  :
NNv  N#v   X ;X	DW&4X	X A	W&X	&
W0	0X	3W0	4X	7X 	
XX XX v  
X(%v  'X((I2v  g,*;g&Af6 gg,"v  $g6
g  gg gg,
g#	#g,&g#	'g,*v  ,
g:6v  9g::Av   Cv  9r;r Aq'r 8r	v  r 
q''r *q'+r .r 
r
	
rr
	rv  
r!v   r!!C	v   
x*#xx xx 4yc                 |    | j         r4	 | j                                          n# t          $ r Y nw xY wd| _         dS dS )z)Close the bridge log file handle if open.N)r   closerP   )r   s    r   r0  z!WhatsAppAdapter._close_bridge_log8  sb     	'#))++++   "&D	' 	's   # 
00c                   K   | j         dS | j                                         }|dS t          | dd          r'|dv r#t                              d| j        |           dS d| d}| j        sgt                              d| j        |           |                     d	|d
           | 	                                 | 
                                 d{V  | j        p|S )z@Return a fatal error message if the managed bridge child exited.Nr   F>   r   z-[%s] Bridge exited during shutdown (code %d).z2WhatsApp bridge process exited unexpectedly (code z).z[%s] %swhatsapp_bridge_exitedTr   )r   r=  r   rl   rm   r   has_fatal_errorr>  r+  r0  _notify_fatal_errorfatal_error_message)r   r~   messages      r   _check_managed_bridge_exitz*WhatsAppAdapter._check_managed_bridge_exitA  s     '4)..00
4 4)511 	jL6P6PKK?	  
 4UzUUU# 	-LLDIw777!!":Gt!TTT""$$$**,,,,,,,,,'272rb   c                   K   d| _         | j        r	 	 t          | j        d           n0# t          t          f$ r | j                                         Y nw xY wt          j        d           d{V  | j                                        H	 t          | j        d           n0# t          t          f$ r | j        	                                 Y nw xY wnI# t          $ r$}t          d| j         d|            Y d}~n d}~ww xY wt          d| j         d           	 | j        d	z                      d
           n# t          $ r Y nw xY w| j        r]| j                                        sD| j                                         	 | j         d{V  n# t          j        t          f$ r Y nw xY wd| _        | j        r+| j        j        s| j                                         d{V  d| _        |                                  |                                  d| _        |                                  t          d| j         d           dS )z=Stop the WhatsApp bridge and clean up any orphaned processes.TFrx   r&   Nr  z] Error stopping bridge: z.] Disconnecting (external bridge left running)rd   )
missing_okz] Disconnected)r   r   r   rM   rN   r}   r   r9  r=  rJ   rP   r-  r   r   rk   rO   r   donecancelCancelledErrorr   closedra  r/  _mark_disconnectedr0  )r   rB  s     r   
disconnectzWhatsAppAdapter.disconnecta  s     
 # 	QC5-d.B%PPPPP*O< 5 5 5(22444445mA&&&&&&&&&',,..641$2FdSSSSS.@ 4 4 4,11333334 C C CA$)AAaAABBBBBBBBC OdiOOOPPP	,.66$6GGGG 	 	 	D	 ? 	4?#7#7#9#9 	O""$$$o%%%%%%%%*I6     	-d&8&? 	-$**,,,,,,,,,!##%%%!!!#   +$)+++,,,,,sz   * C *AC A6C B% $C %*CC CC 
D C??D D? ?
EE	F F0/F0chat_idcontentreply_tometadatac           	        K   | j         r| j        st          dd          S |                                  d{V }|rt          d|          S |r|                                st          dd          S t          |          }	 ddl}|                     |          }|                     || 	                                          }g }	d}
t          |          D ]H\  }}||d}|r|dk    r||d	<   | j                            d
| j         d||                    d                    4 d{V 	 }|j        dk    rT|                                 d{V }|                    d          }
|
r"|	                    t%          |
                     n?|                                 d{V }t          d|          cddd          d{V  c S ddd          d{V  n# 1 d{V swxY w Y   t)          |          dk    rt+          j        d           d{V  Jt          d|
t/          |	dd                   d|	i          S # t0          $ r(}t          dt%          |                    cY d}~S d}~ww xY w)zSend a message via the WhatsApp bridge.

        Formats markdown for WhatsApp, splits long messages into chunks
        that preserve code block boundaries, and sends each chunk sequentially.
        FNot connectedsuccessr>  NTrz  
message_idr   chatIdri  replyTor	  /send   r  r5  r$   r  	messageIdr&   g333333?message_ids)rz  r|  continuation_message_idsraw_response)r.  r   r   rj  r*   r   r2  format_messagetruncate_message_outgoing_chunk_limit	enumeratepostr   r4  r  r5  r   r,   r^   r!   rG   r   r9  tuplerP   )r   rs  rt  ru  rv  bridge_exitr2  	formattedchunkssent_message_idslast_message_ididxchunkpayloadrL  rM  r>  rB  s                     r   sendzWhatsAppAdapter.send  s      } 	DD$6 	De?CCCC ;;======== 	@e;???? 	=gmmoo 	=dt<<<<!'**,	;NNN ++G44I**9d6P6P6R6RSSF*,"O'// - -
U%$+ +  2q *2GI&-22@(9@@@ #111;; 3   F F F F F F F F {c))%)YY[[000000*.((;*?*?* J,33C4H4HIII&*iikk 1 1 1 1 1 1)%uEEEF F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F v;;??!-,,,,,,,,,*)./?/D)E)E+-=>	     	; 	; 	;e3q66:::::::::	;sK   B,I 3B
G$=I I $
G.	.I 1G.	2AI 
J I;5J ;J )finalizer|  r  c                  K   | j         r| j        st          dd          S |                                  d{V }|rt          d|          S 	 ddl}| j                            d| j         dt          |          ||d|                    d	
                    4 d{V 	 }|j	        dk    r#t          d|          cddd          d{V  S |
                                 d{V }t          d|          cddd          d{V  S # 1 d{V swxY w Y   dS # t          $ r(}	t          dt          |	                    cY d}	~	S d}	~	ww xY w)z7Edit a previously sent message via the WhatsApp bridge.Frx  ry  Nr   r	  z/edit)r~  r  ri  r)  r  r  r  Tr{  )r.  r   r   rj  r2  r  r   r   r4  r  r!   rP   r^   )
r   rs  r|  rt  r  r  r2  rL  r>  rB  s
             r   edit_messagezWhatsAppAdapter.edit_message  s      } 	DD$6 	De?CCCC ;;======== 	@e;????	;NNN)..<D$5<<<-g66!+& 
  --B-77 /   B B B B B B B B ;#%%%dzJJJB B B B B B B B B B B B B B #'))++------E%e5AAAB B B B B B B B B B B B B B B B B B B B B B B B B B B B B B  	; 	; 	;e3q66:::::::::	;sO   AD% &DD% *D?D% 
DD% D D% %
E/EEE	file_path
media_typecaption	file_namec                   K   | j         r| j        st          dd          S |                                  d{V }|rt          d|          S 	 ddl}t
          j                            |          st          dd|           S t          |          ||d}|r||d<   |r||d	<   | j        	                    d
| j
         d||                    d                    4 d{V 	 }	|	j        dk    rQ|	                                 d{V }
t          d|
                    d          |
          cddd          d{V  S |	                                 d{V }t          d|          cddd          d{V  S # 1 d{V swxY w Y   dS # t           $ r(}t          dt#          |                    cY d}~S d}~ww xY w)z4Send any media file via bridge /send-media endpoint.Frx  ry  Nr   zFile not found: r~  filePath	mediaTyper  fileNamer	  /send-mediax   r  r  r  Tr  rz  r|  r  )r.  r   r   rj  r2  r   r   rg   r   r  r   r4  r  r5  r   r!   rP   r^   )r   rs  r  r  r  r  r  r2  r  rL  rM  r>  rB  s                r   _send_media_to_bridgez%WhatsAppAdapter._send_media_to_bridge  sF      } 	DD$6 	De?CCCC ;;======== 	@e;????!	;NNN7>>),, W!%7U)7U7UVVVV *'22%'' 'G
  -%,	" 0&/
#)..BD$5BBB--C-88 /   B B B B B B B B ;#%%!%,,,,,,D% $#'88K#8#8%)  B B B B B B B B B B B B B B #'))++------E%e5AAAB B B B B B B B B B B B B B B B B B B B B B B B B B B B B B   	; 	; 	;e3q66:::::::::	;sV   6F A!F )A
F3F *F0F 
FF FF 
G G=GGr&   selectable_countquestionoptionsr  c                4  K   | j         r| j        st          dd          S |                                  d{V }|rt          d|          S 	 ddl}t          |          |t          |pg           |d}| j                            d| j         d||	                    d	
                    4 d{V 	 }|j
        dk    rQ|                                 d{V }	t          d|	                    d          |	          cddd          d{V  S |                                 d{V }
t          d|
          cddd          d{V  S # 1 d{V swxY w Y   dS # t          $ r(}t          dt          |                    cY d}~S d}~ww xY w)a   Send a native WhatsApp poll via the Baileys bridge.

        This is a low-level transport primitive only. Gateway approval UX must
        remain gateway-owned and add text fallback plus explicit confirmation
        semantics before approval prompts are ever mapped onto polls.
        Frx  ry  Nr   )r~  r  r  selectableCountr	  z
/send-pollr  r  r  r  Tr  r  )r.  r   r   rj  r2  r   listr  r   r4  r  r5  r   r!   rP   r^   )r   rs  r  r  r  r  r2  r  rL  rM  r>  rB  s               r   	send_pollzWhatsAppAdapter.send_poll+  s      } 	DD$6 	De?CCCC ;;======== 	@e;????	;NNN *'22$2..#3	' 'G )..AD$5AAA--B-77 /   > > > > > > > > ;#%%!%,,,,,,D% $#'88K#8#8%)  > > > > > > > > > > > > > > #iikk))))))!%u===> > > > > > > > > > > > > > > > > > > > > > > > > > > > > >  	; 	; 	;e3q66:::::::::	;sP   A'E% 8A
EE% *E?E% 
EE% E E% %
F/FFFchoices
clarify_idsession_keyc                   K   d |pg D             }dt          |          cxk    rdk    rrn no|                     |t          |pd                                          |d           d{V }|j        r|S t
                              d| j        |j                   t                      
                    ||||||	           d{V S )
a  Render multiple-choice clarify as a native WhatsApp poll.

        The gateway registers the pending clarify before calling this method.
        When Baileys later emits a poll_update with the selected option as
        message text, the normal clarify text-intercept resolves the pending
        question and the blocked agent continues. Open-ended clarifies use the
        text fallback so the user's next typed message is captured.
        c                     g | ]D}t          |                                          #t          |                                          ES  )r^   r*   ).0choices     r   
<listcomp>z0WhatsAppAdapter.send_clarify.<locals>.<listcomp>i  sB    bbbcRXkkN_N_NaNabV**,,bbbrb   r
     r   r&   r  NzB[%s] Native WhatsApp clarify poll failed; falling back to text: %s)rs  r  r  r  r  rv  )rG   r  r^   r*   rz  rl   rn   r   r>  r   send_clarify)
r   rs  r  r  r  r  rv  clean_choicesr4   r   s
            r   r  zWhatsAppAdapter.send_clarifyX  s,     " cbGMrbbbM""((((b(((((>>HN##))++!"	 *        F ~ NNT	  
 WW))!# * 
 
 
 
 
 
 
 
 	
rb   )r   addressru  rv  latitude	longituder   r  c                d  K   | j         r| j        st          dd          S |                                  d{V }|rt          d|          S 	 ddl}	t          |          t          |          t          |          d}
|r||
d<   |r||
d<   | j                            d	| j         d
|
|		                    d                    4 d{V 	 }|j
        dk    rQ|                                 d{V }t          d|                    d          |          cddd          d{V  S |                                 d{V }t          d|          cddd          d{V  S # 1 d{V swxY w Y   dS # t          $ r(}t          dt          |                    cY d}~S d}~ww xY w)z;Send a native WhatsApp location pin via the Baileys bridge.Frx  ry  Nr   )r~  r  r  r   r  r	  z/send-locationr  r  r  r  Tr  r  )r.  r   r   rj  r2  r   r   r  r   r4  r  r5  r   r!   rP   r^   )r   rs  r  r  r   r  ru  rv  r  r2  r  rL  rM  r>  rB  s                  r   send_locationzWhatsAppAdapter.send_location  s      } 	DD$6 	De?CCCC ;;======== 	@e;????	;NNN *'22!(OO"9--' 'G
  '"& -%,	")..ED$5EEE--B-77 /   > > > > > > > > ;#%%!%,,,,,,D% $#'88K#8#8%)  > > > > > > > > > > > > > > #iikk))))))!%u===> > > > > > > > > > > > > > > > > > > > > > > > > > > > > >  	; 	; 	;e3q66:::::::::	;sP   A?E= A
E*E= -*E*E= *
E44E= 7E48E= =
F/F*$F/*F/	image_urlc                    K   	 t          |           d{V }|                     ||d|           d{V S # t          $ r. t                                          |||||           d{V cY S w xY w)u^  Download image URL to cache, send natively via bridge.

        ``metadata`` is accepted to honor the base-class contract — the
        batch sender ``send_multiple_images`` passes it through to every
        send path. The bridge media call doesn't use it, matching the
        sibling overrides (send_video / send_voice / send_document).
        Nimage)r   r  rP   r   
send_image)r   rs  r  r  ru  rv  
local_pathr   s          r   r  zWhatsAppAdapter.send_image  s      	]3I>>>>>>>>J33GZRYZZZZZZZZZ 	] 	] 	]++GYS[\\\\\\\\\\\	]s   28 5A0/A0
image_pathc                 B   K   |                      ||d|           d{V S )z,Send a local image file natively via bridge.r  Nr  )r   rs  r  r  ru  kwargss         r   send_image_filezWhatsAppAdapter.send_image_file  4       //WgVVVVVVVVVrb   
video_pathc                 B   K   |                      ||d|           d{V S )u>   Send a video natively via bridge — plays inline in WhatsApp.videoNr  )r   rs  r  r  ru  r  s         r   
send_videozWhatsAppAdapter.send_video  r  rb   
audio_pathc                 B   K   |                      ||d|           d{V S )z:Send an audio file as a WhatsApp voice message via bridge.audioNr  )r   rs  r  r  ru  r  s         r   
send_voicezWhatsAppAdapter.send_voice  r  rb   c           	         K   |                      ||d||pt          j                            |                     d{V S )z=Send a document/file as a downloadable attachment via bridge.documentN)r  r   r   basename)r   rs  r  r  r  ru  r  s          r   send_documentzWhatsAppAdapter.send_document  s_       //Y
G4)))44
 
 
 
 
 
 
 
 	
rb   c                 x  K   | j         r| j        sdS |                                  d{V rdS 	 ddl}| j                            d| j         ddt          |          i|                    d                    4 d{V  	 ddd          d{V  dS # 1 d{V swxY w Y   dS # t          $ r Y dS w xY w)	z!Send typing indicator via bridge.Nr   r	  z/typingr~  r   r  r  )	r.  r   rj  r2  r  r   r   r4  rP   )r   rs  rv  r2  s       r   send_typingzWhatsAppAdapter.send_typing  s     } 	D$6 	F0022222222 	F	NNN
 )..>D$5>>> 8 89--A-66 /          
                                	 	 	DD	s6   AB+ BB+ 
B""B+ %B"&B+ +
B98B9c                   K   | j         r| j        sdddS |                                  d{V r|ddS 	 ddl}| j                            d| j         dt          |           |                    d	          
          4 d{V 	 }|j        dk    rq|	                                 d{V }|                    d|          |                    d          rdnd|                    dg           dcddd          d{V  S 	 ddd          d{V  n# 1 d{V swxY w Y   n3# t          $ r&}t                              d||           Y d}~nd}~ww xY w|ddS )z&Get information about a WhatsApp chat.Unknowndm)r   typeNr   r	  z/chat/r{   r  r  r  r   isGroupr2   participants)r   r  r  z+Could not get WhatsApp chat info for %s: %s)r.  r   rj  r2  r   r   r   r4  r  r5  rP   rl   debug)r   rs  r2  rL  rM  rB  s         r   get_chat_infozWhatsAppAdapter.get_chat_info
  s     } 	5D$6 	5%t4440022222222 	3#T222	TNNN)--WD$5WW_W=U=UWW--B-77 .   
 
 
 
 
 
 
 
 ;#%%!%,,,,,,D $ 9 9+/88I+>+> HD(,(D(D 
 
 
 
 
 
 
 
 
 
 
 
 
 
 &	
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  	T 	T 	TLLFQRSSSSSSSS	T  ...sC   AD+ 	A*D3D+ D+ 
D##D+ &D#'D+ +
E5EEc                 P  K   ddl }| j        r| j        sdS |                                  d{V }|rt	          d| j         d|            dS 	 | j                            d| j         d|                    d          	          4 d{V 	 }|j	        d
k    r|
                                 d{V }|D ]}|                     |           d{V }|rmt          j        |                     |                     |j        t           j        k    r|                     |           q|                     |           d{V  ddd          d{V  n# 1 d{V swxY w Y   n# t          j        $ r Y dS t*          $ rz}|                                  d{V }|r t	          d| j         d|            Y d}~dS t	          d| j         d|            t          j        d           d{V  Y d}~nd}~ww xY wt          j        d           d{V  | j        dS dS )z&Poll the bridge for incoming messages.r   Nr  z] r	  z	/messagesr  r  r  r  z] Poll error: r   r&   )r2  r.  r   rj  r-  r   r   r   r4  r  r5  _build_message_eventr   r7  _send_read_receiptmessage_typer   TEXT_enqueue_text_eventhandle_messagero  rP   r9  )r   r2  r  rL  messagesmsg_dataeventrB  s           r   r8  zWhatsAppAdapter._poll_messages$  s     m #	#%  $ ? ? A AAAAAAAK 4$)44{44555'-11D(9DDD#111;; 2   E E E E E E E E {c)))-#4#4#4#4#4#4(0 
E 
EH*.*C*CH*M*M$M$M$M$M$M$ME$ E !( 3D4K4KH4U4U V V V#(#59I#I#I$($<$<U$C$C$C$C*.*=*=e*D*D$D$D$D$D$D$D$D!E E E E E E E E E E E E E E E E E E E E E E E E E E E" )    ' ' '$($C$C$E$EEEEEEE 8di88;88999EEEEE6$)66166777mA&&&&&&&&&&&&&&' -"""""""""G m #	# #	# #	# #	# #	#sI   ?E* B5EE* 
E""E* %E"&E* *G?<	G?6G:4G::G?rM  c                 0  K   | j         r| j        sdS |                    d          }t          |t                    sdS 	 ddl}| j                            d| j         dd|i|                    d          	          4 d{V 	 }|j	        d
k    r&t                              d| j        |j	                   ddd          d{V  dS # 1 d{V swxY w Y   dS # t          $ r,}t                              d| j        |           Y d}~dS d}~ww xY w)z>Mark a policy-accepted inbound message as read via the bridge.NreadReceiptKeyr   r	  z/readr   r   r  r  r  z.[%s] WhatsApp read receipt failed with HTTP %sz%[%s] WhatsApp read receipt failed: %s)r   r   r   r   dictr2  r  r   r4  r  rl   rn   r   rP   )r   rM  r   r2  rL  excs         r   r  z"WhatsAppAdapter._send_read_receiptM  s     ' 	t/A 	Fhh'((#t$$ 	F	TNNN)..<D$5<<<S\--A-66 /   
 
 
 
 
 
 
 
 ;#%%NNH	  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  	T 	T 	TNNBDIsSSSSSSSSS	Ts=    AC 2C9C 
CC CC 
D)!DDip  r  c                     ddl m}  ||j        | j        j                            dd          | j        j                            dd          |j        j                  S )z-Session-scoped key for text message batching.r   )build_session_keygroup_sessions_per_userTthread_sessions_per_userF)r  r  profile)gateway.sessionr  sourcer   r   r   r  )r   r  r  s      r   _text_batch_keyzWhatsAppAdapter._text_batch_keyi  so    555555  L$(K$5$9$9:SUY$Z$Z%)[%6%:%:;UW\%]%]L(	
 
 
 	
rb   c                    |                      |          }| j                            |          }t          |j        pd          }|||_        || j        |<   nw|j        r$|j        r|j         d|j         n|j        |_        ||_        |j        r>|j                            |j                   |j                            |j                   | j	                            |          }|r(|
                                s|                                 t          j        |                     |                    | j	        |<   dS )zBuffer a text event and reset the flush timer.

        When WhatsApp delivers rapid-fire messages (e.g. forwarded
        batches), this concatenates them and waits for a short quiet
        period before dispatching the combined message.
        r   Nrf   )r  r   r   rG   r!   _last_chunk_len
media_urlsextendmedia_typesr   rm  rn  r   r7  _flush_text_batch)r   r  r   existing	chunk_len
prior_tasks         r   r  z#WhatsAppAdapter._enqueue_text_events  sL    ""5))-11#66
(b))	$-E!.3D&s++z bDLM a8= @ @EJ @ @ @W\Wa'0H$ ?#**5+;<<<$++E,=>>>377<<
 	 joo// 	 .5.A""3''/
 /
&s+++rb   c                   K   t          j                    }	 | j                            |          }|rt	          |dd          nd}|| j        k    r| j        }n| j        }t          j        |           d{V  | j        	                    |d          }|s<	 | j
                            |          |u r| j
        	                    |d           dS dS |                     |           d{V  | j
                            |          |u r| j
        	                    |d           dS dS # | j
                            |          |u r| j
        	                    |d           w w xY w)z4Wait for quiet period then dispatch aggregated text.r  r   N)r   current_taskr   r   r   _SPLIT_THRESHOLDr   r   r9  popr   r  )r   r   r  pendinglast_lendelayr  s          r   r  z!WhatsAppAdapter._flush_text_batch  s     +--	>044S99GAHOww(91===aH4000<6-&&&&&&&&&.223==E  -11#66,FF.223===== GF %%e,,,,,,,,,-11#66,FF.223===== GFt-11#66,FF.223==== Gs   B D) D) ):E#c                   K   	 |                      |          sdS t          j        }t          |                    dd          pd          }|dv rt          j        }nx|dk    rt          j        }ne|                    d          rPd|v rt          j        }n?d|v rt          j        }n.d	|v rt          j	        }nd
|v rt          j
        }nt          j        }|                    dd          }|rdnd}|                     |                    dd          |                    d          ||                    d          |                    d                    }|                    dg           }g }g }	|D ]M}
t          |                    d          pd                                          }|t          j        k    r|
                    d          r	 t          |
d           d{V }|                    |           |	                    |pd           t#          d| j         d| d           # t&          $ rS}t#          d| j         d| d           |                    |
           |	                    |pd           Y d}~d}~ww xY w|t          j        k    rt(          j                            |
          rwt/          |
          rJ|                    |
           |	                    |pd           t#          d| j         d|
 d           t#          d| j         d |
 d           |t          j	        t          j
        hv r|
                    d          r	 t1          |
d!           d{V }|                    |           |	                    |p|t          j	        k    rd"nd#           t#          d| j         d$| d           h# t&          $ re}t#          d| j         d%| d           |                    |
           |	                    |p|t          j	        k    rd"nd#           Y d}~d}~ww xY w|t          j	        t          j
        hv rt(          j                            |
          rt/          |
          r\|                    |
           |	                    |p|t          j	        k    rd"nd#           t#          d| j         d&|
 d           ~t#          d| j         d'|
 d           |t          j        k    rt(          j                            |
          rt/          |
          r|                    |
           t3          |
          j                                        }|pt9          j        |d(          }|	                    |           t#          d| j         d)|
 d           _t#          d| j         d*|
 d           }|t          j        k    rt(          j                            |
          rwt/          |
          rJ|                    |
           |	                    |pd+           t#          d| j         d,|
 d           t#          d| j         d-|
 d           #|                    |
           |	                    d.           O|                    d/d          }|                    d          r|                     ||          }|t          j	        k    r;|r9t          |                                                                          d0k    rd}t          |                    d1          pd                                          }|pd}d}d}d}|                    d2          rg|                    d3          }|t          |          }|                     |                    d4                    }|r|}|                     |          }d5}|t          j        k    r[|rX|D ]T}t3          |          j                                        }|d6v r&	 t3          |                                           j!        }||k    r$t#          d| j         d7| d8| d9| d:	d           t3          |          "                    d;d<=          }t3          |          j        }|}d>|v r1|#                    d>d?          }tI          |          d@k    r|d?         }dA| dB| }|r| dC| }n|}t#          d| j         dD| d            # t&          $ r'}t#          d| j         dE| d           Y d}~Ld}~ww xY wVi } t          |                    dF          pd                                          }!|                    dG          }"|!r|!| dH<   tK          |"tL                    r|"r|"| dI<   |                    dJ          r*d| dK<   |                    tN                    stN           | }tQ          |||||                    dL          ||	| ||||M          S # t&          $ r%}t#          d| j         dN|            Y d}~dS d}~ww xY w)OzKBuild a MessageEvent from bridge message data, downloading images to cache.Nr  r   >   locationlive_locationstickerhasMediar  r  pttr  r  Fr2   r  r~  chatNamesenderId
senderName)rs  	chat_name	chat_typeuser_id	user_name	mediaUrlsmime)zhttp://zhttps://.jpg)extz
image/jpegr  z] Cached user image: T)flushz] Failed to cache image: z] Using bridge-cached image: z0] Rejected bridge image path outside cache dir: .oggz	audio/oggz
audio/mpegz] Cached user audio: z] Failed to cache audio: z] Using bridge-cached audio: z0] Rejected bridge audio path outside cache dir: zapplication/octet-streamz ] Using bridge-cached document: z3] Rejected bridge document path outside cache dir: z	video/mp4z] Using bridge-cached video: z0] Rejected bridge video path outside cache dir: r  bodyz[ptt received]
quotedTexthasQuotedMessagequotedMessageIdquotedParticipanti  >   .js.md.py.ts.css.csv.log.txt.xml.yml.html.json.yamlz] Skipping text injection for z (z	 bytes > r  r   r   )r"   r#   _r
  r=   z[Content of z]:
z

z] Injected text content from: z ] Failed to read document text: 
nativeTypenativeMetadatawhatsapp_native_typewhatsapp_native	fromOwnerwhatsapp_from_ownerr  )r!   r  r  raw_messager|  r  r  rv  reply_to_message_idreply_to_textreply_to_author_idreply_to_is_own_messagez] Error building event: ))_should_process_messager   r  r^   r   LOCATIONSTICKERPHOTOVIDEOVOICEAUDIODOCUMENTbuild_sourcer*   
startswithr   r,   r-  r   rP   r   r   isabsr   r   r   suffixr   r   _clean_bot_mention_text_normalize_whatsapp_id_message_is_reply_to_botstatst_sizerh   rF   rG   r   r  _OWNER_REPLY_PREFIXr   )#r   rM  msg_typer  is_groupr  r  raw_urlscached_urlsr  r   bridge_mimecached_pathrB  r  r  r  quoted_textr5  r4  r6  r7  raw_reply_idquoted_participantMAX_TEXT_INJECT_BYTESdoc_path	file_sizert  fnamedisplay_namerQ   	injectionrv  native_typenative_metadatas#                                      r   r  z$WhatsAppAdapter._build_message_event  sH     F	//55 t #'HTXXk266<"==J:::&/y((&.*%% 
4j((*0HH
***0HHj((*0HH
***0HH*3H xx	511H#+5I &&2..((:..#,,((<00 '  F xxR00HKK 92 92!$((6"2"2"8b99??AA{000S^^D[5\5\0H,@&,Q,Q,Q&Q&Q&Q&Q&Q&Q#**;777#**;+F,GGGO$)OO+OOW[\\\\\$ H H HI$)IIaIIQUVVVV#**3///#**;+F,GGGGGGGGH !222rw}}S7I7I2.s33 p#**3///#**;+F,GGGO$)OO#OOW[\\\\\b$)bb]`bbjnooooo+"3[5F!GGGCNN[rLsLsG|,@&,Q,Q,Q&Q&Q&Q&Q&Q&Q#**;777#**;+z(VaVgJgJg;;my{{{O$)OO+OOW[\\\\\$ | | |I$)IIaIIQUVVVV#**3///#**;+z(VaVgJgJg;;my{{{{{{{{| +"3[5F!GGGBGMMZ]L^L^G.s33 p#**3///#**;+z(VaVgJgJg;;my{{{O$)OO#OOW[\\\\\b$)bb]`bbjnooooo!555"'--:L:L5.s33 s#**3///"3ii.4466*k.F.J3Pj.k.k#**4000R$)RRSRRZ^_____e$)ee`ceemqrrrrr!222rw}}S7I7I2.s33 p#**3///#**;+E+FFFO$)OO#OOW[\\\\\b$)bb]`bbjnooooo&&s+++&&y1111
 88FB''Dxx	"" @33D$??K--- .IIOO%%++--1AAA
  dhh|44:;;AACCK'/4M"&!%&+#xx*++ N#xx(9::+*-l*;*;'%)%@%@J]A^A^%_%_"% <);&*.*G*G*M*M'$.!;///K/ + b bHx../5577C  F  F  Fb(,X(;(;(=(=(EI(+@@@ %  'L$)  'L  'LS[  'L  'L_h  'L  'L  tI  'L  'L  'L  TX  !Y  !Y  !Y  !Y (&*8nn&>&>Xa&>&b&bG$(NN$7E+0L"e||(-C(;(;#&u::??388L(R|(R(R(R(RI# 1*3'?'?'?'?'0!"Ydi"Y"Yx"Y"Yaefffff( b b b!"Tdi"T"TQR"T"T\`aaaaaaaaab) F. (*Hdhh|44:;;AACCK"hh'788O ?3>/0/400 >_ >.=*+ xx$$ :26./':;; :19499D% 88K00&'!$7+#5(?     	 	 	<di<<<<===44444	s   i F7i AH32i 3
J=AJi JCi )A1Oi 
Q&AQ i QPi Ae!i "Bei 
e4e/)i /e44C!i 
j j  jr   N)NNN)NNN),__name__
__module____qualname____doc__r   splits_long_messagesr   r   r^   r   r   r   r_  r0  r   rj  rr  r   r   r   r  r  r  r  r-   r  r  r  r  r  r  r  r  r  r  r8  r  r  r   r  r  r  r  __classcell__)r   s   @r   r   r   }  s         : JE~ JE JE JE JE JE JEXs U u    & 5: y) y) y)T y)d y) y) y) y)v	' ' ' '3(3- 3 3 3 3@1- 1- 1- 1-n #'-1C; C;C; C; 3-	C;
 4S>*C; 
C; C; C; C;V ; ; ;; ; 	; ; 
; ; ; ;L "&#'/; /;/; /; 	/;
 #/; C=/; 
/; /; /; /;n !"+; +; +;+; +; c	+; +; 
+; +; +; +;h .2'
 '
'
 '
 $	'

 '
 '
 4S>*'
 
'
 '
 '
 '
 '
 '
^ #!%"&-1,; ,; ,;,; ,; 	,; sm,; #,; 3-,; 4S>*,; 
,; ,; ,; ,;d "&"&-1] ]] ] #	]
 3-] 4S>*] 
] ] ] ] ] ]2 "&"&	W 	W	W 	W #		W
 3-	W 
	W 	W 	W 	W "&"&	W 	W	W 	W #		W
 3-	W 
	W 	W 	W 	W "&"&	W 	W	W 	W #		W
 3-	W 
	W 	W 	W 	W "&#'"&
 

 
 #	

 C=
 3-
 

 
 
 
      ,/3 /4S> / / / /4'# '# '# '#RTT#s(^ T T T T T4 
\ 
c 
 
 
 

 
$ 
 
 
 
8>3 >4 > > > >&HtCH~ H(<BX H H H H H H H Hrb   r   >   .gif.png.jpeg.webpr  >   .3gp.avi.mkv.mov.mp4.webm>   .m4a.mp3.wav.flac.opusr  r  is_voiceforce_documentc                     |rdS t           j                            |           d                                         }|s	|t          v rdS |t
          v rdS |t          v rdS dS )ay  Map a local media file to the bridge /send-media ``mediaType``.

    Returns one of ``image`` | ``video`` | ``audio`` | ``document`` so the
    Baileys bridge renders the right native WhatsApp message kind. Voice notes
    and audio files route to ``audio``; ``force_document`` (the [[as_document]]
    directive) forces every file to ``document`` regardless of extension.
    r  r&   r  r  r  )r   r   splitextr   _WA_AUDIO_EXTS_WA_IMAGE_EXTS_WA_VIDEO_EXTS)r  rr  rs  r  s       r   _bridge_media_typery    ss      z
'

9
%
%a
(
.
.
0
0C 3.((w
nw
nw:rb   )	thread_idmedia_filesrs  r  c          	        K   t          | di           pi }	 ddl}n# t          $ r ddicY S w xY w	 |                    dd          }	t	          |          }
|pg }|pd}|rt          |          d	k    r|nd}d}|                                4 d{V }|                                r|s|                    d
|	 d|
|d|	                    d                    4 d{V 	 }|j
        dk    rM|                                 d{V }dd|j
         d| icddd          d{V  cddd          d{V  S |                                 d{V }|                    d          }ddd          d{V  n# 1 d{V swxY w Y   |D ]1\  }}t          j                            |          s|r	 |                    d
|	 d|
|d|	                    d                    4 d{V 	 }|j
        dk    r-|                                 d{V                     d          }	 ddd          d{V  n# 1 d{V swxY w Y   n*# t           $ r t"                              d           Y nw xY wdd| ic cddd          d{V  S t'          |||          }|
||d}|dk    r"t          j                            |          |d<   |r||d<   |                    d
|	 d||	                    d                    4 d{V 	 }|j
        dk    rO|                                 d{V }dd|j
         d| icddd          d{V  c cddd          d{V  S |                                 d{V }|                    d          p|}ddd          d{V  n# 1 d{V swxY w Y   3	 ddd          d{V  n# 1 d{V swxY w Y   dd|
|dS # t           $ r}dd | icY d}~S d}~ww xY w)!a  Out-of-process WhatsApp delivery via the local bridge HTTP API.

    Implements the standalone_sender_fn contract so deliver=whatsapp cron jobs
    succeed when cron runs separately from the gateway. Replaces the legacy
    _send_whatsapp helper.

    When ``caption`` is provided (single-file ``MEDIA:<path> caption`` send),
    the text rides on the media bubble's native caption via the bridge
    ``/send-media`` ``caption`` field instead of being posted as a separate
    ``/send`` message beforehand.
    r   r   Nr>  z/aiohttp not installed. Run: pip install aiohttpr   r   r   r&   zhttp://localhost:r  r}  r  r  r  r  zWhatsApp bridge error (z): r  z7WhatsApp caption-fallback send failed for missing mediazWhatsApp media file not found: r  r  r  r  r  r  zWhatsApp media error (Twhatsapp)rz  platformrs  r|  zWhatsApp send failed: )r   r2  ImportErrorr   r   rG   r3  r*   r  r4  r  r!   r5  r   r   rg   rP   rl   rn   ry  r  )pconfigrs  ri  rz  r{  rs  r  r   r2  r   normalized_chat_idmediar!   media_captionr  rK  rL  r  rM  
media_pathrr  r  r  rB  s                           r   _standalone_sendr    s	     * GWb))/REL L L LJKKKKLJ7iit44,W55!r}" %,JE

ad((** 8	O 8	O 8	O 8	O 8	O 8	O 8	Og zz|| 
<M 
<"<<::::$64HH#111;; (   	< 	< 	< 	< 	< 	< 	< 	< {c))%)YY[[000000 ')Y4;)Y)YSW)Y)YZ	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	<	8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O "&,,,,,,D&*hh{&;&;O	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< ). %O %O$
Hw~~j11 U
 % 
f	f'.|| FK F F F0B}%]%](/(=(=B(=(G(G (4 ( ( [ [ [ [ [ [ [ [ "&#';##5#5=AYY[[7H7H7H7H7H7H6M6Mk6Z6ZO$Z[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [  ) f f f"NN+deeeeef#%Sz%S%STTTI8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	OJ 0
HnUU
0 *!++ +
 ++*,'*:*::*F*FGJ'  7)6GI&"<<@@@@ #111<< (   	O 	O 	O 	O 	O 	O 	O 	O {c))%)YY[[000000 ')X$+)X)XRV)X)XY	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O_8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	On "&,,,,,,D&*hh{&;&;&NO	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O9%O'8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	O 8	Ov "))	
 
 	
  7 7 75!5566666667s   --A"O/ AO$4E>O*O/ =/E>,O>
F	OF	,O99I39H?-I?
I		II	IO$I85O7I88OO/ A<O4N1OO/ .1N1O1
N;;O>N;?OO/ 
O!!O/ $O!%	O/ /
P
9P?P
P
c                  d   ddl m} m}m} ddlm}m}m}m}m	}  |d            |d            |d            | d          }|r/|
                                dv r |d	            |d
d          sdS  |dd          r |dd            |d           n |dd            |d           dS  |d          }	|	r+ |d|	                    dd                      |d            |d                                          }
|
r |d|
           dS  |d          r |d           dS dS )zGuide the user through WhatsApp setup.

    Replaces the central _setup_whatsapp in hermes_cli/gateway.py and the
    static _PLATFORMS["whatsapp"] dict. CLI helpers are lazy-imported so the
    plugin's module-load surface stays minimal.
    r   )get_env_valueremove_env_valuesave_env_value)promptprompt_yes_noprint_header
print_infoprint_successWhatsAppz;WhatsApp uses a local Node.js bridge (WhatsApp Web client).zBStart the bridge separately; the gateway connects to it over HTTP.WHATSAPP_ENABLED>   r   r   r   zWhatsApp: already enabledzReconfigure WhatsApp?FNzEnable WhatsApp?Tr   zWhatsApp enabledr  zWhatsApp left disabledz@Allowed user IDs (comma-separated, leave empty for no allowlist)r    r   zWhatsApp allowlist configuredz4Home chat ID for cron delivery (leave empty to skip)WHATSAPP_HOME_CHANNELzHome channel cleared.)hermes_cli.configr  r  r  hermes_cli.cli_outputr  r  r  r  r  r   r   r*   )r  r  r  r  r  r  r  r  r  allowed_usershome_channels              r   interactive_setupr    s    RQQQQQQQQQ              LJLMMMJSTTT}/00H HNN$$(<<<
.///}4e<< 	F}'.. )6222()))))7333
+,,,FJ M  7/1F1FsB1O1OPPP56666PQQWWYYL 0.=====344 	0J./////	0 	0rb   yaml_cfgwhatsapp_cfgc                 8   ddl }d|v rHt          j        d          s4t          |d                                                   t          j        d<   d|v r<t          j        d          s(|                    |d                   t          j        d<   |                    d          }|dt          j        d          sPt          |t                    rd	
                    d
 |D                       }t          |          t          j        d<   d|v rHt          j        d          s4t          |d                                                   t          j        d<   |                    d          }|dt          j        d          sPt          |t                    rd	
                    d |D                       }t          |          t          j        d<   d|v rHt          j        d          s4t          |d                                                   t          j        d<   |                    d          }|dt          j        d          sPt          |t                    rd	
                    d |D                       }t          |          t          j        d<   dS )u/  Translate config.yaml whatsapp: keys into WHATSAPP_* env vars.

    Implements the apply_yaml_config_fn contract (#24849). Mirrors the legacy
    whatsapp_cfg block from gateway/config.py::load_gateway_config(). Env vars
    take precedence over YAML. Returns None — everything flows through env.
    r   Nrequire_mentionr  mention_patternsr  free_response_chatsr   ,c              3   4   K   | ]}t          |          V  d S r\  r^   r  vs     r   	<genexpr>z%_apply_yaml_config.<locals>.<genexpr>;  (      //a3q66//////rb   r   r   r   r   c              3   4   K   | ]}t          |          V  d S r\  r  r  s     r   r  z%_apply_yaml_config.<locals>.<genexpr>B  s(      --Q#a&&------rb   r   r   r   r  c              3   4   K   | ]}t          |          V  d S r\  r  r  s     r   r  z%_apply_yaml_config.<locals>.<genexpr>I  r  rb   )r5  r   r   r^   r   environdumpsr   r   r  join)r  r  _jsonfrcafgafs         r   _apply_yaml_configr  ,  sY    L((;U1V1V(14\BS5T1U1U1[1[1]1]
-.\))")<W2X2X)27++lK]>^2_2_
./


0
1
1C
ry)GHHc4   	0((//3/////C58XX
12l""295I+J+J"+.|K/H+I+I+O+O+Q+Q
'(			,	'	'B	~bi(@AA~b$ 	.--"-----B/22ww
+,%%bi8O.P.P%.1,~2N.O.O.U.U.W.W
*+


-
.
.C
ry)GHHc4   	0((//3/////C58XX
124rb   c                     t          | di           pi }| t          | dd          r|rdS ddlm} |                    d          pd                                                                }|d	v S )
uV  WhatsApp is considered connected when the user has explicitly enabled it
    via ``WHATSAPP_ENABLED`` (or the YAML-bridged equivalent on the config).

    Auth itself is handled by the external Node.js bridge — we can't verify the
    bridge token here — so the opt-in flag is the connection signal. The legacy
    built-in path keyed off ``WHATSAPP_ENABLED`` in both the connected-platforms
    check and the setup-status display; returning an unconditional True here
    would make WhatsApp always show as "configured" in ``hermes setup`` even
    when the user never enabled it. #41112.
    r   NenabledFTr   r  r   >   r   r   r   )r   hermes_cli.gatewaygatewayr  r*   r   )r   r   gateway_modr   s       r   _is_connectedr  N  s     FGR((.BEgfi??E t -,,,,,$$%788>B
E
E
G
G
M
M
O
OC&&&rb   c                      t          |           S )zFFactory wrapper that constructs WhatsAppAdapter from a PlatformConfig.)r   )r   s    r   _build_adapterr  f  s    6"""rb   c                     |                      ddt          t          t          dgdt          t
          dddt          dd	d
           dS )u:   Plugin entry point — called by the Hermes plugin system.r}  r  r  uF   WhatsApp requires a Node.js bridge — see the WhatsApp messaging docsr   WHATSAPP_ALLOW_ALL_USERSr  i   u   💬T)r   labeladapter_factorycheck_fnis_connectedrequired_envinstall_hintsetup_fnapply_yaml_config_fnallowed_users_envallow_all_envcron_deliver_env_varstandalone_sender_fnmax_message_lengthemojiallow_update_commandN)register_platformr  r   r  r  r  r  )ctxs    r   registerr  k  s\    &,"()]"/204-!!      rb   )r   r[  )Kr`  r   loggingr   r~  r0   rK   r'   systemrD   pathlibr   typingr   r   r   rE   r   hermes_constantsr	   r
   r   r^   r   	getLoggerr]  rl   rI  r-   r  r7   rT   r   ra   rr   rw   r   sysr   insert__file__r   r  gateway.configr   r   r   r   gateway.whatsapp_identityr   r   r   r   r   r   r   r   r   utilsr   r   r   r   r   rw  rx  rv  ry  r  r  r  r  r  r  r  r  rb   r   <module>r     s   "   				  				     ho9,       & & & & & & & & & & E E E E E E         / / /c /3 / / / /* 
	8	$	$ ' # # # # # #L#S #T # # # #LBS B B B B B B>. . . . . .b 3 4      6; , , ,d ,t , , , ,\ 


 33ttH~~--//7:;; < < < 3 3 3 3 3 3 3 3 C C C C C C 5 5 5 5 5 5                       & & & & & &RT c     T    .m m m m m+-@ m m m~' <;;BBBCCC#  t PS    2 d7 d7 d7 d7 d7N-0 -0 -0 -0` T dTk    D'T ' ' ' '0# # #
     rb   