
    Kiڮ                        d 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m	Z	 ddl
mZmZmZmZ ddlmZ ddlmZ  e ej                              Zd ej                            ed	d
          ej                            ed	d          ej                            ed	d          ej                            ed	d           e e            dz            ej                            ed          ej                            ed          ej                            ed          ej                            ed          ej                            ed          ej                            ed          ej                            ed          ej                            ed          ej                            ed          dddfD             Zd ej                            ed	          ej                            ed          ej                            ed          ej                            ed          dd ej                            ed!          ej                            ed"          ej                            ed#d$          f	D             Zd%ee         fd&Zd'ed%efd(Ze G d) d*                      Ze G d+ d,                      Ze G d- d.                      Ze G d/ d0                      Z e G d1 d2                      Z!e G d3 d4                      Z"e G d5 d6                      Z# G d7 d8e          Z$h d9Z%h d:Z&d;d<d=d>d?d@Z'dAZ(dAZ)dBZ* G dC dDe$          Z+dS )EaL  
File Operations Module

Provides file manipulation capabilities (read, write, patch, search) that work
across all terminal backends (local, docker, singularity, ssh, modal, daytona).

The key insight is that all file operations can be expressed as shell commands,
so we wrap the terminal backend's execute() interface to provide a unified file API.

Usage:
    from tools.file_operations import ShellFileOperations
    from tools.terminal_tool import _active_environments
    
    # Get file operations for a terminal environment
    file_ops = ShellFileOperations(terminal_env)
    
    # Read a file
    result = file_ops.read_file("/path/to/file.py")
    
    # Write a file
    result = file_ops.write_file("/path/to/new.py", "print('hello')")
    
    # Search for content
    result = file_ops.search("TODO", path=".", file_glob="*.py")
    N)ABCabstractmethod)	dataclassfield)OptionalListDictAny)Path)get_hermes_homec                 L    h | ]!}t           j                            |          "S  )ospathrealpath.0ps     2/home/ubuntu/hermes-agent/tools/file_operations.py	<setcomp>r   ,   s5       BGQ      z.sshauthorized_keysid_rsa
id_ed25519configz.envz.bashrcz.zshrcz.profilez.bash_profilez	.zprofilez.netrcz.pgpassz.npmrcz.pypircz/etc/sudoersz/etc/passwdz/etc/shadowc                 f    g | ].}t           j                            |          t           j        z   /S r   )r   r   r   sepr   s     r   
<listcomp>r   B   s<       %&BGQ"&   r   z.awsz.gnupgz.kubez/etc/sudoers.dz/etc/systemdz.dockerz.azurez.configghreturnc                      t          j        dd          } | sdS 	 t           j                            t           j                            |                     S # t
          $ r Y dS w xY w)a\  Return the resolved HERMES_WRITE_SAFE_ROOT path, or None if unset.

    When set, all write_file/patch operations are constrained to this
    directory tree.  Writes outside it are denied even if the target is
    not on the static deny list.  Opt-in hardening for gateway/messaging
    deployments that should only touch a workspace checkout.
    HERMES_WRITE_SAFE_ROOT N)r   getenvr   r   
expanduser	Exception)roots    r   _get_safe_write_rootr(   Q   sp     9-r22D tw 2 24 8 8999   tts   ;A 
A%$A%r   c                 f   t           j                            t           j                            t	          |                               }|t
          v rdS t          D ]}|                    |          r dS t                      }|r*||k    s$|                    |t           j	        z             sdS dS )z.Return True if path is on the write deny list.TF)
r   r   r   r%   strWRITE_DENIED_PATHSWRITE_DENIED_PREFIXES
startswithr(   r   )r   resolvedprefix	safe_roots       r   _is_write_deniedr1   b   s    w 2 23t99 = =>>H %%%t'  v&& 	44	 %&&I I%%)<)<Y=O)P)P%45r   c                   $   e Zd ZU dZdZeed<   dZeed<   dZ	eed<   dZ
eed<   d	Zee         ed
<   dZeed<   dZeed<   d	Zee         ed<   d	Zee         ed<   d	Zee         ed<   d	Zee         ed<    ee          Zee         ed<   defdZd	S )
ReadResultzResult from reading a file.r#   contentr   total_lines	file_sizeF	truncatedNhint	is_binaryis_imagebase64_content	mime_type
dimensionserrordefault_factorysimilar_filesr    c                 H    d | j                                         D             S )Nc                 *    i | ]\  }}||g k    ||S Nr   r   kvs      r   
<dictcomp>z&ReadResult.to_dict.<locals>.<dictcomp>   s(    TTTA!-AQSGG1GGGr   __dict__itemsselfs    r   to_dictzReadResult.to_dict   s$    TT!4!4!6!6TTTTr   )__name__
__module____qualname____doc__r4   r*   __annotations__r5   intr6   r7   boolr8   r   r9   r:   r;   r<   r=   r>   r   listrA   r   dictrN   r   r   r   r3   r3   z   s#        %%GSKIsItD(3-ItHd$(NHSM(((#Ix}### $J$$$E8C=$uT:::M49:::U U U U U U Ur   r3   c                   p    e Zd ZU dZdZeed<   dZeed<   dZ	e
e         ed<   dZe
e         ed<   d	efd
ZdS )WriteResultzResult from writing a file.r   bytes_writtenFdirs_createdNr>   warningr    c                 H    d | j                                         D             S )Nc                     i | ]
\  }}|||S rD   r   rE   s      r   rH   z'WriteResult.to_dict.<locals>.<dictcomp>   s    HHHA!-1---r   rI   rL   s    r   rN   zWriteResult.to_dict   s$    HH!4!4!6!6HHHHr   )rO   rP   rQ   rR   rZ   rT   rS   r[   rU   r>   r   r*   r\   rW   rN   r   r   r   rY   rY      s         %%M3L$E8C=!GXc]!!!I I I I I I Ir   rY   c                   
   e Zd ZU dZdZeed<   dZeed<    e	e
          Zee         ed<    e	e
          Zee         ed<    e	e
          Zee         ed	<   d
