
    yYi7                       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Zddl	Z	ddl
m
Z
mZ ddlmZ 	 ddlZd	Zd	Zd
ZddZ e       ZddZddZddZddZddZddZddZ	 	 	 	 	 	 	 	 	 	 ddZd dZ d!dZ!d"dZ"d#dZ#e$dk(  r ej$                   e#              yy# e$ r)  edej"                          ej$                  d       Y w xY w)$u  create_handoff.py — 봇 간 작업 인계 JSON 생성 스크립트 (task-2454 Phase 1 MVP)

사용법:
    ./scripts/create_handoff.py \
        --task <task-id> \
        --reason <interrupt|complete|takeover_request> \
        [--pending "잔여 작업 요약"] \
        [--pending-file PATH] \
        [--failures "에러 요약"] \
        [--failures-file PATH] \
        [--bot devN]
    )annotationsN)datetimetimezone)PathuG   오류: jsonschema 패키지가 필요합니다. pip install jsonschemafile   i  
   c                     t         j                  j                  d      } | rt        |       j	                         S t        t
              j	                         j                  j                  S )uZ   WORKSPACE_ROOT 환경변수 우선, 없으면 이 스크립트 기준 상위 디렉토리.WORKSPACE_ROOT)osenvirongetr   resolve__file__parent)env_roots    G/home/jay/workspace/.worktrees/task-2507-dev5/scripts/create_handoff.pyget_workspace_rootr   2   sJ    zz~~./HH~%%''>!!#**111    c            	     (   t        j                  dg| t        ddt              }|j                  dk7  rEt        ddj                  |        d|j                   d|j                  j                                |j                  j                         S )	u=   git 명령 실행 후 stdout 반환. 실패 시 RuntimeError.gitT)cwdcapture_outputtexttimeoutr   zgit  u    실패 (exit z): )

subprocessrunr   SUBPROCESS_TIMEOUT
returncodeRuntimeErrorjoinstderrstripstdout)argsresults     r   run_gitr)   A   s    ^^	"F A388D>".1B1B0C3v}}GZGZG\F]^
 	
 ==  r   c                     t        dd      S )u   origin/main HEAD SHA 반환.	rev-parsezorigin/mainr)    r   r   get_base_shar.   Q   s    ;..r   c                     t        dd      S )u!   현재 브랜치 HEAD SHA 반환.r+   HEADr,   r-   r   r   get_head_shar1   V   s    ;''r   c                     t        dd      S )u   현재 브랜치 이름 반환.branchz--show-currentr,   r-   r   r   get_current_branchr4   [   s    8-..r   c                 p    t        ddd      } | sg S | j                         D cg c]  }|s|	 c}S c c}w )u1   origin/main..HEAD 사이 변경된 파일 목록.diffz--name-onlyzorigin/main..HEAD)r)   
splitlines)outputps     r   get_changed_pathsr:   `   s8    V],?@F	((*0!aA000s   33c                X    t        j                  d|       }|r|j                  d      S dS )u5   브랜치 이름 task/task-X-devN 에서 devN 추출.z-(dev\d+|design|qc)$r	   N)researchgroup)r3   ms     r   extract_bot_from_branchr@   h   s(    
		)62A1771:$$r   c                   t         dz  dz  |  dz  }|j                         sg g fS 	 |j                  d      }g }g }d}d}|j	                         D ]  }|j                         }|j                  d      rd}d})|j                  d	      s|j                  d
      rd}d}P|r|j                  d      sd|v r	|s|rd}d}p|j                  d      s|dd j                         j                  d      j                  d      }	|r|	r|j                  |	       |s|	s|j                  |	        ||fS # t        $ r g g fcY S w xY w)uy   memory/tasks/<task-id>.md 에서 allowed_resources 파싱.
    실패 시 빈 배열 반환 (오류 발생 안 함).
    memorytasksz.mdutf-8encodingFzallowed_resources:Tzforbidden_paths:zforbidden_resources:-:r	   N"')r   exists	read_textOSErrorr7   r%   
startswithappend)
task_id	task_filecontentallowed	forbidden
in_allowedin_forbiddenlinestrippeditems
             r   parse_task_pathsrZ   r   sx    )G3	oEI2v%%w%7 GI JL""$ '::<34J L12h6I6IJ`6aLJH//4\"
