+
    jHàjvT  ã                  ó.  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
 ]P                  ! R4      tR R ltR R	 ltR
 R ltRtRtRtRtRtRtRtRtRt]P2                  ! R]P4                  ! ]4       R]P4                  ! ]4       24      t]P2                  ! R]P4                  ! ]4       R]P4                  ! ]4       24      tR R ltR R ltR R ltR R lt Rt!R/R  R! llt"R"R#R$R#R%R/R& R' llt#R( R) lt$R* R+ lt%^ R,I&H't( ^ R-I&H)t* ^ R.I&H+t, R# )0a¹  Cron job prompt assembly: context_from injection, skill loading, the assembled-prompt
injection scan, and the credential-exfil / config-block guards.

Split out of ``cron.scheduler``. Import names from this module directly (``cron.scheduler`` only
imports the few it calls itself). Origin-resident helpers and sibling split modules are reached
late-bound (``_sched`` / module refs at the bottom) so monkeypatching the defining module works.
)ÚannotationsN)Únow)ÚOptionalzcron.schedulerc               ó    € V ^8„  d   QhRRRR/# )é   Úscript_outputÚstrÚreturnÚbool© )Úformats   "Ú:/home/ubuntu/.hermes/hermes-agent/cron/scheduler_prompt.pyÚ__annotate__r      s   € ÷ Rñ R Cð R¨Dñ Ró    c                óž  € T ;'       g    RP                  4        Uu. uF  qP                  4       '       g   K  VNK  	  ppV'       g   R#  \        P                  ! VR,          P                  4       4      p\        T\        4      '       * ;'       g    TP                  RR4      RJ# u upi   \        P                  \
        3 d     R# i ; i)u'  Wake gate: False only if the last non-empty stdout line is JSON ``{"wakeAgent": false}``
(agent skipped entirely â€” no LLM run, no delivery); anything else wakes normally.

Any other output (non-JSON, missing flag, gate absent, or ``wakeAgent: true``) means wake the agent
normally. See #1232.
Ú TÚ	wakeAgentFéÿÿÿÿ)	Ú
splitlinesÚstripÚjsonÚloadsÚJSONDecodeErrorÚ
ValueErrorÚ
isinstanceÚdictÚget)r   ÚlineÚstripped_linesÚgates   &   r   Ú_parse_wake_gater       s©   € ð )6×(;Ð(;¸×'GÑ'GÔ'IÓZÑ'I˜tÏZÉZÏ\—d�dÑ'I€NÐZßÙðÜ�zŠz˜.¨Õ,×2Ñ2Ó4Ó5ˆô ˜$¤Ó%Ô%×QÐQ¨¯©°+¸tÓ)DÈEÐ)QÐQùò [øô
 × Ñ ¤*Ð-ô Úðús   �B(¹B(Á+B- Â-CÃCc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )r   Úpromptr   ÚheadingÚintroÚbodyr	   r   )r   s   "r   r   r   &   s7   € ÷ Dñ D 3ð D°ð D¸Sð DÈð DÐPSñ Dr   c                ó   € RV RV RV RV  2# )z:Prefix ``prompt`` with a fenced ``## heading`` data block.z## Ú
z

```
z
```

r   )r"   r#   r$   r%   s   &&&&r   Ú_prepend_context_blockr(   &   s!   € à��	˜˜E˜7 )¨D¨6°¸6¸(ÐCÐCr   c               ó    € V ^8„  d   QhRRRR/# )r   Újobr   r	   ú	list[str]r   )r   s   "r   r   r   +   s   € ÷ Gñ G˜$ð G 9ñ Gr   c                ó:  € V P                  R4      pVf    V P                  R4      pV'       d   V.M. pM\        V\        4      '       d   V.pV Uu. uF=  p\        V4      P                  4       '       g   K$  \        V4      P                  4       NK?  	  up# u upi )zVNormalized skill names from ``skills`` (list or str) or the legacy singular ``skill``.ÚskillsÚskill)r   r   r   r   )r*   r-   ÚlegacyÚnames   &   r   Ú_job_skill_namesr1   +   su   € à�W‰W�XÓ€FØ‚~Ø—‘˜Ó!ˆß#�&‘¨‰Ü	�FœC×	 Ò	 Ø�ˆÙ*0ÓF©& $´C¸³I·O±O×4EÔŒC�‹I�O‰OÖ©&ÑFÐFùÒFs   Á!BÁ8Bi@  zºThe following is this job's most recent non-silent output from a previous run. Use it for continuity: avoid repeating what was already reported, and continue where the last run left off.zgThe following is the most recent output from a preceding cron job. Use it as context for your analysis.z**Prompt Characters:** z**Response Characters:** z## Prompt

z## Response

z

r'   z(?m)^z(\d+)\nc               ó    € V ^8„  d   QhRRRR/# )r   Úarchiver   r	   ú
str | Noner   )r   s   "r   r   r   R   s   € ÷ #ñ #˜Sð # Zñ #r   c                óV  € \         P                  V 4      pVEe,   V P                  \        4      VP	                  4       \        \        4      ,
          8X  dð   VP	                  4       \        VP                  ^4      4      ,           \        \        4      ,           p\        P                  W4      pVe   WP	                  4       R MRpVeX   \        V4      \        VP                  ^4      4      \        \        4      ,           8w  g   VP                  \        4      '       g   R# VR\        \        4      )  P                  4       pM=RV 9  d   V P                  4       # V P                  R4      ^,          P                  4       pV'       d   \        P                   ! V4      '       d   R# V# )u•  The reusable answer of a stored run, using its length frame when available.

