
    ſi                     b   U d 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Zddl	m
Z
 ddlmZ  e e
e      j                         j                   d         Zeej$                  vrej$                  j'                  de       ddlmZ  ej,                  e      Zdeeef   fdZ	 	 	 d;d	ee   d
edz  dededej:                  e   f
dZd<d	ee   d
edz  defdZdedefdZ dedeeeef      fdZ!dededefdZ"dedededefdZ#d Z$dZ%dededee   fdZ&e$	 	 d=dedededededeeef   fd       Z'dede(fdZ)dedededefd Z*d!ed"ed#ed
edeeeef      f
d$Z+	 d>d%eeeef      d&ed'edeeef   fd(Z,g d)Z-ee   e.d*<   g d+Z/ee   e.d,<   d>d%eeeef      d'edeeeef      fd-Z0d.eeeef      ddfd/Z1e$	 	 	 	 d?dededed0ed1ed2ed3e(d'edeeef   fd4       Z2dedeeef   fd5Z3dedeeef   fd6Z4dededeeef   fd7Z5dejl                  fd8Z7d@d9Z8ed:k(  r e8        yy)Au  
Git Worktree Manager - 멀티봇 환경에서의 안전한 worktree 관리 스크립트.

사용법:
    python3 worktree_manager.py <command> [args]

명령어:
    create   <project_path> <task_id> <team_id>        - worktree 생성
    finish   <project_path> <task_id> <team_id> <action> - worktree 완료 처리
    list     <project_path>                             - 활성 worktree 목록
    status   <project_path> <task_id>                  - worktree 상태 확인
    N)Path)Any   )parse_blast_radiusreturnc                     t        t              j                  dz  } t        j                  d      }i }| j                         r$	 t        j                  | j                               }|j                  d      |k7  r|dd}|dxx   dz  cc<   | j                  t        j                  |             |d   dkD  rd	d
|d    diS i S # t        j                  t        f$ r i }Y |w xY w)uB   Gemini 무료 한도 (일 33건) 체크. 초과 시 경고 반환.zgemini_rate_tracker.jsonz%Y-%m-%ddater   )r	   countr
   r   !   warningzGemini daily limit exceeded: z/33)r   __file__parenttimestrftimeexistsjsonloads	read_textJSONDecodeErrorOSErrorget
write_textdumps)tracker_pathtodaydatas      K/home/jay/workspace/.worktrees/task-2487-B-dev2/scripts/worktree_manager.py_check_rate_limitr   '   s    >((+EELMM*%ED	::l4467D xx5 *MQMDJJt,-G}r:4=/MNNI $$g. 	D	s   #C C%$C%argscwdcheckcapturec                     t        j                  | ||d|rt         j                  nd|rt         j                        S d      S )u1  git 명령을 실행하고 CompletedProcess 반환.

    Args:
        args: 실행할 명령어 리스트.
        cwd: 작업 디렉터리.
        check: 실패 시 CalledProcessError 발생 여부.
        capture: stdout/stderr 캡처 여부.

    Returns:
        완료된 프로세스 객체.
    TN)r    r!   textstdoutstderr)
subprocessrunPIPE)r   r    r!   r"   s       r   _runr*   ?   sD    " >>")zt")z  04     c                 R    t        | |d      }|j                  j                         S )u/   명령 실행 후 stdout을 strip하여 반환.Tr    r!   )r*   r%   strip)r   r    results      r   _outr0   Z   s#    $Ct,F==  r+   project_pathc                    	 t        g d|       }|j                  d      d   S # t        j                  $ r Y nw xY w	 t        g d|       }|j	                         D cg c]  }|j                          nc c}w }}dD ]
  }||v s|c S  n# t        j                  $ r Y nw xY w	 t        g d|       S # t        j                  $ r Y yw xY w)	u   메인 브랜치명 감지.

    git symbolic-ref refs/remotes/origin/HEAD → 실패 시 main/master fallback.

    Args:
        project_path: git 저장소 루트 경로.

    Returns:
        메인 브랜치명 (예: "main" 또는 "master").
    )gitzsymbolic-refzrefs/remotes/origin/HEADr    /)r3   branch--format=%(refname:short))mainmaster)r3   	rev-parsez--abbrev-refHEADr9   )r0   splitr'   CalledProcessError
