
    Ki              	          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mZ ddl	m
Z
 ddlmZ 	 ddlmZ  ee      Z	 ddlmZ dZ	 dd
lmZ ddlmZ dZ 	 ddl!m"Z# dZ$	 ddl%m&Z' dZ( e
ejR                  jU                  dd            Z+e+dz  dz  Z,ejR                  jU                  dd      Z-ejR                  jU                  dd      Z.dZ/dZ0dZ1de
de
fdZ2de
dee
   fdZ3de
ddfdZ4dede
fd Z5de
de6fd!Z7de
d"e6ddfd#Z8de
fd$Z9d%edee:e
e6e6f      fd&Z;defd'Z<dedee   fd(Z=d)eddfd*Z>d%ed+e?deddfd,Z@d%eded-e?ddfd.ZAd%eded-e?ddfd/ZBd8d0ZCd8d1ZDd8d2ZEd8d3ZFd8d4ZGd8d5ZHd8d6ZIed7k(  r eI        yy# e$ r< ej                   j#                  d e e
e      j(                               ddlmZ Y w xY w# e$ r dZd	ZY w xY w# e$ r
 dZdZd	Z Y w xY w# e$ r dZ#d	Z$Y w xY w# e$ r dZ'd	Z(Y w xY w)9uq  
순차 작업 체이닝 관리 유틸리티 — 단일팀 순차 체이닝 (chain_manager.py)

[역할] 개별 작업을 순서대로 체이닝하여 실행하는 유틸리티.
       한정승인(scoped delegation)에서 Phase 순차 실행에 사용.
[파일] memory/chains/chain-{chain_id}.json (chain- 접두어)
[호출] dispatch.py --phases → chain_manager.py create/next
[구분] 멀티팀 Phase 오케스트레이션은 chain.py 참조

Usage:
    python3 chain_manager.py create --chain-id <id> --tasks '<JSON>'
    python3 chain_manager.py next --task-id <완료된task>
    python3 chain_manager.py update --task-id <id> --status <running|done|failed|stalled>
    python3 chain_manager.py check --task-id <id>
    python3 chain_manager.py check-stalled --max-hours 2
    python3 chain_manager.py list

참고: /home/jay/workspace/memory/docs/chaining-architecture.md
    N)datetime)Path)Optional)
get_logger)atomic_json_writeTF)calculate_cost)format_cost)log_file_operation)_write_escalation_fileWORKSPACE_ROOTz/home/jay/workspacememorychainsCOKACDIR_CHAT_ID
6937032012COKACDIR_KEY_ANU          
chain_filereturnc                 $    | j                  d      S )uA   체인 파일에 대응하는 lock 파일 경로를 반환한다.z.lock)with_suffix)r   s    $/home/jay/workspace/chain_manager.py
_lock_pathr   ^   s    !!'**    c                 .   t        |       }t        t        dz         D ]  }	 |j                  d       |c S  y# t        $ rQ |t        k  rEt
        j                  dt         d|dz    dt         d|        t        j                  t               Y uw xY w)	uH   lock 파일을 생성하여 락을 획득한다. 실패 시 None 반환.   F)exist_oku   락 획득 실패, u   초 후 재시도 (/z): N)
r   rangeLOCK_RETRY_COUNTtouchFileExistsErrorloggerwarningLOCK_RETRY_WAITtimesleep)r   lockattempts      r   _acquire_lockr,   c   s    j!D)A-. 	,	,JJJ&K	,   	,)))/)::MgXYk]Z[\l[mmpqupvw 

?+	,s   :ABBr*   c                     	 | j                  d       y# t        $ r%}t        j                  d|  d|        Y d}~yd}~ww xY w)u0   lock 파일을 삭제하여 락을 해제한다.T)
missing_oku   락 해제 실패: , N)unlinkOSErrorr%   error)r*   es     r   _release_lockr4   s   sB    8t$ 8*4&1#6778s    	A>Achain_idc                     t         d|  dz  S )u1   chain_id로 체인 파일 경로를 반환한다.zchain-.json)
CHAINS_DIR)r5   s    r   _chain_file_pathr9      s    &
%000r   c                 @   	 t        | dd      5 }t        j                  |      cddd       S # 1 sw Y   yxY w# t        j                  t        f$ r}t
        j                  d|  d| d       t        t        |       dz         }|j                         r	 t        |dd      5 }t        j                  |      cddd       cY d}~S # 1 sw Y    xY w# t        j                  t        f$ r%}t
        j                  d	| d|        Y d}~ d}~ww xY w d}~ww xY w)