Framed runs (``_PROMPT_FRAME``/``_RESPONSE_FRAME`` stamps) validate the
response length before whitespace normalization, so quoted frames inside the
prompt or answer can never become boundaries and a truncated write is
rejected. Archives without the heading (script-mode runs) stay whole-document.
For legacy unframed archives the LAST ``## Response`` occurrence is the
writer's boundary â€” the assembled prompt half can itself carry the literal
heading (a skill documenting its response format, an injected previous answer
quoting it), so an early split would re-inject the prompt noise this
extraction exists to drop.
``None`` marks "no usable answer" â€” a blank or silent response (any form the
delivery lane itself suppresses) â€” so the caller falls through to an older
archive instead of injecting prompt noise the job already has.
Nr   z## Response)Ú_PROMPT_FRAME_REÚsearchÚfindÚ_PROMPT_HEADINGÚendÚlenÚintÚgroupÚ_PROMPT_SEPARATORÚ_RESPONSE_FRAME_REÚmatchÚ_RESPONSE_TERMINATORÚendswithr   Ú
rpartitionÚ_schedÚ_is_cron_silence_response)r3   Úprompt_frameÚresponse_startÚframeÚtailÚanswers   &     r   Ú_archive_answerrK   R   s:  € ô$ $×*Ñ*¨7Ó3€LØÓ Ø—‘œ_Ó-°×1AÑ1AÓ1CÄcÌ/ÓFZÕ1ZÔZØ%×)Ñ)Ó+¬c°,×2DÑ2DÀQÓ2GÓ.HÕHÌ3ÔO`ÓKaÕaˆÜ"×(Ñ(¨ÓAˆØ(-Ò(9ˆw—y‘y“{�|Ñ$¸rˆàŠMœS ›Y¬#¨e¯k©k¸!«nÓ*=ÄÔDXÓ@YÕ*YÔYØ—}‘}Ô%9×:Ò:ÙØÐ1œÔ0Ó1Ð1Ð2×8Ñ8Ó:‰Ø	˜gÔ	%Ø�}‰}‹Ðà×#Ñ# MÓ2°1Õ5×;Ñ;Ó=ˆß”V×5Ò5°f×=Ò=ÙØ€Mr   c               ó    € V ^8„  d   QhRRRR/# )r   Útextr   r	   r   )r   s   "r   r   r   x   s   € ÷ Sñ S #ð S¨#ñ Sr   c                óš   € \        V 4      \        8:  d   V # \        ^,          p\        V 4      ^V,          ,
          pV RV  RV RW) R  2# )zKClip oversized context head+tail; conclusions and summaries sit at the end.Nz

[... z chars omitted ...]

)r;   Ú_MAX_CONTEXT_CHARS)rM   ÚkeepÚomitteds   &  r   Ú_clip_to_context_budgetrR   x   sT   € ä
ˆ4ƒyÔ&Ô&ØˆÜ Õ"€DÜ�$‹i˜!˜d�(Õ"€GØ�5�Dˆkˆ]˜) G 9Ð,CÀDÈÈÀLÀ>ÐRÐRr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r*   r   r"   r   r	   ztuple[str, bool]r   )r   s   "r   r   r   �   s"   € ÷ =ñ =˜dð =¨Cð =Ð4Dñ =r   c           
     óÀ  € V P                  R4      pV'       g   VR3# ^ RIHp V! 4       p\        V\        4      '       d   V.pRpV EFZ  p\        V\        4      '       dH   VP                  4       P                  4       R8X  d%   \	        V P                  R4      ;'       g    R4      pW`P                  R4      8H  pV'       d;   \        ;QJ d    R V 4       F  '       d   K   RM	  RM! R V 4       4      '       gN   \        P                  R	W`P                  R4      V P                  R
