
    )j_8                       U 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	m
Z
 ddlmZmZmZ  ej        d          Zddd	d
ddddgddddd
dddd
dddd
dddd
dddd
dddd
dddd
dddd
dddd
dddd
ddd d
d!Zd"ed#<   i Zd$ed%<   i Zd&ed'<    ej                    Zd(ZdDd+ZdEd-ZdFd0ZdGd4ZdHd7ZdIdJd:ZdKd;Z	 dLdMd?ZdNd@Z dNdAZ!dOdBZ"g dCZ#dS )Pu  Auto-installation of LSP server binaries.

Tries to install missing servers using whatever package manager is
appropriate.  All installs go to a Hermes-owned bin staging dir,
``<HERMES_HOME>/lsp/bin/``, so we don't pollute the user's global
toolchain.

Strategies:

- ``auto`` — attempt to install with the best available package
  manager.  This is the default.
- ``manual`` — never install; if a binary is missing, the server is
  silently skipped and the user is told about it via ``hermes lsp
  status``.
- ``off`` — same as ``manual`` for now (kept distinct so we can
  evolve behavior later, e.g. logging differently).

The actual installs happen synchronously the first time a server is
needed and concurrent calls to :func:`try_install` for the same
package are deduplicated via a per-package lock.

Failure modes are non-fatal: every install path is wrapped in
try/except and returns ``None`` on failure.  The tool layer then
falls back to its in-process syntax checker, exactly as if the user
hadn't enabled LSP at all.
    )annotationsN)Path)AnyDictOptionalzagent.lsp.installnpmpyrightzpyright-langserver)strategypkgbintypescript-language-server
typescript)r
   r   r   
