
    i/U                        d Z ddlZddlZddlmZmZ ddlmZmZm	Z	m
Z
 ddlmZ  G d de          Ze G d d	                      Ze G d
 d                      Ze G d d                      Zdede	ee         ee         f         fdZdededefdZdee         de
dee         fdZdee         de
ddfdZdede
de	eef         fdZdede
de	eef         fdZdede
de	eef         fdZdede
de	eef         fdZdS )a  
V4A Patch Format Parser

Parses the V4A patch format used by codex, cline, and other coding agents.

V4A Format:
    *** Begin Patch
    *** Update File: path/to/file.py
    @@ optional context hint @@
     context line (space prefix)
    -removed line (minus prefix)
    +added line (plus prefix)
    *** Add File: path/to/new.py
    +new file content
    +line 2
    *** Delete File: path/to/old.py
    *** Move File: old/path.py -> new/path.py
    *** End Patch

Usage:
    from tools.patch_parser import parse_v4a_patch, apply_v4a_operations
    
    operations, error = parse_v4a_patch(patch_content)
    if error:
        print(f"Parse error: {error}")
    else:
        result = apply_v4a_operations(operations, file_ops)
    N)	dataclassfield)ListOptionalTupleAny)Enumc                       e Zd ZdZdZdZdZdS )OperationTypeaddupdatedeletemoveN)__name__
__module____qualname__ADDUPDATEDELETEMOVE     7/home/ubuntu/.hermes/hermes-agent/tools/patch_parser.pyr   r   &   s"        
CFFDDDr   r   c                   (    e Zd ZU dZeed<   eed<   dS )HunkLinezA single line in a patch hunk.prefixcontentN)r   r   r   __doc__str__annotations__r   r   r   r   r   -   s(         ((KKKLLLLLr   r   c                   \    e Zd ZU dZdZee         ed<    ee	          Z
ee         ed<   dS )Hunkz!A group of changes within a file.Ncontext_hintdefault_factorylines)r   r   r   r   r#   r   r   r    r   listr&   r   r   r   r   r   r"   r"   4   sM         ++"&L(3-&&&!E$777E4>77777r   r"   c                       e Zd ZU dZeed<   eed<   dZee         ed<    e	e
          Zee         ed<   dZee         ed<   dS )	PatchOperationz"A single operation in a V4A patch.	operation	file_pathNnew_pathr$   hunksr   )r   r   r   r   r   r    r   r,   r   r   r'   r-   r   r"   r   r   r   r   r)   r)   ;   sv         ,,NNN"Hhsm"""d333E4:333!GXc]!!!!!r   r)   patch_contentreturnc                    |                      d          }g }d}d}t          |          D ]\  }}d|v sd|v r|}d|v sd|v r|} n|d}|t          |          }|dz   }d}d}||k     rh||         }t          j        d	|          }	t          j        d
|          }
t          j        d|          }t          j        d|          }|	r~|r8|r!|j        r|j                            |           |                    |           t          t          j
        |	                    d                                                    }d}n|
r|r8|r!|j        r|j                            |           |                    |           t          t          j        |
                    d                                                    }t                      }n|r|r8|r!|j        r|j                            |           |                    |           t          t          j        |                    d                                                    }|                    |           d}d}n]|r|r8|r!|j        r|j                            |           |                    |           t          t          j        |                    d                                          |                    d                                                    }|                    |           d}d}n|                    d          re|ra|r!|j        r|j                            |           t          j        d|          }|r|                    d          nd}t          |          }n&|r#|r |t                      }|                    d          r1|j                            t%          d|dd                              n|                    d          r1|j                            t%          d|dd                              n|                    d          r1|j                            t%          d|dd                              n>|                    d          rn(|j                            t%          d|                     |dz  }||k     h|r8|r!|j        r|j                            |           |                    |           |s|dfS g }|D ]}|j        s|                    d           |j        t          j
        k    r%|j        s|                    d|j        d           |j        t          j        k    r%|j        s|                    d|j        d           |rg dd                    |          z   fS |dfS )a  
    Parse a V4A format patch.
    
    Args:
        patch_content: The patch text in V4A format
    
    Returns:
        Tuple of (operations, error_message)
        - If successful: (list_of_operations, None)
        - If failed: ([], error_description)
    
