
    0iU@                        d 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                         dz  dz  Z ej                         dz  dz  Z	 ej                         dz  d	z  d
z  Z
d d d d d d d d d d	ZdedefdZdededefdZd/dedefdZdefdZdefdZd/dededefd Zd!ed"edefd#Zd$ed%ededz  fd&Z	 	 	 d0d'ed(eded"ed)edefd*Zd(efd+Zdej2                  fd,Zd- Zed.k(  r e        yy)1u   
Claude Code 세션 JSONL → Markdown 변환기
- 프로젝트별로 대화를 읽기 좋은 Markdown으로 변환
- 도구 사용 로그는 요약, 사람-AI 대화는 전문 보존
- 메타데이터를 프론트매터로 포함
    N)datetime)Pathz.claudeprojectszvibe-sunsangconversationsconfigzproject_names.jsonc                 .    d| j                  dd       dS )Nu   *[Tool: Read → `	file_path?`]*getis    c/home/jay/workspace/teams/dev2/temp/gptaku_plugins/plugins/vibe-sunsang/scripts/convert_sessions.py<lambda>r          /k30G/HL     c                 .    d| j                  dd       dS )Nu   *[Tool: Write → `r	   r
   r   r   r   s    r   r   r      s    0{C1H0IM r   c                 .    d| j                  dd       dS )Nu   *[Tool: Edit → `r	   r
   r   r   r   s    r   r   r      r   r   c                 4    d| j                  dd      d d  dS )Nu   *[Tool: Bash → `commandr
   P   r   r   r   s    r   r   r      s#    /i0Ecr0J/K3O r   c                 .    d| j                  dd       dS )Nu   *[Tool: Grep → `patternr
   r   r   r   s    r   r   r          /i0E/FcJ r   c                 .    d| j                  dd       dS )Nu   *[Tool: Glob → `r   r
   r   r   r   s    r   r   r      r   r   c                 .    d| j                  dd       dS )Nu   *[Tool: WebSearch → `queryr
   r   r   r   s    r   r   r      s    4QUU7C5H4IM r   c                 .    d| j                  dd       dS )Nu   *[Tool: WebFetch → `urlr
   r   r   r   s    r   r   r      s    3AEE%4E3FcJ r   c                 .    d| j                  dd       dS )Nu   *[Tool: Task → `descriptionr
   r   r   r   s    r   r   r      s    /mS0I/J#N r   )	ReadWriteEditBashGrepGlob	WebSearchWebFetchTask
names_filereturnc                     | j                         r.	 t        | dd      5 }t        j                  |      cddd       S i S # 1 sw Y   i S xY w# t        j                  t
        f$ r Y i S w xY w)z1Load project name mappings from JSON config file.rutf-8encodingN)existsopenjsonloadJSONDecodeErrorOSError)r,   fs     r   load_project_namesr:   !   sr    	j#8 $Ayy|$ $ I	$ I $$g. 	I	s-   A A	A AA A A+*A+dir_nameproject_namesc                     | |v r||    S ddl }|j                  dd|       j                  dd      j                         }|xs dS )uK   프로젝트 디렉토리명을 사람이 읽기 좋은 이름으로 변환r   Nz^-Users-[^-]+- -_unknown)resubreplacelower)r;   r<   rB   names       r   get_project_namerG   ,   sN    = X&& 66#R2::3DJJLD9r   verbosec                 `   t        | t              r| S t        | t              rg }| D ]h  }t        |t              s|j	                  d      dk(  r"|j                  |j	                  dd             K|j	                  d      dk(  ri|j	                  dd      }|j	                  di       }t        j	                  |      }|r|j                   ||             |j                  d| d	       |j	                  d      d
