+
    iQ              )          R t ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHtH	t	H
t
Ht ]P                  P                  ^ ]! ]! ]4      P                   P                   4      4       ^ RIHtHtHtHtHtHtHtHtHt . ROOt0 RPmtR R ltR R ltR	 R
 ltRQR R llt RR/R R llt!R R lt"R R lt#RRR R llt$RSR R llt%RTR R llt&RUR R llt'RRRR R!R"R#R$R%R"R&RR'/R(R"R&RR)/R*R"R&RR+/R,R"R&RR-/RR"R&RR./R/R"R0RR1/R2R"R&RR3/R4R"R&RR5/R6R"R&RR7/R8R"R&RR9/R:R"R;RR</R=R"R&RR>/R?R"R@RAR"R&/RRB/RCR"R&RRD/RER"R&RRF//RGR%.//t(RH RI lt)RJ t*^ RKI+H,t, ],PZ                  ! RR](RL ])RMRN7       R# )Vz
Cron job management tools for Hermes Agent.

Expose a single compressed action-oriented tool to avoid schema/context bloat.
Compatibility wrappers remain for direct Python callers and legacy tests.
NPath)AnyDictListOptional)	
create_jobget_job	list_jobsparse_schedule	pause_job
remove_job
resume_jobtrigger_job
update_jobc                0    V ^8  d   QhR\         R\         /# )   promptreturnstr)formats   "0/home/ubuntu/hermes-agent/tools/cronjob_tools.py__annotate__r   7   s      c c     c                    \          F  pW9   g   K  R\        V4      R R2u # 	  \         F8  w  r#\        P                  ! W \        P
                  4      '       g   K2  RV R2u # 	  R# )zUScan a cron prompt for critical threats. Returns error string if blocked, else empty.z-Blocked: prompt contains invisible unicode U+04Xz (possible injection).z(Blocked: prompt matches threat pattern 'zD'. Cron prompts must not contain injection or exfiltration payloads. )_CRON_INVISIBLE_CHARSord_CRON_THREAT_PATTERNSresearch
IGNORECASE)r   charpatternpids   &   r   _scan_cron_promptr'   7   si    %>B3t9S/Qghh & .99Wbmm44=cU  CG  H  H . r   c                \    V ^8  d   QhR\         \        \        \        3,          ,          /# r   r   )r   r   r   )r   s   "r   r   r   B   s      
 
(4S>2 
r   c            
          \         P                  ! R 4      p \         P                  ! R4      pV '       d;   V'       d3   RV RVR\         P                  ! R4      R\         P                  ! R4      /# R# )	HERMES_SESSION_PLATFORMHERMES_SESSION_CHAT_IDplatformchat_id	chat_nameHERMES_SESSION_CHAT_NAME	thread_idHERMES_SESSION_THREAD_IDN)osgetenv)origin_platformorigin_chat_ids     r   _origin_from_envr7   B   s\    ii 9:OYY78N>~#=>#=>	
 	
 r   c                R    V ^8  d   QhR\         \        \        3,          R\        /# r   jobr   r   r   r   )r   s   "r   r   r   O   s&     E Ec3h EC Er   c                    V P                  R 4      ;'       g    / P                  R4      pV P                  R 4      ;'       g    / P                  R^ 4      pVf   R# V^8X  d   V^ 8X  d   R# R# V'       d   V RV 2# V R2# )repeattimes	completedforeveroncez1/1/z times)get)r:   r>   r?   s   &  r   _repeat_displayrD   O   s    WWX$$"))'2E"((b--k1=I}z"av2U2%.i[%!DugV4DDr   c                ~    V ^8  d   QhR\         \        ,          R\         \        ,          R\        \        ,          /# )r   skillskillsr   )r   r   r   r   )r   s   "r   r   r   Y   s0      Xc] 8C= TXY\T] r   c                    Vf   V '       d   V .M. pM%\        V\        4      '       d   V.pM\        V4      p. pV FI  p\        T;'       g    R4      P                  4       pV'       g   K0  WS9  g   K8  VP	                  V4       KK  	  V# )Nr   )
isinstancer   liststripappend)rF   rG   	raw_items
normalizeditemtexts   &&    r   _canonical_skillsrQ   Y   sv    ~$UG"		FC	 	 H	L	J4::2$$&4D*d#  r   strip_trailing_slashFc                h    V ^8  d   QhR\         \        ,          R\        R\         \        ,          /# )r   valuerR   r   )r   r   boolr   )r   s   "r   r   r   j   s-      # QU bjknbo r   c                    V f   R # \        V 4      P                  4       pV'       d   VP                  R4      pT;'       g    R # )NrB   )r   rK   rstrip)rT   rR   rP   s   &$ r   _normalize_optional_job_valuerX   j   s9    }u:D{{3<<4r   c                \    V ^8  d   QhR\         \        ,          R\         \        ,          /# )r   scriptr   )r   r   )r   s   "r   r   r   s   s"     % %x} %# %r   c                   V '       d   V P                  4       '       g   R# ^ RIHp ^ RIHp V P                  4       pVP                  R4      '       g   \        V4      ^8  d   V^,          R8X  d   RV: R2# V! 4       R,          pVP                  RRR	7       WC,          P                  4       p VP                  VP                  4       4       R#   \         d
    R
