§
    ÷žyjš+  ã                  óÒ  — U d Z ddlm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
 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  ej        e¦  «        Z ed
¬¦  «         G d„ d¦  «        ¦   «         Zeegef         Z edd¬¦  «        Zded<    ed¦  «        Zh d£Z dZ!dZ"dZ#dDd„Z$dEd„Z%dFd„Z&dGd „Z'dHd$„Z(dId'„Z)dId(„Z*dJd+„Z+dId,„Z,dKd/„Z-dLd1„Z.dMdNd5„Z/dOd6„Z0dPd7„Z1	 	 dQdRdC„Z2dS )Sa  Pre-execution ACP edit approval helpers.

This module is intentionally isolated from the generic tool registry.  ACP binds
an edit approval requester in a ContextVar for the duration of one ACP agent run;
CLI, gateway, and other sessions leave it unset and therefore bypass this guard.
é    )ÚannotationsN)ÚTimeoutError)Ú
ContextVarÚToken)Ú	dataclass)Úcount)ÚPath)ÚAnyÚCallableT)Úfrozenc                  óF   — e Zd ZU dZded<   ded<   ded<   ded<   ded	<   d
S )ÚEditProposalz?A proposed single-file edit that can be shown to an ACP client.ÚstrÚ	tool_nameÚpathú
str | NoneÚold_textÚnew_textúdict[str, Any]Ú	argumentsN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__© ó    ú?/home/ragecks/.hermes/hermes-agent/acp_adapter/edit_approval.pyr   r      sK   € € € € € € àIÐIà€N€N�NØ€I€I�IØÐÐÑØ€M€M�MØÐÐÑÐÐr   r   ÚACP_EDIT_APPROVAL_REQUESTER)Údefaultz(ContextVar[EditApprovalRequester | None]Ú_EDIT_APPROVAL_REQUESTERé   >   ú.envú
.env.localú.env.productionÚid_rsaÚ
id_ed25519ÚaskÚworkspace_sessionÚsessionÚ	requesterúEditApprovalRequester | NoneÚreturnr   c                ó6   — t                                | ¦  «        S )z<Bind an ACP edit approval requester for the current context.©r!   Úset)r+   s    r   Úset_edit_approval_requesterr1   3   s   € õ $×'Ò'¨	Ñ2Ô2Ð2r   ÚtokenÚNonec                ó:   — t                                | ¦  «         dS )z3Restore a previous edit approval requester binding.N)r!   Úreset)r2   s    r   Úreset_edit_approval_requesterr6   9   s   € õ ×"Ò" 5Ñ)Ô)Ð)Ð)Ð)r   c                 ó:   — t                                d¦  «         dS )z5Clear the current requester; primarily used by tests.Nr/   r   r   r   Úclear_edit_approval_requesterr8   ?   s   € õ × Ò  Ñ&Ô&Ð&Ð&Ð&r   c                 ó4   — t                                ¦   «         S ©N)r!   Úgetr   r   r   Úget_edit_approval_requesterr<   E   s   € Ý#×'Ò'Ñ)Ô)Ð)r   r   r   r   c                óê   — t          | ¦  «                             ¦   «         }|                     ¦   «         sd S |                     ¦   «         st	          d| › �¦  «        ‚|                     dd¬¦  «        S )NzCannot edit non-file path: zutf-8Úreplace)ÚencodingÚerrors)r	   Ú
expanduserÚexistsÚis_fileÚOSErrorÚ	read_text)r   Úps     r   Ú_read_text_if_existsrG   I   sk   € ÝˆT‰
Œ
×ÒÑÔ€AØ�8Š8‰:Œ:ð ØˆtØ�9Š9‰;Œ;ð <ÝÐ:°DÐ:Ð:Ñ;Ô;Ð;Ø�;Š; °	ˆ;Ñ:Ô:Ð:r   r   r   c           	     ó.  — t          |                      d¦  «        pd¦  «        }|st          d¦  «        ‚|                      d¦  «        }|€t          d¦  «        ‚t          d|t	          |¦  «        t          |¦  «        t          | ¦  «        ¬¦  «        S )Nr   Ú úpath requiredÚcontentzcontent requiredÚ
write_file©r   r   r   r   r   )r   r;   Ú
ValueErrorr   rG   Údict)r   r   rK   s      r   Ú_proposal_for_write_filerP   R   s•   € Ýˆy�}Š}˜VÑ$Ô$Ð*¨Ñ+Ô+€DØð *Ý˜Ñ)Ô)Ð)Ø�mŠm˜IÑ&Ô&€GØ€ÝÐ+Ñ,Ô,Ð,ÝØØÝ% dÑ+Ô+Ý�W‘”Ý�y‘/”/ðñ ô ð r   c                óN  — t          |                      d¦  «        pd¦  «        }|st          d¦  «        ‚|                      d¦  «        }|                      d¦  «        }|�|€t          d¦  «        ‚t          |¦  «        }|€t          d|› �¦  «        ‚dd	lm}  ||t          |¦  «        t          |¦  «        t          |                      d
d¦  «        ¦  «        ¦  «        \  }}}}	|	s|dk    rt          |	pd|› �¦  «        ‚t          d|||t          | ¦  «        ¬¦  «        S )Nr   rI   rJ   Ú
old_stringÚ
new_stringz"old_string and new_string requiredzFailed to read file: r   )Úfuzzy_find_and_replaceÚreplace_allFz'Could not find match for old_string in ÚpatchrM   )	r   r;   rN   rG   Útools.fuzzy_matchrT   Úboolr   rO   )
r   r   rR   rS   r   rT   r   Úmatch_countÚ	_strategyÚerrors
             r   Ú_proposal_for_patch_replacer\   b   sT  € Ýˆy�}Š}˜VÑ$Ô$Ð*¨Ñ+Ô+€DØð *Ý˜Ñ)Ô)Ð)Ø—’˜|Ñ,Ô,€JØ—’˜|Ñ,Ô,€JØÐ˜ZÐ/ÝÐ=Ñ>Ô>Ð>å# DÑ)Ô)€HØÐÝÐ7°Ð7Ð7Ñ8Ô8Ð8à8Ð8Ð8Ð8Ð8Ð8à.DÐ.DØÝˆJ‰ŒÝˆJ‰ŒÝˆY�]Š]˜=¨%Ñ0Ô0Ñ1Ô1ñ	/ô /Ñ+€Hˆk˜9 eð ð T�˜qÒ Ð Ý˜ÐRÐ"RÈDÐ"RÐ"RÑSÔSÐSåØØØØÝ�y‘/”/ðñ ô ð r   Ú
