+
    KiD                        R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt]P                  ! 4       R8H  t
^ RIHt ^ RIHt ^ RIHt RtRtR R	 lt]! 4       tRR
 R lltR R lt]tRtR R ltRtR R ltR R lt ! R R]]4      tR# )zHLocal execution environment with interrupt support and non-blocking I/O.NWindows)BaseEnvironment)PersistentShellMixin)is_interrupted__HERMES_FENCE_a9f7b3___HERMES_FORCE_c                $    V ^8  d   QhR\         /#    return)	frozenset)formats   "5/home/ubuntu/hermes-agent/tools/environments/local.py__annotate__r       s     ` `y `    c                 L   \        4       p  ^ RIHp VP                  4        FM  pV P	                  VP
                  4       VP                  '       g   K2  V P                  VP                  4       KO  	   ^ RI	H
p VP                  4        Fc  w  rEVP                  R4      pVRA9   d   V P                  V4       K0  VR8X  g   K9  VP                  R4      '       g   KR  V P                  V4       Ke  	  V P	                  0 RkRkRkR	kR
kRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkRkR kR!kR"kR#kR$kR%kR&kR'kR(kR)kR*kR+kR,kR-kR.kR/kR0kR1kR2kR3kR4kR5kR6kR7kR8kR9kR:kR;kR<kR=kR>kR?kR@k4       \        V 4      #   \         d     ELi ; i  \         d     Li ; i)BaH  Derive the blocklist from provider, tool, and gateway config.

Automatically picks up api_key_env_vars and base_url_env_var from
every registered provider, plus tool/messaging env vars from the
optional config registry, so new Hermes-managed secrets are blocked
in subprocesses without having to maintain multiple static lists.
)PROVIDER_REGISTRY)OPTIONAL_ENV_VARScategorysettingpasswordOPENAI_BASE_URLOPENAI_API_KEYOPENAI_API_BASEOPENAI_ORG_IDOPENAI_ORGANIZATIONOPENROUTER_API_KEYANTHROPIC_BASE_URLANTHROPIC_TOKENCLAUDE_CODE_OAUTH_TOKEN	LLM_MODELGOOGLE_API_KEYDEEPSEEK_API_KEYMISTRAL_API_KEYGROQ_API_KEYTOGETHER_API_KEYPERPLEXITY_API_KEYCOHERE_API_KEYFIREWORKS_API_KEYXAI_API_KEYHELICONE_API_KEYPARALLEL_API_KEYFIRECRAWL_API_KEYFIRECRAWL_API_URLTELEGRAM_HOME_CHANNELTELEGRAM_HOME_CHANNEL_NAMEDISCORD_HOME_CHANNELDISCORD_HOME_CHANNEL_NAMEDISCORD_REQUIRE_MENTIONDISCORD_FREE_RESPONSE_CHANNELSDISCORD_AUTO_THREADSLACK_HOME_CHANNELSLACK_HOME_CHANNEL_NAMESLACK_ALLOWED_USERSWHATSAPP_ENABLEDWHATSAPP_MODEWHATSAPP_ALLOWED_USERSSIGNAL_HTTP_URLSIGNAL_ACCOUNTSIGNAL_ALLOWED_USERSSIGNAL_GROUP_ALLOWED_USERSSIGNAL_HOME_CHANNELSIGNAL_HOME_CHANNEL_NAMESIGNAL_IGNORE_STORIES
HASS_TOKENHASS_URLEMAIL_ADDRESSEMAIL_PASSWORDEMAIL_IMAP_HOSTEMAIL_SMTP_HOSTEMAIL_HOME_ADDRESSEMAIL_HOME_ADDRESS_NAMEGATEWAY_ALLOWED_USERSGH_TOKENGITHUB_APP_IDGITHUB_APP_PRIVATE_KEY_PATHGITHUB_APP_INSTALLATION_IDMODAL_TOKEN_IDMODAL_TOKEN_SECRETDAYTONA_API_KEY>   tool	messaging)sethermes_cli.authr   valuesupdateapi_key_env_varsbase_url_env_varaddImportErrorhermes_cli.configr   itemsgetr   )blockedr   pconfigr   namemetadatar   s          r   _build_provider_env_blocklistrc       s    G5(//1GNN7334'''G445 2	7/557ND||J/H00D!Y&8<<
+C+CD! 8 NN @@@ 	@ 		@
 	@ 	@ 	@ 	@ 	"@ 	@ 	@ 	@ 	@ 	@  	!@" 	#@$ 	%@& 	'@( 	)@* 	+@, 	-@. 	/@0 	1@4 	 5@6 	%7@8 	9@: 	$;@< 	"=@> 	)?@@ 	A@B 	C@D 	"E@F 	G@H 	I@J 	K@L 	!M@N 	O@P 	Q@R 	S@T 	%U@V 	W@X 	#Y@Z 	 [@\ 	]@^ 	_@` 	a@b 	c@d 	e@f 	g@h 	i@j 	"k@l 	 m@p 	q@r 	s@t 	&u@v 	%w@z 	{@| 	}@~ 	@ @B Wa    s7   AF F 4A
F F F FFF#"F#c                X    V ^8  d   QhR\         R,          R\         R,          R\         /# )r
   base_envN	extra_envr   dict)r   s   "r   r   r      s*      td{ td{ VZ r   c                    ^ RI Hp / pT ;'       g    / P                  4        FA  w  rEVP	                  \
        4      '       d   K"  V\        9  g   V! V4      '       g   K=  WSV&   KC  	  T;'       g    / P                  4        FW  w  rEVP	                  \
        4      '       d   V\        \
        4      R pWSV&   K8  V\        9  g   V! V4      '       g   KS  WSV&   KY  	  V#   \         d    R p Li ; i)a+  Filter Hermes-managed secrets from a subprocess environment.