Nz*** Begin Patchz***Begin Patchz*** End Patchz***End Patch   z\*\*\*\s*Update\s+File:\s*(.+)z\*\*\*\s*Add\s+File:\s*(.+)z\*\*\*\s*Delete\s+File:\s*(.+)z)\*\*\*\s*Move\s+File:\s*(.+?)\s*->\s*(.+))r*   r+      )r*   r+   r,   z@@z@@\s*(.+?)\s*@@)r#   +- \zOperation with empty file pathzUPDATE z: no hunks foundzMOVE z2: missing destination path (expected 'src -> dst')zParse error: z; )split	enumeratelenrematchr&   r-   appendr)   r   r   groupstripr   r"   r   r   
startswithr   r+   r*   r,   join)r.   r&   
operations	start_idxend_idxiline
current_opcurrent_hunkupdate_match	add_matchdelete_match
move_match
hint_matchhintparse_errorsops                    r   parse_v4a_patchrR   E   s    %%E')J IGU##  4$$(8D(@(@II$$$(>(>GE )? 	e** 	AA+/J#'L
g++Qx x A4HHH;TBB	x A4HHXJDQQ
 Q	? . :L$6 :$++L999!!*---''.&,,Q//5577  J  LL D	? . :L$6 :$++L999!!*---''+#//!,,2244  J  66LL 8	? . :L$6 :$++L999!!*---''.&,,Q//5577  J j)))JLL *	? . :L$6 :$++L999!!*---'',$**1--3355#))!,,2244  J
 j)))JLL__T"" 	? 7 :L$6 :$++L999  X&8$??
.8Bz''***d#666 	?D 	?##vvs## ?"))(3QRR*A*ABBBB%% 	?"))(3QRR*A*ABBBB%% ?"))(3QRR*A*ABBBB&& ? "))(3*=*=>>>	Qy g++~  & 	2L. 	2##L111*%%%   4 L l l| 	B @AAA<=//// J", J J JKKK<=---bk- j j j jkkk =?TYY|%<%<<<<tr   textpatternc                 `    d}d}	 |                      ||          }|dk    rn|dz  }|dz   }(|S )z9Count non-overlapping occurrences of *pattern* in *text*.r   Tr2   r3   )find)rS   rT   countstartposs        r   _count_occurrencesrZ      sN    EEii''"99
a Lr   rC   file_opsc           
         ddl m} g }| D ]}|j        t          j        k    r|                    |j                  }|j        r%|                    |j         d|j                    _|j	        }|j
        D ]O}d |j        D             }|sw|j        rot          ||j                  }	|	dk    r&|                    |j         d|j         d           n.|	dk    r(|                    |j         d|j         d|	 d	           d
                    |          }
d |j        D             }d
                    |          } |||
|d          \  }}}}|dk    rk|j        rd|j         dnd}|j         d| d|rd| ndz   }	 ddl m} | ||||
|          z  }n# t           $ r Y nw xY w|                    |           M|}Q|j        t          j        k    r@|                    |j                  }|j        r|                    |j         d           |j        t          j        k    r|j        s|                    |j         d           P|                    |j                  }|j        r|                    |j         d           |                    |j                  }|j        s|                    |j         d           |S )aJ  Validate all operations without writing any files.

    Returns a list of error strings; an empty list means all operations
    are valid and the apply phase can proceed safely.

    For UPDATE operations, hunks are simulated in order so that later
    hunks validate against post-earlier-hunk content (matching apply order).
    r   fuzzy_find_and_replace: c                 .    g | ]}|j         d v |j        S ))r7   r6   r   r   .0ls     r   
<listcomp>z(_validate_operations.<locals>.<listcomp>
  s&    XXXaZAWAW	AWAWAWr   z#: addition-only hunk context hint 'z' not foundr3   ' is ambiguous (z occurrences)r1   c                 .    g | ]}|j         d v |j        S ))r7   r5   ra   rb   s     r   re   z(_validate_operations.<locals>.<listcomp>  s&     Y Y Yq!(jBXBXBXBXBXr   Freplace_all'z	(no hint)z: hunk z
 not foundu    —  format_no_match_hintz: file not found for deletionz): MOVE operation missing destination pathz : source file not found for moveu5   : destination already exists — move would overwrite)tools.fuzzy_matchr^   r*   r   r   read_file_rawr+   errorr>   r   r-   r&   r#   rZ   rB   rm   	Exceptionr   r   r,   )rC   r[   r^   errorsrQ   read_result	simulatedhunksearch_linesoccurrencessearch_patternreplace_linesreplacementnew_simulatedrW   	_strategymatch_errorlabelmsgrm   
