
    (GjoH                        d Z ddlZddlZddlmZ ddlmZmZmZ  ee	          j
        j
                                        Zej                            d ee                     ddlmZmZ ddlmZ ddeee                  deee                  fd	Zd
 ZdefdZddZddefdZd Zd ZddZd Zd Z dededede!fdZ"d Z#dS )z
Cron subcommand for hermes CLI.

Handles standalone cron management commands like list, create, edit,
pause/resume/run/remove, status, and tick.
    N)Path)IterableListOptional)Colorscolor)"contains_gateway_lifecycle_commandskillsreturnc                     || d S | g}nt          |          }g }|D ]@}t          |pd                                          }|r||vr|                    |           A|S )N )liststrstripappend)single_skillr
   	raw_items
normalizeditemtexts         5/home/rurouni/.hermes/hermes-agent/hermes_cli/cron.py_normalize_skillsr      s    ~4!N		LL	J $ $4:2$$&& 	$D
**d###    c                  B    ddl m} t          j         |di |           S )Nr   )cronjob )tools.cronjob_toolsr   jsonloads)kwargscronjob_tools     r   	_cron_apir"   -   s4    ;;;;;;:ll,,V,,---r   c                  T    	 ddl m}   |             j        pdS # t          $ r Y dS w xY w)u8  Name of the resolved cron scheduler provider ('builtin', 'chronos', …).

    Best-effort + offline (``resolve_cron_scheduler`` reads config and the
    provider's ``is_available()`` contract forbids network). Returns 'builtin'
    on any failure so callers fall back to the historical ticker-based checks.
    r   resolve_cron_schedulerbuiltin)cron.scheduler_providerr%   name	Exceptionr$   s    r   _active_cron_provider_namer*   3   sR    BBBBBB%%'',9	9   yys    
''c                     	 t                      dk    rdS ddlm}   |             rdS n# t          $ r Y dS w xY wt	          t          dt          j                             t	          t          dt          j                             t	          t          dt          j                             t	          t          dt          j                             dS )	u  Warn that scheduled jobs won't fire unless the gateway is running.

    The cron ticker only runs inside the gateway (``_start_cron_ticker`` in
    gateway/run.py); there is no standalone cron daemon. Without a running
    gateway, ``next_run_at`` passes but jobs never fire and ``last_run_at``
    stays null — the most common cron support report (#51038). Surfacing this
    at create/list time, when the user is right there, prevents it.

    An external provider (e.g. Chronos) fires jobs via a NAS-mediated webhook,
    NOT the in-process ticker, so a momentarily-absent gateway process does not
    mean jobs won't fire — the warning would be a false alarm. Stay quiet for
    any non-builtin provider; the gateway-process heuristic only speaks to the
    built-in ticker's trigger.
    r&   Nr   find_gateway_pidsu@     ⚠  Gateway is not running — jobs won't fire automatically.z*     Start it with: hermes gateway installzI                    sudo hermes gateway install --system  # Linux serversz&     Check status:  hermes cron status)	r*   hermes_cli.gatewayr-   r)   printr   r   YELLOWDIMr,   s    r   _warn_if_gateway_not_runningr2   B   s    
%''944F888888 	F	    
%RTZTa
b
bccc	%<fj
I
IJJJ	%[]c]g
h
hiii	%8&*
E
EFFFFFs   ) ) 
77Fshow_allc           	      n
   ddl m}  ||           }|sPt          t          dt          j                             t          t          dt          j                             dS t                       t          t          dt          j                             t          t          dt          j                             t          t          d	t          j                             t                       |D ]-}|                    d