$s#AB<%%'--c288=Ddt$$  &+'. IA  2vs   D8 8EEc                    t        |       |k  r| dfS t        dz  dz  }|j                  dd       || d| dz  }|j                  | d	       t	        |j                  t                    }d|fS )
u   텍스트가 max_len 이하면 (text, None) 반환.
    초과 시 memory/handoffs/<task>-<field>.txt 에 저장 후 (None, path_str) 반환.
    NrB   handoffsTparentsexist_okrG   z.txtrD   rE   )lenr   mkdir
write_textstrrelative_to)r   
field_namerP   max_lenhandoffs_dirout_filerel_paths          r   handle_long_textrj      s     4yGTz!H,z9Ltd3	:,d;;Hw/8''78H>r   c                &   | j                   j                  dd       t        j                  dd| j                   dd      5 }t	        j
                  ||dd	       |j                  }d
d
d
       t        j                  |        y
# 1 sw Y    xY w)u-   tempfile + os.replace 로 atomic JSON 저장.Tr]   wrD   Fz.tmp)moderF   dirdeletesuffix   )ensure_asciiindentN)	r   ra   tempfileNamedTemporaryFilejsondumpnamer   replace)pathdatatmptmp_paths       r   atomic_write_jsonr~      s    KKdT2		$	$KK
  
		$%:88 JJx s   &BBc                   t         dz  dz  }|j                  dd       ||  dz  }| ||t        j                  t        j
                        j                  d      d}t        ||       t        d| t        j                  	       y )
NrB   eventsTr]   z.handoff-validation-fail.json%Y-%m-%dT%H:%M:%SZ)rP   errordata_snapshot
created_atu   검증 실패 evidence 저장: r   )r   ra   r   nowr   utcstrftimer~   printsysr$   )rP   r{   r   
events_direvidence_pathevidences         r   save_validation_fail_evidencer      s    (*X5JTD1G9,I!JJMll8<<099:NO	H mX.	+M?
;#**Mr   c                 r   t        j                  dt         j                        } | j                  ddd       | j                  ddg dd	
       | j                  dd d       | j                  dd dd       | j                  dd d       | j                  dd dd       | j                  dd d       | S )Nu.   봇 간 작업 인계 JSON 생성 스크립트)descriptionformatter_classz--taskTu   task-id (예: task-2454))requiredhelpz--reason)	interruptcompletetakeover_requestu   인계 사유)r   choicesr   z	--pendingu   잔여 작업 요약 텍스트)defaultr   z--pending-filePATHu"   잔여 작업 외부 파일 경로)r   metavarr   z