T: 2u # i ; i)a  Validate a cron job script path at the API boundary.

Scripts must be relative paths that resolve within HERMES_HOME/scripts/.
Absolute paths and ~ expansion are rejected to prevent arbitrary script
execution via prompt injection.

Returns an error string if blocked, else None (valid).
Nr   )get_hermes_home:zXScript path must be relative to ~/.hermes/scripts/. Got absolute or home-relative path: z@. Place scripts in ~/.hermes/scripts/ and use just the filename.scriptsT)parentsexist_okz9Script path escapes the scripts directory via traversal: )rB   ~)rK   pathlibr   hermes_constantsr\   
startswithlenmkdirresolverelative_to
ValueError)rZ   r   r\   rawscripts_dirresolveds   &     r   _validate_cron_script_pathrm   s   s     0
,,.C ~~j!!c#h!mA#336' :MN	
 "#i/KdT2!**,H
[0023   
GwO	

s   1C C&%C&c                t    V ^8  d   QhR\         \        \        3,          R\         \        \        3,          /# r9   r;   )r   s   "r   r   r      s*      T#s(^ S#X r   c           	      h   V P                  R R4      p\        V P                  R4      V P                  R4      4      p/ RV R,          bRV R,          bRV'       d
   V^ ,          MRbRVbR\        V4      ^d8  d   VR	,          R
,           MTbRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bR\        V 4      bRV P                  RR4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  RR4      bRT P                  RV P                  RR4      '       d   RMR4      bRV P                  R4      bRV P                  R4      /CpV P                  R4      '       d   V R,          VR&   V# )r   r   rF   rG   job_ididnameNprompt_preview:Nd   Nz...modelproviderbase_urlscheduleschedule_displayr=   deliverlocalnext_run_atlast_run_atlast_statusenabledTstate	scheduledpaused	paused_atpaused_reasonrZ   )rC   rQ   re   rD   )r:   r   rG   results   &   r   _format_jobr      s   WWXr"Fswww/1BCF#d)F 	f$ 	&	
 	#f+2C&,. 	! 	CGGJ' 	CGGJ' 	CGG./ 	/#& 	3779g. 	sww}- 	sww}- 	sww}- 	3779d+  	D1I1I+xX!" 	SWW[)#$ 	1%F( wwxx=xMr   c          "         V ^8  d   QhR\         R\        \         ,          R\        \         ,          R\        \         ,          R\        \         ,          R\        \        ,          R\        \         ,          R\        R	\        \         ,          R
\        \        \         ,          ,          R\        \         ,          R\        \         ,          R\        \         ,          R\        \         ,          R\        \         ,          R\         R\         /# )r   actionrp   r   rx   rr   r=   rz   include_disabledrF   rG   ru   rv   rw   reasonrZ   task_idr   )r   r   intrU   r   )r   s   "r   r   r      s    cI cIcISMcI SMcI sm	cI
 3-cI SMcI c]cI cI C=cI T#YcI C=cI smcI smcI SMcI SMcI  !cI" 	#cIr   c                   ? T ;'       g    RP                  4       P                  4       pVR8X  Ed   V'       g   \        P                  ! RRRR/^R7      # \	        W4      pV'       g%   V'       g   \        P                  ! RRRR/^R7      # V'       d0   \        V4      pV'       d   \        P                  ! RRRV/^R7      # V'       d0   \        V4      pV'       d   \        P                  ! RRRV/^R7      # \        T;'       g    RVVVV\        4       V\        V
