§
    øžyjG2 ã            3       ó:  — d Z ddlZddl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mZmZmZ ddlmZ  ej        e¦  «        ZdZdZej                             d e ee¦  «        j        j        ¦  «        ¦  «         ddlmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( d{d
„Z)g d¢Z*g d¢Z+dZ,de,› �dfde,› �dfde,› �dfde,› �dfde,› d�dfgZ-ddl.m/Z0 dZ1dZ2de3d	e4fd„Z5dede3d	e4fd „Z6d!ed	efd"„Z7d!ed	efd#„Z8d!ed	efd$„Z9d!ed	e:ee;e         f         fd%„Z<d!ed	efd&„Z=d'ed	e:eef         fd(„Z>d	eeeef                  fd)„Z?d*eee
f         d+ee         d	ee         fd,„Z@d*eee
f         d	efd-„ZAd|d.ee         d/ee
         d	ee         fd0„ZBd1d2œd3ee
         d4e4d	ee         fd5„ZCd3e
d	ee         fd6„ZDd7ee
         d8ee
         d	ee         fd9„ZEd:ee         d	ee         fd;„ZFd*eee
f         d	eee
f         fd<„ZG	 d}d*eee
f         d=ee         d	eee
f         fd>„ZH	 d}d*eee
f         d=ee         d	eee
f         fd?„ZId~dAedBe3d	ee         fdC„ZJ	 	 d|d*eee
f         dDee         d=ee         d	eeee
f                  fdE„ZK	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddFedAee         d!ee         dGee         dHee         dIee3         dJee         dKe4d.ee         d/eee                  dLee         d7ee         d8ee         dMee         d:ee         dNeeeee         f                  dOeee                  dPee         dQee4         dRee4         dSee         dTee         dUedDee         d	ef2dV„ZLdWdXdYi dFdZd[d\œ“dAdZd]d\œ“d!dZd^d\œ“dGdZd_d\œ“dHdZd`d\œ“dIdadbd\œ“dJdZdcd\œ“d/dddedZidfdgœ“d:dZdh e¦   «         › di�d\œ“dSdZdj e¦   «         › dk�d\œ“dTdZdld\œ“dQdmd1dndoœ“dNdddedZidpdgœ“dOdddedZidqdgœ“dPdZdrd\œ“dRdmdsd\œ“dFgdtœduœZMd	e4fdv„ZNddwlOmPZPmQZQ  ePjR        dWdWeMdx„ eNdy¬z¦  «         dS )€zÇ
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ÚUnion)Údisplay_hermes_homeg      $@g     Õ@)ÚAmbiguousJobReferenceÚclaim_job_for_fireÚeffective_job_stateÚget_jobÚis_job_runnableÚ	list_jobsÚmark_job_runÚparse_scheduleÚ	pause_jobÚ
remove_jobÚresolve_job_refÚ
resume_jobÚ
update_jobÚreturnc                  óJ   — 	 ddl m}   | ¦   «          dS # t          $ r Y dS w xY w)u•   Tell the active cron scheduler provider the job set changed (no-op for
    the built-in). Best-effort â€” never lets a provider error break the tool.r   ©Ú_notify_provider_jobs_changedN)Úcron.schedulerr   Ú	Exceptionr   s    ú9/home/ragecks/.hermes/hermes-agent/tools/cronjob_tools.pyÚ"_notify_provider_jobs_changed_safer   9   sP   € ðØ@Ð@Ð@Ð@Ð@Ð@Ø%Ð%Ñ'Ô'Ð'Ð'Ð'øÝð ð ð Øˆˆðøøøs   ‚ ”
"¡")©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)zKcat\s+[^\n]*(\.env|credentials|\.netrc|\.pgpass|id_rsa|id_ed25519|id_ecdsa)Úread_secrets)Úauthorized_keysÚssh_backdoor)z/etc/sudoers|visudoÚsudoers_mod)zrm\s+-rf\s+/Údestructive_root_rm)r   r!   r#   r%   z:\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)\w*\}?z curl\s+[^\n]*https?://[^\s"\'`]*Úexfil_curl_urlz wget\s+[^\n]*https?://[^\s"\'`]*Úexfil_wget_urlzIcurl\s+[^\n]*(?:--data(?:-raw|-binary|-urlencode)?|-d|--form|-F)\s+[^\n]*Úexfil_curl_dataz(wget\s+[^\n]*--post-(?:data|file)=[^\n]*Úexfil_wget_postzHcurl\s+[^\n]*(?:-H|--header)\s+["\']Authorization:\s*(?:Bearer|token)\s+z["\']Úexfil_curl_auth_header)ÚINVISIBLE_CHARS))i ð iÿÿ )i &  i¿'  )i #  iÿ#  )iæñ iÿñ )éã   r2   iþ  Úcpc                 óD   ‡ — t          ˆ fd„t          D ¦   «         ¦  «        S )Nc              3   ó>   •K  — | ]\  }}|‰cxk    o|k    nc V — Œd S ©N© )Ú.0ÚloÚhir3   s      €r   ú	<genexpr>z_is_emoji_cp.<locals>.<genexpr>¡   s;   øè è € ÐGÐG¡& " bˆr�Rˆ~ˆ~Š~ˆ~˜2Š~ˆ~ˆ~ˆ~ÐGÐGÐGÐGÐGÐGó    )ÚanyÚ_EMOJI_NEIGHBOUR_CP_RANGES)r3   s   `r   Ú_is_emoji_cpr?       s'   ø€ ÝÐGÐGÐGÐGÕ,FÐGÑGÔGÑGÔGÐGr<   ÚtextÚidxc                 ó8  — |dz
  }|dk    rGt          | |         ¦  «        t          k    r)|dz  }|dk    rt          | |         ¦  «        t          k    °)|dz   }|t          | ¦  «        k     rTt          | |         ¦  «        t          k    r6|dz  }|t          | ¦  «        k     rt          | |         ¦  «        t          k    °6|dk    oV|t          | ¦  «        k     oCt          t          | |         ¦  «        ¦  «        o!t          t          | |         ¦  «        ¦  «        S )zGReturn True when the ZWJ at text[idx] appears inside an emoji sequence.é   r   )ÚordÚ_VARIATION_SELECTOR_CPÚlenr?   )r@   rA   ÚleftÚrights       r   Ú_zwj_has_emoji_neighbourrI   ¤   s  € à�‰7€DØ
�!Š)ˆ)�˜D œJ™œÕ+AÒAÐAØ�‰	ˆð �!Š)ˆ)�˜D œJ™œÕ+AÒAÐAà�!‰G€EØ
•#�d‘)”)Ò
Ð
¥ D¨¤KÑ 0Ô 0Õ4JÒ JÐ JØ�‰
ˆð •#�d‘)”)Ò
Ð
¥ D¨¤KÑ 0Ô 0Õ4JÒ JÐ Jð 	�Š	ð 	+�e�c $™iœiÒ'ð 	+Ý�˜T $œZ™œÑ)Ô)ð	+å�˜T %œ[Ñ)Ô)Ñ*Ô*ðr<   Úpromptc                 ó¾   — d| vr| S g }t          | ¦  «        D ]1\  }}|dk    rt          | |¦  «        rŒ|                     |¦  «         Œ2d                     |¦  «        S )Nõ   â€�Ú )Ú	enumeraterI   ÚappendÚjoin)rJ   ÚcleanedrA   Úchs       r   Ú_strip_legitimate_emoji_zwjrS   ³   st   € Ø�vÐÐØˆØ€GÝ˜VÑ$Ô$ð ð ‰ˆˆRØ�Š>ˆ>Õ6°v¸sÑCÔCˆ>ØØ�Š�rÑÔÐÐØ�7Š7�7ÑÔÐr<   c                 óX   — t          j        dt          › d�d| t           j        ¬¦  «        S )u³  Strip the GitHub `Authorization: token $GITHUB_TOKEN` auth-header
    pattern so it doesn't trip the broader curl-auth-header exfil rule.

    Allows the bundled GitHub skill fallback without opening a blanket
    exemption for arbitrary Authorization-header exfiltration.

    Uses ``re.sub`` so EVERY occurrence is scrubbed, not just the first â€” a
    cron job that loads 2+ GitHub skills (e.g. github-issues +
    github-pr-workflow + github-code-review) contains several such blocks,
    and the old ``re.search`` + single ``str.replace`` left the rest to trip
    the exfil_curl_auth_header detector on every run. The trailing
    ``[^\s;&|$`]*`` consumes only the URL path â€” never whitespace, command
    separators, or subshell openers â€” so a payload smuggled onto the same
    line (``;``, ``&&``, ``|``, ``$(...)``, backticks) survives the strip
    and is still scanned. The host must be exactly ``api.github.com``
    followed by ``/``, whitespace, quote, or end: lookalike authorities
    (``api.github.com.evil.com``, ``api.github.com@evil.com``) are not the
    trusted construct and fall through to the exfil detectors, while
    legitimately quoted bare-host URLs stay exempt.
    zBcurl\s+[^\n;&|$`]*(?:-H|--header)\s+["\']Authorization:\s*token\s+zJ["\']\s+["\']?https://api\.github\.com(?::\d+)?(?:/|\s|$|["\'])[^\s;&|$`]*z curl https://api.github.com/user)Úflags)ÚreÚsubÚ_CRON_SECRET_VAR_REÚ
IGNORECASE)rJ   s    r   Ú_strip_cron_safe_constructsrZ   ¾   sC   € õ* Œ6ð	QÕNað 	Qð 	Qð 	Qà*ØÝŒmðñ ô ð r<   c                 ól   — t          | ¦  «        }t          D ]}||v rdt          |¦  «        d›d�c S ŒdS )zŽReturn an error string if the prompt contains invisible-unicode
    injection markers (ZWJ inside legitimate emoji sequences is allowed).
    z-Blocked: prompt contains invisible unicode U+Ú04Xz (possible injection).rM   )rS   Ú_CRON_INVISIBLE_CHARSrD   )rJ   Úprompt_for_invisible_scanÚchars      r   Ú_check_invisible_unicoder`   Ü   sY   € õ !<¸FÑ CÔ CÐÝ%ð ið iˆØÐ,Ð,Ð,ØhÅ3ÀtÁ9Ä9ÐhÐhÐhÐhÐhÐhÐhð -àˆ2r<   c                 ó‚  — | s| g fS t          ¦   «         }g }t          | ¦  «        D ]v\  }}|t          v rS|dk    r&t          | |¦  «        r|                     |¦  «         Œ:|                     dt          |¦  «        d›�¦  «         Œa|                     |¦  «         Œwd                     |¦  «        t          |¦  «        fS )u>  Strip invisible-unicode characters from *prompt*, preserving the ZWJ
    that lives inside legitimate emoji sequences.

    Returns ``(cleaned_prompt, removed_codepoints)`` where ``removed_codepoints``
    is the sorted list of ``U+XXXX`` labels that were stripped (empty when the
    prompt was already clean). Used by the skills-attached cron path, where the
    skill body is already vetted at install time by ``skills_guard.py`` â€” a
    stray zero-width space in a code example should be sanitized, not turned
    into a hard block that permanently kills the job.
    rL   zU+r\   rM   )	ÚsetrN   r]   rI   rO   ÚaddrD   rP   Úsorted)rJ   ÚremovedrQ   rA   rR   s        r   Ú_strip_invisible_unicoderf   ç   sÓ   € ð ð Ø�rˆzÐõ ™œ€GØ€GÝ˜VÑ$Ô$ð ð ‰ˆˆRØÕ&Ð&Ð&Ø�XŠ~ˆ~Õ":¸6À3Ñ"GÔ"Gˆ~Ø—’˜rÑ"Ô"Ð"ØØ�KŠKÐ*�S ™WœWÐ*Ð*Ð*Ñ+Ô+Ð+ØØ�Š�rÑÔÐÐØ�7Š7�7ÑÔ�V G™_œ_Ð,Ð,r<   c                 ó  — t          | ¦  «        }t          |¦  «        }|r|S t          D ]-\  }}t          j        ||t          j        ¦  «        rd|› d�c S Œ.t          D ]-\  }}t          j        ||t          j        ¦  «        rd|› d�c S Œ.dS )u}  Scan the USER-SUPPLIED cron prompt for critical threats.

    Strict pattern set â€” used at job create/update time and as a runtime
    defense-in-depth for prompts authored before the scanner existed.
    The user prompt is small and directive; bare `cat .env` or `rm -rf /`
    there is a smoking gun, not prose. Returns an error string when
    blocked, else empty string.
    ú(Blocked: prompt matches threat pattern 'úD'. Cron prompts must not contain injection or exfiltration payloads.rM   )rZ   r`   Ú_CRON_THREAT_PATTERNSrV   ÚsearchrY   Ú_CRON_EXFIL_COMMAND_PATTERNS)rJ   Úprompt_to_scanÚinvisible_errÚpatternÚpids        r   Ú_scan_cron_promptrq     sñ   € õ 1°Ñ8Ô8€NÝ,¨^Ñ<Ô<€MØð ØÐÝ-ð Hð H‰ˆ�ÝŒ9�W˜n­b¬mÑ<Ô<ð 	Hð H¸cð  Hð  Hð  Hð  Hð  Hð  Hð	Hå4ð Hð H‰ˆ�ÝŒ9�W˜n­b¬mÑ<Ô<ð 	Hð H¸cð  Hð  Hð  Hð  Hð  Hð  Hð	Hàˆ2r<   Ú	assembledc                 ó6  — t          | ¦  «        \  }}|r<t                               dt          |¦  «        d                     |¦  «        ¦  «         t          |¦  «        }t          D ]/\  }}t          j        ||t          j	        ¦  «        r
