
    i4;                        d Z ddlmZ ddlZddlZddlmZmZ ddlmZ dd
Z	ddZ
ddZddZddZddZddZddZddZddZddZdddZedk    r ej         e                       dS dS )u0  CLI subcommand: `hermes curator <subcommand>`.

Thin shell around agent/curator.py and tools/skill_usage.py. Renders a status
table, triggers a run, pauses/resumes, and pins/unpins skills.

This module intentionally has no side effects at import time — main.py wires
the argparse subparsers on demand.
    )annotationsN)datetimetimezone)OptionaltsOptional[str]returnstrc                   | sdS 	 t          j        |           }n&# t          t          f$ r t	          |           cY S w xY w|j         |                    t          j                  }t          j	        t          j                  |z
  }t          |                                          }|dk     r| dS |dk     r|dz   dS |dk     r|dz   dS |dz   d	S )
Nnever)tzinfo<   zs agoi  zm agoiQ zh agozd ago)r   fromisoformat	TypeError
ValueErrorr
   r   replacer   utcnowinttotal_seconds)r   dtdeltasecss       7/home/ubuntu/.hermes/hermes-agent/hermes_cli/curator.py_fmt_tsr      s    w#B''z"   2ww	yZZx|Z,,L&&+Eu""$$%%Dbyy~~~d{{"*####e||$,%%%%em""""s     >>r   c                ,   ddl m} ddlm} |                                }|                                }|                    dd          }|                    d          }|                    d          pd}|                    d	d          }|r|sd
n|rdnd}	t          d|	            t          d|            t          dt          |                      t          d|            |                    d          }
|
rt          d|
            |	                                }|dz  dk    r|dk    r|dz   dn| d}t          d|            t          d|
                                 d           t          d|                                 d           |                                }|st          d           dS g g g d}g }|D ]q}|                    dd          }|                    |g                               |           |                    d          r|                    |d                    rt          d t          |           d!           dD ];}|                    |g           }t          d"|d#d$t          |                      <|r5t          d%t          |           d&d'                    |                      t#          |                    dg           d( )          d d*         }|rt          d+           |D ]}t          |                    d,                    }t          d"|d         d-d.|                    d/d          d0d1|                    d2d          d0d3|                    d4d          d0d5|                    d6d          d0d7|            |                    dg           }|rt#          |d8 d9:          d d*         }|r|d                             d/          pddk    rt          d;           |D ]}t          |                    d,                    }t          d"|d         d-d.|                    d/d          d0d1|                    d2d          d0d3|                    d4d          d0d5|                    d6d          d0d7|            t#          |d< )          d d*         }|rt          d=           |D ]}t          |                    d,                    }t          d"|d         d-d.|                    d/d          d0d1|                    d2d          d0d3|                    d4d          d0d5|                    d6d          d0d7|            dS )>Nr   curatorskill_usagepausedFlast_run_atlast_run_summaryz(none)	run_countENABLEDPAUSEDDISABLED	curator: z  runs:           z  last run:       z  last summary:   last_report_pathz  last report:       dhz  interval:       every z  stale after:    zd unusedz  archive after:  z
