Ë
    ãß²jv^  ã                   óø  — d Z ddlZddlZddlmZmZ ddlmZmZmZm	Z	m
Z
 ddlmZ ddlZ ej                  d«      ZdZde
eeeef   df   d	efd
„Z	 d1de
eeeef   df   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	e   d	ee   fd„Zde	e   de	e   de	e   d	efd„Zdeeef   d	efd„Zded	ee   fd„Zd2de	e   de	e   d	ee   fd„Zddœde	e   ded	e	e   fd„Zded	e	e   fd„Zd e	e   d	e	e   fd!„Zd e	e   d	e	e   fd"„Zd#e	e   d$e	e   d	e	e   fd%„Z d&e	e   d	e	e   fd'„Z!d(e	e
eee   f      d)ed	e	ee      fd*„Z"d+ee   d	e	e   fd,„Z#d-Z$deeef   d	eeef   fd.„Z%d3d/ed	e&fd0„Z'y)4zgCron job argument normalization, validation and result shaping (re-exported by
tools/cronjob_tools.py).é    N)ÚdatetimeÚ	timedelta)ÚAnyÚDictÚListÚOptionalÚUnion)Úeffective_job_stateztools.cronjob_toolsé<   ÚscheduleÚreturnc                 óh  — | syt        | t        «      r| }n2d}t        j                  t        «      5  ddlm}  || «      }ddd«       t        |t        «      r|j                  d«      dk7  ry|j                  d«      }|sy	 t        j                  t        |«      j                  dd	«      «      }t        j                  «       }|j                  €|j                  |j                  ¬
«      }||z
  }t!        d«      |cxk  xr t!        t"        ¬«      k  S c S # 1 sw Y   ŒÙxY w# t        $ r Y yw xY w)a  True when the job's first fire is close enough that the creating conversation is still
    alive when it happens. Only near one-shots qualify; recurring jobs and one-shots beyond the
    horizon outlive the conversation, which is what the synthetic-drop rule protects.FNr   )Úparse_scheduleÚkindÚonceÚrun_atÚZz+00:00)Útzinfo)Úminutes)Ú
isinstanceÚdictÚ
contextlibÚsuppressÚ	ExceptionÚ	cron.jobsr   Úgetr   ÚfromisoformatÚstrÚreplaceÚ
ValueErrorÚhermes_timeÚnowr   r   Ú_THREAD_HORIZON_MINUTES)r   Úparsedr   r   Úfire_atr"   Údeltas          ú;/home/ubuntu/.hermes/hermes-agent/tools/cronjob_job_args.pyÚ!_first_fire_within_thread_horizonr(      s  € ñ Øä�(œDÔ!Ø‰àˆÜ× Ñ ¤Ó+ñ 	.Ý0á# HÓ-ˆF÷	.ô �fœdÔ# v§z¡z°&Ó'9¸VÒ'CØØ�Z‰Z˜Ó!€FÙØðÜ×(Ñ(¬¨V«×)<Ñ)<¸SÀ(Ó)KÓLˆô �/‰/Ó
€CØ‡~�~ÐØ—/‘/¨¯©�/Ó4ˆð
 �c‰M€EÜ�Q‹<˜5ÖN¤IÔ6MÔ$NÑNÐNÑNÐN÷+	.ð 	.ûô ò Ùðús   ²DÂ.D% ÄD"Ä%	D1Ä0D1c                 ó²  — ddl m}m}  |d«      } |d«      }|r|sy  |«       sy  |d«      xs d }|rd|dk(  r_ |d«      xs d }|rQt        |«      t        |«      k(  r:t	        | «      rt
        j                  d|«       nt
        j                  d	|«       d }|rt
        j                  d