4      \        P                  ! V 4      4       EK   \        WF,          P                  R4      R RR7      pRp	V Fá  p
V
P                  RR7      pVP                  R^4      ^ ,          P                  R^4      ^ ,          pVP!                  R4      ;'       dQ    \"        ;QJ d*    R VP%                  4        4       F  '       g   K   RM	  RM! R VP%                  4        4       4      pVP                  4       '       d	   V'       d   KÎ  \'        V4      pVf   Kß  Tp	 M	  V	'       g   EK  \)        V	4      p	V'       d   \+        VR\,        V	4      pM\+        VRV R2\.        V	4      pRpEK]  	  W3#   \0        \2        3 d#   p\        P                  RYo4        Rp?EK�  Rp?ii ; i)zWPrepend the latest output of each ``context_from`` job; returns ``(prompt, injected)``.Úcontext_fromF)Úget_cron_output_dirÚselfÚidr   c              3  ó*   "  € T F	  qR 9   x € K  	  R# 5i)Ú0123456789abcdefNr   )Ú.0Úcs   & r   Ú	<genexpr>Ú'_inject_context_from.<locals>.<genexpr>‘   s   é € Ð'WÉÀAÐ-?Ö(?Ëùs   ‚Tz@context_from: skipping invalid job_id %r for job_id=%r name=%r%sr0   z*.mdc                ó6   € V P                  4       P                  # )N)ÚstatÚst_mtime)Úfs   &r   Ú<lambda>Ú&_inject_context_from.<locals>.<lambda>š   s   € ÈÏÉË×IZÒIZr   )ÚkeyÚreversez	utf-8-sig)Úencodingz
---
z