|d|› d�fc S Œ0|dfS )uÇ  Scan an ASSEMBLED cron prompt that includes loaded skill content.

    Looser pattern set â€” only catches unambiguous prompt-injection
    directives. Drops command-shape patterns (cat .env, rm -rf /,
    authorized_keys, /etc/sudoers) because they false-positive on
    legitimate skill markdown that *describes* attack commands in
    security postmortems and runbooks.

    Invisible unicode is SANITIZED, not blocked. Skill bodies are
    user-curated and already scanned at install time by
    ``skills_guard.py``; a stray zero-width space in a code example
    (common in copy-pasted unicode docs) should not permanently kill the
    job. The offending codepoints are stripped and logged, the cleaned
    prompt is returned. The hard block remains for raw user prompts via
    ``_scan_cron_prompt`` â€” that path is the actual injection surface.

    Returns ``(cleaned_prompt, error)``; ``error`` is empty when the
    prompt passed (after sanitization).
    zaCron skill-assembled prompt: stripped %d invisible-unicode char(s) (%s) from vetted skill contentz, rh   ri   rM   )
rf   ÚloggerÚwarningrF   rP   rZ   Ú_CRON_SKILL_ASSEMBLED_PATTERNSrV   rk   rY   )rr   rQ   re   rm   ro   rp   s         r   Ú_scan_cron_skill_assembledrw     sÒ   € õ( 0°	Ñ:Ô:Ñ€GˆWØð 
Ý�Šð5å�‰LŒL˜$Ÿ)š) GÑ,Ô,ñ	
ô 	
ð 	
õ
 1°Ñ9Ô9€NÝ6ð Qð Q‰ˆ�ÝŒ9�W˜n­b¬mÑ<Ô<ð 	QØð  QÀsð  Qð  Qð  Qð  Qð  Qð  Qð  Qð	Qà�Bˆ;Ðr<   c                  óÚ   — ddl m}   | d¦  «        } | d¦  «        }|rL|rJ | d¦  «        pd }|rt                               d|||¦  «         || | d¦  «        pd | | d¦  «        pd d	œS d S )
Nr   ©Úget_session_envÚHERMES_SESSION_PLATFORMÚHERMES_SESSION_CHAT_IDÚHERMES_SESSION_THREAD_IDz+Cron origin captured thread_id=%s for %s:%sÚHERMES_SESSION_CHAT_NAMEÚHERMES_SESSION_USER_ID)ÚplatformÚchat_idÚ	chat_nameÚ	thread_idÚuser_id)Úgateway.session_contextrz   rt   Údebug)rz   Úorigin_platformÚorigin_chat_idrƒ   s       r   Ú_origin_from_envr‰   <  sÉ   € Ø7Ð7Ð7Ð7Ð7Ð7Ø%�oÐ&?Ñ@Ô@€OØ$�_Ð%=Ñ>Ô>€NØð 
˜>ð 
Ø#�OÐ$>Ñ?Ô?ÐGÀ4ˆ	Øð 	Ý�LŠLØ=Ø˜?¨Nñô ð ð
 (Ø%Ø(˜Ð)CÑDÔDÐLÈØ"ð '�Ð'?Ñ@Ô@ÐHÀDð
ð 
ð 	
ð ˆ4r<   ÚjobÚuser_deliverc                 óÞ   — |pd                      ¦   «                              ¦   «         dk    rdS 	 ddlm}  || ¦  «        rdS n(# t          $ r |                      d¦  «        rY dS Y nw xY w	 dS )uU  Return an informational notice when a created job won't deliver anywhere.

    TUI/CLI sessions cannot be captured as a cron ``origin`` (no
    ``HERMES_SESSION_PLATFORM``/``CHAT_ID`` is set for them), so a
    ``deliver="origin"`` request â€” or an omitted ``deliver`` that defaults to
    origin-or-local â€” produces a job that runs and saves output to
    ``last_output`` but is never delivered back into the session. This is by
    design (there is no live-delivery channel for local sessions), but silently
    dropping the user's "tell me when it runs" intent is the trap reported in
    #51568. Surface it at create time so the agent can relay it instead of
    promising a delivery that never happens.

    Returns ``None`` when the user explicitly asked for ``local`` (no surprise),
    or when the job resolves to a real delivery target.
    rM   ÚlocalNr   )Ú_resolve_delivery_targetsÚoriginuQ  This is a local-only cron job: its output is saved (view it with cronjob(action='list')) but will NOT be delivered back into this session â€” CLI/TUI sessions have no live-delivery channel. To be notified when it runs, recreate or update the job with deliver set to a gateway-connected platform, e.g. deliver='telegram' or deliver='all'.)ÚstripÚlowerr   rŽ   r   Úget)rŠ   r‹   rŽ   s      r   Ú_local_delivery_noticer“   V  sµ   € ð" 	Ð˜×!Ò!Ñ#Ô#×)Ò)Ñ+Ô+¨wÒ6Ð6ØˆtðØ<Ð<Ð<Ð<Ð<Ð<à$Ð$ SÑ)Ô)ð 	Ø�4ð	øåð ð ð à�7Š7�8ÑÔð 	Ø�4�4ð	ð 	ðøøøð
	Rðð s   °A ÁA)Á(A)c                 óð   — |                       d¦  «        pi                       d¦  «        }|                       d¦  «        pi                       dd¦  «        }|€dS |dk    r
|dk    rdndS |r|› d	|› �n|› d
�S )NÚrepeatÚtimesÚ	completedr   ÚforeverrC   Úoncez1/1ú/z times©r’   )rŠ   r–   r—   s      r   Ú_repeat_displayrœ   {  s˜   € Ø�WŠW�XÑÔÐ$ "×)Ò)¨'Ñ2Ô2€EØ—’˜Ñ"Ô"Ð( b×-Ò-¨k¸1Ñ=Ô=€IØ€}ØˆyØ�‚z€zØ" aš˜ˆvˆv¨UÐ2Ø%.ÐDˆiÐ!Ð!˜%Ð!Ð!Ð!°uÐ4DÐ4DÐ4DÐDr<   ÚskillÚskillsc                 óô   — |€| r| gng }n(t          |t          ¦  «        r|g}nt          |¦  «        }g }|D ]@}t          |pd¦  «                             ¦   «         }|r||vr|                     |¦  «         ŒA|S )NrM   )Ú
isinstanceÚstrÚlistr�   rO   )r�   rž   Ú	raw_itemsÚ
normalizedÚitemr@   s         r   Ú_canonical_skillsr¦   …  s›   € Ø€~Ø$Ð,�U�G�G¨"ˆ	ˆ	Ý	�F�CÑ	 Ô	 ð !Ø�Hˆ	ˆ	å˜‘L”Lˆ	à€JØð $ð $ˆÝ�4�:˜2‰Œ×$Ò$Ñ&Ô&ˆØð 	$�D 
Ð*Ð*Ø×Ò˜dÑ#Ô#Ð#øØÐr<   F©Ústrip_trailing_slashÚvaluer¨   c                ó‚   — | €d S t          | ¦  «                             ¦   «         }|r|                     d¦  «        }|pd S )Nrš   )r¡   r�   Úrstrip)r©   r¨   r@   s      r   Ú_normalize_optional_job_valuer¬   —  sF   € Ø€}ØˆtÝˆu‰:Œ:×ÒÑÔ€DØð  Ø�{Š{˜3ÑÔˆØˆ<�4Ðr<   c                 óÖ   — | €dS t          | t          t          f¦  «        r%d„ | D ¦   «         }|rd                     |¦  «        ndS t	          | ¦  «                             ¦   «         }|pdS )uÒ  Normalize a user-supplied ``deliver`` value to the canonical string form.

    The cron schema documents ``deliver`` as a string (``"local"``, ``"origin"``,
    ``"telegram"``, ``"telegram:chat_id[:thread_id]"``, or comma-separated combos).
    Some callers â€” MCP clients passing arrays, scripts building the payload as a
    list â€” supply ``["telegram"]``.  ``create_job``/``update_job`` store it as-is,
    and the scheduler's ``str(deliver).split(",")`` then serializes the list to
    the literal ``"['telegram']"`` which is not a known platform.  Flatten lists
    / tuples at the API boundary so storage is always a string.  Returns ``None``
    for ``None``/empty so callers can treat it as "not supplied".
    Nc                 ó’   — g | ]D}t          |¦  «                             ¦   «         ¯#t          |¦  «                             ¦   «         ‘ŒES r7   ©r¡   r�   )r8   Úps     r   ú