splitlinesr.   )r1   refbranches_rawbbranches	candidates         r   detect_main_branchrE   `   s    ?

 yy~b!!(( 
:
 (4'>'>'@A!AGGIAAA+ 	!IH$  	! (( @lSS(( sG   "% ;;!B  A87B 	B B B%$B%)B8 8CCc                    t        g d|       }g }i }|j                         D ]L  }|j                         s|r|j                  |       i })d|v r|j	                  d      \  }}}|||<   Hd||<   N |r|j                  |       |S )u   git worktree list --porcelain 파싱.

    Args:
        project_path: git 저장소 루트 경로.

    Returns:
        각 worktree 정보 딕셔너리 리스트.
        키: "worktree", "HEAD", "branch" (branch는 없을 수 있음)
    )r3   worktreelist--porcelainr4     )r0   r?   r.   append	partition)r1   output	worktreescurrentlinekey_values           r   list_worktrees_rawrU      s     2F
 ')I G!!# zz|  )$; NN3/MCE GCL GDM !r+   task_idteam_idc                     d|  d| S )u   worktree 브랜치명 생성.task/- )rV   rW   s     r   branch_namer\      s    7)1WI&&r+   c                 @    t        t        |       dz  | d| z        S )u$   worktree 디렉터리 경로 생성.z
.worktreesrZ   )strr   )r1   rV   rW   s      r   worktree_pathr_      s'    tL!L0gYay3IIJJr+   c                 v     t        j                         dt        dt        t        t        f   f fd       }|S )Nr1   r   c                 .   |j                  dd      r 	| g|i |S t        |       dz  }|j                         sdd|  dS t        |       dz  }d}t        j                  g d| d	
      }|j
                  dk7  rgt        |d      5 }|j                         r/|j                         j                  dkD  r|j                  d       n|j                  d       d d d        d	} 	| g|i |}t        |t              r|rd	|d<   |S # 1 sw Y   0xY w)N	read_onlyFz.giterrorzNot a git repository: statusmessagez
.gitignore)r3   zcheck-ignorez-qz.worktrees/T)r    capture_outputr   az
.worktrees/
z.worktrees/
gitignore_updated)r   r   r   r'   r(   
returncodeopenstatst_sizewrite
isinstancedict)
r1   r   kwargsgit_dirgitignore_pathri   check_resultfr/   funcs
            r   wrapperz)validate_worktree_safety.<locals>.wrapper   s%    ::k5)6t6v66|$v-~~%4J<.2YZZl+l:!!~~8
 ""a'nc* -a!((*~/B/B/D/L/Lq/PGG-.GGO,	-
 !%l4T4V4fd#(9*.F&'- -s   ADD)	functoolswrapsr^   rp   r   )rv   rw   s   ` r   validate_worktree_safetyrz      s<    __Tc tCH~  @ Nr+   )z.envz
.env.localz.env.developmentz.env.development.local	dest_pathc                 x   ddl }t        |       }t        |      }g }|j                         r|j                         s|S t        D ]A  }||z  }|j	                         s||z  }	 |j                  ||       |j                  |       C |S # t        $ r%}	t        j                  d| d|	        Y d}	~	od}	~	ww xY w)u  project_path 루트의 .env 패턴 파일들을 dest_path로 복사.

    `.env.example`, `.env.sample` 같은 템플릿은 무시한다 (이미 git에 커밋됨).
    secret 안전: 파일 내용/절대경로는 로그/응답에 노출하지 않고 basename만 반환.

    Args:
        project_path: 원본 프로젝트 루트 경로.
        dest_path: 복사 대상 (워크트리) 경로.

    Returns:
        복사된 파일명 리스트 (basename만).
    r   Nz[copy_env] u    복사 실패: )
shutilr   is_dir_ENV_COPY_PATTERNSis_filecopy2rL   r   loggerr   )
r1   r{   r}   src_rootdst_rootcopiednamesrcdstexcs
             r   _copy_env_filesr      s     L!HIHF??HOO$5" o{{}o	LLc"MM$ M	  	NN[.>seDE	s   $#B	B9B44B9rb   copy_envc                    |rddddg dS t        ||      }t        | ||      }t        |       }|D ]  }|j                  d      |k(  sd||g dc S  t	        |      j
                  j                  dd	       	 t        d
dd|g|        d}	|	rt        d
dd||g|        nt        d
ddd||g|        t        d
ddd|g|d       g }
|rt        | |      }
d|||
dS # t        j                  $ r d}	Y iw xY w)u6  worktree 생성 또는 재사용.

    Args:
        project_path: git 저장소 루트 경로.
        task_id: 태스크 식별자.
        team_id: 팀 식별자.
        read_only: True이면 worktree 미생성 (read 에이전트 전용).
        copy_env: True이면 워크트리 생성 직후 project_path 루트의 .env 패턴
            파일을 워크트리로 자동 복사 (task-2377). 기본 True.

    Returns:
        {"status": "created"|"reused"|"skipped", "worktree_path": str|None,
         "branch": str|None, "copied_env_files": list[str]}
    skippedNu#   read-only agent: worktree 미생성)re   r_   r7   reasoncopied_env_filesrG   reused)re   r_   r7   r   Tparentsexist_okr3   r;   z--verifyr4   Faddz-bpush-uoriginr-   created)r\   r_   rU   r   r   r   mkdirr0   r'   r>   r*   r   )r1   rV   rW   rb   r   r7   wt_pathexistingwtbranch_exists