Zeeeef                  ed<   d
Zee         ed<   defdZd
S )PatchResultzResult from patching a file.Fsuccessr#   diffr?   files_modifiedfiles_createdfiles_deletedNlintr>   r    c                     d| j         i}| j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   |S )Nra   rb   rc   rd   re   rf   r>   )ra   rb   rc   rd   re   rf   r>   rM   results     r   rN   zPatchResult.to_dict   s    T\*9 	'!YF6N 	;'+':F#$ 	9&*&8F?# 	9&*&8F?#9 	'!YF6N: 	)"jF7Or   )rO   rP   rQ   rR   ra   rU   rS   rb   r*   r   rV   rc   r   rd   re   rf   r   r	   r
   r>   rW   rN   r   r   r   r`   r`      s         &&GTD#NNN %d ; ; ;NDI;;;$uT:::M49:::$uT:::M49:::%)D(4S>
")))E8C=      r   r`   c                   @    e Zd ZU dZeed<   eed<   eed<   dZeed<   dS )SearchMatchzA single search match.r   line_numberr4   g        mtimeN)	rO   rP   rQ   rR   r*   rS   rT   rm   floatr   r   r   rk   rk      sF           
IIILLLE5r   rk   c                       e Zd ZU dZ ee          Zee         e	d<    ee          Z
ee         e	d<    ee          Zeeef         e	d<   dZee	d<   dZee	d	<   d
Zee         e	d<   defdZd
S )SearchResultzResult from searching.r?   matchesfilescountsr   total_countFr7   Nr>   r    c                     d| j         i}| j        rd | j        D             |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        rd|d<   | j        r
| j        |d<   |S )	Nrt   c                 8    g | ]}|j         |j        |j        d S ))r   liner4   r   rl   r4   )r   ms     r   r   z(SearchResult.to_dict.<locals>.<listcomp>   s8     ! ! ! 19MM! ! !r   rq   rr   rs   Tr7   r>   )rt   rq   rr   rs   r7   r>   rh   s     r   rN   zSearchResult.to_dict   s    !12< 	! !! ! !F9 : 	)"jF7O; 	+#{F8> 	'"&F;: 	)"jF7Or   )rO   rP   rQ   rR   r   rV   rq   r   rk   rS   rr   r*   rW   rs   r	   rT   rt   r7   rU   r>   r   rN   r   r   r   rp   rp      s           !&t!<!<!<GT+<<<uT222E49222"U4888FDcN888KItE8C=      r   rp   c                   X    e Zd ZU dZdZeed<   dZeed<   dZe	ed<   dZ
e	ed<   d	efd
ZdS )
LintResultzResult from linting a file.Tra   Fskippedr#   outputmessager    c                 J    | j         r
d| j        dS | j        rdnd| j        dS )Nr|   )statusr~   okr>   )r   r}   )r|   r~   ra   r}   rL   s    r   rN   zLintResult.to_dict   s?    < 	B'DLAAA"l7ddk
 
 	
r   N)rO   rP   rQ   rR   ra   rU   rS   r|   r}   r*   r~   rW   rN   r   r   r   r{   r{      sw         %%GTGTFCGS
 
 
 
 
 
 
r   r{   c                   0    e Zd ZU dZdZeed<   dZeed<   dS )ExecuteResultz&Result from executing a shell command.r#   stdoutr   	exit_codeN)	rO   rP   rQ   rR   r   r*   rS   r   rT   r   r   r   r   r      s8         00FCIsr   r   c                       e Zd ZdZeddedededefd            Zeded	ede	fd
            Z
e	 ddededededef
d            Zededefd            Ze	 	 	 ddedededee         dededededefd            ZdS )FileOperationsz@Abstract interface for file operations across terminal backends.     r   offsetlimitr    c                     dS )z$Read a file with pagination support.Nr   )rM   r   r   r   s       r   	read_filezFileOperations.read_file   	     	r   r4   c                     dS )z8Write content to a file, creating directories as needed.Nr   )rM   r   r4   s      r   
write_filezFileOperations.write_file   r   r   F
old_string
new_stringreplace_allc                     dS )z,Replace text in a file using fuzzy matching.Nr   )rM   r   r   r   r   s        r   patch_replacezFileOperations.patch_replace  s	     	r   patch_contentc                     dS )zApply a V4A format patch.Nr   )rM   r   s     r   	patch_v4azFileOperations.patch_v4a
  r   r   .N2   r   patterntarget	file_globoutput_modecontextc	                     dS )zSearch for content or files.Nr   )	rM   r   r   r   r   r   r   r   r   s	            r   searchzFileOperations.search  s	    
 	r   r   r   Fr   r4   Nr   r   r4   r   )rO   rP   rQ   rR   r   r*   rT   r3   r   rY   r   rU   r`   r   r   r   rp   r   r   r   r   r   r      s       JJ c 3 3     ^ s S [    ^ */ # 3 C #'4?   ^
 s {    ^ BKOP<= c  C "3-7:IL69BN   ^  r   r   >4   .a.o.7z.db.gz.so.xz.avi.bin.bz2.dll.doc.eot.exe.mkv.mov.mp3.mp4.ogg.otf.pdf.ppt.pyc.pyo.rar.svg.tar.tif.ttf.wav.xls.zip.docx.flac.pptx.tiff.wasm.webm.woff.xlsx.class.dylib.woff2.sqlite.sqlite3.bmp.gif.ico.jpg.png.jpeg.webp>   r   r   r   r   r   r   r   z python -m py_compile {file} 2>&1znode --check {file} 2>&1znpx tsc --noEmit {file} 2>&1zgo vet {file} 2>&1zrustfmt --check {file} 2>&1)z.pyz.jsz.tsz.goz.rsi  i   c                   l   e Zd ZdZd9defdZ	 	 d:dededededef
d	Zd
ede	fdZ
d9dedede	fdZdede	fdZd;dededefdZdedefdZdedefdZdedededefdZd<dedededefdZdZdedefd Zdedefd!Zdededefd"Z	 d=ded$ed%ed&e	def
d'Zd(edefd)Zdedefd*Z	 	 	 d>d.eded/ed0ee         deded1ed2edefd3Zd.ededededef
d4Z d.ededededef
d5Z!d.eded0ee         deded1ed2edefd6Z"d.eded0ee         deded1ed2edefd7Z#d.eded0ee         deded1ed2edefd8Z$dS )?ShellFileOperationsz
    File operations implemented via shell commands.
    
    Works with ANY terminal backend that has execute(command, cwd) method.
    This includes local, docker, singularity, ssh, modal, and daytona environments.
    Ncwdc                     || _         |p2t          |dd          p!t          t          |dd          dd          pd| _        i | _        dS )a<  
        Initialize file operations with a terminal environment.
        
        Args:
            terminal_env: Any object with execute(command, cwd) method.
                         Returns {"output": str, "returncode": int}
            cwd: Working directory (defaults to env's cwd or current directory)
        r   Nr   /)envgetattrr   _command_cache)rM   terminal_envr   s      r   __init__zShellFileOperations.__init__I  se      
  V',t<< V7<4@@%NNVRU 	 02r   commandtimeout
stdin_datar    c                     i }|r||d<   |||d<    | j         j        |fd|p| j        i|}t          |                    dd          |                    dd          	          S )
zExecute command via terminal backend.
        
        Args:
            stdin_data: If provided, piped to the process's stdin instead of
                        embedding in the command string. Bypasses ARG_MAX.
        r   Nr   r   r}   r#   
returncoder   )r   r   )r   executer   r   get)rM   r   r   r   r   kwargsri   s          r   _execzShellFileOperations._exec]  s      	( 'F9!#-F< !!'IIsdhI&II::h++jjq11
 
 
 	
r   cmdc                     || j         vr>|                     d| d          }|j                                        dk    | j         |<   | j         |         S )z6Check if a command exists in the environment (cached).zcommand -v z >/dev/null 2>&1 && echo 'yes'yes)r   r   r   strip)rM   r   ri   s      r   _has_commandz ShellFileOperations._has_commandq  s[    d)))ZZ Qc Q Q QRRF'-}':':'<'<'ED$"3''r   r   content_samplec                     t           j                            |          d                                         }|t          v rdS |rI|sdS t          d |dd         D                       }|t          t          |          d          z  dk    S dS )z
        Check if a file is likely binary.
        
        Uses extension check (fast) + content analysis (fallback).
        r   TFc              3   H   K   | ]}t          |          d k     |dvdV  dS )    z
	r   N)ord)r   cs     r   	<genexpr>z8ShellFileOperations._is_likely_binary.<locals>.<genexpr>  sJ        E  Ea"%a&&2++!82C2C !"2C2C2C2C E  Er   Ni  g333333?)r   r   splitextlowerBINARY_EXTENSIONSsumminlen)rM   r   r   extnon_printables        r   _is_likely_binaryz%ShellFileOperations._is_likely_binaryx  s     gt$$Q'--//###4  	I! u  E  E>%4%+@  E  E  E E EM 3s>':':D#A#AADHHur   c                     t           j                            |          d                                         }|t          v S )z2Check if file is an image we can return as base64.r   )r   r   r   r   IMAGE_EXTENSIONS)rM   r   r   s      r   	_is_imagezShellFileOperations._is_image  s4    gt$$Q'--//&&&r   r   r4   
start_linec                    |                     d          }g }t          ||          D ]J\  }}t          |          t          k    r|dt                   dz   }|                    |dd|            Kd                    |          S )z7Add line numbers to content in LINE_NUM|CONTENT format.
)startNz... [truncated]6d|)split	enumerater   MAX_LINE_LENGTHappendjoin)rM   r4   r  linesnumberedirw   s          r   _add_line_numbersz%ShellFileOperations._add_line_numbers  s    d## j999 	. 	.GAt4yy?**,_,-0AAOOq,,,d,,----yy"""r   c                    |s|S |                     d          r9|                     d          }|j        dk    r|j                                        r|j                                        }|dk    r|S |                     d          r||dd         z   S |dd         }|                    d          }|dk    r
|d|         n|}|rt          j        d|          rt|                     d	|           }|j        dk    rQ|j                                        r8|j                                        }|dt          |          z   d         }	||	z   S |S )
z
        Expand shell-style paths like ~ and ~user to absolute paths.
        
        This must be done BEFORE shell escaping, since ~ doesn't expand
        inside single quotes.
        ~z
echo $HOMEr   z~/r   Nr   z[a-zA-Z0-9._-]+zecho ~)	r-   r   r   r   r   findre	fullmatchr   )
rM   r   ri   homerest	slash_idxusernameexpand_result	user_homesuffixs
             r   _expand_pathz ShellFileOperations._expand_path  sr     	K ??3 	2ZZ--F1$$)<)<)>)>$}**,,3;;K__T** +$qrr(?* ABBx IIcNN	/8A~~4

++4 2-? J J 2 %)JJ/B/B/B$C$CM$.!338L8R8R8T8T3$1$8$>$>$@$@	!%a#h--&7&8&8!9(611r   argc                 :    d|                     dd          z   dz   S )z/Escape a string for safe use in shell commands.'z'"'"')replace)rM   r   s     r   _escape_shell_argz%ShellFileOperations._escape_shell_arg  s"     S[[i000366r   old_contentnew_contentfilenamec                     |                     d          }|                     d          }t          j        ||d| d|           }d                    |          S )z2Generate unified diff between old and new content.T)keependsza/zb/)fromfiletofiler#   )
splitlinesdifflibunified_diffr  )rM   r%  r&  r'  	old_lines	new_linesrb   s          r   _unified_diffz!ShellFileOperations._unified_diff  sn    **D*99	**D*99	#y$(__"??
 
 

 wwt}}r   r   r   r   c           	         |                      |          }t          |t                    }d|                     |           d}|                     |          }|j        dk    r|                     |          S 	 t          |j        	                                          }n# t          $ r d}Y nw xY w|t          k    r	 |                     |          rt          dd|d          S d|                     |           d}|                     |          }|                     ||j                  rt          d|d	          S ||z   d
z
  }	d| d|	 d|                     |           }
|                     |
          }|j        dk    rt          d|j                   S d|                     |           }|                     |          }	 t          |j        	                                          }n# t          $ r d}Y nw xY w||	k    }d}|rd|	d
z    d| d|	 d| d	}t          |                     |j        |          ||||          S )a  
        Read a file with pagination, binary detection, and line numbers.
        
        Args:
            path: File path (absolute or relative to cwd)
            offset: Line number to start from (1-indexed, default 1)
            limit: Maximum lines to return (default 500, max 2000)
        
        Returns:
            ReadResult with content, metadata, or error info
        wc -c <  2>/dev/nullr   TzImage file detected. Automatically redirected to vision_analyze tool. Use vision_analyze with this file path to inspect the image contents.r:   r9   r6   r8   zhead -c 1000 zUBinary file - cannot display as text. Use appropriate tools to handle this file type.)r9   r6   r>   r   zsed -n ',zp' Failed to read file: r>   zwc -l < NzUse offset=z to continue reading (showing -z of z lines))r4   r5   r6   r7   r8   )r  r   	MAX_LINESr$  r   r   _suggest_similar_filesrT   r   r   
ValueErrorMAX_FILE_SIZEr  r3   r   r  )rM   r   r   r   stat_cmdstat_resultr6   
sample_cmdsample_resultend_lineread_cmdread_resultwc_cmd	wc_resultr5   r7   r8   s                    r   r   zShellFileOperations.read_file  s      && E9%% Id44T::HHHjj** A%%..t444	K.446677II 	 	 	III	 }$$ >>$ 		#\    PT%;%;D%A%AOOO


:..!!$(<== 	#m    E>A%RfRRxRRD4J4J44P4PRRjj** A%%$PK<N$P$PQQQQ ;D22488::JJv&&		i.446677KK 	 	 	KKK	  (*	 	yxAxxVxxV^xxdoxxxD**;+=vFF#
 
 
 	
s$   :&B! !B0/B0&G5 5HHi   c                 x   d|                      |           d}|                     |          }	 t          |j                                                  }n# t
          $ r d}Y nw xY w|| j        k    rt          dd|d|dd          S d	|                      |           d}|                     |d
          }|j        dk    rt          dd|d|j                   S d}| 	                    d          rRd|                      |           d}|                     |          }	|	j        dk    r|	j                                        }t          j                            |          d                                         }
dddddddd}|                    |
d          }t          dd||j        ||          S )z-Read an image file, returning base64 content.r3  r4  r   TzImage is too large to inline (r6  zJ bytes). Use vision_analyze to inspect the image, or reference it by path.r5  zbase64 -w 0    r   zFailed to read image: )r:   r9   r6   r>   Nidentifyzidentify -format '%wx%h' r   z	image/pngz
image/jpegz	image/gifz
image/webpz	image/bmpzimage/x-icon)r   r   r   r   r   r   r   zapplication/octet-stream)r:   r9   r6   r;   r<   r=   )r$  r   rT   r   r   r<  MAX_IMAGE_BYTESr3   r   r   r   r   r   r   r   )rM   r   r>  r?  r6   b64_cmd
b64_resultr=   dim_cmd
dim_resultr   
mime_typesr<   s                r   _read_imagezShellFileOperations._read_image2  s3    Id44T::HHHjj**	K.446677II 	 	 	III	 t+++#XYK X X X    L!7!7!=!=KKKZZZ44
1$$#Bz/@BB	    
Z(( 	7\$2H2H2N2N\\\GG,,J#q(('.4466
 gt$$Q'--// !!"
 

 NN3(BCC	%,!
 
 
 	
s   &A A&%A&c                    t           j                            |          pd}t           j                            |          }d|                     |           d}|                     |          }g }|j        dk    r|j                                        r|j                                        	                    d          }|D ]}t          |                                          t          |                                          z  }	t          |	          t          |          dz  k    r3|                    t           j                            ||                     t          d| |dd	         
          S )z;Suggest similar files when the requested file is not found.r   zls -1 z 2>/dev/null | head -20r   r  g      ?zFile not found: N   )r>   rA   )r   r   dirnamebasenamer$  r   r   r   r   r
  setr   r   r  r  r3   )
rM   r   dir_pathr'  ls_cmd	ls_resultsimilarrr   fcommons
             r   r;  z*ShellFileOperations._suggest_similar_filesq  sQ    7??4((/C7##D)) T$00::SSSJJv&&	!##	(8(>(>(@(@#$**,,22488E > >X^^--..QWWYY?v;;#h--#"555NN27<<!#<#<===+T++!"1"+
 
 
 	
r   c                    |                      |          }t          |          rt          d| d          S t          j                            |          }d}|r:d|                     |           }|                     |          }|j        dk    rd}d|                     |           }|                     ||	          }|j        dk    rt          d
|j	                   S d|                     |           d}	|                     |	          }
	 t          |
j	                                                  }n2# t          $ r% t          |                    d                    }Y nw xY wt          ||          S )u  
        Write content to a file, creating parent directories as needed.

        Pipes content through stdin to avoid OS ARG_MAX limits on large
        files. The content never appears in the shell command string —
        only the file path does.

        Args:
            path: File path to write
            content: Content to write

        Returns:
            WriteResult with bytes written or error
        Write denied: '(' is a protected system/credential file.r8  Fz	mkdir -p r   Tzcat > )r   zFailed to write file: r3  r4  zutf-8)rZ   r[   )r  r1   rY   r   r   rT  r$  r   r   r   rT   r   r<  r   encode)rM   r   r4   parentr[   	mkdir_cmdmkdir_result	write_cmdwrite_resultr>  r?  rZ   s               r   r   zShellFileOperations.write_file  s       && D!! 	g%et%e%e%effff && 	$DD$:$:6$B$BDDI::i00L%**# <T33D99;;	zz)z@@!Q&&%Sl>Q%S%STTTT Id44T::HHHjj**	9 2 8 8 : :;;MM 	9 	9 	9w 7 788MMM	9 '%
 
 
 	
s   &D> >,E-,E-Fr   r   r   c                    |                      |          }t          |          rt          d| d          S d|                     |           d}|                     |          }|j        dk    rt          d|           S |j        }ddlm}  |||||          \  }	}
}|rt          |          S |
dk    rt          d	|           S | 	                    ||	          }|j
        rt          d
|j
                   S |                     ||	|          }|                     |          }t          d||g|r|                                nd          S )ai  
        Replace text in a file using fuzzy matching.

        Args:
            path: File path to modify
            old_string: Text to find (must be unique unless replace_all=True)
            new_string: Replacement text
            replace_all: If True, replace all occurrences

        Returns:
            PatchResult with diff and lint results
        r^  r_  r8  zcat r4  r   r7  )fuzzy_find_and_replacez'Could not find match for old_string in zFailed to write changes: TN)ra   rb   rc   rf   )r  r1   r`   r$  r   r   r   tools.fuzzy_matchrg  r   r>   r1  _check_lintrN   )rM   r   r   r   r   rC  rD  r4   rg  r&  match_countr>   re  rb   lint_results                  r   r   z!ShellFileOperations.patch_replace  s      && D!! 	g%et%e%e%effff E$0066DDDjj** A%%%CT%C%CDDDD$ 	=<<<<<*@*@Z[+
 +
'[%  	,U++++!%Ut%U%UVVVV t[99 	W%UAS%U%UVVVV !!';== &&t,, 6*5?$$&&&4	
 
 
 	
r   r   c                 t    ddl m}m}  ||          \  }}|rt          d|           S  |||           }|S )a  
        Apply a V4A format patch.
        
        V4A format:
            *** Begin Patch
            *** Update File: path/to/file.py
            @@ context hint @@
             context line
            -removed line
            +added line
            *** End Patch
        
        Args:
            patch_content: V4A format patch string
        
        Returns:
            PatchResult with changes made
        r   )parse_v4a_patchapply_v4a_operationszFailed to parse patch: r8  )tools.patch_parserrm  rn  r`   )rM   r   rm  rn  
operationsparse_errorri   s          r   r   zShellFileOperations.patch_v4a  sm    ( 	MLLLLLLL"1/-"@"@
K 	N%L{%L%LMMMM &%j$77r   c                 d   t           j                            |          d                                         }|t          vrt          dd| d          S t          |         }|                                d         }|                     |          st          d| d          S |                    | 	                    |                    }| 
                    |d	
          }t          |j        dk    |j                                        r|j                                        nd          S )z
        Run syntax check on a file after editing.
        
        Args:
            path: File path to lint
        
        Returns:
            LintResult with status and any errors
        r   TzNo linter for z files)r|   r~   r   z not available)filerH  rI  r#   )ra   r}   )r   r   r   r   LINTERSr{   r
  r   formatr$  r   r   r   r   )rM   r   r   
linter_cmdbase_cmdr   ri   s          r   ri  zShellFileOperations._check_lint#  s.    gt$$Q'--//gd4PS4P4P4PQQQQ S\
##%%a(  ** 	Qdx4O4O4OPPPP T%;%;D%A%ABBC,,$),2M,?,?,A,AI6=&&(((r
 
 
 	
r   r   r   r   r   r   r   r   r   c	           	      2   |                      |          }|                     d|                     |           d          }	d|	j        v rt	          d| dd          S |dk    r|                     ||||          S |                     |||||||          S )	a\  
        Search for content or files.
        
        Args:
            pattern: Regex (for content) or glob pattern (for files)
            path: Directory/file to search (default: cwd)
            target: "content" (grep) or "files" (glob)
            file_glob: File pattern filter for content search (e.g., "*.py")
            limit: Max results (default 50)
            offset: Skip first N results
            output_mode: "content", "files_only", or "count"
            context: Lines of context around matches
        
        Returns:
            SearchResult with matches or file list
        ztest -e z! && echo exists || echo not_found	not_foundzPath not found: z3. Verify the path exists (use 'terminal' to check).r   r>   rt   rr   )r  r   r$  r   rp   _search_files_search_content)
rM   r   r   r   r   r   r   r   r   checks
             r   r   zShellFileOperations.searchG  s    (   && 

ed&<&<T&B&Beeeff%,&&bbbb   
 W%%gtUFCCC''y%(3W> > >r   c                 H   |                     d          sd|vr|}n|                    d          d         }|                     d          r|                     ||||          S |                     d          st	          d          S d}d	|                     |           d
| d|                     |           d|dz    d| 
}|                     |d          }|j                                        sTd	|                     |           d
| d|                     |           d||z    d|dz    
}	|                     |	d          }g }
|j                                                            d          D ]}|s|                    d
d          }t          |          dk    rJ|d         
                    dd                                          r|
                    |d                    x|
                    |           t	          |
t          |
                    S )z-Search for files by name pattern (glob-like).z**/r   rgr  zFile search requires 'rg' (ripgrep) or 'find'. Install ripgrep for best results: https://github.com/BurntSushi/ripgrep#installationr8  z-not -path '*/.*'zfind  z -type f -name z7 -printf '%T@ %p\\n' 2>/dev/null | sort -rn | tail -n +r   z | head -n <   rI   2>/dev/null | head -n z | tail -n +r     r   r   r#   rr   rt   )r-   r
  r   _search_files_rgrp   r$  r   r   r   r   r#  isdigitr  )rM   r   r   r   r   search_patternhidden_excluder   ri   
cmd_simplerr   rw   partss                r   r{  z!ShellFileOperations._search_filesk  s    !!%(( 	4S-?-?$NN$]]3//3N
 T"" 	N((ufMMM   (( 	K    -hd,,T22 h h^ h hTXTjTjkyTzTz h hIORSh h`eh h C,,}""$$ 	8Z!7!7!=!= Z Z Z Z_c_u_u  wE  `F  `F Z Z16Z ZMSVWZZ ZJZZ