## Promptz# Cron Job:c              3  óD   "  € T F  pVP                  R4      x € K  	  R# 5i)ú**Status:** no_changeN)ri   z**Status:** silentz&Script gate returned `wakeAgent=false`)Ú
startswith)r[   r   s   & r   r]   r^   £   s0   é € ð Kñ !4˜ð —O‘Oð %O÷ Pð Pã 3ùs   ‚ NzYour previous run's outputzOutput from job 'Ú'z2context_from: failed to read output for job %r: %s)r   Ú	cron.jobsrV   r   r   r   ÚlowerÚallÚloggerÚwarningÚ	_deliveryÚ_cron_job_origin_log_suffixÚsortedÚglobÚ	read_textÚsplitrj   Úanyr   rK   rR   r(   Ú_SELF_CONTEXT_INTROÚ_UPSTREAM_CONTEXT_INTROÚOSErrorÚPermissionError)r*   r"   rU   rV   Ú
output_dirÚinjectedÚsource_job_idÚis_selfÚoutput_filesÚlatest_outputÚoutput_fileÚ	candidateÚheaderÚsilent_auditrJ   Úes   &&              r   Ú_inject_context_fromr‡   �   s‚  € à—7‘7˜>Ó*€LßØ�uˆ}ÐÝ-Ù$Ó&€JÜ�,¤×$Ò$Ø$�~ˆØ€HÜ%ˆä�m¤S×)Ò)¨m×.AÑ.AÓ.C×.IÑ.IÓ.KÈvÔ.UÜ §¡¨£× 3Ð 3°Ó4ˆMØ§7¡7¨4£=Ñ0ˆç§C£CÑ'WÉÓ'W§C§C¢CÑ'WÉÓ'W×$WÒ$WÜ�N‰NØRØŸw™w t›}¨c¯g©g°f«oÜ×5Ò5°cÓ:ôò
 ð%	cÜ!ØÕ+×1Ñ1°&Ó9Ñ?ZØôˆLð ˆMÛ+�Ø'×1Ñ1¸;Ð1ÓG�	ð #Ÿ™¨°AÓ6°qÕ9×?Ñ?ÀÈqÓQÐRSÕT�Ø(×3Ñ3°MÓB÷  ð  ÇsÃsñ Kð !'× 1Ñ 1Ô 3óKÇsÇsÂsñ Kð !'× 1Ñ 1Ô 3óKó H�ð
 !—‘×(Ò(¯LÙÜ(¨Ó3�Ø’>ÙØ &�Ùñ!  ,÷" !ÚÜ3°MÓBˆMßÜ/ØÐ8Ô:MÈ}ó^‘ô 0ØÐ/°¨¸aÐ@ÔBYØ!ó�ð ‹Hñ_ &ðf ÐÐøô œÐ)ô 	cä�N‰NÐOÐQ^×bÓbûð	cús=   ÅBJ*ÇJ*ÇJ*Ç?8J*È8J*É  J*É$>J*Ê*KÊ;KËKc               ó$   € V ^8„  d   QhRRRRRR/# )r   r*   r   Úskill_namesr+   r	   r   )r   s   "r   r   r   Á   s&   € ÷ @ñ @ ð @°9ð @Àñ @r   c           
     ó  aaa€ ^ RI Hp ^ RIHp ^ RIHpHp ^ RIHpH	p ^ RI
Hp V P                  RV P                  R4      4      o\        V P                  R4      ;'       g    R4      ;'       g    R	p	. p
. oR
R	/R VVV3R lllpV EFf  oV! SP                  R4      4      pV'       dQ   V! VRV	R7      pV'       d3   V
'       d   V
P                  R4       V
P                  V^ ,          4       M	V! RS4       Ks   \         P"                  ! V! V! S4      4      4      pT! ST4      ;p'       d   T! RYÿR7       K³  TP                  R4      '       g)   T! RTP                  R4      ;'       g    RS R24       Kò   T! ST	R7       T
'       d   T
P                  R4       T
P/                  RS R2R\        TP                  R4      ;'       g    R4      P1                  4       .4       T! Yê4       EKi  	  S'       d8   V
P3                  ^ RR P5                  S4       R!R P5                  S4       R"24       V
#   \         P$                  \&        3 d    T! RS4        EKÔ  i ; i  \(         d    \*        P-                  RSRR7        ELi ; i)#zWLoad each named skill/bundle into prompt parts; unknown ones are skipped with a notice.)Ú
skill_view)Úbump_use)Úbuild_bundle_invocation_messageÚresolve_bundle_command_key)Ú_inject_skill_configÚambiguous_skill_label)Únormalize_skill_lookup_namer0   rX   r   NÚlabelc               ó$   € V ^8„  d   QhRRRRRR/# )r   Úmsgr   r’   r4   r	   ÚNoner   )r   s   "r   r   Ú,_load_cron_skill_parts.<locals>.__annotate__Í   s!   € ÷ ,ñ ,�3ð , jð ,¸Dñ ,r   c               ó~   <€ \         P                  ! R V ,           S.VO5!   SP                  T;'       g    S4       R# )zCron job '%s': N)ro   rp   Úappend)r”   r’   ÚargsÚ	job_labelÚ
skill_nameÚskippeds   &$*€€€r   Ú_skipÚ%_load_cron_skill_parts.<locals>._skipÍ   s0   ø€ Ü�ŠÐ(¨3Õ.°	ÐA¸DÔAØ�‰�u×*Ð* 
Ö+r   Ú/)Úuser_instructionÚtask_idz/bundle '%s' could not load any skills, skippingz*skill '%s' returned invalid JSON, skippingu   %s â€” skipping)r’   Úsuccessu    skill not found, skipping â€” %sÚerrorzFailed to load skill 'rk   )r¡   z-Cron job: failed to bump skill usage for '%s'T)Úexc_infoz&[IMPORTANT: The user has invoked the "zf" skill, indicating they want you to follow its instructions. The full skill content is loaded below.]Úcontentze[IMPORTANT: The following skill(s) were listed for this job but could not be found and were skipped: z, un   . Start your response with a brief notice so the user is aware, e.g.: 'âš ï¸� Skill(s) not found and skipped: z'])Útools.skills_toolr‹   Útools.skill_usagerŒ   Úagent.skill_bundlesr�   rŽ   Úagent.skill_commandsr�   r�   Úagent.skill_utilsr‘   r   r   Úlstripr˜   r   r   r   Ú	TypeErrorÚ	Exceptionro   ÚdebugÚextendr   ÚinsertÚjoin)r*   r‰   r‹   rŒ   r�   rŽ   r�   r�   r‘   r¡   Úpartsr�   Ú
bundle_keyÚbundle_payloadÚloadedÚ	ambiguousrš   r›   rœ   s   &&              @@@r   Ú_load_cron_skill_partsr·   Á   s^  ú€ å,Ý*ß_ßPÝ=Ø—‘˜ §¡¨£Ó.€IÜ�#—'‘'˜$“-×%Ð% 2Ó&×.Ð.¨$€GØ€EØ€Gð,°4÷ ,ô ,ô "ˆ
á/°
×0AÑ0AÀ#Ó0FÓGˆ
ßÙ<Ø¨R¸ôBˆNçßØ—L‘L Ô$Ø—‘˜^¨AÕ.Õ/áÐGÈÔTÙð	Ü—Z’Z¡
Ñ+FÀzÓ+RÓ SÓTˆFñ .¨j¸&ÓAÐAˆ9ÖAÙÐ# YÕ@ÙØ�z‰z˜)×$Ò$ÙØ2Ø—
‘
˜7Ó#×MÐMÐ)?À
¸|È1Ð'MôOñ ð	eÙ�Z¨Õ1÷ Ø�L‰L˜ÔØ�‰Ø4°Z°Lð  Agð  hØÜ�—
‘
˜9Ó%×+Ð+¨Ó,×2Ñ2Ó4ð6ô 	7ñ 	˜V×+ñO "÷R Ø�‰�Qð!Ø!%§¡¨7Ó!3Ð 4ð 57à7;·y±yÀÓ7IÐ6JÈ"ðNô	ð €LøôA ×$Ñ$¤iÐ0ô 	ÙÐ>À
ÔKÛð	ûô ô 	eÜ�L‰LÐHÈ*Ð_cˆL×dð	eús$   Ã>"H6Å=
I"È6$IÉIÉ"#J	ÊJ	uo  [IMPORTANT: You are running as a scheduled cron job. DELIVERY: Your final response will be automatically delivered to the user â€” do NOT use send_message or try to deliver the output yourself. Just produce your report/output as your final response and the system handles the rest. SILENT: If there is genuinely nothing new to report, respond with exactly "[SILENT]" (nothing else) to suppress delivery. [SILENT] is a literal ASCII control token â€” never translate or rephrase it, whatever language the rest of your answer uses. Never combine [SILENT] with content â€” either report your findings normally, or say [SILENT] and nothing more. FAILURE: If a delegated child fails and this cron run must be recorded as failed, put [CRON_FAILURE] on the first line by itself, then explain the child failure on following lines. RECURSION: This is a run of an EXISTING scheduled job â€” execute the task now. NEVER create or update a cron job because of recurring or future-schedule language in the task prompt below; treat phrasing like "each Monday" or "every day at 9" as context for this run, not as a request to schedule another job.]