<listcomp>z,_normalize_deliver_param.<locals>.<listcomp>¯  s9   € ÐAÐAÐA Aµ#°a±&´&·,²,±.´.ÐA•�Q‘”—’‘”ÐAÐAÐAr<   Ú,)r    r¢   ÚtuplerP   r¡   r�   )r©   Úpartsr@   s      r   Ú_normalize_deliver_paramrµ      sq   € ð €}ØˆtÝ�%�$¥˜Ñ'Ô'ð 2ØAÐA¨ÐAÑAÔAˆØ"'Ð1ˆs�xŠx˜‰Œˆ¨TÐ1Ýˆu‰:Œ:×ÒÑÔ€DØˆ<�4Ðr<   ÚproviderÚbase_urlc                 óÆ  — t          |d¬¦  «        }|sdS t          | ¦  «        }|s	 dS 	 ddlm}m}m} ddlm} ddlm}m	}	 n# t          $ r	 d	|›d
�cY S w xY w|                     ¦   «         dk    rdS  ||¦  «        rb	  ||¦  «        }
n# t          $ r d}
Y nw xY w|
r! |	|
pi                      dd¦  «        ¦  «        nd}|r |||¦  «        rdS d|›d|›d|pd› d�S 	  ||¦  «        }n# t          $ r |}Y nw xY wt          |t          ¦  «        r|                     |¦  «        nd} |	|rt          |dd¦  «        nd¦  «        }|r |||¦  «        rdS d|›d|›d�S )a‹  Reject pairing a named provider's stored credential with an off-host base_url.

    The cron tool is model-callable, so a prompt-injected job could set a real
    provider plus an attacker ``base_url``; on fire the scheduler resolves that
    provider's stored API key and sends it to the URL, exfiltrating the
    credential (CWE-200/CWE-522). Allow a ``base_url`` override only when it
    cannot leak a stored secret: no override at all, a configured custom/byok
    provider that carries its own endpoint+key, or an override whose host
    matches the named provider's own endpoint.

    Returns an error string if blocked, else None (valid).
    Tr§   Nzwbase_url override requires an explicit provider. Set provider to a configured custom provider to use a custom endpoint.r   )Úhas_named_custom_providerÚresolve_requested_providerÚ_get_named_custom_provider)ÚPROVIDER_REGISTRY)Úbase_url_host_matchesÚbase_url_hostnamez2Unable to validate base_url override for provider z
; refused.Úcustomr·   rM   z	base_url z is not allowed for provider z_. A named custom provider's stored credential may only be sent to its own configured endpoint (Úunknownz).Úinference_base_urlz˜. A named provider's stored credential may only be sent to its own endpoint; use a configured custom provider (provider="custom") for a custom base_url.)r¬   Úhermes_cli.runtime_providerr¹   rº   r»   Úhermes_cli.authr¼   Úutilsr½   r¾   r   r‘   r’   r    r¡   Úgetattr)r¶   r·   ÚbuÚprovr¹   rº   r»   r¼   r½   r¾   r3   Úcfg_hostÚresolvedÚpconfigÚ
known_hosts                  r   Ú_validate_cron_base_urlrÌ   µ  s´  € õ 
' xÀdÐ	KÑ	KÔ	K€BØð ØˆtÝ(¨Ñ2Ô2€DØð 
ð
Cð	
ð 	
ð
Wð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð
 	6Ð5Ð5Ð5Ð5Ð5ØBÐBÐBÐBÐBÐBÐBÐBÐBøÝð Wð Wð WàVÀDÐVÐVÐVÐVÐVÐVðWøøøð ‡z‚z�|„|�xÒÐð ˆtØ Ð  Ñ&Ô&ð 
ð
	Ø+Ð+¨DÑ1Ô1ˆBˆBøÝð 	ð 	ð 	ØˆBˆBˆBð	øøøàHJÐRÐ$Ð$ b h¨B§^¢^°JÀÑ%CÔ%CÑDÔDÐDÐPRˆØð 	Ð-Ð-¨b°(Ñ;Ô;ð 	Ø�4ð>˜ð >ð >¸4ð >ð >à$,Ð$9°	ð>ð >ð >ð	
ð
Ø-Ð-¨dÑ3Ô3ˆˆøÝð ð ð Øˆˆˆðøøøå1;¸HÅcÑ1JÔ1JÐTÐ×#Ò# HÑ-Ô-Ð-ÐPT€GØ"Ð"ÐQXÐ#`¥7¨7Ð4HÈ"Ñ#MÔ#MÐ#MÐ^`ÑaÔa€JØð Ð+Ð+¨B°
Ñ;Ô;ð Øˆtð	W�Bð 	Wð 	W°tð 	Wð 	Wð 	Wðs5   «A ÁAÁAÂ B ÂBÂBÃ"C. Ã.C=Ã<C=Úscriptc                 ó^  — | r|                       ¦   «         sdS ddlm} |                       ¦   «         }|                     d¦  «        st	          |¦  «        dk    r|d         dk    rd|›d	�S dd
lm}  |¦   «         dz  }|                     dd¬¦  «          |||z  |¦  «        }|rd|›�S dS )a3  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)rš   Ú~é   rC   ú: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.)Úvalidate_within_dirÚscriptsT)ÚparentsÚexist_okz9Script path escapes the scripts directory via traversal: )r�   Úhermes_constantsrÏ   Ú
startswithrF   Útools.path_securityrÓ   Úmkdir)rÍ   rÏ   ÚrawrÓ   Úscripts_dirÚcontainment_errors         r   Ú_validate_cron_script_pathrÞ     s  € ð ð ˜Ÿš™œð Øˆtà0Ð0Ð0Ð0Ð0Ð0à
�,Š,‰.Œ.€Cð ‡~‚~�jÑ!Ô!ð 
¥c¨#¡h¤h°!¢m m¸¸A¼À#º¸ðNØ36ðNð Nð Nð	
ð 8Ð7Ð7Ð7Ð7Ð7à!�/Ñ#Ô# iÑ/€KØ×Ò˜d¨TÐÑ2Ô2Ð2Ø+Ð+¨K¸#Ñ,=¸{ÑKÔKÐØð 
àOÈÐOÐOð	
ð ˆ4r<   c                 óú  — t          |                      d¦  «        pd¦  «        }t          |                      d¦  «        |                      d¦  «        ¦  «        }t          |                      d¦  «        pd¦  «        }t          |                      d¦  «        p|d d…         p|r|d	         ndp|pd
¦  «        }i d|“d|“d|r|d	         nd “d|“dt          |¦  «        dk    r|d d…         dz   n|“d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        pd“dt	          | ¦  «        “d|                      dd¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      dd¦  «        “dt          | ¦  «        “|                      d¦  «        |                      d ¦  «        d!œ¥}|                      d"¦  «        r| d"         |d"<   |                      d#¦  «        r| d#         |d#<   |                      d$¦  «        r| d$         |d$<   |                      d%¦  «        r| d%         |d%<   |                      d&¦  «        rd|d&<   |                      d'¦  «        r| d'         |d'<   |                      d(¦  «        r| d(         |d(<   |S ))NrJ   rM   r�   rž   ÚidrÀ   Únameé2   r   zcron jobÚjob_idÚprompt_previewéd   z...Úmodelr¶   r·   ÚscheduleÚschedule_displayú?r•   Údeliverr�   Únext_run_atÚlast_run_atÚlast_statusÚlast_delivery_errorÚenabledTÚstateÚ	paused_atÚpaused_reason)rñ   rò   rÍ   Úmonitor_scriptÚmonitor_urlÚmonitor_stateÚno_agentÚenabled_toolsetsÚworkdir)r¡   r’   r¦   rF   rœ   r   )rŠ   rJ   rž   rã   rá   Úresults         r   Ú_format_jobrú   ,  sa  € Ý�—’˜Ñ"Ô"Ð( bÑ)Ô)€FÝ˜sŸwšw wÑ/Ô/°·²¸Ñ1BÔ1BÑCÔC€FÝ�—’˜‘”Ð+ )Ñ,Ô,€FÝˆs�wŠw�v‰ŒÐf &¨¨"¨¤+Ðf¸vÐ2M°&¸´)°)È2ÐfÐRXÐfÐ\fÑgÔg€DðØ�&ðà�ðð 	˜fÐ.�˜”�¨$ðð 	�&ð	ð
 	µ#°f±+´+ÀÒ2CÐ2C˜&  # œ,¨Ñ.Ð.Èðð 	�—’˜Ñ!Ô!ðð 	�C—G’G˜JÑ'Ô'ðð 	�C—G’G˜JÑ'Ô'ðð 	�C—G’GÐ.Ñ/Ô/Ð6°3ðð 	•/ #Ñ&Ô&ðð 	�3—7’7˜9 gÑ.Ô.ðð 	�s—w’w˜}Ñ-Ô-ðð 	�s—w’w˜}Ñ-Ô-ðð 	�s—w’w˜}Ñ-Ô-ðð 	˜sŸwšwÐ'<Ñ=Ô=ðð  	�3—7’7˜9 dÑ+Ô+ð!ð$ 	Õ$ SÑ)Ô)ð%ð& —W’W˜[Ñ)Ô)ØŸš Ñ1Ô1ð)ð ð €Fð, ‡w‚wˆxÑÔð )Ø˜xœ=ˆˆxÑØ
‡w‚wÐÑ Ô ð 9Ø#&Ð'7Ô#8ˆÐÑ Ø
‡w‚wˆ}ÑÔð 3Ø # MÔ 2ˆˆ}ÑØ
‡w‚wˆÑÔð 7Ø"% oÔ"6ˆˆÑØ
‡w‚wˆzÑÔð "Ø!ˆˆzÑØ
‡w‚wÐ!Ñ"Ô"ð =Ø%(Ð);Ô%<ˆÐ!Ñ"Ø
‡w‚wˆyÑÔð +Ø 	œNˆˆyÑØ€Mr<   Úextra_promptc                 óž  — | d         }	 t          |¦  «        s.t          |¦  «        }|€d}nt          |¦  «        sd}nd}dd|dœS nv# t          $ ri}t                               d||¦  «         	 t          |dt          |¦  «        ¦  «         n# t          $ r Y nw xY wd	dt          |¦  «        dœcY d}~S d}~ww xY wt          | |¬
¦  «        S )u  Execute a cron job immediately, outside the scheduler tick.

    Atomically claims the job first via ``claim_job_for_fire`` â€” the same
    at-most-once CAS the scheduler/external-provider fire path uses â€” so a
    concurrently-running gateway ticker cannot also fire it (the claim both
    blocks a duplicate fire and advances ``next_run_at`` for recurring jobs).
    If the claim is lost (another fire is in flight), this is a no-op.

    The actual firing is delegated to ``run_one_job`` â€” the single shared
    executeâ†’saveâ†’deliverâ†’mark body the ticker and external providers use â€” so
    failure delivery, ``[SILENT]`` handling, and live-adapter delivery stay
    identical across paths and can't drift.

    Returns {"claimed": bool, "success": bool, "error": str|None}.
    rà   Nú%Job no longer exists; nothing to run.ú1Job is paused/disabled; resume it before running.ú;Job is already being fired by the scheduler; not run again.F©ÚclaimedÚsuccessÚerrorz1Failed to claim cron job %s for immediate run: %sT©rû   )	r   r   r   r   rt   r  r   r¡   Ú_run_claimed_job)rŠ   rû   rã   Ú	refreshedÚreasonÚes         r   Ú_execute_job_nowr	  X  s(  € ð$ �ŒY€FðDå! &Ñ)Ô)ð 	Iõ
   ™œˆIØÐ Ø@��Ý$ YÑ/Ô/ð WØL��àV�Ø$°ÀÐHÐHÐHð	Iøõ ð Dð Dð DÝ�ŠÐHÈ&ÐRSÑTÔTÐTð	Ý˜ ­¨A©¬Ñ/Ô/Ð/Ð/øÝð 	ð 	ð 	ØˆDð	øøøà¨E½CÀ¹F¼FÐCÐCÐCÐCÐCÐCÐCÐCøøøøðDøøøõ ˜C¨lÐ;Ñ;Ô;Ð;sA   Š<A Á