uN   체인 파일을 읽어 dict로 반환한다. .bak에서 복구 시도 포함.rutf-8encodingN   체인 파일 읽기 실패: r/   u   . .bak에서 복구 시도..baku   .bak 복구 실패: )openjsonloadJSONDecodeErrorr1   r%   r&   r   strexistsr2   )r   fr3   bake2s        r   _load_chain_filerJ      s   *cG4 	 99Q<	  	  	   '* 	6zl"QCGbcd3z?V+,::<A#sW5 (99Q<( ( ( 	 (('2 A3C52$?@@A	sx   ; /	; 8; ; DADC&C
;	CD
C	CDCD/D
DDDDdatac                    | j                         r-t        t        |       dz         }t        j                  | |       t
        rt        	 t        | |d       yt        | dd      5 }t        j                  ||d	d
       ddd       y# t        $ r"}t        j                  d|        Y d}~Wd}~ww xY w# 1 sw Y   yxY w)uS   체인 데이터를 파일에 저장한다. 저장 전 .bak 백업을 생성한다.r@   Nr   )indentuF   [atomic_write] 원자적 쓰기 실패, 기존 방식으로 fallback: wr<   r=   Fensure_asciirM   )rF   r   rE   shutilcopy2_ATOMIC_WRITE_AVAILABLE_atomic_json_write	Exceptionr%   r&   rA   rB   dump)r   rK   rH   _erG   s        r   _save_chain_filerX      s     3z?V+,Z% #5#A	jz4: 
j#	0 9A		$a89 9  	jNNcdfcghii	j9 9s$   B (B9	B6B11B69Cc                     t        |       }|=t        d| j                   t        j                         t        j
                  d       	  ||i |t        |       S # t        |       w xY w)uI   락을 획득하여 func를 실행하고, 완료 후 락을 해제한다.u   [ERROR] 락 획득 실패: filer   )r,   printnamesysstderrexitr4   )r   funcargskwargsr*   s        r   
_with_lockrd      sZ    $D|+JOO+<=CJJOT$V$dds   A A,task_idc                 6   t         j                  dd       t        t         j                  d            D ]B  }	 t	        |      }|j                  dg       D ]  }|j                  d      | k(  s|||fc c S  D y# t
        j                  t        f$ r Y aw xY w)up   모든 체인 파일에서 task_id를 가진 task를 찾아 (chain_file, chain_data, task_dict)를 반환한다.Tparentsr   chain-*.jsontasksre   N)	r8   mkdirsortedglobrJ   rB   rD   r1   get)re   r   rK   tasks       r   _find_chain_for_taskrp      s    TD1Z__^<= .
	#J/D HHWb) 	.Dxx	"g-!4--	..  $$g. 		s   A<<BBc                  0    t         st        d      t         S )u^   ANU_KEY가 설정되어 있는지 확인하고, 없으면 EnvironmentError를 발생시킨다.uk   COKACDIR_KEY_ANU 환경변수가 설정되지 않았습니다. source /home/jay/workspace/.env.keys 필요.)ANU_KEYEnvironmentError r   r   _require_anu_keyru      s    y
 	
 Nr   c           
      $   t               }d}dd|dddt        d|dg
}t        j                  |d	d	
      }|j                  dk7  r1t
        j                  d|j                  j                                 y	 t        j                  |j                        }|j                  d      }t
        j                  d|  d|        |S # t        j                  t        f$ r3 t
        j                  d|j                  j                                 Y yw xY w)u=   체인 watchdog cron을 등록하고 cron_id를 반환한다.u   python3 /home/jay/workspace/chain_manager.py check-stalled --max-hours 2 실행. stalled 작업 있으면 제이회장님께 보고.cokacdirz--cronz--at2h--chat--keyz--onceTcapture_outputtextr   u   watchdog cron 등록 실패: Ncron_idu   watchdog cron 등록: chain=z