k(  s|j	                  dd      }t        |t              s|j                         s|r|j                  d| d       ,|dd j                  dd      }t        |      dkD  r|dz  }|j                  d| d       k dj                  |      S t        |       S )u+   메시지 content에서 텍스트만 추출typetextr>   tool_userF   rA   inputz*[Tool: z]*tool_resultcontentz
> *[Result]:*
> 
N    ...z
> *[Result]: z*
)
isinstancestrlistdictr   appendTOOL_FORMATTERSstriprD   lenjoin)	rO   rH   textsblock	tool_name
tool_input	formatterresult_contentpreviews	            r   extract_text_contentrd   7   s}   '3'4  	IE%&99V$.LL62!67YYv&*4 %		&) <I!&7B!7J / 3 3I >I Yz%:;x	{"%=>YYv&-7%*YYy"%=N!.#6>;O;O;Q"!LL+>~>Nb)QR&4Tc&:&B&B4&MG">2S8 '5 0!LL?7)3)GH+	I, yyw<r   c                    t        | t              r7	 t        j                  | j	                  dd            }|j                  d      S t        | t        t        f      rE	 | dkD  rt        j                  | dz        }nt        j                  |       }|j                  d      S t        |       S # t        $ r | cY S w xY w# t        $ r t        |       cY S w xY w)u*   타임스탬프를 읽기 좋은 형태로Z+00:00%Y-%m-%d %H:%M   mB  
rT   rU   r   fromisoformatrD   strftime	Exceptionintfloatutcfromtimestamptsdts     r   format_timestampru   W   s    "c	''

3(ABB;;/00 "sEl#	Dy..rDy9..r2;;/00 r7N  	I	  	r7N	s$   5B. AB? .B<;B<?CCc                    t        | t              r7	 t        j                  | j	                  dd            }|j                  d      S t        | t        t        f      rE	 | dkD  rt        j                  | dz        }nt        j                  |       }|j                  d      S y# t        $ r Y yw xY w# t        $ r Y yw xY w)u&   타임스탬프에서 날짜만 추출rf   rg   z%Y-%m-%dzunknown-dateri   rj   rk   rr   s     r   get_session_daterw   k   s    "c	"''

3(ABB;;z** "sEl#	"Dy..rDy9..r2;;z**   	"!	"  	"!	"s$   5B$ AB3 $	B0/B03	B?>B?
jsonl_pathc           
      ^   g }| j                   t               t               ddddddd	}t        | dd      5 }|D ]  }|j                         }|s	 t	        j
                  |      }|j                  dd      }|j                  d	d      }|d
   |r||d
<   |r||d<   |j                  d      r|d   |d<   |j                  d      r|d   |d<   |j                  di       }	|	j                  d|      }
|	j                  dd      }|r|d   j                  |       |	j                  di       }|dxx   |j                  dd      z  cc<   |dxx   |j                  dd      z  cc<   |	j                  dd      }|sDt        ||      }|r|j                         set        |t              rQ|D ]L  }t        |t              s|j                  d      dk(  s)|d   j                  |j                  dd             N |
dv r |j                  d|t        |      d        |
d!v s|j                  d"|t        |      d         	 ddd       t        |d         |d<   t        |d         |d<   t!        |      |d#<   ||d$S # t        j                  $ r Y ew xY w# 1 sw Y   XxY w)%u   단일 세션 JSONL을 파싱r   N)	
session_idmodels_used
tools_usedtotal_input_tokenstotal_output_tokens
start_timeend_time
git_branchcwdr/   r0   r1   rJ   r>   	timestampr   r   	gitBranchr   r   messagerolemodelr{   usager}   input_tokensr~   output_tokensrO   rH   rL   r|   rF   rA   )userhumanr   )r   rO   time)	assistantr   message_count)messagesmetadata)stemsetr4   rZ   r5   loadsr7   r   addrd   rT   rV   rW   rX   ru   sortedr[   )rx   rH   r   r   r9   lineentry
entry_typer   msgr   r   r   rO   rK   r^   s                   r   convert_sessionr      s   H ooue 
H 
j#	0 >A =	D::<D