`_HERMES_FORCE_<VAR>` entries in ``extra_env`` opt a blocked variable back in
intentionally for callers that truly need it.  Vars registered via
:mod:`tools.env_passthrough` (skill-declared or user-configured) also
bypass the blocklist.
is_env_passthroughc                     R # F _s   &r   <lambda>*_sanitize_subprocess_env.<locals>.<lambda>       Er   N)tools.env_passthroughrk   	Exceptionr]   
startswith!_HERMES_PROVIDER_ENV_FORCE_PREFIX_HERMES_PROVIDER_ENV_BLOCKLISTlen)re   rf   _is_passthrough	sanitizedkeyvaluereal_keys   &&     r   _sanitize_subprocess_envr      s    *O !#I~~2,,.
>>;<<448L8L"cN	 / !B--/
>>;<<3@ABCH"'h66/#:N:N"cN 0 %  *)*s   C   C10C1c                $    V ^8  d   QhR\         /# r	   str)r   s   "r   r   r      s     ( (C (r   c            	     R   \         '       g   \        P                  ! R4      ;'       g    \        P                  P                  R4      '       d   RMR;'       g[    \        P                  P                  R4      '       d   RMR;'       g*    \        P                  P                  R4      ;'       g    R# \        P                  P                  R4      p V '       d(   \        P                  P                  V 4      '       d   V # \        P                  ! R4      pV'       d   V# \        P                  P                  \        P                  P                  RR	4      R
RR4      \        P                  P                  \        P                  P                  RR4      R
RR4      \        P                  P                  \        P                  P                  RR4      RR
RR4      3 F6  pV'       g   K  \        P                  P                  V4      '       g   K4  Vu # 	  \        R4      h)u   Find bash for command execution.

The fence wrapper uses bash syntax (semicolons, $?, printf), so we
must use bash — not the user's $SHELL which could be fish/zsh/etc.
On Windows: uses Git Bash (bundled with Git for Windows).
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environr^   joinRuntimeError)customfound	candidates      r   
_find_bashr      s    ;LL   #%77>>/#B#B !ww~~k::  zz~~g&  	
 ZZ^^23F"''..(( LL E 	RZZ^^N4GH%QVXbc