src_result
dst_results                         r   _validate_operationsr      s    988888F C C<=///"00>>K  DD1BDDEEE#+I ). ).XX4:XXX# ( &8DDU&V&V&!++"MM#%< !C !C$($5!C !C !C    )1__"MM#%< !? !?$($5!? !?$/!? !? !?  
 !%<!8!8 Y YDJ Y Y Y"ii66?U?U~{@ @ @<ui A::8<8IZ4 14444{E<AAAAA4?G0;000RI JJJJJJ33KXabbb$   MM#&&&& !.IIS).V \]111"00>>K  NLLLMMM\]///; XXXYYY!//==J QOOOPPP!//<<J# {YYY   Ms   F
F+*F+PatchResultc                    ddl m} t          | |          }|r- |ddd                    d |D                       z             S g }g }g }g }g }| D ]~}		 |	j        t
          j        k    rwt          |	|          }
|
d         r7|                    |	j	                   |                    |
d                    n|                    d	|	j	         d
|
d                     n|	j        t
          j
        k    rwt          |	|          }
|
d         r7|                    |	j	                   |                    |
d                    nE|                    d|	j	         d
|
d                     n|	j        t
          j        k    rt          |	|          }
|
d         r@|                    |	j	         d|	j                    |                    |
d                    n|                    d|	j	         d
|
d                     n|	j        t
          j        k    rtt!          |	|          }
|
d         r6|                    |	j	                   |                    |
d                    n&|                    d|	j	         d
|
d                     ;# t"          $ r8}|                    d|	j	         d
t%          |                      Y d}~xd}~ww xY wi }||z   D ]>}t'          |d          r,|                    |          }|                                ||<   ?d                    |          }|r6 |d|||||r|nddd                    d |D                       z             S  |d|||||r|nd          S )a  Apply V4A patch operations using a file operations interface.

    Uses a two-phase validate-then-apply approach:
    - Phase 1: validate all operations against current file contents without
      writing anything. If any validation error is found, return immediately
      with no filesystem changes.
    - Phase 2: apply all operations. A failure here (e.g. a race between
      validation and apply) is reported with a note to run ``git diff``.

    Args:
        operations: List of PatchOperation from parse_v4a_patch
        file_ops: Object with read_file_raw, write_file methods

    Returns:
        PatchResult with results of all operations
    r   )r   Fz2Patch validation failed (no files were modified):
r1   c              3       K   | ]	}d | V  
dS u     • Nr   rc   es     r   	<genexpr>z'apply_v4a_operations.<locals>.<genexpr>f  s(      FFqlqllFFFFFFr   )successrp   r3   zFailed to add r_   zFailed to delete  -> zFailed to move zFailed to update zError processing N_check_lintuM   Apply phase failed (state may be inconsistent — run `git diff` to assess):
c              3       K   | ]	}d | V  
dS r   r   r   s     r   r   z'apply_v4a_operations.<locals>.<genexpr>  s(      ;;qlqll;;;;;;r   )r   difffiles_modifiedfiles_createdfiles_deletedlintrp   T)r   r   r   r   r   r   )tools.file_operationsr   r   rB   r*   r   r   
_apply_addr>   r+   r   _apply_deleter   _apply_mover,   r   _apply_updaterq   r   hasattrr   to_dict)rC   r[   r   validation_errorsr   r   r   	all_diffsrr   rQ   resultr   lint_resultsflint_resultcombined_diffs                   r   apply_v4a_operationsr   K  s4   & 211111 -ZBB 
{GIIFF4EFFFFFG
 
 
 	
 NMMIF #H #H"	H|}000#B11!9 P!((666$$VAY////MM"N2<"N"N6!9"N"NOOOO!555&r844!9 S!((666$$VAY////MM"Qbl"Q"QfQi"Q"QRRRR!333$R22!9 Q"))R\*L*Lr{*L*LMMM$$VAY////MM"OBL"O"OF1I"O"OPPPP!555&r844!9 S"))",777$$VAY////MM"Qbl"Q"QfQi"Q"QRRR 	H 	H 	HMMFblFFc!ffFFGGGGGGGG	H Lm+ 4 48]++ 	4"..q11K)1133LOIIi((M 

{)''!-74bII;;F;;;;;<	
 	
 	
 		
 ;%##)3\\t   s   H5J
K-K

KrQ   c                 Z   g }| j         D ]1}|j        D ]'}|j        dk    r|                    |j                   (2d                    |          }|                    | j        |          }|j        r	d|j        fS d| j         d}|d                    d |D                       z  }d|fS )zApply an add file operation.r5   r1   Fz--- /dev/null
+++ b/c              3       K   | ]	}d | V  
dS )r5   Nr   )rc   rG   s     r   r   z_apply_add.<locals>.<genexpr>  s(      ;;Tj$jj;;;;;;r   T)	r-   r&   r   r>   r   rB   
write_filer+   rp   )rQ   r[   content_linesru   rG   r   r   r   s           r   r   r     s     M 3 3J 	3 	3D{c!!$$T\222	3 ii&&G  w77F| #fl""32<333DDII;;];;;;;;D:r   c                 j   |                     | j                  }|j        rdd| j         dfS |                    | j                  }|j        r	d|j        fS |j                            d          }d                    t          j        |g d| j         d	                    }d|p	d
| j         fS )zApply a delete file operation.FzCannot delete z: file not foundTkeependsrk   a/z	/dev/nullfromfiletofilez# Deleted: )	ro   r+   rp   delete_filer   
splitlinesrB   difflibunified_diff)rQ   r[   rs   r   removed_linesr   s         r   r   r     s     ((66K FEr|EEEEE!!",//F| #fl""'22D2AAM777'r$bl$$    D
 55r|5555r   c                     |                     | j        | j                  }|j        r	d|j        fS d| j         d| j         }d|fS )zApply a move file operation.Fz	# Moved: r   T)	move_filer+   r,   rp   )rQ   r[   r   r   s       r   r   r     sU    bk::F| #fl""6r|6666D:r   c                    ddl m} |                    | j                  }|j        rdd|j         fS |j        }|}| j        D ]}g }g }|j        D ]}	|	j        dk    r5|	                    |	j                   |	                    |	j                   B|	j        dk    r|	                    |	j                   h|	j        dk    r|	                    |	j                   |rd
                    |          }