|||«       || |d«      xs d | |d«      xs d  |d«      xs d dœS )Nr   ©Úasync_delivery_supportedÚget_session_envÚHERMES_SESSION_PLATFORMÚHERMES_SESSION_CHAT_IDÚHERMES_SESSION_THREAD_IDÚslackÚHERMES_SESSION_MESSAGE_IDuc   Cron origin: keeping synthetic Slack thread_id=%s â€” first fire is within the conversation horizonzWCron origin: dropping synthetic per-message Slack thread_id=%s (== creation message id)z+Cron origin captured thread_id=%s for %s:%sÚHERMES_SESSION_CHAT_NAMEÚHERMES_SESSION_USER_IDÚHERMES_SESSION_SCOPE_ID)ÚplatformÚchat_idÚ	chat_nameÚ	thread_idÚuser_idÚscope_id)Úgateway.session_contextr+   r,   r   r(   ÚloggerÚdebug)r   r+   r,   Úorigin_platformÚorigin_chat_idr8   Ú
message_ids          r'   Ú_origin_from_envrA   ;   s  € ÷ RÙ%Ð&?Ó@€OÙ$Ð%=Ó>€NÙ¡Øñ $Ô%ØÙÐ :Ó;ÒC¸t€Iñ �_¨Ò/Ù$Ð%@ÓAÒIÀTˆ
Ùœ#˜i›.¬C°
«OÒ;Ü0°Ô:Ü—‘ð6àõô —‘ð<àôð
 !�	ÙÜ�‰Ø9Ø�¨ô	8ð $°Ù$Ð%?Ó@ÒHÀDÐW`á"Ð#;Ó<ÒDÀñ $Ð$=Ó>ÒFÀ$ñð ó    ÚjobÚuser_deliverc                 ól  — |xs dj                  «       j                  «       dk(  ry	 ddlm}  || «      }|rSddlm}m} |D �cg c]  }|j                  d«      dk(  sŒ|‘Œ }}|r$ |d	«      r |«       sd
|d   d   › d|d   d   › d�S y	 	 yc c}w # t        $ r | j                  d«      rY yY 	 yw xY w)uƒ  Notice when a created job won't deliver anywhere: CLI/TUI sessions have no capturable
    origin, so deliver='origin' (or omitted) saves output but never delivers it. None when the
    user explicitly asked for ``local`` or the job resolves to a real target.

    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. See #51568.
    Ú ÚlocalNr   )Ú_resolve_delivery_targetsr*   Ú_resolved_fromÚorigin_fallbackr-   zpNote: this stateless HTTP API session cannot receive cron delivery, so this job will report to the home channel r5   ú:r6   z instead of back here.Úoriginuh  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 and stateless HTTP API 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ÚlowerÚcron.schedulerrH   r;   r+   r,   r   r   )rC   rD   rH   Útargetsr+   r,   ÚtÚfallbacks           r'   Ú_local_delivery_noticerS   n   sù   € ð 	Ò˜×!Ñ!Ó#×)Ñ)Ó+¨wÒ6ØðÝ<Ù+¨CÓ0ˆÙ÷ ZØ#*Ö[˜a¨a¯e©eÐ4DÓ.EÐIZÓ.ZšÐ[ˆHÐ[Ù™OÐ,EÔFÑOgÔOið?Ø?GÈ¹{È:Ñ?VÐ>WÐWXØ# A™; yÑ1Ð2Ð2HðJð Kð ð ð	RðSùò \øô ò Ø�7‰7�8ÔÙð ð	RðSðús)   ¨B ÁBÁBÁ"'B ÂB ÂB3Â2B3c                 ó   — g }| j                  d«      s| j                  d«      r|j                  d«       | j                  d«      r|j                  d«       |xs dj                  «       j                  «       }|rÒd|j	                  d«      v r|j                  d	«       |j                  d
«      r|j                  d«       |j	                  d«      D ]x  }|j                  «       j	                  d«      }t        |«      dk(  sŒ1|d   dvsŒ9|d   sŒ?|d   j                  d«      rŒT|j                  d|j                  «       › d�«        |S  |S )zuMode guidance echoed once in the create/update response (not in the schema, which is
    paid for on every API call).Úmonitor_scriptÚmonitor_urlus  Monitor mode: the source runs first each tick and its output is hashed as exact bytes â€” unchanged output suppresses the agent run (silent no_change tick), changed output injects a MONITOR CHANGE DETECTED diff into the prompt. The first tick always runs as baseline. The source must emit STABLE output (no timestamps, no random ordering) or every tick will look changed.Úno_agentué   no_agent mode: stdout is delivered verbatim; EMPTY stdout sends nothing at all (watchdog pattern â€” script should stay quiet when there is nothing to report). Non-zero exit or timeout sends an error alert. prompt/skills are ignored.rF   Úallú,u�   deliver='all' resolves at fire time and never includes bot-chat targets â€” channels connected later are picked up automatically.z	bot-chat:zJTargeting another profile's Bot Chat costs that bot an agent turn per run.rK   é   r   )zbot-chatÚsmsé   ú#zdeliver target 'uk   ' has no :thread_id segment â€” on thread/topic platforms the delivery lands in the main chat, not a topic.)r   ÚappendrM   rN   ÚsplitÚ
startswithÚlen)rC   rD   ÚnotesÚ_deliverÚtargetÚpartss         r'   Ú_mode_guidance_notesrf   ”   sG  € ð €EØ
‡w�wÐÔ  C§G¡G¨MÔ$:Ø�‰ð@ô	Að ‡w�wˆzÔØ�‰ð6ô	7ð
 Ò" ×)Ñ)Ó+×1Ñ1Ó3€HÙØ�H—N‘N 3Ó'Ñ'Ø�L‰Lð!ô"ð ×Ñ˜{Ô+Ø�L‰LÐeÔfà—n‘n SÓ)ò 	ˆFØ—L‘L“N×(Ñ(¨Ó-ˆEä�E“
˜a“Ø˜!‘HÐ$7Ò7Ø˜!“HØ˜a™×+Ñ+¨CÕ0Ø—‘Ø& v§|¡|£~Ð&6ð 72ð 2ô3ð Ø€Lð	ð €LrB   ÚmonitorrU   rV   c                 ó‚   — | €||fS | j                  «       }|sy|j                  «       j                  d«      rd|fS |dfS )aŒ  Resolve the model-facing ``monitor`` field into the stored ``(monitor_script,
    monitor_url)`` pair. http(s):// is a URL, anything else a script path (a legal script path
    never starts with a URL scheme). None = unchanged, '' = clear; setting one source clears
    the other so switching transports never trips mutual exclusion; an explicit ``monitor``
    wins over the legacy alias fields.)rF   rF   )zhttp://zhttps://rF   )rM   rN   r`   )rg   rU   rV   Úvalues       r'   Ú_split_monitor_argrj   ¿   sN   € ð €Ø˜{Ð*Ð*Ø�M‰M‹O€EÙØØ‡{�{ƒ}×ÑÐ 7Ô8Ø�5ˆyÐØ�"ˆ9ÐrB   c                 ó°   — | j                  d«      xs i }|j                  d«      |j                  dd«      }}|€y|dk(  r	|dk(  rdS dS |r|› d	|› �S |› d
