
    ژj;%                       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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"d@dZ#dAdZ$dBdZ%dCd Z&dDd$Z'dEd'Z(dEd(Z)dFd+Z*dGd-Z+dHdId1Z,dJd2Z-dKd3Z.	 	 dLdMd?Z/dS )Na  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/ubuntu/.hermes/hermes-agent/acp_adapter/edit_approval.pyr   r      sK         IINNNIIIMMM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   2   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   8   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<   D   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   H   sk    T

A88:: t99;; <: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   Q   s    y}}V$$*++D *)))mmI&&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\   a   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	/ /+Hk9e  Tq  R"RD"R"RSSSy//   r   r   EditProposal | Nonec                    | dk    rt          |          S | dk    r)|                    dd          dk    rt          |          S dS )z:Return an edit proposal for supported file mutation calls.rL   rV   moder>   N)rP   r;   r\   )r   r   s     r   build_edit_proposalr`      sS     L  '	222G	fi @ @I M M*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     ...tzz||...r   z.gitz.sshT)r	   rA   partsnamerc   SENSITIVE_AUTO_APPROVE_NAMES)r   rg   lowereds      r   _is_sensitive_auto_approve_pathrk      si    JJ!!##)E.....GFg--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    rt          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 )zReturn 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_ASKstriprk   r   r	   rA   resolveAUTO_APPROVE_SESSIONAUTO_APPROVE_WORKSPACEtempfile
gettempdirrelative_torN   )rl   rm   rn   r   tmp_rootroots         r   should_auto_approve_editr{      si    ++,,2244F!!!%DX]%S%S!u))++3353AAD%%%t''' +--..66e6DD	X&&&4 	 	 	D	 	99''))111??D  &&&t   uu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 )
zRun 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<   r`   	ExceptionloggerwarningjsondumpsrX   )r   r   r+   rl   excapproveds         r   maybe_require_edit_approvalr      s=    ,--Itr&y)<< r r rNPY[^___z7$[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   )rl   r   tool_call_ids      r   build_acp_edit_tool_callr      s     JJJCD)@$A$ACCL.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.rl   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   rh   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)rl   r   r   rm   rn   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+HfcBB  KK LfV^Vcddd4   Z Z ZITXYYYYYZ |,\ZZZvMOOO
 -X66	$$!
 
 

 *)K	
 
 
 >5	}}W}55HHy) 	 	 	MMOOONNJCPPP55555	 (It44GY--; Dd33|C	
s)   ?A &A<;A<C( (D39/D..D3)rl   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-   rX   r:   )rl   r   rm   r   rn   r   r-   rX   )r   r   r   r   r-   r   )rl   r   )r   N)r   r   r   r   r   r   r   r   r   r   r-   r   )0r   
__future__r   asyncior   loggingrv   concurrent.futuresr   r   contextvarsr   r   dataclassesr   	itertoolsr   pathlibr	   typingr
   r   	getLoggerr   r   r   rX   r   r!   r   r   ri   rq   ru   rt   r1   r6   r8   r<   rG   rP   r\   r`   rk   r{   r   r   r   r   r   r   <module>r      s     # " " " " "     < < < < < < ) ) ) ) ) ) ) ) ! ! ! ! ! !                            		8	$	$ $        !,!56 EOZ!F F F       %((   a``  ,   3 3 3 3* * * *' ' ' '* * * *; ; ; ;       B   C C C C    Bs s s s>   4 GK4 4 4 4 4 4 4r   