B;ÁB6Á/BÂB6Â
BÂB6ÂBÂB6Â0B;Â6B;c                 ó€  ‡‡‡— | d         }d}	 ddl m}m}m}  ||¦  «        sddddœS d}	 ddlm}  |¦   «         Šn# t          $ r d	ŠY nw xY wt          j        ¦   «         Šd	}‰�Wt          |  
                    d
¦  «        p|¦  «        Šdˆˆˆfd„}	t          j        |	dd¬¦  «        }|                     ¦   «          t          j         
                    d¦  «        }
t          |
dd	¦  «        }t!          |¦  «        r
 |¦   «         nd	}|�t          |dd	¦  «        nd	}|�t          |dd	¦  «        nd	}	 	  || |||¬¦  «        }‰                     ¦   «          |�|                     t&          dz   ¬¦  «         n:# ‰                     ¦   «          |�|                     t&          dz   ¬¦  «         w w xY wd} ||¦  «         n# d} ||¦  «         w xY wt)          |¦  «        pi }| 
                    d¦  «        dk    }dt+          |o|¦  «        | 
                    d¦  «        dœS # t          $ rŽ}t,                               d||¦  «         |r#	 ddl m}  ||¦  «         n# t          $ r Y nw xY w	 t1          |dt          |¦  «        ¦  «         n# t          $ r Y nw xY wddt          |¦  «        dœcY d	}~S d	}~ww xY w)už  Fire an already-claimed job through the shared ``run_one_job`` body.

    Split out of ``_execute_job_now`` so the background dispatch path
    (``_try_dispatch_background_run``) can take the claim synchronously â€” so
    the tool response can report "paused"/"already firing" immediately â€” and
    hand the actual run to a daemon worker.

    Returns {"claimed": True, "success": bool, "error": str|None}.
    rà   Fr   )Úrelease_running_jobÚrun_one_jobÚtry_register_running_jobTúcJob is already running (a scheduler tick or another manual run is executing it); not started again.r   )Úget_activity_callbackNrá   r   c                  óz  •— t          j        ¦   «         } ‰                     t          ¦  «        sŒt          j        ¦   «         | z
  }|t          k    rt
                               d‰|¦  «         d S 	  ‰d‰› dt          |¦  «        › d�¦  «         n# t          $ r Y Œ†w xY w‰                     t          ¦  «        ¯Šd S d S )Nuu   cronjob run heartbeat ceiling reached for job '%s' (%.0fs) â€” stopping heartbeat; gateway watchdog regains authorityzcronjob: running job 'ú' (z
s elapsed))	ÚtimeÚ	monotonicÚwaitÚ_CRON_RUN_HEARTBEAT_INTERVALÚ_CRON_RUN_HEARTBEAT_CEILINGrt   ru   Úintr   )ÚstartedÚelapsedÚ_heartbeat_stopÚactivity_cbÚjob_names     €€€r   Ú_heartbeat_loopz)_run_claimed_job.<locals>._heartbeat_loopÉ  sû   ø€ Ýœ.Ñ*Ô*�Ø)×.Ò.Õ/KÑLÔLð !Ý"œnÑ.Ô.°Ñ8�GØÕ!<Ò<Ð<õ Ÿšð9ð % gñ	ô ð ð ˜ð!Ø#˜ØZ°XÐZÐZÅ#ÀgÁ,Ä,ÐZÐZÐZñô ð ð øõ %ð !ð !ð !ð !˜ð	!øøøð! *×.Ò.Õ/KÑLÔLð !ð !ð !ð !ð !s   Á/B Â
BÂBzcronjob-run-heartbeat)ÚtargetÚdaemonrá   zgateway.runÚ_gateway_runner_refÚadaptersÚ_gateway_loop)r!  Úlooprû   rC   )Útimeoutrí   ÚokÚ
last_errorz-Failed to execute cron job %s immediately: %s)r  ©r   N)r   r  r  r  Útools.environments.baser  r   Ú	threadingÚEventr¡   r’   ÚThreadÚstartÚsysÚmodulesrÅ   Úcallablerb   rP   r  r   Úboolrt   r  r   )rŠ   rû   rã   Ú_registeredr  r  r  r  Ú_heartbeat_threadr  Úgateway_moduleÚ
runner_refÚrunnerr!  Úgateway_loopÚ	processedr  r%  r  Ú_releaser  r  r  s                       @@@r   r  r  …  s  øøø€ ð �ŒY€FØ€KðIDð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð (Ð'¨Ñ/Ô/ð 	àØ ðFð	ð ð ð ˆð	ØEÐEÐEÐEÐEÐEð
 0Ð/Ñ1Ô1ˆKˆKøÝð 	ð 	ð 	ØˆKˆKˆKð	øøøõ $œ/Ñ+Ô+ˆØ ÐàÐ"Ý˜3Ÿ7š7 6™?œ?Ð4¨fÑ5Ô5ˆHð!ð !ð !ð !ð !ð !ð !ð !õ0 !*Ô 0Ø&ØØ,ð!ñ !ô !Ðð
 ×#Ò#Ñ%Ô%Ð%õ œŸš¨Ñ7Ô7ˆÝ˜^Ð-BÀDÑIÔIˆ
Ý!)¨*Ñ!5Ô!5Ð?��‘”�¸4ˆØ8>Ð8J•7˜6 :¨tÑ4Ô4Ð4ÐPTˆØAGÐAS•w˜v ¸Ñ=Ô=Ð=ÐY]ˆð	(ðUØ'˜KØ (°Ø!-ðñ ô �	ð
  ×#Ò#Ñ%Ô%Ð%Ø$Ð0Ø%×*Ò*Õ3OÐRSÑ3SÐ*ÑTÔTÐTøøð  ×#Ò#Ñ%Ô%Ð%Ø$Ð0Ø%×*Ò*Õ3OÐRSÑ3SÐ*ÑTÔTÐTÐTð 1øøøð  ˆKØÐ Ñ'Ô'Ð'Ð'øð  ˆKØÐ Ñ'Ô'Ð'Ð'øøøÝ˜F‘O”OÐ) rˆ	Ø�]Š]˜=Ñ)Ô)¨TÒ1ˆàÝ˜IÐ,¨"Ñ-Ô-Ø—]’] <Ñ0Ô0ð
ð 
ð 	
øõ ð Dð Dð DÝ�ŠÐDÀfÈaÑPÔPÐPØð 
	ð
ØJÐJÐJÐJÐJÐJà�˜Ñ Ô Ð Ð øÝð ð ð Ø�ðøøøð	Ý˜ ­¨A©¬Ñ/Ô/Ð/Ð/øÝð 	ð 	ð 	ØˆDð	øøøà¨E½CÀ¹F¼FÐCÐCÐCÐCÐCÐCÐCÐCøøøøð#Døøøs¶   �H% ªH% ­> ½H% ¾AÁ
H% ÁAÁC&H% Ä5E9 Å5G Å97F0Æ0G Æ3H% ÇGÇAH% È%
J=È/J8ÉI ÉJ8É 
I-É*J8É,I-É-J8É1JÊJ8Ê
JÊJ8ÊJÊJ8Ê2J=Ê8J=éÐ  rã   Ú	max_charsc                 óV  — 	 ddl m}  |¦   «         | z  }t          |                     d¦  «        ¦  «        }|sdS |d                              dd¬¦  «                             ¦   «         }|sdS t          |¦  «        |k    r|d|…         d	|d         › d
�z   }|S # t          $ r Y dS w xY w)a  Best-effort excerpt of the job's most recent saved output file.

    Included in the background-run completion block so the parent agent sees
    what the job actually produced without having to dig through
    ``~/.hermes/cron/output/``. Never raises.
    r   )Úget_cron_output_dirz*.mdNéÿÿÿÿzutf-8Úreplace)ÚencodingÚerrorsu   
â€¦ (truncated; full output: ú))Ú	cron.jobsr<  rd   ÚglobÚ	read_textr�   rF   r   )rã   r:  r<  Úout_dirÚfilesr@   s         r   Ú_latest_job_output_excerptrG    sâ   € ðØ1Ð1Ð1Ð1Ð1Ð1à%Ð%Ñ'Ô'¨&Ñ0ˆÝ�w—|’| FÑ+Ô+Ñ,Ô,ˆØð 	Ø�4Ø�RŒy×"Ò"¨G¸IÐ"ÑFÔF×LÒLÑNÔNˆØð 	Ø�4Ýˆt‰9Œ9�yÒ Ð Ø˜
˜˜
Ô#Ð&TÈÈbÌ	Ð&TÐ&TÐ&TÑTˆDØˆøÝð ð ð Øˆtˆtðøøøs   ‚7B »1B Á.+B Â
B(Â'B(Ú
session_idc                 óN  ‡ ‡‡‡‡‡— 	 ddl m}  |¦   «         sdS n# t          $ r Y nw xY w‰ d         Št          ‰                      d¦  «        p‰¦  «        Š	 ddlm}  |d¬¦  «        }n# t          $ r d}Y nw xY w|s|rt          |¦  «        }|sdS 	 	 dd	lm} ‰ |¦   «         v rd
d
ddœS n# t          $ r Y nw xY wt          ‰¦  «        s.t          ‰¦  «        }|€d}nt          |¦  «        sd}nd}d
d
|dœS nw# t          $ rj}	t                               d‰|	¦  «         	 t          ‰d
t          |	¦  «        ¦  «         n# t          $ r Y nw xY wdd
d
t          |	¦  «        dœcY d}	~	S d}	~	ww xY wd}
	 ddl m}  |dd¦  «        pd}
