
    `gj^              
          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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ee   f   fdZy)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y)OperationTypeaddupdatedeletemoveN)__name__
__module____qualname__ADDUPDATEDELETEMOVE     E/root/.hermes/venv/lib/python3.12/site-packages/tools/patch_parser.pyr   r   &   s    
CFFDr   r   c                   &    e Zd ZU dZeed<   eed<   y)HunkLinezA single line in a patch hunk.prefixcontentN)r   r   r   __doc__str__annotations__r   r   r   r   r   -   s    (KLr   r   c                   H    e Zd ZU dZdZee   ed<    ee	      Z
ee   ed<   y)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   s&    +"&L(3-&!$7E4>7r   r"   c                   p    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<   y)	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)   ;   s?    ,N"Hhsm"d3E4:3!GXc]!r   r)   patch_contentreturnc                 
   | j                  d      }g }d}d}t        |      D ]  \  }}d|v sd|v r|}d|v sd|v s|} n |d}|t        |      }|dz   }d}d}||k  r||   }t        j                  d	|      }	t        j                  d
|      }
t        j                  d|      }t        j                  d|      }|	rx|r:|r'|j
                  r|j                  j                  |       |j                  |       t        t        j                  |	j                  d      j                               }d}n$|
r|r:|r'|j
                  r|j                  j                  |       |j                  |       t        t        j                  |
j                  d      j                               }t               }n|r|r:|r'|j
                  r|j                  j                  |       |j                  |       t        t        j                  |j                  d      j                               }|j                  |       d}d}n|r|r:|r'|j
                  r|j                  j                  |       |j                  |       t        t        j                   |j                  d      j                         |j                  d      j                               }|j                  |       d}d}nj|j#                  d      rd|rV|r'|j
                  r|j                  j                  |       t        j                  d|      }|r|j                  d      nd}t        |      }n|r|r|
t               }|j#                  d      r)|j
                  j                  t%        d|dd              n|j#                  d      r)|j
                  j                  t%        d|dd              nq|j#                  d      r)|j
                  j                  t%        d|dd              n7|j#                  d      rn%|j
                  j                  t%        d|             |dz  }||k  r|r:|r'|j
                  r|j                  j                  |       |j                  |       |s|dfS g }|D ]  }|j&                  s|j                  d       |j(                  t        j                  k(  r+|j                  s|j                  d|j&                  d       |j(                  t        j                   k(  s|j*                  r|j                  d|j&                  d        |rg ddj-                  |      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(@I$$(>G 	e* 	AA+/J#'L
g+Qx xx A4HHH;TB	xx A4HXXJDQ
L$6$6$$++L9!!*-''..&,,Q/557J  LL$6$6$$++L9!!*-''++#//!,224J  6LL$6$6$$++L9!!*-''..&,,Q/557J j)JLL$6$6$$++L9!!*-'',,$**1-335#))!,224J
 j)JL__T"L$6$6$$++L9  XX&8$?
.8z''*d#6D##vs#""))(3QR*AB%""))(3QR*AB%""))(3QR*AB& ""))(3*=>	Qy g+~ L..##L1*% 4 L l|| @A<<=///'",,)99I JK<<=---bkk%'77i jkl ?TYY|%<<<<tr   textpatternc                 V    d}d}	 | j                  ||      }|dk(  r	 |S |dz  }|dz   }%)z9Count non-overlapping occurrences of *pattern* in *text*.r   r2   r3   )find)rS   rT   countstartposs        r   _count_occurrencesrZ      sI    EE
ii'"9 L 	
a r   rC   file_opsc           
         ddl m} g }d}| D ]  }|j                  t        j                  k7  r|dz  }|j                  t        j                  k(  r~|j                  |j                        }|j                  r+|j                  |j                   d|j                          |j                  }t        |j                  d      D ]  \  }}	|	j                  D 
cg c]  }
|
j                  dv s|
j                   }}
|	j                  D 
cg c]  }
|
j                  dk(  s|
j                    }}
|	j                  D 
cg c]  }
|
j                  dk(  s|
j                    }}
|s|s|dz  }|s|	j                  rzt        ||	j                        }|dk(  r,|j                  |j                   d	|	j                   d
       n3|dkD  r.|j                  |j                   d	|	j                   d| d       3dj!                  |      }|	j                  D 
cg c]  }
|
j                  dv s|
j                   }}
dj!                  |      } ||||d      \  }}}}|dk(  re|	j                  rd|	j                   dnd}|j                   d| d| d|rd| ndz   }	 ddl m} | |||||      z  }|j                  |       |} |j                  t        j&                  k(  rI|j                  |j                        }|j                  s|j                  |j                   d       (|j                  t        j(                  k(  sG|j*                  s |j                  |j                   d       s|j                  |j                        }|j                  r|j                  |j                   d       |j                  |j*                        }|j                  r|j                  |j*                   d        |s|dk(  r|j                  d       |S c c}
w c c}
w c c}
w c c}
w # t$        $ r Y w xY w)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_replacer3   : )rX   >   r7   r6   r6   r5   z#: addition-only hunk context hint 'z' not found' is ambiguous (z occurrences)r1   >   r7   r5   Freplace_all'z	(no hint)z: hunk r7   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 overwritez<Patch contains no changes (only context lines were provided))tools.fuzzy_matchr^   r*   r   r   read_file_rawr+   errorr>   r   r:   r-   r&   r   r#   rZ   rB   rf   	Exceptionr   r   r,   )rC   r[   r^   errorsreal_change_countrQ   read_result	simulated
hunk_indexhunklsearch_linesremoved_linesadded_linesoccurrencessearch_patternreplace_linesreplacementnew_simulatedrW   	_strategymatch_errorlabelmsgrf   
src_result
dst_results                              r   _validate_operationsr      s    9F L<<=///"<<=///"00>K  b1B1B0CDE#++I$-bhha$@ 0. 
D37::XaZAW		XX48JJ Rq!((c/ R R26**PQCqyyPP$[ !Q&!#((&8DDUDU&V&!+"MM#%<<. 1$$($5$5#6k!C )1_"MM#%<<. 1$$($5$5#6 7$$/=!?
 !%<!848JJ Yq!((jBX Y Y"ii6?U~{@<ui A:8<8I8Ia 1 12!4{E<<.
|1UG:N4?U;-0RI J3KXabb MM#& !.Ia0.d \\]111"00>K  .KLM\\]///;;.WXY!//=J.NOP!//<J##{{m#XYUL` '1,TUMQ  Y RP0 !Z % sB   P)/P)P."P. P3P3P8,P8!P==	Q
	Q