d          }|                    dd          }|                    d|                    di                               dd                    }|                    d|                    dd          rdnd          }|                    dd          }|                    d          pi }	|	                    d          }
|	                    dd          }|
r| d|
 nd}|                    d          pdg}t          |t                    r|g}d
                    |          }|                    d          p|                    d           r	|d          gng }|dk    rt          d!t          j                  }nl|dk    rt          d"t          j                  }nK|                    dd          rt          d#t          j                  }nt          d$t          j                  }t          d%t          |t          j                   d&|            t          d'|            t          d(|            t          d)|            t          d*|            t          d+|            |r%t          d,d
                    |                      |                    d-          }|rt          d.|            |                    d/          r+t          d0t          d1t          j                   d2           |                    d3          }|rt          d4|            |                    d5          }|r|                    d6d          }|d7k    rt          d7t          j                  }n3t          | d8|                    d9d           t          j                  }t          d:| d%|            |                    d;          }|r-t          d<t          d=t          j                   d&|            t                       /t                       dS )>zList all scheduled jobs.r   	list_jobsinclude_disabledzNo scheduled jobs.zFCreate one with 'hermes cron create ...' or the /cron command in chat.Nu   ┌─────────────────────────────────────────────────────────────────────────┐uO   │                         Scheduled Jobs                                  │u   └─────────────────────────────────────────────────────────────────────────┘id?r(   z	(unnamed)schedule_displayschedulevaluestateenabledT	scheduledpausednext_run_atrepeattimes	completed/u   ∞deliverlocal, r
   skillz[paused]z[completed]z[active]z
[disabled]   z    Name:      z    Schedule:  z    Repeat:    z    Next run:  z    Deliver:   z    Skills:    scriptz    Script:    no_agentz    Mode:      zno-agentz# (script stdout delivered directly)workdirz    Workdir:   last_statuslast_run_atokz: 
last_errorz    Last run:  last_delivery_errorz    u   ⚠ Delivery failed:)	cron.jobsr6   r/   r   r   r1   CYANget
isinstancer   joinr0   BLUEGREENREDr2   )r3   r6   jobsjobjob_idr(   r<   r>   next_runrepeat_inforepeat_timesrepeat_completed
repeat_strrG   deliver_strr
   statusrM   rO   rP   last_runstatus_displaydelivery_errs                          r   	cron_listrj   c   sX   ######9h///D e(&*55666e\^d^hiijjj	GGG	%  t  v|  vA  B  B  C  C  C	%acicn
o
oppp	%  t  v|  vA  B  B  C  C  C	GGG A As##wwv{++77-swwz2/F/F/J/J7TW/X/XYY	40H0H!VhWW77=#..
 ggh''-2"w//&??;::=IT(99<999u
 '')$$1	gs## 	 iGii((""R9I9I'QG~~rH:v}55FFk!!=&+66FFWWY%% 	5:v|44FF<44F:5//::&::;;;&&&'''***+++,