c          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r   r*   r   Úprerun_scriptzOptional[tuple]Úextra_promptúOptional[str]Úruntime_data_promptr	   r   r   )r   s   "r   r   r     s=   € ÷ Qñ QØ	ðQØ-ðQØDQðQà&ðQð 	ñQr   c                óD  € \        V P                  R4      ;'       g    R4      pV'       d   V RV 2pTpRpV'       d
   V RV 2pRpV P                  R4      pV'       d–   Ve   TM^\        P                  ! T\        P
                  ! T \        V P                  R4      ;'       g    R4      4      V P                  R	4      R
7      w  r‰V'       d   V	'       g   R# V'       d   RMRw  r«\        WZW¹4      pRp\        W4      w  r\T;'       g    Tp^ RIH	p TP                  \        V P                  R4      ;'       g    R4      4      pV'       d	   V V 2pRp\        V,           p\        V 4      pV'       g   \        WPRVVR7      # \        W4      pRpV'       d!   ^ RIHp VP#                  R4       V! VV4      p\        RP%                  V4      V RR7      pV'       d?   \'        V4      \'        V4      8”  d&   VP)                  V4      '       d   ^ RIHp V! V4       V# )uÖ  Build the effective prompt for a cron job, optionally loading skills first.
``prerun_script``: cached ``(success, stdout)`` from a script the caller already ran (wake-gate
check) â€” skips re-execution. ``extra_prompt``: user-authored per-run ``## Run Context`` for this
fire only, never persisted to the job. ``runtime_data_prompt`` is operator-configured runtime
data (such as monitor output) and is scanned as injected data rather than user input.