copied_envs              r   
cmd_creater     sc   , !; "
 	
 '*FL'7;G ",/H 66*("!( $&	  	Mtd;KV4	
  Jw7	
 	JtVW=	
 		h/ J$\7;
  &	 9 (( s   :C C76C7c                 .   t        t              j                  j                  dz  dz  }t        |j	                  |  d            t        |j	                  |  d            z   }|D ]z  }	 |j                  d      }|j                  d      rT|j                  dd      }|d	kD  r=	 d	d
l}|j                  |d|       }t        |t              rd|v rt        |d         c S | t        t              j                  j                  dz  dz  }
	 t+        j,                  |
j                  d            }|j/                  | i       }|j/                  dd      }|r)t        |j1                  dd      j3                               S 	 y	# t        $ rH d	d
l} |j                  d|d| |j                         }	|	rt        |	j#                  d            cY c S Y w xY w# t$        t&        t(        f$ r Y w xY w# t$        t*        j4                  t&        f$ r Y y	w xY w)u6   task 파일에서 level을 읽어 반환. 없으면 0.memorytasksz.mdz*.mdutf-8encodingz---   r   Nlevelz^level:\s*(\d+)r   ztask-timers.json
work_levelrK   lv)r   r   r   rH   globr   
startswithfindyaml	safe_loadro   rp   intImportErrorresearch	MULTILINEgroupr   
ValueError	TypeErrorr   r   r   replacer.   r   )rV   	tasks_dir
candidatespr$   endr   fmr   mtimers_pathtimersentrywls                 r   _resolve_task_levelr   r  s   X%%,,x7'AIinny_56innPWyX\M]>^9__J 	;;;0Du%iiq)73#!^^D3K8%b$/GrM#&r'{#33. x.''..9<NNKK1171CD

7B'YY|R(rzz$+11344  + ' 3!%BII&8$q+r||T#&qwwqz?2 	3 Y/ 		 T)):6 sJ   +:G&9FA3G3 A
GGGGGG0/G03HHr7   main_branchc                 2   ddl } |j                  t              }	 t        j                  ddd| d| ddg| d	d
t        j
                  t        j
                  d      }|j                  dk7  r-|j                  d|j                  j                                 y|j                  j                         j                         D cg c]#  }|j                         s|j                         % }}|syd}d|d| dg|z   dgz   }	t        j                  |	| d	d
t        j
                  t        j
                  d      }
|
j                  dk7  r-|j                  d|
j                  j                                 yt        j                  |
j                        }t        |      \  }}dj                  |      }|rdj                  |      nd}|rdj                  |      nd}dt!        |       d| dt!        |       d| dt!        |       d| d}|S c c}w # t        j"                  $ r |j                  d       Y yt        j$                  t&        f$ r}|j                  d|        Y d}~yd}~wt(        $ r}|j                  d|        Y d}~yd}~ww xY w)u8  AST 의존성 분석으로 PR blast radius 요약 생성.

    Args:
        project_path: git 저장소 루트 경로.
        branch: 분석할 브랜치명.
        main_branch: 비교 기준 메인 브랜치명.

    Returns:
        Blast radius 요약 마크다운 문자열. 실패 시 빈 문자열.
    r   Nr3   diffz--name-onlyz...--z*.pyFT   )r    r!   r$   r%   r&   timeoutu    [blast_radius] git diff 실패: rK   z1/home/jay/workspace/scripts/ast_dependency_map.pypython3z--rootz--files--jsonu(   [blast_radius] AST 스크립트 실패: z, u   없음u!   ## Blast Radius
- 변경 파일: u   개 (u   )
- 영향받는 파일: u   )
- 관련 테스트: )u*   [blast_radius] 타임아웃 (30초 초과)u#   [blast_radius] JSON 파싱 실패: u(   [blast_radius] 예상치 못한 오류: )logging	getLogger__name__r'   r(   r)   rj   r   r&   r.   r%   r?   r   r   r   joinlenTimeoutExpiredr   KeyError	Exception)r1   r7   r   r   r   diff_resultru   changed_files
ast_scriptast_cmd
ast_resultr   direct_importers
test_fileschanged_strimporters_str	tests_strsummaryes                      r   _get_blast_radius_summaryr     s    Wx(F< nnFMk]#fX+FfU????
 !!Q&NN=k>P>P>V>V>X=YZ[,7,>,>,D,D,F,Q,Q,SaqWXW^W^W`aa I
j(L)L}\`h_ii^^????

   A%NNEjFWFWF]F]F_E`abzz*++,'9$'?$* ii.7G		"23X-7DIIj)X	  #M 235 F&&)*:&;%<E- Q##&z?"351F 	 G bJ $$ CD  (+ <QC@A A!EFsV   A>H *H HH-H 2BH 6BH H $J;JI,,J8JJ	pr_numberowner	repo_namec                 j   t        ddd| d| d|  dg|d      }|j                  d	k7  rg S 	 t        j                  |j                        }g }|D ]=  }|j                  d