,,---***+++---... 	97DIIf$5$577888"" 	.,F,,---77: 	hfE*fj$A$Afffggg'')$$ 	/-G--... ggm,, 	Bww}c22Hd""!&tV\!:!:!&+'U'Us9S9S'U'UW]Wa!b!b@H@@@@AAAww455 	XV5v}EEVVVVWWW """""r   c                  *    ddl m}   | d           dS )zRun due jobs once and exit.r   tickT)verboseN)cron.schedulerrm   rl   s    r   	cron_tickrp      s-    ######Dr   c            	      P   ddl m}  ddlm} t	                       t                      }|dk    rt	          t          d| dt          j                             t	          t          dt          j	                             t	                       t           | d	                     t	                       d
S  |            }|rddl m}m}m} |dz  dz   } |            } |            }	|||k    rt	          t          dt          |           dt          j                             t	          dd                    t#          t$          |                                t	          d           n}||	|	|k    rt	          t          dt          |	           dt          j                             t	          dd                    t#          t$          |                                t	          d           nt	          t          dt          j                             t	          dd                    t#          t$          |                                | t	          dt          |           d           nqt	          t          dt          j                             t	                       t	          d           t	          d           t	          d           t	          d           t	                       t           | d	                     t	                       d
S )zShow cron execution status.r   r5   r,   r&   u   ✓ Cron provider: uD    — jobs fire via the managed scheduler, not the in-process ticker.zq  (No ticker heartbeat is expected for an external provider; due jobs are delivered by an authenticated webhook.)Fr7   N)get_ticker_heartbeat_ageget_ticker_success_ageTICKER_INTERVAL_SECONDS      uN   ⚠ Gateway is running but the cron ticker looks STALLED — no heartbeat for zs (expected every ~60s).z  PID: rI   z>  Cron jobs may NOT be firing. Restart: hermes gateway restartuF   ⚠ Gateway and cron ticker are running, but no tick has succeeded in u   s — ticks may be failing.z.  Check the gateway log for 'Cron tick error'.u<   ✓ Gateway is running — cron jobs will fire automaticallyz  Ticker heartbeat: zs agou6   ✗ Gateway is not running — cron jobs will NOT firez   To enable automatic execution:z9    hermes gateway install    # Install as a user servicezS    sudo hermes gateway install --system  # Linux servers: boot-time system servicez4    hermes gateway            # Or run in foreground)rU   r6   r.   r-   r/   r*   r   r   r[   r1   _print_active_jobs_summaryrr   rs   rt   intr0   rY   mapr   r\   )
r6   r-   providerpidsrr   rs   rt   STALE_AFTERhb_ageok_ages
             r   cron_statusr      s   ######444444	GGG)++H9 	e)( ) ) )L
 
 	 	 	
 	eCJ
 
 	 	 	
 	"99e#D#D#DEEED 1F	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 .1B6))++''))&;"6"6%J$'KKJ J J    
 7DIIc#tnn5577888RSSSSF$66K;O;O %I #FI I I    
 7DIIc#tnn5577888BCCCC%VX^Xdeefff7DIIc#tnn5577888!?S[[???@@@eLfjYYZZZ0111IJJJcdddDEEE	GGGyy%@@@AAA	GGGGGr   c                     | rQd | D             }t          dt          |            d           |r!t          dt          |                      dS dS t          d           dS )zvPrint the '<N> active job(s)' + next-run line shared by every status
    path (built-in ticker AND external provider).c                 b    g | ],}|                     d           |                     d           -S )rB   )rW   ).0js     r   
<listcomp>z._print_active_jobs_summary.<locals>.<listcomp>  s5    PPPa155;O;OPQUU=))PPPr   rK   z active job(s)  Next run: z  No active jobsN)r/   lenmin)r]   	next_runss     r   rw   rw     s      "PP4PPP	,3t99,,,--- 	31Y1122222	3 	3 	 !!!!!r   c                    t          d| j        | j        t          | dd           t          | dd           t          | dd           t          | dd           t	          t          | dd           t          | dd                     t          | dd           t          | dd           t          | d	d
          pd           }|                    d          s@t          t          d|                    dd           t          j	                             dS t          t          d|d          t          j
                             t          d|d                     t          d|d                     |                    d          r+t          dd                    |d                               |                    di           }|                    d          rt          d|d                     |                    d	          rt          d           |                    d          rt          d|d                     t          d|d                     t                       dS )Ncreater(   rG   rC   rJ   r
   rM   rO   rN   F)actionr<   promptr(   rG   rC   rJ   r
   rM   rO   rN   successzFailed to create job: errorunknown error   zCreated job: r_     Name:   Schedule: r<   
  Skills: rI   r^   
  Script: 3  Mode: no-agent (script stdout delivered directly)  Workdir: r   rB   r   )r"   r<   r   getattrr   rW   r/   r   r   r\   r[   rY   r2   )argsresultjob_datas      r   cron_creater   &  sf    {T64((i..tXt,,dGT** w!=!=wtXW[?\?\]]tXt,,i..z5119T  F ::i   eSVZZ-Q-QSSU[U_``aaaq	%2x 022FL
A
ABBB	
%VF^
%
%&&&	
-
+
-
-...zz( :8499VH%56688999zz%$$H||H 1/8H-//000||J ECDDD||I 31HY/11222	
0.
0
0111 """1r   c                    ddl m}m} 	  || j                  }n# |$ rx}t	          t          t          |          t          j                             |j	        D ]1}t	          d|d          d|
                    d          d           2Y d }~dS d }~ww xY w|s1t	          t          d	| j         t          j                             dS t          |
                    d
          p,|
                    d          sg n|
                    d          g          }t          t          | dd           t          | d