RZZ^^$79RSUZ\acmn
RZZ^^NB7UES]^	
 9	22 	A r   c                0    V ^8  d   QhR\         R\         /# )r
   outputr   r   )r   s   "r   r   r      s      s s r   c                   R R lpV P                  R4      pV'       d)   V! V^ ,          4      '       d   VP                  ^ 4       K0  \        V4      ^,
          pV^ 8  d.   W#,          '       d   V! W#,          4      '       d   V^,          pK4  V^ 8  d   R# VRV^,            pRP                  V4      pV P	                  R4      '       d)   V'       d!   VP	                  R4      '       g
   VR,          pV# )zStrip shell startup/exit warnings that leak when using -i without a TTY.

Removes lines matching known noise patterns from both the beginning
and end of the output.  Lines in the middle are left untouched.
c                0    V ^8  d   QhR\         R\        /# )r
   liner   )r   bool)r   s   "r   r   (_clean_shell_noise.<locals>.__annotate__   s     G G G Gr   c                    a  \         ;QJ d#    V 3R  l\         4       F  '       g   K   R# 	  R# ! V 3R  l\         4       4      # )c              3   ,   <"   T F	  qS9   x  K  	  R # 5iNrn   ).0noiser   s   & r   	<genexpr>8_clean_shell_noise.<locals>._is_noise.<locals>.<genexpr>   s     F.EUD=.Es   TF)any_SHELL_NOISE_SUBSTRINGS)r   s   fr   	_is_noise%_clean_shell_noise.<locals>._is_noise   s.    sF.EFssFsFsF.EFFFr   
r   N)splitpopry   r   endswith)r   r   linesendcleanedresults   &     r   _clean_shell_noiser      s    G LLE IeAh''		! e*q.C
(EJJ)EJ*?*?q
QwIcAgGYYwF t0E0E$Mr   za/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binc                0    V ^8  d   QhR\         R\         /# )r
   envr   rg   )r   s   "r   r   r     s      t  r   c                    ^ RI Hp \        \        P
                  V ,          4      p/ pVP                  4        FW  w  rEVP                  \        4      '       d   V\        \        4      R pWSV&   K8  V\        9  g   V! V4      '       g   KS  WSV&   KY  	  VP                  RR4      pRVP                  R4      9  d   V'       d   V R\         2M\        VR&   V#   \         d    R p Li ; i)zDBuild a run environment with a sane PATH and provider-var stripping.rj   c                     R # rm   rn   ro   s   &r   rq   _make_run_env.<locals>.<lambda>  rs   r   NPATHr   z/usr/bin:)rt   rk   ru   rh   r   r   r]   rv   rw   ry   rx   r^   r   
_SANE_PATH)r   rz   mergedrun_envkvr~   existing_paths   &       r   _make_run_envr     s    *O "**s"#FG<<9::>?@AH !H448J8JAJ  KK+M,,S11=J]O1ZL9PZN  *)*s   C C,+C,c                0    V ^8  d   QhR\         R\         /# )r
   rawr   r   )r   s   "r   r   r   %  s        r   c                    V P                  \        4      pVR8X  d   \        V 4      # V\        \        4      ,           pV P	                  \        4      pW18:  d   \        WR 4      # WV # )ab  Extract real command output from between fence markers.

The execute() method wraps each command with printf(FENCE) markers.
This function finds the first and last fence and returns only the
content between them, which is the actual command output free of
any shell init/exit noise.

Falls back to pattern-based _clean_shell_noise if fences are missing.
N)find_OUTPUT_FENCEr   ry   rfind)r   firststartlasts   &   r   _extract_fenced_outputr   %  s_     HH]#E{!#&&C&&E99]#D}!#f+..T?r   c                      a a ] tR tRt oRtRV3R lV 3R lllt]V3R lR l4       tV3R lR	 ltV3R
 lR lt	R t
R tRRRRR/V3R lR llltRtVtV ;t# )LocalEnvironmenti=  a  Run commands directly on the host machine.

