
    (<iUG                         d 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m	Z	  e
 ee      j                         j                  j                        Zeej                  vrej                  j!                  de       ej"                  j%                  d e
 ee      j                         j                  j                  j                              ZddlmZmZmZmZmZ ddlmZmZ ddlmZ dd	lm Z m!Z! d
e
de
de
fdZ"d
e
de
de
de
ddf
dZ#d
e
de
de
de
ddf
dZ$de
de%e&e
ef      fdZ'	 	 d0d
e
de
de
de&e
ef   de&e
ef   de(de)de
de
de
de
dz  de%e
   dz  de*e
e)e&e
ef   f   fdZ+dddd d!d"d#d$ e
 ee      d%z        d$f
d
e
d&e
de
dz  de%e
   dz  d'e(d(e)d)e(de
de
d*e,de
d+e,de&e
ef   fd,Z-d1d-e%e
   dz  de(fd.Z.e/d/k(  r ej`                   e.              yy)2u   Autoresearch 코어 러너 - 스킬 프롬프트 자동 최적화

Karpathy의 autoresearch 방법론 적용:
딱 1가지만 변경 → 테스트 → 좋으면 유지, 나쁘면 롤백 → 목표 달성 시 종료
    N)Path)AnycastWORKSPACE_ROOT)	add_round
create_logfinalize_logget_recent_changelogsave_log)judge_outputload_checklist)generate_mutation)execute_skill
load_skill
skill_name
skills_dirreturnc                     t        |      | z  dz  }t        |      | z  dz  }|j                  dd       |dz  }t        j                  t	        |      t	        |             t	        |j                               S )u   원본 SKILL.md를 백업. 경로: skills/<name>/evals/backup-original.md

    Returns:
        백업 파일 경로 (절대 경로 문자열)
    SKILL.mdevalsTparentsexist_okzbackup-original.md)r   mkdirshutilcopy2strresolve)r   r   
skill_path	evals_dirbackup_paths        L/home/jay/workspace/.worktrees/task-2057-dev2/scripts/autoresearch/runner.pybackup_originalr#      sr     j!J.;JZ :-7IOOD4O022K
LLZ#k"23{""$%%    backup_contentfrontmatterc                 f    t        |      | z  dz  }|r	d| d| }n|}|j                  |d       y)u"  SKILL.md를 원래 내용으로 복원 (frontmatter 보존).

    Args:
        skill_name: 스킬 이름
        backup_content: 복원할 본문 (body) 텍스트
        skills_dir: 스킬 디렉토리 경로
        frontmatter: YAML 프론트매터 문자열 (--- 구분자 제외)
    r   ---

---
utf-8encodingNr   
write_text)r   r%   r   r&   r   contents         r"   restore_skillr0   .   sF     j!J.;J+gn-=> 'G4r$   mutated_bodyc                 f    t        |      | z  dz  }|r	d| d| }n|}|j                  |d       y)u"  변경된 본문으로 SKILL.md 업데이트 (frontmatter 보존).

    Args:
        skill_name: 스킬 이름
        mutated_body: 변경된 마크다운 본문
        skills_dir: 스킬 디렉토리 경로
        frontmatter: YAML 프론트매터 문자열 (--- 구분자 제외)
    r   r(   r)   r*   r+   Nr-   )r   r1   r   r&   r   r/   s         r"   apply_mutationr3   A   sE     j!J.;J+gl^<'G4r$   	file_pathc                    ddl }t        |       }|j                         st        d|        |j	                  d      5 }|j                  |      }ddd       r|j                  dg       ng }|st        d|        |S # 1 sw Y   1xY w)uU  YAML 파일에서 테스트 입력 목록을 로드.

    Args:
        file_path: test-inputs.yaml 파일 경로

    Returns:
        입력 항목 리스트 (각 항목: {"id": ..., "text": ...})

    Raises:
        FileNotFoundError: 파일이 존재하지 않을 경우
        ValueError: inputs 리스트가 비어 있을 경우
    r   Nu)   테스트 입력 파일이 없습니다: r*   r+   inputsu)   inputs 리스트가 비어 있습니다: )yamlr   existsFileNotFoundErroropen	safe_loadget
ValueError)r4   _yamlpathfdatar6   s         r"   load_test_inputsrB   T   s     	?D;;="KI; WXX	G	$ "q!" >B488Hb#9rFDYKPQQM" "s    BBcurrent_body	checklistlog	round_num
prev_scoremodel_mutatemodel_judge
test_inputtest_inputsc           
         ddl }||}n|
|
g}nt        d      t        |      }|j                  |dd      }	 t	        ||||      }|d
   }|d   }|d   }t        |j                  dd            }t        |j                  dd            }t        | |||       g }g }d}d}d}d}d}|D ]!  }t        t        t        t        f   t        |||            }t        |j                  dd            } |t        |j                  d      xs d      z  }|t        |j                  d      xs d      z  }	 t        || |	      }!t!        |!j                  dd            }"|j#                  |"       |j%                  |!j                  dg              |t        |!j                  dd            z  }|t        |!j                  dd            z  }$ |r|||fS |rt)        |      t+        |      z  nd}#t+        |      dkD  r-dj-                  d |D              }$t        d| d|$ d|#d       |#|z
  }%|#|k\  r	d}&|}'|#}(d})nd}&|}'|}(d })t'        | |||       |%dk\  rd!|%dn|%d}*t        d"| d#| d$| d%       t        d&|dd'|#dd(|* d)|)        ||z   |z   }+||z   |z   },t/        d6i d*|d+|d
|d|d,|d-|#d.|d/|&d|+d|,d0|d1|d2|d3|d4|d5|}-|'|(|-fS # t
        $ r }t        d| d	|        |||fcY d}~S d}~ww xY w# t
        $ r-}t        d| d|        t'        | |||       d}Y d}~ nd}~ww xY w)7u  단일 라운드 실행.

    Returns:
        (current_body_after_round, score, updated_log)

    로직:
    1. get_recent_changelog(log) → recent_changelog
    2. generate_mutation(current_body, checklist_yaml_str, recent_changelog, model_mutate, api_key)
    3. apply_mutation → 변경된 SKILL.md 저장
    4. execute_skill → 스킬 실행 (각 입력으로)
    5. judge_output → 채점 (각 입력에 대해)
    6. 점수 비교 (멀티입력의 경우 평균 사용):
       - score >= prev_score → KEEP
       - score < prev_score → REVERT (원본 복원)
    7. add_round → 로그에 추가
    8. Return (body, score, log)
    r   NC   test_input 또는 test_inputs 중 하나를 제공해야 합니다.TF)allow_unicodedefault_flow_style)current_skill_mdchecklist_yamlrecent_changelogmodelz	  [Round u,   ] mutation 생성 실패, 라운드 스킵: mutation_typemutation_descriptionmodified_skill_mdinput_tokensoutput_tokens
skill_bodyrJ   rS   output rD   skill_outputrS   total_score        itemsu#   ] 채점 실패, 라운드 스킵:    z, c              3   $   K   | ]  }|d  
 yw).2fN ).0ss     r"   	<genexpr>zrun_round.<locals>.<genexpr>   s     :a!Cz:s   u   ] 입력별 점수: [u   ] → 평균: rd   keptu   ✓ KEEPrevertedu
   ✗ REVERT+z[Round u
   ] 변경: z - ""u
     점수: u    → z (z) rE   rF   score_beforescore_afteritems_detaildecisionmutation_input_tokensmutation_output_tokensexecution_input_tokensexecution_output_tokensjudge_input_tokensjudge_output_tokensre   )r7   r=   r
   dumpr   	Exceptionprintintr<   r3   r   dictr   r   r   r   floatappendextendr0   sumlenjoinr   ).r   rC   r&   rD   rE   rF   rG   r   rH   rI   rJ   rK   r>   inputs_listrR   checklist_yaml_strmutation_resultexcrT   rU   r1   mut_input_tokensmut_output_tokensscoresro   total_exec_input_tokenstotal_exec_output_tokensru   rv   judge_failedinpexec_resultr^   judge_result	inp_score	new_score
score_strsdeltarp   result_bodyresult_scoresymbol	delta_strtotal_input_tokenstotal_output_tokensupdated_logs.                                                 r"   	run_roundr   r   s{   >  !		!l^__+C0 ITV[\	-+)--	
 )9M /0F G'(;<L 3 3NA FG !4!4_a!HI :|ZE F L L &*cN'"'
  " =>3{~'F'K!#LL C(H(MA$NN 	'#)!L
  %\%5%5mS%IJIMM)$ 0 0" =>#l&6&6~q&I"JJ3|'7'7'K#LL/< Z,, 5;s6{S[0I ;!YY:6::
	)$9*^T]^aSbcd 
"EJ" "!j,
KH $)A:!E#;eC[I	GI;jt<P;QQR
ST	Jz#&eIc?"YKr&
RS *,CCFXX+.FFI\\  $ 2	
    "  ( * /  1  7 !9 .  0!K& k11S  -	)$PQTPUVWZ,,-\  	Ii[(KC5QR*lJLL		s6   K# 8BL#	L,LLL	M!M  M2   ffffff?   claude-sonnet-4-6claude-haiku-4-5-20251001Fskillschecklist_pathroundstarget_scoreconsecutivedry_run
backgroundc                 2   |||g}n||}nt        d      t        |      }t        | |
      \  }}t        | |
       t	        |       }t        d|         g }|D ]~  }t        t        t        t        f   t        |||            }t        |j                  dd            }t        |||      }|j                  t        |j                  dd                    |rt        |      t!        |      z  nd}t        d	|d
       |}|}d}t#        d|dz         D ]`  }t%        | ||||||||
||      \  }}}||k\  r|dz  }nd}|	rt        d       t'        | ||
|        n||k\  sMt        d|d
d| d        n t)        ||      }t+        ||        |S )uX  메인 루프.

    Returns:
        최종 로그 dict

    흐름:
    1. load_checklist(checklist_path)
    2. load_skill(skill_name, skills_dir) → (frontmatter, body)
    3. backup_original(skill_name, skills_dir)
    4. create_log(skill_name)
    5. 초기 실행: execute_skill → judge_output → 초기 점수
    6. for round_num in range(1, rounds+1):
       a. run_round(...)
       b. 연속 target_score 이상 consecutive회 → STOP
       c. dry_run이면 1라운드만 실행 후 종료
    7. finalize_log(log, final_score)
    8. save_log(log, skill_name)
    9. Return log
    rM   u   초기 실행 중: rY   r[   r\   r]   r_   r`   u   초기 점수: .2%r   rb   )r   rC   r&   rD   rK   rE   rF   rG   r   rH   rI   u8     [dry-run] 1라운드 완료. 원본 복원 후 종료.u   목표 점수 u   를 u!   회 연속 달성. 조기 종료.)r=   r   r   r#   r   ry   r   r{   r   r   r   r<   r   r}   r|   r   r   ranger   r0   r	   r   )r   r   rJ   rK   r   r   r   rH   rI   r   r   r   resolved_inputsrD   r&   bodyrE   initial_scoresr   r   r^   r   initial_scorerC   current_scoreconsecutive_countrF   	final_logs                               r"   runr     s   D +"5&0\		 %^__ ~.I #:z:K J
+ %Z0C 

|
,-"$N K&*cN"'
 ;??8R89#%

 	eL$4$4]C$HIJ!K$ IW3~.^1DD\_M	OM#.
/0L!M 1fqj) 	+4!%#'$!%#,
(mS L(" ! LN*dJD +N<"4DEfgh=B S-0I Y
#r$   argvc           
      	   t        j                  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                  ddd       |j                  ddd       |j                  ddd       |j                  dt        t        t              dz        d        |j                  d!dd"       |j                  d#dd$       |j                  d%      }|j                  d&d'(       |j                  d)d*(       |j                  |       }|j                  |j                  |j                  |j                  |j                  |j                  |j                   |j"                  |j$                  d+	}|j&                  |j&                  |d-<   n+t)        |j*                        }|D cg c]  }|d.   	 c}|d/<   |j,                  rd|d0<   d,}d,}d,}	|j,                  rd1d,l}
t        |j$                        |j                  z  d2z  }|j1                  dd3       |d4z  }t3        t        |      d5d67      }t4        j6                  }t4        j8                  }	|t4        _        |t4        _        	 t;        dRi |}|j,                  r+|)|t4        _        |	t4        _        ||j=                          	 |j,                  rd1d,l}
d1d8lm } |
j.                  jC                         jE                  d9      }t        |j$                        |j                  z  d2z  }t        |d:| d;z        } |||       tG        d<|        |jH                  r<d1d,l%}|j;                  d=d>|d?tL        jN                  jQ                  d@dA      dBdCgdDE       tG        dFdG        tG        dH|j                          tG        dI|dJ           tG        dK|dL   dM       tG        dN|dO    dP|dQ           tG        dG        y1c c}w # |j,                  r-|*|t4        _        |	t4        _        ||j=                          w w w w xY w)Su   CLI 엔트리포인트u2   Autoresearch: 스킬 프롬프트 자동 최적화)descriptionz--skillTu$   스킬명 (skills/ 하위 폴더명))requiredhelpz--checklistu   체크리스트 YAML 경로z--roundsr   u    최대 라운드 수 (기본 50))typedefaultr   z--target-scorer   u   목표 점수 (기본 0.95)z--consecutiver   u   연속 달성 횟수 (기본 3)z--model-mutater   u   변경 생성용 모델)r   r   z--model-judger   u   채점용 모델z	--dry-run
store_trueu2   실제 변경 없이 1라운드만 시뮬레이션)actionr   z--skills-dirr   u   스킬 디렉토리 경로z--backgrounduQ   백그라운드 모드: stdout 파일 리다이렉트 후 보고서 자동 생성z--notifyuG   완료 시 cokacdir로 보고서 전송 (--background와 함께 사용))r   z--test-inputu&   테스트용 입력 텍스트 (단일))r   z--test-inputs-fileu,   테스트 입력 YAML 파일 경로 (멀티))	r   r   r   r   r   rH   rI   r   r   NrJ   textrK   r   r   r   r   zautoresearch-stdout.logwr*   r+   )generate_reportz%Y%m%d-%H%M%Szreport-z.mdu   보고서 저장: z/usr/local/bin/cokacdirz
--sendfilez--chatCOKACDIR_CHAT_ID
6937032012z--key109fa85250c6d46bF)check
z2==================================================u   Autoresearch 완료: u   라운드: total_roundsu   최종 점수: final_scorer   zKEEP: ri   z
, REVERT: rj   re   ))argparseArgumentParseradd_argumentrz   r|   r   r   _WORKSPACE_ROOTadd_mutually_exclusive_group
parse_argsskillrD   r   r   r   rH   rI   r   r   rJ   rB   test_inputs_filer   datetimer   r:   sysstdoutstderrr   closeautoresearch.reporterr   nowstrftimery   notify
subprocessosenvironr<   )r   parserinput_groupargs
run_kwargsinputs_dataitemlog_fileoriginal_stdoutoriginal_stderrr   r    log_pathrE   r   	timestampreport_pathr   s                     r"   mainr     si   $$1efF
	D7]^
;XY

b?ab
(udIfg
c1Cde
(2ELef
1LSef
L?st
D4IH4T0U\xy
|  3F   <.w  
 55t5DK^2Z[18fgT"D jj..++))''))''<<oo
"J "#'??
<  't'<'<=>I$JdT&\$J
=! #'
<  HOO)DJJ6@	t488HsW=****

!J ??:(CJ(CJ#  9%%))+44_E	)DJJ6@	)	{#&>>?[)";-01 ;;NN- JJNN#5|D&    
Bvh-	!$**
./	KN+,
-.	OC.s3
45	F3v;-z#j/):
;<	VHK %K4 ??:(CJ(CJ#  $  ;?s   ?QQ ;R__main__)NN)N)1__doc__r   r   r   r   pathlibr   typingr   r   r   __file__r   parent_SCRIPTS_DIRr?   insertr   r<   r   autoresearch.changelogr   r   r	   r
   r   autoresearch.judger   r   autoresearch.mutatorr   autoresearch.skill_executorr   r   r#   r0   r3   listr{   rB   rz   r|   tupler   boolr   r   __name__exitre   r$   r"   <module>r      s    	  
   4>))+2299:sxxHHOOA|$**..c$x.00299@@GGH g f ; 2 A& & & &5c 53 5C 5VY 5^b 5&5s 5# 53 5UX 5]a 5& T#s(^(< R "$(^2^2^2 ^2 CH~	^2
 
c3h^2 ^2 ^2 ^2 ^2 ^2 d
^2 cT!^2 3tCH~%&^2H "$(+2$/(:;xxx d
x cT!	x
 x x x x x x x x 
#s(^xvqtCy4 q3 qh zCHHTV r$   