Ë
    ãß²jS9 ã                   ó®  — U 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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 ddlmZ ddlmZ ddlmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% dd	l&m'Z'm(Z(m)Z) dd
l*m+Z+  e	jX                  e-«      Z. e/ ej`                  «       «      Z1dZ2e3e4d<   de5de/fd„Z6dee5   de7de/fd„Z8 G d„ de«      Z9h d£Z:dZ;dZ<dZ=dZ>de/de/fd„Z?de/de/de@e/   fd„ZA G d„ de(e+e9«      ZBdd lmCZC dd!lmDZD dd"lmEZE dd#lmFZF dd$lmGZG dd%lHmIZI dd&lHmJZJ ddlKZKddlLZLd'ZMd'ZN eFe1«      ZO eGe1«      ZPd(d)d*d+d,d-d.d/d0d1d2d3d4œZQd5„ ZRy)6a�  File operations (read, write, patch, search) over any terminal backend.

Every operation is a shell command run through the backend's ``execute()``, so one
implementation serves every environment (local, docker, ssh, modal, ...). Companions:
``file_operations_common`` (result dataclasses, text helpers), ``file_operations_lint``
(LintMixin), ``file_operations_search`` (SearchMixin).
é    N)ÚABCÚabstractmethod)ÚOptionalÚDict)ÚPath)Úhas_binary_extension)Úget_write_denied_error)ÚExecuteResultÚPatchResultÚ
ReadResultÚSearchResultÚWriteResultÚ	_UTF8_BOMÚ_detect_line_endingÚ_has_bomÚ_normalize_line_endingsÚ
_strip_bomÚ_strip_terminal_fence_leaksÚnormalize_read_paginationÚnormalize_search_pagination)ÚLINTERS_INPROCÚ	LintMixinÚ_FAIL_CLOSED_INPROC_EXTS)ÚSearchMixin))s   ‰PNG

zPNG image data)s   ÿØÿzJPEG image data)s   GIF87aúGIF image data)s   GIF89ar   )s   RIFFz$RIFF container (WAV/AVI/WebP family))s   %PDF-zPDF document)s   PKz$ZIP archive (also docx/xlsx/jar/apk))s   PKzZIP archive (empty))s   ‹zgzip compressed data)s   BZhzbzip2 compressed data)s   ý7zXZ zxz compressed data)s   7z¼¯'z7-Zip archive)s   ELFzELF executable)s   MZzWindows PE executable)s   ÏúíþzMach-O executable (64-bit))s   Êþº¾z$Mach-O universal binary / Java class)s   SQLite format 3 zSQLite database)s   OggSzOgg container)s   fLaCz
FLAC audio)s   ID3zMP3 audio (ID3 tag))s      z$ISO media container (MP4/MOV family))s   BMzBMP image data)s   II* zTIFF image data (little-endian))s   MM *zTIFF image data (big-endian)Ú_MAGIC_SIGNATURESÚsampleÚreturnc                 ó~   — t         D ]4  \  }}| j                  |«      sŒ|j                  d«      r	| dd dk7  rŒ2|c S  y)zÉBest-effort human name for binary content from its magic bytes; never raises.
    The ISO-media entry additionally requires ``ftyp`` at offset 4 (three leading
    NULs alone are too weak a signature).z	ISO mediaé   é   s   ftypzunknown binary)r   Ú
startswith)r   ÚprefixÚnames      ú:/home/ubuntu/.hermes/hermes-agent/tools/file_operations.pyÚidentify_binary_bytesr&   G   sK   € ô *ò ‰ˆ�Ø×Ñ˜VÕ$Ø�‰˜{Ô+°°q¸°¸wÒ0FØØŠKð	ð
 ó    Ú	file_sizec                 óx   — t        | xs d«      }|dk\  r
|dz  d›d�}n|dk\  r
|dz  d›d�}n|› d�}d|› d	|› d
�S )z¡One-line binary-file refusal naming the TYPE ("PNG image data, 4.1 KB"), so the
    model gets what-is-this in one read instead of hunting for tools it may lack.r'   é   z.1fz MBi   z KBz byteszBinary file (ú, u   ) â€” cannot display as text.)r&   )r   r(   ÚkindÚsizes       r%   Údescribe_binary_filer.   S   sl   € ô ! ¢¨3Ó/€DØ�KÒØ˜{Ñ+¨CÐ0°Ð4‰Ø	�dÒ	Ø˜dÑ" 3Ð' sÐ+‰à�˜FÐ#ˆØ˜4˜&  4 &Ð(EÐFÐFr'   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fd„«       Z	edded	ed
e
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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
e   dedededededefd„«       Zy)!ÚFileOperationsz@Abstract interface for file operations across terminal backends.ÚpathÚoffsetÚlimitr   c                  ó   — y)z$Read a file with pagination support.N© )Úselfr1   r2   r3   s       r%   Ú	read_filezFileOperations.read_filec   ó   � r'   c                  ó   — y)zFWhole file as a plain string: no pagination, line numbers or clamping.Nr5   ©r6   r1   s     r%   Úread_file_rawzFileOperations.read_file_rawg   r8   r'   NÚcontentÚpre_contentc                  ó   — y)z8Write content to a file, creating directories as needed.Nr5   )r6   r1   r<   r=   s       r%   Ú
write_filezFileOperations.write_filek   r8   r'   Ú
old_stringÚ
new_stringÚreplace_allc                  ó   — y)z,Replace text in a file using fuzzy matching.Nr5   )r6   r1   r@   rA   rB   s        r%   Úpatch_replacezFileOperations.patch_replaceo   r8   r'   Úpatch_contentc                  ó   — y)zApply a V4A format patch.Nr5   )r6   rE   s     r%   Ú	patch_v4azFileOperations.patch_v4at   r8   r'   c                  ó   — y)z>Delete a file. Returns WriteResult with .error set on failure.Nr5   r:   s     r%   Údelete_filezFileOperations.delete_filex   r8   r'   ÚsrcÚdstc                  ó   — y)zCMove/rename a file. Returns WriteResult with .error set on failure.Nr5   )r6   rJ   rK   s      r%   Ú	move_filezFileOperations.move_file|   r8   r'   ÚpatternÚtargetÚ	file_globÚoutput_modeÚcontextÚorderc
                  ó   — y)zSearch for content or files.Nr5   )
r6   rN   r1   rO   rP   r3   r2   rQ   rR   rS   s
             r%   ÚsearchzFileOperations.search€   r8   r'   ©é   éÐ  ©N©F©ú.r<   Né2   r   r<   r   Ú	discovery)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   ÚstrÚintr   r7   r;   r   r   r?   Úboolr   rD   rG   rI   rM   r   rU   r5   r'   r%   r0   r0   `   s»  „ ÙJàñ3˜cð 3¨3ð 3¸3ð 3È*ò 3ó ð3ð ðU #ð U¨*ò Uó ðUð ñG˜sð G¨Sð G¸xÈ¹}ð GÐXcò Gó ðGð à*/ñ; #ð ;°3ð ;ÀCð ;Ø#'ð;Ø4?ò;ó ð;ð ð( sð (¨{ò (ó ð(ð ðM ð M¨ò Mó ðMð ðR˜Sð R sð R¨{ò Ró ðRð ØBKØOPØ<=Ø'ñ+˜cð +¨ð +¸Cð +Ø" 3™-ð+Ø7:ð+ØILð+àð+à69ð+ð ð+ð -9ò+ó ñ+r'   r0   >   ú.bmpú.gifú.icoú.jpgú.pngú.jpegú.webpÚ__hermes_not_regular__Ú__hermes_missing__Ú__HERMES_RF_Ú__HERMES_WF_r#   c                 ó6   — | › t        j                  d«      › d�S )a  Per-call separator line for a compound shell probe. 128 random bits make a
    collision with file content negligible; the underscores keep the token outside
    the base64 alphabet, so a sentinel leaking into a sample segment fails base64
    validation instead of decoding into bytes.é   Ú__)ÚsecretsÚ	token_hex)r#   s    r%   Ú_new_sentinelrv   š   s!   € ð
 ˆX”g×'Ñ'¨Ó+Ð,¨BÐ/Ð/r'   ÚoutputÚsentinelc                 ó*   — | j                  |dz   «      S )a	  Split compound-probe stdout on its sentinel lines. Every producer (``wc``,
    ``base64``, ``cut``) newline-terminates or prints nothing, so the separator is
    always ``sentinel + "
"`` on its own line; the text after the final sentinel
    is the status segment.Ú
©Úsplit)rw   rx   s     r%   Ú_split_segmentsr}   ¢   s   € ð
 �<‰<˜ 4™Ó(Ð(r'   c                   ór  — e Zd ZdZdmdefd„Z	 	 dnd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ededefd„Zdedefd„Zdodedefd„Zededee   fd„«       Zedede	fd„«       Zdmdedede	fd„Zdede	fd„Zdpd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fd!„Zdededd"fd#„Zdmded$ee   de	fd%„Zd&ed'ed(edefd)„Zededefd*„«       Zdedeeef   fd+„Z dqded,edefd-„Z!dedee	ee   f   fd.„Z"d/Z#d0Z$ded1ed2ed3edd4f
d5„Z%drded1ed2edefd6„Z&de	fd7„Z'ded1ed2edefd8„Z(ed3edefd9„«       Z)ded1ed:ed;ed<edefd=„Z*ded1ed2edefd>„Z+ded1ed2ed3ed?ee   defd@„Z,ded1ed2edefdA„Z-dBed1ed:edCed3edDee	   defdE„Z.dFZ/dedee   fdG„Z0dedefdH„Z1dedefdI„Z2dmdedJee   defdK„Z3dede4fdL„Z5dMedNede4fdO„Z6 e7jp                  dP«      Z9dededee4   fdQ„Z:ededRededee4   fdS„«       Z;ded<edTee   defdU„Z<ded$ee   dVe	dee	ee   ee   f   fdW„Z=ded$ee   dVe	dee	ee   ee   f   fdX„Z>dedYedeee	   ee4   f   fdZ„Z?dmdeded$ee   de4fd[„Z@deded\ed]ed^ed_ee   deAfd`„ZBded'edeeA   fda„ZC	 dsded\ed]edbe	deAf
dc„ZDddedeAfde„ZE	 	 	 	 dtdfededgedhee   d2ed1ediedjedkedeFfdl„ZGy)uÚShellFileOperationsaÍ  File operations over any terminal backend exposing ``execute(command, cwd)``
    returning ``{"output": str, "returncode": int}``.

    cwd rule: every ``_exec`` prefers the LIVE ``env.cwd`` so a ``cd`` run via the
    terminal tool is picked up immediately; the init-time ``self.cwd`` is only a
    fallback for envs that don't track cwd (using it for every call once made
    patches "succeed" with a plausible diff while landing in the wrong directory).
    NÚcwdc                 ó¤   — || _         |xs+ t        |dd «      xs t        t        |dd «      dd «      xs d| _        i | _        i | _        i | _        y )Nr€   Úconfigú/)ÚenvÚgetattrr€   Ú_command_cacheÚ_rg_resolution_cacheÚ_rg_modified_capability)r6   Úterminal_envr€   s      r%   Ú__init__zShellFileOperations.__init__´   sb   € ØˆŒàò Vœ' ,°°tÓ<ò VÜœ7 <°¸4Ó@À%ÈÓNòVØRUð 	Œð
 02ˆÔØ46ˆÔ!ØACˆÕ$r'   ÚcommandÚtimeoutÚ
stdin_datar   c                 óè  — i }|r||d<   |�||d<   |xs% t        | j                  dd«      xs | j                  } | j                  j                  |fd|i|¤Ž}|j	                  dd«      }|j	                  dd«      }	d}
|d	k(  rJd
|	v rFddlm} t        | j                  dd«      }|r
 ||«      rdnd}d|›d|› d|	j                  «       › �x}
}	|j	                  d«      r|dk(  rd}t        |	||
¬«      S )u–   Run ``command`` on the backend. cwd: explicit arg â†’ live ``env.cwd`` â†’
        init-time ``self.cwd``. ``stdin_data`` is piped (bypasses ARG_MAX).rŒ   Nr�   r€   Ú