d
                    |          } |||
|d	          \  }}}}|r|dk    r|j        r|                    |j                  }|d
k    rqt          d|dz
            }t          t          |          |dz             }|||         } |||
|d	          \  }}}}|dk    r|d|         |z   ||d         z   }d}|r4d| }	 ddl m} | ||d|
|          z  }n# t"          $ r Y nw xY wd|fc S d
                    |          }|j        rt%          ||j                  }|dk    r |                    d          dz   |z   dz   }|dk    rdd|j         d| dfc S |                    |j                  }|                    d|          }|d
k    r#|d|dz            |z   dz   ||dz   d         z   }}|dz   |z   }|                    d          dz   |z   dz   }|                    | j        |          }|j        r	d|j        fS t+          j        |                    d          |                    d          d| j         d| j                   }d
                    |          }d|fS )zApply an update file operation.r   r]   FzCannot read file: r7   r6   r5   r1   rh   r2   i  i  NzCould not apply hunk: rl   r3   z"Addition-only hunk: context hint 'rf   u,    occurrences) — provide a more unique hintTr   r   zb/r   rk   )rn   r^   ro   r+   rp   r   r-   r&   r   r>   rB   r#   rV   maxminr;   rm   rq   rZ   rstripr   r   r   r   )rQ   r[   r^   rs   current_contentnew_contentru   rv   ry   rG   rx   rz   rW   r|   rp   hint_poswindow_start
window_endwindow
window_newerr_msgrm   insert_textrw   eolwrite_result
diff_linesr   s                               r   r   r     s    988888 ((66K ?>;+<>>>>!)O "K HS HSJ 	3 	3D{c!!##DL111$$T\2222####DL1111##$$T\222 :	S!YY|44N))M22K3I3I^[e4 4 40K	5  *!$ )*//0ABBH2~~'*1hn'='=%([)9)98d?%K%K
!,\*-D!E>T>T"NKU? ? ?;
E9e !199*5m|m*Dz*QT_`j`k`kTl*lK$(E *>u>>GJJJJJJ#7#7q.R]#^#^^$    '>))) ))M22K  S0d>OPP!##"-"4"4T":":T"AK"ORV"VKK 1__ VT=N V V'V V V   
  +//0ABBH%**4::Cbyy&1(37(&;k&ID&PS^_bef_f_g_gSh&h&1D&8;&F)0066=KdR &&r|[AAL )l((( %""D"11--$bl$$"BL""	  J 77:D:s   	G!!
G.-G.)r   r   r<   dataclassesr   r   typingr   r   r   r   enumr	   r   r   r"   r)   r   rR   intrZ   r   r   boolr   r   r   r   r   r   r   <module>r      s   :  				 ( ( ( ( ( ( ( ( - - - - - - - - - - - -          D            8 8 8 8 8 8 8 8 " " " " " " " "[3 [5n1ExPS}1T+U [ [ [ [|
S 
3 
3 
 
 
 
X^$XX 
#YX X X XvfT.%9 f$'f,9f f f fR> S U495E    *6n 6 6dCi8H 6 6 6 6*N c eD#I6F    hn h hdCi8H h h h h h hr   