no agent-created skills)activestalearchivedstater-   pinnednamez
agent-created skills: z totalz  10s z	
pinned (z): z, c                Z    |                      d          p|                      d          pdS )Nlast_activity_at
created_at getrs    r   <lambda>z_cmd_status.<locals>.<lambda>`   s)    aee.//L1553F3FL"     )key   z
least recently active (top 5):r6   40sz  activity=activity_count3dz  use=	use_countz  view=
view_countz
  patches=patch_countz  last_activity=c                ^    |                      d          pd|                      d          pdfS NrB   r   r6   r8   r9   r;   s    r   r=   z_cmd_status.<locals>.<lambda>y   0    155!1227a?Q9R9R9XVXY r>   T)r?   reversez
most active (top 5):c                ^    |                      d          pd|                      d          pdfS rH   r9   r;   s    r   r=   z_cmd_status.<locals>.<lambda>   rI   r>   z
least active (top 5):)agentr   toolsr    
load_state
is_enabledr:   printr   get_interval_hoursget_stale_after_daysget_archive_after_daysagent_created_report
setdefaultappendlenjoinsorted)argsr   r    r0   enabledr!   last_runsummaryrunsstatus_line_report_ih_interval_labelrowsby_stater1   r<   
state_namebucketr-   last
active_allmost_activeleast_actives                           r   _cmd_statusrk   &   s'   !!!!!!  E  ""GYYx''Fyy''Hii*++7xG99[!$$D  	V 			 	 
 

#k
#
#$$$	
%t
%
%&&&	
2wx00
2
2333	
(w
(
()))ii*++G .,7,,---

$
$
&
&C8q==SBYY3"9YYY  

6_
6
6777	
Gw;;==
G
G
GHHH	
Iw==??
I
I
IJJJ++--D )***qrr::HF % %UU7H--
J++22155555?? 	%MM!F)$$$	
6SYY
6
6
67775 3 3
j"--1:111CKK112222 @>3v;;>>499V+<+<>>???
 Xr""LL   	qb
F  0111 		 		A155!34455D(QvY& ( (EE"2A66=( (uu[!,,3( ( lA..5( ( 55229	( (
 "&( (    h++J "YY
 
 
 1"	
  	KN../?@@EAJJ*+++  	 	quu%78899,6* , , !&6 : :A, ,55a007, , EE,229, ,  !uu]A66=	, ,
 &*, ,    YY
 
 
 1"  	+,,,! 	 	quu%78899,6* , , !&6 : :A, ,55a007, , EE,229, ,  !uu]A66=	, ,
 &*, ,    1r>   c                   ddl m} |                                st          d           dS t	          t          | dd                    }|rt          d           nt          d           dd}|                    |t	          | j                  |          }|                    di           }|r|r(t          d|                    dd           d           nkt          d|                    dd           d|                    dd           d|                    dd           d|                    dd                      | j        st          d           |rt          d           dS )Nr   r   zAcurator: disabled via config; enable with `curator.enabled: true`   dry_runFz7curator: running DRY-RUN (report only, no mutations)...zcurator: running review pass...msgr
   r	   Nonec                $    t          |            d S N)rP   )ro   s    r   _on_summaryz_cmd_run.<locals>._on_summary   s    c




r>   )
on_summarysynchronousrn   auto_transitionszauto (preview): checkedu9    candidate skill(s) — no transitions applied in dry-runzauto: checked=z stale=marked_stalez
 archived=r/   z reactivated=reactivateduF   llm pass running in background — check `hermes curator status` laterzdry-run: no changes applied. When the report lands, read it with `hermes curator status` and run `hermes curator run` (no flag) to apply.)ro   r
   r	   rp   )	rL   r   rO   rP   boolgetattrrun_curator_reviewru   r:   )rZ   r   dryrs   resultautos         r   _cmd_runr      s    QRRRq
wtY..
/
/C
 1GHHHH/000    '')** (  F
 ::("--D  	8488Iq#9#9 8 8 8   
 <)Q!7!7 < <.!44< < HHZ33< <  $xxq99< <    XVWWW
 
W	
 	
 	
 1r>   c                Z    ddl m} |                    d           t          d           dS )Nr   r   Tzcurator: pausedrL   r   
set_pausedrP   rZ   r   s     r   
_cmd_pauser      s<    t	
1r>   c                Z    ddl m} |                    d           t          d           dS )Nr   r   Fzcurator: resumedr   r   s     r   _cmd_resumer      s<    u	
1r>   c                    ddl m} |                    | j                  st	          d| j         d           dS |                    | j        d           t	          d| j         d           dS )	Nr   r   
curator: 'u`   ' is bundled or hub-installed — cannot pin (only agent-created skills participate in curation)rm   Tzcurator: pinned 'z ' (will bypass auto-transitions)rM   r    is_agent_createdskillrP   
set_pinnedrZ   r    s     r   _cmd_pinr      s    !!!!!!''
33 B B B B	
 	
 	
 q4:t,,,	