, cron_id=u$   watchdog cron 응답 파싱 실패: )ru   CHAT_ID
subprocessrun
returncoder%   r&   r_   striprB   loadsstdoutrn   inforD   AttributeError)r5   keypromptcmdresultrespr~   s          r   _register_watchdog_cronr      s   

C> 
 	C ^^C4@FA6v}}7J7J7L6MNOzz&--(((9%28*JwiPQ  .1 =fmm>Q>Q>S=TUVs   6AC A	DDr~   c                    t               }dd| dt        d|g}t        j                  |dd      }|j                  dk7  r4t
        j                  d|  d	|j                  j                                 yt
        j                  d
|         y)u   watchdog cron을 제거한다.rw   z--cron-removery   rz   Tr{   r   u%   watchdog cron 제거 실패: cron_id=r/   u%   watchdog cron 제거 완료: cron_id=N)
ru   r   r   r   r   r%   r&   r_   r   r   )r~   r   r   r   s       r   _remove_watchdog_cronr      s    

CC ^^C4@FA>wir&--J]J]J_I`ab;G9EFr   r+   c                     t         r t        	 d| d}t        | |dd|        yyy# t        $ r t        j	                  d|  d| d       Y yw xY w)	u9   재위임 이벤트를 audit-trail.jsonl에 기록한다.Nzmemory/chains/chain-r7   chain_managerretry_attempt_u#   [F12] audit 기록 실패 (task_id=z
, attempt=))_AUDIT_LOGGER_AVAILABLE
_log_auditrU   r%   r&   )re   r+   r5   filepaths       r   _audit_retryr   
  sm    :#9	`-hZu=Hw/^G9;UV $:  	`NN@	T[S\\]^_	`s   ( %AAtotal_attemptsc           
      f   t         rVt        P	 t        dz  dz  }||  dz  }t        | d| dt         d||| |t        |       t        j                  d	|        nt        | ||       t        | ||       y# t        $ r/}t        j                  d
|        t        | ||       Y d}~Ad}~ww xY w)uB   circuit breaker 발동 — utils/circuit_breaker 모듈에 위임.Nr   escalations_escalation.jsonQC FAIL    회 연속 — MAX_RETRY(   ) 초과)contextreasonerror_countoutput_pathre   r5   	max_retryr   u   [F12] Circuit breaker 발동: u6   [F12] circuit_breaker 모듈 호출 실패, fallback: )
_CB_AVAILABLE_cb_write_escalation	WORKSPACE	MAX_RETRYr%   r&   rU   r2   !_trigger_circuit_breaker_fallbackr   )re   r5   r   escalations_direscalation_filer3   s         r   _trigger_circuit_breakerr     s    -9	Q'(2]BO-7);K0LLO !.!11J9+U]^*+!#-	 NN;O;LMN
 	*'8^L.(3  	QLLQRSQTUV-gxPP	Qs   AA8 8	B0%B++B0c                    t         dz  dz  }|j                  dd       ||  dz  }| |t        j                         j	                         d| dt
         dt
        |d	d
}	 t        |dd      5 }t        j                  ||dd       ddd       t        j                  d|        y# 1 sw Y   "xY w# t        $ r%}t        j                  d| d|        Y d}~yd}~ww xY w)uR   circuit_breaker 모듈 미사용 시 fallback — 직접 escalation 파일 생성.r   r   Trg   r   r   r   r   
escalation)re   r5   triggered_atr   r   r   actionrN   r<   r=   Fr   rO   Nu)   [F12] Circuit breaker 발동 (fallback): u'   [F12] escalation 파일 생성 실패: r/   )r   rk   r   now	isoformatr   rA   rB   rV   r%   r&   r1   r2   )re   r5   r   r   r   payloadrG   r3   s           r   r   r   -  s    (*]:O$6%7)3C(DDO 002^,,Ei[PXY(GW/39 	@QIIgquQ?	@B?BSTU	@ 	@  W>>OrRSQTUVVWs0   "B7 0B+
 B7 +B40B7 7	C% C  C%c                    t         j                  dd       	 t        j                  | j                        }t        | dd      }t              |kD  r@t        d	t        |       d
