
    Zi7                    p   d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
m
Z
mZmZ ddlmZ ddlmZ 	 ddlZg dZdZd	Zej,                  j/                  d
d      Z ee d      Zedz  Z ee d      Z ee d      Z e ed            Zeddf	 	 	 	 	 	 	 	 	 	 	 d dZ	 d!	 	 	 	 	 d"dZ	 d!	 	 	 	 	 	 	 d#dZ edf	 	 	 	 	 	 	 d$dZ!efd%dZ"efd&dZ#ee ee      eddf	 	 	 	 	 	 	 	 	 	 	 	 	 d'dZ$d(dZ%d(dZ&d)dZ'd!d*dZ(e)dk(  r ejT                   e(              yy# e$ r dZY w xY w)+u  IDS 6 Phase 통합 watcher + .done.clear 월별 archive (task-2395).

Author: 쿠쿨칸 / dev7-team
Task: task-2395

기능:
1) archive_old_done_clear: memory/events/*.done.clear 중 90일 이상 파일을
   memory/events/archive/<YYYY-MM>/ 로 이동 (삭제 절대 금지).
2) check_phase_progress / run_completion_checks / watch_once:
   IDS 6 Phase (task-2389~2394) .done 마커를 polling 하여 진행률 보고.
   6/6 도착 시 보고서 존재 + git status 검증 + Telegram 통보.

원칙:
- 외부 dispatch 스크립트 임포트 절대 금지 (자동 위임 차단)
- 파일 삭제 금지 (history 보존 의무) — shutil.move 만 사용
- pytest 자동 실행 금지 (메시지 권고만)

CLI:
    python3 scripts/ids_phase_monitor.py archive [--dry-run] [--age-days 90]
    python3 scripts/ids_phase_monitor.py watch [--no-notify]
    python3 scripts/ids_phase_monitor.py check-progress
    )annotationsN)datetime	timedeltatimezone)Path)Optional)z	task-2389z	task-2390z	task-2391z	task-2392z	task-2393z	task-2394Z   
6937032012WORKSPACE_ROOTz/home/jay/workspacez/memory/eventsarchivez/memory/reportsz+/memory/events/ids_phase_monitor.state.json	   )hoursFc                   |t        j                  t              }|t        |      z
  j	                         }d}d}i }g }	| j                         sddi d|  gdS | j                         D ]  }
|
j                         s|
j                  j                  d      s1	 |
j                         j                  }||kD  r|dz  }Wt        j                  |t        	      j                  d
      }||z  }||
j                  z  }|r|dz  }|j!                  |d      dz   ||<   	 |j#                  dd       t%        j&                  t)        |
      t)        |             |dz  }|j!                  |d      dz   ||<    ||||	dS # t        $ r+}|	j                  |
j                   d|        Y d}~Gd}~ww xY w# t        $ r+}|	j                  |
j                   d|        Y d}~~d}~ww xY w)u~   *.done.clear 중 mtime 기준 age_days 이상 오래된 파일을
    archive_root/<YYYY-MM>/ 로 이동 (삭제 금지).
    N)daysr   zevents_dir missing: )movedskippedby_montherrors.done.clearz: stat failed:    )tzz%Y-%mTparentsexist_okz: move failed: )r   nowKSTr   	timestampexistsiterdiris_filenameendswithstatst_mtimeOSErrorappendfromtimestampstrftimegetmkdirshutilmovestr)
events_dirarchive_rootage_daysdry_runr   	cutoff_tsr   r   r   r   entrymtimee	month_key
target_dirtarget_paths                   J/home/jay/workspace/.worktrees/task-2520-dev4/scripts/ids_phase_monitor.pyarchive_old_done_clearr:   >   s    {ll3yh//::<IEG!HFqbG[\f[gEhDijj##% =}}zz""=1	JJL))E
 9qLG**5S9BB7K	!I-
 5::-QJE"*,,y!"<q"@HY	=TD9KKE
C$45QJE"*,,y!"<q"@HY;=D 	 3  	MMUZZLs;<	,  	=MMUZZLs;<<	=s1   F"AF;	F8 F33F8;	G/ G**G/c                   |t        t              }	 | j                         D ch c]  }|j                         s|j                  ! }}g }g }|D ]  }d}|D ]r  }|j                  |      s|j                  d      s'|j                  d      r9|t        |      d }	|	dk(  s$|	j                  d      s^|	j                  d      spd} n |r|j                  |       |j                  |        t        |      }
t        |      }t        |      |||
 d| |
||
|k(  dS c c}w # t
        $ r t               }Y w xY w)	u   events_dir 안의 <task_id>.done (또는 <task_id>.dev*.done / <task_id>.<team>.done)
    마커 존재 여부로 진행률 산출. .done.clear 는 제외.NFz.doner   .T/)tasksdonependingration_donen_totalcomplete)listTARGET_TASKSr   r    r!   r%   set
startswithr"   lenr&   )r.   r>   f	all_files
done_taskspending_taskstask_idmatchedfnametailrB   rC   s               r9   check_phase_progressrR      sW    }\"%/%7%7%9IQYY[QVVI	I J!M * 	E##G,>>'*~~m,W'Dw4??3#7DMM'<R	 g&  )#*& _F%jGe 81WI&g% 9 J E	s'   D* D%D%	D* %D* *E ?E c                   |t        t              }g }g }|D ]M  }| | dz  }|j                         r"|j                         r|j	                  |       =|j	                  |       O d}d}|dz  }	|	j                         r	 t        j                  ddt        |      dd	gd
d
dd      }
|
j                  dk(  r!|
j                  j                         }|rdnd}n;d|
j                   }|
j                  xs |
j                  xs dj                         }d}t        | dz        }||||||dS # t        t
        j                  f$ r-}dt        |      j                   }t        |      }Y d}~Zd}~ww xY w)u   6/6 도착 시 통합 검증.

    1) reports_dir/<task_id>.md 존재 확인
    2) git status (project_root)
    3) pytest 권고 메시지만 반환 (자동 실행 금지)
    Nz.mdzno-git z.gitgitz-Cstatusz--porcelainT   F)capture_outputtexttimeoutcheckr   dirtycleanz
error: rc=zerror: z9pytest tests/dev1 tests/dev6 tests/design-team tests/dev3zbatch-ids-master.md)
reports_okreports_missing
git_status
git_outputpytest_recommendationbatch_report_target)rE   rF   r   r    r&   
subprocessrunr-   
returncodestdoutstripstderrr%   SubprocessErrortype__name__)reports_dirproject_rootr>   r^   r_   rN   report_pathr`   ra   git_dirresr5   rb   rc   s                 r9   run_completion_checksrr      s    }\"J!#O ,!wisO3K$7$7$9g&""7+, JJV#G~~	 ..c,/=I#C ~~" ZZ--/
(2W
)#..)9:
!jj<CJJ<"CCE
 	D  k,AAB !*  !62  334 	 "47#3#3"45JQJ	 s   BD. .E4#E//E4c                   | t         j                  j                  dd      }|syt        yd| d}t	        dd      D ]  }|| dd	}	 t        j
                  ||d
      }|j                  dk(  r y|j                  dk(  rRd}	 t        |j                         j                  di       j                  dd            }t        j                  |       |j                  dk(  r,t        j
                  ||| dd
      }|j                  dk(  c S |dk  rt        j                  d        y# t        $ r Y yw xY w# t        j                  $ r |dk  rt        j                  d       Y +w xY w)uF   Telegram 메시지 전송. 토큰 부재 시 False (조용히 실패).ANU_BOT_TOKENrT   Fzhttps://api.telegram.org/botz/sendMessager      Markdown)chat_idrY   
parse_mode
   )jsonrZ      Ti     
parametersretry_afteri  )rw   rY         )osenvironr)   requestsrangepoststatus_codeintrz   	ExceptiontimesleepRequestException)	messagerw   	bot_tokenurlattemptpayloadrespr~   resp2s	            r9   send_telegram_notificationr      sf    JJNN?B7	(<
@CA; %wjQ	==7B?D3&3&"%diikoolB&G&K&KM[\&]"^K 

;'3& '7CR ((C//{

1)0  !  (( 	{

1	sH   	'D:2D:9D+=D:8D:D:+	D74D:6D77D::-E+*E+c                    | j                         sd d ddS 	 t        j                  | j                  d            S # t        t        j
                  f$ r	 d d ddcY S w xY w)NF)
last_ratiolast_notified_atcompletion_notifiedutf-8encoding)r   rz   loads	read_textr%   JSONDecodeError
state_files    r9   
load_stater      si    "UZ[[\zz*...@AAT))* \"UZ[[\s   $= AAc                   |j                   j                  dd       |j                  |j                  dz         }|j	                  t        j                  | dd      d       t        j                  t        |      t        |             y )	NTr   z.tmpr   Findentensure_asciir   r   )
parentr*   with_suffixsuffix
write_textrz   dumpsr+   r,   r-   )stater   tmps      r9   
save_stater   )  si    D48

 
 !2!2V!;
<CNN4::eAEBWNU
KKC#j/*    Tc                   |t        t              }t        | |      }t        |      }|ddd}|j	                  d      }	|d   |	k7  r~|rJd|d    d	d
j                  |d         xs d dd
j                  |d         xs d }
t        |
       d|d<   |d   |d<   t        j                  t              j                         |d<   |d   r|j	                  d      srt        |||      }||d<   |rXdt        |d          dt        |       dd
j                  |d         xs d d|d    d|d    d|d     }
t        |
       d|d<   d|d<   	 t        ||       |S # t        $ r Y |S w xY w)!u   1회 polling. 진행률 변화 시 Telegram 1회 발송, 6/6 시 통합 검증.
    자동 dispatch 호출 금지 (외부 스크립트 임포트 일체 없음).N)r.   r>   r   F)progress
completionnotifiedr   rA   u   *IDS 6 Phase 진행률* `z`
done: z, r?   -z

pending: r@   Tr   r   rD   r   )rm   rn   r>   r   u/   *IDS 6/6 완료 — 통합 검증*
reports_ok: r^   r=   z
reports_missing: r_   z
git_status: r`   u
   
권고: `rb   z`
batch report: rc   )rE   rF   rR   r   r)   joinr   r   r   r   	isoformatrr   rI   r   r%   )r.   rm   rn   r   r>   notifyr   r   outputr   msgr   s               r9   
watch_oncer   3  s    }\"#zGH*-E (%PF<(JJ&+HW,=+> ?8F#34;< = IIhy&9:AcBD 
 's+!%F:&w/l$,LL$5$?$?$A !
EII.C$D*#,e

  *|":l#;<=Qs5zl K$$(IIj9J.K$L$SPS#T U),78 9&'>?@ A!!+,A!B CE  's+!%F:'+#$5Z0 M  Ms   E   	E-,E-c                    t        t        t        | j                  | j                        }t        t        j                  |dd             |d   sdS dS )N)r.   r/   r0   r1   r   Fr   r   r   r   )r:   
EVENTS_DIRARCHIVE_DIRr0   r1   printrz   r   argsresults     r9   _cmd_archiver   o  sI    # 	F 
$**VAE
:;8$1+!+r   c                ~    t        | j                         }t        t        j                  |ddt
                     y)N)r   r   F)r   r   defaultr   )r   	no_notifyr   rz   r   r-   r   s     r9   
_cmd_watchr   z  s-    4>>12F	$**VAE3
GHr   c                f    t        t              }t        t        j                  |dd             y)N)r.   r   Fr   r   )rR   r   r   rz   r   )_argsr   s     r9   _cmd_check_progressr     s$    #z:H	$**Xae
<=r   c                   t        j                  d      }|j                  dd      }|j                  dd      }|j	                  d	t
        t        
       |j	                  dd       |j                  t               |j                  dd      }|j	                  dd       |j                  t               |j                  dd      }|j                  t               |j                  |       }|j                  |      S )Nz'IDS phase monitor + done.clear archiver)descriptioncmdT)destrequiredr   z*archive *.done.clear older than --age-days)helpz
--age-days)rk   r   z	--dry-run
store_true)action)funcwatchzrun one polling cyclez--no-notifyzcheck-progresszprint current N/6 progress)argparseArgumentParseradd_subparsers
add_parseradd_argumentr   DEFAULT_AGE_DAYSset_defaultsr   r   r   
parse_argsr   )argvparsersubp_archp_watchp_chkr   s          r9   mainr     s    $$1Z[F


UT

:C^^I,X^YF
38HI
L9
\*nnW+BnCG|<j)NN+2NNOE	/0T"D99T?r   __main__)r.   r   r/   r   r0   r   r1   boolr   zOptional[datetime]returndict)N)r.   r   r>   Optional[list[str]]r   r   )rm   r   rn   r   r>   r   r   r   )r   r-   rw   r-   r   zOptional[str]r   r   )r   r   r   r   )r   r   r   r   r   None)r.   r   rm   r   rn   r   r   r   r>   r   r   r   r   r   )r   argparse.Namespacer   r   )r   r   r   r   )r   r   r   r   )+__doc__
__future__r   r   rz   r   r+   rd   sysr   r   r   r   pathlibr   typingr   r   ImportErrorrF   r   DEFAULT_CHAT_IDr   r)   r   r   r   REPORTS_DIR
STATE_FILEr   r:   rR   rr   r   r   r   r   r   r   r   r   rl   exit r   r9   <module>r      s@  . #   	   
  2 2   ^  02GH^$N34
9$n%_56^$$OPQ
yq!" %"=== = 	=
 
= 
=J "&... 
.n "&999 9 
	9B ##&&& & 
	&X #- \ 0: + "#n-!!%666 6 	6
 6 6 
6x,( zCHHTV e  Hs   D+ +D54D5