�S )NÚrepeatÚtimesÚ	completedr   Úforeverr\   r   z1/1ú/z times)r   )rC   Úreprm   rn   s       r'   Ú_repeat_displayrr   Ò   sq   € Ø
�'‰'�(Ó
Ò
!˜r€CØ—w‘w˜wÓ'¨¯©°¸aÓ)@ˆ9€EØ€}ØØ�‚zØ" ašˆvÐ2¨UÐ2Ù%.ˆiˆ[˜˜%˜Ð!ÐD°u°g¸VÐ4DÐDrB   Úitemsc                 ón   — | €g S t        | t        «      r| g} d„ | D «       D �cg c]  }|sŒ|‘Œ	 c}S c c}w )zMStripped, non-empty ``str(item)`` values from a str-or-iterable (order kept).c              3   óN   K  — | ]  }t        |«      j                  «       –— Œ y ­w©N)r   rM   )Ú.0Úis     r'   ú	<genexpr>z"_clean_str_list.<locals>.<genexpr>â   s   è ø€ Ò6¨1œ˜A›Ÿ™ŸÑ6ùs   ‚#%)r   r   )rs   Úss     r'   Ú_clean_str_listr{   Ü   s8   € à€}Øˆ	Ü�%œÔØ�ˆÙ6°Ô6Ö<�!º!ŠAÒ<Ð<ùÒ<s   £2«2ÚskillÚskillsc                 ó˜   — |€| r| gng }nt        |t        «      r|g}t        t        j	                  t        d„ |D «       «      «      «      S )Nc              3   ó(   K  — | ]
  }|xs d –— Œ y­w)rF   N© )rw   Úitems     r'   ry   z$_canonical_skills.<locals>.<genexpr>ë   s   è ø€ Ò-L¸T¨dªj°b«jÑ-Lùs   ‚)r   r   Úlistr   Úfromkeysr{   )r|   r}   s     r'   Ú_canonical_skillsr„   å   sB   € Ø€~Ù!�%‘ r‰Ü	�FœCÔ	 Ø�ˆä”—‘œoÑ-LÀVÔ-LÓLÓMÓNÐNrB   F©Ústrip_trailing_slashri   r†   c                ól   — | €y t        | «      j                  «       }|r|j                  d«      }|xs d S )Nrp   )r   rM   Úrstrip)ri   r†   Útexts      r'   Ú_normalize_optional_job_valuerŠ   î   s7   € Ø€}ØÜˆu‹:×ÑÓ€DÙØ�{‰{˜3ÓˆØŠ<�4ÐrB   c                 óª   — | €yt        | t        t        f«      rdj                  t	        | «      «      xs dS t        | «      j                  «       xs dS )z­Canonical string form of ``deliver``; None for None/empty. MCP clients may pass a list
    (``["telegram"]``) which the scheduler's ``str(deliver).split(",")`` would mangle.NrY   )r   r‚   ÚtupleÚjoinr{   r   rM   )ri   s    r'   Ú_normalize_deliver_paramrŽ   ÷   sK   € ð €}ØÜ�%œ$¤˜Ô'Ø�x‰xœ¨Ó.Ó/Ò7°4Ð7Üˆu‹:×ÑÓÒ% Ð%rB   Údeliverc                 ó  — | sy	 ddl m} ddlm}m} t        | «      j                  d«      D ]4  } ||j                  «       «      }|sŒ	  ||«      } ||«      rŒ.d|› d	�c S  y# t
        $ r Y yw xY w# t
        $ r d|› d�cY c S w xY w)