patch_bodyú	list[str]c                ó
  — g }t          j        d| t           j        ¦  «        D ]@}|                     d¦  «                             ¦   «         }|r|                     |¦  «         ŒAt          j        d| t           j        ¦  «        D ]~}|                     d¦  «                             ¦   «         }|                     d¦  «                             ¦   «         }|r|                     |¦  «         |r|                     |¦  «         Œ|S )Nz/^\*\*\*\s+(?:Update|Add|Delete)\s+File:\s*(.+)$r"   z+^\*\*\*\s+Move\s+File:\s*(.+?)\s*->\s*(.+)$é   )ÚreÚfinditerÚ	MULTILINEÚgroupÚstripÚappend)r]   ÚpathsÚmatchr   ÚsrcÚdsts         r   Ú_extract_v4a_patch_pathsrk   ƒ   sý   € Ø€EÝ”Ø:ØÝ
Œñô ð ð ˆð
 �{Š{˜1‰~Œ~×#Ò#Ñ%Ô%ˆØð 	Ø�LŠL˜ÑÔÐøÝ”Ø6ØÝ
Œñô ð 
ð 
ˆð
 �kŠk˜!‰nŒn×"Ò"Ñ$Ô$ˆØ�kŠk˜!‰nŒn×"Ò"Ñ$Ô$ˆØð 	Ø�LŠL˜ÑÔÐØð 	Ø�LŠL˜ÑÔÐøØ€Lr   c           	     ó®  — |                       d¦  «        }t          |t          ¦  «        r|st          d¦  «        ‚t	          |¦  «        }|st          d¦  «        ‚t          |¦  «        dk    r|d         nd                     |¦  «        }t          |¦  «        dk    rt          |d         ¦  «        nd }t          d|||t          | ¦  «        ¬¦  «        S )NrV   zpatch content requiredz no file paths found in V4A patchr"   r   z, rM   )