n# t          $ r Y nw xY w	 ddlm}m}  |¦   «         }nK# t          $ r>}	t                               d|	‰¦  «         t)          ‰ ‰¬¦  «        }d
|d<   |cY d}	~	S d}	~	ww xY w	 ddlm}  |¦   «         }n# t          $ r d}Y nw xY wt/          j        ¦   «         Š‰                      dd¦  «        Šdt0          t          t2          f         fˆˆˆ ˆˆˆfd„} |d‰› d ‰› d!�d"dd#‰                      d$¦  «        ||rt          |¦  «        nd||
||¬%¦  «        }|                     d&¦  «        dk    rdd|                     d'¦  «        d(œS t                               d)|                     d*d+¦  «        ‰¦  «         t)          ‰ ‰¬¦  «        }d
|d<   |S ),uh  Claim ``job`` now, then fire it on the async-delegation daemon executor.

    A manual ``cronjob(action='run')`` used to execute the job synchronously
    on the calling agent's tool thread. A cron job is a full agent run that
    routinely takes minutes-to-hours, so the parent turn sat inside ONE tool
    call the whole time: uninterruptible (the interrupt flag is only checked
    between loop iterations) and serial (a batch of runs executed one by one).

    This dispatches the run like ``delegate_task``'s background mode: the tool
    returns immediately with a handle, the run executes on the shared async
    daemon executor, and a ``type="async_delegation"`` completion event
    re-enters the conversation as a fresh turn when the job finishes â€” riding
    the existing completion-queue rail (CLI drain + gateway watcher), which
    keeps message-role alternation legal and the prompt cache intact.

    The at-most-once claim is taken SYNCHRONOUSLY before dispatch so
    unrunnable jobs (paused / missing / already firing) report in the tool
    response immediately instead of as a delayed completion event.

    Returns
    -------
    None
        Background delivery unavailable on this session runtime (one-shot
        ``hermes -z``, stateless HTTP, Kanban worker, nested cron run).
        Caller falls back to the synchronous path unchanged.
    dict
        ``{"claimed": False, "success": False, "error": ...}`` â€” claim lost;
        same shape as ``_execute_job_now`` so the caller's existing response
        formatting applies.
        ``{"claimed": True, "dispatched": True, "delegation_id": ...}`` â€”
        run is executing in the background.
        ``{"claimed": True, "dispatched": False, "success": ..., "error": ...}``
        â€” dispatch pool was at capacity; the run executed inline (the claim
        was already taken and must not be stranded).
    r   )Úasync_delivery_supportedNrà   rá   )Úget_current_session_keyrM   )Údefault)Úget_running_job_idsFr  r   rý   rþ   rÿ   z2Failed to claim cron job %s for background run: %sT)r  Ú
dispatchedr  r  ry   ÚHERMES_UI_SESSION_ID)Ú_current_origin_session_idÚdispatch_async_delegationzQcronjob run: async delegation registry unavailable (%s); running job '%s' inline.r  rN  )Ú_get_max_async_childrené   rê   r�   r   c                  ó¾  •— t          ‰‰¬¦  «        } t          t          j        ¦   «         ‰
z
  d¦  «        }t          ‰¦  «        pi }d‰	› d‰› d�d|                      d¦  «        rdnd	› �|                      d
¦  «        rd|                      d
¦  «        › �ndz   d‰› �‰dk    rdndz   g}|                     d¦  «        r|                     d|d         › �¦  «         t          ‰¦  «        }|r*|                     d¦  «         |                     |¦  «         |                      d¦  «        rdnd
d                     |¦  «        |                      d
¦  «        d|dœS )Nr  rÑ   ú
Cron job 'r  z) finished its manual run.zResult: r  r%  ÚFAILEDr  u    â€” rM   zDelivery target: r�   z/ (output was delivered there by the job itself)z (output saved locally only)rë   zNext scheduled run: z--- JOB OUTPUT ---r—   Ú
r   )ÚstatusÚsummaryr  Ú	api_callsÚduration_seconds)r  Úroundr  r   r’   rO   rG  rP   )ÚresÚdurationr  ÚlinesÚexcerptrê   rû   rŠ   rã   r  Ú
started_ats        €€€€€€r   Ú_runnerz-_try_dispatch_background_run.<locals>._runnerÈ  s•  ø€ Ý˜s°Ð>Ñ>Ô>ˆÝ�œ™œ zÑ1°1Ñ5Ô5ˆÝ˜F‘O”OÐ) rˆ	àH˜ÐHÐH fÐHÐHÐHØA˜sŸwšw yÑ1Ô1Ð?�t�t°xÐAÐAØ-0¯WªW°WÑ-=Ô-=ÐEÐ)�s—w’w˜wÑ'Ô'Ð)Ð)Ð)À2ñGà) Ð)Ð)ð ˜gÒ%Ð%ð BÐAà3ñ	ð	

ˆð �=Š=˜Ñ'Ô'ð 	LØ�LŠLÐJ°	¸-Ô0HÐJÐJÑKÔKÐKÝ,¨VÑ4Ô4ˆØð 	"Ø�LŠLÐ-Ñ.Ô.Ð.Ø�LŠL˜Ñ!Ô!Ð!à%(§W¢W¨YÑ%7Ô%7ÐD�k�k¸WØ—y’y Ñ'Ô'Ø—W’W˜WÑ%Ô%ØØ (ð
ð 
ð 	
r<   zManual run of cron job 'r  rA  ztTriggered via cronjob(action='run'). The job executed in its own fresh cron session; this block reports its outcome.Úcron_runræ   )ÚgoalÚcontextÚtoolsetsÚroleræ   Úsession_keyÚparent_session_idr5  Úorigin_ui_session_idÚorigin_session_idÚmax_async_childrenrX  Údelegation_id)r  rN  rm  zGcronjob run: background pool unavailable (%s); running job '%s' inline.r  Úrejected)r…   rJ  r   r¡   r’   Útools.approvalrK  r   rM  r   r   r   rt   r  r   rz   Útools.async_delegationrP  rQ  ru   r  Útools.delegate_toolrR  r  r   r   Úinfo)rŠ   rH  rû   rJ  rK  rh  rM  r  r  r  rj  rz   rP  rQ  rk  rù   rR  Ú	max_asyncrb  Údispatchrê   rã   r  ra  s   ` `                 @@@@r   Ú_try_dispatch_background_runru  7  s*  øøøøøø€ ðRØDÐDÐDÐDÐDÐDà'Ð'Ñ)Ô)ð 	Ø�4ð	øåð ð ð Øˆðøøøð �ŒY€FÝ�3—7’7˜6‘?”?Ð, fÑ-Ô-€Hð
Ø:Ð:Ð:Ð:Ð:Ð:à-Ð-°bÐ9Ñ9Ô9ˆˆøÝð ð ð Øˆˆˆðøøøàð &˜:ð &õ
 ˜*‘o”oˆØð ð ˆtð#Yð
	Ø:Ð:Ð:Ð:Ð:Ð:àÐ,Ð,Ñ.Ô.Ð.Ð.à$Ø$ðJð	ð ð ð /øõ ð 	ð 	ð 	ØˆDð	øøøõ " &Ñ)Ô)ð 	IÝ ™œˆIØÐ Ø@��Ý$ YÑ/Ô/ð WØL��àV�Ø$°ÀÐHÐHÐHð	Iøõ ð Yð Yð YÝ�ŠÐIÈ6ÐSTÑUÔUÐUð	Ý˜ ­¨A©¬Ñ/Ô/Ð/Ð/øÝð 	ð 	ð 	ØˆDð	øøøà¨uÀÕQTÐUVÑQWÔQWÐXÐXÐXÐXÐXÐXÐXÐXøøøøðYøøøð ÐðØ;Ð;Ð;Ð;Ð;Ð;à.˜Ð/EÀrÑJÔJÐPÈbÐÐøÝð ð ð Øˆðøøøðð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð
 7Ð6Ñ8Ô8ÐÐøÝð ð ð Ý�Šð'Ø()¨8ñ	