Features:
- Popen + polling for interrupt support (user can cancel mid-command)
- Background stdout drain thread to prevent pipe buffer deadlocks
- stdin_data support for piping content (bypasses ARG_MAX limits)
- sudo -S transform via SUDO_PASSWORD env var
- Uses interactive login shell so full user env is available
- Optional persistent shell mode (cwd/env vars survive across calls)
Nc                2   < V ^8  d   QhRS[ RS[RS[RS[/# )r
   cwdtimeoutr   
persistent)r   intrh   r   )r   __classdict__s   "r   r   LocalEnvironment.__annotate__I  s*     * *C *s *d *!*r   c                   < \         ST `  T;'       g    \        P                  ! 4       W#R 7       W@n        V P                  '       d   V P                  4        R# R# ))r   r   r   N)super__init__r   getcwdr   _init_persistent_shell)selfr   r   r   r   	__class__s   &&&&&r   r   LocalEnvironment.__init__I  sB    S//BIIKJ$???'') r   c                    < V ^8  d   QhRS[ /# r	   r   )r   r   s   "r   r   r   Q  s     7 7c 7r   c                     R V P                    2# )z/tmp/hermes-local-)_session_idr   s   &r   _temp_prefixLocalEnvironment._temp_prefixP  s    #D$4$4#566r   c                4   < V ^8  d   QhRS[ P                  /# r	   )
subprocessPopen)r   r   s   "r   r   r   T  s     
 
j&6&6 
r   c           
        \        4       p\        V P                  4      p\        P                  ! VR .\        P
                  \        P
                  \        P                  RT\        '       d   RR7      # \        P                  R7      # )z-lTN)stdinstdoutstderrtextr   
preexec_fn)
r   r   r   r   r   PIPEDEVNULLr   r   setsid)r   
user_shellr   s   &  r   _spawn_shell_process%LocalEnvironment._spawn_shell_processT  si    \
)//??%%*{t
 	
 13		
 	
