
    iB                     ^   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ddlm	Z	m
Z
  ej                    dk    ZdZdefdZ e            Zddedz  d	edz  defd
ZdefdZeZdZdedefdZdeee         ef         fdZdee         fdZdedee         defdZ G d de	          ZdS )uE   Local execution environment — spawn-per-call with session snapshot.    N)BaseEnvironment_pipe_stdinWindows_HERMES_FORCE_returnc                  `   t                      } 	 ddlm} |                                D ]=}|                     |j                   |j        r|                     |j                   >n# t          $ r Y nw xY w	 ddl	m
} |                                D ]d\  }}|                    d          }|dv r|                     |           4|dk    r*|                    d          r|                     |           en# t          $ r Y nw xY w|                     h d           t          |           S )	z=Derive the blocklist from provider, tool, and gateway config.r   )PROVIDER_REGISTRY)OPTIONAL_ENV_VARScategory>   tool	messagingsettingpassword>?   GH_TOKENHASS_URL	LLM_MODEL
HASS_TOKENXAI_API_KEYGROQ_API_KEYVERCEL_TOKENEMAIL_ADDRESSGITHUB_APP_IDOPENAI_ORG_IDWHATSAPP_MODECOHERE_API_KEYEMAIL_PASSWORDGOOGLE_API_KEYMODAL_TOKEN_IDOPENAI_API_KEYSIGNAL_ACCOUNTVERCEL_TEAM_IDANTHROPIC_TOKENDAYTONA_API_KEYEMAIL_IMAP_HOSTEMAIL_SMTP_HOSTMISTRAL_API_KEYOPENAI_API_BASEOPENAI_BASE_URLSIGNAL_HTTP_URLDEEPSEEK_API_KEYHELICONE_API_KEYPARALLEL_API_KEYTOGETHER_API_KEYWHATSAPP_ENABLEDFIRECRAWL_API_KEYFIRECRAWL_API_URLFIREWORKS_API_KEYVERCEL_OIDC_TOKENVERCEL_PROJECT_IDANTHROPIC_BASE_URLEMAIL_HOME_ADDRESSMODAL_TOKEN_SECRETOPENROUTER_API_KEYPERPLEXITY_API_KEYSLACK_HOME_CHANNELDISCORD_AUTO_THREADOPENAI_ORGANIZATIONSIGNAL_HOME_CHANNELSLACK_ALLOWED_USERSDISCORD_HOME_CHANNELSIGNAL_ALLOWED_USERSGATEWAY_ALLOWED_USERSSIGNAL_IGNORE_STORIESTELEGRAM_HOME_CHANNELWHATSAPP_ALLOWED_USERSCLAUDE_CODE_OAUTH_TOKENDISCORD_REQUIRE_MENTIONEMAIL_HOME_ADDRESS_NAMESLACK_HOME_CHANNEL_NAMESIGNAL_HOME_CHANNEL_NAMEDISCORD_HOME_CHANNEL_NAMEGITHUB_APP_INSTALLATION_IDSIGNAL_GROUP_ALLOWED_USERSTELEGRAM_HOME_CHANNEL_NAMEGITHUB_APP_PRIVATE_KEY_PATHDISCORD_FREE_RESPONSE_CHANNELS)sethermes_cli.authr	   valuesupdateapi_key_env_varsbase_url_env_varaddImportErrorhermes_cli.configr
   itemsget	frozenset)blockedr	   pconfigr
   namemetadatar   s          =/home/ubuntu/.hermes/hermes-agent/tools/environments/local.py_build_provider_env_blocklistr`      s   G555555(//11 	6 	6GNN73444' 6G4555	6    	777777/5577 	" 	"ND(||J//H000D!!!!Y&&8<<
+C+C&D!!!	"     NN @ @ @ @ @ @B Ws%   AA) )
A65A6:A?C: :
DDbase_env	extra_envc                    	 ddl m} n# t          $ r d }Y nw xY wi }| pi                                 D ]9\  }}|                    t
                    r |t          vs ||          r|||<   :|pi                                 D ]Z\  }}|                    t
                    r"|t          t
                    d         }|||<   A|t          vs ||          r|||<   [ddlm	}  |            }|r||d<   |S )z<Filter Hermes-managed secrets from a subprocess environment.r   is_env_passthroughc                     dS NF _s    r_   <lambda>z*_sanitize_subprocess_env.<locals>.<lambda>x       E     Nget_subprocess_homeHOME)