returncoder   rw   Ú é~   zcd: )Ú_is_container_backendÚenv_typezI; for container backends use a path inside the container, e.g. /workspacezworking directory zU does not exist on the active terminal backend (check terminal.cwd or the session cwdz). Ústdin_errorrW   )ÚstdoutÚ	exit_codeÚ	cwd_error)	r…   r„   r€   ÚexecuteÚgetÚtools.terminal_tool_configr’   Ústripr
   )r6   r‹   r€   rŒ   r�   ÚkwargsÚeffective_cwdÚresultr–   rw   r—   r’   r“   Úhints                 r%   Ú_execzShellFileOperations._execÀ   s$  € ð ˆÙØ 'ˆF�9ÑØÐ!Ø#-ˆF�<Ñ ØÒIœw t§x¡x°¸Ó=ÒIÀÇÁˆØ!�—‘×!Ñ! 'ÑG¨}ÐGÀÑGˆØ—J‘J˜|¨QÓ/ˆ	Ø—‘˜H bÓ)ˆð
 ˆ	Ø˜Ò ¨&Ñ 0ÝHÜ˜tŸx™x¨°TÓ:ˆHáÑ$9¸(Ô$Cñ `ØIKð ð % ]Ð$5ð 6AØAEÀÀcÈ&Ï,É,Ë.ÐIYð[ð\ˆI˜ð
 �:‰:�mÔ$¨°aªØˆIÜ F°iÈ9ÔUÐUr'   Úcmdc                 ó  — |dk(  r| j                  |«      duS || j                  vrL| j                  d|› d�«      }|j                  ry|j                  j                  «       dk(  | j                  |<   | j                  |   S )z…Check if a command exists in the environment (cached); rg goes through
        the resolver so a mid-session install becomes visible.ÚrgNzcommand -v z >/dev/null 2>&1 && echo 'yes'FÚyes)Ú_resolve_commandr†   r    r—   r•   r›   )r6   r¡   rž   s      r%   Ú_has_commandz ShellFileOperations._has_commandà   s†   € ð �$Š;Ø×(Ñ(¨Ó-°TÐ9Ð9Ø�d×)Ñ)Ñ)Ø—Z‘Z +¨c¨UÐ2PÐ QÓRˆFØ×ÒØØ'-§}¡}×':Ñ':Ó'<ÀÑ'EˆD×Ñ Ñ$Ø×"Ñ" 3Ñ'Ð'r'   r1   c                 óJ   — | j                  d| j                  |«      › d�«      S )uG   ``cat`` the file with stderr silenced (missing file â†’ non-zero exit).úcat ú 2>/dev/null©r    Ú_escape_shell_argr:   s     r%   Ú_catzShellFileOperations._catì   s&   € à�z‰z˜D ×!7Ñ!7¸Ó!=Ð >¸lÐKÓLÐLr'   Únbytesc                 óP   — | j                  d|› d| j                  |«      › d�«      S )Núhead -c Ú r©   rª   )r6   r1   r­   s      r%   Ú_headzShellFileOperations._headð   s,   € Ø�z‰z˜H V H¨A¨d×.DÑ.DÀTÓ.JÐ-KÈ<ÐXÓYÐYr'   Úsnippetc                 óÔ   — | j                  d| j                  |«      › �«      }|j                  dk7  r5d|j                  xs dv r#| j                  d| j                  |«      › �«      }|S )z…Run ``snippet`` via the backend's ``python3``, retrying with ``python``
        when only that name exists (Windows / older systems).zpython3 -c r   Úpython3r�   z
python -c )r    r«   r–   r•   )r6   r²   rž   s      r%   Ú_run_python_snippetz'ShellFileOperations._run_python_snippetó   si   € ð —‘˜k¨$×*@Ñ*@ÀÓ*IÐ)JÐKÓLˆØ×Ñ˜qÒ  Y°6·=±=Ò3FÀBÑ%GØ—Z‘Z *¨T×-CÑ-CÀGÓ-LÐ,MÐ NÓOˆFØˆr'   Úlengthc                 ó¦   — | j                  d|› d| j                  |«      › d�«      }|j                  dk7  ry| j                  |j                  «      S )a>  First ``length`` raw bytes, base64-wrapped so they survive the terminal
        transport (which decodes stdout with ``errors="replace"`` and manufactures
        U+FFFD for every undecodable byte, including a multibyte char cut in half
        by ``head -c``). None when no clean base64 came back (no ``base64`` binary);
        callers then fall back to the text heuristic.

        Wrapping the sample in base64 lets the original bytes survive the transport, so binary detection can
        happen at the byte layer where it is well-defined (#80308 and friends).
        r¯   r°   z 2>/dev/null | base64r   N)r    r«   r–   Ú_decode_base64_sampler•   )r6   r1   r¶   rž   s       r%   Ú_sample_file_bytesz&ShellFileOperations._sample_file_bytesû   sT   € ð —‘˜h v h¨a°×0FÑ0FÀtÓ0LÐ/MÐMbÐcÓdˆØ×Ñ˜qÒ ØØ×)Ñ)¨&¯-©-Ó8Ð8r'   Útextc                 óô   — dj                  t        | «      j                  «       «      }|syt        j                  d|«      sy	 t        j                  |d¬«      S # t        j                  t        f$ r Y yw xY w)uì   Decode one ``head -c N | base64`` sample. Whitespace-joins the whole text
        first (``base64`` wraps at 76 columns), so callers hand over exactly one
        segment; anything else fails validation â†’ None (legacy text heuristic).r�   r'   z[A-Za-z0-9+/]+={0,2}NT©Úvalidate)
Újoinr   r|   ÚreÚ	fullmatchÚbase64Ú	b64decodeÚbinasciiÚErrorÚ
ValueError)rº   Úencodeds     r%   r¸   z)ShellFileOperations._decode_base64_sample
  sl   € ð
 —'‘'Ô5°dÓ;×AÑAÓCÓDˆÙØÜ�|‰|Ð3°WÔ=Øð	Ü×#Ñ# G°dÔ;Ð;øÜ—‘¤
Ð+ò 	Ùð	ús   ÁA ÁA7Á6A7r   c                 ó   — | syd| v ry	 | j                  d«       y# t        $ rX}|j                  t        | «      dz
  k\  r3	 | d|j                   j                  d«       Y d}~y# t        $ r Y nw xY wY d}~yd}~ww xY w)u   Byte-layer binary detection: text iff valid UTF-8, allowing one incomplete
        multibyte sequence at the very end (artifact of the byte-boundary cut).
        NUL bytes or mid-stream invalid UTF-8 stay read-only so a readâ†’editâ†’write
        round-trip never rewrites undecodable bytes as U+FFFD; a file that
        legitimately CONTAINS U+FFFD is valid UTF-8 and reads as text.

        See #80308.
        Fó    Túutf-8é   N)ÚdecodeÚUnicodeDecodeErrorÚstartÚlen)r   Úexcs     r%   Ú_is_likely_binary_bytesz+ShellFileOperations._is_likely_binary_bytes  s…   € ñ ØØ�fÑØð	Ø�M‰M˜'Ô"ØøÜ!ò 		ð �y‰yœC ›K¨!™OÒ+ðØ˜;˜SŸY™YÐ'×.Ñ.¨wÔ7Ü øÜ)ò Ùðúäûð		ús2   Š œ	A=¥A8ÁA$Á$	A0Á-A8Á/A0Á0A8Á8A=Úcontent_samplec                 ó�   — t        |«      ry|r8d|dd v ryt        d„ |dd D «       «      }|t        t        |«      d«      z  dkD  S y)zILegacy text-layer binary check: extension, else >30% non-printable chars.Tu   ï¿½Néè  c              3   óH   K  — | ]  }t        |«      d k  sŒ|dvsŒd–— Œ y­w)é    z
	rW   N)Úord)Ú.0Úcs     r%   ú	<genexpr>z8ShellFileOperations._is_likely_binary.<locals>.<genexpr>>  s#   è ø€ Òf aÄCÈÃFÈRÃKÐTUÐ]eÒTe¤Ñfùs   ‚"–"›"g333333Ó?F)r   ÚsumÚminrÎ   )r6   r1   rÑ   Únon_printables       r%   Ú_is_likely_binaryz%ShellFileOperations._is_likely_binary5  sZ   € ä Ô%ØÙð ˜>¨%¨4Ð0Ñ0ØÜÑf¨>¸%¸4Ð+@ÔfÓfˆMØ ¤3¤s¨>Ó':¸DÓ#AÑAÀDÑHÐHØr'   c                 ón   — t         j                  j                  |«      d   j                  «       t        v S )NrW   )Úosr1   ÚsplitextÚlowerÚIMAGE_EXTENSIONSr:   s     r%   Ú	_is_imagezShellFileOperations._is_imageB  s+   € Ü�w‰w×Ñ Ó% aÑ(×.Ñ.Ó0Ô4DÐDÐDr'   r<   Ú
start_linec                 ó²   ‡— ddl m}  |«       Š|j                  d«      r|dd }dj                  ˆfd„t	        |j                  d«      |¬«      D «       «      S )zÝPrefix each line with a compact ``<n>|`` gutter, clamping long lines. Not
        fixed-width: padding cost ~16% more tokens per line for no accuracy gain in
        A/B, while dropping numbers regressed line-referencing.r   ©Úget_max_line_lengthrz   Néÿÿÿÿc              3   ó^   •K  — | ]$  \  }}|› d t        |«      ‰k  r|n|d‰ dz   › �–— Œ& y­w)Ú|Nz... [truncated]©rÎ   )r×   ÚiÚlineÚmax_line_lengths      €r%   rÙ   z8ShellFileOperations._add_line_numbers.<locals>.<genexpr>R  sF   øè ø€ ò Má��4ð ˆc�œ3˜t›9¨Ò7‘4¸TÐBRÀ?Ð=SÐVgÑ=gÐhÔiñMùs   ƒ*-)rÍ   )Útools.tool_output_limitsrç   Úendswithr¾   Ú	enumerater|   )r6   r<   rä   rç   rî   s       @r%   Ú_add_line_numbersz%ShellFileOperations._add_line_numbersE  s^   ø€ õ 	AÙ-Ó/ˆð ×Ñ˜DÔ!Ø˜c˜r�lˆGØ�y‰yó Mä$ W§]¡]°4Ó%8À
ÔKôMó Mð 	Mr'   c                 ó^  — |r|j                  d«      s|S | j                  d«      }|j                  dk(  r÷|j                  j	                  «       rÝ|j                  j	                  «       }|dk(  r|S |j                  d«      r||dd z   S |dd }|j                  d«      }|dk\  r|d| n|}|rt        j                  d|«      ri| j                  d	|› �«      }|j                  dk(  rF|j                  j	                  «       r,|j                  j	                  «       |dt        |«      z   d z   S |S )
u“   Expand ``~`` / ``~user`` via the backend's shell (its HOME, not the
        host's). Must run BEFORE shell escaping â€” ~ doesn't expand in quotes.Ú~z
echo $HOMEr   z~/rW   Nrƒ   z[a-zA-Z0-9._-]+zecho ~)	r"   r    r–   r•   r›   Úfindr¿   rÀ   rÎ   )r6   r1   rž   ÚhomeÚrestÚ	slash_idxÚusernameÚexpand_results           r%   Ú_expand_pathz ShellFileOperations._expand_pathV  s  € ñ ˜4Ÿ?™?¨3Ô/ØˆKØ—‘˜LÓ)ˆØ×Ñ˜qÒ  V§]¡]×%8Ñ%8Ô%:Ø—=‘=×&Ñ&Ó(ˆDØ�sŠ{Ø�Ø�‰˜tÔ$Ø˜d 1 2˜h‘Ð&ð ˜˜�8ˆDØŸ	™	 #›ˆIØ+4¸ª>�t˜J˜YÑ'¸tˆHÙœBŸL™LÐ);¸XÔFØ $§
¡
¨V°H°:Ð+>Ó ?�Ø ×*Ñ*¨aÒ/°M×4HÑ4H×4NÑ4NÔ4PØ(×/Ñ/×5Ñ5Ó7¸$¸qÄ3ÀxÃ=Ñ?PÐ?QÐ:RÑRÐRØˆr'   Úargc                 óJ   — ddl m} d ||«      j                  dd«      z   dz   S )a5  Single-quote ``arg`` for the shell. On Windows, native drive paths and
        mixed MSYS leftovers are first rewritten to the Git Bash ``/c/Users/x``
        form via the env-layer ``_bash_safe_path`` (bash eats backslashes; MSYS
        mangles drive paths), so shell file ops and the terminal ``cd`` agree.r   )Ú_bash_safe_pathú'ú'"'"')Útools.environments.localrþ   Úreplace)r6   rü   rþ   s      r%   r«   z%ShellFileOperations._escape_shell_argm  s)   € õ
 	=Ø‘_ SÓ)×1Ñ1°#°yÓAÑAÀCÑGÐGr'   c                 óz   — ddl m}m} |r|r ||«      j                  dd«      }d|j                  dd«      z   dz   S )uB  Quote a path for a NATIVE Windows binary (rg, node, git ...): those don't
        understand the MSYS ``/c/...`` form and Hermes disables MSYS argument
        conversion, so nothing translates it back (â†’ ``os error 3``). ``C:/Users/x``
        is accepted by every layer. Identical to ``_escape_shell_arg`` off Windows.r   )Ú_IS_WINDOWSÚ_msys_to_windows_pathú\rƒ   rÿ   r   )r  r  r  r  )r6   rü   r  r  s       r%   Ú_escape_native_tool_argz+ShellFileOperations._escape_native_tool_argu  s?   € ÷
 	PÙ™3Ù'¨Ó,×4Ñ4°T¸3Ó?ˆCØ�S—[‘[  iÓ0Ñ0°3Ñ6Ð6r'   r
   c                 óî   — | j                  |«      }| j                  t        j                  j                  |«      xs d«      }| j                  d«      }d|› d|› d�|z   dz   }| j	                  ||¬«      S )u7  Write ``content`` atomically: stdin â†’ temp file in the SAME directory â†’
        ``mv -f`` (same-FS rename; cross-device ``mv`` is copy+unlink, NOT atomic).
        ``mkdir -p`` folded in. Exit 0 = swap happened; non-zero = original intact.

        Symlink targets are resolved first (replacing the link would orphan the
        target) and the temp dir recomputed from the RESOLVED target. Existing
        target: mode copied via ``stat`` (GNU ``-c%a`` / BSD ``-f%Lp``) + ``chmod``
        (``chmod --reference`` is GNU-only). New target: ``chmod "=rw"`` AFTER cat
        gives umask-default perms instead of mktemp's 0600 â€” not ``$(umask)``
        arithmetic (zsh parses leading-zero constants as decimal), quoted so zsh
        doesn't =word-expand. ``trap ... EXIT`` removes the temp on every failure.
        r\   z.hermes-tmp.XXXXXXz
set -e; d=z; t=z¾; if [ -L "$t" ]; then rt="$(readlink -f "$t" 2>/dev/null || realpath "$t" 2>/dev/null || true)"; [ -n "$rt" ] && { t="$rt"; d="$(dirname "$t")"; }; fi; mkdir -p "$d"; tmp="$(mktemp -p "$d" aó   2>/dev/null || mktemp "$d/.hermes-tmp.$$.XXXXXX" 2>/dev/null || { tmp="$d/.hermes-tmp.$$"; : > "$tmp" && echo "$tmp"; })"; [ -n "$tmp" ] || { echo "atomic write: could not create temp file" >&2; exit 1; }; trap 'rm -f \"$tmp\"' EXIT; if [ -e "$t" ]; then m="$(stat -c%a "$t" 2>/dev/null || stat -f%Lp "$t" 2>/dev/null || true)"; [ -n "$m" ] && chmod "$m" "$tmp" 2>/dev/null || true; fi; cat > "$tmp"; if [ ! -e "$t" ]; then chmod "=rw" "$tmp" 2>/dev/null || true; fi; mv -f "$tmp" "$t"; trap - EXIT)r�   )r«   rß   r1   Údirnamer    )r6   r1   r<   Úq_pathÚq_parentÚtmplÚscripts          r%   Ú_atomic_writez!ShellFileOperations._atomic_write  s’   € ð ×'Ñ'¨Ó-ˆØ×)Ñ)¬"¯'©'¯/©/¸$Ó*?Ò*FÀ3ÓGˆØ×%Ñ%Ð&:Ó;ˆðð  �
˜$˜v˜hð '%ð!%ð, (,ñ-,ð,/ñ-$ð 	ðL �z‰z˜&¨WˆzÓ5Ð5r'   r=   c                 ór   — | j                  |d«      }|j                  dk(  xr t        |j                  «      S )uë   Whether the on-disk file starts with a UTF-8 BOM. ALWAYS probes disk:
        ``pre_content`` usually comes from ``read_file_raw``, which strips BOMs, so
        trusting it would silently drop the marker on rewrite. Missing â†’ False.rÊ   r   )r±   r–   r   r•   )r6   r1   r=   Úhead_results       r%   Ú_file_has_bomz!ShellFileOperations._file_has_bom·  s5   € ð —j‘j  qÓ)ˆØ×$Ñ$¨Ñ)ÒJ¬h°{×7IÑ7IÓ.JÐJr'   Úold_contentÚnew_contentÚfilenamec           	      óž   — dj                  t        j                  |j                  d¬«      |j                  d¬«      d|› �d|› �¬«      «      S )Nr�   T)Úkeependsza/zb/)ÚfromfileÚtofile)r¾   ÚdifflibÚunified_diffÚ
splitlines)r6   r  r  r  s       r%   Ú_unified_diffz!ShellFileOperations._unified_diff¾  sS   € Ø�w‰w”w×+Ñ+Ø×"Ñ"¨DÐ"Ó1°;×3IÑ3IÐSWÐ3IÓ3XØ˜(˜�_¨r°(°¨_ô>ó ?ð 	?r'   c                 ó"   — t        d| › d�¬«      S )z5Error for a path that exists but would block if read.zCannot read 'z`': not a regular file (directory, FIFO, socket, or device). Reading it could block indefinitely.©Úerror©r   )r1   s    r%   Ú_not_regular_errorz&ShellFileOperations._not_regular_errorÅ  s&   € ô Ø˜D˜6ð "Gð GôIð 	Ir'   c                 ó`  — | j                  |«      }| j                  d|› d|› d|› dt        › dt        › d�«      }t	        |j
                  «      j                  «       }|t        k(  ry|t        k(  ry|j                  d	k7  rd	|j                  xs d
fS 	 t        |«      dfS # t        $ r Y yw xY w)a0  Byte size of a REGULAR file: ``(file_size, status)`` with status ``"ok"``,
        ``"missing"``, ``"not_regular"``, ``"bad_size"`` (unparseable ``wc``),
        ``"env_unavailable"``, or the named working-directory error when the exec
        wrapper itself failed (``_env_unavailable_error`` surfaces it verbatim).
        ``wc -c <`` on a writer-less FIFO/socket//dev/zero blocks forever and a
        name-based blocklist can't cover a FIFO (a file TYPE at any path); ``[ -f ]``
        is a stat (symlinks followed) so it answers without touching content.úif [ -f ú ]; then wc -c < z 2>/dev/null; elif [ -e ú ]; then echo ú; else echo ú; fi)r   Úmissing)r   Únot_regularr   Úenv_unavailableÚok)r   Úbad_size)r«   r    ÚNOT_REGULAR_SENTINELÚMISSING_SENTINELr   r•   r›   r–   r—   rd   rÅ   )r6   r1   rü   Ústat_resultÚstat_outputs        r%   Ú_probe_regular_filez'ShellFileOperations._probe_regular_fileÌ  sÖ   € ð ×$Ñ$ TÓ*ˆð —j‘jØ�s�eÐ,¨S¨Eð 2Ø˜˜^Ô,@Ð+Að BÜ)Ð*¨$ð0ó1ˆô 2°+×2DÑ2DÓE×KÑKÓMˆØÔ*Ò*ØØÔ.Ò.Ø#Ø× Ñ  AÒ%Ø�k×+Ñ+Ò@Ð/@Ð@Ð@ð	!Ü�{Ó# TÐ)Ð)øÜò 	!Ù ð	!ús   ÂB! Â!	B-Â,B-Ústatusc                 óD   — |dk7  rt        |¬«      S t        d|› d�¬«      S )Nr*  r  ú1Terminal environment unavailable: could not stat úC (the sandbox may still be starting or was removed). Retry shortly.r   )r6   r1   r2  s      r%   Ú_env_unavailable_errorz*ShellFileOperations._env_unavailable_errorè  s;   € ØÐ&Ò&Ü FÔ+Ð+ÜÐ#TÐUYÐTZð [fð "fô hð 	hr'   c                 óÞ   — | j                  |«      }|�"t        |«      }|xs | j                  |«      |fS t        | j	                  |d«      j
                  «      }| j                  ||«      dfS )uš   ``(is_binary, sample_bytes)`` â€” byte-layer detection when the transport
        allows (base64 sample), else the legacy text heuristic (sample is None).NrÓ   )r¹   r   rÐ   r   r±   r•   rÝ   )r6   r1   Úsample_bytesÚ
ext_binaryÚsample_outputs        r%   Ú_detect_binaryz"ShellFileOperations._detect_binaryî  sr   € ð ×.Ñ.¨tÓ4ˆØÐ#Ü-¨dÓ3ˆJØÒK ×!=Ñ!=¸lÓ!KÈ\ÐYÐYÜ3°D·J±J¸tÀTÓ4J×4QÑ4QÓRˆØ×%Ñ% d¨MÓ:¸DÐ@Ð@r'   i    i   r2   r3   r(   zOptional[ReadResult]c                 óÒ  ‡— t        |«      s|| j                  kD  ryd|›dt        |«      › dt        |«      › d| j                  › d| j                  › d�}| j	                  |«      }t        |j                  xs d«      }|j                  d	«      }|j                  d
k7  s|d
k  ry||t        d	«      z   d j                  «       }		 t        j                  d|	v r|	j                  dd«      d
   n|	«      }
|
d   }t        |
d   «      }t        |
j                  dd«      «      }||z   dz
  }||kD  }d|j'                  «       › d�g}|r!|j)                  d|dz   › d|› d|› d|› d�	«       d
dlm}  |«       Št/        ˆfd„|j                  d«      D «       «      }t1        | j3                  ||«      |||dj5                  |«      |rd¬«      S d¬«      S # t         t"        t$        f$ r Y yw xY w)zÊRead ``path`` as UTF-16 transcoded to UTF-8, or None (caller falls back
        to the binary-file error). Skips known-binary extensions and files over
        10 MiB. ``path`` must already be expanded.Nzimport sys, json, os
p = z

offset = z	
limit = z
MAX = z

SAMPLE = af  
try:
    size = os.path.getsize(p)
    if size > MAX:
        print('HERMES_UTF16:NO'); sys.exit(0)
    with open(p, 'rb') as f:
        data = f.read()
    sample = data[:SAMPLE]
    enc = None
    if sample[:2] == b'\xfe\xff':
        enc = 'utf-16-be'
    elif sample[:2] == b'\xff\xfe':
        enc = 'utf-16-le'
    else:
        odd = sum(1 for i in range(1, len(sample), 2) if sample[i] == 0)
        even = sum(1 for i in range(0, len(sample), 2) if sample[i] == 0)
        if even == 0 and odd >= 2:
            enc = 'utf-16-le'
        elif odd == 0 and even >= 2:
            enc = 'utf-16-be'
    if enc is None:
        print('HERMES_UTF16:NO'); sys.exit(0)
    text = data.decode(enc, 'replace')
    if text[:1] == '\ufeff':
        text = text[1:]
    text = text.replace('\r\n', '\n')
    lines = text.split('\n')
    total = len(lines)
    sel = lines[offset - 1: offset - 1 + limit]
    out = {'total_lines': total, 'encoding': enc,
           'content': '\n'.join(sel)}
    print('HERMES_UTF16:OK')
    print(json.dumps(out, ensure_ascii=True))
except Exception:
    print('HERMES_UTF16:NO'); sys.exit(0)
r�   zHERMES_UTF16:OKr   rz   rW   r<   Útotal_linesÚencodingzutf-16zTranscoded from zP to UTF-8 for display. Text edits via patch/write_file would re-encode as UTF-8.úUse offset=ú to continue reading (showing Ú-ú of ú lines)ræ   c              3   ó:   •K  — | ]  }t        |«      ‰kD  –— Œ y ­wrY   rë   ©r×   rí   rî   s     €r%   rÙ   z6ShellFileOperations._try_read_utf16.<locals>.<genexpr>J  s   øè ø€ ÒZ¸dœc $›i¨/Õ9ÑZùó   ƒr°   T©r<   r=  r(   Ú	truncatedrŸ   Útruncated_lines)r   Ú_UTF16_MAX_BYTESrd   Ú_UTF16_SAMPLE_BYTESrµ   r   r•   rõ   r–   rÎ   r›   ÚjsonÚloadsr|   rc   r™   rÅ   ÚKeyErrorÚ	TypeErrorÚupperÚappendrï   rç   Úanyr   rò   r¾   )r6   r1   r2   r3   r(   r²   rž   r•   ÚmarkerÚpayloadÚdatar<   r=  r>  Úend_linerH  Ú
hint_partsrç   rI  rî   s                      @r%   Ú_try_read_utf16z#ShellFileOperations._try_read_utf16  s8  ø€ ô
   Ô%¨°T×5JÑ5JÒ)JØðØ�(ð Ü˜F›�}ð %Ü˜5“z�lð #Ø×*Ñ*Ð+ð ,Ø×0Ñ0Ð1ð "2:ð':ð 	ðR ×)Ñ)¨'Ó2ˆÜ,¨V¯]©]Ò-@¸bÓAˆØ—‘Ð.Ó/ˆØ×Ñ˜qÒ  F¨Q¢JØØ˜¤#Ð&7Ó"8Ñ8Ð9Ð:×@Ñ@ÓBˆð	Ü—:‘:¸4À7¹?˜gŸm™m¨D°!Ó4°QÒ7ÐPWÓXˆDØ˜9‘oˆGÜ˜d =Ñ1Ó2ˆKÜ˜4Ÿ8™8 J°Ó9Ó:ˆHð ˜E‘> AÑ%ˆØ (Ñ*ˆ	Ø(¨¯©Ó)9Ð(:ð ;Rð Rð Sˆ
áØ×ÑØ˜h¨™l˜^ð ,Ø"˜8 1 X J¨d°;°-¸wðHôIõ 	AÙ-Ó/ˆÜÓZÀgÇmÁmÐTXÓFYÔZÓZˆÜØ×*Ñ*¨7°FÓ;ÈØ¨9¸3¿8¹8ÀJÓ;OÙ$3˜Dô?ð 	?ð :>ô?ð 	?øô œH¤iÐ0ò 	Ùð	ús   ÃAG ÇG&Ç%G&c           	      óN  — | j                  |«      }t        ||«      \  }}| j                  «       r| j                  |||«      S | j	                  |«      st        |«      r| j                  |||«      S ddlm} d |«       z  dz   }||z   dz
  }t        t        «      }| j                  | j                  |||||«      «      }|j                  xs d}	||	vr�t        |	«      j                  «       }
|
t         k(  r| j#                  |||«      S |
t$        k(  r| j'                  |«      S t(        j+                  d||j,                  t/        |	«      «       | j                  |||«      S t1        |	|«      }|j,                  dk7  st/        |«      dk7  r>t(        j+                  d||j,                  t/        |«      «       | j                  |||«      S |\  }}}}}}t        |«      j3                  «       }	 t5        |d   «      t5        |d   «      }}	 t5        t        |«      j                  «       «      }|dk(  r| j;                  |«      nd}|�| j=                  |«      }nNt(        j+                  d||«       t        | j?                  |d«      j                  «      }| jA                  ||«      }|r| jC                  |||||«      S |dk7  rtE        dt        |«      › �¬«      S t        |«      }	 t5        t        |«      j                  «       «      }t        |«      j                  «       }|dv r|dk(  nd}| jG                  ||||||¬«      S # t6        t8        f$ r0 t(        j+                  d	||d
d «       | j                  |||«      cY S w xY w# t8        $ r d}Y �Œgw xY w# t8        $ r d}Y Œœw xY w)aE  Read a file with pagination, binary detection, and line numbers.

        ``offset`` is 1-indexed; ``limit`` is clamped by ``normalize_read_pagination``.
        One shell round-trip answers every question the read needs (existence, size,
        binary sample, page, line count, trailing newline; see ``_read_probe_cmd``).
        An unparseable reply falls back to ``_read_file_sequential`` (one probe per
        question), so an exotic shell can never do worse than before. On a local
        POSIX environment the read never touches the shell (``_read_file_native``).
        r   ræ   r    rW   r�   zmread_file: compound probe reply for %s has no sentinel (exit %s, %d chars); falling back to sequential probesé   znread_file: compound probe for %s returned exit %s with %d segments (want 6); falling back to sequential probesz]read_file: compound probe for %s has unparseable status %r; falling back to sequential probesiØÿÿÿNznread_file: no usable base64 sample for %s (base64 exit %s); paying one extra round-trip for the text heuristicrÓ   úFailed to read file: r  )Ú0Ú1r]  ©r2   rV  r=  r(   Úfile_ends_with_newline)$rû   r   Ú_native_read_enabledÚ_read_file_nativerã   r   Ú_read_file_sequentialrï   rç   rv   Ú_READ_SENTINEL_PREFIXr    Ú_read_probe_cmdr•   r   r›   r.  Ú_read_file_missingr-  r!  ÚloggerÚdebugr–   rÎ   r}   r|   rd   Ú
IndexErrorrÅ   r¸   rÐ   r±   rÝ   Ú_read_binary_filer   Ú_assemble_read_result)r6   r1   r2   r3   rç   Úline_clamp_bytesrV  rx   Úproberw   rS  ÚsegmentsÚsize_segÚ
sample_segÚpage_segÚwc_segÚtail_segÚ
status_segr2  Ú	sample_rcÚread_rcr(   r8  Ú	is_binaryr:  Úread_outputr=  Ú	tail_flagr_  s                                r%   r7   zShellFileOperations.read_fileP  sÄ  € ð × Ñ  Ó&ˆÜ1°&¸%Ó@‰ˆ�à×$Ñ$Ô&Ø×)Ñ)¨$°¸Ó>Ð>ð �>‰>˜$ÔÔ#7¸Ô#=Ø×-Ñ-¨d°F¸EÓBÐBå@ØÑ2Ó4Ñ4°qÑ8ÐØ˜E‘> AÑ%ˆÜ Ô!6Ó7ˆØ—
‘
˜4×/Ñ/°°f¸hÐHXÐZbÓcÓdˆØ—‘Ò# ˆà˜6Ñ!ä0°Ó8×>Ñ>Ó@ˆFØÔ)Ò)Ø×.Ñ.¨t°V¸UÓCÐCØÔ-Ò-Ø×.Ñ.¨tÓ4Ð4Ü�L‰LðIà�e—o‘o¤s¨6£{ô4ð ×-Ñ-¨d°F¸EÓBÐBä" 6¨8Ó4ˆØ�?‰?˜aÒ¤3 x£=°AÒ#5Ü�L‰LðGà�e—o‘o¤s¨8£}ô6ð ×-Ñ-¨d°F¸EÓBÐBØGOÑDˆ�*˜h¨°¸*ä,¨ZÓ8×>Ñ>Ó@ˆð	CÜ!$ V¨A¡Y£´°V¸A±Y³�wˆIð	ÜÔ7¸ÓA×GÑGÓIÓJˆIð BKÈaÂ�t×1Ñ1°*Ô=ÐUYˆØÐ#Ø×4Ñ4°\ÓB‰Iä�L‰LðEØFJÈIôWô 8¸¿
¹
À4ÈÓ8N×8UÑ8UÓVˆMØ×.Ñ.¨t°]ÓCˆIÙØ×)Ñ)¨$°¸¸yÈ,ÓWÐWà�aŠ<ÜÐ&;Ô<WÐX`Ó<aÐ;bÐ$cÔdÐdÜ1°(Ó;ˆð	ÜÔ9¸&ÓA×GÑGÓIÓJˆKô 0°Ó9×?Ñ?ÓAˆ	Ø5>À*Ñ5L ¨cÒ!1ÐRVÐØ×)Ñ)Ø °À{ØÐ8Nð *ó Pð 	PøôE œJÐ'ò 	CÜ�L‰Lð4Ø59¸:ÀcÀdÐ;KôMð ×-Ñ-¨d°F¸EÓBÒBð		Cûô ò 	Ø‹Ið	ûô, ò 	ØŠKð	ús6   Ç,M È	"N Ë%"N Í<NÎ NÎNÎNÎN$Î#N$c                 óÎ   — t         j                  j                  dd«      j                  «       j	                  «       }|dv ryt
        j                  dk7  xr | j                  «       S )a3  Whether ``read_file`` and ``search_files`` may bypass the shell: only POSIX + ``LocalEnvironment``
        (file is on this host, path already native; Windows keeps the shell path since
        file_operations holds Git-Bash-style paths there). ``HERMES_NATIVE_FILE_READ=0``
        turns the fast path off.ÚHERMES_NATIVE_FILE_READr]  )r\  ÚfalseÚnoÚoffFÚwin32)rß   Úenvironr™   r›   rá   ÚsysÚplatformÚ_lsp_local_only)r6   Úflags     r%   r`  z(ShellFileOperations._native_read_enabled«  sV   € ô
 �z‰z�~‰~Ð7¸Ó=×CÑCÓE×KÑKÓMˆØÐ.Ñ.Øô �|‰|˜wÑ&ÒA¨4×+?Ñ+?Ó+AÐAr'   c                 óØ  — ddl }t        j                  j                  |«      r|nBt        j                  j	                  t        | j                  dd«      xs | j                  |«      }	 t        j                   |«      }|j                  |j                  «      s| j                  |«      S |j                   }| j#                  |«      r| j%                  |«      S ddlm} d |«       z  dz   }	||z   dz
  }
g }d}d}t+        «       }d}d}t-        j.                  «       }	 t1        |d	«      5 }|j3                  d
«      }t5        |«      }|s| j7                  |«      r| j9                  |||||«      cddd«       S |j;                  d«       	 |j3                  d«      }|s�n|j=                  |«       |dd }||
kD  r||j?                  d«      z  }|dd dk7  }ŒNdtA        |«      }}||k  rÀ|jC                  d|«      }||cxk  xr |
k  nc }|dk  r*|r%tA        |«      |	k  r|||||	tA        |«      z
  z    z  }d}no|rLtA        |«      |	k  r!|||tE        |||	tA        |«      z
  z   «       z  }|jG                  tI        |«      dz   «       t+        «       }d}|dz  }|dz  }|dz   }||k  rŒÀ�Œ!	 ddd«       |r+||cxk  r|
k  r n n|jG                  tI        |«      dz   «       tK        dj	                  |«      jM                  dd¬«      «      }| jO                  |||
|||r|dk(  nd¬«      }|jP                  |jR                  |j                   |jT                  |jV                  |jY                  «       f|_-        |S # t        t        f$ r | j                  |||«      cY S t        $ r | j                  |||«      cY S w xY w# 1 sw Y   �ŒxY w# t        $ r | j                  |||«      cY S w xY w)uÂ  ``read_file`` without a shell â€” same contract as the shell path, byte for
        byte. ``os.stat`` is the ``[ -f ]`` guard (a stat, never an open, so FIFOs and
        devices are refused before anything touches them); the first 1000 bytes drive
        the byte-layer binary check; the page is produced exactly as
        ``sed -n 'a,bp' | cut -b1-N`` prints it (each line clamped to N bytes and
        newline-terminated) then decoded with errors="replace" like the transport.
        One chunked pass counts lines and collects the page, so neither the file nor
        a pathological line is ever held whole. ``path`` is already expanded; any
        unexpected OSError hands over to the shell path.r   Nr€   ræ   r    rW   Fr'   ÚrbrÓ   Tr*   rè   ó   
rÉ   r  )Úerrorsr^  ).Ústatrß   r1   Úisabsr¾   r…   r„   r€   ÚFileNotFoundErrorÚNotADirectoryErrorre  ÚOSErrorrb  ÚS_ISREGÚst_moder!  Úst_sizerã   Ú_image_redirect_resultrï   rç   Ú	bytearrayÚhashlibÚsha256ÚopenÚreadr   rÐ   ri  ÚseekÚupdateÚcountrÎ   rõ   rÛ   rQ  Úbytesr   rË   rj  Úst_devÚst_inoÚst_mtime_nsÚst_ctime_nsÚdigestÚ	_snapshot)r6   r1   r2   r3   Ú_statÚfullÚstr(   rç   ÚclamprV  Úpager=  ÚlinenoÚkeptÚhave_partialÚ	last_byterž  Úfhr   r9  ÚchunkÚposÚnÚnlÚin_pagerw  rž   s                               r%   ra  z%ShellFileOperations._read_file_native·  sæ  € ó 	ä—w‘w—}‘} TÔ*‰t´·±·±Ü�D—H‘H˜e TÓ*Ò6¨d¯h©h¸ó1>ˆð	CÜ—‘˜“ˆBð
 �}‰}˜RŸZ™ZÔ(Ø×*Ñ*¨4Ó0Ð0Ø—J‘Jˆ	Ø�>‰>˜$ÔØ×.Ñ.¨yÓ9Ð9å@ØÑ'Ó)Ñ)¨AÑ-ˆØ˜E‘> AÑ%ˆàˆØˆØˆÜ‹{ˆØˆØˆ	Ü—‘Ó!ˆð&	CÜ�d˜DÓ!ð #% RØŸ™ ›�Ü1°$Ó7�
Ù ×!=Ñ!=¸fÔ!EØ×1Ñ1°$¸ÀÀyÐRXÓY÷	#%ñ #%ð
 —‘˜”
ØØŸG™G GÓ,�EÙ ÙØ—M‘M %Ô(Ø % b c 
�IØ Ò(ð $ u§{¡{°5Ó'9Ñ9˜Ø',¨R¨S z°UÑ':˜Ø Ø¤ E£
˜�CØ š'Ø"ŸZ™Z¨¨sÓ3˜Ø"(¨FÖ">°hÔ">˜Ø š6Ù&¬3¨t«9°uÒ+<Ø $¨¨c°#¸ÄÀTÃÑ9JÑ2KÐ(LÑ L Ø+/˜LØ!Ù"Ü" 4›y¨5Ò0Ø $¨¨c´#°b¸#ÀÌÈTËÑARÑ:SÓ2TÐ(UÑ U Ø ŸK™K¬¨d«°eÑ(;Ô<Ü(›{˜Ø',˜Ø# qÑ(˜Ø !™˜Ø  1™f˜ð!  ›'ñ ð ÷#%ñL ˜F fÔ8°Õ8à�K‰Kœ˜d› eÑ+Ô,ä1°#·(±(¸4³.×2GÑ2GÈÐXaÐ2GÓ2bÓcˆØ×+Ñ+Ø °À{ØÙ;D I°Ò$6È$ð ,ó Pˆð ŸI™I r§y¡y°"·*±*¸b¿n¹nÈbÏnÉnÐ^d×^kÑ^kÓ^mÐnˆÔØˆøôM "Ô#5Ð6ò 	@Ø×*Ñ*¨4°¸Ó?Ò?Üò 	CØ×-Ñ-¨d°F¸EÓBÒBð	Cú÷(#%ñ #%ûôH ò 	CØ×-Ñ-¨d°F¸EÓBÒBð	CúsV   Á*M8 ÄO
 Ä)AN=Å-	O
 Å7D0N=Ê(N=Ê+O
 Í8"N:ÎN:Î9N:Î=OÏO
 Ï
O)Ï(O)c                 ó    — t        dd| d¬«      S )NTz‹Image file detected. Automatically redirected to vision_analyze tool. Use vision_analyze with this file path to inspect the image contents.)Úis_imagerv  r(   rŸ   r   )r(   s    r%   r�  z*ShellFileOperations._image_redirect_result  s   € äØ T°YðXôZð 	Zr'   rV  rk  rx   c                 ó  — | j                  |«      }d|› �}dj                  g d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d	‘|› ‘d
‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘|› ‘d‘t        › ‘d‘t        › ‘d‘«      S )uú  One shell command answering every question ``read_file`` asks: six
        segments each closed by a ``sentinel`` line â€” byte size, base64 of the first
        1000 bytes, the ``sed | cut`` page, ``wc -l``, whether the last byte is a
        newline, then the base64 and page pipeline statuses. Probes run only inside
        ``[ -f ]`` (stat-not-open, like ``_probe_regular_file``) so a FIFO/device never
        reaches ``head``/``sed``. A missing path echoes ``MISSING_SENTINEL`` (a compound
        command only reports its last status). Every stage silences stderr: the local
        backend merges stderr into stdout and a stray diagnostic would land inside a
        segment. The byte clamp is ``4 * max_line_length + 1``; see ``_read_file_sequential``.zecho r�   r#  r$  z 2>/dev/null; z; head -c 1000 z, 2>/dev/null | base64 2>/dev/null; __hs=$?; z
; sed -n 'ú,úp' z 2>/dev/null | cut -b1-z 2>/dev/null; __hr=$?; z
; wc -l < z; tail -c 1 z 2>/dev/null | wc -l; z ; echo "$__hs $__hr"; elif [ -e r%  r&  r'  )r«   r¾   r-  r.  )r6   r1   r2   rV  rk  rx   rü   Úmarks           r%   rd  z#ShellFileOperations._read_probe_cmd  s§  € ð ×$Ñ$ TÓ*ˆØ�x�jÐ!ˆ÷	0ó 	0ˆhð 	0�s�eð 	0ð ð 	0Ø�eð	0Ø)ð	0Ø*.¨ð	0ð0ð	0à˜5ð	0à Lð	0àMQÈFð	0ðSð	0ð �hð	0ð  ð	0ð !)˜zð	0ð *-ð	0ð .1¨Eð	0ð2ð	0ð +Ð+ð		0ð ,Cð		0ð DHÀ&ð		0ðIð		0ð
 �eð	0ð
 *ð	0ð
 +/¨ð	0ð
0ð	0ð ˜ð	0ð 4ð	0ð 59°6ð	0ð:ð	0ð ˜ð	0ð ,ð	0ô -AÐ+Að	0ðBð	0ô *Ð*ð	0ð +/ô	0ð
	1r'   c                 óÞ   — | j                  |«      }|�J| j                  |||¬«      }d|› d|› d�}|j                  r|› d|j                  › �|_        |S ||_        |S | j                  |«      S )u*  Not-found recovery shared by every read path. Unicode-equivalent spellings
        (NFC/NFD, confusable spaces/quotes) render identically, so the model can never
        discover the byte mismatch by retyping â€” retrying is the tool's job. No
        equivalent spelling â†’ suggest similar files.)r2   r3   zNote: 'zD' not found byte-for-byte; resolved to the unicode-equivalent file 'zM' (invisible encoding difference: NFC/NFD or special space/quote characters).r°   )Ú_unicode_variant_matchr7   rŸ   Ú_suggest_similar_files)r6   r1   r2   r3   Úvariantrž   Únotes          r%   re  z&ShellFileOperations._read_file_missing0  s’   € ð
 ×-Ñ-¨dÓ3ˆØÐØ—^‘^ G°FÀ%�^ÓHˆFà˜$˜ð  0Ø07¨yð 9ðð ð
 6<·[²[˜T˜F ! F§K¡K =Ð1ˆFŒKØˆMð GKˆFŒKØˆMØ×*Ñ*¨4Ó0Ð0r'   r8  c                 ób   — | j                  ||||«      }|�|S t        d|t        ||«      ¬«      S )aB  Binary branch shared by every read path: UTF-16 text (Notepad, PowerShell
        ``>``) trips the binary guard; transcode it, else refuse with the type name.

        UTF-16 rescue (ported from MoonshotAI/kimi-code#2647): the terminal env decodes stdout as UTF-8 with
        errors="replace", so a UTF-16 text file (Windows Notepad .txt, PowerShell `>` redirects) arrives
        mangled with U+FFFD and trips the binary guard. Probe the raw bytes via the backend's Python and
        transcode to UTF-8 when a BOM or the zero-byte parity heuristic identifies UTF-16.
        T©rv  r(   r  )rX  r   r.   )r6   r1   r2   r3   r(   r8  Úutf16_results          r%   ri  z%ShellFileOperations._read_binary_fileA  sD   € ð ×+Ñ+¨D°&¸%ÀÓKˆØÐ#ØÐÜØ iÜ& |°YÓ?ôAð 	Ar'   c           
      ó&  — | j                  |«      \  }}|dk(  r| j                  |||«      S |dk(  r| j                  |«      S |dvr| j                  ||«      S | j	                  |«      r| j                  |«      S | j                  |«      \  }}|r| j                  |||||«      S ddlm	} d |«       z  dz   }	||z   dz
  }
| j                  d|› d	|
› d
| j                  |«      › d|	› �«      }|j                  dk7  rt        d|j                  › �¬«      S t        |j                  «      }| j                  d| j                  |«      › �«      }	 t!        t        |j                  «      j#                  «       «      }d}||
kD  sj|j'                  d«      rY| j                  d| j                  |«      › d�«      }|j                  dk(  r&t        |j                  «      j#                  «       dk7  }| j)                  |||
|||¬«      S # t$        $ r d}Y Œ•w xY w)zØOne-probe-per-call read: the pre-compound form, kept as fallback for
        image / known-binary extensions and unparseable compound replies. ``path`` is
        already expanded and ``offset``/``limit`` normalized.r(  r)  ©r+  r,  r   ræ   r    rW   zsed -n 'r²  r³  z | cut -b1-r[  r  zwc -l < Nrz   z
tail -c 1 z | wc -lr\  r^  )r1  re  r!  r6  rã   r�  r;  ri  rï   rç   r    r«   r–   r   r•   r   rd   r›   rÅ   rð   rj  )r6   r1   r2   r3   r(   r2  rv  r8  rç   rk  rV  Úread_resultrw  Ú	wc_resultr=  r_  Útail_results                    r%   rb  z)ShellFileOperations._read_file_sequentialR  sH  € ð !×4Ñ4°TÓ:Ñˆ	�6Ø�YÒØ×*Ñ*¨4°¸Ó?Ð?Ø�]Ò"Ø×*Ñ*¨4Ó0Ð0ØÐ+Ñ+Ø×.Ñ.¨t°VÓ<Ð<Ø�>‰>˜$ÔØ×.Ñ.¨yÓ9Ð9Ø"&×"5Ñ"5°dÓ";Ñˆ	�<ÙØ×)Ñ)¨$°¸¸yÈ,ÓWÐWõ 	AØÑ2Ó4Ñ4°qÑ8ÐØ˜E‘> AÑ%ˆØ—j‘jØ�v�h˜a ˜z¨¨T×-CÑ-CÀDÓ-IÐ,JØÐ*Ð+ð-ó.ˆð × Ñ  AÒ%ÜÐ&;¸K×<NÑ<NÐ;OÐ$PÔQÐQÜ1°+×2DÑ2DÓEˆà—J‘J ¨$×*@Ñ*@ÀÓ*FÐ)GÐHÓIˆ	ð	ÜÔ9¸)×:JÑ:JÓK×QÑQÓSÓTˆKð 26ÐØ˜XÒ%¨+×*>Ñ*>¸tÔ*DØŸ*™* z°$×2HÑ2HÈÓ2NÐ1OÈxÐ%XÓYˆKØ×$Ñ$¨Ò)Ü)DÀ[×EWÑEWÓ)X×)^Ñ)^Ó)`ÐdgÑ)gÐ&Ø×)Ñ)Ø °À{ØÐ8Nð *ó Pð 	Pøô ò 	ØŠKð	ús   Å,H ÈHÈHrw  r=  r_  c                óÞ  ‡— |dkD  r	|du r|dz  }|dk(  rt        |«      \  }}||kD  }d}	|rd|dz   › d|› d|› d|› d	�	}	|s|j                  d
«      r	|du r|dd }|dk(  rt        dddd¬«      S ||cxkD  rdkD  rn nt        d||d|› d|› d|› d�¬«      S ddlm}
  |