4( 62.J		+r2I %-))2&'0$yy%).{);&yy"',))Ir*C776:.DGGGR(E'++E2 GGGR(E)*eii.JJ**+uyy!/LL+ ggi,G'ADtzz| '4($ QE!%.599V3D
3R .22599VY3OPQ (("#,Y7! 
 ''#,Y7! s=	>@ %Xm%<=H]#H\$:;H\ #HH_ h77{ '' > >sC   J#J	'EJ#J#AJ#*!J#	J J#J  J##J,session_dataproject_namec                 p   | d   }| d   }|syt        |d         }g }|j                  d       |j                  d|        |j                  d|d           |j                  d	|        |j                  d
t        |d                 |j                  dt        |d                 |d   r0|j                  d       |d   D ]  }|j                  d|         n|j                  d       |d   r0|j                  d       |d   D ]  }|j                  d|         n|j                  d       |j                  d|d           |j                  d|d           |j                  d|d           |d   r|j                  d|d           |d   r|j                  d|d           |j                  d       |j                  d       |d   d   d d! j                  d"d#      }|j                  d$| d%|        |j                  d&| d'       |j                  d       |D ]q  }	|	d(   d)k(  r|j                  d*|	d+    d,       n|j                  d-|	d+    d,       |j                  d       |j                  |	d          |j                  d       s d"j	                  |      S ).u)   파싱된 세션을 Markdown으로 변환r   r   r>   r   z---z	project: zsession_id: rz   zdate: zstart: zend: r   r{   zmodels:z  - zmodels: unknownr|   ztools:ztools: nonez
messages: r   zinput_tokens: r}   zoutput_tokens: r~   r   zgit_branch: r   zworking_dir: r   rO   Nr   rP   rR   z#  | u   > 첫 메시지: rS   r   r   z	## User (r   )z## Assistant ()rw   rX   ru   rD   r\   )
r   r   metar   datelinesmt	first_msgr   s
             r   session_to_markdownr      s   
#DJ'HD./DE 
LL	LL9\N+,	LL<\ 2345	LL6$!	LL7+D,>?@AB	LL5)$z*:;<=> MYm$ 	%ALL4s$	% 	&' LXl# 	%ALL4s$	% 	]#	LL:d?3456	LL>$';"<!=>?	LL?4(=#>"?@AL|D$6#789E{}T%[M23	LL	LL I&s+33D#>I	LL2dV3|n-.	LL$YKs34	LL  v;& LL9S[M34LL>#f+a89RS^$R 99Ur   
output_dirshort_idc                 >    | j                  d| d      D ]  }|c S  y)z=Find an existing markdown file matching the short_id pattern.z*_.mdN)glob)r   r   r9   s      r   _find_existing_outputr     s+    __r(3/0 r   project_diroutput_baseforcec           
         t         | z  }|j                         st        d|  d       y|t        | |      }||z  }d}t	        |j                  d            }	d}
d}|	D ]  }	 |j                  dd }|sY|j                         rIt        ||      }|r;|j                         j                  |j                         j                  k\  r|dz  }nt        ||	      }|d
   st        ||      }|s|s|j                  dd       d}t        |d   d         }|| d| dz  }|j                  |d       |
dz  }
 |j                         r)t#        |j%                               s|j'                          |rd| dnd}t        d| d|
 dt)        |	       d|        |
S # t        $ r&}t        d|j                    d|        Y d}~ld}~ww xY w)u4   프로젝트 디렉토리의 모든 세션을 변환z	  [SKIP] u    - 디렉토리 없음r   NFz*.jsonl      r   r   T)parentsexist_okr   r   r@   r   r0   r1   z
  [ERROR] z: z, z skipped (up-to-date)r>   z  [z] /u    세션 변환 완료)CLAUDE_PROJECTS_DIRr3   printrG   r   r   r   r   statst_mtimer   r   mkdirrw   
write_textrn   rF   anyiterdirrmdirr[   )r   r   r<   r   r   rH   project_pathr   dir_createdjsonl_files	convertedskipped
jsonl_filer   existingr   
md_contentr   output_fileeskip_msgs                        r   convert_projectr     s    '4L 	+&<=>']C|+JK**956KIG! 7
	7!r*H Z..00XF 8 8JOO<M<V<V VqLG*:wGL
+,\<HJ    ="#L$<\$JKD$$q
#'>>K"":"@NI77@ 3z'9'9';#<6=G9122H	C~R	{!C,<+==RS[R\
]^  	7Jz/r!566	7s,   #A)F!F! F!/AF!!	G*GGc                    | j                         st        d       yg }|j                  d       |j                  dt        j                         j                  d       d       d}g }t        | j                               D ]  }|j                         st        |j                  d            }|s1|t        |      z  }|D cg c]  }|j                  dd	  }}|j                  |j                  t        |      t        |      t        |      d
        |j                  d| dt        |       d       |j                  d       |j                  d       t        |d       D ]2  }|j                  d|d    d|d    d|d    d|d    d|d    d       4 |j                  d       |j                  d       | dz  }	|	j                  dj!                  |      d        t        d!|	 d"| d#       yc c}w )$u   전체 인덱스 파일 생성z8