tools.env_passthroughre   	ExceptionrX   
startswith!_HERMES_PROVIDER_ENV_FORCE_PREFIX_HERMES_PROVIDER_ENV_BLOCKLISTlenhermes_constantsro   )	ra   rb   _is_passthrough	sanitizedkeyvaluereal_keyro   _profile_homes	            r_   _sanitize_subprocess_envr~   s   sf   *OOOOOOO * * *)/* !#I~2,,.. # #
U>>;<< 	4448L8L4"IcN B--// # #
U>>;<< 	#3@AABBCH"'Ih666//#:N:N6"IcN 544444''))M *)	&   	 c            	         t           s{t          j        d          pft          j                            d          rdndpCt          j                            d          rdndp t          j                            d          pdS t          j                            d          } | r!t          j                            |           r| S t          j        d          }|r|S t          j                            t          j                            dd	          d
dd          t          j                            t          j                            dd          d
dd          t          j                            t          j                            dd          dd
dd          fD ]'}|r#t          j                            |          r|c S (t          d          )z Find bash for command execution.bashz/usr/bin/bashNz	/bin/bashSHELLz/bin/shHERMES_GIT_BASH_PATHProgramFileszC:\Program FilesGitbinzbash.exezProgramFiles(x86)zC:\Program Files (x86)LOCALAPPDATA ProgramszGit Bash not found. Hermes Agent requires Git for Windows on Windows.
Install it from: https://git-scm.com/download/win
Or set HERMES_GIT_BASH_PATH to your bash.exe location.)
_IS_WINDOWSshutilwhichospathisfileenvironrY   joinRuntimeError)customfound	candidates      r_   
_find_bashr      s    
L   #%7>>/#B#BL!w~~k::D z~~g&& 	
 Z^^233F "'..(( L  E  	RZ^^N4GHH%QVXbcc
RZ^^$79RSSUZ\acmnn
RZ^^NB77UES]^^  	
  		22 	
	A  rm   za/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binenvc                    	 ddl m} n# t          $ r d }Y nw xY wt          t          j        | z            }i }|                                D ]Z\  }}|                    t                    r"|t          t                    d         }|||<   A|t          vs ||          r|||<   [|                    dd          }d|                    d          vr|r| dt           nt          |d<   dd	lm}  |            }	|	r|	|d
<   |S )zDBuild a run environment with a sane PATH and provider-var stripping.r   rd   c                     dS rg   rh   ri   s    r_   rk   z_make_run_env.<locals>.<lambda>   rl   rm   NPATHr   z/usr/bin:rn   rp   )rq   re   rr   dictr   r   rX   rs   rt   rv   ru   rY   split
_SANE_PATHrw   ro   )
r   rx   mergedrun_envkvr|   existing_pathro   r}   s
             r_   _make_run_envr      s^   *OOOOOOO * * *)/* "*s"##FG  1<<9:: 	>??@@AH !GH4448J8J4GAJKK++M,,S1111=JZ]99Z999PZ
 544444''))M ('Nr   c                  <   	 ddl m}   |             pi }|                    d          pi }|                    d          pg }t          |t                    sg }t          |                    dd                    }d |D             |fS # t          $ r g dfcY S w xY w)u   Return (shell_init_files, auto_source_bashrc) from config.yaml.

    Best-effort — returns sensible defaults on any failure so terminal
    execution never breaks because the config file is unreadable.
    r   )load_configterminalshell_init_filesauto_source_bashrcTc                 0    g | ]}|t          |          S rh   )str).0fs     r_   
<listcomp>z4_read_terminal_shell_init_config.<locals>.<listcomp>   s#    +++1+A+++rm   )rW   r   rY   
isinstancelistboolrr   )r   cfgterminal_cfgfilesauto_bashrcs        r_    _read_terminal_shell_init_configr      s    111111kmm!rwwz**0b  !344:%&& 	E<++,@$GGHH+++++[88   4xs   BB
 
BBc                     t                      \  } }g }| r|                    |            n |rt          s|                    g d           g }|D ]}	 t          j                            t          j                            |                    }n# t          $ r Y Lw xY w|r4t          j                            |          r|	                    |           |S )uh  Resolve the list of files to source before the login-shell snapshot.

    Expands ``~`` and ``${VAR}`` references and drops anything that doesn't
    exist on disk, so a missing ``~/.bashrc`` never breaks the snapshot.
    The ``auto_source_bashrc`` path runs only when the user hasn't supplied
    an explicit list — once they have, Hermes trusts them.
    )z
~/.profilez~/.bash_profilez	~/.bashrc)
r   extendr   r   r   
expandvars
expanduserrr   r   append)explicitr   
candidatesresolvedrawr   s         r_   _resolve_shell_init_filesr      s     =>>HkJ J(####	 J[ J  	HHHIIIH " "	7%%bg&8&8&=&=>>DD 	 	 	H	 	"BGNN4(( 	"OOD!!!Os   <B
BB
cmd_stringr   c                     |s| S dg}|D ]4}|                     dd          }|                    d| d| d           5d                    |          dz   }|| z   S )a  Prepend ``source <file>`` lines (guarded + silent) to a bash script.

    Each file is wrapped so a failing rc file doesn't abort the whole
    bootstrap: ``set +e`` keeps going on errors, ``2>/dev/null`` hides
    noisy prompts, and ``|| true`` neutralises the exit status.
    zset +e'z'\''z[ -r 'z
' ] && . 'z' 2>/dev/null || true
)replacer   r   )r   r   prelude_partsr   safepreludes         r_   _prepend_shell_initr     s      JM S S ||C))QdQQdQQQRRRRii&&-GZrm   c                        e Zd ZdZddededef fdZd	efd
Zdddddede	dededz  d	e
j        f
dZd ZdefdZd Z xZS )LocalEnvironmentzRun commands directly on the host machine.

    Spawn-per-call: every execute() spawns a fresh bash process.
    Session snapshot preserves env vars across calls.
    CWD persists via file-based read after each command.
    r   <   Ncwdtimeoutr   c                     |rt           j                            |          }t                                          |pt          j                    ||           |                                  d S )N)r   r   r   )r   r   r   super__init__getcwdinit_session)selfr   r   r   	__class__s       r_   r   zLocalEnvironment.__init__8  sb     	*'$$S))CS/BIKKcJJJrm   r   c                    dD ]k}| j                             |          pt          j                            |          }|r.|                    d          r|                    d          pdc S lt          j                            d          r.t          j        dt          j	        t          j
        z            rdS t          j                    }|                    d          r|                    d          pdS dS )a6  Return a shell-safe writable temp dir for local execution.

        Termux does not provide /tmp by default, but exposes a POSIX TMPDIR.
        Prefer POSIX-style env vars when available, keep using /tmp on regular
        Unix systems, and only fall back to tempfile.gettempdir() when it also
        resolves to a POSIX path.

        Check the environment configured for this backend first so callers can
        override the temp root explicitly (for example via terminal.env or a
        custom TMPDIR), then fall back to the host process environment.
        )TMPDIRTMPTEMP/z/tmp)r   rY   r   r   rs   rstripr   isdiraccessW_OKX_OKtempfile
gettempdir)r   env_varr   s      r_   get_temp_dirzLocalEnvironment.get_temp_dir>  s     1 	4 	4GW--H1H1HI 4Y11#66 4 '',,33337==   	RYvrw7H%I%I 	6'))	$$ 	0##C((/C/vrm   Fx   )loginr   
stdin_datar   r   r   c                   t                      }|r t                      }|rt          ||          }|r|dd|gn|d|g}t          | j                  }t          j        |d|ddt
          j        t
          j        |t
          j        nt
          j	        t          rd nt          j        | j        
  
        }	t          s0	 t          j        |	j                  |	_        n# t"          $ r Y nw xY w|t%          |	|           |	S )Nz-lz-cTzutf-8r   )	textr   encodingerrorsstdoutstderrstdin
preexec_fnr   )r   r   r   r   r   
subprocessPopenPIPESTDOUTDEVNULLr   r   setsidr   getpgidpid_hermes_pgidProcessLookupErrorr   )
r   r   r   r   r   r   
init_filesargsr   procs
             r_   	_run_bashzLocalEnvironment._run_bashX  s!    ||  	I244J I0ZHH
16TdD*--T4<T))?$%/%;*//AS*9tt	
 
 
  	$&Jtx$8$8!!%    !j)))s   <C 