a  Validate ``bot-chat[:<profile>]`` deliver elements at create time: Bot Chat delivery is
    machine-local, so the profile must exist where the scheduler fires (Desktop rosters may
    show same-named profiles from other machines). Returns an error string or None.Nr   )Úparse_bot_chat_deliver_token)Únormalize_profile_nameÚprofile_existsrY   zinvalid bot-chat profile name 'ú'zbot-chat delivery profile 'uÄ   ' not found on this gateway's machine. Bot Chat delivery is machine-local â€” use a profile that exists here (hermes profile list), or omit the name (deliver='bot-chat') for the job's own profile.)	Úcron.scheduler_deliveryr‘   Úhermes_cli.profilesr’   r“   r   r   r_   rM   )r�   r‘   r’   r“   ÚpartÚprofile_argÚcanons          r'   Ú_validate_bot_chat_deliverrš     sº   € ñ ØðÝHßNô �G“×"Ñ" 3Ó'ò HˆÙ2°4·:±:³<Ó@ˆÙØð	DÙ*¨;Ó7ˆEñ ˜eÕ$à-¨k¨]ð ;Gð GòHðHð øô! ò Ùðûô ò 	DØ4°[°MÀÐCÔCð	Dús#   …A% Á
A4Á%	A1Á0A1Á4BÂBc                 óV  ‡— ddl mŠ ddlm}  | ‰dd«      «      s| S dt        fˆfd„}| € |«       S t        t	        | «      j                  d	«      «      D �cg c]  }|j                  «       d
k(  r |«       n|‘Œ  }}d	j                  t        j                  |«      «      xs dS c c}w )a¾  Resolve ``origin`` to a concrete target for creates made FROM a cron run (the creating
    session is ephemeral, so by fire time there is no origin). Non-cron sessions: unchanged.
    Cron sessions: ``origin`` (or omitted) becomes the creating run's ``platform:chat_id[:thread]``
    from HERMES_CRON_AUTO_DELIVER_*, or ``local`` when it has no concrete target; other
    elements pass through. Otherwise the scheduler would guess a home channel.r   )r,   )Úis_truthy_valueÚHERMES_CRON_SESSIONrF   r   c                  ó¾   •—  ‰dd«      j                  «       }  ‰dd«      j                  «       }| r|sy ‰dd«      j                  «       }|r