«       Št        ˆfd„|j                  d
«      D «       «      }t        | j                  ||«      ||||	|rd¬«      S d¬«      S )aF  Turn a raw ``sed | cut`` page into the final ``ReadResult``. Shared by every
        read path so the BOM strip, pagination hint, ``cut`` newline-artifact fix and
        the ambiguous-silence guards never drift apart. ``file_ends_with_newline`` is
        None when the caller could not tell (artifact left alone, as before).r   FrW   Nr?  r@  rA  rB  rC  rz   rè   r�   zFile is empty (0 bytes).)r<   r=  r(   rŸ   zNote: offset z  is beyond the end of the file (z$ lines total). Retry with offset <= r\   ræ   c              3   ó:   •K  — | ]  }t        |«      ‰kD  –— Œ y ­wrY   rë   rE  s     €r%   rÙ   z<ShellFileOperations._assemble_read_result.<locals>.<genexpr>©  s   øè ø€ Ò^¸dœc $›i¨/Õ9Ñ^ùrF  TrG  )r   rð   r   rï   rç   rR  r|   rò   )r6   rw  r2   rV  r=  r(   r_  Ú_rH  rŸ   rç   rI  rî   s               @r%   rj  z)ShellFileOperations._assemble_read_result„  sX  ø€ ð �qŠ=Ð3°uÑ<Ø˜1ÑˆKØ�QŠ;Ü'¨Ó4‰NˆK˜Ø (Ñ*ˆ	ØˆÙØ  ¨A¡ Ð.LÈVÈHÐTUÐV^ÐU_Ð_cÐdoÐcpÐpwÐxˆDñ ˜[×1Ñ1°$Ô7Ð<RÐV[Ñ<[Ø% c rÐ*ˆKð ˜Š>Ü b°aÀ1ÐKeÔfÐfØ�KÔ# !Õ#ÜØ¨¸yà# F 8ð ,Ø#�}Ð$HØ"�m 1ð&ô(ð (õ 	AÙ-Ó/ˆÜÓ^Àk×FWÑFWÐX\ÓF]Ô^Ó^ˆÜØ×*Ñ*¨;¸Ó?È[Ø¨9¸4Ù$3˜Dô?ð 	?ð :>ô?ð 	?r'   ))u   â€¯r°   )õ   Â r°   )u   â€™rÿ   )u   â€˜rÿ   c                 ól  ‡ — t         j                  j                  |«      xs d}t         j                  j                  |«      }|sydt        dt        fˆ fd„} ||«      }‰ j                  d‰ j                  |«      › d�«      }|j                  dk7  s|j                  j                  «       syt        |j                  «      j                  «       D �cg c]  }|r||k7  r ||«      |k(  r|‘Œ }}t        |«      d	k(  r1|dk7  sd
|v r#t         j                  j                  ||d   «      S |d   S yc c}w )u  On-disk spelling of a file whose name is unicode-equivalent to ``path``
        (NFC/NFD, confusable spaces/quotes). Returns the entry only when EXACTLY one
        matches â€” several candidates = homoglyph collision, guessing would read the
        wrong file.r\   Nr$   r   c                 ó€   •— t        j                  d| «      }‰j                  D ]  \  }}|j                  ||«      }Œ |S )NÚNFC)ÚunicodedataÚ	normalizeÚ_CONFUSABLESr  )r$   ÚoutrJ   rK   r6   s       €r%   Ú_canonz:ShellFileOperations._unicode_variant_match.<locals>._canonÁ  sC   ø€ Ü×'Ñ'¨¨tÓ4ˆCØ ×-Ñ-ò ,‘��SØ—k‘k # sÓ+‘ð,àˆJr'   úls -1 r©   r   rW   rƒ   )rß   r1   r	  Úbasenamerc   r    r«   r–   r•   r›   r   r  rÎ   r¾   )	r6   r1   Údir_pathr  rÍ  rO   Ú	ls_resultÚentryÚ