When provided, the script is not re-executed and the cached result is used for prompt injection. When
omitted, the script (if any) runs inline as before. extra_prompt: Optional per-run context (from
``cronjob(action='run')``, 57331 â€” salvaged from #57342 by @liuhao1024).
r"   r   z

## Run Context
FTÚscriptNrX   Úinterpreter)Úworkdirr¿   )Únotepad)Ú
has_skillsÚhas_injected_dataÚuser_prompt)Úappend_user_instructionr'   )rÂ   )Úregister_stable_prefix)zScript OutputzZThe following data was collected by a pre-run script. Use it as context for your analysis.)zScript Errorz;The data-collection script failed. Report this to the user.)r   r   Ú_scriptÚ_run_job_scriptrD   Ú_resolve_job_workdirr(   r‡   ÚcronrÁ   Úrender_notepad_sectionÚ
_CRON_HINTr1   Ú_scan_assembled_cron_promptr·   r©   rÅ   r˜   r±   r;   rj   Úagent.prompt_cache_boundaryrÆ   )r*   r¹   rº   r¼   rÄ   r"   rÃ   Úscript_pathr¢   r   r#   r$   Ú_ctx_injectedÚcron_notepadÚnotepad_sectionr‰   r²   Ústable_prefixrÅ   Ú	assembledrÆ   s   &&&&                 r   Ú_build_job_promptrÕ     s  € ô �c—g‘g˜hÓ'×-Ð-¨2Ó.€KßØ$˜Ð%9¸,¸ÐHˆØ€Fð ÐßØ�8Ð/Ð0CÐ/DÐEˆØ Ðà—'‘'˜(Ó#€Kßà*Ò6‰MÜ×(Ò(Ø¤V×%@Ò%@ÀÄcÈ#Ï'É'ÐRVË-×J]ÐJ]Ð[]ÓF^Ó%_ØŸG™G MÓ2ô4ñ 	ˆ÷
 Ÿ=Ù÷ ñFð añ	 	ˆô (¨¸ÓNˆØ Ðä0°Ó=Ñ€FØ)×:Ð:¨]Ðõ -Ø"×9Ñ9¼#¸c¿g¹gÀd»m×>QÐ>QÈrÓ:RÓS€OßØ#Ð$ V HÐ-ˆØ Ðä˜&Õ €FÜ" 3Ó'€KßÜ*Ø EÐ=NØ#ô