| › d|› d|› �S | › d|› �S )NÚ!HERMES_CRON_AUTO_DELIVER_PLATFORMrF   Ú HERMES_CRON_AUTO_DELIVER_CHAT_IDrG   Ú"HERMES_CRON_AUTO_DELIVER_THREAD_IDrK   )rM   )r5   r6   r8   r,   s      €r'   Ú_creator_targetz6_resolve_cron_context_deliver.<locals>._creator_target(  sy   ø€ Ù"Ð#FÈÓK×QÑQÓSˆÙ!Ð"DÀbÓI×OÑOÓQˆÙ™wØÙ#Ð$HÈ"ÓM×SÑSÓUˆ	Ù6?�(�˜1˜W˜I Q y kÐ2Ð\ÈÀzÐQRÐSZÐR[ÐE\Ð\rB   NrY   rL   )r;   r,   Úutilsrœ   r   r{   r_   rN   r�   r   rƒ   )r�   rœ   r¢   ÚpÚresolvedr,   s        @r'   Ú_resolve_cron_context_deliverr¦     s¡   ø€ õ 8Ý%Ù™?Ð+@À"ÓEÔFØˆð]œSõ ]ð €ÙÓ Ð ÜKZÔ[^Ð_fÓ[g×[mÑ[mÐnqÓ[rÓKsÖtÀa Q§W¡W£Y°(Ò%:‘Ô!ÀÑAÐt€HÐtà�8‰8”D—M‘M (Ó+Ó,Ò4°Ð4ùò us   Á#B&ÚproviderÚbase_urlc                 óR  — t        |d¬«      }|syt        | «      }|s	 y	 ddlm}m}m} ddlm} ddlm}m	}	 |j                  «       dk(  ry ||«      rE	  ||«      }
|
r |	|
xs i j                  dd«      «      nd}|r
 |||«      ryd|›d|›d|xs d› d�S 	  ||«      }t        |t        «      r|j                  |«      nd} |	|rt        |dd«      nd«      }|r
 |||«      ryd|›d|›d�S # t        $ r	 d	|›d
�cY S w xY w# t        $ r d}
Y Œ¶w xY w# t        $ r |}Y Œ‚w xY w)ae  Reject pairing a named provider's stored credential with an off-host base_url (a
    prompt-injected job could exfil the key). Allowed: no override; bare 'custom' (pure BYOK,
    key derived from the base_url); an override whose host matches the named provider's own
    endpoint. Everything else fails closed. Returns an error string if blocked, else None.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¨   rF   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­   r£   r®   r¯   r   rN   r   r   r   Úgetattr)r§   r¨   ÚbuÚprovrª   r«   r¬   r­   r®   r¯   ÚcpÚcfg_hostr¥   ÚpconfigÚ