d                     }t          d t          | dd                     pg }t          t          d t          | dd                     pg           d }	t          | dd          rg }	n5||}	n0|sr,fd|D             }	|D ]}
|
|	vr|	                    |
           t!          d| j        t          | dd           t          | dd           t          | dd           t          | dd           t          | dd           |	t          | dd           t          | dd           t          | dd                     }|
                    d          s@t	          t          d|
                    dd           t          j                             dS |d         }t	          t          d|d           t          j                             t	          d!|d                     t	          d"|d                     |
                    d
          r,t	          d#d$                    |d
                               nt	          d%           |
                    d          rt	          d&|d                     |
                    d          rt	          d'           |
                    d          rt	          d(|d                     dS ))Nr   )AmbiguousJobReferenceresolve_job_refrK   r9   z	  (name: r(   )r   zJob not found: r
   rJ   
add_skillsremove_skillsclear_skillsFc                     g | ]}|v|	S r   r   )r   rJ   r   s     r   r   zcron_edit.<locals>.<listcomp>g  s#    YYY%e=>X>X>X>X>Xr   updater<   r   rG   rC   rM   rO   rN   )r   r_   r<   r   r(   rG   rC   r
   rM   rO   rN   r   zFailed to update job: r   r   r^   zUpdated job: r_   r   r   r   rI   z  Skills: noner   r   r   )rU   r   r   r_   r/   r   r   r   r\   matchesrW   r   r   r   setr   r"   r[   rY   )r   r   r   r^   excmexisting_skillsreplacement_skillsr   final_skillsrJ   r   updatedr   s                @r   	cron_editr   N  sZ   @@@@@@@@odk**    eCHHfj))*** 	= 	=A;qw;;v;;;<<<<qqqqq	
  e3dk33VZ@@AAAq3778,,d3777;K;K1cRURYRYZaRbRbQceeO*74$+G+GQUW_aeIfIfgg"4|T)J)JKKQrJ)$ot0T0TUU[Y[\\MLt^U++ +		')	 +} +YYYY?YYY 	+ 	+EL((##E***{z400tXt,,T64((i..tXt,,tXt,,i..z400  F ::i   eSVZZ-Q-QSSU[U_``aaaqUmG	%3 133V\
B
BCCC	
&WV_
&
&'''	
.,
.
.///{{8  9499WX%67799::::{{8 0.78,..///{{: ECDDD{{9 20GI.001111s    BA-BBr   r_   success_verbc                    t          | |          }|                    d          sCt          t          d|  d|                    dd           t          j                             dS |                    d          p|                    d	          pi }t          t          | d|                    d
|           d| dt          j                             | dv rG|                    di                               d          rt          d|d         d                     | dk    r|                    di           }|                    d          r-|                    d          rdnd}t          d| d           n=|                    d          rt          d|d                     nt          d           dS )N)r   r_   r   z
Failed to z job: r   r   r   r^   removed_jobr(   z (r   >   runresumerB   r   r   executedexecution_success	succeededfailedz  Ran now: .execution_skippedrK   z)  It will run on the next scheduler tick.r   )r"   rW   r/   r   r   r\   r[   )r   r_   r   r   r^   outcomes         r   _job_actionr     s   fV444F::i   eUUUvzz'?/S/SUUW]Wabbcccq
**U


>vzz-88
>BC	%<KKswwvv'>'>KK&KKKV\
Z
Z[[["""vzz%'<'<'@'@'O'O";VE]=9;;<<<jj##77: 	?%(WW-@%A%AOkkxG****++++WW()) 	?1s./112222=>>>1r   c                 j   t          | dd          }||dk    r"t          | dd          }t          |           dS |dk    rt                       dS |dk    rt                       dS |d	v rt	          |           S |d
k    rt          |           S |dk    rt          d| j        d          S |dk    rt          d| j        d          S |dk    rt          d| j        d          S |dv rt          d| j        d          S t          d|            t          d           t          j
        d           dS )zHandle cron subcommands.cron_commandNr   allFr   rf   rm   >   addr   editpausePausedr   Resumedr   	Triggered>   rmdeleteremover   RemovedzUnknown cron command: zIUsage: hermes cron [list|create|edit|pause|resume|run|remove|status|tick]r   )r   rj   r   rp   r   r   r   r_   r/   sysexit)r   subcmdr3   s      r   r   r     s[   T>400F~6))4..(qqq"""4   7DK:::8T[)<<<5$+{;;;+++8T[)<<<	
+6
+
+,,,	
UVVVHQKKKKKr   )NN)r   N)F)$__doc__r   r   pathlibr   typingr   r   r   __file__parentresolvePROJECT_ROOTpathinsertr   hermes_cli.colorsr   r   cron.lifecycle_guardr	   #_contains_gateway_lifecycle_commandr   r"   r*   r2   boolrj   rp   r   rw   r   r   rx   r   r   r   r   r   <module>r      s     



       + + + + + + + + + +tH~~$+3355 33|$$ % % % + + + + + + + +     
 (3-1H T\]abe]fTg     . . .C    G G G GBT# T# T# T# T# T#n  W W Wt	" 	" 	" 	"% % %P= = =@ S      *% % % % %r   