ð 	
ô
 # 3Ó4€EØ€MßÝ@Ø�‰�RÔñ 0°°vÓ>ˆÜ+¨D¯I©I°eÓ,<¸cÈdÔS€IçÜ�	‹NœS Ó/Ô/Ø× Ñ  ×/Ò/õ 	GÙ˜}Ô-ØÐr   rÂ   FrÃ   rÄ   c               ó0   € V ^8„  d   Qh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   s   "r   r   r   o  s>   € ÷ ñ ØðØðØ.2ðØOSðàðð 	ñr   c               ór  € ^ RI Hp ^ RIHp V'       g	   V'       d,   V! V 4      w  rV'       g   V'       g   V'       d	   V! V4      pMV! V 4      pV'       d`   \        P                  RVP                  R4      ;'       g    VP                  R4      ;'       g    RV4       \        P                  ! V4      hV # )uÈ  Scan the assembled cron prompt for injection; raise ``CronPromptInjectionBlocked`` on a hit.
Needed because skill content is loaded from disk at runtime (never scanned at create/update)
and cron auto-approves tool calls. Tier by what the prompt CONTAINS: user prompt + hint only â†’
STRICT ``_scan_cron_prompt``; skills or injected data â†’ LOOSER ``_scan_cron_skill_assembled``
(command-shape patterns dropped, invisible unicode sanitized not blocked, so a false positive
cannot permanently kill a job); injected data without skills also scans ``user_prompt`` STRICT.

Since cron runs non-interactively (auto-approves tool calls), a malicious skill carrying an injection
payload bypassed every gate. See #3968.
)Ú_scan_cron_prompt)Ú_scan_cron_skill_assembleduC   Cron job '%s': assembled prompt blocked by injection scanner â€” %sr0   rX   z	<unknown>)	Útools.cronjob_toolsrØ   Útools.cronjob_prompt_scanrÙ   ro   rp   r   rD   ÚCronPromptInjectionBlocked)rÔ   r*   rÂ   rÃ   rÄ   rØ   rÙ   Ú
scan_errors   &&$$$   r   rÍ   rÍ   o  sŠ   € õ 6ÝDß×&á :¸9Ó EÑˆ	ß§*·Ù*¨;Ó7ˆJøá& yÓ1ˆ
ßÜ�‰ØQØ�G‰G�F‹O×;Ð;˜sŸw™w t›}×;Ð;°¸Zô	Iô ×/Ò/°
Ó;Ð;ØÐr   c               ó    € V ^8„  d   QhRRRR/# )r   r*   r   r	   r•   r   )r   s   "r   r   r   Ž  s   € ÷ Mñ M Tð M¨dñ Mr   c                ó~  €  ^ RI Hp V! V P                  R4      V P                  R4      4      pV'       d9   V P                  R4      p\        P                  R	WB4       \        R
V RV 24      hR#   \         dA   pT P                  R4      '       d   RTP                  P
                   RT R2MRp Rp?LˆRp?ii ; i)a7  Fail closed (RuntimeError) if the stored provider/base_url pair could exfiltrate a key.