ô 	
ð 	
õ " #°LÐAÑAÔAˆØ$ˆˆ|ÑØˆˆˆˆˆˆøøøøðøøøðØ?Ð?Ð?Ð?Ð?Ð?à+Ð+Ñ-Ô-ˆ	ˆ	øÝð ð ð Øˆ	ˆ	ˆ	ðøøøõ ”‘”€JØ�gŠg�i Ñ)Ô)€Gð
•T�#�s˜(”^ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð: )Ð(Ø>¨Ð>Ð>°VÐ>Ð>Ð>ðBð ØØ�gŠg�gÑÔØØ-7ÐA�#˜j™/œ/˜/¸TØØ1Ø+Ø$ðñ ô €Hð" ‡|‚|�HÑÔ Ò-Ð-àØØ%Ÿ\š\¨/Ñ:Ô:ð
ð 
ð 	
õ ‡K‚KØQØ�Š�W˜jÑ)Ô)¨8ñô ð õ ˜c°Ð=Ñ=Ô=€FØ €Fˆ<ÑØ€MsÀ   ˆ ›
(§(ÁA+ Á+A:Á9A:ÂB/ Â.C= Â/
B<Â9C= Â;B<Â<?C= Ã=
E1ÄE,Ä$EÅE,Å
EÅE,ÅEÅE,Å&E1Å,E1Å7F Æ
FÆFÆF0 Æ0
G8Æ:3G3Ç-G8Ç3G8Ç<H ÈHÈHÚactionrç   rá   r•   rê   Úinclude_disabledræ   r  Úcontext_fromr÷   rø   rö   Úattach_to_sessionró   rô   Útask_idc                 ó0  — ~	 | pd                      ¦   «                              ¦   «         }|dk    �rþ|st          dd¬¦  «        S t          ||	¦  «        }t	          |¦  «        }|r|st          dd¬¦  «        S n|s|st          dd¬¦  «        S |r"t          |¦  «        }|rt          |d¬¦  «        S |r"t          |¦  «        }|rt          |d¬¦  «        S |r"t          |¦  «        }|rt          |d¬¦  «        S t          ||¦  «        }|rt          |d¬¦  «        S |rGdd	lm	} t          |t          ¦  «        r|gn|} | D ]$}! ||!¦  «        st          d
|!› d�d¬¦  «        c S Œ%ddlm}"m}# 	  |#d^i d|pd“d|“d|“d|“dt          |¦  «        “dt!          ¦   «         “d|“dt#          |
¦  «        “dt#          |¦  «        “dt#          |d¬¦  «        “dt#          |¦  «        “d|“d|pd“dt#          |¦  «        “d|“d|“d t#          |¦  «        “d!t#          |¦  «        “Ž}$nH# |"$ r@}%|%                     ¦   «         }&t          |&                     d"¦  «        fd#di|&¤ŽcY d}%~%S d}%~%ww xY wd$|$d         › d%�}'t)          |$t          |¦  «        ¦  «        }(|(r|'› d&|(› �}'t+          j        d|$d'         |$d         |$                     d(¦  «        |$                     dg ¦  «        |$d)         t1          |$¦  «        |$                     dd*¦  «        |$d+         t3          |$¦  «        |'d,œd-¬.¦  «        S |d/k    rAd0„ t5          |¬1¦  «        D ¦   «         })t+          j        dt7          |)¦  «        |)d2œd-¬.¦  «        S |st          d3|› d4�d¬¦  «        S 	 t9          |¦  «        }$nM# t:          $ r@}%t+          j        dt          |%¦  «        d5„ |%j        D ¦   «         d6œd-¬.¦  «        cY d}%~%S d}%~%ww xY w|$st+          j        dd7|› d8�d9œd-¬.¦  «        S |$d'         }|d:k    rut?          |¦  «        }*|*st          d;|› d4�d¬¦  «        S tA          ¦   «          t+          j        dd$|$d         › d<�||$d         |$                     d)¦  «        d=œd>œd-¬.¦  «        S |d?k    rEtC          ||¬@¦  «        }+tA          ¦   «          t+          j        dt3          |+¦  «        dAœd-¬.¦  «        S |dBk    rCtE          |¦  «        }+tA          ¦   «          t+          j        dt3          |+¦  «        dAœd-¬.¦  «        S |dCv �r°|pd},|,r"t          |,¦  «        }|rt          |d¬¦  «        S tG          |$||,¬D¦  «        }-|-�|-                     dE¦  «        rjtA          ¦   «          t3          t          |¦  «        pd'|i¦  «        }.d|.dF<   dG|.dH<   |-                     dI¦  «        |.dI<   t+          j        d|.dJdKœd-¬.¦  «        S |-�|-ntI          |$|,¬L¦  «        }/|/                     dMd¦  «        rtA          ¦   «          t3          t          |¦  «        pd'|i¦  «        }.|/                     dMd¦  «        |.dF<   |/                     d#d¦  «        |.dN<   |/                     dMd¦  «        s|/                     d"¦  «        pdO|.dP<   n |/                     d"¦  «        r|/d"         |.dQ<   t+          j        d|.dAœd-¬.¦  «        S |dRk    �rði }0|�'t          |¦  «        }|rt          |d¬¦  «        S ||0d<   |�||0d<   |�t          |¦  «        |0d<   |	€|�$t          ||	¦  «        }||0d<   |r|d         nd|0d(<   |
�t#          |
¦  «        |0d<   |�t#          |¦  «        |0d<   |�t#          |d¬¦  «        |0d<   d|0v r|0d         n|$                     d¦  «        }1d|0v r|0d         n|$                     d¦  «        }2t          |1|2¦  «        }|rt          |d¬¦  «        S |�:|r"t          |¦  «        }|rt          |d¬¦  «        S |rt#          |¦  «        nd|0d<   |�:|r"t          |¦  «        }|rt          |d¬¦  «        S |rt#          |¦  «        nd|0d <   |�|rt#          |¦  «        nd|0d!<   |€|�Wd |0v r|0d          n|$                     d ¦  «        }3d!|0v r|0d!         n|$                     d!¦  «        }4|3r|4rt          dSd¬¦  «        S |�ƒt          |t          ¦  «        r,|                      ¦   «         r|                      ¦   «         gng } ndT„ |D ¦   «         } | r-dd	lm	} | D ]$}! ||!¦  «        st          d
|!› d�d¬¦  «        c S Œ%| pd|0d<   |�|pd|0d<   |�t	          |¦  «        |0d<   |�t#          |¦  «        pd|0d<   |�Wt	          |¦  «        }5|5rAd|0v r|0                     d¦  «        n|$                     d¦  «        }6|6st          dUd¬¦  «        S |5|0d<   |�8|dk    rdn|}7tK          |$                     d¦  «        pi ¦  «        }8|7|8dV<   |8|0d<   |�PtM          |¦  «        }9|9|0d<   |9                     dW|¦  «        |0d)<   |$                     dX¦  «        dYk    r
dZ|0dX<   d|0d[<   |0st          d\d¬¦  «        S tO          ||0¦  «        }+tA          ¦   «          t+          j        dt3          |+¦  «        dAœd-¬.¦  «        S t          d]| › d4�d¬¦  «        S # tP          $ r(}:t          t          |:¦  «        d¬¦  «        cY d}:~:S d}:~:ww xY w)_z!Unified cron job management tool.rM   Úcreatezschedule is required for createF)r  uF   create with no_agent=True requires a script â€” the script is the job.z3create requires either prompt or at least one skillr   )r   zcontext_from job 'z>' not found. Use cronjob(action='list') to see available jobs.)ÚCronSchedulerRegistrationErrorÚ&create_job_with_scheduler_registrationrJ   rç   rá   r•   rê   r�   rž   ræ   r¶   r·   Tr§   rÍ   rx  r÷   Nrø   rö   ry  ró   rô   r  r  rU  z
' created.Ú rà   r�   rè   r�   rë   )r  rã   rá   r�   rž   rç   r•   rê   rë   rŠ   ÚmessagerÑ   )Úindentr¢   c                 ó,   — g | ]}t          |¦  «        ‘ŒS r7   )rú   )r8   rŠ   s     r   r±   zcronjob.<locals>.<listcomp>‘  s    € Ð]Ð]Ð]¨•K Ñ$Ô$Ð]Ð]Ð]r<   )rw  )r  ÚcountÚjobszjob_id is required for action 'ú'c                 óš   — g | ]H}|d          |                      d¦  «        |                      d¦  «        |                      d¦  «        dœ‘ŒIS )rà   rá   rè   rë   )rà   rá   rç   rë   r›   )r8   Úms     r   r±   zcronjob.<locals>.<listcomp>ž  sd   € ð  ð  ð  ð ð #$ D¤'Ø$%§E¢E¨&¡M¤MØ()¯ªÐ.@Ñ(AÔ(AØ+,¯5ª5°Ñ+?Ô+?ð	ð ð ð  ð  r<   )r  r  ÚmatcheszJob with ID or name 'z8' not found. Use cronjob(action='list') to inspect jobs.)r  r  ÚremovezFailed to remove job 'z
' removed.)rà   rá   rç   )r  r€  Úremoved_jobÚpause)r  )r  rŠ   Úresume>   ÚrunÚrun_nowÚtrigger)rH  rû   rN  ÚexecutedÚ
backgroundÚexecution_moderm  u¹   The job is running in the background. You and the user can keep working; its outcome re-enters the conversation as a new message when it finishes. Do not wait or poll â€” just continue.)r  rŠ   Únoter  r  Úexecution_successz4Already being fired by the scheduler; not run again.Úexecution_skippedÚexecution_errorÚupdateu]   monitor_script and monitor_url are mutually exclusive â€” clear one before setting the other.c                 ó’   — g | ]D}t          |¦  «                             ¦   «         ¯#t          |¦  «                             ¦   «         ‘ŒES r7   r¯   )r8   Újs     r   r±   zcronjob.<locals>.<listcomp>g  s9   € ÐSÐSÐS¨qÅCÈÁFÄFÇLÂLÁNÄNÐS�C ™FœFŸLšL™NœNÐSÐSÐSr<   ziCannot set no_agent=True on a job without a script. Set `script` in the same update, or on the job first.r–   Údisplayrð   ÚpausedÚ	scheduledrï   zNo updates provided.zUnknown cron action 'r7   ))r�   r‘   Ú
tool_errorr¦   r0  rq   rÞ   rÌ   rB  r   r    r¡   r   r}  r~  rµ   r‰   r¬   Úto_dictÚpopr“   ÚjsonÚdumpsr’   rœ   rú   r   rF   r   r
   rˆ  r   r   r   r   ru  r	  Údictr   r   r   );rv  rã   rJ   rç   rá   r•   rê   rw  r�   rž   ræ   r¶   r·   r  rÍ   rx  r÷   rø   rö   ry  ró   rô   rz  rH  r¤   Úcanonical_skillsÚ	_no_agentÚ
scan_errorÚscript_errorÚmonitor_errorÚbase_url_errorÚ_get_jobÚrefsÚref_idr}  r~  rŠ   ÚexcÚ_partialÚ_create_messageÚ_local_noticer„  re   Úupdatedrû   Úbgrù   Úexec_resultÚupdatesÚeff_providerÚeff_base_urlÚeff_mon_scriptÚeff_mon_urlÚtarget_no_agentÚeffective_scriptÚnormalized_repeatÚrepeat_stateÚparsed_scheduler  s;                                                              r   Úcronjobr½    sâ  € ð6 	ðy1Ø�l ×)Ò)Ñ+Ô+×1Ò1Ñ3Ô3ˆ
à˜Ò!Ñ!Øð TÝ!Ð"CÈUÐSÑSÔSÐSÝ0°¸Ñ?Ô?ÐÝ˜X™œˆIð ð hØð Ý%ð1à %ðñ ô ð ðð ð hÐ$4ð hÝ!Ð"WÐafÐgÑgÔgÐgØð AÝ.¨vÑ6Ô6�
Øð AÝ% j¸%Ð@Ñ@Ô@Ð@ð ð CÝ9¸&ÑAÔA�Øð CÝ% l¸EÐBÑBÔBÐBð ð DÝ :¸>Ñ JÔ J�Ø ð DÝ% m¸UÐCÑCÔCÐCõ 5°X¸xÑHÔHˆNØð AÝ! .¸%Ð@Ñ@Ô@Ð@ð ð 	Ø9Ð9Ð9Ð9Ð9Ð9Ý)3°LÅ#Ñ)FÔ)FÐX˜�~�~ÈL�Ø"ð ð �FØ#˜8 FÑ+Ô+ð Ý)ðP°ð Pð Pð Pà$)ð ñ  ô  ð ð ð ððð ð ð ð ð ð ð ð
TØ<Ð<ð ð ð Ø!˜< Røðà%˜Xðð ˜ðð "˜6ð	õ
 5°WÑ=Ô=Ð=ðõ ,Ñ-Ô-Ð-ðð ,Ð+ðõ 8¸Ñ>Ô>Ð>ðõ ;¸8ÑDÔDÐDðõ ;¸8ÐZ^Ð_Ñ_Ô_Ð_ðõ 9¸Ñ@Ô@Ð@ðð ". ðð &6Ð%=¸øðõ :¸'ÑBÔBÐBðð '˜Yðð  '8Ð&7ð!õ" $AÀÑ#PÔ#PÐ#Pð#õ$ !>¸kÑ JÔ JÐ Jð%��øð( 2ð Tð Tð TØŸ;š;™=œ=�Ý! (§,¢,¨wÑ"7Ô"7ÐSÐSÀÐSÈ(ÐSÐSÐSÐSÐSÐSÐSÐSøøøøðTøøøð C¨3¨v¬;ÐBÐBÐBˆOÝ2°3Õ8PÐQXÑ8YÔ8YÑZÔZˆMØð GØ%4Ð"FÐ"F°}Ð"FÐ"F�Ý”:à#Ø! $œiØ œKØ ŸWšW WÑ-Ô-Ø!Ÿgšg h°Ñ3Ô3Ø #Ð$6Ô 7Ý-¨cÑ2Ô2Ø"Ÿwšw y°'Ñ:Ô:Ø#& }Ô#5Ý& sÑ+Ô+Ø.ðð ð ðñ ô ð ð" ˜ÒÐØ]Ð]µ	ÐK[Ð0\Ñ0\Ô0\Ð]Ñ]Ô]ˆDÝ”:¨$½¸T¹¼ÈDÐQÐQÐZ[Ð\Ñ\Ô\Ð\àð 	^ÝÐMÀ