C('C(c                    dt           dt          fddt           dt          dt          ffd}	 t          r                                 dS 	 t          j        j                  }n$# t          $ r t          dd          }| Y nw xY w	 t          j
        |t          j                   n# t          $ r Y dS w xY w ||d          rdS 	 t          j
        |t          j                   n# t          $ r Y dS w xY w ||d	           	                     d
           dS # t          j        t"          f$ r Y dS w xY w# t          t$          t"          f$ r+ 	                                  Y dS # t(          $ r Y Y dS w xY ww xY w)z-Kill the entire process group (all children).pgidr   c                 l    	 t          j        | d           dS # t          $ r Y dS t          $ r Y dS w xY w)Nr   TF)r   killpgr   PermissionError)r   s    r_   _group_alivez4LocalEnvironment._kill_process.<locals>._group_alive  sY    	$"""t%   uu"   tts    
3	33r   c                 ~   t          j                    |z   }t          j                    |k     r^	                                  n# t          $ r Y nw xY w |           sdS t          j        d           t          j                    |k     ^	                                  n# t          $ r Y nw xY w |            S )NTg?)time	monotonicpollrr   sleep)r   r   deadliner  r   s      r_   _wait_for_group_exitz<LocalEnvironment._kill_process.<locals>._wait_for_group_exit  s    ~'''1H.""X--IIKKKK    D#|D))  4
4    .""X--		   #|D))))s#   A 
AAB# #
B0/B0r   Ng      ?g       @g?)r   )intr   floatr   	terminater   r   r   r   getattrr   signalSIGTERMSIGKILLwaitr   TimeoutExpiredOSErrorr  killrr   )r   r   r	  r   r  s    `  @r_   _kill_processzLocalEnvironment._kill_process  s&   		s 		t 		 		 		 			*s 	*U 	*t 	* 	* 	* 	* 	* 	* 	*$$	      :dh//DD)   "4>>D| $|
IdFN3333)   FF ('c22 FIdFN3333)   FF$$T3///IIcI*****"17;   DD"OW= 	 	 			   	s   E A* )E *BE 
BE B/ .E /
B=9E <B==E C/ .E /
C=9E <C==E D% %D?;E >D??E FE11
F ;F?F  Fresultc                    	 t          | j                  5 }|                                                                }ddd           n# 1 swxY w Y   |r|| _        n# t
          t          f$ r Y nw xY w|                     |           dS )z;Read CWD from temp file (local-only, no round-trip needed).N)open	_cwd_filereadstripr   r  FileNotFoundError_extract_cwd_from_output)r   r  r   cwd_paths       r_   _update_cwdzLocalEnvironment._update_cwd  s    	dn%% ,6688>>++, , , , , , , , , , , , , , , $#*+ 	 	 	D	 	%%f-----s3   A 'A	A 	AA AA A21A2c                 r    | j         | j        fD ]'}	 t          j        |           # t          $ r Y $w xY wdS )zClean up temp files.N)_snapshot_pathr  r   unlinkr  )r   r   s     r_   cleanupzLocalEnvironment.cleanup  sY    %t~6 	 	A	!   	 	s   '
44)r   r   N)__name__
__module____qualname____doc__r   r
  r   r   r   r   r   r   r   r  r  r#  __classcell__)r   s   @r_   r   r   0  s         C s d      c    4 ;@!$+/& & &C &4 &&!Dj&4>4D& & & &PD D DL.$ . . . .      rm   r   )N)r'  r   platformr   r  r   r   r  tools.environments.baser   r   systemr   rt   rZ   r`   ru   r   r~   r   r   _find_shellr   r   tupler   r   r   r   r   r   rh   rm   r_   <module>r.     s   K K 				          @ @ @ @ @ @ @ @ho9, %5 !Yy Y Y Y Yx "?!>!@!@  td{ td{ VZ    >C    F 
C t     <%S	4*@    ('49 ' ' ' 'T C  S	  c        *i i i i i i i i i irm   