
    Pmj:                    D   d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZmZ ddlmZ  ej        e          ZdZde ZdZd	Z ed
 eD                       Z ed eD                       ZdZ ed eD                       Z ed eD                       Zd;dZd<dZd=dZd>d?dZ dZ!dZ"d>d@d!Z#dAdBd#Z$ed$fdCd'Z%edfdDd(Z&dEd*Z'	 	 dFdGd0Z(d1Z)d2Z*e G d3 d4                      Z+e G d5 d6                      Z,dHd8Z-edfdId9Z.edfdJd:Z/dS )KzHShared helpers for attaching Hermes to a local Chromium-family CDP port.    )annotationsN)	dataclassfield)get_hermes_homei$  zhttp://127.0.0.1:)z</Applications/Google Chrome.app/Contents/MacOS/Google Chromez2/Applications/Chromium.app/Contents/MacOS/Chromiumz</Applications/Brave Browser.app/Contents/MacOS/Brave Browserz>/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge)))
chrome.exechrome))GoogleChromeApplicationr   ))chromium.exechromium))Chromiumr   r   )r   r   r   ))	brave.exebrave))BraveSoftwarezBrave-Browserr   r   ))
msedge.exemsedge))	MicrosoftEdger   r   c              #  *   K   | ]\  }}|D ]}|V  d S N .0names_names       @/home/thesage/.hermes/hermes-agent/hermes_cli/browser_connect.py	<genexpr>r   (   s4      ZZHE1TYZZD4ZZZZZZZ    c              #  *   K   | ]\  }}|D ]}|V  d S r   r   )r   r   grouppartss       r   r   r   )   s5      ``EZ_``QVu```````r    )))zgoogle-chromezgoogle-chrome-stable)z/opt/google/chrome/chromez/usr/bin/google-chromez/usr/bin/google-chrome-stable))zchromium-browserr   )z/usr/bin/chromium-browserz/usr/bin/chromium))zbrave-browserzbrave-browser-stabler   )z/usr/bin/brave-browserz/usr/bin/brave-browser-stablez/usr/bin/bravez/snap/bin/bravez"/opt/brave.com/brave/brave-browserz/opt/brave.com/brave/bravez/opt/brave-bin/brave))zmicrosoft-edgezmicrosoft-edge-stabler   )z/usr/bin/microsoft-edgez/usr/bin/microsoft-edge-stablez$/opt/microsoft/msedge/microsoft-edgez/opt/microsoft/msedge/msedgec              #  *   K   | ]\  }}|D ]}|V  d S r   r   r   s       r   r   r   K   s4      VV(%PUVVVVVVVVVr    c              #  *   K   | ]\  }}|D ]}|V  d S r   r   )r   r   pathspaths       r   r   r   L   s4      ZZhaTYZZDTZZZZZZZr    systemstrreturn	list[str]c           	        g t                      dfddfd
}| dk    rt          D ]} |           S | dk    rt          j                            d          t          j                            d          t          j                            d          f}t
          D ]_\  }}|D ]} t          j        |                      t          d |          D ]'}|D ]"} t          j	        j
        |g|R             #(`S t          D ]7\  }}	|D ]} t          j        |                      |	D ]}
 |
           8 |dt
                     S )Nr'   