BZ77FM''))//55 	# 	#D JJsA&&E5zzQ58#3#3C#<#<#D#D#F#FU1X&&&&T""""E


 
 
 	
r   c                    d|vr|                     d          sd| }n|}||z   }d|                     |           d|                     |           d| }|                     |d          }d |j                                                            d	          D             }	|	|||z            }
t          |
t          |	          t          |	          |k    
          S )zSearch for files by name using ripgrep's --files mode.

        rg --files respects .gitignore and excludes hidden directories by
        default, and uses parallel directory traversal for ~200x speedup
        over find on wide trees.
        r   *zrg --files -g r  r  r  rI  c                     g | ]}||S r   r   r   r[  s     r   r   z8ShellFileOperations._search_files_rg.<locals>.<listcomp>  s    GGG1QGQGGGr   r  )rr   rt   r7   )r-   r$  r   r   r   r
  rp   r   )rM   r   r   r   r   glob_patternfetch_limitr   ri   	all_filespages              r   r  z$ShellFileOperations._search_files_rg  s    gg&8&8&=&=(w==LL"Lfn'T33LAA ' '%%d++' '$' ' 	
 C,,GG 3 3 5 5 ; ;D A AGGG	./I)nn3
 
 
 	
r   c           	          |                      d          r|                     |||||||          S |                      d          r|                     |||||||          S t          d          S )z,Search for content inside files (grep-like).r  grepzqContent search requires ripgrep (rg) or grep. Install ripgrep: https://github.com/BurntSushi/ripgrep#installationr8  )r   _search_with_rg_search_with_greprp   )rM   r   r   r   r   r   r   r   s           r   r|  z#ShellFileOperations._search_content  s     T"" 	''y%(3W> > >v&& 	))'4E6*5w@ @ @  \   r   c                 	   g d}|dk    r$|                     dt          |          g           |r*|                     d|                     |          g           |dk    r|                    d           n|dk    r|                    d           |                    |                     |                     |                    |                     |                     |dk    r||z   d	z   n||z   }	|                     d
ddt          |	          g           d                    |          }
|                     |
d          }|j        dk    r_|j                                        sFt          |d          r |j
        r|j
                                        nd}t          d| d          S |dk    rcd |j                                                            d          D             }t          |          }||||z            }t          ||          S |dk    ri }|j                                                            d          D ]_}d|v rY|                    dd          }t          |          dk    r0	 t          |d                   ||d         <   O# t           $ r Y [w xY w`t          |t#          |                                                    S t'          j        d          }t'          j        d          }g }|j                                                            d          D ]W}|r|dk    r|                    |          }|r|                    t-          |                    d          pd|                    d          z   t          |                    d                    |                    d           d!d"         #                     |dk    r|                    |          }|r|                    t-          |                    d          pd|                    d          z   t          |                    d                    |                    d           d!d"         #                     Yt          |          }||||z            }t          |||||z   k    $          S )%zSearch using ripgrep.)r  z--line-numberz--no-headingz--with-filenamer   -Cz--glob
