
    Ri                        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j                  e      Zdeeef   fdZ	 	 	 d5dee   dedz  d	ed
edej*                  e   f
dZd6d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ed7d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!	 d7d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&<   d7deeeef      d!edeeeef      fd'Z&d(eeeef      ddfd)Z'e	 	 	 	 d8dededed*ed+ed,ed-ed!edeeef   fd.       Z(dedeeef   fd/Z)dedeeef   fd0Z*dededeeef   fd1Z+dejX                  fd2Z-d9d3Z.ed4k(  r e.        yy):u  
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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      !   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      I/home/jay/workspace/.worktrees/task-2117-dev1/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)   8   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   _outr/   S   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   /)r2   branch--format=%(refname:short))mainmaster)r2   	rev-parsez--abbrev-refHEADr8   )r/   splitr&   CalledProcessError
splitlinesr-   )r0   refbranches_rawbbranches	candidates         r   detect_main_branchrD   Y   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는 없을 수 있음)
    )r2   worktreelist--porcelainr3     )r/   r>   r-   append	partition)r0   output	worktreescurrentlinekey_values           r   list_worktrees_rawrT      s     2F
 ')I G!!# zz|  )$; NN3/MCE GCL GDM !r*   task_idteam_idc                     d|  d| S )u   worktree 브랜치명 생성.task/- )rU   rV   s     r   branch_namer[      s    7)1WI&&r*   c                 @    t        t        |       dz  | d| z        S )u$   worktree 디렉터리 경로 생성.z