| dt        j                         t        j                  d       | j                  }t        |      }|j                         r3t        d| t        j                         t        j                  d       g }|D ]h  }|j                  |j!                  d      |j!                  d      |j!                  d      d|j!                  d      |j!                  dd      ddd       j |t        | dd      t#        j$                         j'                         dt        | dd      |t        | dd      |d}t)        |      }	|	r|	|d<   nd|d<   t+        |dd      5 }
t        j,                  ||
d d!"       ddd       t        d#|        t.        j1                  d$| d%t        |              y# t        j
                  $ r>}t        d| t        j                         t        j                  d       Y d}~7d}~ww xY w# 1 sw Y   xY w)&u<   체인 파일을 생성하고 watchdog cron을 등록한다.Trg   u"   [ERROR] tasks JSON 파싱 실패: rZ   r   N	max_tasks
   u   [ERROR] tasks 수(u   )가 max_tasks(u   )를 초과합니다.u-   [ERROR] 이미 존재하는 체인입니다: order	task_fileteampendingre   gateauto)r   r   r   statusre   r   
started_atcompleted_at
created_byanuactivescoper   original_task_file)r5   r   
created_atr   r   r   r   rj   watchdog_cron_idrN   r<   r=   Fr   rO   u   [OK] 체인 생성 완료: u   체인 생성: z, tasks=)r8   rk   rB   r   rj   rD   r\   r^   r_   r`   getattrlenr5   r9   rF   appendrn   r   r   r   r   rA   rV   r%   r   )rb   	raw_tasksr3   r   r5   r   normalized_taskstrK   r~   rG   s              r   
cmd_creater   H  sB   TD1JJtzz*	 T;3I
9~	! Y 0	{J_`	
 	MMH!(+J =hZHszzZ $& 
wUU;/f#55+ff-" $		

 dL%8lln..0w+%d,@$G!	D &h/G#* #' 	j#	0 9A		$a89 
'
|
45
KK/(8C8H4I3JKLw  21#6SZZHn9 9s#   H# I7#I463I//I47J c                     | j                   t              }|'dd}t        t        j                  |dd             y|\  }}fd}t        |       y)u8   완료된 task의 다음 pending 작업을 반환한다.Nno_chainr   re   Fr   rO   c                  F   t              } d }| j                  dg       D ]  }|j                  d      k(  s|} n |'dd}t        t        j                  |dd             y |j                  d      }|d	k(  r9|j                  d
      r(ddd}t        t        j                  |dd             y d	|d<   t        j                         j                         |d
<   | d   }|j                  dd      }|dk(  r{t        dz  dz   dz  }|j                         rX|j                  d      }dd l}	d}
d}|	j                  |
||	j                        s|	j                  ||      r|j                  dd      }|t        k  r|dz   |d<   d|d<   t        j                         j                         |d<   d |d
<   t        |        t!        |dz   |       d|d   |d   ||dz   d }t        t        j                  |dd             y t#        ||dz          d!| d<   t        |        d!d"t         d# t%        t        dz  d$z   d%z        d&}t        t        j                  |dd             y t'               }| d   D ]<  }|j                  d      s|j                  d      d'v s)|j)                  |d          > d }t+        | d   d( )      D ]  }|j                  d      d*k(  rQ|j                  d      |v r:t        |        d!d+|d    d,}t        t        j                  |dd              y |} nZ|j                  d      dk(  s}t        |        d-|j                  d      d.d}t        t        j                  |dd              y  |*d|d<   t        j                         j                         |d<   t        |        |t        |d   z  }|j                         s| j                  d/      }|r|t        |z  }|j                         rc	 |j,                  j/                  d0d01       dd l} |j2                  t%        |      t%        |             t4        j7                  d2| d3| d4       d|d   |d   ||j                  d      d7}t        t        j                  |dd             y t              }d8|d<   t        |       |j                  d9      }|rt=        |       t>        rlt@        ftB        `	 tE        |j                  dg             }d:}|d;z  }|d<z  }tA        |||=      }t4        j7                  d>| d?| d@| dAtC        |              dC|dD}t        t        j                  |dd             y # t8        $ rW}t4        j;                  d5|        t        |        d!d6| d,}t        t        j                  |dd             Y d }~y d }~ww xY w# t8        $ r"}t4        jG                  dB|        Y d }~d }~ww xY w)ENrj   re   r   r   Fr   rO   r   doner   already_donezTask already marked as done)r   re   messager5   r   r   r   reportsz.mdr<   r=   r   u?   (?:종합|overall|최종)\s*(?:판정|verdict|결과)[:\s]*FAILu&   QC\s+FAIL(?!\s*[\(\[]?\s*범위\s*외)retry_countr   runningr   dispatchr   r   )r   r   r   r5   re   retry_attemptstalledzcircuit_breaker: MAX_RETRY(z) exceeded for r   r   )r   r   r   )r   r   c                 &    | j                  dd      S Nr   r   rn   r   s    r   <lambda>z,cmd_next.<locals>._do_next.<locals>.<lambda>  s    aeeGQ>O r   r   r   zduplicate task_file: )r   r   already_runningzNext task is already runningr   Trg   u   task_file 자동 생성: u
    (원본: r   u   task_file 복사 실패: zfailed to create task_file: )r   r   r   r5   re   	completedr   zclaude-sonnet-4-6i'  i  )modelinput_tokensoutput_tokensu6   [usage_pricing] 체인 완료 비용 추정 (chain_id=z
): phases=z, model=z, est_cost=u/   [usage_pricing] 비용 추정 실패 (무시): chain_complete)r   r5   )$rJ   rn   r\   rB   dumpsr   r   r   r   rF   	read_textresearch
IGNORECASEr   rX   r   r   rE   setaddrl   parentrk   rQ   copyr%   r   rU   r2   r   _USAGE_PRICING_AVAILABLE_calculate_cost_format_costr   debug)
chain_datatarget_taskro   outputoriginal_statusr5   r   report_pathcontentr   verdict_patternqc_fail_patternr   completed_task_files	next_tasknext_task_fileoriginal_task_file_strr   rQ   r3   chain_data_finalr   _task_count
_est_model
_est_input_est_output_cost_resultrW   r   re   s                               r   _do_nextzcmd_next.<locals>._do_next  sx   %j1
 '+NN7B/ 	Dxx	"g-"	
  *w?F$**V%BC &//(3f$)H )"8F
 $**V%BC &H&.lln&>&>&@N#":. vv.6>#h.:y_LK!!#%///A
  #e"K99_gr}}ESbdkIl"-//-"CK"Y.5@1_M209H-4<LLN4L4L4NL16:N3(Z@$WkAoxH&0)4[)A$/$7(0'.-81_" djjeANO  1(KRSOT/8