[INDEX] No output directory, skipping index generation.Nu   # Claude Code 대화 회고록u   
생성일: rh   rP   r   z*.md
   )rF   countfirstlastu   **총 u   개 세션** | u   개 프로젝트
u&   | 프로젝트 | 세션 수 | 기간 |z|----------|---------|------|c                     | d    S )Nr    )xs    r   r   z generate_index.<locals>.<lambda>  s    QwZK r   )keyz| [rF   z](./z/) | r   r   r   z ~ r   z |z
---
uM   바선생과 함께 과거 대화를 분석하고 회고할 수 있습니다.zINDEX.mdr0   r1   z	
[INDEX] u    생성 완료 (총 u   개 세션))r3   r   rX   r   nowrm   r   r   is_dirr   r[   r   rF   minmaxr   r\   )
r   r   total_sessionsproject_statsr   md_filesr9   datesr   
index_paths
             r   generate_indexr   _  s   IJE	LL12	LL=!8!89I!J K2NONMk1134 !!#+**623#h-' '////$$]ZJ	
 	" 
LL6.)]9K8LL^_`	LL9:	LL01}*?@ 
$v,tDL>tG}oSgWZ[_`f[gZhhjk	


 
LL	LL`az)J$))E*W=	Jzl"6~6Fk
RS- 0s   G=c                  \   t        j                  d      } | j                  ddd       | j                  ddd	
       | j                  ddd
       | j                  dt        dd       | j                  dt        dd       | j                  dt        dd       | j                         S )zParse command line arguments.u/   Claude Code 세션 JSONL → Markdown 변환기)r"   r   *uA   특정 프로젝트 디렉토리명 (미지정 시 전체 변환))nargshelpz--force
store_truez2Force full reconversion (ignore incremental cache))actionr   z	--verbosez5Include full tool results (not just 200 char preview)z--output-dirNzCustom output directory path)rJ   defaultr   z--names-filezNPath to project_names.json (default: ~/vibe-sunsang/config/project_names.json)z	--projectz3Convert a specific project only (by directory name))argparseArgumentParseradd_argumentr   rU   
parse_args)parsers    r   r   r     s    $$EF P  
 A  
 D  
 +	   ]	   B	   r   c            	      F   t               } | j                  r| j                  nt        }| j                  r| j                  nt        }t        |      }| j                  r| j                  g}nU| j                  r| j                  }n<t        j                         D cg c]  }|j                         s|j                  ! }}t        d       t        dt                t        d|        t        d|        t        dt        |       d       | j                  rt        d       | j                  rt        d       t                d	}t!        |      D ])  }|t#        |||| j                  | j                  
      z  }+ t%        |       t        d| d       y c c}w )Nu.   === Claude Code 세션 → Markdown 변환 ===u   소스: u   출력: u   이름 매핑: u   대상: u   개 프로젝트u"   모드: --force (전체 재변환)u/   모드: --verbose (전체 도구 결과 포함)r   )r   rH   u   
=== 완료: 총 u   개 세션 변환 ===)r   r   DEFAULT_OUTPUT_DIRr,   DEFAULT_NAMES_FILEr:   projectr   r   r   r   rF   r   r[   r   rH   r   r   r   )argsr   r,   r<   targetsdtotaltargets           r   mainr     s]   <D$(OO9KJ$(OO9KJ 'z2M ||<<.	-- $7#>#>#@OaAHHJ166OO	:<	H()
*+	HZL
!"	OJ<
()	HS\N"2
34zz24||?A	GE/ 
**LL
 	

 :	ug%:
;<1 Ps   F1F__main__)F)NFF)__doc__r   r5   sysr   pathlibr   homer   r   r   rY   rW   r:   rU   rG   boolrd   ru   rw   r   r   r   r   r   	Namespacer   r   __name__r   r   r   <module>r      s     
  diikI-
: TYY[>1OC TYY[>1H<?SS  MMLOJJMJN
4 D s 4 C 4 C @C (C (S8 S8t S8 S8l?d ?# ?# ?Dd c dTk  >>> > 	>
 > >B,T ,T^&H&& &R(=V zF r   