known_hosts                  r'   Ú_validate_cron_base_urlr¼   7  s•  € ô 
' xÀdÔ	K€BÙØÜ(¨Ó2€DÙðCð	DðW÷	(ñ 	(õ 	6ßBð ‡z�zƒ|�xÒØÙ  Ô&ð	Ù+¨DÓ1ˆBñ IKÑ$ b¢h¨B§^¡^°JÀÓ%CÔDÐPRˆÙÑ-¨b°(Ô;Øà˜�vÐ:¸4¸(ð C$à$,Ò$9°	Ð#:¸"ð>ð	?ðÙ-¨dÓ3ˆô 2<¸HÄcÔ1JÐ×#Ñ# HÔ-ÐPT€GÙ"ÑQX¤7¨7Ð4HÈ"Ô#MÐ^`Óa€JÙÑ+¨B°
Ô;Øð �B�6Ð6°t°hð ?Vð 	WðXøô7 ò WØCÀDÀ8È:ÐVÒVðWûô ò 	ØŠBð	ûô ò ØŠðús5   ¡C2 ÁD ÂD Ã2DÄDÄDÄDÄD&Ä%D&Úscriptc                 óZ  — | r| j                  «       syddlm} | j                  «       } |«       dz  }|j                  d«      st	        |«      dk\  r|d   dk(  rd	|› d
|›d|› d�S ddlm} |j                  dd¬«       ||z  } |||«      rd|›�S |j                  «       s	d|› d|› d�S y)u´   Scripts must be relative paths within HERMES_HOME/scripts/ (absolute / ~ / drive-letter
    rejected â€” prompt-injection guard). Error string if blocked, else None; empty = clear.Nr   )Úget_hermes_homeÚscripts)rp   Ú~rZ   r\   rK   z Script path must be relative to z'/. Got absolute or home-relative path: z. Place scripts in z/ and use just the filename.)Úvalidate_within_dirT)ÚparentsÚexist_okz9Script path escapes the scripts directory via traversal: zScript file not found: z. Create it in z/ first.)	rM   Úhermes_constantsr¿   r`   ra   Útools.path_securityrÂ   ÚmkdirÚis_file)r½   r¿   ÚrawÚscripts_dirrÂ   Úresolved_scripts         r'   Ú_validate_cron_script_pathrÌ   m  sß   € ñ ˜Ÿ™œØå0Ø
�,‰,‹.€CÙ!Ó# iÑ/€KØ
‡~�~�jÔ!¤c¨#£h°!¢m¸¸A¹À#ºà.¨{¨mð <3Ø36°'ð : Ø +˜}Ð,HðJð	Kõ
 8Ø×Ñ˜d¨TÐÔ2Ø! CÑ'€OÙ˜?¨KÔ8ØJÈ3È'ÐRÐRØ×"Ñ"Ô$à% oÐ%6ð 7Ø'˜=¨ð2ð	3ð rB   Úcontext_fromÚ