candidatess	   `        r%   r¶  z*ShellFileOperations._unicode_variant_match·  s,  ø€ ô
 —7‘7—?‘? 4Ó(Ò/¨CˆÜ—7‘7×#Ñ# DÓ)ˆÙØð	œð 	¤õ 	ñ ˜Ó!ˆØ—J‘J ¨×(>Ñ(>¸xÓ(HÐ'IÈÐVÓWˆ	Ø×Ñ !Ò#¨9×+;Ñ+;×+AÑ+AÔ+CØä:¸9×;KÑ;KÓL×WÑWÓYöHØÙ˜ (Ò*©v°e«}ÀÒ/Fò ðHˆ
ð Hô ˆz‹?˜aÒØ<DÈºOÈsÐVZÉ{”2—7‘7—<‘< ¨*°Q©-Ó8ÐmÐ`jÐklÑ`mÐmØùòHs   ÃD1c           	      óÒ  — t         j                  j                  |«      xs d}t         j                  j                  |«      }t         j                  j	                  |«      d   j                  «       }t         j                  j	                  |«      d   j                  «       }|j                  «       }| j                  d| j                  |«      › d�«      }g }|j                  dk(  �rÁ|j                  j                  «       �r¦|j                  j                  «       j                  d«      D �]y  }	|	sŒ|	j                  «       }
d}|
|k(  rd}nòt         j                  j	                  |	«      d   j                  «       |k(  rd}n¼|
j                  |«      s|j                  |
«      rd	}n—||
v rd
}n�|
|v rt        |
«      dkD  rd}n{|ryt         j                  j	                  |	«      d   j                  «       |k(  rFt        |«      t        |
«      z  }t        |«      t        t        |«      t        |
«      «      dz  k\  rd}|dk(  r*t!        j"                  d||
«      j%                  «       dk\  rd}|dkD  s�ŒI|j'                  |t         j                  j)                  ||	«      f«       �Œ| |j+                  d„ ¬«       t-        d|› �|dd D ��cg c]  \  }}|‘Œ	 c}}¬«      S c c}}w )zN"File not found" result listing up to 5 similar names from the same directory.r\   r   rW   rÎ  z 2>/dev/null | head -50rz   éd   éZ   éF   é<   é   é(   gš™™™™™Ù?é   Ngš™™™™™é?r]   c                 ó   — | d    S )Nr   r5   )Úxs    r%   ú<lambda>z<ShellFileOperations._suggest_similar_files.<locals>.<lambda>ô  s   €  1 Q¡4 %€ r'   )ÚkeyúFile not found: é   )r  Úsimilar_files)rß   r1   r	  rÏ  rà   rá   r    r«   r–   r•   r›   r|   r"   rÎ   ÚsetÚmaxr  ÚSequenceMatcherÚratiorQ  r¾   Úsortr   )r6   r1   rÐ  r  Úbasename_no_extÚextÚ
lower_namerÑ  ÚscoredÚfÚlfÚscoreÚcommonrÄ  Úfps                  r%   r·  z*ShellFileOperations._suggest_similar_filesÒ  st  € ä—7‘7—?‘? 4Ó(Ò/¨CˆÜ—7‘7×#Ñ# DÓ)ˆÜŸ'™'×*Ñ*¨8Ó4°QÑ7×=Ñ=Ó?ˆÜ�g‰g×Ñ˜xÓ(¨Ñ+×1Ñ1Ó3ˆØ—^‘^Ó%ˆ
Ø—J‘J ¨×(>Ñ(>¸xÓ(HÐ'IÐI`ÐaÓbˆ	ØˆØ×Ñ !Ó#¨	×(8Ñ(8×(>Ñ(>Õ(@Ø×%Ñ%×+Ñ+Ó-×3Ñ3°DÓ9ó F�ÙØØ—W‘W“Y�Ø�Ø˜Ò#Ø‘EÜ—W‘W×%Ñ% aÓ(¨Ñ+×1Ñ1Ó3°ÒFØ‘EØ—]‘] :Ô.°*×2GÑ2GÈÔ2KØ‘EØ 2Ñ%Ø‘EØ˜:Ñ%¬#¨b«'°Aª+Ø‘EÙœRŸW™W×-Ñ-¨aÓ0°Ñ3×9Ñ9Ó;¸sÒBÜ  ›_¬s°2«wÑ6�FÜ˜6“{¤c¬#¨j«/¼3¸r»7Ó&CÀcÑ&IÒIØ "˜à˜A’:¤'×"9Ñ"9¸$À
ÈBÓ"O×"UÑ"UÓ"WÐ[^Ò"^Ø�EØ˜1”9Ø—M‘M 5¬"¯'©'¯,©,°xÀÓ*CÐ"DÖEð/Fð0 	�‰™ˆÔ(ÜÐ"2°4°&Ð 9ÐZ`ÐacÐbcÐZd×IeÑQVÐQRÐTVÊ"ÓIeÔfÐfùÓIes   ËK#c                 ó\  — | j                  |«      }| j                  |«      \  }}|dk(  r| j                  |«      S |dk(  r| j                  |«      S |dvr| j	                  ||«      S | j                  |«      rt        dd|¬«      S | j                  |«      \  }}|rt        d|t        ||«      ¬«      S | j                  d| j                  |«      › �«      }|j                  dk7  rt        d	|j                  › �¬
«      S t        t        |j                  «      «      \  }}t        ||¬«      S )zCWhole file as a plain string (no pagination/line numbers/clamping).r(  r)  r¾  T)r°  rv  r(   r»  r¨   r   r[  r  )r<   r(   )rû   r1  r·  r!  r6  rã   r   r;  r.   r    r«   r–   r•   r   r   )	r6   r1   r(   r2  rv  r8  Ú
cat_resultÚraw_contentrÄ  s	            r%   r;   z!ShellFileOperations.read_file_raw÷  s3  € à× Ñ  Ó&ˆØ ×4Ñ4°TÓ:Ñˆ	�6Ø�YÒØ×.Ñ.¨tÓ4Ð4Ø�]Ò"Ø×*Ñ*¨4Ó0Ð0ØÐ+Ñ+Ø×.Ñ.¨t°VÓ<Ð<Ø�>‰>˜$ÔÜ t°tÀyÔQÐQØ"&×"5Ñ"5°dÓ";Ñˆ	�<ÙÜ¨¸	ÔI]Ð^jÐluÓIvÔwÐwØ—Z‘Z $ t×'=Ñ'=¸dÓ'CÐ&DÐ EÓFˆ
Ø×Ñ 1Ò$ÜÐ&;¸J×<MÑ<MÐ;NÐ$OÔPÐPô $Ô$?À
×@QÑ@QÓ$RÓS‰ˆ�QÜ +¸ÔCÐCr'   Ú	max_bytesc                 óä  — | j                  |«      }| j                  |«      \  }}|dk(  rt        d|› �¬«      S |dk(  r| j                  |«      S |dvr| j	                  ||«      S |dk(  rt        d|› �¬«      S |�||kD  rt        |d|d	›d
|d	›d�¬«      S | j                  d| j                  |«      › �«      }|j                  dk7  rt        d|j                  › �¬«      S dj                  t        |j                  «      j                  «       «      }	 t        j                  |d¬«       t        ||d¬«      S # t        t        j                  j                   f$ r t        d|› �¬«      cY S w xY w)zERead binary-safe bytes (as base64) from any shell-backed environment.r(  rà  r  r)  r¾  r,  zCould not determine file size: zFile is too large (r²  z bytes, limit is ú))r(   r  z	base64 < r   zFailed to read binary file: r�   Tr¼   z*Backend returned invalid binary data for: )Úbase64_contentr(   rv  )rû   r1  r   r!  r6  r    r«   r–   r•   r¾   r   r|   rÁ   rÂ   rÅ   rÃ   rÄ   )r6   r1   rô  r(   r2  rÆ   Úcompacts          r%   Úread_file_bytesz#ShellFileOperations.read_file_bytes  s“  € à× Ñ  Ó&ˆØ ×4Ñ4°TÓ:Ñˆ	�6Ø�YÒÜÐ&6°t°fÐ$=Ô>Ð>Ø�]Ò"Ø×*Ñ*¨4Ó0Ð0ØÐ+Ñ+Ø×.Ñ.¨t°VÓ<Ð<Ø�ZÒÜÐ&EÀdÀVÐ$LÔMÐMØÐ  Y°Ò%:ÜØ#Ø+¨I°a¨=Ð8IÈ)ÐTUÈÐVWÐXôZð Zð —*‘*˜y¨×)?Ñ)?ÀÓ)EÐ(FÐGÓHˆØ×Ñ Ò!ÜÐ&BÀ7Ç>Á>ÐBRÐ$SÔTÐTØ—'‘'Ô5°g·n±nÓE×KÑKÓMÓNˆð	YÜ×Ñ˜W¨tÕ4ô ¨¸IÐQUÔVÐVøô œFŸO™O×1Ñ1Ð2ò 	YÜÐ&PÐQUÐPVÐ$WÔXÒXð	Yús   ÄD: Ä:2E/Å.E/c                 ó  — | j                  |«      }t        |d¬«      }|rt        |¬«      S d|›d�}| j                  |«      }|j                  dk7  r2t        d|› d|j
                  xs d	j                  «       xs d
› �¬«      S t        «       S )zžDelete a single file (directories rejected) via the backend's ``python -c``
        so one code path works on local/docker/ssh AND Windows shells (no ``rm``).ÚDelete©Úverbr  z-import shutil, pathlib, sys
p = pathlib.Path(a\  )
recursive = False
try:
    if p.is_dir() and not p.is_symlink():
        if recursive:
            shutil.rmtree(p)
        else:
            print('is a directory: ' + str(p), file=sys.stderr); sys.exit(2)
    else:
        p.unlink()
except FileNotFoundError:
    pass
except Exception as exc:
    print(str(exc), file=sys.stderr); sys.exit(1)
r   zFailed to delete ú: r�   zunknown error)rû   r	   r   rµ   r–   r•   r›   )r6   r1   Údeniedr²   rž   s        r%   rI   zShellFileOperations.delete_file(  s¤   € ð × Ñ  Ó&ˆÜ'¨°8Ô<ˆÙÜ VÔ,Ð,ð Ø $˜xð (BðBð 	ð  ×)Ñ)¨'Ó2ˆØ×Ñ˜qÒ ÜÐ'8¸¸¸bÀ&Ç-Á-ÒBUÐSU×A\ÑA\ÓA^ÒAqÐbqÐ@rÐ%sÔtÐtÜ‹}Ðr'   rJ   rK   c                 ól  — | j                  |«      }| j                  |«      }||fD ]  }t        |d¬«      }|sŒt        |¬«      c S  | j                  d| j	                  |«      › d| j	                  |«      › �«      }|j
                  dk7  rt        d|› d|› d	|j                  › �¬«      S t        «       S )
NÚMoverü  r  zmv r°   r   zFailed to move z -> rþ  )rû   r	   r   r    r«   r–   r•   )r6   rJ   rK   Úprÿ  rž   s         r%   rM   zShellFileOperations.move_fileF  s½   € Ø×Ñ Ó$ˆØ×Ñ Ó$ˆØ�s�ò 	1ˆAÜ+¨A°FÔ;ˆFÚÜ"¨Ô0Ò0ð	1ð —‘˜c $×"8Ñ"8¸Ó"=Ð!>¸aÀ×@VÑ@VÐWZÓ@[Ð?\Ð]Ó^ˆØ×Ñ˜qÒ Ü °s°e¸4À¸uÀBÀvÇ}Á}ÀoÐ%VÔWÐWÜ‹}Ðr'   z[\ud800-\udc7f\udd00-\udfff]c                 ó‚   — | j                   j                  |«      }|r"t        d|› d|j                  d«      ›d�¬«      S y)zÎRefuse content with a lone surrogate BEFORE any subprocess: letting it
        reach the pipe spawns a child that hangs or truncates the target via
        empty-stdin ``cat``. A regex scan needs no encode.úRefusing to write 'z0': content contains a lone surrogate character (r   zH) that cannot be encoded as UTF-8. The file was NOT created or modified.r  N)Ú_LONE_SURROGATE_RErU   r   Úgroup)r6   r1   r<   Úms       r%   Ú_reject_unencodablez'ShellFileOperations._reject_unencodableX  sV   € ð ×#Ñ#×*Ñ*¨7Ó3ˆÙÜØ% d Vð ,(Ø()¯©°«
 ~ð 6JðJôLð Lð r'   ré  c           	      ó˜   — |t         v rt        j                  |«      nd}|€y ||«      \  }}|s|dk(  ryt        d| › d|› d|› d�¬«      S )aG  Fail-closed pre-write gate for ``_FAIL_CLOSED_INPROC_EXTS`` (JSON/YAML/TOML):
        a structured-format write that doesn't parse is a corrupt write, so refuse
        before any bytes touch disk. Checked against the RAW content, before the
        BOM/CRLF shims (post-shim linting would false-positive on a BOM-marked file).NÚ__SKIP__r  z': candidate content fails z syntax validation (zC). The file was NOT created or modified. Fix the content and retry.r  )r   r   r™   r   )r1   ré  r<   Úlinterr+  Úerrs         r%   Ú_fail_closed_syntax_errorz-ShellFileOperations._fail_closed_syntax_errord  sr   € ð -0Ô3KÑ,K”×#Ñ# CÔ(ÐQUˆØˆ>ØÙ˜“/‰ˆˆCÙ�˜
Ò"ØÜØ! $ Ð'BØˆeÐ'¨ uð -BðBôDð 	Dr'   Úbodyc                 ó„   — | j                  |«      }|dk(  rd|› d�}n|dk(  rd|› d�}nd}d|› d|› d	|› d
|› dt        › d�S )aû  One shell command for the on-disk questions ``write_file`` asks. Two
        segments closed by a ``sentinel`` line: base64 of the first three bytes (BOM
        detection at the byte layer, same on-disk truth as ``_file_has_bom``), then
        ``body``: ``"cat"`` for the full text when pre-content is wanted, ``"sample"``
        for the 4 KB line-ending sample, or None for nothing. Gated on ``[ -f ]`` so a
        FIFO/device never reaches ``head``/``cat``; a missing path echoes ``MISSING_SENTINEL``.Úcatr¨   r©   r   zhead -c 4096 ú:r#  z ]; then head -c 3 z( 2>/dev/null | base64 2>/dev/null; echo z; r&  r'  )r«   r.  )r6   r1   rx   r  rü   Úbody_cmds         r%   Ú_write_probe_cmdz$ShellFileOperations._write_probe_cmdu  sz   € ð ×$Ñ$ TÓ*ˆØ�5Š=Ø˜c˜U ,Ð/‰HØ�XÒØ& s e¨<Ð8‰HàˆHà�s�eð Ø˜ÐEÀhÀZÈrØˆjð Ü)Ð*¨$ð0ð	1r'   Úwant_prec                 ó†  — |r|€d}n|sd}nd}t        t        «      }| j                  | j                  |||«      «      }|j                  xs d}||vrrt        |«      j                  «       t        k(  r|rt        |«      nd}d||fS t        j                  d||j                  t        |«      «       | j                  |||«      S t        ||«      }	|j                  dk7  st        |	«      dk7  r>t        j                  d	||j                  t        |	«      «       | j                  |||«      S |	\  }
}| j                  |
«      }|€)t        j                  d
|«       | j!                  ||«      }n$|j#                  t%        j&                  d«      «      }|dk(  r|r|}|rt        |«      }n|dk(  r|rt        |«      }nd}|||fS )aß  ``(has_bom, pre_content, original_line_ending)`` for ``path`` in ONE
        round-trip (replaces ``cat`` when pre-content is wanted, a ``head -c 4096``
        line-ending sample and a ``head -c 3`` BOM check). Semantics unchanged:
        pre-content is read only when wanted and not supplied; the line ending comes
        from pre-content when there is any, else from the sample; the BOM always comes
        from disk. An unparseable reply falls back to the separate probes.Nr  r   r�   Fzowrite_file: pre-write probe reply for %s has no sentinel (exit %s, %d chars); falling back to sequential probesr   rÙ  zpwrite_file: pre-write probe for %s returned exit %s with %d segments (want 2); falling back to sequential probeszWwrite_file: no usable base64 head for %s; paying one extra round-trip for the BOM proberÉ   )rv   Ú_WRITE_SENTINEL_PREFIXr    r  r•   r   r›   r.  r   rf  rg  r–   rÎ   Ú_probe_write_target_sequentialr}   r¸   r  r"   r   Úencode)r6   r1   r=   r  Ú	body_moderx   rl  rw   Úendingrm  Úhead_segr  Ú
head_bytesÚhas_boms                 r%   Ú_probe_write_targetz'ShellFileOperations._probe_write_target‰  sÆ  € ñ ˜Ð+Ø',‰IÙØ ‰IàˆIä Ô!7Ó8ˆØ—
‘
˜4×0Ñ0°°xÀÓKÓLˆØ—‘Ò# ˆØ˜6Ñ!Ü*¨6Ó2×8Ñ8Ó:Ô>NÒNÙ=HÔ,¨[Ô9Èd�Ø˜k¨6Ð1Ð1Ü�L‰LðIà�e—o‘o¤s¨6£{ô4ð ×6Ñ6°t¸[È(ÓSÐSä" 6¨8Ó4ˆØ�?‰?˜aÒ¤3 x£=°AÒ#5Ü�L‰LðGà�e—o‘o¤s¨8£}ô6ð ×6Ñ6°t¸[È(ÓSÐSØ!‰ˆ�$à×/Ñ/°Ó9ˆ
ØÐä�L‰Lð/Ø04ô6ð ×(Ñ(¨¨{Ó;‰Gà ×+Ñ+¬I×,<Ñ,<¸WÓ,EÓFˆGà˜Ò¡$ØˆKÙÜ(¨Ó5‰FØ˜(Ò"¡tÜ(¨Ó.‰FàˆFØ˜ VÐ+Ð+r'   c                 óH  — |r:|€8| j                  |«      }|j                  dk(  r|j                  r|j                  }|rt        |«      }nD| j	                  |d«      }|j                  dk(  r!|j                  rt        |j                  «      nd}| j                  ||«      ||fS )zµPre-compound form of ``_probe_write_target``: one exec per question. A
        failed ``cat`` leaves pre_content None so the lint-delta and LSP consumers
        degrade gracefully.Nr   i   )r¬   r–   r•   r   r±   r  )r6   r1   r=   r  r¿  r  Úheads          r%   r  z2ShellFileOperations._probe_write_target_sequentialÂ  s—   € ñ
 ˜Ð+ØŸ)™) D›/ˆKØ×$Ñ$¨Ò)¨k×.@Ò.@Ø)×0Ñ0�ÙÜ(¨Ó5‰Fà—:‘:˜d DÓ)ˆDØ9=¿¹È1Ò9LÐQU×Q\ÒQ\Ô(¨¯©Ô5ÐbfˆFØ×!Ñ! $¨Ó4°kÀ6ÐIÐIr'   Úcontent_bytesc                 ó†  — 	 | j                  d| j                  |«      › d�«      }|j                  dk(  r~|j                  j	                  «       rd|j                  j	                  «       j                  «       d   }|t        j                  |«      j                  «       k7  rdt        d|› d�¬«      fS yy	# t        $ r Y y	w xY w)
zãCompare the on-disk sha256 to the intended bytes: ``(verified, error)``.
        The explicit flag saves the model a confirming re-read; a mismatch is a hard
        error. ``verified`` is None when the hash could not be taken.z
sha256sum r©   r   Fú#Post-write verification failed for u{   : on-disk content hash differs from the intended write. The write did not persist correctly â€” re-read the file and retry.r  )TN)NN)r    r«   r–   r•   r›   r|   r’  r“  Ú	hexdigestr   Ú	Exception)r6   r1   r!  Úhash_resultÚdisk_shas        r%   Ú_verify_written_hashz(ShellFileOperations._verify_written_hashÒ  sÌ   € ð	ØŸ*™* z°$×2HÑ2HÈÓ2NÐ1OÈ|Ð%\Ó]ˆKØ×$Ñ$¨Ò)¨k×.@Ñ.@×.FÑ.FÔ.HØ&×-Ñ-×3Ñ3Ó5×;Ñ;Ó=¸aÑ@�ØœwŸ~™~¨mÓ<×FÑFÓHÒHØ ¤+Ø=¸d¸Vð D%ð %ô#'ð 'ð 'ð
 "ð øô ò 	ØØð	ús   ‚B/B4 Â4	C Â?C c                 ó0  — | j                  |«      }t        |«      }|rt        |¬«      S | j                  ||«      }|�|S t        j
                  j                  |«      d   j                  «       }| j                  |||«      }|�|S |t        v xs | j                  |«      }| j                  |||«      \  }}}	|	dk(  rt        |d«      }|rt        |«      s	t        |z   }| j                  |«       t!        t        j
                  j#                  |«      «      }
|j%                  dd«      }| j'                  ||«      }|j(                  dk7  rt        d|j*                  › �¬«      S | j-                  ||«      \  }}|�|S | j/                  |||¬	«      }d}|j0                  s|j2                  r| j5                  |||¬	«      xs d}t        t7        |«      |
|t9        j:                  |«      j=                  «       |r|j?                  «       |¬
«      S d|¬
«      S )u€  Write content atomically, creating parent directories as needed.

        Order: deny list â†’ lone-surrogate refusal â†’ fail-closed syntax gate on the
        CANDIDATE content (JSON/YAML/TOML) â†’ one compound on-disk probe
        (pre-content when wanted, CRLF, BOM; see ``_probe_write_target``) â†’
        CRLF/BOM preservation â†’ LSP baseline snapshot â†’ atomic write (content rides
        stdin: no ARG_MAX limit) â†’ sha256 verification â†’ lint delta â†’ LSP
        diagnostics when syntax is clean. ``pre_content``: pre-edit content the
        caller already has (skips the read); BOM detection always probes disk.
        r  NrW   ú
rÉ   Úsurrogateescaper   zFailed to write file: ©r=   Úpost_content)Úbytes_writtenÚdirs_createdÚverifiedÚ_content_sha256ÚlintÚlsp_diagnostics) rû   r	   r   r  rß   r1   rà   rá   r  r   Ú_lsp_handles_extensionr  r   r   r   Ú_snapshot_lsp_baselinere   r	  r  r  r–   r•   r(  Ú_check_lint_deltaÚsuccessÚskippedÚ_maybe_lsp_diagnosticsrÎ   r’  r“  r$  Úto_dict)r6   r1   r<   r=   rÿ  Úrefusedré  r  r  Úoriginal_endingr/  r!  Úwrite_resultÚcontent_verifiedÚverify_errorÚlint_resultr3  s                    r%   r?   zShellFileOperations.write_fileå  s)  € ð × Ñ  Ó&ˆÜ'¨Ó-ˆÙÜ VÔ,Ð,Ø×*Ñ*¨4°Ó9ˆØÐØˆNÜ�g‰g×Ñ˜tÓ$ QÑ'×-Ñ-Ó/ˆØ×0Ñ0°°s¸GÓDˆØÐØˆNð œ.Ð(ÒL¨D×,GÑ,GÈÓ,LˆØ04×0HÑ0HÈÈ{Ð\dÓ0eÑ-ˆ�˜oð ˜fÒ$Ü-¨g°vÓ>ˆGÙœ8 GÔ,Ü 'Ñ)ˆGà×#Ñ# DÔ)ô œBŸG™GŸO™O¨DÓ1Ó2ˆð  Ÿ™ wÐ0AÓBˆØ×)Ñ)¨$°Ó8ˆØ×!Ñ! QÒ&ÜÐ'=¸l×>QÑ>QÐ=RÐ%SÔTÐTØ)-×)BÑ)BÀ4ÈÓ)WÑ&Ð˜,ØÐ#ØÐà×,Ñ,¨T¸{ÐY`Ð,Óaˆð *.ˆØ×Ò +×"5Ò"5Ø"×9Ñ9¸$ÈKÐfmÐ9ÓnÒvÐrvˆOÜÜ˜mÓ,¸<ÐRbÜ#ŸN™N¨=Ó9×CÑCÓEÙ*5�×$Ñ$Ó&ÐQ`ôbð 	bð <@ÐQ`ôbð 	br'   r@   rA   Úmatch_countr  c                 ó°   — ddl m}m}  ||||«      rt        ddd|› d�¬«      S |xs d|› �}		 |	 ||	|||«      z  }	t        |	¬«      S # t        $ r Y Œw xY w)	a9  PatchResult for a failed fuzzy match. Already-applied detection first: the
        most common production failure is a re-send of an edit that already landed,
        and a success-shaped no-op stops the model burning turns on re-reads.
        Otherwise attach a best-effort "Did you mean?" snippet to the error.r   )Úformat_no_match_hintÚis_already_appliedTuT   File already contains the target text â€” the edit appears to be already applied to z0. No write performed; do not re-send this patch.)r7  Ú	no_changer¹  z'Could not find match for old_string in r  )Útools.fuzzy_matchrC  rD  r   r%  )