i       j                  dd      }d|j                         vr9|j                  dd      }	d}
|	j                         }t        j                  dt        j                        }t        j                  dt        j                        }d|v s)d|v s%d|	v s!d|	v sd|	v s|j                  |	      sd|v sd|v rd}
n'd|v s!d|	v sd|	v sd|	v s|j                  |	      sd|v rd}
|j                  |
|j                  d d      |	d!d" t        |j                  d#d	            d$       @ |S # t        j
                  t        f$ r g cY S w xY w)%u   GitHub API로 PR 코멘트를 파싱하여 severity 분류된 리스트 반환.

    Returns:
        [{"severity": "high"|"medium"|"low", "path": str, "body": str, "line": int}]
    ghapirepos/r5   /pulls/z	/commentsFr-   r   userloginrK   geminibodylowz&!\[(security-critical|critical|high)\]z!\[(medium)\]zseverity: highzseverity: criticalu   🔴HIGHCRITICALzhigh-priority.svgzcritical.svghighzseverity: mediumu   ⚠️MEDIUMWARNINGzmedium-priority.svgmediumpathNi  rQ   )severityr   r   rQ   )r*   rj   r   r   r%   r   r   r   lowerr   compile
IGNORECASEr   rL   r^   )r   r   r   r    comments_resultcommentsparsedcommentr   	body_textr   
body_lower_high_img_re_medium_img_res                 r   _parse_gemini_commentsr    s    	uugQyk9MNO
 !!Q&	::o445 $&F %
{{62&**7B74::<'KK+	__&
zz"KR]][$4bmmD
*#z1""Y&""9-"j0+H*,9$9$I%$$Y/$
2H$FB/!$3GKK23		
=%
L MU   (+ 	s   F F21F2r   r_   collect_modec                    | D cg c]  }|d   dk(  s| }}|sg dddS g }|D ]'  }d|d    d|d	    d
|d    }|j                  |       ) |r|dddS dj                  |      }t        dd|dg|d       t        g d|d       t        g d|d       t        g d|d      }|j                  dk(  r|j                  j                         nd}	t        ddg|d       |d|	dS c c}w )u	  HIGH severity 코멘트를 기반으로 자동 수정 프롬프트 생성 및 실행.

    collect_mode=False(기본값)이면 실제 수정 실행. True이면 프롬프트만 생성.

    Returns:
        {"prompts": [...], "executed": bool, "diff_stat": str}
    r   r   FrK   )promptsexecuted	diff_statz)Fix the following HIGH severity issue in r   z (line rQ   z):
r   z

---

claudez-pz--dangerously-skip-permissionsr-   )r3   r   z-A)r3   commitz-mz&[auto-fix] Gemini HIGH severity issues)r3   r   z--statzHEAD~1r   r3   r   T)rL   r   r*   rj   r%   r.   )
r   r_   r  chigh_commentsr  promptcombined_promptr   r  s
             r   _auto_fix_high_commentsr  '  s>    !)D1AjMV,CQDMD5rBBG <QvYK{STU[S\R]]abcdjbkalmv "BGG $((1O	4*JK 		=>I +K
 /:.D.D.I""((*rI 	%m59DyIIO Es
   C+C+)zsql injectionxsscsrfauth
permissionznull pointerzrace conditiondeadlockz	data loss
corruptionzenv variableconfigaccessibilitya11y
responsiveMEDIUM_FIX_PATTERNS)znaming conventionz
code style
formatting
whitespaceztype annotation	docstringMEDIUM_SKIP_PATTERNSc           
      @   | D cg c]  }|d   dk(  s| }}g }|D ]y  }|d   j                         }|rd}d}n3d}d}t        D ]  }||v sd}|} n |dk(  rt        D ]  }||v sd}|} n |j                  d||d   |j	                  d	d      |d
       { |S c c}w )uS  MEDIUM 코멘트를 FIX/SKIP/DEFER 3종으로 자동 분류.

    collect_mode=False(기본값)이면 패턴 매칭으로 분류. True이면 모든 MEDIUM을 DEFER로 분류하고 로그만 수집.

    Returns:
        [{"severity": "medium", "classification": "FIX"|"SKIP"|"DEFER", "body": str, "path": str, "pattern_matched": str}]
    r   r   r   DEFERr  rK   FIXSKIPr   )r   classificationr   r   pattern_matched)r   r  r  rL   r   )	r   r  r	  medium_comments