ÐMÐMÐMÐW\Ð]Ñ]Ô]Ð]ð	Ý! &Ñ)Ô)ˆCˆCøÝ$ð 	ð 	ð 	Ý”:à$Ý  ™XœXð ð  ð "%¤ð ñ  ô  ðð ð ðñ ô ð ð ð ð ð ð øøøøð	øøøð" ð 	Ý”:Ø!ð  -EÀFð  -Eð  -Eð  -Eð  Fð  FØðñ ô ð ð
 �T”ˆà˜Ò!Ð!Ý  Ñ(Ô(ˆGØð UÝ!Ð"D¸6Ð"DÐ"DÐ"DÈeÐTÑTÔTÐTÝ.Ñ0Ô0Ð0Ý”:à#ØC¨C°¬KÐCÐCÐCà$Ø # F¤Ø$'§G¢GÐ,>Ñ$?Ô$?ð$ð $ðð ð ðñ ô ð ð ˜Ò Ð Ý ¨vÐ6Ñ6Ô6ˆGÝ.Ñ0Ô0Ð0Ý”:¨$µ{À7Ñ7KÔ7KÐLÐLÐUVÐWÑWÔWÐWà˜Ò!Ð!Ý  Ñ(Ô(ˆGÝ.Ñ0Ô0Ð0Ý”:¨$µ{À7Ñ7KÔ7KÐLÐLÐUVÐWÑWÔWÐWàÐ6Ð6Ñ6ð "˜> TˆLØð AÝ.¨|Ñ<Ô<�
Øð AÝ% j¸%Ð@Ñ@Ô@Ð@õ .Ø 
¸ðñ ô ˆBð ˆ~ "§&¢&¨Ñ"6Ô"6ˆ~Ý2Ñ4Ô4Ð4Ý$¥W¨V¡_¤_Ð%F¸¸v¸ÑGÔG�Ø%)��zÑ"Ø+7�Ð'Ñ(Ø*,¯&ª&°Ñ*AÔ*A��Ñ'Ý”zà#'Ø%ðEð		ð 	ð ðñ ô ð ð" �n��Ý% c¸ÐEÑEÔEð ð �Š˜y¨%Ñ0Ô0ð 5Ý2Ñ4Ô4Ð4å ¥¨¡¤Ð!B°T¸6°NÑCÔCˆFØ!,§¢°¸EÑ!BÔ!BˆF�:ÑØ*5¯/ª/¸)ÀUÑ*KÔ*KˆFÐ&Ñ'Ø—?’? 9¨eÑ4Ô4ð AØ.9¯oªo¸gÑ.FÔ.Fð /ØJð Ð*Ñ+Ð+ð —’ Ñ)Ô)ð AØ,7¸Ô,@�Ð(Ñ)Ý”:¨$°vÐ>Ð>ÀqÐIÑIÔIÐIà˜Ò!Ñ!Ø&(ˆGØÐ!Ý.¨vÑ6Ô6�
Øð AÝ% j¸%Ð@Ñ@Ô@Ð@Ø$*�˜Ñ!ØÐØ"&�˜‘ØÐ"Ý%=¸gÑ%FÔ%F�˜	Ñ"ØÐ! UÐ%6Ý#4°U¸FÑ#CÔ#CÐ Ø$4�˜Ñ!Ø:JÐ#TÐ#3°AÔ#6Ð#6ÐPT�˜Ñ ØÐ Ý#@ÀÑ#GÔ#G�˜Ñ ØÐ#Ý&CÀHÑ&MÔ&M�˜
Ñ#ØÐ#Ý&CÀHÐcgÐ&hÑ&hÔ&h�˜
Ñ#ð (2°WÐ'<Ð'<�˜
Ô#Ð#À#Ç'Â'È*ÑBUÔBUð ð (2°WÐ'<Ð'<�˜
Ô#Ð#À#Ç'Â'È*ÑBUÔBUð õ 5°\À<ÑPÔPˆNØð AÝ! .¸%Ð@Ñ@Ô@Ð@ØÐ!àð GÝ#=¸fÑ#EÔ#E�LØ#ð GÝ)¨,ÀÐFÑFÔFÐFØMSÐ$]Õ$AÀ&Ñ$IÔ$IÐ$IÐY]�˜Ñ!ØÐ)à!ð HÝ$>¸~Ñ$NÔ$N�MØ$ð HÝ)¨-ÀÐGÑGÔGÐGàESÐ]Õ1°.ÑAÔAÐAÐY]ð Ð(Ñ)ð Ð&ð CNÐWÕ1°+Ñ>Ô>Ð>ÐSWð ˜Ñ&ð Ð)¨[Ð-Dà1AÀWÐ1LÐ1L�GÐ,Ô-Ð-ÐRU×RYÒRYÐZjÑRkÔRkð ð /<¸wÐ.FÐ.F�G˜MÔ*Ð*ÈCÏGÊGÐTaÑLbÔLbð ð "ð  kð Ý%ð>à %ðñ ô ð ð
 Ð'õ ˜l­CÑ0Ô0ð TØ5A×5GÒ5GÑ5IÔ5IÐQ˜L×.Ò.Ñ0Ô0Ð1Ð1Èr�D�DàSÐS°LÐSÑSÔS�DØð Ø=Ð=Ð=Ð=Ð=Ð=Ø"&ð ð ˜Ø'˜x¨Ñ/Ô/ð Ý#-ð!T°Vð !Tð !Tð !Tà(-ð$ñ $ô $ð ð ð ðð +/¨,°$�˜Ñ'ØÐ+Ø.>Ð.FÀ$�Ð*Ñ+Ø Ð,Ý/3Ð4EÑ/FÔ/F�Ð+Ñ,ØÐ"õ &CÀ7Ñ%KÔ%KÐ%SÈt�˜	Ñ"ØÐ#õ #' x¡.¤.�Ø"ð Ø@HÈGÐ@SÐ@S w§{¢{°8Ñ'<Ô'<Ð'<ÐY\×Y`ÒY`ÐaiÑYjÔYjÐ$Ø+ð Ý)ðTà$)ð ñ  ô  ð ð
 '6�˜
Ñ#ØÐ!à,2°aªK¨K D D¸VÐ!Ý# C§G¢G¨HÑ$5Ô$5Ð$;¸Ñ<Ô<�Ø(9�˜WÑ%Ø$0�˜Ñ!ØÐ#Ý"0°Ñ":Ô":�Ø&5�˜
Ñ#Ø.=×.AÒ.AÀ)ÈXÑ.VÔ.V�Ð*Ñ+Ø—7’7˜7Ñ#Ô# xÒ/Ð/Ø'2�G˜GÑ$Ø)-�G˜IÑ&Øð IÝ!Ð"8À%ÐHÑHÔHÐHÝ  ¨Ñ1Ô1ˆGÝ.Ñ0Ô0Ð0Ý”:¨$µ{À7Ñ7KÔ7KÐLÐLÐUVÐWÑWÔWÐWåÐ;°&Ð;Ð;Ð;ÀUÐKÑKÔKÐKøåð 1ð 1ð 1Ý�#˜a™&œ&¨%Ð0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0øøøøð1øøøs/  ƒAk# Á3k# Á9k# Â#k# Â3#k# Ã#k# Ã;"k# ÄAk# Å&	k# Å0B6H' È&k# È'I,È,5I'É!I,É"k# É'I,É,Ck# Ì0Ak# Í7k# ÎN Îk# Î
O)Î)5O$ÏO)Ïk# Ï$O)Ï)!k# Ð3k# Ð?Ak# ÒA
k# ÓAk# Ô",k# ÕBk# ×"C4k# Û,k# ÜC*k# ß/%k# à;k# áBk# ãA<k# åBk# ç&B#k# ê
Ak# ëk# ë#
lë-lì
lìlr½  u¦  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.

action='run' fires the job immediately in the BACKGROUND (like delegate_task): the call returns at once with a handle and the job's outcome re-enters the conversation as a new message when it finishes. Do not wait or poll after triggering a run â€” just continue. Optionally pass 'prompt' with action='run' to inject transient per-run context (appended to the job's stored prompt for that single fire only, never persisted).

To stop a job the user no longer wants: first action='list' to find the job_id, then action='remove' with that job_id. Never guess job IDs â€” always list first.

Jobs run in a fresh session with no current-chat context, so prompts must be self-contained.
If 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.

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.ÚobjectÚstringz~One of: create, list, update, pause, resume, remove, run. When action=create, the 'schedule' and 'prompt' fields are REQUIRED.)ÚtypeÚdescriptionz+Required for update/pause/resume/remove/runzóFor create: the full self-contained prompt. If skills are also provided, this becomes the task instruction paired with those skills. For run: optional transient context appended to the stored prompt for that single fire only (never persisted).a  REQUIRED for action=create. For create/update: '30m', 'every 2h', '0 9 * * *', or ISO timestamp. Examples: '30m' (every 30 minutes), 'every 2h' (every 2 hours), '0 9 * * *' (daily at 9am), '2026-06-01T09:00:00' (one-shot). You MUST include this field when action=create.zOptional human-friendly nameÚintegerzTOptional repeat count. Omit for defaults (once for one-shot, forever for recurring).a  Omit this parameter to auto-deliver back to the current chat and topic (recommended). Auto-detection preserves thread/topic context. Only set explicitly when the user asks to deliver somewhere OTHER than the current conversation. Values: 'origin' (same as omitting), 'local' (no delivery, save only), 'all' (fan out to every connected home channel), or platform:chat_id:thread_id for a specific destination. Combine with comma: 'origin,all' delivers to the origin plus every other connected channel. Examples: 'telegram:-1001234567890:17585', 'discord:#engineering', 'sms:+15551234567', 'all'. WARNING: 'platform:chat_id' without :thread_id loses topic targeting. 'all' resolves at fire time, so a job created before a channel was wired up will pick it up automatically once connected.ÚarrayrÀ  z‡Optional ordered list of skill names to load before executing the cron prompt. On update, pass an empty array to clear attached skills.)rÀ  ÚitemsrÁ  a3  Optional path to a script that runs each tick. In the default mode its stdout is injected into the agent's prompt as context (data-collection / change-detection pattern). With no_agent=True, the script IS the job and its stdout is delivered verbatim (classic watchdog pattern). Relative paths resolve under zx/scripts/. ``.sh``/``.bash`` extensions run via bash, everything else via Python. On update, pass empty string to clear.zIOptional monitor-mode source script (same rules as `script`: relative to u^  /scripts/, .sh/.bash via bash, else Python). Each tick it runs FIRST and its output is hashed as exact bytes: UNCHANGED output suppresses the agent run entirely (no LLM, no delivery, recorded as a silent no_change tick); CHANGED output injects a MONITOR CHANGE DETECTED block (unified diff + new output) into the prompt before a normal agent run. The first tick always runs the agent (baseline). Scripts must emit STABLE output â€” no timestamps or random ordering â€” or every tick looks changed. Mutually exclusive with monitor_url; incompatible with no_agent=True. On update, pass empty string to clear.u  Optional http(s) URL used as the monitor source instead of a script â€” fetched with a bounded GET (30s timeout, 256KB cap) each tick. Same hash-suppression semantics as monitor_script. Mutually exclusive with monitor_script. On update, pass empty string to clear.Úbooleanu_  Default: False (LLM-driven job â€” the agent runs the prompt each tick). Set True to skip the LLM entirely: the scheduler just runs ``script`` on schedule and delivers its stdout verbatim. No tokens, no agent loop, no model override honoured. 

REQUIREMENTS when True: ``script`` MUST be set (``prompt`` and ``skills`` are ignored). 

