
    iD                        d Z ddlmZ ddlZddlZddlmZ ddlmZ 	 ddl	m
Z dZd	Zd
ZdZdZ ej$                  d      ZddZdddZddZddZddZddZdddZddZdddZy# e$ r dZY Kw xY w) us  M-05 @ 참조 시스템.

텍스트 내 @file:, @folder:, @diff, @staged 참조를 파싱하고
실제 파일 내용 / git 출력으로 치환한다.

Usage:
    from utils.context_refs import parse_refs, resolve_refs

    refs = parse_refs("check @file:utils/config_loader.py and @diff")
    text = resolve_refs("review @file:README.md", base_dir="/home/jay/workspace")
    )annotationsN)Path)Any)scan_contentTFi   i        zI(?P<ref>@(?P<type>file|folder):(?P<path>[^\s]+)|@(?P<bare>diff|staged)\b)c                   g }t         j                  |       D ]m  }|j                  d      r#|j                  d      |j                  d      }}n|j                  d      d}}|j                  |||j                  d      d       o |S )u   텍스트에서 @ 참조를 파싱하여 목록을 반환한다.

    Returns:
        각 항목은 {"type": str, "path": str | None, "raw": str} 형태.
    typepathbareNref)r
   r   raw)_REF_PATTERNfinditergroupappend)textresultsmref_typeref_paths        C/home/jay/workspace/.worktrees/task-2116-dev1/utils/context_refs.py
parse_refsr   #   s|     %'G""4( T776?!"!''&/hH!"$hH(1775>RST N    c                   | j                         r1| j                         r!| j                         j                  t        kD  ry	 | j                  dd      }|"dj                  |j                         d|       }|S # t        $ r Y yw xY w)uN   파일을 안전하게 읽는다. 크기 초과 또는 오류 시 None 반환.Nutf-8replace)encodingerrors
)	existsis_filestatst_size_MAX_FILE_BYTES	read_textjoin
splitlinesOSError)r   	max_linesr   s      r   
_read_safer+   3   sy    ;;=$))+2E2E2W~~wy~A 99T__.z	:;D s   8A= =	B	B	c                    t        |       }|j                         s||S || z  j                         }	 |j                  |j                                |S # t        $ r t        d|        w xY w)u;   상대/절대 경로를 base_dir 기준으로 해석한다.zPath escape detected: )r   is_absoluteresolverelative_to
ValueErrorPermissionError)path_strbase_dirpresolveds       r   _targetr6   @   s{    XA}}(*8#,,.HCX--/0 O  C 6xjABBCs   A A-c                2    | d   t        |      z   t        k  S )u    예산 확인. 초과 시 False.r   )len_MAX_TOTAL_BYTES)budgetdatas     r   _check_budgetr<   M   s    !9s4y $444r   c                v   t        ||      }|j                         r|j                         sd|  dS |j                         j                  }|t
        kD  rd|  d| dt
         dS t        |d|z        sd|  dS t        |      }|d|  dS |dxx   t        |j                  d	            z  cc<   d|  d
| S )u2   @file: 참조를 실제 내용으로 치환한다.<!-- : not found -->z: too large (z bytes, limit z) -->   x: context budget exceeded -->r   r    -->
)
r6   r!   r"   r#   r$   r%   r<   r+   r8   encode)r   r2   r3   r:   tsizecontents          r   _resolve_filerG   R   s    (#A88:QYY[se?++668Dose=n_<MUSS-se899mGse?++
1IW^^G,--I3%vgY''r   c                   t        ||      }|j                         r|j                         sd|  dS 	 t        d |j	                         D              }d|  dt        |       dd| dg}|j                  d |d	t         D               |d	t         D ]  }t        |t              }| |j                  d
|j                   d       5|j                  d      }	t        ||	      s |j                  d
|j                   d       r|dxx   t        |	      z  cc<   |j                  d
|j                   d|         dj                  |      S # t
        $ r	 d|  dcY S w xY w)uF   @folder: 참조를 폴더 내 파일 목록+내용으로 치환한다.r>   r?   c              3  B   K   | ]  }|j                         s|  y wN)r"   .0fs     r   	<genexpr>z"_resolve_folder.<locals>.<genexpr>i   s     =Qq=s   u    — z file(s) -->z	Files in :c              3  :   K   | ]  }d |j                      yw)z  - N)namerK   s     r   rN   z"_resolve_folder.<locals>.<genexpr>m   s     DQ4xDs   Nz