.worktreesrY   )strr   )r0   rU   rV   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 )Nr0   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)r2   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)
r0   r   kwargsgit_dirgitignore_pathrh   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]   ro   r   )ru   rv   s   ` r   validate_worktree_safetyry      s<    __Tc tCH~  @ Nr*   ra   c                    |rdddddS t        ||      }t        | ||      }t        |       }|D ]  }|j                  d      |k(  sd||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       d||dS # t        j                  $ r d}Y Xw xY w)ue  worktree 생성 또는 재사용.

    Args:
        project_path: git 저장소 루트 경로.
        task_id: 태스크 식별자.
        team_id: 팀 식별자.
        read_only: True이면 worktree 미생성 (read 에이전트 전용).

    Returns:
        {"status": "created"|"reused"|"skipped", "worktree_path": str|None, "branch": str|None}
    skippedNu#   read-only agent: worktree 미생성)rd   r^   r6   reasonrF   reused)rd   r^   r6   Tparentsexist_okr2   r:   z--verifyr3   Faddz-bpush-uoriginr,   created)r[   r^   rT   r   r   r   mkdirr/   r&   r=   r)   )	r0   rU   rV   ra   r6   wt_pathexistingwtbranch_existss	            r   
cmd_creater      sD    !;	
 	
 '*FL'7;G ",/H 66*("!(   	Mtd;KV4	
  Jw7	
 	JtVW=	
 		h/   / (( s   8C C$#C$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*.mdzutf-8)encodingz---   r   Nlevelz^level:\s*(\d+)r	   ztask-timers.json
work_levelrJ   lv)r   r   r   rG   globr   
startswithfindyaml	safe_loadrn   ro   intImportErrorresearch	MULTILINEgroupr   
ValueError	TypeErrorr   r   r   replacer-   r   )rU   	tasks_dir
candidatespr#   endr   fmr   mtimers_pathtimersentrywls                 r   _resolve_task_levelr   0  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r6   main_branchc                 ^   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                        }|j                  dg       }|j                  dg       }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   Nr2   diffz--name-onlyz...--z*.pyFT   )r   r    r#   r$   r%   timeoutu    [blast_radius] git diff 실패: rJ   z1/home/jay/workspace/scripts/ast_dependency_map.pypython3z--rootz--files--jsonu(   [blast_radius] AST 스크립트 실패: direct_importers
test_filesz, u   없음u!   ## Blast Radius
- 변경 파일: u   개 (u   )
- 영향받는 파일: u   )
- 관련 테스트: )u*   [blast_radius] 타임아웃 (30초 초과)u#   [blast_radius] JSON 파싱 실패: u(   [blast_radius] 예상치 못한 오류: )logging	getLogger__name__r&   r'   r(   ri   r   r%   r-   r$   r>   r   r   r   joinlenTimeoutExpiredr   KeyError	Exception)r0   r6   r   r   loggerdiff_resultrt   changed_files
ast_scriptast_cmd
ast_resultr   r   r   changed_strimporters_str	tests_strsummaryes                      r   _get_blast_radius_summaryr   Z  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*++,&*hh/A2&F $r :
 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,)JJ,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/r4   /pulls/z	/commentsFr,   r   userloginrJ   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  rP   )severityr   r   rP   )r)   ri   r   r   r$   r   r   r   lowerr   compile
IGNORECASEr   rK   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   FrJ   )promptsexecuted	diff_statz)Fix the following HIGH severity issue in r   z (line rP   z):
r   z

---

claudez-pz--dangerously-skip-permissionsr,   )r2   r   z-A)r2   commitz-mz&[auto-fix] Gemini HIGH severity issues)r2   r   z--statzHEAD~1r   r2   r   T)rK   r   r)   ri   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   rJ   FIXSKIPr   )r   classificationr   r   pattern_matched)r   r  r  rK   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   rJ   r  )	timestampr  r   r   r  Tr~      F)indentensure_ascii)r   r   resolver   r   r   r   r   r   r   r   r   r   rK   r   r   r   )r  log_pathr   r   r   s        r   _log_medium_commentsr  n  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                   3 |dk(  rt        |      }|dk\  rdnd}t        ||      }	t        | ||      3t        |       }
t	        3fd|
D              }|dk(  r[d}|rQt        |       }t        g d3d	       t        d
d|dg3d	      }|j                  dk(  rd}nt        g d3d	       d}d|	|dS |dk(  r|st        d3       t        |       }t        g d3d	       t        d
d|dg3d	      }|j                  dk7  r1t        g d3d	       |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3g|        t        d
d d!|	g| d	       t        d
d"d#d$|	g| d	       d%|	d&S |d'k(  rl|st        d3       t        g d(3d	       t        g d)3d	       t        d
ddd3g|        t        d
d d*|	g| d	       t        d
d"d#d$|	g| d	       d+|	d&S |dk(  r|st        d3       t        |       }t        g d3d	       t        d
d|dg3d	      }|j                  dk7  rt        g d3d	       t        d|	       t        d
d"d,d#|	g3d	       |xs d-| d.}|xs d/| d0| }t        | |	|      }|r|d1z   |z   }t               }t        d2dd3d4|d5|d6|d7|	g3d	      }|j                  dk7  rd}d}t        d2dd8|	d9d:g3d	      }|j                  dk(  rLt        j                  |j                        }t        |j                  d;d            }|j                  d<d      }|st        d=|j                          |j                  j#                         }t        d2dd8|	d9d;g3d	      }|j                  dk(  r9t        t        j                  |j                        j                  d;d            }nd}d}d}d>}t        g d?3d	      }d}d} |j                  dk(  rSt        j                  |j                        }!|!j                  d@i       j                  dAd      }|!j                  dBd      } ||k  rm|rkt        d2dCdD| dE|  dF| dGg3d	      }"|"j                  dk(  rdH|"j                  j%                         v rdI}n"t'        j(                  |       ||z  }||k  r|rkd}#g }$d}%dJ}&g }'g }(|s|rt*        j-                  dK       t'        j(                  dL       t        d2dCdD| dE|  dF| dGg3d	      })|)j                  dk(  r3dH|)j                  j%                         v rdI}t*        j-                  dM       |rE|rBt/        |&      D ]  }*t1        ||| 3      }'|'D +cg c]  }+|+dN   dOk(  s|+ },}+t3        |,      }#|#dk(  s|*|&dPz
  k(  r!|'D +cg c]  }+|+dN   |+dQ   |+dR   dSdT dU }$}+ n|%dPz  }%t5        |,3|V      }-|r!|'D +cg c]  }+|+dN   |+dQ   |+dR   dSdT dU }$}+ n|-j                  dW      sd}.|.|k  st        d2dCdD| dE|  dF| dGg3d	      }/|/j                  dk(  rdH|/j                  j%                         v rt'        j(                  d>       |.d>z  }.|.|k  rg t7        |'|V      }(|(rt9        |(       dX}0|sdY}1n
|#dk(  rdZ}1nd[}1|sd\}0t*        j;                  d]|       nd|#dk(  r]t        d2dd|d^d_g3d	      }|j                  dk(  r7d%}0t        d
d|g| d	       t        d
d`g| d	       t        d
ddd3g| d	       nda}0ndb}0|0|	|||| |1|#|$|%|(r7|(D +cg c]+  }+|+dc   |+j                  dQd      |+j                  ddd      de- c}+ng df}2|r|j                  dgd      |2dh<   |2S t=        di| dj      c c}+w c c}+w c c}+w c c}+w )ku  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)rF   N)r   ).0r   r   s     r   	<genexpr>zcmd_finish.<locals>.<genexpr>  s     DR266*%0Ds   !r{   )r2   fetchr   Fr,   r2   mergez	--no-editr   synced)r2   r(  z--abortconflictkept)rd   r6   sync_with_mainzworktree not found: rJ   uC   main 최신화 중 충돌 발생. 수동 해결 필요.
브랜치: u   
충돌 파일:
checkoutr3   z--no-ffz'Merge conflict detected while merging 'z' into 'z'. Resolve conflicts manually.rF   remove--forcer6   -dr   r   --deletemerged)rd   r6   discard)r2   r-  r   .)r2   cleanz-fdz-D	discardedr   [z] worktree finishzTask z	 by team z