str | Noner*   Nonec                &   | sd S t           j                            t           j                            |                     }|v st           j                            |           sd S                     |                                |           d S r   )osr'   normcasenormpathisfileappendadd)r'   
normalized
candidatesseens     r   r5   z(get_chrome_debug_candidates.<locals>.addS   s     	FW%%bg&6&6t&<&<==
RW^^D%9%9F$r    basestuple[str | None, ...]install_groups?tuple[tuple[tuple[str, ...], tuple[tuple[str, ...], ...]], ...]c           	     ~    |D ]8\  }}t          d |           D ]"}|D ]} t          j        |g|R             #9d S r   )filter	posixpathjoin)r9   r;   r   r"   baser#   r5   s         r   add_windows_install_pathsz>get_chrome_debug_candidates.<locals>.add_windows_install_paths\   s{     ' 	6 	6HAutU++ 6 6" 6 6E C	t4e4445555	66	6 	6r    DarwinWindowsProgramFileszProgramFiles(x86)LOCALAPPDATA)z/mnt/c/Program Filesz/mnt/c/Program Files (x86))r'   r-   r*   r.   )r9   r:   r;   r<   r*   r.   )set_DARWIN_APPSr0   environget_WINDOWS_BROWSER_GROUPSshutilwhichr>   r'   r@   _LINUX_BROWSER_GROUPS)r(   rB   appinstall_basesr   install_partsr   rA   r#   r&   r'   r5   r7   r8   s              @@@r   get_chrome_debug_candidatesrR   O   s   JUUD      
6 
6 
6 
6 
6 
6  	 	CCHHHHJNN>**JNN.//JNN>**

 %< 	4 	4 E= ( (FL&&''''t]33 4 4* 4 4ECT2E222333344 -  u 	$ 	$DCT""#### 	 	DCIIII	TVmnnnr    c                 >    t          t                      dz            S )Nzchrome-debug)r)   r   r   r    r   chrome_debug_data_dirrT      s      >1222r    portintc                2    d|  dt                       ddgS )Nz--remote-debugging-port=z--user-data-dir=z--no-first-runz--no-default-browser-check)rT   )rU   s    r   _chrome_debug_argsrX      s/    )4))402244$	 r          ?urltimeoutfloatboolc                $   ddl }ddl}ddlm}  |d| v r| nd|            }	 |j        p|j        dv rdnd}n# t          $ r Y d	S w xY w|j        d
v rn|j                            d          rT|j	        sd	S 	 |
                    |j	        |f|          5  	 ddd           dS # 1 swxY w Y   n# t          $ r Y d	S w xY wddd                    |j        |j                  }|dvs|j        sd	S | d|j                             d          }| d| dfD ]u}		 |j                            |	|          5 }
dt#          |
dd          cxk    rdk     rn n	 ddd            dS ddd           n# 1 swxY w Y   f# t$          $ r Y rw xY wd	S )zFReturn True when ``url`` exposes a reachable Chrome DevTools endpoint.r   N)urlparsez://http://>   wsshttpsi  P   F>   wsra   z/devtools/browser/r[   Thttprb   )rd   ra   >   rf   rb   /z/json/versionz/json   statusi,  )socketurllib.requesturllib.parser_   rU   scheme
ValueErrorr'   
startswithhostnamecreate_connectionOSErrorrJ   netlocrstriprequesturlopengetattr	Exception)rZ   r[   rj   urllibr_   parsedrU   rm   rootproberesps              r   is_browser_debug_readyr~      s   MMM%%%%%%XUc\\cc??F{Pfm7G&G&GssR   uu }%%&+*@*@AU*V*V% 	5	))6?D*A7)SS                   	 	 	55	 7++//v}MMF&&&fm&u((((//44D(((T...9  	''w'??  4'$#66<<<<<<<<<                                                 	 	 	H	5s   9 
AA7B0 B$B0 $B((B0 +B(,B0 0
B>=B>F 9!E4F (F 4E8	8F ;E8	<F  
FF)	127.0.0.1z[::1])r   ::1r-   c                T    t           D ]}d| d|  }t          ||          r|c S  dS )ay  Return the first loopback URL (IPv4 first, then IPv6) speaking CDP.

    Dual-stack discovery: when another application squats the IPv4
    loopback on ``port``, a debug browser launched with
    ``--remote-debugging-port`` may bind only ``[::1]``. Probing both
    literals finds it either way. Returns ``None`` when neither
    loopback exposes a CDP discovery endpoint.
    r`   :re   N)_LOOPBACK_PROBE_HOSTSr~   )rU   r[   hostrZ   s       r   discover_local_cdp_urlr      sP     &  %%%t%%!#w777 	JJJ	4r          ?c                    ddl }t          D ]G}	 |                    || f|          5  	 ddd            dS # 1 swxY w Y   8# t          $ r Y Dw xY wdS )a  Return True when either loopback accepts TCP on ``port``.

    Callers use this AFTER a failed CDP probe to distinguish "port is
    free, we can launch a browser on it" from "another application
    (IDE debugger, dev server) is squatting the port and a launch
    would fight it".
    r   Nre   TF)rj   _LOOPBACK_SOCKET_HOSTSrq   rr   )rU   r[   rj   r   s       r   local_port_in_user      s     MMM&  	))4,)HH                    	 	 	H	5s-   A8A<	A<	 A
AA
   	preferredattemptsc                   ddl }t          | dz   | dz   |z             D ]}d}|j        df|j        dffD ]\  }}	 |                     ||j                  5 }|                    |j        |j        d           |                    ||f           ddd           n# 1 swxY w Y   r# t          $ r d}Y  nw xY w|r|c S | dz   S )a|  Return the first port after ``preferred`` bindable on both loopbacks.

    Used when ``preferred`` is occupied by a non-CDP application: rather
    than launching a browser into a bind conflict, pick a nearby free
    port. Falls back to ``preferred + 1`` if nothing binds (the launch
    will then fail with a clear browser-side error instead of silently
    doing nothing).
    r   N   Tr   r   F)
rj   rangeAF_INETAF_INET6SOCK_STREAM
setsockopt
SOL_SOCKETSO_REUSEADDRbindrr   )r   r   rj   rU   bindablefamilyr   socks           r   find_free_debug_portr      sJ    MMMi!mY]X%=>>  $nk:V_e<TU 	 	LFD]]66+=>> ,$OOF$5v7JANNNIItTl+++, , , , , , , , , , , , , , ,       	KKK	q=s5   B&9BB&BB&!B"B&&B65B6c                   |pt          j                    }t          |          }|rF|d         gt          |           }|dk    rt	          j        |          nt          j        |          S |dk    rt                      }d|  d| dS d S )Nr   rD   rC   z7open -a "Google Chrome" --args --remote-debugging-port=z --user-data-dir="z+" --no-first-run --no-default-browser-check)	platformr(   rR   rX   
subprocesslist2cmdlineshlexr@   rT   )rU   r(   r7   argvdata_dirs        r   manual_chrome_debug_commandr      s    (x((F,V44J Z19 24 8 8906)0C0Cz&t,,,TXIYIYY(**Vd V V (V V V	

 4r    dictc                    | dk    rddiS t          t          dd          t          t          dd          z  }|rd|ini S )NrD   start_new_sessionTDETACHED_PROCESSr   CREATE_NEW_PROCESS_GROUPcreationflags)rw   r   )r(   flagss     r   _detach_kwargsr     sZ    #T**J 2A66.: : E (-4OU##"4r           @皙?procsubprocess.Popenintervalc                $   t          j                    |z   }t          j                    |k     rbt          |t          |d                    rdS |                                 dS t          j        |           t          j                    |k     bdS )a+  Classify a launched browser as ready, exited, or still starting.

    We only need to wait long enough to catch the common failure mode where a
    candidate binary exists but exits immediately before exposing the CDP port.
    Slower browsers can still finish starting after this grace window.
    g?re   readyNexitedstarting)time	monotonicr   minpollsleep)r   rU   r[   r   deadlines        r   %_wait_for_browser_debug_ready_or_exitr     s     ~')H
.

X
%
% "$Hc0B0BCCC 	799;;"8
8 .

X
%
% :r    zlaunch-stderr.logi  c                  D    e Zd ZU dZded<   ded<   dZded<   dZded	<   dS )
LaunchAttemptz/Outcome of one candidate-binary launch attempt.r)   binarystateNz
int | None
returncode stderr_tail)__name__
__module____qualname____doc____annotations__r   r   r   r    r   r   r   3  sL         99KKKJJJ!J!!!!Kr    r   c                  \    e Zd ZU dZdZded<    ee          Zded<   e	dd
            Z
dS )ChromeDebugLaunchaL  Structured result of ``launch_chrome_debug``.

    ``launched`` mirrors the legacy boolean contract: a launch command was
    executed and the browser is ready or still starting (it does NOT
    guarantee the CDP port ever opens). ``attempts`` carries per-candidate
    diagnostics so callers can explain *why* nothing came up.
    Fr]   launched)default_factoryzlist[LaunchAttempt]r   r*   r-   c                   | j         D ]F}|j        dk    r9|j        dk    r.t          j                            |j                  }| d| dc S G| j         D ]n}|j        dk    ra|j        rZt          j                            |j                   d|j                                        d         	                                 c S odS )z>Best user-facing explanation for a failed/soft launch, if any.r   r   uJ    exited immediately without opening the debug port — an already-running z instance likely absorbed the launch (Chromium's single-instance behavior). Close ALL of its processes (including background/tray instances) and retry /browser connect.z& exited before the debug port opened: N)
r   r   r   r0   r'   basenamer   r   
splitlinesstrip)selfattemptr   s      r   hintzChromeDebugLaunch.hintJ  s    } 	 	G}((W-?1-D-Dw''77 2 22 2 2   } 	 	G}((W-@(w''77 F F*5577;AACCF F   tr    N)r*   r-   )r   r   r   r   r   r   r   listr   propertyr   r   r    r   r   r   =  so           H$)E$$?$?$?H????   X  r    r   r'   c                   	 t          | d          5 }|                                }d d d            n# 1 swxY w Y   |t           d                              dd                                          S # t
          $ r Y dS w xY w)Nrbzutf-8replace)errorsr   )openread_STDERR_TAIL_LIMITdecoder   rr   )r'   fhdatas      r   _read_stderr_tailr   _  s    $ 	7799D	 	 	 	 	 	 	 	 	 	 	 	 	 	 	''(()000KKQQSSS   rrs,   A5 3A5 7A5 79A5 5
BBc           
     x   |pt          j                    }t                      }t          |          }|st                              d|           |S t                      }t          j        |d           t          j	        
                    |t                    }|D ]}	 t          |d          5 }t          j        |gt          |           ft          j        |dt#          |          }ddd           n# 1 swxY w Y   n\# t$          $ rO}	|j                            t+          |d                     t                              d	||	           Y d}	~	d}	~	ww xY wt                              d
|t-          |dd          |            t/          ||           }
t+          ||
          }|j                            |           |
dk    rd|_        |c S t-          |dd          |_        t5          |          |_        t                              d||j        | |j        r
d|j         nd           |S )uV  Launch a Chromium-family browser with remote debugging, with diagnostics.

    Tries each detected candidate binary in turn. A candidate that exits
    before the CDP port opens (crash, singleton forward to an existing
    instance, bad profile dir) is logged — with exit code and a stderr tail —
    and the next candidate is tried.
    zAbrowser debug launch: no Chromium-family binary found (system=%s)T)exist_okwb)stdoutstderrNzspawn-failed)r   r   z,browser debug launch: failed to spawn %s: %szIbrowser debug launch: spawned %s (pid=%s) with --remote-debugging-port=%dpidr   r   zAbrowser debug launch: %s exited (code=%s) before port %d opened%sz; stderr tail: r   )r   r(   r   rR   loggerinforT   r0   makedirsr'   r@   _LAUNCH_STDERR_LOGr   r   PopenrX   DEVNULLr   rx   r   r4   r   rw   r   r   r   r   r   warning)rU   r(   resultr7   r   stderr_path	candidatestderr_filer   excr   r   s               r   launch_chrome_debugr   h  s    (x((F  F,V44J WY_```$&&HK4((((',,x);<<K $
 $
		k4(( K!':!3D!9!9:%-&  %V,,	                 	 	 	O""=	#X#X#XYYYKKF	SVWWWHHHH	
 	WD%&&		
 	
 	
 6dDAAy>>>w'''H"FOMMM$T<>>/<<O7>7JR3g1333PR	
 	
 	
 	
 Ms=   !D1=C:.D:C>	>DC>	D
EAEEc                ,    t          | |          j        S r   )r   r   )rU   r(   s     r   try_launch_chrome_debugr     s    tV,,55r    )r(   r)   r*   r+   )r*   r)   )rU   rV   r*   r+   )rY   )rZ   r)   r[   r\   r*   r]   )rU   rV   r[   r\   r*   r-   )r   )rU   rV   r[   r\   r*   r]   )r   rV   r   rV   r*   rV   )rU   rV   r(   r-   r*   r-   )r(   r)   r*   r   )r   r   )
r   r   rU   rV   r[   r\   r   r\   r*   r)   )r'   r)   r*   r)   )rU   rV   r(   r-   r*   r   )rU   rV   r(   r-   r*   r]   )0r   
__future__r   loggingr0   r   r?   r   rL   r   r   dataclassesr   r   hermes_constantsr   	getLoggerr   r   DEFAULT_BROWSER_CDP_PORTDEFAULT_BROWSER_CDP_URLrH   rK   tuple_WINDOWS_BIN_NAMES_WINDOWS_INSTALL_PARTSrN   _LINUX_BIN_NAMES_LINUX_INSTALL_PATHSrR   rT   rX   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   <module>r     sB   N N " " " " " "  				             ( ( ( ( ( ( ( ( , , , , , ,		8	$	$   H.FHH   UZZ0GZZZZZ ``5L`````  @ 5VV.CVVVVV uZZ2GZZZZZ 2 2 2 2j3 3 3 3   ! ! ! ! !P / -          & +CTV     4 -E[_     $5 5 5 5 	    4 )                  B    )t; ; ; ; ;| )AW[ 6 6 6 6 6 6 6r    