extra_pkgs@vue/language-serverzvue-language-serversvelte-language-serversvelteserver@astrojs/language-serverzastro-lsyaml-language-serverbash-language-serverintelephense!dockerfile-language-server-nodejszdocker-langservergozgolang.org/x/tools/gopls@latestgoplsmanual rust-analyzerclangdlua-language-server)r	   r   r   r   r   r   r   r   r   r   r   r   r   zDict[str, Dict[str, Any]]INSTALL_RECIPESzDict[str, threading.Lock]_install_lockszDict[str, Optional[str]]_install_results)z.cmd.exez.batreturnboolc                 "    t           j        dk    S )Nnt)osname     8/home/wildlama/.hermes/hermes-agent/agent/lsp/install.py_is_windowsr,   r   s    7d?r*   r   c                    t           j                            d          } | =t           j                            t           j                            d          d          } t          |           dz  dz  }|                    dd           |S )	z8Return the Hermes-owned bin staging dir for LSP servers.HERMES_HOMEN~z.hermeslspr   Tparentsexist_ok)r'   environgetpathjoin
expanduserr   mkdir)homeps     r+   hermes_lsp_bin_dirr<   v   so    :>>-((D|w||BG..s33Y??T

UU"AGGD4G(((Hr*   base
list[Path]c                \   | g}t                      rt          |                                           h}t          D ]p}t	          t          |           |z             }t          |                                          }||vr*|                    |           |                    |           q|S )zAReturn platform-native executable candidates for a staged binary.)r,   strlower_WINDOWS_WRAPPER_SUFFIXESr   appendadd)r=   
candidatesexistingsuffix	candidatekeys         r+   _native_binary_candidatesrJ      s    J}} "IIOO%%&/ 	" 	"FSYY/00Ii..&&((C(""!!),,,S!!!r*   r(   r@   Optional[str]c                l   t          t                      | z            D ]F}|                                r0t          j        |t          j                  rt          |          c S Gt          j        |           }|r|S t                      r(t          D ] }t          j        |  |           }|r|c S !dS )z9Probe the staging dir + PATH for a binary named ``name``.N)rJ   r<   existsr'   accessX_OKr@   shutilwhichr,   rB   )r(   stagedon_pathrG   s       r+   _existing_binaryrT      s    +,>,@,@4,GHH  ==?? 	ry99 	v;;l4  G }} / 	 	Fld#4F#4#455G 4r*   r   threading.Lockc                    t           5  t                              |           }|t          j                    }|t          | <   |cd d d            S # 1 swxY w Y   d S N)_install_lock_metar    r5   	threadingLock)r   locks     r+   	_get_lockr\      s    	  !!#&&<>##D"&N3                 s   ;AAAautor
   c                   |dvr@t                               | i           }|                    d|           }t          |          S | t          v rt          |          S t	          |           }|5  | t          v rt          |          cddd           S t          |           }|t          | <   |cddd           S # 1 swxY w Y   dS )u  Try to install ``pkg`` and return the binary path if successful.

    ``strategy`` is ``"auto"``, ``"manual"``, or ``"off"``.  In
    ``manual``/``off`` mode, this function only probes for an
    existing binary and returns ``None`` if not found.

    The install is cached per-package — a second call returns the
    same path (or ``None``) without reinstalling.  Concurrent calls
    are serialized.
    >   r]   r   N)r   r5   rT   r!   r\   _do_install)r   r
   recipebin_namer[   results         r+   try_installrc      s,    y   !$$S"--::eS)))))
$$S>>D	  """#C(        S!! &                 s   ,B6B66B:=B:c                   t                               |           }|t          j        |           S |                    dd          }|                    d|           }t	          |          }|r|S |dk    rt
                              d| |           d S |dk    r;t          |                    d|           ||                    d          pg           S |d	k    r$t          |                    d|           |          S |d
k    r$t          |                    d|           |          S t
          
                    d||            d S )Nr
   r   r   z0[install] %s requires manual install (recipe=%s)r   r   r   )r   r   pipz$[install] unknown strategy %r for %s)r   r5   rP   rQ   rT   loggerdebug_install_npm_install_go_install_pipwarning)r   r`   r
   ra   rF   s        r+   r_   r_      sM     %%F~|C   zz*h//Hzz%%%H  ))H 8GfUUUt5JJuc""zz,//52
 
 
 	

 46::eS118<<<5FJJuc22H===
NN98SIII4r*   ra   r   Optional[list]c           	        t          j        d          }|t                              d|            dS t	                      j        }| gt          |pg           z   }	 t                              d|d                    |                     t          j	        |ddt          |          dd	d
g|ddddt          j                  }|j        dk    r=t                              d| |j                                        dd                    dS n@# t          j        t"          f$ r'}t                              d| |           Y d}~dS d}~ww xY w|dz  dz  |z  }t%          |          D ]}	|	                                rt	                      |	j        z  }
|
                                sh	 |
                    |	           nQ# t"          t,          f$ r= 	 t          j        |	|
           n## t"          $ r t          |	          cY cY c S w xY wY nw xY wt          |
                                r|
n|	          c S t                              d| |           dS )a  Install an npm package into our staging dir.

    Uses ``npm install --prefix`` so the binaries land in
    ``<staging>/node_modules/.bin/<bin_name>`` and we symlink them up
    one level for direct PATH-style access.

    ``extra_pkgs`` is a list of sibling packages to install in the
    same ``node_modules`` tree.  Used for LSP servers with runtime
    peer deps that npm doesn't auto-pull (typescript-language-server
    needs ``typescript`` next to it; intelephense ships standalone).
    r   Nz,[install] cannot install %s: npm not on PATHz$[install] npm install --prefix %s %s installz--prefixz--silentz	--no-fundz
--no-auditFT,  checkcapture_outputtexttimeoutstdinr   z'[install] npm install failed for %s: %s  z([install] npm install errored for %s: %snode_modulesz.binz;[install] npm install for %s succeeded but bin %s not found)rP   rQ   rf   infor<   parentlistr7   
subprocessrunr@   DEVNULL
returncoderk   stderrstripTimeoutExpiredOSErrorrJ   rM   r(   
symlink_toNotImplementedErrorcopy2)r   ra   r   r   staginginstall_targetsprocenm_binclinks              r+   rh   rh      s     ,u

C
{BCHHHt "")Ged:#3444O2HH_%%	
 	
 	

 ~)ZWz;P\o_no$
 
 
 ?aNN93@Q@Q@S@STXUXTX@Y   4	  
 %w/   A3JJJttttt
 ~%.9F&v.. 5 588:: 	5%''!&0D;;== &&OOA&&&&!45 & & &&Q----" & & &"1vv& .-& t{{}}3tt!44444	5 NNPRUW_```4sO   B/D E%EE*G  HG('H(HHHHHc           	     H   t          j        d          }|t                              d|            dS t	                      }t          t          j                  }t          |          |d<   	 t                              d| |           t          j
        |d| gdddd	|t          j        
          }|j        dk    r=t                              d| |j                                        dd                    dS n@# t          j        t"          f$ r'}t                              d| |           Y d}~dS d}~ww xY w||z  }t%                      r|                    d          }|                                rt          |          S t                              d| |           dS )z'Install a Go module to GOBIN=<staging>.r   Nz+[install] cannot install %s: go not on PATHGOBINz"[install] go install %s (GOBIN=%s)ro   FTiX  )rr   rs   rt   ru   envrv   r   z&[install] go install failed for %s: %srw   z'[install] go install errored for %s: %sr"   z:[install] go install for %s succeeded but bin %s not found)rP   rQ   rf   ry   r<   dictr'   r4   r@   r|   r}   r~   r   rk   r   r   r   r   r,   with_suffixrM   )r   ra   r   r   r   r   r   bin_paths           r+   ri   ri   (  s   	d		B	zA3GGGt ""G
rz

Cw<<CL8#wGGG~C $
 
 
 ?aNN8#t{?P?P?R?RSWTWSW?X   4	  
 %w/   @#qIIIttttt !H}} 0''// 8}}
NNOQTV^___4s   .B
C; ;D8D33D8c           
     `   t                      j        dz  }|                    dd           	 t                              d||            t          j        t          j        ddddt          |          d	| gd
dddt
          j
                  }|j        dk    r=t                              d| |j                                        dd                    dS n@# t
          j        t           f$ r'}t                              d| |           Y d}~dS d}~ww xY w|dz  g}t#                      r|                    |dz             |D ]}t'          ||z            D ]}|                                rt                      |j        z  }|                                sj	 |                    |           nS# t           t.          f$ r? 	 t1          j        ||           n%# t           $ r t          |          cY cY c c S w xY wY nw xY wt          |                                r|n|          c c S ԌdS )a;  Install a Python package into a hermes-owned target dir.

    We avoid polluting the user's site-packages by using
    ``pip install --target``.  Bins go into
    ``<staging>/python-packages/bin/`` which we symlink into
    ``<staging>/bin``.  Note: this only works for packages that ship a
    console script.
    zpython-packagesTr1   z$[install] pip install --target %s %sz-mre   ro   z--targetz--quietFrp   rq   r   z'[install] pip install failed for %s: %sNrw   z([install] pip install errored for %s: %sr   Scripts)r<   rz   r9   rf   ry   r|   r}   sys
executabler@   r~   r   rk   r   r   r   r   r,   rC   rJ   rM   r(   r   r   rP   r   )	r   ra   
pip_targetr   r   script_dirs
script_dirr   r   s	            r+   rj   rj   M  s    $%%,/@@JTD111:JLLL~^T5)ZZR[]`a$
 
 
 ?aNN93@Q@Q@S@STXUXTX@Y   4	  
 %w/   A3JJJttttt
 %&K}} 3:	1222! @ @
1*x2GHH 	@ 	@H   
@)++hm;{{}} 111111#%89 1 1 11"L48888& 1 1 1#&x==0000000001 981
 4;;==>44h???????
@	@ 4sN   B%C D-DDF00H GH G:	1H 9G:	:H ?H c                    t                               |           }|r|                    d|           n| }t          |          rdS |r|                    d          dk    rdS dS )zReturn ``installed``, ``missing``, or ``manual-only`` for a package.

    Used by the ``hermes lsp status`` CLI to give users a quick
    overview of what's available without spawning anything.
    r   	installedr
   r   zmanual-onlymissing)r   r5   rT   )r   r`   ra   s      r+   detect_statusr     sq       %%F)/8vzz%%%%SH!! { &**Z((H44}9r*   )r   rc   r   r<   )r#   r$   )r#   r   )r=   r   r#   r>   )r(   r@   r#   rK   )r   r@   r#   rU   )r]   )r   r@   r
   r@   r#   rK   )r   r@   r#   rK   rW   )r   r@   ra   r@   r   rl   r#   rK   )r   r@   ra   r@   r#   rK   )r   r@   r#   r@   )$__doc__
__future__r   loggingr'   rP   r|   r   rY   pathlibr   typingr   r   r   	getLoggerrf   r   __annotations__r    r!   rZ   rX   rB   r,   r<   rJ   rT   r\   rc   r_   rh   ri   rj   r   __all__r)   r*   r+   <module>r      s    4 # " " " " "  				      



           & & & & & & & & & &		.	/	/ ")<PQQ ++
 $n	# 	# %$  '  )! ! %%  %% 
 "'~nUU2"* * 'HQXYY #+2oNN#Bx@@ )1DYZZm7. 7. 7 7 7 7t -/ . . . .-/  / / / /#Y^%% 4                     >   H "&> > > > >B" " " "J/ / / /d     r*   