r   c                6   < V ^8  d   QhRS[ RS[S[ ,          /# )r
   pathsr   )r   list)r   r   s   "r   r   r   a  s      s tCy r   c                *   . pV Fv  p\         P                  P                  V4      '       d>   \        V4      ;_uu_ 4       pVP	                  VP                  4       4       R R R 4       Ke  VP	                  R4       Kx  	  V#   + '       g   i     K  ; i)Nr   )r   r   existsopenappendread)r   r   resultsr   fs   &*   r   _read_temp_files!LocalEnvironment._read_temp_filesa  sg    Dww~~d##$ZZ1NN1668,  Z r"  	  ZZs     BBc                    V P                   f   R #  \        P                  ! RR\        V P                   4      .R^R7       R #   \        P                  \
        3 d     R # i ; i)Npkillz-PT)capture_outputr   )
_shell_pidr   runr   TimeoutExpiredFileNotFoundErrorr   s   &r   _kill_shell_children%LocalEnvironment._kill_shell_childrenk  sX    ??"	NN$DOO 45#Q ))+<= 		s   /A A"!A"c                    \         P                   ! V P                   R 24       F@  p\        P                  P	                  V4      '       g   K*  \        P
                  ! V4       KB  	  R# )z-*N)globr   r   r   r   remove)r   r   s   & r   _cleanup_temp_files$LocalEnvironment._cleanup_temp_filesv  sA    d//034Aww~~a  		! 5r   r   
stdin_datac          
      T   < V ^8  d   QhRS[ RS[ RS[R,          RS[ R,          RS[/# )r
   commandr   r   Nr  r   )r   r   rh   )r   r   s   "r   r   r   {  sI     kA kA kA# kA"%*kA%(4ZkA;?kAr   c               D  aaa T;'       g*    V P                   ;'       g    \        P                  ! 4       pT;'       g    V P                  pV P	                  V4      w  rxVe   Ve
   W,           oM	Ve   VoMVo\        4       p	R\         RV R\         R2p
\        V P                  4      p\        P                  ! V	RV
.RTTRR\        P                  \        P                  Se   \        P                  M\        P                  \        '       d   R M\        P                  R	7
      oSe.   VV3R
 lp\         P"                  ! VRR7      P%                  4        . oVV3R lp\         P"                  ! VRR7      pVP%                  4        \&        P(                  ! 4       V,           pSP+                  4       Ef   \-        4       '       d    \        '       d   SP/                  4        MX\        P0                  ! SP2                  4      p\        P4                  ! V\6        P8                  4        SP;                  RR7       VPG                  ^R7       RRPG                  S4      R,           R^/# \&        P(                  ! 4       V8  d    \        '       d   SP/                  4        MD\        P4                  ! \        P0                  ! SP2                  4      \6        P8                  4        VPG                  ^R7       RPG                  S4      pRV R2pRV'       d   VV,           R^|/# VPI                  4       R^|/# \&        PJ                  ! R4       EK  VPG                  ^R7       \M        RPG                  S4      4      pRVRSPN                  /#   \        P<                   d*    \        P4                  ! T\6        P>                  4        ELi ; i  \@        \B        3 d    SPE                  4         ELi ; i  \@        \B        3 d    SPE                  4         EL3i ; i)Nzprintf 'z'
z
__hermes_rc=$?
printf 'z'
exit $__hermes_rc
z-licTzutf-8replace)	r   r   r   encodingerrorsr   r   r   r   c                     <  SP                   P                  S 4       SP                   P                  4        R #   \        \        3 d     R # i ; ir   )r   writecloseBrokenPipeErrorOSError)effective_stdinprocs   r   _write_stdin7LocalEnvironment._execute_oneshot.<locals>._write_stdin  sA    JJ$$_5JJ$$&'1 s   5: AA)targetdaemonc                  0  <  SP                    F  p SP                  V 4       K  	   SP                   P                  4        R #   \         d     L*i ; i  \         d     R # i ; i   SP                   P                  4        i   \         d     i i ; i; ir   )r   r   
ValueErrorr  ru   )r   _output_chunksr  s    r   _drain_stdout8LocalEnvironment._execute_oneshot.<locals>._drain_stdout  s    	 KKD"))$/ (
KK%%'	  
 ! KK%%'  sX   $A A AA' AA' A$#A$'B)BBBBBBg      ?)r   r   r   u2   
[Command interrupted — user sent a new message]
returncodez
[Command timed out after zs]g?)(r   r   r   r   _prepare_commandr   r   r   r   r   r   r   STDOUTr   r   r   	threadingThreadr   time	monotonicpollr   	terminategetpgidpidkillpgsignalSIGTERMwaitr  SIGKILLProcessLookupErrorPermissionErrorkillr   lstripsleepr   r%  )r   r  r   r   r  work_direffective_timeoutexec_command
sudo_stdinr   
fenced_cmdr   r  r#  readerdeadlinepgidpartialtimeout_msgr   r"  r  r  s   &&&$$               @@@r   _execute_oneshot!LocalEnvironment._execute_oneshot{  sF    11$((11biik#33t||#'#8#8#A !j&<(5O#(O(O\
 }oSn $o &"# 	  ),??$$%4%@*//jFXFX*{t		
 & L>DDF$&
	 !!tD>>#&77iik! "{(!zz$((3		$7< IIcI2
 A&bggn58mm #  ~~(* "{(		"**TXX"6G A&''.1 ;<M;NbQwg3 # DODVDVDX #  JJsOA'(?@&,@@9  *88 <IIdFNN;<*O<  IIK  +O<  IIK s\   O O )AO /N 
O: O: 'AO: :OO OO !O76O7:!PP)r   )r   <   NF)r   )__name__
__module____qualname____firstlineno____doc__r   propertyr   r   r   r  r  rD  __static_attributes____classdictcell____classcell__)r   r   s   @@r   r   r   =  so     	* * 7 7
 
 	
kA/3kA26kA kA kAr   r   r   )z'bash: cannot set terminal process groupz"bash: no job control in this shellzno job control in this shellz!cannot set terminal process groupz)tcsetattr: Inappropriate ioctl for devicezRestored session:zSaving session...zLast login:zcommand not found:z	Oh My Zshz	compinit:)rK  r
  r   platformr   r1  r   r(  r*  systemr   tools.environments.baser   #tools.environments.persistent_shellr   tools.interruptr   r   rw   rc   rx   r   r   _find_shellr   r   r   r   r   r   rn   r   r   <module>rV     s    N  	      oo9, 3 D * * %5 !`F "?!@ >(X 
 "HC *0iA+_ iAr   