r;   Ú
isinstancer   rN   rk   ÚlenÚjoinrG   r   rO   )r   r]   rg   Úproposal_pathr   s        r   Ú_proposal_for_patch_v4arq   ›   sÙ   € Ø—’˜wÑ'Ô'€JÝ�j¥#Ñ&Ô&ð 3¨jð 3ÝÐ1Ñ2Ô2Ð2å$ ZÑ0Ô0€EØð =ÝÐ;Ñ<Ô<Ð<å # E¡
¤
¨a¢ �E˜!”H�H°T·Y²Y¸uÑ5EÔ5E€MÝ14°U±´¸q²°Õ# E¨!¤HÑ-Ô-Ð-Àd€HÝØØØð Ý�y‘/”/ð	ñ 	ô 	ð 	r   r   úEditProposal | Nonec                ó¼   — | dk    rt          |¦  «        S | dk    r@|                     dd¦  «        }|dk    rt          |¦  «        S |dk    rt          |¦  «        S dS )z:Return an edit proposal for supported file mutation calls.rL   rV   Úmoder>   N)rP   r;   r\   rq   )r   r   rt   s      r   Úbuild_edit_proposalru   ²   sp   € ð �LÒ Ð Ý'¨	Ñ2Ô2Ð2Ø�GÒÐØ�}Š}˜V YÑ/Ô/ˆØ�9ÒÐÝ.¨yÑ9Ô9Ð9Ø�7Š?ˆ?Ý*¨9Ñ5Ô5Ð5Øˆ4r   rX   c                óÔ   — t          | ¦  «                             ¦   «         j        }d„ |D ¦   «         }d|v sd|v rdS t          | ¦  «        j                             ¦   «         t
          v S )Nc                ó6   — h | ]}|                      ¦   «         ’ŒS r   )Úlower)Ú.0Úparts     r   ú	<setcomp>z2_is_sensitive_auto_approve_path.<locals>.<setcomp>Â   s    € Ð.Ð.Ð. ˆt�zŠz‰|Œ|Ð.Ð.Ð.r   z.gitz.sshT)r	   rA   ÚpartsÚnamerx   ÚSENSITIVE_AUTO_APPROVE_NAMES)r   r|   Úlowereds      r   Ú_is_sensitive_auto_approve_pathr€   À   si   € Ý�‰JŒJ×!Ò!Ñ#Ô#Ô)€EØ.Ð.¨Ð.Ñ.Ô.€GØ�ÐÐ˜F gÐ-Ð-ØˆtÝ�‰:Œ:Œ?× Ò Ñ"Ô"Õ&BÐBÐBr   ÚproposalÚpolicyÚcwdc                ó´  — t          |pt          ¦  «                             ¦   «         }|t          k    st          | j        ¦  «        rdS t          | j        ¦  «                             ¦   «                              d¬¦  «        }|t          k    rdS |t          k    r¼t          t          j        ¦   «         ¦  «                             d¬¦  «        }	 |                     |¦  «         dS # t          $ r Y nw xY w|r^t          |¦  «                             ¦   «                              d¬¦  «        }	 |                     |¦  «         dS # t          $ r Y dS w xY wdS )zÊReturn whether an ACP edit proposal may bypass the prompt for this session.

    This is intentionally session-scoped and conservative: sensitive paths still
    ask even under autonomous policies.
    F)ÚstrictT)r   ÚAUTO_APPROVE_ASKre   r€   r   r	   rA   ÚresolveÚAUTO_APPROVE_SESSIONÚAUTO_APPROVE_WORKSPACEÚtempfileÚ