r6   r1   r<   r@   rA   rA  r  rC  rD  Úerr_msgs
             r%   Ú_no_match_resultz$ShellFileOperations._no_match_result#  sŠ   € ÷ 	OÙ˜g z°:Ô>ÜØ¨ð8Ø8<°vð ><ð<ô>ð >ð ÒKÐDÀTÀFÐKˆð	ØÑ+¨G°[À*ÈgÓVÑVˆGô  Ô)Ð)øô ò 	Ùð	ús   ¯A	 Á		AÁAc           
      ót  — | j                  |«      }|j                  dk7  rt        d|› �¬«      S t        |j                  «      \  }}|j                  dd«      j                  dd«      }|j                  dd«      j                  dd«      }||k7  r(t        d|› dt        |«      › d	t        |«      › d
�¬«      S y)af  Re-read ``path`` and confirm the intended bytes landed; error result or None.
        Catches silent persistence failures (FS oddities, races, truncated pipe).
        Line endings are normalized first (Windows text-mode ``open()`` writes LF as
        CRLF) and the re-read's BOM stripped (``new_content`` is the BOM-less
        string we matched against).r   z2Post-write verification failed: could not re-read r  r*  rz   úr#  z5: on-disk content differs from intended write (wrote z chars, read back zb chars after normalizing line endings). The patch did not persist. Re-read the file and try again.N)r¬   r–   r   r   r•   r  rÎ   )r6   r1   r  Úverify_resultÚbomlessrÄ  Úon_diskÚintendeds           r%   Ú_verify_patch_persistedz+ShellFileOperations._verify_patch_persisted8  sÍ   € ð Ÿ	™	 $›ˆØ×"Ñ" aÒ'ÜÐ'YÐZ^ÐY_Ð%`ÔaÐaÜ × 4Ñ 4Ó5‰