4      \        V4      \        VR	R
7      \        V4      R7      p\        P                  ! RR	RVR,          RVR,          RVP                  R4      RVP                  R. 4      RVR,          R\        V4      RVP                  RR4      RVR,          R\        V4      RRVR,           R2/^R7      # VR8X  dL   \        VR7       Uu. uF  p\        V4      NK  	  pp\        P                  ! RR	R\        V4      RV/^R7      # V'       g!   \        P                  ! RRRRV R 2/^R7      # \        V4      pV'       g!   \        P                  ! RRRR!V R"2/^R7      # VR#8X  dy   \!        V4      pV'       g!   \        P                  ! RRRR$V R 2/^R7      # \        P                  ! RR	RRVR,           R%2R&RVRVR,          RVP                  R4      //^R7      # VR'8X  d2   \#        WR(7      p\        P                  ! RR	R\        V4      /^R7      # VR)8X  d1   \%        V4      p\        P                  ! RR	R\        V4      /^R7      # VR99   d1   \'        V4      p\        P                  ! RR	R\        V4      /^R7      # VR*8X  Ed   / pVe5   \        V4      pV'       d   \        P                  ! RRRV/^R7      # VVR,&   Ve   VVR&   Ve   VVR&   V	f   Ve'   \	        W4      pVVR&   V'       d
   V^ ,          MR+VR&   V
e   \        V
4      VR-&   Ve   \        V4      VR.&   Ve   \        VR	R
7      VR/&   VeP   V'       d0   \        V4      pV'       d   \        P                  ! RRRV/^R7      # V'       d   \        V4      MR+VR0&   Ve:   V^ 8:  d   R+MTp\)        VP                  R4      ;'       g    / 4      pVVR1&   VVR&   VeF   \+        V4      pVVR&   VP                  R2V4      VR&   VP                  R34      R48w  d   R5VR3&   R	VR6&   V'       g   \        P                  ! RRRR7/^R7      # \-        VV4      p\        P                  ! RR	R\        V4      /^R7      # \        P                  ! RRRR8V  R 2/^R7      # u upi   \.         d0   p\        P                  ! RRR\1        T4      /^R7      u R+p?# R+p?ii ; i):z!Unified cron job management tool.r   createsuccessFerrorzschedule is required for create)indentz3create requires either prompt or at least one skillT)rR   )r   rx   rr   r=   rz   originrG   ru   rv   rw   rZ   rp   rq   rr   rF   rG   rx   ry   r=   rz   r{   r|   r:   messagez
Cron job 'z
' created.rJ   )r   countjobszjob_id is required for action ''zJob with ID 'z8' not found. Use cronjob(action='list') to inspect jobs.removezFailed to remove job 'z
' removed.removed_jobpause)r   resumeupdateNr   ru   rv   rw   rZ   r>   displayr   r   r   r   zNo updates provided.zUnknown cron action '>   runrun_nowtrigger)rK   lowerjsondumpsrQ   r'   rm   r   r7   rX   rC   rD   r   r
   re   r	   r   r   r   r   dictr   r   	Exceptionr   )r   rp   r   rx   rr   r=   rz   r   rF   rG   ru   rv   rw   r   rZ   r   rN   canonical_skills