Runtime backstop: jobs persisted before the create/update guard, or written directly to the
store, reach provider resolution unchecked. Fallback providers come from operator config and
are validated by the caller, not here.)Ú_validate_cron_base_urlÚproviderÚbase_urlz+could not validate provider/base_url pair (z: z=); refusing to run a job with an unverified base_url overrideNrX   ud   Job '%s': refusing to run â€” unsafe provider/base_url pair could exfiltrate a stored credential: %sz
Cron job 'z' blocked for safety: )	rÚ   rà   r   r­   Ú	__class__Ú__name__ro   r£   ÚRuntimeError)r*   rà   ÚerrÚexcÚjob_ids   &    r   Ú_guard_job_credential_exfilré   Ž  sÀ   € ð

+Ý?Ù% c§g¡g¨jÓ&9¸3¿7¹7À:Ó;NÓOˆ÷ Ø—‘˜“ˆÜ�‰ð1àô	ô ˜Z¨ xÐ/EÀcÀUÐKÓLÐLñ øô ô +ð �W‰W�Z× Ò ðØ—‘×&Ñ&Ð' r¨#¨ð /.ñ.ð '+õ	 	ûð+ús   ‚-A1 Á1B<Á<6B7Â7B<c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   rè   r   Újob_nameÚreasonr	   z$tuple[bool, str, str, Optional[str]]r   )r   s   "r   r   r   §  s,   € ÷ %ñ %Øð%Øð%Ø(+ð%Ø0Tñ%r   c           	     ó  € ^ RI Hp \        P                  RW4        V! V RV 24       \        4       P                  R4      pRV RV  RV R	V R
2	pRV RV 2pRWVV3#   \         d    \        P                  RT 4        LXi ; i)zšFail a run closed and pause the job: an unrunnable job left enabled re-fires every tick
forever; ``paused_at``/``paused_reason`` give an auditable record.)Ú	pause_jobzJob '%s': %szAuto-paused by scheduler: z-Job '%s': failed to auto-pause unrunnable jobz%Y-%m-%d %H:%M:%Sz# Cron Job: z

**Job ID:** z
**Run Time:** u7   
**Status:** blocked (unrunnable job) â€” auto-paused

r'   u   âš  Cron job 'z' was auto-paused

F)rl   rî   ro   r£   r­   Ú	exceptionÚ_hermes_nowÚstrftime)rè   rë   rì   rî   Únow_isoÚdocÚalerts   &&&    r   Ú_block_and_pause_jobrõ   §  sº   € õ $Ü
‡L�L� Ô0ðRÙ�&Ð6°v°hÐ?Ô@ô ‹m×$Ñ$Ð%8Ó9€Gà
�x�jð !Ø�hð Ø ˜	ð "Càˆ(�"ð		ð ð ˜X˜JÐ&;¸F¸8ÐD€EØ�#˜fÐ$Ð$øô ô RÜ×ÑÐHÈ&ÖQðRús   žA Á!BÂB)Ú	scheduler)Úscheduler_delivery)Úscheduler_script)NNN)-Ú__doc__Ú
__future__r   r   ÚloggingÚreÚhermes_timer   rð   Útypingr   Ú	getLoggerro   r    r(   r1   rO   rx   ry   Ú_PROMPT_FRAMEÚ_RESPONSE_FRAMEr9   Ú_RESPONSE_HEADINGr>   rA   ÚcompileÚescaper6   r?   rK   rR   r‡   r·   rÌ   rÕ   rÍ   ré   rõ   rÊ   rö   rD   r÷   rq   rø   rÇ   r   r   r   Ú<module>r     sI  ðñõ #ã Û Û 	Ý *Ý ð 
×	Ò	Ð+Ó	,€õRõ"Dõ
Gð Ð ðð ðð ð *€Ø-€Ø!€Ø%Ð ØÐ ØÐ Ø—:’:ØˆR�YŠY�}Ó%Ð& g¨b¯iªi¸Ó.HÐ-IÐJóLÐ à—Z’ZØˆR�YŠY�Ó'Ð(¨°·	²	Ð:KÓ0LÐ/MÐNóPÐ õ#õLSõ=õ@@ðHKð ÷.QðhØ5:ðØV[ðà!%÷õ>Mõ2%õ2 %Ý 0ß ,r   