files_only-lcount-c   r	  head-nr  r  rI  r  stderrSearch errorSearch failed: rz  c                     g | ]}||S r   r   r  s     r   r   z7ShellFileOperations._search_with_rg.<locals>.<listcomp>      KKKqKKKKr   r  r  :r   rs   rt   ^([A-Za-z]:)?(.*?):(\d+):(.*)$^([A-Za-z]:)?(.*?)-(\d+)-(.*)$--r#         Nr   rx   rq   rt   r7   )extendr*   r$  r  r  r   r   r   r   hasattrr  rp   r
  r   rsplitrT   r<  r   valuesr  compilematchrk   grouprM   r   r   r   r   r   r   r   	cmd_partsr  r   ri   	error_msgr  totalr  rs   rw   r  	_match_re_ctx_rerq   ry   s                          r   r  z#ShellFileOperations._search_with_rg  s    ONN	 Q;;dCLL1222  	Lh(>(>y(I(IJKKK ,&&T""""G##T""" 	//88999//55666
 /6kkefns**uv~#vtS-=-=>???hhy!!C,, q  )<)<)>)> 181J1Jpv}p++---bpI&C	&C&CQRSSSS ,&&KKFM$7$7$9$9$?$?$E$EKKKI	NNEVFUN23Dd>>>>G##F++--33D99 ! !$;; KKQ//E5zzQ!/258}}F58,,) ! ! ! D!v3v}};O;OPPPP 