ˆ�Ø—/‘/ &¨$Ó/×7Ñ7¸¸dÓCˆØ×&Ñ& v¨tÓ4×<Ñ<¸TÀ4ÓHˆØ�hÒÜØ5°d°Vð <ä˜h›-˜Ð(:Ü�w“<�.ð !MðMôOð Oð r'   rB   c                 óÞ  — | j                  |«      }t        |«      }|rt        |¬«      S | j                  |«      }|j                  dk7  rt        |j
                  xs d|› �¬«      S |j                  }t        |«      \  }}	ddlm	}
  |
||||«      \  }}}}|s|dk(  r| j                  ||||||«      S t        |«      }|rt        ||«      }| j                  |||¬«      }|j                  rt        d|j                  › �¬«      S | j                  ||«      }|�|S | j!                  |||¬«      }t        d	| j#                  |||«      |g|r|j%                  «       nd|j&                  ¬
«      S )z“Replace text in a file using fuzzy matching (``old_string`` must be
        unique unless ``replace_all``). Returns a PatchResult with diff + lint.r  r   r[  )Úfuzzy_find_and_replace)r=   zFailed to write changes: Nr,  T)r7  ÚdiffÚfiles_modifiedr2  r3  )rû   r	   r   r¬   r–   r—   r•   r   rF  rQ  rH  r   r   r?   r  rO  r6  r  r:  r3  )r6   r1   r@   rA   rB   rÿ  r¿  ró  r<   rÄ  rQ  r  rA  Ú	_strategyr  Úfile_endingr=  r?  r@  s                      r%   rD   z!ShellFileOperations.patch_replaceM  s�  € ð × Ñ  Ó&ˆÜ'¨Ó-ˆÙÜ VÔ,Ð,Ø—i‘i “oˆØ× Ñ  AÒ%Ü [×%:Ñ%:Ò%\Ð@UÐVZÐU[Ð>\Ô]Ð]ð "×(Ñ(ˆÜ Ó,‰