8,(Z@&/(CI;o^e]f&g/29x3G-3W]d\eeuZv3v/w"
 djjeANO *-w' 	<Dxx$();?R)R$((k):;	<
 %)	:g.4OP 	Dxx!Y.88K(,@@$Z<"+$9${:K9L"MF $**V%JK 	(#y0 Z8/#xx	2=
 djjeAFG-	0  "+Ih&.lln&>&>&@Il#Z0 &;)??N!((*)38L)M&))25K)K&)002#*1177t7T)'FKK,>(?^ATU"KK*CNCSS]^p]qqr(st %&{3!&)$$==3F $**V%BC  0
;)4X&Z)9:  0334FG%&67 (O,GLLdY"%&6&:&:7B&G"HK!4J!,u!4J"-"4K#2(%/&1$L
 KKPQYPZ [""-hzl C$$0$>#?A +$F $**V%BCo  ) #"LL+DQC)HI,ZD*3,H*L&F "$**V%PQ"RS"#` ! YLL#RSURV!WXXYs3   A"V AW5 	W2AW--W25	X >XX )re   rp   r\   rB   r   rd   )rb   foundr   _r  r   re   s        @@r   cmd_nextr    s_    <<G !)E}&7;djjeA>?J1DB z8$r   c                     | j                   | j                  t              }|4t        d dt        j
                         t	        j                  d       |\  }}fd}t        |       y)u,   특정 task의 상태를 업데이트한다.N[ERROR] task_id 'u4   '를 어떤 체인에서도 찾을 수 없습니다.rZ   r   c                     t              } d }| j                  dg       D ]  }|j                  d      k(  s|} n |4t        d dt        j                         t        j
                  d       |d<   t        j                         j                         }dk(  r||d	<   n
d
k(  r||d<   t        |        t        j                  d d        t        d d d       y )Nrj   re   r
  u   '를 찾을 수 없습니다.rZ   r   r   r   r   r   r   u"   task 상태 업데이트: task_id=z	, status=z[OK] task 'u   ' 상태를 'u!   '으로 업데이트했습니다.)rJ   rn   r\   r^   r_   r`   r   r   r   rX   r%   r   )r   r   ro   r   r   
new_statusre   s       r   
_do_updatezcmd_update.<locals>._do_updatet  s    %j1
&*NN7B/ 	Dxx	"g-"	
 %gY.KLSVS]S]^HHQK *Hlln&&("(+K%6!*-K'Z08	:,WXG9M*=^_`r   )re   r   rp   r\   r^   r_   r`   rd   )rb   r  r  r  r   r  re   s       @@@r   
cmd_updater  h  si    <<GkkJ )E}!'*^_fifpfpqJ1a2 z:&r   c                 <   t        | dd      }t        j                  dd       g }t        j                         }t        t        j                  d            D ]  }	 t        |      }|j                  dd      }|dvr&|j                  d	|j                        }|j                  d
g       D ]  }|j                  d      dk7  r|j                  d      }	|	s,	 t        j                  |	      }
||
z
  j                         dz  }||k\  s^|j!                  ||j                  d      |j                  d      t#        |d      d         t%        t        j&                  |dd             y# t        j                  t        f$ r Y 2w xY w# t        $ r Y w xY w)uT   정체된 (max_hours 초과) running 작업을 검색하여 JSON으로 출력한다.	max_hoursr   Trg   ri   r   r   )r   r5   rj   r   r   i  re   r   )r5   re   r   hours_elapsedFrO   N)r   r8   rk   r   r   rl   rm   rJ   rB   rD   r1   rn   stemfromisoformat