scan_errorscript_errorr:   r   removedupdatedupdatesnormalized_repeatrepeat_stateparsed_schedulees   &&&&&&&&&&&&&&&&             r   cronjobr      s   & 	NIll))+113
!zz9eW>_"`ijkk0?"2zz9eW>s"t}~.v6
::y%*&MVWXX 9&A::y%,&OXYZZ||!')'3E:6x@6xVZ[4V<C ::tc$iCKSWWW-cggh3$6 7oc2swwy':!3}#5;s+CK=
C  " 09K[0\]0\K$0\D]::y$TFDQZ[\\::y%<[\f[ggh:ijstuufo::E7mF8C{,|} 
 ! (Gzz9eW@VW]V^^_>`"ajkll::tCK=
C!fF"CGG,>$?$    6G::y${77KLUVWW! (G::y${77KLUVWW66!&)G::y${77KLUVWW!&(G!.v6
::y%*&MVWXX$*!"&"%,	"!U%6#4U#C $4!:J#3A#6PT  #@#G #&CH&M
##&CHcg&h
#!#=f#EL##zz9eWl*S\]^^MS$A&$IY]!!,2aKDV!#CGGH$5$;$;<(9W%$0!#"0":&5
#.=.A.A)X.V*+777#x/'2GG$)-GI&zz9eW>T"U^_`` 1G::y${77KLUVWWzz9eW8MfXUV6WXabccq ^t  Izz9eWc!f=aHHIs   V? .V? V? V? 2V? V? .V? V? .V? <V? 
CV?  V? 5V:	(V? 2V? :V? 2V? 9V? AV? 7V? 6V? ;6V? 2<V? /BV? 8.V? 'V? /;V? +A!V? V? )0V? V? :V? ?W9
$W4.W94W9c                   V ^8  d   QhR\         R\         R\        \         ,          R\        \        ,          R\        \         ,          R\        \         ,          R\        \         ,          R\        \         ,          R	\         R
\         /
# )r   r   rx   rr   r=   rz   ru   rv   rw   r   r   )r   r   r   )r   s   "r   r   r   a  s       3- SM	
 c] C= sm sm  	r   c	                 ,    \        R V VVVVVVVVR7
      # )r   )
r   r   rx   rr   r=   rz   ru   rv   rw   r   r   )	r   rx   rr   r=   rz   ru   rv   rw   r   s	   &&&&&&&&&r   schedule_cronjobr   a  s/      r   c                <    V ^8  d   QhR\         R\        R\        /# )r   r   r   r   )rU   r   )r   s   "r   r   r   z  s&     V VD V3 V# Vr   c                     \        R WR7      # )rJ   )r   r   r   r   )r   r   s   &&r   list_cronjobsr   z  s    &3CUUr   c                <    V ^8  d   QhR\         R\         R\         /# )r   rp   r   r   r   )r   s   "r   r   r   ~  s&     D D3 D D Dr   c                     \        R WR7      # )r   )r   rp   r   r   )rp   r   s   &&r   remove_cronjobr   ~  s    (6CCr   rr   r   descriptionu  Manage scheduled cron jobs with a single compressed tool.

Use action='create' to schedule a new job from a prompt or one or more skills.
Use action='list' to inspect jobs.
Use action='update', 'pause', 'resume', 'remove', or 'run' to manage an existing job.

Jobs run in a fresh session with no current-chat context, so prompts must be self-contained.
If skill or skills are provided on create, the future cron run loads those skills in order, then follows the prompt as the task instruction.
On update, passing skills=[] clears attached skills.

If script is provided on create, the referenced Python script runs before each agent turn.
Its stdout is injected into the prompt as context. Use this for data collection and change
detection — the script handles gathering data, the agent analyzes and reports.
On update, pass script="" to clear an attached script.

NOTE: The agent's final response is auto-delivered to the target. Put the primary
user-facing content in the final response. Cron jobs run autonomously with no user
present — they cannot ask questions or request clarification.

Important safety rule: cron-run sessions should not recursively schedule more cron jobs.
parameterstypeobject
propertiesr   stringz8One of: create, list, update, pause, resume, remove, runrp   z+Required for update/pause/resume/remove/runr   zFor create: the full self-contained prompt. If skill or skills are also provided, this becomes the task instruction paired with those skills.rx   zCFor create/update: '30m', 'every 2h', '0 9 * * *', or ISO timestampzOptional human-friendly namer=   integerzTOptional repeat count. Omit for defaults (once for one-shot, forever for recurring).rz   a;  Delivery target: origin, local, telegram, discord, slack, whatsapp, signal, matrix, mattermost, homeassistant, dingtalk, feishu, wecom, email, sms, or platform:chat_id or platform:chat_id:thread_id for Telegram topics. Examples: 'origin', 'local', 'telegram', 'telegram:-1001234567890:17585', 'discord:#engineering'ru   z;Optional per-job model override used when the cron job runsrv   zJOptional per-job provider override used when resolving runtime credentialsrw   zEOptional per-job base URL override paired with provider/model routingr   booleanz'For list: include paused/completed jobsrF   zCOptional single skill name to load before executing the cron promptrG   arrayitemszOptional ordered list of skills to load before executing the cron prompt. On update, pass an empty array to clear attached skills.r   zOptional pause reasonrZ   a  Optional path to a Python script that runs before each cron job execution. Its stdout is injected into the prompt as context. Use for data collection and change detection. Relative paths resolve under ~/.hermes/scripts/. On update, pass empty string to clear.requiredc                $    V ^8  d   QhR\         /# r)   )rU   )r   s   "r   r   r     s      D r   c                     \        \        P                  ! R4      ;'       g5    \        P                  ! R4      ;'       g    \        P                  ! R4      4      # )z
Check if cronjob tools can be used.

Available in interactive CLI mode and gateway/messaging platforms.
The cron system is internal (JSON file-based scheduler ticked by the gateway),
so no external crontab executable is required.
HERMES_INTERACTIVEHERMES_GATEWAY_SESSIONHERMES_EXEC_ASK)rU   r3   r4    r   r   check_cronjob_requirementsr     sL     
		&' 	( 	(99-.	( 	(99&' r   c                     \         .# )z/Return tool definitions for cronjob management.)CRONJOB_SCHEMAr   r   r   get_cronjob_tool_definitionsr     s    r   )registryc           	      X   \        R/ R V P                  R R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  RR	4      bR
V P                  R
4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRV P                  R4      bRVP                  R4      b # )r   r   rp   r   rx   rr   r=   rz   r   FrF   rG   ru   rv   rw   r   rZ   r   r   )r   rC   )argskws   &,r   <lambda>r     s:   w  xx"% xx!  xx!  *%	 
 XXf  xx!  #  "4e<  hhw  xx!  hhw  *%  *%  xx!  xx!   y!! r   u   ⏰)rr   toolsetschemahandlercheck_fnemoji)
)zJignore\s+(?:\w+\s+)*(?:previous|all|above|prior)\s+(?:\w+\s+)*instructionsprompt_injection)zdo\s+not\s+tell\s+the\s+userdeception_hide)zsystem\s+prompt\s+overridesys_prompt_override)z<disregard\s+(your|all|any)\s+(instructions|rules|guidelines)disregard_rules)z?curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)
exfil_curl)z?wget\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)
exfil_wget)z0cat\s+[^\n]*(\.env|credentials|\.netrc|\.pgpass)read_secrets)authorized_keysssh_backdoor)z/etc/sudoers|visudosudoers_mod)zrm\s+-rf\s+/destructive_root_rm>
      ​   ‌   ‍   ‪   ‫   ‬   ‭   ‮   ⁠   ﻿)NN)NNNNNNFNNNNNNNN)NNNNNNN)FN)N).__doc__r   r3   r!   sysrb   r   typingr   r   r   r   pathinsertr   __file__parent	cron.jobsr   r	   r
   r   r   r   r   r   r   r    r   r'   r7   rD   rQ   rX   rm   r   r   r   r   r   r   r   r   tools.registryr   registerr   r   r   <module>r      sn    	 	 
  , , 3tH~,,334 5
 
 
$  
E"X] %P8cIT2VD
 I \( Y L    o d = 	u    ] \ k f 	H! d &(+   d
 6    eu>
~ 	XJCB-Yx $   	$ (
/r   