#DEEIj!BCCGG++--33D99   tt|| OOD)) NN;ggajj.B!''!**<$'

OO !

4C4 0$ $ $   
  Q;;d++A {"#''!**"2aggajj!@(+AGGAJJ$%GGAJJtt$4( ( (    LLE6&5.01D!&5.0   s   >J
J*)J*c                 	   ddg}|                     d           |dk    r$|                    dt          |          g           |r*|                    d|                     |          g           |dk    r|                     d           n|d	k    r|                     d
           |                     |                     |                     |                     |                     |                     ||z   |dk    rdndz   }	|                    dddt          |	          g           d                    |          }
|                     |
d          }|j        dk    r_|j                                        sFt          |d          r |j
        r|j
                                        nd}t          d| d          S |dk    rcd |j                                                            d          D             }t          |          }||||z            }t          ||          S |d	k    ri }|j                                                            d          D ]_}d|v rY|                    dd          }t          |          dk    r0	 t          |d                   ||d         <   O# t           $ r Y [w xY w`t          |t#          |                                                    S t'          j        d          }t'          j        d          }g }|j                                                            d          D ]W}|r|dk    r|                    |          }|r|                     t-          |                    d          pd |                    d          z   t          |                    d!                    |                    d"          d#d$         %                     |dk    r|                    |          }|r|                     t-          |                    d          pd |                    d          z   t          |                    d!                    |                    d"          d#d$         %                     Yt          |          }||||z            }t          |||||z   k    &          S )'zFallback search using grep.r  z-rnHz--exclude-dir='.*'r   r  z	--includer  r  r  r  r  r	  r  r  r  r  rI  r  r  r  r  rz  c                     g | ]}||S r   r   r  s     r   r   z9ShellFileOperations._search_with_grep.<locals>.<listcomp>Y  r  r   r  r  r  r   r  r  r  r  r#   r  r  Nr   rx   r  )r  r  r*   r$  r  r   r   r   r   r  r  rp   r
  r   r  rT   r<  r   r  r  r  r  rk   r  r  s                          r   r  z%ShellFileOperations._search_with_grep1  s    V$	 	-... Q;;dCLL1222  	Ok4+A+A)+L+LMNNN ,&&T""""G##T""" 	//88999//55666 fnw{{B#vtS-=-=>???hhy!!C,, q  )<)<)>)> 181J1Jpv}p++---bpI&C	&C&CQRSSSS,&&KKFM$7$7$9$9$?$?$E$EKKKI	NNEVFUN23Dd>>>>G##F++--33D99 ! !$;; KKQ//E5zzQ!/258}}F58,,) ! ! ! D!v3v}};O;OPPPP 