PatchResultc                    ddl m} t        | |      }|r# |dddj                  d |D              z         S g }g }g }g }g }g }	| D ]U  }
	 |
j                  t
        j                  k(  rt        |
|      }|d   rK|j                  |
j                         |j                  |d          |d	   r|j                  |d	          n|	j                  d
|
j                   d|d           n|
j                  t
        j                  k(  rht        |
|      }|d   r1|j                  |
j                         |j                  |d          nS|	j                  d|
j                   d|d           n-|
j                  t
        j                  k(  rut        |
|      }|d   r?|j                  |
j                   d|
j                          |j                  |d          n|	j                  d|
j                   d|d           n|
j                  t
        j                  k(  r~t!        |
|      }|d   rI|j                  |
j                         |j                  |d          |d	   r9|j                  |d	          n$|	j                  d|
j                   d|d           X i }||z   D ]3  }t'        |d      s|j)                  |      }|j+                         ||<   5 dj                  |      }|rdj                  |      nd}|	r- |d|||||r|nd|ddj                  d |	D              z         S  |d|||||r||      S d|      S # t"        $ r5}|	j                  d|
j                   dt%        |              Y d}~=d}~ww xY w)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 |   ywu     • Nr   .0es     r   	<genexpr>z'apply_v4a_operations.<locals>.<genexpr>s  s     FqqclF   )successri   r3   r4   zFailed to add r_   zFailed to delete  -> zFailed to move zFailed to update zError processing N_check_lintz

uM   Apply phase failed (state may be inconsistent — run `git diff` to assess):
c              3   &   K   | ]	  }d |   ywr   r   r   s     r   r   z'apply_v4a_operations.<locals>.<genexpr>  s     ;qqcl;r   )r   difffiles_modifiedfiles_createdfiles_deletedlintlsp_diagnosticsri   T)r   r   r   r   r   r   r   )tools.file_operationsr   r   rB   r*   r   r   
_apply_addr>   r+   r   _apply_deleter   _apply_mover,   r   _apply_updaterj   r   hasattrr   to_dict)rC   r[   r   validation_errorsr   r   r   	all_diffs
lsp_blocksrk   rQ   resultr   lint_resultsflint_resultcombined_diffcombined_lsps                     r   apply_v4a_operationsr   X  s   & 2 -ZBGIIF4EFFG
 	
 NMMI JF 'H&	H||}000#B1!9!((6$$VAY/ay"))&)4MMN2<<.6!9+"NO!5!55&r84!9!((6$$VAY/MM$5bll^2fQi["QR!3!33$R2!9"))R\\N$r{{m*LM$$VAY/MMOBLL>F1I;"OP!5!55&r84!9"))",,7$$VAY/ay"))&)4MM$5bll^2fQi["QRI'HT Lm+ 48]+"..q1K)113LO4
 IIi(M /96;;z*dL)''!-4(bII;F;;<

 
	
 %##)\$  04$ A  	HMM-bll^2c!fXFGG	Hs   IM

	N*NNrQ   c                    g }| j                   D ]>  }|j                  D ]-  }|j                  dk(  s|j                  |j                         / @ dj                  |      }|j                  | j                  |      }|j                  rd|j                  dfS d| j                   d}|dj                  d |D              z  }d|t        |dd      fS )	ul  Apply an add file operation.

    Returns ``(success, diff_or_error, lsp_diagnostics)``.  The third
    element carries the formatted ``<diagnostics>`` block from
    :class:`WriteResult.lsp_diagnostics` so V4A patches can surface
    semantic diagnostics from the LSP layer — without this, the LSP
    tier would silently swallow them on the V4A code path.
    r5   r1   FNz--- /dev/null