Jdj
J
J
JKKK1r>   c                    ddl m} |                    | j                  st	          d| j         d           dS |                    | j        d           t	          d| j         d           dS )	Nr   r   r   ue   ' is bundled or hub-installed — there's nothing to unpin (curator only tracks agent-created skills)rm   Fzcurator: unpinned ''r   r   s     r   
_cmd_unpinr      s    !!!!!!''
33 R R R R	
 	
 	
 q4:u---	
-

-
-
-...1r>   c                x    ddl m} |                    | j                  \  }}t	          d|            |rdndS )Nr   r   r(   rm   )rM   r    restore_skillr   rP   )rZ   r    okro   s       r   _cmd_restorer      sR    !!!!!!''
33GB	
c

>11r>   c                   ddl m} |                                st          d           dS t	          | dd          pd}|                    |          }|t          d	           dS t          d
|j                    dS )zuTake a manual snapshot of the skills tree. Same mechanism as the
    automatic pre-run snapshot, just user-initiated.r   curator_backupzacurator: backups are disabled via config (`curator.backup.enabled: false`); re-enable to snapshotrm   reasonNmanual)r   uE   curator: snapshot failed — check logs (backup disabled or IO error)z?curator: snapshot created at ~/.hermes/skills/.curator_backups/)rL   r   rO   rP   r{   snapshot_skillsr2   )rZ   r   r   snaps       r   _cmd_backupr      s     %$$$$$$$&& G	
 	
 	
 qT8T**6hF)))88D|UVVVq	
WDI
W
WXXX1r>   c                   ddl m} t          | dd          r#t          |                                           dS t          | dd          }|                    |          }||                                }|st          d           nWt          d|rd	t          |          z   nd
 d           t          d           t          |                                           dS |                    |          }t          d|j	                    |rt          d|
                    dd                      t          d|
                    dd                      t          d|
                    dd                      |
                    d          pi }t          |t                    rf|
                    d          r(t          d|
                    dd           d           n)|
                    dd          }t          d| d           t          d           t          | dd          sq	 t          d                                                                           }n'# t           t"          f$ r t          d!           Y dS w xY w|d"vrt          d#           dS |                    |j	        $          \  }	}
}|	rt          d%|
            dS t          d&|
            dS )'a7  Restore the skills tree from a snapshot. Defaults to newest.

    ``--list`` prints available snapshots and exits. ``--id <stamp>`` picks
    a specific one. Without ``-y``, prompts for confirmation. A safety
    snapshot of the current tree is always taken first, so rollbacks are
    themselves undoable.
    r   r   listF	backup_idNzhcurator: no snapshots exist yet. Take one with `hermes curator backup` or wait for the next curator run.zcurator: no snapshot matching zid z
your query.z
Available:rm   zRollback target: z  reason:      r   ?z  created_at:  r7   z  skill files: skill_files	cron_jobs	backed_upz  cron jobs:   
jobs_countz. (will be restored for skill-link fields only)znot capturedz   cron jobs:   not in snapshot ()a  
This will replace the current ~/.hermes/skills/ tree (a safety snapshot of the current state is taken first so this is undoable). Cron jobs that still exist will have their skills/skill fields restored from the snapshot; all other cron fields are left alone.yeszProceed? [y/N] z