gettempdirÚrelative_torN   )r�   r‚   rƒ   r   Útmp_rootÚroots         r   Úshould_auto_approve_editr�   È   si  € õ �Ð+Õ+Ñ,Ô,×2Ò2Ñ4Ô4€FØÕ!Ò!Ð!Õ%DÀXÄ]Ñ%SÔ%SÐ!ØˆuÝ�”ÑÔ×)Ò)Ñ+Ô+×3Ò3¸5Ð3ÑAÔA€DØÕ%Ò%Ð%ØˆtØÕ'Ò'Ð'õ �Ô+Ñ-Ô-Ñ.Ô.×6Ò6¸eÐ6ÑDÔDˆð	Ø×Ò˜XÑ&Ô&Ð&Ø�4øÝð 	ð 	ð 	ØˆDð	øøøàð 	Ý˜‘9”9×'Ò'Ñ)Ô)×1Ò1¸Ð1Ñ?Ô?ˆDðØ× Ò  Ñ&Ô&Ð&Ø�tøÝð ð ð Ø�u�uðøøøàˆ5s$   ÃC( Ã(
C5Ã4C5Ä0E Å
EÅEc                óÄ  — t          ¦   «         }|€dS 	 t          | |¦  «        }nO# t          $ rB}t                               d| |¦  «         t          j        dd|› d�id¬¦  «        cY d}~S d}~ww xY w|€dS 	 t           ||¦  «        ¦  «        }n4# t          $ r'}t                               d|¦  «         d}Y d}~nd}~ww xY w|rdS t          j        dd	id¬¦  «        S )
zÁRun ACP edit approval if bound.

    Returns a JSON tool-error string when the edit must be blocked, otherwise
    ``None`` so dispatch can continue.  Requester exceptions deny by default.
    Nz5Could not build ACP edit approval proposal for %s: %sr[   z.Edit approval denied: could not prepare diff (ú)F)Úensure_asciiz&ACP edit approval requester failed: %sz:Edit approval denied by ACP client; file was not modified.)r<   ru   Ú	ExceptionÚloggerÚwarningÚjsonÚdumpsrX   )r   r   r+   r�   ÚexcÚapproveds         r   Úmaybe_require_edit_approvalrš   é   s=  € õ ,Ñ-Ô-€IØÐØˆtðrÝ& y°)Ñ<Ô<ˆˆøÝð rð rð rÝ�ŠÐNÐPYÐ[^Ñ_Ô_Ð_ÝŒz˜7Ð$[ÐUXÐ$[Ð$[Ð$[Ð\ÐkpÐqÑqÔqÐqÐqÐqÐqÐqÐqøøøøðrøøøð ÐØˆtðÝ˜	˜	 (Ñ+Ô+Ñ,Ô,ˆˆøÝð ð ð Ý�ŠÐ?ÀÑEÔEÐEØˆˆˆˆˆˆøøøøðøøøð ð ØˆtÝŒ:�wÐ \Ð]ÐlqÐrÑrÔrÐrs2   ”% ¥
A1¯7A,Á&A1Á,A1Á9B Â
CÂB>Â>Cc                óä   — ddl }dt          t          ¦  «        › �}|                     |d| j        › �dd|                     | j        | j        | j        ¬¦  «        g| j        | j	        dœ¬	¦  «        S )
z<Build the ToolCallUpdate payload for ACP request_permission.r   Nzedit-approval-zApprove edit: ÚeditÚpending)r   r   r   )Útoolr   )ÚtitleÚkindÚstatusrK   Ú	raw_input)
ÚacpÚnextÚ_PERMISSION_REQUEST_IDSÚupdate_tool_callr   Útool_diff_contentr   r   r   r   )r�   r£   Útool_call_ids      r   Úbuild_acp_edit_tool_callr©     s—   € ð €J€J€JàC¥DÕ)@Ñ$AÔ$AÐCÐC€LØ×ÒØØ.˜xœ}Ð.Ð.ØØà×!Ò!Ø”]Ø!Ô*Ø!Ô*ð "ñ ô ð
ð $Ô-¸HÔ<NÐOÐOð  ñ ô ð r   ç      N@Úrequest_permission_fnr   Úloopúasyncio.AbstractEventLoopÚ
session_idÚtimeoutÚfloatÚauto_approve_getterú+Callable[[], tuple[str, str | None]] | NoneÚEditApprovalRequesterc                ó$   ‡ ‡‡‡‡— dˆˆˆ ˆˆfd„}|S )zGReturn a sync requester that bridges edit proposals to ACP permissions.r�   r   r-   rX   c                óâ  •— ddl m} ddlm} ‰�o	  ‰¦   «         \  }}t	          | ||¦  «        r#t
                               d|| j        ¦  «         dS n,# t          $ r t
           	                    dd¬¦  «         Y nw xY w |ddd	¬
¦  «         |ddd¬
¦  «        g}t          | ¦  «        } ‰‰||¬¦  «        } ||‰t
          d¬¦  «        }|€dS 	 |                     ‰¬¦  «        }	nN# t          t          f$ r:}
|                     ¦   «          t
                               d|