continuityc                 óÌ   — t        | «      }t        d„ |D «       «      }|r|s|j                  d«       n'|s%|r#|D �cg c]  }|j                  «       dk7  sŒ|‘Œ }}|xs dS c c}w )zVcontinuity=True ensures "self" is in context_from; False removes it; others untouched.c              3   óB   K  — | ]  }|j                  «       d k(  –— Œ y­w)ÚselfN)rN   )rw   Úrs     r'   ry   z$_apply_continuity.<locals>.<genexpr>�  s   è ø€ Ò5¨1�1—7‘7“9 Õ&Ñ5ùs   ‚rÑ   N)r{   Úanyr^   rN   )rÍ   rÎ   ÚrefsÚhas_selfrÒ   s        r'   Ú_apply_continuityrÖ   ˆ  sc   € ô ˜<Ó(€DÜÑ5°Ô5Ó5€HÙ™(Ø�‰�FÕÙ™HØÖ7�a 1§7¡7£9°Ó#6’Ð7ˆÐ7ØŠ<�4Ðùò 8s   ¼A!ÁA!rÔ   c                 ó¢   — ddl m} | D ]D  }t        |t        «      r"|j	                  «       j                  «       dk(  rŒ5 ||«      rŒ>d|› d�c S  y)u­   Error string if any non-"self" ref names a missing job ("self" resolves to the job's
    own id at run time, so it can't be checked â€” the job doesn't exist yet at create).r   )Úget_jobrÑ   zcontext_from job 'z>' not found. Use cronjob(action='list') to see available jobs.N)r   rØ   r   r   rM   rN   )rÔ   Ú_get_jobÚref_ids      r'   Ú_validate_context_from_refsrÛ   •  sa   € õ .Øò EˆÜ�fœcÔ" v§|¡|£~×';Ñ';Ó'=ÀÒ'GØÙ˜Õà$ V Hð -Dð DòEð	Eð rB   )r½   Úreasoning_effortrU   rV   Úmonitor_staterW   Úenabled_toolsetsÚworkdirc           	      ó  ‡ ‡— ddl m} t        ‰ j                  d«      xs d«      }t	        ‰ j                  d«      ‰ j                  d«      «      }t        ‰ j                  d«      xs d«      }t        ‰ j                  d	«      xs |d d
 xs |r|d   ndxs |xs d«      }i d|“d	|“d|r|d   nd “d|“dt        |«      dkD  r|d d dz   n|“d‰ j                  d«      “d‰ j                  d«      “dt        t        ‰ j                  d«      xs d«      j                  «       «      “d‰ j                  d«      “d‰ j                  d«      xs d“dt        ‰ «      “d‰ j                  dd«      “d‰ j                  d«      “d‰ j                  d«      “d‰ j                  d«      “d‰ j                  d«      “d‰ j                  d«      “‰ j                  d«      ‰ j                  d «      r |‰ d    d!d!¬"«      n‰ j                  d «      ‰ j                  d#d!«      t        ‰ «      ‰ j                  d$«      ‰ j                  d%«      d&œ¥}t        D ]#  }‰ j                  |«      sŒ|d'k(  rd!n‰ |   ||<   Œ% ‰ j                  d(«      xs g }t        |t        «      r|g}ˆ fd)„Št        ˆfd*„|D «       «      rd!|d+<   |D �	cg c]  }	 ‰|	«      rŒ|	‘Œ }
}	|
r|
|d(<   t        ‰ j                  d,«      t        «      r‰ d,   |d,<   |S c c}	w )-Nr   )Úredact_sensitive_textÚpromptrF   r|   r}   Úidr±   Únameé2   zcron jobÚjob_idÚprompt_previewéd   z...Úmodelr§   Úpinnedr¨   r   Úschedule_displayú?rl   r�   rG   Únext_run_atÚlast_run_atÚlast_statusÚlast_delivery_errorÚlast_delivery_unverifiedÚlast_fire_errorÚ
last_errorT)ÚforceÚredact_url_credentialsÚenabledÚ	paused_atÚpaused_reason)rò   ró   rö   Ústater÷   rø   rW   rÍ   c                 ó„   •— t        | «      j                  «       j                  «       dk(  xs | ‰j                  d«      k(  S )NrÑ   rã   )r   rM   rN   r   )rÒ   rC   s    €r'   ú<lambda>z_format_job.<locals>.<lambda>Ó  s1   ø€ œ˜A›Ÿ™›×,Ñ,Ó.°&Ñ8ÒN¸AÀÇÁÈÃÑ<N€ rB   c              3   ó.   •K  — | ]  } ‰|«      –— Œ y ­wrv   r€   )rw   rÒ   Úis_selfs     €r'   ry   z_format_job.<locals>.<genexpr>Ô  s   øè ø€ Ò
+˜!‰7�1�:Ñ
+ùs   ƒrÎ   Úattach_to_session)Úagent.redactrá   r   r   r„   ra   ÚboolrM   rr   r
   Ú_FORMAT_JOB_OPTIONAL_KEYSr   rÓ   )rC   rá   râ   r}   ræ   rä   ÚresultÚkeyÚstored_refsrÒ   Úexternal_refsrý   s   `          @r'   Ú_format_jobr  ©  s@  ù€ Ý2ä�—‘˜Ó"Ò( bÓ)€FÜ˜sŸw™w wÓ/°·±¸Ó1BÓC€FÜ�—‘˜“Ò+ )Ó,€FÜˆs�w‰w�v‹Òf &¨¨" +Òf¹v°&¸²)È2ÒfÐRXÒfÐ\fÓg€DðØ�&ðà�ðð 	™f�˜’¨$ðð 	�&ð	ð
 	´#°f³+ÀÒ2C˜&  #˜,¨Ò.Èðð 	�—‘˜Ó!ðð 	�C—G‘G˜JÓ'ðð 	”$”s˜3Ÿ7™7 7Ó+Ò1¨rÓ2×8Ñ8Ó:Ó;ðð 	�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Ð'<Ó=ð#ð$ 	# C§G¡GÐ,FÓ$Gð%ð& Ÿ7™7Ð#4Ó5ð �W‰W�\Ô"ñ ,Ø�Ñ TÀ$õ
à(+¯©°Ó(=Ø—7‘7˜9 dÓ+ä$ SÓ)Ø—W‘W˜[Ó)ØŸ™ Ó1ò7€Fô: )ò BˆØ�7‰7�3�<Ø"%¨Ò"3™$¸¸S¹ˆF�3ŠKðBð —'‘'˜.Ó)Ò/¨R€KÜ�+œsÔ#Ø"�mˆÛN€GÜ
Ó
+˜{Ô
+Ô+Ø#ˆˆ|ÑØ +Ö>˜1±7¸1µ:’QÐ>€MÐ>ÙØ!.ˆˆ~ÑÜ�#—'‘'Ð-Ó.´Ô5Ø&)Ð*=Ñ&>ˆÐ"Ñ#Ø€Mùò ?s   Ê?LËLÚpluralc                 ó|   — 	 ddl m}  |«       }|du r| rdnd}dd|› d	�d
œS d|€diS diS # t        $ r ddicY S w xY w)a½  ``gateway_running``/``warning`` payload via the shared CLI helper so CLI and tool agree
    on "scheduler active". False -> warning (no gateway process), None -> probe failed.

    Thin adapter over the shared CLI helper ``hermes_cli.cron._builtin_gateway_liveness`` (#87033) so the
    CLI and this tool can never disagree about what "scheduler active" means. ``plural`` rewords the warning
    for multi-job results (the ``list`` action).
    r   )Ú_builtin_gateway_livenessÚgateway_runningNFzthese jobs are savedzthis job is savedu&   The Hermes gateway is not running â€” z˜ but will NOT fire until the gateway is started (hermes gateway install / hermes gateway start). Tell the user the task is scheduled but not active yet.)r
  ÚwarningT)Úhermes_cli.cronr	  r   )r  r	  Ú_gwÚsubjects       r'   Ú_gateway_liveness_noticer  Þ  s|   € ð)Ý=Ù'Ó)ˆð ˆe�|Ù,2Ñ(Ð8Kˆà$à8¸¸	ð BJð Jñ
ð 	
ð  s {˜tÐ=Ð=¸Ð=Ð=øô ò )Ø! 4Ð(Ò(ð)ús   ‚+ «;º;rv   )NN)F)(Ú__doc__r   Úloggingr   r   Útypingr   r   r   r   r	   r   r
   r!   Ú	getLoggerr<   r#   r   r   r(   rA   rS   rf   rŒ   rj   rr   r{   r„   rŠ   rŽ   rš   r¦   r¼   rÌ   rÖ   rÛ   r  r  r   r  r€   rB   r'   ú<module>r     sò  ðñó Û ß (ß 3Õ 3å )ã ð 
ˆ×	Ñ	Ð0Ó	1€ð
 Ð ð"OØ�C˜˜c 3˜h™¨Ð-Ñ.ð"Oà	ó"OðL 26ñ0Ø�C˜˜c 3˜h™¨Ð-Ñ.ð0àˆd�3˜�8‰nÑó0ðf#S  S¨# X¡ð #S¸hÀs¹mð #SÐPXÐY\ÑP]ó #SðL(˜d 3¨ 8™nð (¸HÀS¹Mð (ÈdÐSVÉió (ðVØ�c‰]ðà˜S‘Mðð ˜#‘ðð $)óð&E˜˜c 3˜h™ð E¨Có Eð=˜3ð = 4¨¡9ó =ñO˜X c™]ð O¸8ÀC¹=ð OÐTXÐY\ÑT]ó Oð Y^ò ¨°#©ð ÐQUð ÐbjÐknÑboó ð& Cð &¨H°S©Mó &ð¨°©ð ¸(À3¹-ó ð85¨8°C©=ð 5¸XÀc¹]ó 5ð43XØ�s‰mð3XØ'/°¡}ð3XØ9AÀ#¹ó3Xðl x°¡}ð ¸À#¹ó ð6
Ø˜5  d¨3¡i Ñ0Ñ1ð
àð
à! $ s¡)Ñ,ó
ð d¨3¡ið °H¸S±Mó ð@Ð ð
2�T˜#˜s˜(‘^ð 2¨¨S°#¨X©ó 2ñj> Tð >°dô >rB   