+++ b/c              3   &   K   | ]	  }d |   yw)r5   Nr   )r   rG   s     r   r   z_apply_add.<locals>.<genexpr>  s     ;T$j;r   Tr   )
r-   r&   r   r>   r   rB   
write_filer+   ri   getattr)rQ   r[   content_linesrp   rG   r   r   r   s           r   r   r     s     M 3JJ 	3D{{c!$$T\\2	33
 ii&G  w7F||fllD(("2<<.3DDII;];;;Dwv'8$???r   c                    |j                  | j                        }|j                  rdd| j                   dfS |j                  | j                        }|j                  rd|j                  fS |j                  j                  d      }dj                  t        j                  |g d| j                   d	            }d|xs d
| j                   fS )zApply a delete file operation.FzCannot delete z: file not foundTkeependsrd   a/z	/dev/nullfromfiletofilez# Deleted: )	rh   r+   ri   delete_filer   
splitlinesrB   difflibunified_diff)rQ   r[   rm   r   rs   r   s         r   r   r     s     ((6Kr||n4DEEE!!",,/F||fll""''22D2AM777''rbll^$ D
 5;r||n555r   c                     |j                  | 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,   ri   )rQ   r[   r   r   s       r   r   r     sV    bkk:F||fll""r||nD6D:r   c                 ,   ddl m} |j                  | j                        }|j                  rdd|j                   dfS |j
                  }|}| j                  D ]}  }g }g }|j                  D ]  }	|	j                  dk(  r7|j                  |	j
                         |j                  |	j
                         I|	j                  dk(  r|j                  |	j
                         t|	j                  dk(  s|j                  |	j
                          |r||k(  r|rd	j                  |      }
d	j                  |      } |||
|d
      \  }}}}|s|dk(  s|j                  rr|j                  |j                        }|dk7  rRt        d|dz
        }t        t        |      |dz         }||| } |||
|d
      \  }}}}|dkD  r|d| |z   ||d z   }d}|s}d| }	 ddl m} | ||d|
|      z  }d|dfc S d	j                  |      }|j                  rt%        ||j                        }|dk(  r|j'                  d	      d	z   |z   d	z   }|dkD  rdd|j                   d| ddfc S |j                  |j                        }|j                  d	|      }|dk7  r|d|dz    |z   d	z   ||dz   d z   }Z|d	z   |z   }d|j'                  d	      d	z   |z   d	z   } |j)                  | j                  |      }|j                  rd|j                  dfS t+        j,                  |j/                  d      |j/                  d      d| j                   d| j                         }dj                  |      }d|t1        |dd      fS # t"        $ r Y w xY w)u   Apply an update file operation.

    Returns ``(success, diff_or_error, lsp_diagnostics)`` — see
    :func:`_apply_add` for the rationale on the third element.
    r   r]   FzCannot read file: Nr7   r6   r5   r1   ra   r2   i  i  zCould not apply hunk: re   r3   z"Addition-only hunk: context hint 'r`   u,    occurrences) — provide a more unique hintTr   r   zb/r   rd   r   )rg   r^   rh   r+   ri   r   r-   r&   r   r>   rB   r#   rV   maxminr;   rf   rj   rZ   rstripr   r   r   r   r   )rQ   r[   r^   rm   current_contentnew_contentrp   rr   rw   rG   rv   rx   rW   rz   ri   hint_poswindow_start
window_endwindow
window_newerr_msgrf   insert_textru   eolwrite_result
diff_linesr   s                               r   r   r     s    9 ((6K*;+<+<*=>DD!))O "K JSJJ 	3D{{c!##DLL1$$T\\2###DLL1#$$T\\2	3 LM9!YY|4N))M2K3I^[e40K	5 !$$*//0A0ABH2~'*1hn'=%([)98d?%K
!,\*!E>T"NKU?;
E9e !19*5m|*Dz*QT_`j`kTl*lK$(E 6ug>GJ#7q.R]#^^ !'4// ))M2K  0d>O>OP!#"-"4"4T":T"AK"ORV"VK 1_ <T=N=N<O P'=(TV 
  +//0A0ABH%**4:Cby&1(37&;k&ID&PS^_bef_f_gSh&h&1D&8;&F)006=KdRUJSZ &&r||[ALl(($.. %%""D"1-bll^$BLL>"	J 77:Dw|->EEEU % s   N	NN)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 " " "[3 [5n1ExPS}1T+U [|
S 
3 
3 
e^$ee 
#YePyT.%9 y$'y,9yx@> @S @U4hsm;S5T @86n 6 6dCi8H 6*N c eD#I6F nFn nF nFdCRU>V8W nFr   