ValueErrortotal_secondsr   roundr\   r   )rb   r  r   r   r   rK   chain_statusr5   ro   started_at_strr   elapsed_hourss               r   cmd_check_stalledr    s   t[!4ITD1G
,,.CZ__^<= 
	#J/D
 xx(3{*88J
8HHWb) 	Dxx!Y.!XXl3N!%33NC
 !:-<<>EM	)$,#'88I#6 $ 0).}a)@		B 
$**W5
;<= $$g. 		"  s$   E/F/FF	FFc                 ~   t         j                  dd       g }t        t         j                  d            D ]z  }	 t	        |      }|j                  |j                  d      |j                  d      |j                  d      t        |j                  dg             |j                  d      d	       | t        t        j                   |dd             y# t        j                  t        f$ rL}t        j                  d
| d|        |j                  |j                  t        |      d       Y d}~d}~ww xY w)u0   활성 체인 목록을 JSON으로 출력한다.Trg   ri   r5   r   r   rj   r   )r5   r   r   
task_countr   r?   r/   )r5   r2   NFr   rO   )r8   rk   rl   rm   rJ   r   rn   r   rB   rD   r1   r%   r&   r  rE   r\   r   )rb   r   r   rK   r3   s        r   cmd_listr    s	   TD1FZ__^<= J
	J#J/DMM $ 4"hhx0!XXg."%dhhw&;"<"&((<"8J  
$**V%
:;	 $$g. 	JNN::,bLMMMzQHII	Js   A7CD<0AD77D<c                    | j                   }t        |      }|)ddddd}t        t        j                  |dd             y|\  }}}|d   }t        |j                  dg       d 	      }d}d}	|D ]4  }
|r|
j                  d
      dk(  s|
}	 n|
j                  d      |k(  s3d}6 |	du }d}|	|	j                  d      }d|||d}t        t        j                  |dd             y)u]   task_id가 체인 소속인지, 그리고 마지막 Phase인지 확인한다 (읽기 전용).NF)in_chainis_lastr5   next_task_idr   rO   r5   rj   c                 &    | j                  dd      S r   r   r   s    r   r   zcmd_check.<locals>.<lambda>  s    QUU7TUEV r   r   r   r   re   T)re   rp   r\   rB   r   rl   rn   )rb   re   r  r   r  r   r5   sorted_tasksfound_currentr   ro   r   r!  s                r   	cmd_checkr%    s   <<G )E} 	
 	djjeA>?Az1z*H *.."5;VWL M $I !xx!Y. 	XXi G+ M! 4G"&L }}Y/ $	F 