#DEEIj!BCCGG++--33D99   tt||OOD)) NN;ggajj.B!''!**<$'

OO !

4C4 0$ $ $   
 Q;;d++A {"#''!**"2aggajj!@(+AGGAJJ$%GGAJJtt$4( ( (    LLE6&5.01D!&5.0   s   J//
J<;J<rD   )NNN)r   r   r   r   )%rO   rP   rQ   rR   r*   r   rT   r   r   rU   r   r   r  r  r  r$  r1  r3   r   rK  rQ  r;  rY   r   r`   r   r   r{   ri  r   rp   r   r{  r  r|  r  r  r   r   r   r   r   A  s        2 2# 2 2 2 2( CG $
 
S 
s 
C 

)6
 
 
 
(( ( ( ( ( ( c 3 $    ('c 'd ' ' ' '
	# 	# 	## 	#c 	# 	# 	# 	## # # # # #J7S 7S 7 7 7 7
	 	3 	# 	RU 	 	 	 	W
 W
c W
3 W
3 W
 W
 W
 W
 W
v !O=
 =

 =
 =
 =
 =
~
3 
: 
 
 
 
:4
s 4
S 4
[ 4
 4
 4
 4
v +0;
 ;
# ;
3 ;
C ;
#';
4?;
 ;
 ;
 ;
zs {    <
 

 
 
 
 
H CLOP<="> ">c "> ">C ">"3-">7:">IL">">69">BN"> "> "> ">H1
S 1
 1
C 1
 1
Q] 1
 1
 1
 1
f
 
3 
s 
C 
T` 
 
 
 
>s # (3- ",/>ALOT`   "as a# a(3- a"a,/a>AaLOaT`a a a aF_ _C _HSM _!$_.1_@C_NQ_Vb_ _ _ _ _ _r   r   ),rR   r   r  r-  abcr   r   dataclassesr   r   typingr   r   r	   r
   pathlibr   hermes_constantsr   r*   r  _HOMEr   r  r+   r,   r(   rU   r1   r3   rY   r`   rk   rp   r{   r   r   r   r  rt  r:  r  r=  r   r   r   r   <module>r     s$   4 
			 				  # # # # # # # # ( ( ( ( ( ( ( ( , , , , , , , , , , , ,       , , , , , , 	IDIKK 
UF$566
UFH--
UFL11
UFH--OO&''
UI&&
UH%%
UJ''
UO,,
UK((
UH%%
UI&&
UH%%
UI&&#"   , 
UF##
UF##
UH%%
UG$$
UI&&
UH%%
UIt,,
+   hsm    "3 4    0 U U U U U U U U& I I I I I I I I        6                6 
 
 
 
 
 
 
 
             S   J   ( NMM  .%)(  	O O O O O. O O O O Or   