DELIVERY SEMANTICS when True: (a) non-empty stdout is sent verbatim as the message; (b) EMPTY stdout means SILENT â€” nothing is sent to the user and they won't see anything happened, so design your script to stay quiet when there's nothing to report (the watchdog pattern); (c) non-zero exit / timeout sends an error alert so a broken watchdog can't fail silently. 

WHEN TO USE True: recurring script-only pings where the script itself produces the exact message text (memory/disk/GPU watchdogs, threshold alerts, heartbeats, CI notifications, API pollers with a fixed output shape). WHEN TO USE False (default): anything that needs reasoning â€” summarize a feed, draft a daily briefing, pick interesting items, rephrase data for a human, follow conditional logic based on content.)rÀ  rL  rÁ  u™  Optional job ID or list of job IDs whose most recent completed output is injected into the prompt as context before each run. Use this to chain cron jobs: job A collects data, job B processes it. Each entry must be a valid job ID (from cronjob action='list'). Note: injects the most recent completed output â€” does not wait for upstream jobs running in the same tick. On update, pass an empty array to clear.uÎ  Optional list of toolset names to restrict the job's agent to (e.g. ["web", "terminal", "file", "delegation"]). When set, only tools from these toolsets are loaded, significantly reducing input token overhead. When omitted, all default tools are loaded. Infer from the job's prompt â€” e.g. use "web" if it calls web_search, "terminal" if it runs scripts, "file" if it reads files, "delegation" if it calls delegate_task. On update, pass an empty array to clear.u1  Optional absolute path to run the job from. When set, AGENTS.md / CLAUDE.md / .cursorrules from that directory are injected into the system prompt, and the terminal/file/code_exec tools use it as their working directory â€” useful for running a job inside a specific project repo. Must be an absolute path that exists. When unset (default), preserves the original behaviour: no project context files, tools use the scheduler's cwd. On update, pass an empty string to clear. Jobs with workdir run sequentially (not parallel) to keep per-job directories isolated.uº  When True, this job becomes CONTINUABLE: the user can reply to its delivery and the agent has the brief in context instead of asking 'what is that?'. On thread-capable platforms (Telegram topics, Discord/Slack threads) a dedicated thread is opened for the job and its replies; on DM-only platforms (WhatsApp/Signal) the brief is mirrored into the origin DM session. Use this for conversational recurring jobs the user will reply to â€” daily briefings, reminders that kick off follow-up work. Leave unset for fire-and-forget alerts/watchdogs. Overrides the global cron.mirror_delivery config for this one job. Only the origin chat is touched (never fan-out targets); no effect when deliver='local'.)rÀ  Ú
propertiesÚrequired)rá   rÁ  Ú
parametersc                  óP   — ddl m}   | d¦  «        p | d¦  «        p
 | d¦  «        S )u  
    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.

    Session env vars must hold an explicit truthy string (``1``, ``true``,
    ``yes``, ``on``) â€” false-like values (``0``, ``false``, ``no``, ``off``)
    leave the tool disabled. Uses the shared ``env_var_enabled`` helper so
    every consumer of these flags agrees on the truthy set.
    r   ©Úenv_var_enabledÚHERMES_INTERACTIVEÚHERMES_GATEWAY_SESSIONÚHERMES_EXEC_ASK)rÄ   rË  rÊ  s    r   Úcheck_cronjob_requirementsrÏ    sQ   € ð &Ð%Ð%Ð%Ð%Ð%ð 	ˆÐ,Ñ-Ô-ð 	.Øˆ?Ð3Ñ4Ô4ð	.àˆ?Ð,Ñ-Ô-ðr<   )Úregistryr�  c           	      óŠ  — t          di d|                      dd¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d	|                      d	d
¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                      d¦  «        “d|                     d¦  «        “d|                     d¦  «        “ŽS )Nrv  rM   rã   rJ   rç   rá   r•   rê   rw  Tr�   rž   r  rÍ   rx  r÷   rø   rö   ró   rô   rz  rH  r7   )r½  r’   )ÚargsÚkws     r   ú<lambda>rÔ  6  s  € �wð  ð  ð  Ø�xŠx˜ "Ñ%Ô%Ð%ð à�xŠx˜Ñ!Ô!Ð!ð ð �xŠx˜Ñ!Ô!Ð!ð ð —’˜*Ñ%Ô%Ð%ð	 ð
 �XŠX�fÑÔÐð ð �xŠx˜Ñ!Ô!Ð!ð ð —’˜Ñ#Ô#Ð#ð ð ŸšÐ"4°dÑ;Ô;Ð;ð ð �hŠh�wÑÔÐð ð �xŠx˜Ñ!Ô!Ð!ð ð  �xŠx˜Ñ!Ô!Ð!ð! ð" �xŠx˜Ñ!Ô!Ð!ð# ð$ —X’X˜nÑ-Ô-Ð-ð% ð& ŸšÐ"4Ñ5Ô5Ð5ð' ð( —’˜Ñ#Ô#Ð#ð) ð* —’˜*Ñ%Ô%Ð%ð+ ð, —x’xÐ 0Ñ1Ô1Ð1ð- ð. —H’H˜]Ñ+Ô+Ð+ð/ ð0 —’�yÑ!Ô!Ð!ð1 ð2 —6’6˜,Ñ'Ô'Ð'ð3 € r<   u   â�°)rá   ÚtoolsetÚschemaÚhandlerÚcheck_fnÚemojir'  )NNr6   )r9  )NNNNNNFNNNNNNNNNNNNNNNN)SÚ__doc__r   ÚloggingrV   r-  r)  r  Úpathlibr   Útypingr   r   r   r   r   r×   r	   Ú	getLoggerÚ__name__rt   r  r  ÚpathÚinsertr¡   Ú__file__ÚparentrB  r
   r   r   r   r   r   r   r   r   r   r   r   r   r   rj   rv   rX   rl   Útools.threat_patternsr1   r]   r>   rE   r  r0  r?   rI   rS   rZ   r`   r³   r¢   rf   rq   rw   r‰   r“   rœ   r¦   r¬   rµ   rÌ   rÞ   rú   r	  r  rG  ru  r½  ÚCRONJOB_SCHEMArÏ  Útools.registryrÐ  r�  Úregisterr7   r<   r   ú<module>rè     s‹  ððð ð €€€Ø €€€Ø 	€	€	€	Ø 
€
€
€
Ø Ð Ð Ð Ø €€€Ø Ð Ð Ð Ð Ð Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3à 0Ð 0Ð 0Ð 0Ð 0Ð 0à	ˆÔ	˜8Ñ	$Ô	$€ð  $Ð ð )Ð ð „‡‚��3�3�t�t˜H‘~”~Ô,Ô3Ñ4Ô4Ñ 5Ô 5Ð 5ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð"ð ð ð ðR	ð 	ð 	Ð ð$"ð "ð "Ð ð TÐ ð ?Ð)<Ð>Ð>Ð@PÐQØ>Ð)<Ð>Ð>Ð@PÐQØgÐReÐgÐgÐizÐ{ØFÐ1DÐFÐFÐHYÐZØkÐQdÐkÐkÐkð  nFð  Gð Ð ð( KÐ JÐ JÐ JÐ JÐ JðÐ ð  Ð ðH�Sð H˜Tð Hð Hð Hð Hð 3ð ¨Sð °Tð ð ð ð ð¨ð °ð ð ð ð ð¨ð °ð ð ð ð ð< Sð ¨Sð ð ð ð ð- Sð -¨U°3¸¸S¼	°>Ô-Bð -ð -ð -ð -ð:˜cð  cð ð ð ð ð,¨#ð °%¸¸S¸´/ð ð ð ð ðD˜( 4¨¨S¨¤>Ô2ð ð ð ð ð4"  S¨# X¤ð "¸hÀs¼mð "ÐPXÐY\ÔP]ð "ð "ð "ð "ðJE˜˜c 3˜hœð E¨Cð Eð Eð Eð Eðð ˜X cœ]ð ¸8ÀC¼=ð ÐTXÐY\ÔT]ð ð ð ð ð$ Y^ð ð ð ¨°#¬ð ÐQUð ÐbjÐknÔboð ð ð ð ð Cð ¨H°S¬Mð ð ð ð ð*MØ�sŒmðMØ'/°¤}ðMàˆc„]ðMð Mð Mð Mð`$ x°¤}ð $¸À#¼ð $ð $ð $ð $ðN)�T˜#˜s˜(”^ð )¨¨S°#¨X¬ð )ð )ð )ð )ðZ 8<ð*<ð *<Ø	ˆc�3ˆhŒð*<Ø'/°¤}ð*<à	ˆ#ˆsˆ(„^ð*<ð *<ð *<ð *<ð\ 8<ðWDð WDØ	ˆc�3ˆhŒðWDØ'/°¤}ðWDà	ˆ#ˆsˆ(„^ðWDð WDð WDð WDðtð  sð °sð ÀhÈsÄmð ð ð ð ð2 6:Ø"&ðNð NØ	ˆc�3ˆhŒðNØ%-¨c¤]ðNà˜3”-ðNð ˆd�3˜�8ŒnÔðNð Nð Nð Nðf !Ø Ø"ØØ Ø!Ø"ØØ"&ØØ"Ø"Ø Ø Ø48Ø,0Ø!Ø#Ø(,Ø$(Ø!%ØØ $ð1V1ð V1ØðV1à�SŒMðV1ð �SŒMðV1ð �sŒmð	V1ð
 �3Œ-ðV1ð �SŒMðV1ð �cŒ]ðV1ð ðV1ð �CŒ=ðV1ð �T˜#”YÔðV1ð �CŒ=ðV1ð �sŒmðV1ð �sŒmðV1ð �SŒMðV1ð �SŒMðV1ð  ˜5  d¨3¤i Ô0Ô1ð!V1ð" ˜t CœyÔ)ð#V1ð$ �cŒ]ð%V1ð& �tŒnð'V1ð(   ”~ð)V1ð* ˜S”Mð+V1ð, ˜#”ð-V1ð. ð/V1ð0 ˜”ð1V1ð2 	ð3V1ð V1ð V1ð V1ðv ð\ð( ðZ
ØØ ð  `ðð ðZ
ð
 Ø ØLðð ðZ
ð Ø ð  Uðð ðZ
ð Ø ð  pðð ðZ
ð" Ø Ø=ðð ð#Z
ð* Ø!Øuðð ð+Z
ð2 Ø ð  sðð ð3Z
ð: ØØ  (Ð+ð  iðð ð;Z
ðD Ø ð  eð  Við  Viñ  Vkô  Vkð   eð   eð   eðð ðEZ
ðL Ø ð  aÐk~Ðk~ñ  lAô  lAð   að   að   aðð ðMZ
ðT Ø ð  jðð ðUZ
ð\ Ø!Ø ð]ð	ð ð]Z
ð@ ØØ  (Ð+ð?ð	ð ðAZ
ðZ ØØ  (Ð+ð  @ð!ð !ð[Z
ðd Ø ð  S	ðð ðeZ
ðl  Ø!ð  \ð"ð "ðmZ
ðv �Jð{^ð ^ð+tð t€ðn Dð ð ð ð ð. 0Ð /Ð /Ð /Ð /Ð /Ð /Ð /à €Ô Ø	ØØðð ð6 (Ø
ðA!ñ !ô !ð !ð !ð !r<   