$**V%
:;r   c                  0   t        j                  dt         j                        } | j                  dd      }|j	                  dd      }|j                  d	dd
d       |j                  ddd       |j                  ddd       |j                  dd d       |j                  dddd       |j                  dt        ddd       |j	                  d d!      }|j                  d"dd#d$       |j	                  d%d&      }|j                  d"dd#d'       |j                  d(dg d)d*+       |j	                  d,d-      }|j                  d.t        d/d0d1       |j	                  d2d3       |j	                  d4d5      }|j                  d"dd#d6       | j                         }t        t        t        t        t        t        d7}|j                  |j                         }	|	r	 |	|       y | j#                          t%        j&                  d8       y )9Nu+   순차 작업 체이닝 관리 유틸리티)descriptionformatter_classcommandT)destrequiredcreateu   체인 생성)helpz
--chain-idr5   u	   체인 ID)r+  r*  r-  z--tasksu   tasks JSON 배열 문자열)r+  r-  z--scoper   u   체인 범위 설명)defaultr-  z--original-task-fileu;   원본 지시서 파일 경로 (Phase N+1 파일 생성용)z--created-byr   r   u   생성자 (기본: anu))r.  r*  r-  z--max-tasksr   r   u   최대 task 수 (기본: 10))typer.  r*  r-  nextu   다음 pending 작업 반환z	--task-idre   u   완료된 task IDupdateu   task 상태 업데이트u   업데이트할 task IDz--status)r   r   failedr   u
   새 상태)r+  choicesr-  check-stalledu   정체 작업 확인z--max-hoursr   r  u    최대 허용 시간 (기본: 2)listu   활성 체인 목록checku:   task_id의 체인 소속 및 마지막 Phase 여부 확인u   확인할 task ID)r,  r0  r1  r4  r5  r6  r   )argparseArgumentParserRawDescriptionHelpFormatteradd_subparsers
add_parseradd_argumentintfloat
parse_argsr   r  r  r  r  r%  rn   r)  
print_helpr^   r`   )
parser
subparsersp_createp_nextp_update	p_stalledp_checkrb   dispatch_tablehandlers
             r   mainrJ    s6   $$A <<F &&I&EJ $$XO$DH,J[Y)d9VW)R6LM0$  FC  D.%lQjk-c2KVtu ""60N"OF
dI\] $$X4N$OH+9Kde8	   %%o<R%SI=uakXz{ &'=> ##G2n#oGt)J]^D *N   .Gr   __main__)r   N)J__doc__r7  rB   osrQ   r   r^   r(   r   pathlibr   typingr   utils.loggerr   ImportErrorpathinsertrE   __file__r   __name__r%   utils.atomic_writer   rT   rS   utils.usage_pricingr   r   r	   r   r   utils.audit_loggerr
   r   r   utils.circuit_breakerr   r   r   environrn   r   r8   r   rr   r'   r"   r   r   r,   r4   r9   dictrJ   rX   rd   tuplerp   ru   r   r   r=  r   r   r   r   r  r  r  r  r%  rJ  rt   r   r   <module>r]     s"  (   	   
    ('
 
H	$J"
%E?#$C"
TM  02GHI	!H,

**..+\
:
**..+R
0  	+4 +D +
d x~  8 8 81s 1t 1
 $ "9 9T 9d 9&	4 	# (5tT9I3J*K &# c hsm BG3 G4 G0`# ` `s `t `4c 4S 4# 4RV 42Ws Wc WSV W[_ W6BMTN%l%'Z)=b<:+<f9x zF _  (HHOOAs4>0012''(  $#$  %OL$%  $J#$  MsY   F G	 
G G+ "G; =GG		GGG('G(+	G87G8;	HH