--failuresu(   알려진 실패/에러 요약 텍스트z--failures-fileu%   알려진 실패 외부 파일 경로z--botu8   봇 ID (예: dev4). 미지정 시 브랜치에서 추출)argparseArgumentParserRawDescriptionHelpFormatteradd_argument)r9   s    r   build_parserr      s    D <<	A NN8d1KNLNN=	   NN;3SNTNN#T6HlNmNN<4^N_NN$dFIpNqNN7D/iNjHr   c                 L   t               } | j                         }|j                  }|j                  }	 t	               }	 t               }t               }t               }|j                  }	|	st        |      }	|	s t        d| dt        j                         yd }
d }|j                  Pt        |j                        }|j!                         st        d| t        j                         yt#        |      }n+|j$                  t'        |j$                  d|t(              \  }
}d }d }|j*                  Pt        |j*                        }|j!                         st        d	| t        j                         yt#        |      }n+|j,                  t'        |j,                  d
|t.              \  }}t1        |      \  }}t3        j4                  t6        j8                        j;                  d      }|d|	||||||i ||d}|
|
|d<   |||d<   |||d<   |||d<   t<        dz  dz  dz  }|j!                         st        d| t        j                         y	 t?        j@                  |jC                  d            }	 tI        jJ                  |      }tM        |jO                  |            }|r-djQ                  d |D              }tI        jR                  |      	 t<        dz  dz  }|| dz  }tY        ||       t        d|        t        d|        y # t
        $ r(}t        d| t        j                         Y d }~yd }~ww xY w# t
        $ r(}t        d| t        j                         Y d }~yd }~ww xY w# tD        t>        jF                  f$ r(}t        d| t        j                         Y d }~yd }~ww xY w# tH        jR                  $ rJ}t#        |jT                        }t        d| t        j                         tW        |||       Y d }~yd }~ww xY w)!Nu*   오류: origin/main SHA 조회 실패 — r   r	   u%   오류: git 정보 조회 실패 — u$   오류: --bot 미지정, 브랜치 'uF   '에서 봇 ID 추출 실패. --bot devN 형식으로 명시하세요.u<   오류: --pending-file 경로가 존재하지 않습니다: pendingu=   오류: --failures-file 경로가 존재하지 않습니다: failuresr   z1.0)rP   schema_versionprevious_botcurrent_branchbase_shahead_shachanged_pathsallowed_pathsforbidden_pathstest_resultshandoff_reasonr   pending_workpending_work_pathknown_failuresknown_failures_pathrB   specszhandoff-schema.jsonu5   오류: 스키마 파일을 찾을 수 없습니다: rD   rE   u+   오류: 스키마 파일 읽기 실패 — z; c              3  F   K   | ]  }t        |j                          y w)N)rc   message).0es     r   	<genexpr>zmain.<locals>.<genexpr>q  s     !AQ#aii.!As   !u6   오류: 핸드오프 JSON 스키마 검증 실패 — r\   z.jsonu   핸드오프 생성 완료: zhandoff_reason: r   )-r   
parse_argstaskreasonr.   r"   r   r   r$   r1   r4   r:   botr@   pending_filer   rK   rc   r   rj   PENDING_MAX_LENfailures_filer   FAILURES_MAX_LENrZ   r   r   r   r   r   r   rv   loadsrL   rM   JSONDecodeError
jsonschemaDraft202012Validatorlistiter_errorsr#   ValidationErrorr   r   r~   )parserr'   rP   r   r   r   r   r   r   r   pending_inlinepending_pathpffailures_inlinefailures_pathffr   r   r   handoff_dataschema_pathschema	validatorerrors	error_msg	error_strrg   out_paths                               r   mainr      s   ^FD99G++F
>
>+-)+  $xxL.~>2>2B C7 7	

 
 "&N#L$$##$yy{PQSPTU\_\f\fg2w		!'7LL)Wo(
$ #'O $M%$$$%yy{QRTQUV]`]g]ghB		")9MM:w0@*
& &6g%>"M?
 hll+445IJJ $(&&*  L !'5^$,8()")8%& .;*+
 !8+g58MMKEk]SZ]ZdZdeK1171CD

33F;	i++L9:		!A&!AAI,,Y77  "H,z9L	//Hh-
 
(

34	VH
%&K  :1#>SZZP  5aS9

KB T))* ;A3?cjjQ %% 		N	FykRY\YcYcd%g|YG	s`   
L M %N >AO 	M#MM	M?M::M?ON>>OP#A PP#__main__)returnr   )r'   rc   r   rc   )r   rc   )r   z	list[str])r3   rc   r   z
str | None)rP   rc   r   ztuple[list[str], list[str]])
r   rc   re   rc   rP   rc   rf   intr   ztuple[str | None, str | None])rz   r   r{   dictr   None)rP   rc   r{   r   r   rc   r   r   )r   zargparse.ArgumentParser)r   r   )%__doc__
__future__r   r   rv   r   r<   r   r   rt   r   r   pathlibr   r   ImportErrorr   r$   exitr   r   r    r   r   r)   r.   r1   r4   r:   r@   rZ   rj   r~   r   r   r   __name__r-   r   r   <module>r      s   #   	 	  
  ' 
   2 $%! /
(
/
1%*b
  	
 #0&N$(Qh zCHHTV Q  	QZZ CHHQKs   B! !+CC