¦  «         Y d }
~
dS d }
~
ww xY wt          |	dd ¦  «        }t          |dd ¦  «        dk    ot          |dd ¦  «        dk    S )Nr   )ÚPermissionOption)Úsafe_schedule_threadsafez*Auto-approved ACP edit under policy %s: %sTz*ACP edit auto-approval policy check failed)Úexc_infoÚ
allow_oncez
Allow edit)Ú	option_idr    r}   ÚdenyÚreject_onceÚDeny)r®   Ú	tool_callÚoptionsz1Edit approval request: failed to schedule on loop)r”   Úlog_messageF)r¯   z-Edit approval request timed out or failed: %sÚoutcomeÚselectedrº   )Ú
acp.schemar¶   Úagent.async_utilsr·   r�   r”   Úinfor   r“   Údebugr©   ÚresultÚFutureTimeoutÚcancelr•   Úgetattr)r�   r¶   r·   r‚   rƒ   r¿   r¾   ÚcoroÚfutureÚresponser˜   rÁ   r±   r¬   r«   r®   r¯   s               €€€€€r   Ú
_requesterz4make_acp_edit_approval_requester.<locals>._requester'  s  ø€ Ø/Ð/Ð/Ð/Ð/Ð/Ø>Ð>Ð>Ð>Ð>Ð>àÐ*ðZØ1Ð1Ñ3Ô3‘�˜Ý+¨H°f¸cÑBÔBð  Ý—K’KÐ LÈfÐV^ÔVcÑdÔdÐdØ˜4ð øõ ð Zð Zð ZÝ—’ÐIÐTX�ÑYÔYÐYÐYÐYðZøøøð Ð |¸,È\ÐZÑZÔZØÐ v°MÈÐOÑOÔOð
ˆõ -¨XÑ6Ô6ˆ	Ø$Ð$Ø!ØØð
ñ 
ô 
ˆð
 *Ð)ØØÝØKð	
ñ 
ô 
ˆð ˆ>Ø�5ð	Ø—}’}¨W�}Ñ5Ô5ˆHˆHøÝ�yÐ)ð 	ð 	ð 	Ø�MŠM‰OŒOˆOÝ�NŠNÐJÈCÑPÔPÐPØ�5�5�5�5�5øøøøð	øøøõ ˜( I¨tÑ4Ô4ˆå�G˜Y¨Ñ-Ô-°Ò;ð DÝ˜ ¨dÑ3Ô3°|ÒCð	
s)   ‘?A Á&A<Á;A<ÃC( Ã(D3Ã9/D.Ä.D3)r�   r   r-   rX   r   )r«   r¬   r®   r¯   r±   rÎ   s   ````` r   Ú make_acp_edit_approval_requesterrÏ     sB   øøøøø€ ð)
ð )
ð )
ð )
ð )
ð )
ð )
ð )
ð )
ð )
ðV Ðr   )r+   r,   r-   r   )r2   r   r-   r3   )r-   r3   )r-   r,   )r   r   r-   r   )r   r   r-   r   )r]   r   r-   r^   )r   r   r   r   r-   rr   )r   r   r-   rX   r:   )r�   r   r‚   r   rƒ   r   r-   rX   )r   r   r   r   r-   r   )r�   r   )rª   N)r«   r   r¬   r­   r®   r   r¯   r°   r±   r²   r-   r³   )3r   Ú
__future__r   Úasyncior–   Úloggingra   rŠ   Úconcurrent.futuresr   rÈ   Úcontextvarsr   r   Údataclassesr   Ú	itertoolsr   Úpathlibr	   Útypingr
   r   Ú	getLoggerr   r”   r   rX   r³   r!   r   r¥   r~   r†   r‰   rˆ   r1   r6   r8   r<   rG   rP   r\   rk   rq   ru   r€   r�   rš   r©   rÏ   r   r   r   ú<module>rÚ      sì  ððð ð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø 	€	€	€	Ø €€€Ø <Ð <Ð <Ð <Ð <Ð <Ø )Ð )Ð )Ð )Ð )Ð )Ð )Ð )Ø !Ð !Ð !Ð !Ð !Ð !Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø  Ð  Ð  Ð  Ð  Ð  Ð  Ð  à	ˆÔ	˜8Ñ	$Ô	$€ð €�$ÐÑÔðð ð ð ð ñ ô ñ Ôðð ! , °Ð!5Ô6Ð àEOÀZØ!ØðFñ Fô FÐ ð ð ð ñ ð  ˜% ™(œ(Ð ð  aÐ`Ð`Ð ØÐ Ø,Ð Ø Ð ð3ð 3ð 3ð 3ð*ð *ð *ð *ð'ð 'ð 'ð 'ð*ð *ð *ð *ð;ð ;ð ;ð ;ðð ð ð ð ð ð ð ðBð ð ð ð0ð ð ð ð.ð ð ð ðCð Cð Cð Cðð ð ð ð ðBsð sð sð sð>ð ð ð ð4 ØGKð4ð 4ð 4ð 4ð 4ð 4ð 4r   