ˆ�å<Ù5KØ�Z ¨[ó6:Ñ2ˆ�[ )¨Uá�K 1Ò$Ø×(Ñ(¨¨w¸
ÀJÐP[Ð]bÓcÐcô *¨'Ó2ˆÙÜ1°+¸{ÓKˆKØ—‘ t¨[Àk�ÓRˆØ×ÒÜÐ'@À×ASÑASÐ@TÐ%UÔVÐVØ×3Ñ3°D¸+ÓFˆØÐ#ØÐØ×,Ñ,¨T¸wÐU`Ð,ÓaˆÜØ˜t×1Ñ1°'¸;ÈÓMÐ_cÐ^dÙ*5�×$Ñ$Ô&¸4à(×8Ñ8ô	:ð 	:r'   rE   c                 ó\   — ddl m}m}  ||«      \  }}|rt        d|› �¬«      S  ||| «      S )zyApply a V4A format patch (``*** Begin Patch`` / ``*** Update File:`` /
        ``@@ hint @@`` hunks / ``*** End Patch``).r   )Úparse_v4a_patchÚapply_v4a_operationszFailed to parse patch: r  )Útools.patch_parserrW  rX  r   )r6   rE   rW  rX  Ú
operationsÚparse_errors         r%   rG   zShellFileOperations.patch_v4at  s:   € ÷ 	MÙ"1°-Ó"@Ñˆ
�KÙÜÐ'>¸{¸mÐ%LÔMÐMÙ# J°Ó5Ð5r'   rN   rO   rP   rQ   rR   rS   c
                 ó@  — t        ||«      \  }}|dk(  r|	dvrt        d|	›d�¬«      S | j                  |«      }| j                  |«      }