### u&    (skipped — too large or unreadable)r   u&    (skipped — context budget exceeded)r   r    )r6   r!   is_dirsortediterdirr)   r8   extend_MAX_FOLDER_FILESr+   _MAX_FOLDER_LINESr   rQ   rC   r<   r'   )
r   r2   r3   r:   rD   filespartsrM   rF   chunks
             r   _resolve_folderr[   c   sj   (#A88:QXXZse?++,=!))+==  uE#e*\BiPQsRSDTUE	LLD%0B1B*CDD%%& 
3Q 12?LL6!&&)OPQw'VU+LL6!&&)OPQq	SZ	vaffXRy12
3 99U  ,se?++,s    E E"!E"c                r    	 t        j                  dg| z   ddd|      j                  S # t        $ r Y yw xY w)uL   git 명령을 실행하고 출력을 반환한다. 실패 시 빈 문자열.gitT
   )capture_outputr   timeoutcwd )
subprocessrunstdout	Exception)argsra   s     r   _run_gitrh   |   s>    ~~ugnTVX^abiii s   '* 	66c                    t        ||rt        |      nd      xs |}|j                  d      }t        ||      sd|  dS |dxx   t	        |      z  cc<   d|  d| S )u/   git 명령 출력으로 참조를 치환한다.N)ra   r   r>   rA   r   rB   )rh   strrC   r<   r8   )r   git_argsfallbackr3   r:   outputrZ   s          r   _resolve_gitrn      sh    hXCM4HTHFMM'"E'se899
1IUI3%vfX&&r   c                d    |t        |      nddgdfd}t        j                  ||       S )u8  텍스트 내 @ 참조를 실제 내용으로 치환한 문자열을 반환한다.

    Args:
        text: @ 참조가 포함된 원본 텍스트.
        base_dir: 상대 경로 해석 기준 디렉터리. None이면 현재 디렉터리.

    Returns:
        @ 참조가 내용으로 치환된 문자열.
    Nr   c                Z   | j                  d      }| j                  d      rJ| j                  d      | j                  d      }}|dk(  rt        ||      S |dk(  rt        ||      S |S | j                  d      }|dk(  rt        |ddgd	      S |d
k(  rt        |g dd      S |S )Nr   r
   r   filefolderr   diff--stagedz((no staged diff or not a git repository)staged)rs   rt   z--name-onlyz)(no staged files or not a git repository))r   rG   r[   rn   )r   r   r   r2   baser:   s       r   _replacezresolve_refs.<locals>._replace   s    ggen776?!"!''&/hH6!$S(D&AA8#&sHdFCC 
 wwvH6!#C&*)=?ikoqwxx8##<>ikoqw  
r   )r   zre.Match[str]returnrj   )r   r   sub)r   r3   rw   rv   r:   s      @@r   resolve_refsrz      s6     &14>tDF$ Hd++r   )r   rj   rx   zlist[dict[str, Any]]rJ   )r   r   r*   z
int | Nonerx   
str | None)r2   rj   r3   Path | Nonerx   r   )r:   	list[int]r;   bytesrx   bool)
r   rj   r2   rj   r3   r|   r:   r}   rx   rj   )rg   	list[str]ra   r{   rx   rj   )r   rj   rk   r   rl   rj   r3   r|   r:   r}   rx   rj   )r   rj   r3   zstr | Path | Nonerx   rj   )__doc__
__future__r   rerc   pathlibr   typingr   utils.injection_guardr   _scan_content_GUARD_AVAILABLEImportErrorr%   r9   rV   rW   compiler   r   r+   r6   r<   rG   r[   rh   rn   rz    r   r   <module>r      s   
 # 	   C    rzzrs 

5
("2',m  s   A( (A21A2