r   createz--titlez--bodyz--basez--headviewr   z
number,urlnumberurlu   PR 생성 실패: r   )r   repor9  r   z
owner,namer   r   namer   r   r4   r   z/reviewszgemini-code-assistTr   u6   [gemini-retry] 타임아웃 후 60초 추가 대기...<   u;   [gemini-retry] 재확인 성공 — Gemini 리뷰 감지됨r   r   r	   r   r   Nr  )r   r   r   )r   r   pendingTIMEOUTPASSBLOCKEDblocked_by_timeoutzJGemini review timed out for PR #%s. Merge blocked. Manual review required.z--mergez--delete-branchpullmerge_failedblocked_by_high_severityr  r  )r  r   r  )rd   r6   pr_urlr   gemini_reviewedr  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^   rT   anyrD   r)   ri   RuntimeErrorr$   r   r   r   r   r]   r   r%   r-   r   r   sleepr   inforanger   r   r   r  r  r   r   )4r0   rU   rV   r  r  r  r  r   r   r6   r   wt_foundsync_statusr   sync_resultconflict_infomerge_resulttitler   blast_summaryrate_limit_result	pr_resultrG  r   find_prpr_infopr_viewgemini_foundelapsedinterval	repo_infor   r   rireviews_resultrJ  rK  rL  max_auto_fix_attemptsr   rM  retry_resultattemptr   r   
fix_result
re_elapsed
re_reviewsmerge_statusrI  r.   r   s4                                                      @r   
cmd_finishrm    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 :ay(9:=E')G9=1,T&==0D-/49eXtX{\dflm
	 1$FItVVX|DG
 !!Q&**W^^4Hb 9:	 UB/"%7	8H8H7I#JKK %%++-FtVVXx@G
 !!Q&

7>> : > >x L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%tWi<MNL
 &&!+'eZ5<uUeV_,eDeZ9gFL`ef-5L #"+"..,#6,!2 # +" 	 '((8&9EE&"-'(uu->'C" )+%"
( +<+@+@B+OF'(
(0MN
OO} !O&&D"s   	_*_*9_//_40_9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}]}
    r6   rJ   zrefs/heads/task/zrefs/heads/rX   rY   r5   Nr	   rF   r   r6   rU   rV   rN   )rT   r   r   removeprefixrfindrK   )
r0   rawr.   r   
branch_refshort_branch	task_partdash_idxt_idtm_ids
             r   cmd_listry    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": [...]}
    r2   r6   z--mergedr7   r3   rN   r   rU   rV   rF   r.  r/  r0  Fr,   r   r   r1  ro  
not_merged)r   r6   rU   rV   r|   )cleanedr{   )
ry  rD   r/   r>   r-   r&   r=   setr)   rK   )r0   listedr   
merged_rawrA   merged_branchesr|  r{   r   r6   r   rU   rV   s                r   cmd_cleanupr  
  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}]}
    rN   rU   r   r6   )r2   rd   rH   r3   r   r2   zrev-listz--countz..)r   r6   r   commits_ahead)ry  rD   r/   r   r>   r-   r&   r=   isdigitr   rK   )r0   rU   r~  wmatchingr.   r   r   r   r6   
status_outrP   r   	ahead_outr  s                  r   
cmd_statusr  R  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                  D   t        j                  dd      } | j                  dd      }|j                  dd	      }|j	                  d
d	       |j	                  dd	       |j	                  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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requiredr8  u   새 worktree 생성)helpr0   u   git 저장소 루트 경로rU   u   태스크 ID (예: 329.1)rV   u   팀 ID (예: dev1)finishu   worktree 작업 완료u   태스크 IDu   팀 IDz--action)r(  r3  r#  r"  r!  u)   완료 액션: merge|discard|keep|pr|auto)r  choicesr  z
--pr-titlerJ   u	   PR 제목)defaultr  z	--pr-bodyu	   PR 본문z--gemini-timeout,  u    Gemini 리뷰 대기 시간(초))typer  r  cleanupu'   머지 완료된 worktree 자동 정리rG   u   활성 worktree 목록rd   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	   ,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                        }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 메인 진입점.r8  r  r  rJ   r  r  r  )r  r  r  r  rG   rd   rb   zUnknown command: rc   NFr  )r  r  r	   )r  
parse_argsr  r   r0   rU   rV   rm  r  getattrr  ry  r  r&   r=   rP  r   r   r]   printr   r   r   sysexit)r  r   r.   excs       r   r8   r8     sx   ^FD: <<8# 1 14<<NF\\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   D2F #G=GG__main__)NTT)N)F)rJ   rJ   r  F)r   N)/__doc__r  rw   r   r   r   r&   r  r   pathlibr   typingr   r   r   r   ro   r]   r   rG   boolCompletedProcessr)   r/   rD   rT   r[   r^   ry   r   r   r   r   r   r   r  __annotations__r  r  r  rm  ry  r  r  r  r  r8   rZ   r*   r   <module>r     s       	  
   			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"T FS F3 F F FZ^_bdg_gZh F FR' ' '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  RPRPRP RP 	RP
 RP RP RP RP 
#s(^RP RPj
*!3 *!4S> *!ZE4c E4d38n E4P6!S 6!3 6!4S> 6!|*h-- *Z#L zF r*   