classifiedr   r!  r"  patterns	            r   _classify_medium_commentsr&    s     #+HQa
mx.GqHOH')J !
vY__&
$N,O %N O. j(%*N&-O	 (3 G*,)/*1	 	$"0&	fb)#2	
3!
F M Is
   BBr$  c           	      f   t        t              j                         j                  j                  dz  dz  dz  }g }|j	                         r$	 t        j                  |j                               }| D ]W  }t        j                  d      |d   |d   dd |j                  d	d
      |j                  dd
      d}|j                  |       Y |j                  j                  dd       |j                  t        j                   |dd             y# t
        j                  t        f$ r g }Y w xY w)u0   MEDIUM 분류 결과를 로그 파일에 기록.	dashboardr   zmedium-comments-log.jsonz%Y-%m-%dT%H:%M:%Sr!  r   N   r   rK   r"  )	timestampr!  r   r   r"  Tr      F)indentensure_ascii)r   r   resolver   r   r   r   r   r   r   r   r   r   rL   r   r   r   )r$  log_pathr   r	  r   s        r   _log_medium_commentsr0    s   H~%%'..55CfLOiiH%'H	zz("4"4"67H  ':; 01fIdsOEE&"% uu%6;
 	 OO$6

8AEJK $$g. 	H	s   #D D0/D0actionpr_titlepr_bodygemini_timeoutc                 F  9 |dk(  rt        |      }|dk\  rdnd}t        ||      }	t        | ||      9t        |       }
t	        9fd|
D              }|dk(  r[d}|rQt        |       }t        g d9d	       t        d
d|dg9d	      }|j                  dk(  rd}nt        g d9d	       d}d|	|dS |dk(  r|st        d9       t        |       }t        g d9d	       t        d
d|dg9d	      }|j                  dk7  r1t        g d9d	       |j                  xs d}t        d|	 d|       t        d
d|g|        t        d
dd|	g| d	      }|j                  dk7  r"t        g d| d	       t        d|	 d| d      t        d
ddd9g|        t        d
d d!|	g| d	       t        d
d"d#d$|	g| d	       d%|	d&S |d'k(  rl|st        d9       t        g d(9d	       t        g d)9d	       t        d
ddd9g|        t        d
d d*|	g| d	       t        d
d"d#d$|	g| d	       d+|	d&S |dk(  r|st        d9       t        |       }t        g d9d	       t        d
d|dg9d	      }|j                  dk7  rt        g d9d	       t        d|	       t        d
d"d,d#|	g9d	       |xs d-| d.| }t        | |	|      }|r|d/z   |z   }t        j                  d0|xs d1| d2       t               }t        |       d3z  d4z  }|j                         s1dd5l}|j"                  j%                  d6d7      }t        |      d3z  d4z  }t        d8t'        |      d9|d:g9d	      }t        j                  d;|j                         d}d}	 dd5l}dd5l}|j"                  j%                  d6d7      }t        |      d<z  d=z  | d>z  }|j                         rO|j+                  |j-                  d?@            }|j%                  dAi       j%                  dB      }|rt'        |      }|j                  dk7  r|st        dD|j2                         d}!d}"dE}#t        g dF9d	      }$d}%d}&|$j                  dk(  rSt)        j*                  |$j                        }'|'j%                  dGi       j%                  dHd      }%|'j%                  dId      }&|"|k  rm|rkt        dJdKdL|% dM|& dN| dOg9d	      }(|(j                  dk(  rdP|(j                  j5                         v rdQ}!n"t7        j8                  |#       |"|#z  }"|"|k  r|rkd})g }*d}+dR},g }-g }.|!s|rt        j                  dS       t7        j8                  dT       t        dJdKdL|% dM|& dN| dOg9d	      }/|/j                  dk(  r3dP|/j                  j5                         v rdQ}!t        j                  dU       |!rE|rBt;        |,      D ]  }0t=        ||%|&9      }-|-D 1cg c]  }1|1dV   dWk(  s|1 }2}1t?        |2      })|)dk(  s|0|,dXz
  k(  r!|-D 1cg c]  }1|1dV   |1dY   |1dZ   d5d[ d\ }*}1 n|+dXz  }+tA        |29|]      }3|r!|-D 1cg c]  }1|1dV   |1dY   |1dZ   d5d[ d\ }*}1 n|3j%                  d^      sd}4|4|k  st        dJdKdL|% dM|& dN| dOg9d	      }5|5j                  dk(  rdP|5j                  j5                         v rt7        j8                  dE       |4dEz  }4|4|k  rg tC        |-|]      }.|.rtE        |.       d_}6|!sd`}7n
|)dk(  rda}7ndb}7|!sdc}6t        j1                  dd|       n|)dk(  rt        j                  de       df}6ndg}6|6|	|||!|! |7|)|*|+|.r7|.D 1cg c]+  }1|1dh   |1j%                  dYd      |1j%                  did      dj- c}1ng dk}8|r|j%                  dld      |8dm<   |8S tG        dn| do      # t.        $ r!} t        j1                  dC|        Y d5} ~ d5} ~ ww xY wc c}1w c c}1w c c}1w c c}1w )pu  worktree 작업 완료 처리.

    Args:
        project_path: git 저장소 루트 경로.
        task_id: 태스크 식별자.
        team_id: 팀 식별자.
        action: "merge" | "discard" | "keep" | "pr" | "auto" (auto: task level에 따라 자동 결정)
        pr_title: PR 제목 (기본값: "[{task_id}] worktree finish").
        pr_body: PR 본문.
        gemini_timeout: Gemini 리뷰 대기 최대 시간(초).
        collect_mode: False이면 실제 수정 루프 실행(기본값), True이면 프롬프트 수집만.

    Returns:
        {"status": "merged"|"discarded"|"kept"|"pending"|"merge_failed"|"blocked_by_high_severity", "branch": str}
    autor+  prkeepc              3   F   K   | ]  }|j                  d       k(    yw)rG   N)r   ).0r   r   s     r   	<genexpr>zcmd_finish.<locals>.<genexpr>  s     DR266*%0Ds   !r   )r3   fetchr   Fr-   r3   mergez	--no-editr   synced)r3   r=  z--abortconflictkept)re   r7   sync_with_mainzworktree not found: rK   uC   main 최신화 중 충돌 발생. 수동 해결 필요.
브랜치: u   
충돌 파일:
checkoutr4   z--no-ffz'Merge conflict detected while merging 'z' into 'z'. Resolve conflicts manually.rG   remove--forcer7   -dr   r   --deletemerged)re   r7   discard)r3   rB  r   .)r3   cleanz-fdz-D	discardedr   zTask z	 by team z

uE   [task-2467] worktree_manager → taskctl pr-open 위임 (pr_title=%r)[z] worktree finishscriptsz
taskctl.pyNWORKSPACE_ROOTz/home/jay/workspacer   zpr-openz--autou2   [task-2467] taskctl pr-open --auto 호출: exit=%sz.tasksstatez.jsonr   r   evidencer   u:   [task-2467] state 파일에서 PR 번호 읽기 실패: %su   taskctl pr-open 실패: r   )r   repoviewr   z
owner,namer   r   r   r   r   r   r5   r   z/reviewszgemini-code-assistTr   u6   [gemini-retry] 타임아웃 후 60초 추가 대기...<   u;   [gemini-retry] 재확인 성공 — Gemini 리뷰 감지됨r   r   r   r   r   r)  )r   r   r   )r  r  pendingTIMEOUTPASSBLOCKEDblocked_by_timeoutzJGemini review timed out for PR #%s. Merge blocked. Manual review required.uU   [task-2467] worktree_manager에서 자동 머지 폐기. taskctl merge 호출 안내.pr_opened_taskctl_pendingblocked_by_high_severityr!  r"  )r!  r   r"  )re   r7   pr_urlr   gemini_reviewedr4  gemini_verdicthigh_severity_countreview_summaryauto_fix_attemptsmedium_classifiedr   rate_limit_warningzUnknown action: 'z'. Use merge|discard|keep|pr.)$r   r\   r_   rU   anyrE   r*   rj   RuntimeErrorr%   r   r   infor   r   r   osenvironr   r^   r   r   r   r   r   r&   r   r   sleepranger  r   r  r&  r0  r   ):r1   rV   rW   r1  r2  r3  r4  r  r   r7   r   wt_foundsync_statusr   sync_resultconflict_infomerge_resultr   blast_summaryrate_limit_resulttaskctl_path_os_ws	pr_resultr[  r   _json_os2_ws2_state_path_state_data_pr_n_egemini_foundelapsedinterval	repo_infor   r   rireviews_resultr^  r_  r`  max_auto_fix_attemptsr   ra  retry_resultattemptr	  r
  
fix_result
re_elapsed
re_reviewsmerge_statusr]  r/   r   s:                                                            @r   
cmd_finishr    s	   6 #G,!'*FL'7;G ",/HD8DDH,\:K+Fk:K
 %%*&0gUK( FkRR!5gY?@@(6 	'WEBG[+6

 !!Q&,'G'..4"MZ[aZbbx  zG  yH  I 
 	eZ-<@GY/
 ""a',,eL9& B= >@  	eZ9g>LQeXtV,,eLFHj&9	
 #f55!5gY?@@ 	+F$'?eZ9g>LQeXtV,,eLFHj&9	
 &88~!5gY?@@(6 	'WEBG[+6

 !!Q&,'G!eflemnoo 	eVT8V4'O
 =E')G9=1,T&==0D[]e  ^Hklmtlu  vG  jH  	I-/ L)I5D""$++//"24IJC9y0<?LL)9gxH
	
 	H)J^J^_ 		] <<##$46KLDt*x/'9wiu<MMK!!##kk+*?*?*?*QR#
B7;;KH #E
I 1$Y!9):J:J9KLMM  :
	
 	1$I,,-BFF7B'++GR8Evr*I&9!uugQyk8TUN
 ((A-2F.J_J_JeJeJg2g#JJx xG &9  /1 !')24 	KKPQJJrNuugQyk8TUL
 &&!+0DH[H[HaHaHc0c#YZI !67 #)/	5)WU,2 Nqa
mv6M N N&)-&8#&!+w:ORS:S/Sio&deQz]AfIqQWyY]Z]_&N &  "Q&!4]GZfg
 jp&deQz]AfIqQWyY]Z]_&N &  >>*-!"J$~5%)!5F5'9+WYKW_*`a '"'&

 &00A5:NR\RcRcRiRiRk:k!

2"b(
 %~55#)L !:&| \ $%67 !&N A%#N&N/LNNgirs A% KKop6L 6L #"+"..,#6,!2 # +" 	 '((8&9EE&"-'(uu->'C" )+%"
( +<+@+@B+OF'(
(0MN
OOi  	]NNWY[\\	]| !O&&t"s7   B_" ``6`,`0`"	`+``c                 R   t        |       }g }|D ]  }|j                  dd      }|j                  d      s'|j                  d      }|j                  d      }|j	                  d      }|dk(  r`|d| }||d	z   d }	|j                  |j                  d
d      |||	d        d|iS )u  활성 worktree 목록 반환.

    task/<task_id>-<team_id> 패턴 브랜치를 가진 worktree만 포함.

    Args:
        project_path: git 저장소 루트 경로.

    Returns:
        {"worktrees": [{"path": str, "branch": str, "task_id": str, "team_id": str}]}
    r7   rK   zrefs/heads/task/zrefs/heads/rY   rZ   r6   Nr   rG   r   r7   rV   rW   rO   )rU   r   r   removeprefixrfindrL   )
r1   rawr/   r   
branch_refshort_branch	task_partdash_idxt_idtm_ids
             r   cmd_listr    s     \
*C#%F 
VVHb)
$$%78!..}= !--g6	 ??3'r>(#(Q,.)z2.& 		
'
8   r+   c           	      <   t        |       }t        |       }	 t        ddd|dg|       }|j                         D ch c]#  }|j	                         s|j	                         % }}g }g }|d   D ]  }|d   }	|d   }
|d   }|d	   }|	|v rNt        dd
dd|
g|        t        ddd|	g| d       t        dddd|	g| d       |j                  |
|	||d       i|j                  |
|	||dd        ||dS c c}w # t
        j                  $ r t               }Y w xY w)uU  머지 완료된 워크트리를 자동 정리.

    main 브랜치에 이미 머지된 task/ 브랜치의 워크트리만 제거한다.
    머지되지 않은 워크트리는 건드리지 않는다 (안전장치).

    Args:
        project_path: git 저장소 루트 경로.

    Returns:
        {"cleaned": [...], "skipped": [...]}
    r3   r7   z--mergedr8   r4   rO   r   rV   rW   rG   rC  rD  rE  Fr-   r   r   rF  r  
not_merged)r   r7   rV   rW   r   )cleanedr   )
r  rE   r0   r?   r.   r'   r>   setr*   rL   )r1   listedr   
merged_rawrB   merged_branchesr  r   r   r7   r   rV   rW   s                r   cmd_cleanupr  E  sv    l#F$\2K Hj+7RS

 /9.C.C.ES1779SS %'G$&G[! 'HV*Y-Y-_$
HiA  $/ 
 *f= 
 NN#$&&	 NN#$&&*?'R 733a T((  % s(   $C; C6C6$C; 6C; ;DDc           	      6   t        |       }|d   D cg c]  }|d   |k(  s| }}g }t        |       }|D ]  }|d   }|d   }		 t        g d|      }
t        |
j	                         D cg c]  }|j                         s| c}      }	 t        dd	d
| d|	 g|      }|j                         rt        |      nd}|j                  ||	||d        d|iS c c}w c c}w # t        j                  $ r d}Y qw xY w# t        j                  $ r d}Y Xw xY w)u4  특정 task_id에 해당하는 모든 worktree 상태 반환.

    Args:
        project_path: git 저장소 루트 경로.
        task_id: 태스크 식별자 (team_id 무관하게 검색).

    Returns:
        {"worktrees": [{"path": str, "branch": str, "changed_files": int, "commits_ahead": int}]}
    rO   rV   r   r7   )r3   re   rI   r4   r   r3   zrev-listz--countz..)r   r7   r   commits_ahead)r  rE   r0   r   r?   r.   r'   r>   isdigitr   rL   )r1   rV   r  wmatchingr/   r   r   r   r7   
status_outrQ   r   	ahead_outr  s                  r   
cmd_statusr    sU    l#F!+.Ja!I,'2IJHJ#%F$\2K $
V*H	0J  *2G2G2I Z$TZZ\ Z[M
	"m2fX.	 I /8.?.?.AC	NqM 	 !.!.		
;$
L   W K ![,, 	M	 ,, 	M	sF   CC&C%*C 
 C 
C%3D  C%%C=<C= DDc                     t        j                  dd      } | j                  dd      }|j                  dd	      }|j	                  d
d	       |j	                  dd	       |j	                  dd	       |j	                  ddd       |j                  dd	      }|j	                  d
d	       |j	                  dd	       |j	                  dd	       |j	                  ddg dd       |j	                  ddd       |j	                  ddd       |j	                  d d!d"       |j	                  d#d!d$       |j	                  d%t
        d&d'(       |j                  d)d*	      }|j	                  d
d	       |j                  d+d,	      }|j	                  d
d	       |j                  d-d.	      }|j	                  d
d	       |j	                  dd	       | S )/u   argparse 파서 구성.zworktree_manager.pyu6   Git Worktree 관리 스크립트 (멀티봇 환경용))progdescriptioncommandT)destrequiredcreateu   새 worktree 생성)helpr1   u   git 저장소 루트 경로rV   u   태스크 ID (예: 329.1)rW   u   팀 ID (예: dev1)z--no-copy-env
store_trueuO   워크트리 생성 시 .env 파일 자동 복사 건너뛰기 (기본: 복사))r1  r  finishu   worktree 작업 완료u   태스크 IDu   팀 IDz--action)r=  rH  r8  r7  r6  u)   완료 액션: merge|discard|keep|pr|auto)r  choicesr  z
--worktreeNuA   worktree 경로 정식 지정 (TASKCTL_CWD env deprecated 대체))defaultr  z
--pr-titlerK   u	   PR 제목z	--pr-bodyu	   PR 본문z--gemini-timeout,  u    Gemini 리뷰 대기 시간(초))typer  r  cleanupu'   머지 완료된 worktree 자동 정리rH   u   활성 worktree 목록re   u   worktree 상태 확인)argparseArgumentParseradd_subparsers
add_parseradd_argumentr   )parsersubp_createp_finish	p_cleanupp_listp_statuss          r   build_parserr    s   $$"LF 

Y

>C ~~h-B~CH./LM)*EF)*>?^   ~~h-E~FH./LM).9)(3:8	   P  
 P  
 ,E+rD,3Jlm y/XYI>0MN ^^F)A^BF
-JK ~~h-E~FH./LM).9Mr+   c                     t               } | j                         }	 |j                  dk(  r:t        |j                  |j
                  |j                  t        |dd             }n|j                  dk(  r\t        |j                  |j
                  |j                  |j                  t        |dd      t        |dd      t        |d	d
            }n|j                  dk(  rt        |j                        }ng|j                  dk(  rt        |j                        }nB|j                  dk(  r!t        |j                  |j
                        }ndd|j                   d}t'        t)        j*                  |dd             |j-                  d      dk(  rt/        j0                  d       yy# t        j                  t        t         t"        f$ r}dt%        |      d}Y d}~d}~ww xY w)u   CLI 메인 진입점.r  no_copy_envF)r   r  r2  rK   r3  r4  r  )r2  r3  r4  r  rH   re   rc   zUnknown command: rd   Nr+  )r-  r,  r   )r  
parse_argsr  r   r1   rV   rW   getattrr  r1  r  r  r  r'   r>   rd  r   r   r^   printr   r   r   sysexit)r  r   r/   r   s       r   r9   r9     s   ^FD: <<8#!!$T=%@@	F \\X%!! z26i4&t-=sCF \\Y& !2!23F\\V#d//0F\\X% 1 14<<@F '6G~4VWF
 
$**V%
:;zz(w& ' ))<WM :#C9:s   E F( (#G#GG#__main__)NTT)N)FT)F)rK   rK   r  F)r   N)9__doc__r  rx   r   r   r   r'   r  r   pathlibr   typingr   r^   r   r.  r   _WS_ROOTr   insertutils.blast_radius_parserr   r   r   r   rp   r   rH   boolCompletedProcessr*   r0   rE   rU   r\   r_   rz   r   r   r   r   r   r   r  r  r  __annotations__r  r&  r0  r  r  r  r  r  r  r9   r[   r+   r   <module>r     su       	  
    tH~%%'//23388HHOOAx  8			8	$4S> 4 	
s)	t  	
   %6!tCy !sTz !S !'S 'S 'T"S "T$sCx.-A "T' 's 's '
K Kc KC KC K"V Z ## ## #$s) #L 
 WWW W 	W
 W 
#s(^W Wt' ' 'TKC K K3 KSV K\:c :# :# :C :TXY]^acf^fYgTh :| NS1J4S>"1J361JFJ1J	#s(^1Jh" T#Y .
# d3i 
.T#s(^(< .D .]abfgjlogobp]q .bLT$sCx.%9 Ld L2  KPKPKP KP 	KP
 KP KP KP KP 
#s(^KP KP\
*!3 *!4S> *!ZE4c E4d38n E4P6!S 6!3 6!4S> 6!|:h-- :z(V zF r+   