o
    E&j                     @  s   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	ej
ej
eZej
eZej
edZej
edZej
edZej
edZej
edZdddZdddZdddZh dZd ddZd!ddZedkryee dS )"u  US Equity Kakao Dispatcher (Mac-side, Codex-free).

클로드 예약 작업(셸 없음)이 outputs/pending_kakao_*.md 로 남긴 6줄 요약을
맥의 launchd가 주기적으로 이 스크립트로 실행 → 기존 send_kakao_memo.py 로 카톡 발송,
(있으면) 짝꿍 pending_state_*.json 으로 update_dashboard_summary.py 대시보드 갱신,
처리 완료분은 kakao_sent/ 로 이동한다.

설계 원칙:
- 기존 전략/스크립트는 건드리지 않는다. 발송/갱신은 정식 스크립트만 호출.
- 자격증명은 워크스페이스 루트의 .kakao_env(우선) → macOS Keychain(send_kakao_memo.py 내부) 순.
- 중복 발송 방지: 처리분은 즉시 이동, 로그 기록.
    )annotationsNz
.kakao_env
kakao_sentzkakao_dispatch_log.jsonlzsend_kakao_memo.pyzupdate_dashboard_summary.pyrecdictreturnNonec                 C  s~   t jt jj | d< z(ttddd}|t	j
| ddd  W d    W d S 1 s-w   Y  W d S  ty>   Y d S w )Ntsautf-8encodingF)ensure_ascii
)dtdatetimenowtimezoneutc	isoformatopenDISPATCH_LOGwritejsondumps	Exception)r   f r   kakao_dispatch.pylog    s   &r   c                  C  s   t tj} tjtrEttdd,}|D ] }| }|r%|ds%d|vr&q|	dd\}}|r4|| |< qW d    | S 1 s@w   Y  | S )Nr
   r   #=   )
r   osenvironpathexistsENV_FILEr   strip
startswithsplit)envr   linekvr   r   r   load_env)   s    

r.   r$   strc                 C  s:   t j| }|dr|tdtd  n|}d| S )Npending_kakao_.mdzUS Equity - )r"   r$   basenamer(   len)r$   nameblockr   r   r   title_from_name7   s   $
r6   >   	AH-URGENTWEEKEND-RISKCASHATTACKDEFENSERECOVERYTACTICALtextc                 C  s   ddddd}|   D ]]}| }|dr3|dd  }|r2|d  tv r2|d  |d< q|drE|dd	d	  |d
< q|drW|dd	d	  |d< q|drh|dd	d	  |d< q|S )uZ   6줄 요약([상황]/계좌/시장/행동/금지/다음)에서 대시보드 필드 추출.r=    )modemarket_statusverdict
next_checku   [상황]r   r@   u   시장::r!   rA   u   행동:rB   u   다음:rC   )
splitlinesr'   r(   replacer)   upperVALID_MODES)r>   outrawr+   tokr   r   r   parse_six_line@   s    



rL   intc                  C  s  t jtdd t } t jtd}t j|rjz3tj	t
j|gdd| dd}|j s/|jdkrItd|jdk|j d d |j d d d	 W n tyi } ztd
t|d d d W Y d }~nd }~ww t jtd}t j|rz)tj	t
j|gdd| dd}td|jdk|j d d |j d d d	 W n ty } ztdt|d d d W Y d }~nd }~ww | dr| ds| dstddd td dS ttt jtd}|sdS |D ]m}zEt|dd}|  }	W d    n	1 sw   Y  |	st | W qt|}
tj	t
jtd|
ddg|	dd| dd}|jdk}tdt j|||j d d |j d d d |rt jtr|d d!d"d#}t|	}t j|rz| d$d% t!"t|dd# D  W n
 ty   Y nw zat
jtd&t|d'pd(d)t|d*d+d,t|d-d+d.t|d/d+g
}tj	||	dd| dd}td0t j||jdk|j d d d1 t j|rt |t jtt j| W n% ty } ztd2t j|t|d d d3 W Y d }~nd }~ww |r6t$j%& 'd4}t |t jt| d5t j|  W q ty\ } ztd6t j|t|d d7 d3 W Y d }~qd }~ww dS )8NT)exist_okzapply_targets.py<   )capture_outputr>   r*   timeoutr   apply_targets   )eventokrI   errapply_targets_error)rT   rV   zrefresh_prices_yf.pyZ   price_refreshprice_refresh_errorKAKAO_REST_API_KEYKAKAO_REFRESH_TOKENKAKAO_ACCESS_TOKENskipno_credentials)rT   reasonu6   자격증명 없음(.kakao_env 또는 Keychain 확인)zpending_kakao_*.mdr
   r   z--titlez--button-titleu   대시보드 열기)inputrP   r>   r*   rQ   
kakao_send)rT   filerU   rI   rV   r0   pending_state_r1   z.jsonc                 S  s   i | ]	\}}|r||qS r   r   ).0r,   r-   r   r   r   
<dictcomp>   s    zmain.<locals>.<dictcomp>z--moder@   r=   z--market-statusrA   r?   z	--verdictrB   z--next-checkrC   dashboard_update)rT   rc   rU   rV   dashboard_error)rT   rc   rV   z%Y%m%d_%H%M%S_errori,  )(r"   makedirsSENT_DIRr.   r$   joinBASEr%   
subprocessrunsys
executablestdoutr'   
returncoder   stderrr   r/   getprintsortedglobr   readremover6   SENDERr2   DASHrF   rL   updater   loaditemsr   r   r   strftime)r*   applierare	refresherprpendingr$   r   r>   titleresrU   
state_pathstdargsdresstampr   r   r   mainR   s    & &



 *0(0r   __main__)r   r   r   r   )r   r   )r$   r/   r   r/   )r>   r/   r   r   )r   rM   )__doc__
__future__r   r   r   ry   r   r"   ro   rq   r$   dirnameabspath__file__rn   ROOTrm   r&   rl   r   r|   r}   r   r.   r6   rH   rL   r   __name__
SystemExitr   r   r   r   <module>   s0   

	


T