cancelled)yr   	cancelled)r   r(   u   curator: rollback failed — )rL   r   r{   rP   summarize_backups_resolve_backuplist_backupsrepr_read_manifestr2   r:   
isinstancedictinputstriplowerEOFErrorKeyboardInterruptrollback)rZ   r   r   target_pathrc   manifestcronr   ansr   ro   _s               r   _cmd_rollbackr     s}    %$$$$$tVU## n..00111qk400I 00;;K**,, 	6L   
 M.7I54	??**\M M M   ,.2244555q,,[99H	
0k.
0
0111 D=Xs ; ;==>>>A\3 ? ?AABBBB]C @ @BBCCC||K((.BdD!! 	Dxx$$ DEdhh|Q&?&? E E E   
 (N;;BBBBCCC		L   4&& 	)**002288::CC+, 	 	 	-   11	 l""+1((;3C(DDJBQ	 #   q	
/#
/
/0001s   63I* * JJparentargparse.ArgumentParserrp   c                                           fd                                d          }|                    dd          }|                     t                     |                    dd	          }|                    d
dddd           |                    dddd           |                     t
                     |                    dd          }|                     t                     |                    dd          }|                     t                     |                    dd          }|                    dd           |                     t                     |                    dd          }|                    dd           |                     t                     |                    dd          }|                    dd           |                     t                     |                    dd           }	|	                    d!d"d#$           |	                     t                     |                    d%d&          }
|
                    d'dd()           |
                    d*d+d"d,-           |
                    d.d/dd0)           |
                     t                     d"S )1zAttach `curator` subcommands to *parent*.

    main.py calls this with the ArgumentParser returned by
    ``subparsers.add_parser("curator", ...)``.
    c                <                                     dfd         S )Nr   rm   )
print_help)ar   s    r   r=   zregister_cli.<locals>.<lambda>^  s    (9(9(;(;Q'?'B r>   )funccurator_command)deststatusz#Show curator status and skill stats)helprunzTrigger a curator review nowz--syncz--synchronousru   
store_truezCWait for the LLM review pass to finish (default: background thread))r   actionr   z	--dry-runrn   uk   Report only — no state changes, no archives, no consolidation (use this to preview what curator would do)pausezPause the curator until resumedresumezResume a paused curatorpinz4Pin a skill so the curator never auto-transitions itr   z
Skill nameunpinzUnpin a skillrestorezRestore an archived skillbackupzoTake a manual tar.gz snapshot of ~/.hermes/skills/ (curator also does this automatically before every real run)z--reasonNz;Free-text label stored in manifest.json (default: 'manual'))defaultr   r   zJRestore ~/.hermes/skills/ from a curator snapshot (defaults to the newest)z--listz3List available snapshots and exit without restoring)r   r   z--idr   z6Snapshot id to restore (see `--list`); default: newest)r   r   r   z-yz--yeszSkip confirmation prompt)set_defaultsadd_subparsers
add_parserrk   add_argumentr   r   r   r   r   r   r   r   )r   subsp_statusp_runp_pausep_resumep_pinp_unpin	p_restorep_backup
p_rollbacks   `          r   register_clir   X  s1    BBBBCCC  &7 88Dx.STTH{+++OOE(FOGGE	/lR     
)L;    
 
H%%%oog,MoNNGj)))x.GHHH{+++OOE(^O__E	w\222	H%%%oogOo<<G|444j)))	0KLLI7666---L   H
 DJ     {+++( !  J
 B     [$E     gl'     /////r>   c                    t          j        d          }t          |           |                    |           }t	          |dd          }||                                 dS t           ||          pd          S )z>Standalone entry (also usable by hermes_cli.main fallthrough).zhermes curator)progr   Nr   )argparseArgumentParserr   
parse_argsr{   r   r   )argvparserrZ   fns       r   cli_mainr     s~    $*:;;;FT""D	vt	$	$B	zqrr$xx}1r>   __main__)r   r   r	   r
   )r	   r   )r   r   r	   rp   rr   )__doc__
__future__r   r   sysr   r   typingr   r   rk   r   r   r   r   r   r   r   r   r   r   __name__exit r>   r   <module>r      s    # " " " " "  



 ' ' ' ' ' ' ' '      # # # #(t t t tn) ) ) )X      
 
 
 

 
 
 
      &F F F FZF0 F0 F0 F0R	 	 	 	 	 zCHXXZZ r>   