|
j                  }|
j
                  rt        |
j
                  ¬«      S d|vrd|vrt        d|› d	�¬«      S d|v r.| j                  |||||||||	«	      }|�|S | j                  |«      S | j                  |||||||||	«	      }| j                  |«      }|r/|j                  s#d
j                  d„ |D «       «      }d|› d�|_        |S )u  Search for content (regex, ``target="content"``) or files (glob,
        ``target="files"``). ``output_mode``: "content", "files_only" or "count";
        ``context``: lines of context around matches; ``order``: file-search
        ordering â€” fast "discovery" or exact "modified" time.Úfiles>   Úmodifiedr^   zInvalid file search order z%; expected 'discovery' or 'modified'.r  ÚexistsÚ	not_foundr4  r5  r+   c              3   óD   K  — | ]  }|j                  d «      d   –— Œ y­w)rƒ   rè   Nr{   )r×   Úitems     r%   rÙ   z-ShellFileOperations.search.<locals>.<genexpr>Ÿ  s   è ø€ ÒK¸ §
¡
¨3£°Õ 3ÑKùs   ‚ z[Skipped macOS protected folders during broad search to avoid an unattended privacy prompt: z@. Search a protected folder directly when access is intentional.)r   r   rû   Ú_path_exists_prober•   r—   Ú_try_multi_path_searchÚ_path_not_found_resultÚ_dispatch_searchÚ_macos_search_exclusionsr  r¾   Úwarning)r6   rN   r1   rO   rP   r3   r2   rQ   rR   rS   rl  Úexists_probeÚmultirž   Ú
exclusionsr8  s                   r%   rU   zShellFileOperations.search  st  € ô 4°F¸EÓB‰ˆ�Ø�WÒ Ð.GÑ!GÜØ3°E°9ð =4ð 4ô6ð 6ð × Ñ  Ó&ˆØ×'Ñ'¨Ó-ˆØ—|‘|ˆØ�?Š?Ü e§o¡oÔ6Ð6Ø˜<Ñ'¨K¸|Ñ,KÜÐ)ZÐ[_ÐZ`ð alð (lô nð nà˜,Ñ&à×/Ñ/Ø˜˜v y°%¸ÀÈgÐW\ó^ˆEàÐ Ø�Ø×.Ñ.¨tÓ4Ð4Ø×&Ñ& w°°f¸iÈÐPVØ'2°G¸UóDˆà×2Ñ2°4Ó8ˆ
Ù˜fŸlšlØ—i‘iÑKÀ
ÔKÓKˆGð1Ø18°	ð :>ð>ð ŒNð ˆr'   rY   )NNN)rÓ   )rW   )r*  rV   rZ   r[   )Hr_   r`   ra   rb   rc   rŠ   rd   r
   r    re   r¦   r¬   r±   rµ   r¹   Ústaticmethodr   r™  r¸   rÐ   rÝ   rã   rò   rû   r«   r  r  r  r  r   r!  Útupler1  r6  r;  rJ  rK  rX  r7   r`  ra  r�  rd  re  ri  rb  rj  rË  r¶  r·  r;   rù  r   rI   rM   r¿   Úcompiler  r  r  r  r  r  r(  r?   r   rH  rO  rD   rG   r   rU   r5   r'   r%   r   r   ª   sA  „ ññ
D¨#ó 
Dð CGØ $ñV˜Sð V sð V¸Cð VØðVØ)6óVð@
( ð 
(¨ó 
(ðM˜ð M ó MðZ˜#ð Z sð Z¨}ó Zð¨3ð °=ó ñ9 sð 9°Có 9ð ð Cð ¨H°U©Oò ó ðð ð¨ð °$ò ó ðñ6 cð ¸3ð È$ó ðE˜cð E dó EñM¨ð M¸#ð MÀcó Mð" ð ¨ó ð.H Sð H¨Só Hð7¨3ð 7°3ó 7ð66 #ð 66°ð 66¸ó 66ñpK #ð K°H¸S±Mð KÈTó Kð?¨ð ?¸3ð ?È#ð ?ÐRUó ?ð ðI ð I¨ò Ió ðIð!¨ð !°°c¸3°h±ó !ñ8h¨3ð h¸ð hÐT^ó hðA 3ð A¨5°°xÀ±Ð1FÑ+Gó Að$ (ÐØÐðK? Cð K?°ð K?¸Sð K?Ø#&ðK?Ø+AóK?ñZYP˜cð YP¨3ð YP¸3ð YPÈ*ó YPðv
B dó 
BðV cð V°3ð V¸sð VÀzó Vðp ðZ¨#ð Z°*ò Zó ðZð1 Cð 1°ð 1Àð 1Ø*-ð1Ø9<ð1ØADó1ð21 sð 1°Cð 1Àð 1È
ó 1ð"A cð A°3ð A¸sð AØ%(ðAØ8@À¹ðAØLVóAð"0P¨#ð 0P°sð 0PÀ3ð 0PÈ:ó 0Pðd)?°ð )?Àð )?ÐPSð )?Ø+.ð)?Ø;>ð)?à6>¸t±nð)?àISó)?ðX€Lð¨3ð °8¸C±=ó ð6#g¨3ð #g°:ó #gðJD #ð D¨*ó Dñ.W Cð W°H¸S±Mð WÈZó Wð4 ð ¨ó ð<
˜Sð 
 sð 
¨{ó 
ð  $˜Ÿ™Ð$CÓDÐð
¨ð 
°cð 
¸hÀ{Ñ>Só 
ð ðD¨ð D°#ð DÀð DÈÐQ\ÑH]ò Dó ðDð 1 Sð 1°Cð 1¸xÈ¹}ð 1ÐQTó 1ð(7,¨ð 7,¸(À3¹-ð 7,ÐSWð 7,Ø!& t¨X°c©]¸HÀS¹MÐ'IÑ!Jó7,ðrJ°3ð JÀXÈcÁ]ð JÐ^bð JØ,1°$¸À¹ÀxÐPSÁ}Ð2TÑ,UóJð ¨ð ¸Uð ÀuÈXÐVZÉ^Ð]eÐfqÑ]rÐMrÑGsó ñ&:b˜sð :b¨Sð :b¸xÈ¹}ð :bÐXcó :bð|* Sð *°3ð *ÀCð *Ø%(ð*Ø7:ð*ØCKÈCÁ=ð*ØU`ó*ð*¨Cð ¸cð ÀhÈ{ÑF[ó ð, +0ñ%: #ð %:°3ð %:ÀCð %:Ø#'ð%:Ø4?ó%:ðN6 sð 6¨{ó 6ð CLØOPØ<=Ø'ñ%˜cð %¨ð %¸Cð %Ø" 3™-ð%Ø7:ð%ØILð%àð%à69ð%ð ð%ð -9ô%r'   r   )ÚAny)ÚClassVar)ÚList)Úbuild_write_denied_paths)Úbuild_write_denied_prefixes)Ú	dataclass)ÚfieldrX   )útools.file_operations_commonÚDEFAULT_READ_LIMIT)rv  ÚDEFAULT_READ_OFFSET)rv  ÚDEFAULT_SEARCH_LIMIT)rv  ÚDEFAULT_SEARCH_OFFSET)ztools.file_operations_lintÚLINTERS)rv  Ú
LintResult)ztools.transcription_commonÚMAX_FILE_SIZE)zagent.search_policyÚSEARCH_PRUNE_DIR_NAMES)rv  ÚSearchMatch)úagent.file_safetyrr  )r€  rs  )ÚtoolsÚ	interrupt)rw  rx  ry  rz  r{  r|  r}  r~  r  rr  rs  Útool_interruptc                 óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncerW   )	Ú_PLUGIN_COMPAT_LAZYr™   ÚAttributeErrorr_   Ú	importlibÚhermes_cli.plugin_compatr…  r…   Úimport_module)r$   rO   rˆ  r…  s       r%   Ú__getattr__r‹  Î  se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐAr'   )Srb   rÁ   rÃ   rß   r¿   r€  r  r’  rL  Úloggingrt   rÉ  Úabcr   r   Útypingr   r   Úpathlibr   Útools.binary_extensionsr   Úagent.file_safetyr	   Útools.file_operations_commonr
   r   r   r   r   r   r   r   r   r   r   r   r   Útools.file_operations_lintr   r   r   Útools.file_operations_searchr   Ú	getLoggerr_   rf  rc   rö   Ú_HOMEr   rm  Ú__annotations__r™  r&   rd   r.   r0   râ   r-  r.  rc  r  rv   Úlistr}   r   ro  rp  rq  rr  rs  Údataclassesrt  ru  Ú	posixpathÚ	threadingÚ	MAX_LINESÚMAX_LINE_LENGTHÚWRITE_DENIED_PATHSÚWRITE_DENIED_PREFIXESr†  r‹  r5   r'   r%   ú<module>r      s²  ðòó Û Û 	Û 	Û 
Û Û Û Û Û Û ß #ß !Ý å 8Ý 4÷Y÷ Y÷ Yõ Y÷ [Ñ ZÝ 4à	ˆ×	Ñ	˜8Ó	$€ñ 	ˆIˆD�I‰I‹KÓ€ðÐ �5ó ð<	 %ð 	¨Có 	ð
G ¨%¡ð 
G¸Sð 
GÀSó 
Gô%+�Sô %+òV NÐ ð 0Ð ð
 (Ð à&Ð Ø'Ð ð0˜#ð 0 #ó 0ð)˜Cð )¨3ð )°4¸±9ó )ôz˜) [°.ô zõB( Ý Ý Ý 6Ý 9Ý !Ý Û Û à€	à€á-¨eÓ4Ð á3°EÓ:Ð ð QØRØTØVØ8Ø@ØDØOØBØ QØ#WØ,ñÐ ó Br'   