Ë
    ãß²jð  ã                  ó´  — U d Z ddlm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 ddlmZ ddlmZ ddlmZmZmZ dd	lmZmZ 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&m'Z'  ejP                  e)«      Z*dZ+dZ,d†d„Z-d‡d„Z.d†d„Z/d†d„Z0dˆd„Z1ed†d„«       Z2ed†d„«       Z3 e4h d£«      Z5 G d„ de6«      Z7d‰d„Z8 e4ddh«       e4dh«      dœZ9de:d<   dŠd„Z;d‹d„Z<dŒd „Z=d�d!„Z>dŽd"„Z?d�d#„Z@d�d$„ZAd‘d%„ZBd’d&„ZCd‹d'„ZDe	d(d)œd“d*„«       ZEd”d+„ZFd•d,„ZGd–d-„ZHd—d.„ZId˜d/„ZJd™d0„ZKd(d1œdšd2„ZLd›d3„ZMdœd4„ZNd�džd5„ZOd6d6d6d(d(d(d7œZPdŸd8„ZQd�d d9„ZR eSd:j©                  «       «      ZU eSd;j©                  «       «      ZV eSd<j©                  «       «      ZWd=ZXd>ZY eSd?j©                  «       «      ZZd@Z[d¡dA„Z\d¢dB„Z] e4dCdDh«      Z^d†dE„Z_dFdGdHœdIdJdHœdKœZ`d£dL„ZadMZbdNacdOe:dP<   d(add†dQ„ZedRZfdNagdOe:dS<   i ZhdTe:dU<   d¤dV„Zi e;dW«      d�dX„«       Zj e;dY«      d�dZ„«       Zk e;d[«      d�d\„«       Zl e;d]«      d�d^„«       Zm e;d_«      d�d`„«       Zn e;da«      d�db„«       Zo e;dc«      d�dd„«       Zp e;de«      d�df„«       Zqd¥dg„Zr e;dh«      d�di„«       ZsdjZtd¦dk„Zu e;dl«      d�dm„«       Zv e;dn«      d�do„«       Zwd§dp„Zx e;dq«      d�dr„«       Zyd¨ds„Zzd©dt„Z{ e;du«      d�dv„«       Z| e;dw«      d�dx„«       Z} e4dYduh«      Z~dWe&ejdyfdYe#ekdyfd[eeldzfd]eemd{fd_e%end|fdae$eod}fdce!epd~fdeeeqdfdheesd€fdleevd€fdneewd€fdqe eyd�fdue'e|d‚fdwe"e}dƒffZeD ](  \  Z€Z�Z‚Zƒe€e~v re3ne2Z„ e�j
                  e€d„e�e‚eƒe„¬…«       Œ* y)ªu«  Kanban tools â€” structured tool-call surface for worker + orchestrator agents.

Registered only under the dispatcher (``HERMES_KANBAN_TASK`` set) or when the profile
enables the ``kanban`` toolset. Tools rather than ``hermes kanban`` shell-outs: they run
in the agent's process (reach ``kanban.db`` from a container/SSH terminal backend, no
shlex quoting of JSON metadata, structured-JSON failures). Humans use CLI/dashboard.
é    )ÚannotationsN)Úcontextmanager)ÚAnyÚCallableÚOptional)Úredact_sensitive_text)Ú
judge_goal)Úno_cache_check_fnÚregistryÚ
tool_error)Úcfg_getÚload_config)ÚKANBAN_ATTACH_SCHEMAÚKANBAN_ATTACH_URL_SCHEMAÚKANBAN_ATTACHMENTS_SCHEMAÚKANBAN_BLOCK_SCHEMAÚKANBAN_COMMENT_SCHEMAÚKANBAN_COMPLETE_SCHEMAÚKANBAN_CREATE_SCHEMAÚKANBAN_HEARTBEAT_SCHEMAÚKANBAN_LINK_SCHEMAÚKANBAN_LIST_SCHEMAÚKANBAN_REQUEST_CHANGES_SCHEMAÚKANBAN_REQUEST_REVIEW_SCHEMAÚKANBAN_SHOW_SCHEMAÚKANBAN_UNBLOCK_SCHEMAé2   éÈ   c                 ó  ‡‡— ddl m}   | «       }|ry	 t        «       Šd‰j                  d«      xs g v ry|�yddlmŠ ‰j                  d«      xs i }t        ˆˆfd	„|j                  «       D «       «      S # t        $ r Y yw xY w)
Nr   )Úkanban_toolset_requestedTÚkanbanÚtoolsetsF)Ú_get_platform_toolsÚplatform_toolsetsc              3  ó^   •K  — | ]$  \  }}t        |t        «      rd  ‰‰|d¬«      v –— Œ& y­w)r!   F)Úinclude_default_mcp_serversN)Ú
isinstanceÚlist)Ú.0ÚplatformÚnamesr#   Úconfigs      €€ú7/home/ubuntu/.hermes/hermes-agent/tools/kanban_tools.pyú	<genexpr>z._profile_has_kanban_toolset.<locals>.<genexpr>8   s6   øè ø€ ò 
á�˜%¼
À5Ì$Ô8Oð Ñ+¨F°HÐZ_Ô`Ô`ñ
ùs   ƒ*-)	Útools.kanban_toolset_contextr    r   ÚgetÚhermes_cli.tools_configr#   ÚanyÚitemsÚ	Exception)r    Ú	requestedÚ	platformsr#   r,   s      @@r-   Ú_profile_has_kanban_toolsetr7   %   s‘   ù€ ÝEá(Ó*€IÙØðÜ“ˆà˜Ÿ
™
 :Ó.Ò4°"Ñ5ØØÐ àõ 	@à—J‘JÐ2Ó3Ò9°rˆ	Üô 
à#,§?¡?Ó#4ô
ó 
ð 	
øô ò Ùðús   ”!A7 ¶A7 ¹=A7 Á7	BÂBc                óT   — 	 ddl m}  t        || «      «       S # t        $ r |cY S w xY w)zT``agent.delegation_context.<predicate>()``; ``default`` when it cannot be evaluated.r   )Údelegation_context)Úagentr9   Úgetattrr4   )Ú	predicateÚdefaultr9   s      r-   Ú_delegation_ctxr>   @   s1   € ðÝ,Ø5ŒwÐ)¨9Ó5Ó7Ð7øÜò ØŠðús   ‚ ™'¦'c                 ó   — t        dd«      S )NÚis_delegated_child_contextF©r>   © ó    r-   Ú_is_delegated_child_contextrD   I   s   € ÜÐ7¸Ó?Ð?rC   c                 ó   — t        dd«      S )u�   False for delegate_task children AND for cron jobs fired in-process from
    a worker â€” i.e. whenever HERMES_KANBAN_* is present but not ours.Ú"is_dispatcher_owned_worker_contextTrA   rB   rC   r-   Ú_is_dispatcher_owned_workerrG   M   s   € ô Ð?ÀÓFÐFrC   c                ó‚   — t        «       ryt        j                  j                  d«      rt	        «       r| S t        «       S )z�check_fn core: never for delegate children; dispatcher-spawned env workers
    (HERMES_KANBAN_TASK) per flag; else the profile toolset decides.FÚHERMES_KANBAN_TASK)rD   ÚosÚenvironr0   rG   r7   ©Úto_env_workers    r-   Ú_visiblerN   S   s3   € ô #Ô$ØÜ	‡z�z‡~�~Ð*Ô+Ô0KÔ0MØÐÜ&Ó(Ð(rC   c                 ó   — t        d¬«      S )zKLifecycle tools: dispatcher workers + profiles with the ``kanban`` toolset.TrL   ©rN   rB   rC   r-   Ú_check_kanban_moderQ   ]   s   € ô  $Ô'Ð'rC   c                 ó   — t        d¬«      S )zLBoard-routing tools (kanban_list, kanban_unblock): hidden from task workers.FrL   rP   rB   rC   r-   Ú_check_kanban_orchestrator_moderS   c   s   € ô  %Ô(Ð(rC   >   Úkanban_blockÚkanban_completeÚkanban_request_reviewÚkanban_request_changesc                  ó$   ‡ — e Zd ZdZdˆ fd„Zˆ xZS )Ú_RejectzECarries a finished ``tool_error`` payload out of a validation helper.c                ó6   •— t         ‰| �  t        |«      «       y ©N)ÚsuperÚ__init__r   )ÚselfÚmessageÚ	__class__s     €r-   r]   z_Reject.__init__w   s   ø€ Ü‰Ñœ GÓ,Õ-rC   )r_   Ústr)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r]   Ú__classcell__)r`   s   @r-   rY   rY   t   s   ø„ ÙO÷.ñ .rC   rY   c                ó   — | st        |«      ‚y)z3Reject (as a tool error) unless ``cond`` is truthy.N)rY   )Úcondr_   s     r-   Ú_checkri   {   s   € áÜ�gÓÐð rC   Ú
session_idÚ
project_idÚtitle)Úkanban_createÚkanban_attach_urlzdict[str, frozenset[str]]Ú_UNDECLARED_ARGSc                ó   ‡ — ˆ fd„}|S )zúWrap a handler so every failure is a structured tool error. ``ValueError``
    (invalid board slug, DB validation such as cycle/self-link, ``AttachmentTooLarge``)
    is reported without a traceback; anything else is logged with ``logger.exception``.c                óH   •‡ — t        j                  ‰ «      dˆ ˆfd„«       }|S )Nc                ó&  •— 	 t        j                  ‰«      d   d   }t        |«      t        j	                  ‰t        «       «      z  }t        t        | «      |z
  «      }t        | ‰› ddj                  |«      › ddj                  t        |«      «      › d�«        ‰| fi |¤ŽS # t        $ r}|j                  d   cY d }~S d }~wt        $ rB}t        |t        «      st        j                  ‰› d�«       t!        ‰› d	|› �«      cY d }~S d }~ww xY w)
NÚ
parametersÚ
propertiesz: unknown parameter(s): ú, z. Valid parameters: z. Nothing changed.r   z failedú: )r   Ú
get_schemaÚsetro   r0   Ú	frozensetÚsortedri   ÚjoinrY   Úargsr4   r'   Ú
ValueErrorÚloggerÚ	exceptionr   )r|   Úkwrt   ÚallowedÚunknownÚeÚfnÚ	tool_names         €€r-   Úwrapperz._kanban_handler.<locals>.deco.<locals>.wrapper�   s  ø€ ð7ä%×0Ñ0°Ó;¸LÑIÈ,ÑW�
Ü˜j›/Ô,<×,@Ñ,@ÀÌIËKÓ,XÑX�Ü ¤ T£¨WÑ!4Ó5�Ü˜7�{Ø#˜Ð$<¸T¿Y¹YÀwÓ=OÐ<Pð Q,Ø,0¯I©I´f¸ZÓ6HÓ,IÐ+JÐJ\ð^ô_ñ ˜$‘~ "‘~Ð%øÜò !Ø—v‘v˜a‘yÕ ûÜò 7Ü! !¤ZÔ0Ü×$Ñ$¨	 {°'Ð%:Ô;Ü! Y K¨r°!°Ð"5Ó6Õ6ûð7ús0   ƒB!B% Â%	DÂ.CÂ<DÃDÃ7DÄDÄD©r|   ÚdictÚreturnra   )Ú	functoolsÚwraps)r„   r†   r…   s   ` €r-   Údecoz_kanban_handler.<locals>.deco�   s%   ù€ Ü	�‰˜Ó	õ	7ó 
ð	7ð  ˆrC   rB   )r…   rŒ   s   ` r-   Ú_kanban_handlerr�   ‹   s   ø€ ôð& €KrC   c                ó8   — t        dd«      rt        | › d�«      ‚y)zžA delegate_task child shares the parent's process, so inherited HERMES_KANBAN_*
    env is not proof of ownership: it may report findings but must not mutate.Ú"is_delegated_child_process_contextFzÈ refused: delegate_task child agents are not Kanban run owners. Return findings to the parent agent; the dispatcher worker or an explicitly configured Kanban orchestrator must perform board mutations.N)r>   rY   ©r…   s    r-   Ú _reject_delegated_child_mutationr‘   ¥   s5   € ô Ð;¸UÔCÜØˆkð Kð KóLð 	Lð DrC   c                óz   — | r| S t        «       s
t        «       syt        j                  j	                  d«      xs dS )z�``task_id`` arg or the dispatcher's env var. A delegate child or an
    in-process cron job must never inherit the worker's task id implicitly.NrI   )rD   rG   rJ   rK   r0   )Úargs    r-   Ú_default_task_idr”   ¯   s4   € ñ Øˆ
Ü"Ô$Ô,GÔ,IØÜ�:‰:�>‰>Ð.Ó/Ò7°4Ð7rC   c                óR   — t        | j                  d«      «      }t        |d«       |S )NÚtask_idz:task_id is required (or set HERMES_KANBAN_TASK in the env))r”   r0   ri   )r|   Útids     r-   Ú_require_task_idr˜   ¹   s%   € Ü
˜4Ÿ8™8 IÓ.Ó
/€CÜ
ˆ3ÐLÔMØ€JrC   c                óˆ   — t         j                  j                  d«      | k(  rt         j                  j                  |«      S dS )zC``$var`` only when this worker is scoped to ``task_id``; else None.rI   N)rJ   rK   r0   )r–   Úvars     r-   Ú_own_task_envr›   ¿   s0   € ä"$§*¡*§.¡.Ð1EÓ"FÈ'Ò"QŒ2�:‰:�>‰>˜#ÓÐ[ÐW[Ð[rC   c                óX   — t        | d«      }	 |rt        |«      S dS # t        $ r Y yw xY w)z=This worker's dispatcher run id when it is scoped to task_id.ÚHERMES_KANBAN_RUN_IDN)r›   Úintr}   )r–   Úraws     r-   Ú_worker_run_idr    Ä   s7   € ä
˜Ð!7Ó
8€CðÙŒs�3‹xÐ( DÐ(øÜò Ùðús   Ž › �	)¨)c                ó:   — t        | d«      }|ri |xs i ¥d|i¥S |S )zBAdd trusted worker session id metadata for this worker's own task.ÚHERMES_SESSION_IDÚworker_session_id)r›   )r–   Úmetadatarj   s      r-   Ú_stamp_worker_session_metadatar¥   Í   s/   € ä˜wÐ(;Ó<€JÙDNÐ@ˆxŠ~˜2Ð@Ð 3°ZÑ@Ð\ÐT\Ð\rC   c                óv   — t         j                  j                  d«      }|r| |k7  rt        d|› d| › d�«      ‚yy)aó  A dispatcher-spawned worker may only mutate its own HERMES_KANBAN_TASK; a
    prompt-injected ``task_id`` must not corrupt sibling/cross-tenant runs.
    Orchestrators (toolset enabled, no env task) legitimately route child tasks.

    Tools like ``kanban_complete`` / ``kanban_block`` / ``kanban_heartbeat`` mutate run-lifecycle state, so
    a buggy or prompt-injected worker that passed an explicit ``task_id`` for some other task could corrupt
    sibling or cross-tenant runs (see #19534).
    rI   zworker is scoped to task z; refusing to mutate zf. Use kanban_comment to hand off information to other tasks, or kanban_create to spawn follow-up work.N©rJ   rK   r0   rY   )r—   Úenv_tids     r-   Ú_enforce_worker_task_ownershipr©   Ó   sQ   € ô �j‰j�n‰nÐ1Ó2€GÙ�3˜'’>ÜØ'¨ yÐ0EÀcÀUð K`ð aóbð 	bð "€wrC   c                óÈ   — t        | «       t        |«      }t        |«       | t        v r8t        j
                  j                  d«      rt        |«      €t        | › d�«      ‚|S )aÌ  Worker mutation preamble, in order: delegate-child rejection, task id
    resolution, task-scope ownership, run-identity proof. Returns the task id.

    A dispatcher-spawned worker (``HERMES_KANBAN_TASK`` set) that cannot name
    its run id is refused on the run-lifecycle mutations: ``expected_run_id=None``
    would silently skip the run-ownership CAS in ``kanban_db`` (``complete_task`` /
    ``block_task`` / ``request_review`` / ``request_changes`` only append
    ``AND current_run_id = ?`` when the value is not ``None``), so an unbound
    stale worker could complete a card a live successor owns. This mirrors
    ``agent/kanban_stop.py``, which already treats an unbound run id as unknown
    and fails closed. CLI / human / orchestrator paths (no ``HERMES_KANBAN_TASK``)
    legitimately pass ``expected_run_id=None`` and are unaffected. Non-lifecycle
    worker tools (heartbeat / attach / attach_url) do not terminate a run and are
    not gated here.
    rI   a@   refused: this worker cannot resolve its HERMES_KANBAN_RUN_ID, so it cannot prove ownership of the card's current run. A stale or unbound worker must not terminate a run a live successor owns. Re-run through the dispatcher so the run id is pinned, or use an orchestrator/CLI path that passes an explicit expected_run_id.)	r‘   r˜   r©   Ú_RUN_LIFECYCLE_TOOLSrJ   rK   r0   r    rY   )r…   r|   r—   s      r-   Ú_worker_guardr¬   ã   sf   € ô  % YÔ/Ü
˜4Ó
 €CÜ" 3Ô'àÔ)Ñ)Ü�J‰J�N‰NÐ/Ô0Ü˜3ÓÐ'äØˆkð ð ó
ð 	
ð €JrC   c                ó^   — t         j                  j                  d«      rt        | › d�«      ‚y)z�The check_fn already hides orchestrator tools from workers; this catches
    a stale registration or test harness routing a worker here anyway.rI   zÅ is orchestrator-only; dispatcher-spawned workers must use kanban_complete, kanban_request_review, kanban_request_changes, kanban_block, kanban_heartbeat, or kanban_comment for their assigned task.Nr§   r�   s    r-   Ú_require_orchestrator_toolr®     s:   € ô 
‡z�z‡~�~Ð*Ô+ÜØˆkð Kð KóLð 	Lð ,rC   F©Úquiet_closec             #  óì   K  — ddl m} ddl m} |j                  | ¬«      }	 ||f–— 	 |j	                  «        y# t
        $ r |s‚ Y yw xY w# 	 |j	                  «        w # t
        $ r |s‚ Y w w xY wxY w­w)a  ``with _board(slug) as (kb, conn)``; lazy import so the module loads in non-kanban
    contexts. ``board=None`` keeps the env/symlink resolution chain; an explicit slug
    overrides it per call. ``quiet_close`` swallows close() errors (best-effort bridges).r   ©Ú	kanban_db)Úkanban_db_connect)ÚboardN)Ú
hermes_clir³   r´   ÚconnectÚcloser4   )rµ   r°   ÚkbÚkbcÚconns        r-   Ú_boardr¼     s{   è ø€ õ
 +Ý3Ø�;‰;˜Uˆ;Ó#€DðØ�$ˆhŠð	Ø�J‰J�LøÜò 	ÙØñ ð	ûð	Ø�J‰J�LøÜò 	ÙØñ ð	ÿsZ   ‚A4¢A ©: ¹A4ºA	ÁA4ÁA	Á	A4ÁA1ÁAÁA1ÁA.Á+A1Á-A.Á.A1Á1A4c                óN   — | j                  ||«      }t        |d ud|› d�«       |S )Nztask z
 not found)Úget_taskri   )r¹   r»   r—   Útasks       r-   Ú_existing_taskrÀ   "  s/   € Ø�;‰;�t˜SÓ!€DÜ
ˆ4�tÐ˜u S E¨Ð4Ô5Ø€KrC   c                 ó4   — t        j                  ddi| ¥«      S )NÚokT)ÚjsonÚdumps)Úfieldss    r-   Ú_okrÆ   (  s   € Ü�:‰:�t˜TÐ, VÐ,Ó-Ð-rC   c                ó    — | j                  ||«      }| j                  ||«      }t        d||r|j                  nd|r|j                  n|dœ|¤ŽS )zpSuccess payload reporting where the task actually landed (routing may
    not leave it in the requested status).N)r–   Úrun_idÚstatusrB   )Ú
latest_runr¾   rÆ   ÚidrÉ   )r¹   r»   r—   Údefault_statusÚextraÚrunÚlandeds          r-   Ú
_ok_landedrÐ   ,  sY   € ð �-‰-˜˜cÓ
"€CØ�[‰[˜˜sÓ#€FÜð L�s©S 3§6¢6°dÙ'-�f—m’m°>ñLØEJñLð LrC   c                ó.   — t        t        | «      d¬«      S )NT©Úforce)r   ra   ©Úvalues    r-   Ú_redactrÖ   5  s   € Ü ¤ U£°4Ô8Ð8rC   c                ó    — | rt        | «      S | S r[   )rÖ   rÔ   s    r-   Ú_redact_optrØ   9  s   € Ù"Œ7�5‹>Ð-¨Ð-rC   c                óœ   — 	 t        j                  t        t        j                  | «      d¬«      «      S # t         j                  $ r Y yw xY w)zDRedact via a JSON round-trip; None if the result can't be re-parsed.TrÒ   N)rÃ   Úloadsr   rÄ   ÚJSONDecodeError©r¤   s    r-   Ú_redact_metadatarÝ   =  s?   € ðÜ�z‰zÔ/´·
±
¸8Ó0DÈDÔQÓRÐRøÜ×Ñò Ùðús   ‚25 µAÁ
A©Ústripc          	     ó8  — | €yt        | t        «      r| g} t        | t        t        f«      s&t	        |› d|› dt        | «      j                  › �«      ‚|r@| D �cg c]5  }t        |«      j                  «       sŒt        |«      j                  «       ‘Œ7 } }| S c c}w )z‚Accept a single string (convenience) or a list/tuple; with ``strip`` the
    items are stringified, stripped, and empties dropped.Nz must be a list of z, got )r'   ra   r(   ÚtuplerY   Útyperb   rß   )rÕ   ÚnameÚwhatrß   Úxs        r-   Ú_coerce_str_listræ   E  sŠ   € ð €}ØÜ�%œÔØ�ˆÜ�eœd¤E˜]Ô+Ü˜˜Ð1°$°°v¼dÀ5»k×>RÑ>RÐ=SÐTÓUÐUÙØ).ÖA A´#°a³&·,±,µ.”�Q“—‘•ÐAˆÐAØ€Lùò Bs   ÁBÁ8Bc                óp   — t        | d u xs t        | t        «      dt        | «      j                  › �«       y )Nz%metadata must be an object/dict, got )ri   r'   rˆ   râ   rb   rÜ   s    r-   Ú_require_dict_metadatarè   S  s3   € Ü
ˆ8�tÐÒ9œz¨(´DÓ9Ø2´4¸³>×3JÑ3JÐ2KÐLõNrC   c                óî   — t        | «       | €i n| } | j                  d«      }t        |t        t        f«      r7d„ g |¢|¢D «       }t        t
        j                  d„ |D «       «      «      | d<   | S || d<   | S )a  Fold ``artifacts`` into ``metadata["artifacts"]`` (merged with, never overwriting, a
    list the worker passed manually). Artifacts ride inside metadata so the completed-event
    payload needs no DB schema change; the gateway notifier uploads each as an attachment.Ú	artifactsc              3  óN   K  — | ]  }t        |«      j                  «       –— Œ y ­wr[   )ra   rß   )r)   Úitems     r-   r.   z#_merge_artifacts.<locals>.<genexpr>`  s   è ø€ ÒH¨”#�d“)—/‘/×#ÑHùs   ‚#%c              3  ó&   K  — | ]	  }|sŒ|–— Œ y ­wr[   rB   )r)   Úss     r-   r.   z#_merge_artifacts.<locals>.<genexpr>a  s   è ø€ Ò2J¸Ê´1Ñ2Jùs   ‚Š)rè   r0   r'   r(   rá   rˆ   Úfromkeys)r¤   rê   ÚexistingÚmergeds       r-   Ú_merge_artifactsrò   X  s   € ô ˜8Ô$ØÐ%‰r¨8€HØ�|‰|˜KÓ(€HÜ�(œT¤5˜MÔ*ÙHÐ0G°(Ð0G¸YÐ0GÔHˆÜ $¤T§]¡]Ñ2J¸fÔ2JÓ%JÓ Kˆ�Ñð €Oð !*ˆ�ÑØ€OrC   c                ó„   — | j                  |«      }t        |xr t        |«      j                  «       |xs |› d�«       |S )z.``args[name]``; rejects when missing or blank.z is required)r0   ri   ra   rß   )r|   rã   r_   rÕ   s       r-   Ú_require_textrô   g  s<   € à�H‰H�T‹N€EÜ
ˆ5Ò'”S˜“Z×%Ñ%Ó'¨Ò)I°t°f¸LÐ4IÔJØ€LrC   T)ÚtrueÚ1ÚyesÚfalseÚ0Únoc                óø   — | j                  |«      }|�t        |t        «      rt        |«      S t        j                  t	        |«      j                  «       j                  «       «      }t        |d u|› d�«       |S )Nz$ must be a boolean or 'true'/'false')r0   r'   ÚboolÚ_BOOL_WORDSra   rß   Úlowerri   )r|   rã   rÕ   Úparseds       r-   Ú_parse_bool_argr   q  sg   € Ø�H‰H�T‹N€EØ€}œ
 5¬$Ô/Ü�E‹{ÐÜ�_‰_œS ›Z×-Ñ-Ó/×5Ñ5Ó7Ó8€FÜ
ˆ6˜Ð $ Ð'KÐLÔMØ€MrC   c                ó    — | �t        | «      S |S r[   )rž   )rÕ   r=   s     r-   Ú_opt_intr  z  s   € ØÐ*Œ3ˆu‹:Ð7°Ð7rC   z×id title body assignee status tenant priority workspace_kind workspace_path created_by created_at started_at completed_at result current_run_id model_override provider_override completion_contract last_failure_errorz¯id title assignee status priority tenant workspace_kind workspace_path project_id created_by created_at started_at completed_at current_run_id model_override provider_overridezDid profile status outcome summary error metadata started_at ended_at)ÚauthorÚbodyÚ
created_at)ÚkindÚpayloadr  rÈ   z@id filename content_type size uploaded_by stored_path created_at)rÉ   Úworkspace_kindÚworkspace_pathrk   c                óJ   — |D �ci c]  }|| �t        | |«      nd“Œ c}S c c}w )zF``{name: getattr(obj, name)}``; every value None when ``obj`` is None.N)r;   )Úobjr+   Úns      r-   Ú_fieldsr  �  s'   € àEJÖKÀˆA # /Œw�s˜AŒ°tÑ;ÒKÐKùÒKs   … c                óÈ   — | j                  ||j                  «      }| j                  ||j                  «      }i t        |t        «      ¥||t        |«      t        |«      dœ¥S )N)ÚparentsÚchildrenÚparent_countÚchild_count)Ú
parent_idsrË   Ú	child_idsr  Ú_TASK_SUMMARY_FIELDSÚlen)r¹   r»   r¿   r  r  s        r-   Ú_task_summary_dictr  ’  s_   € Ø�m‰m˜D $§'¡'Ó*€GØ�|‰|˜D $§'¡'Ó*€HðDÜ
�$Ô,Ó
-ðDØ:AÈxÜ˜G›´S¸³]òDð DrC   Ú
dependencyÚneeds_inputc                 óf   — 	 ddl m}   | d«      \  }}|duxr t        |«      S # t        $ r Y yw xY w)zá``judge_goal`` fails open (no auxiliary model -> ``"continue"``), which is
    indistinguishable from "not done yet" and would wedge every goal_mode
    worker; so the gate is enforced only when a judge is actually reachable.r   )Úget_text_auxiliary_clientÚ
goal_judgeFN)Úagent.auxiliary_clientr  r4   rü   )r  ÚclientÚmodels      r-   Ú_goal_judge_availabler   Ÿ  sB   € ðÝDÙ1°,Ó?‰ˆ�ð ˜ÐÒ-¤$ u£+Ð-øô ò Ùðús   ‚$ ¤	0¯0uì   Goal completion rejected: judge ruled the goal unachievable â€” {reason}. The task will NOT complete silently. Either re-scope the task with kanban_edit, or record the block with kanban_block and hand the decision to a human / reviewer.zçGoal completion rejected by judge: {reason}. To proceed, either: (1) provide explicit acceptance evidence in your summary matching the task's criteria, or (2) create continuation tasks with parents=[{tid}] and keep this task alive.)ÚblockedÚcontinueuŽ   Goal review handoff rejected: judge ruled the goal unachievable â€” {reason}. Record the block with kanban_block instead of requesting review.zxGoal review handoff rejected by judge: {reason}. Provide acceptance evidence matching the card before requesting review.)rU   rV   c                ó:  — |r|j                   r
t        «       sy	 ddlm}m}m}  |«       rdn
 |d|› �«      }	 t        |j                  › d|j                  xs d› �j                  «       |j                  «       ¬«      \  }}	}
}
}|�	 ||«       	 |rt        j                  d|	«       y|dk(  ry|dk(  rdnd}t        t        |    |   j                  |	|¬«      «      ‚# |�	 ||«       w w xY w# t        $ r"}t        j                  d|d	¬
«       Y d}~yd}~ww xY w)a'  Goal-mode pre-handoff judge gate: a worker must not complete / request
    review before acceptance criteria are met. ``blocked`` gets its own
    guidance; any other non-``done`` verdict gets the ``continue`` guidance.
    A broken judge fails open (logged) so it cannot permanently wedge work.Nr   )Úget_affinity_scopeÚreset_affinity_scopeÚset_affinity_scopezkanban:z

Ú )ÚgoalÚlast_responsez7goal judge check failed, allowing lifecycle handoff: %sT©Úexc_infoz7goal judge unreachable (%s), allowing lifecycle handoffÚdoner!  r"  )Úreasonr—   )Ú	goal_moder   Úagent.portal_tagsr$  r%  r&  r	   rl   r  rß   r4   r~   ÚwarningrY   Ú_GOAL_GATE_MESSAGESÚformat)r…   r¿   r—   Úevidencer$  r%  r&  Úaffinity_tokenÚverdictr-  Ú_Útransport_failedÚ	judge_excÚkeys                 r-   Ú
_goal_gater:  ¿  s8  € ñ
 �t—~’~Ô-BÔ-DØð÷ 	cÑbÙ!3Ô!5™Ñ;MÐPWÐX[ÐW\ÈoÓ;^ˆð	5Ü6@ØŸ
™
�| 4¨¯	©	ª°RÐ'8Ð9×?Ñ?ÓAÐQY×Q_ÑQ_ÓQaô7cÑ3ˆG�V˜Q Ð#3ð Ð)Ù$ ^Õ4ñ
 ô 	�‰ÐPÐRXÔYØØ�&ÒØØ )Ò+‰)°€CÜ
Ô% iÑ0°Ñ5×<Ñ<ÀFÐPSÐ<ÓTÓ
UÐUøð Ð)Ù$ ^Õ4ð *ûäò Ü�‰ØEÀyÐ[_ð 	ô 	aäûðús/   ›C/ ºAC ÂC/ ÃC,Ã,C/ Ã/	DÃ8DÄDg      N@g        ÚfloatÚ_auto_heartbeat_last_attemptc            	     óø  — t         j                  j                  d«      } t        j                  «       }| r|t
        z
  t        k  ryt        «       ry|a	 ddlm	} t        dd¬«      5 \  }}|j                  dt         j                  j                  d	«      if|j                  dt        | «      d
œff}d}|D ])  \  }}|j                  }		 t         ||| fi |¤Ž«      xr |}Œ+ 	 ddd«       |S # t         $ r+}
d}t"        sdat$        j'                  d| |
«       Y d}
~
Œfd}
~
wt(        $ r t$        j+                  d|	d¬«       d}Y ŒŽw xY w# 1 sw Y   S xY w# t(        $ r t$        j+                  dd¬«       Y yw xY w)zþClaim extension + board heartbeat for the current worker; True iff both writes
    succeed. ``HERMES_KANBAN_RUN_ID`` pins the run row so a reclaimed stale run is not
    heartbeated; ``HERMES_KANBAN_CLAIM_LOCK`` absent -> default claimer (local workers).rI   Fr   ©Úkanban_db_dispatchNTr¯   ÚclaimerÚHERMES_KANBAN_CLAIM_LOCK©ÚnoteÚexpected_run_ida`  kanban auto-heartbeat for task %s refused (%s): this process carries HERMES_DELEGATED_CHILD_CONTEXT together with HERMES_KANBAN_TASK, so the board treats it as a delegate_task descendant and its claim will not be extended by activity. Only the dispatcher's own spawn grants worker scope; do not copy a worker's environment into a hand-launched process.zauto-heartbeat: %s failedr*  zauto-heartbeat: bridge failed)rJ   rK   r0   ÚtimeÚ	monotonicr<  Ú$_AUTO_HEARTBEAT_MIN_INTERVAL_SECONDSrD   r¶   r?  r¼   Úheartbeat_claimÚheartbeat_workerr    rb   rü   ÚPermissionErrorÚ_auto_heartbeat_fence_warnedr~   r0  r4   Údebug)r—   ÚnowÚkbdr¹   r»   ÚopsÚ	succeededr„   ÚkwargsÚopÚexcs              r-   Ú!heartbeat_current_worker_from_envrT  ù  sˆ  € ô
 �*‰*�.‰.Ð-Ó
.€CÜ
�.‰.Ó
€CÙ�3Ô5Ñ5Ô9]Ò]ØÜ"Ô$ð Ø#&Ð ðÝ8Ü�D dÔ+ð 	&©z°°DØ×&Ñ&¨´B·J±J·N±NÐC]Ó4^Ð(_Ð`Ø×(Ñ(°4ÌNÐ[^ÓL_Ñ*`ÐaðcˆCàˆIØ!ò &‘
��FØ—[‘[�ð&Ü $¡R¨¨cÑ%<°VÑ%<Ó =Ò KÀ)‘Iñ&÷		&ð2 Ðøô# 'ò \ð
 !&�IÝ7Ø7;Ð4ÜŸ™ðQð SVÐWZô\ÿøô !ò &Ü—L‘LÐ!<¸bÈ4�LÔPØ %’Ið&ú÷-	&ð2 ÐûÜò Ü�‰Ð4¸tˆÔDÙðúsg   ÁE Á(A!E	Ã
C.Ã!E	Ã$	E Ã.	EÃ7!DÄE	Ä&EÅE	ÅEÅE	Å	EÅE ÅE Å E9Å8E9g      @Ú_comment_poll_last_attemptzdict[str, int]Ú_comment_watermarkc                óž  — t        «       rt        j                  j                  d«      nd}t	        j
                  «       }|r| �t        | d«      r|t        z
  t        k  ry|at        j                  |«      }	 t        dd¬«      5 \  }}|j                  |||xs d¬«      }ddd«       |€t        d„ D «       d¬«      t        |<   |�syt        d„ |D «       «      t        |<   t        j                  j                  d«      xs dj!                  «       }|D �cg c]E  }|j"                  xs dj!                  «       |k7  sŒ%|j$                  xs dj!                  «       sŒD|‘ŒG }	}|	sy|	D �cg c]0  }d|j"                  xs d› d|j$                  j!                  «       › �‘Œ2 }
}dt'        |	«      dkD  rdndz   dz   dz   dj)                  |
«      z   }	 t+        | j-                  |«      «      S # 1 sw Y   �ŒLxY w# t        $ r t        j                  d	d¬
«       Y yw xY wc c}w c c}w # t        $ r t        j                  dd¬
«       Y yw xY w)z Steer new operator comments on the worker's task into ``agent``; True iff a
    steer was injected; never raises. Own comments (``HERMES_PROFILE``) are skipped.rI   NÚsteerFTr¯   r   )Úafter_idzcomment-inject: bridge failedr*  c              3  ó4   K  — | ]  }|j                   –— Œ y ­wr[   ©rË   ©r)   Úcs     r-   r.   z/inject_new_comments_from_env.<locals>.<genexpr>D  s   è ø€ Ò&:° q§t¥tÑ&:ùó   ‚©r=   c              3  ó4   K  — | ]  }|j                   –— Œ y ­wr[   r[  r\  s     r-   r.   z/inject_new_comments_from_env.<locals>.<genexpr>H  s   è ø€ Ò!5¨1 !§$¥$Ñ!5ùr^  ÚHERMES_PROFILEr'  z- Úoperatorrv   zNew noteé   rî   z< on your kanban task from the operator (delivered mid-run). z:Take it into account for the work you're doing right now:
Ú
zcomment-inject: steer failed)rG   rJ   rK   r0   rE  rF  ÚhasattrrU  Ú"_COMMENT_POLL_MIN_INTERVAL_SECONDSrV  r¼   Úlist_comments_afterr4   r~   rL  Úmaxrß   r  r  r  r{   rü   rX  )r:   r—   rM  Úseenr¹   r»   ÚrowsÚownr]  ÚfreshÚlinesrC  s               r-   Úinject_new_comments_from_envrn  0  s,  € ô 3NÔ2OŒ"�*‰*�.‰.Ð-Ô
.ÐUY€CÜ
�.‰.Ó
€CÙ�5�=¬°°wÔ(?ØÔ0Ñ0Ô4VÒVØØ!$ÐÜ×!Ñ! #Ó&€DðÜ�D dÔ+ð 	I©z°°DØ×)Ñ)¨$°¸dºiÀaÐ)ÓHˆD÷	Ið
 €|Ü"%Ñ&:°TÔ&:ÀAÔ"FÔ˜3ÑØ€|™4Øä!Ñ!5°Ô!5Ó5Ô�sÑÜ�:‰:�>‰>Ð*Ó+Ò1¨r×
8Ñ
8Ó
:€CØÖ[�1 §¡¢¨R× 6Ñ 6Ó 8¸CÓ ?ÀQÇVÁVÂ\Èr×DXÑDXÕDZŠQÐ[€EÐ[ÙØØFKÖLÀˆr�!—(‘(Ò(˜jÐ)¨¨A¯F©F¯L©L«NÐ+;Ò<ÐL€EÐLØ¤ U£¨a¢™#°RÑ8ØLñMàKñLàNRÏiÉiÐX]ÓN^ñ_€DðÜ�E—K‘K Ó%Ó&Ð&÷)	Iñ 	Iûäò Ü�‰Ð4¸tˆÔDÙðüò \ùò Møô ò Ü�‰Ð3¸dˆÔCÙðúsT   Á9G9 ÂG,Â"G9 Ä&HÅHÅ HÅ-5H$ÇH) Ç,G6Ç1G9 Ç9 HÈHÈ) IÉIÚkanban_showc                óÔ  — t        | «      }t        | j                  d«      «      5 \  }}t        |||«      }t	        j
                  t        |t        «      |j                  ||«      |j                  ||«      D ��cg c]
  \  }}||dœ‘Œ c}}|j                  ||«      |j                  ||«      D �cg c]  }t        |t        «      ‘Œ c}|j                  ||«      dd D �	cg c]  }	t        |	t        «      ‘Œ c}	|j                  ||«      D �
cg c]  }
t        |
t         «      ‘Œ c}
|j#                  ||«      dœ«      cddd«       S c c}}w c c}w c c}	w c c}
w # 1 sw Y   yxY w)zHFull task state: row, parents, children, comments, runs, last 50 events.rµ   )rË   rÉ   iÎÿÿÿN)r¿   r  Úunsatisfied_parentsr  ÚcommentsÚeventsÚrunsÚworker_context)r˜   r¼   r0   rÀ   rÃ   rÄ   r  Ú_TASK_FIELDSr  rq  r  Úlist_commentsÚ_COMMENT_FIELDSÚlist_eventsÚ_EVENT_FIELDSÚ	list_runsÚ_RUN_FIELDSÚbuild_worker_context)r|   r€   r—   r¹   r»   r¿   ÚpidrÉ   r]  rƒ   Úrs              r-   Ú_handle_showr€  Z  sJ  € ô ˜4Ó
 €CÜ	�—‘˜Ó!Ó	"ð C¡j r¨4Ü˜b $¨Ó,ˆÜ�z‰zÜ˜D¤,Ó/Ø—}‘} T¨3Ó/ð BD×AWÑAWÐX\Ð^aÓAb÷$dÙ2=°#°v�s fÓ-ó$dàŸ™ T¨3Ó/Ø>@×>NÑ>NÈtÐUXÓ>YÖZ¸œ ¤OÕ4ÒZà:<¿.¹.ÈÈsÓ:SÐTWÐTXÐ:YÖZ°Q”w˜q¤-Õ0ÒZØ68·l±lÀ4ÈÓ6MÖN°”W˜Q¤Õ,ÒNà ×5Ñ5°d¸CÓ@ñBó C÷Cñ Cùó$dùò [ùâZùÚN÷Cð CúsB   ¦AEÁ;E	Â
(EÂ2EÃ	EÃ"EÃ9EÄEÄ&EÅ	EÅE'Úkanban_listc                ó
  — t        d«       t        | d«      }| j                  d«      }	 |€t        n
t	        |«      }t        |dk\  d«       t        |t        k  dt        › �«       t        | j                  d	«      «      5 \  }}|j                  |«      }|j                  || j                  d
«      | j                  d«      | j                  d«      ||dz   ¬«      }t        |«      |kD  }|d| }	t        j                  |	D �
cg c]  }
t!        |||
«      ‘Œ c}
t        |	«      |||r|t        k  rt#        |dz  t        «      nd|dœ«      cddd«       S # t
        t        f$ r t        d«      cY S w xY wc c}
w # 1 sw Y   yxY w)z5Task summaries with the same core filters as the CLI.r�  Úinclude_archivedÚlimitNzlimit must be an integerrc  zlimit must be >= 1zlimit must be <= rµ   ÚassigneerÉ   Útenant)r…  rÉ   r†  rƒ  r„  é   )ÚtasksÚcountr„  Ú	truncatedÚ
next_limitÚpromoted)r®   r   r0   ÚKANBAN_LIST_DEFAULT_LIMITrž   Ú	TypeErrorr}   r   ri   ÚKANBAN_LIST_MAX_LIMITr¼   Úrecompute_readyÚ
list_tasksr  rÃ   rÄ   r  Úmin)r|   r€   rƒ  r„  r¹   r»   rŒ  rj  rŠ  rˆ  Úts              r-   Ú_handle_listr”  p  sˆ  € ô ˜}Ô-Ü& tÐ-?Ó@ÐØ�H‰H�WÓ€Eð6Ø-2¨]Õ)ÄÀEÃ
ˆô ˆ5�A‰:Ð+Ô,Ü
ˆ5Ô)Ñ)Ð->Ô?TÐ>UÐ+VÔWÜ	�—‘˜Ó!Ó	"ð #¡j r¨4ð ×%Ñ% dÓ+ˆà�}‰}Ø˜4Ÿ8™8 JÓ/¸¿¹ÀÓ8JØ—8‘8˜HÓ%Ð8HÐPUÐXYÑPYð ó [ˆô ˜“I Ñ%ˆ	Ø�V�e�ˆÜ�z‰zØ?DÖE¸!Ô(¨¨T°1Õ5ÒEÜ˜“Z¨%¸iá'¨EÔ4IÒ,Iô ˜u q™yÔ*?Ô@ØOSØ ñ"ó #÷#ñ #øô	 ”zÐ"ò 6ÜÐ4Ó5Ò5ð6üò F÷#ð #ús0   ªE Â BE9ÄE4
Ä4E9ÅE1Å0E1Å4E9Å9FrU   c                ó:  — t        d| «      }t        | j                  d«      «      }t        | j                  d«      «      }| j                  d«      }t        |t        «      rt        |«      xs |}t        | j                  d«      ddd¬«      }t        | j                  d	«      d	d
d¬«      }|rt        ||«      }t        |xs |d«       t        |«       t        ||«      }t        | j                  d«      «      5 \  }}	|j                  |	|«      }
t        d|
||xs |xs dj                  «       «       	 |j                  |	|||||t!        |«      ¬«      }|j                  |	|«      }
|s`|j1                  |	|«      }|r*dj+                  d„ |D «       «      }t3        d|› d|› d�«      ‚t        d|
r|
j4                  ndxs d|› d�«       |j7                  |	|«      }t9        ||r|j:                  nd|j=                  |	|«      D �cg c]  }t?        |t@        «      ‘Œ c}¬ «      cddd«       S # |j"                  $ r"}t%        d|› d�«      cY d}~cddd«       S d}~w|j&                  $ r%}t%        d|› d|› d�«      cY d}~cddd«       S d}~w|j(                  $ r;}t%        ddj+                  |j,                  «      › d�«      cY d}~cddd«       S d}~w|j.                  $ r"}t%        d|› d�«      cY d}~cddd«       S d}~ww xY wc c}w # 1 sw Y   yxY w)!z5Mark the current task done with a structured handoff.rU   ÚsummaryÚresultr¤   Úcreated_cardsútask idsTrÞ   rê   ú
file pathsz4provide at least one of: summary (preferred), resultrµ   r'  )r—  r–  r¤   r˜  rD  z;kanban_complete could not preserve the declared artifacts: zœ. Your task is still in-flight and its scratch workspace was kept. Fix the artifact path or storage error, then retry kanban_complete with the same handoff.Nzkanban_complete refused: zi. Nothing changed. Wait for the worker to finish, or an operator can run `hermes kanban complete --force z`.zfkanban_complete blocked: the following created_cards do not exist or were not created by this worker: ru   zÔ. Your task is still in-flight (no state change). Retry kanban_complete with the same summary/metadata and either drop these ids from created_cards, or pass created_cards=[] to skip the card-claim check entirely.zkanban_complete blocked: z„. Your task is still in-flight (no state change). Retry kanban_complete with a non-empty summary or result describing what was done.c              3  ó2   K  — | ]  \  }}|› d |› d�–— Œ y­w)z (ú)NrB   )r)   r~  rÉ   s      r-   r.   z#_handle_complete.<locals>.<genexpr>Ó  s!   è ø€ Ò"S¹;¸3À c U¨"¨V¨H°AÔ#6Ñ"Sùs   ‚zcould not complete z#: unsatisfied parent dependencies: z/; complete the parents first (done or archived)Fz- (unknown id, stale run, or already terminal))r–   rÈ   Úattachments)!r¬   rØ   r0   r'   rˆ   rÝ   ræ   rò   ri   rè   r¥   r¼   r¾   r:  rß   Úcomplete_taskr    ÚArtifactPreservationErrorr   ÚLiveClaimErrorÚHallucinatedCardsErrorr{   ÚphantomÚEmptyCompletionErrorrq  rY   Úlast_failure_errorrÊ   rÆ   rË   Úlist_attachmentsr  Ú_ATTACHMENT_FIELDS)r|   r€   r—   r–  r—  r¤   r˜  rê   r¹   r»   r¿   rÂ   Úartifact_errÚ	claim_errÚhall_errÚ	empty_errÚblockersÚdetailrÎ   Úas                       r-   Ú_handle_completer®  Ž  s†  € ô Ð)¨4Ó
0€CÜ˜$Ÿ(™( 9Ó-Ó.€GÜ˜Ÿ™ (Ó+Ó,€FØ�x‰x˜
Ó#€HÜ�(œDÔ!ä# HÓ-Ò9°ˆÜ$Ø�‰�Ó! ?°JÀdôL€Mä  §¡¨+Ó!6¸À\ÐY]Ô^€IÙÜ# H¨iÓ8ˆÜ
ˆ7Ò�fÐTÔUÜ˜8Ô$Ü-¨c°8Ó<€HÜ	�—‘˜Ó!Ó	"ð AA¡j r¨4ð �{‰{˜4 Ó%ˆÜÐ$ d¨C°'Ò2I¸VÒ2IÀr×1PÑ1PÓ1RÔSð%	#Ø×!Ñ!Ø�c &°'ÀHØ+¼^ÈCÓ=Pð "ó RˆBðJ �{‰{˜4 Ó%ˆÙð ×-Ñ-¨d°CÓ8ˆHÙØŸ™Ñ"SÈ(Ô"SÓS�ÜØ)¨#¨Ð.QØ�hÐMðOóPð Pô �5±d˜4×2Ò2Àò \Ø(¨¨Ð-ZÐ[ô]à�m‰m˜D #Ó&ˆô
 ˜3± s§v¢v¸$ð !#× 3Ñ 3°D¸#Ó >ö @àô ˜qÔ"4Õ5ò @ôA÷}AAñ AAøð ×+Ñ+ò 
	ô ØMÈlÈ^ð \ð óô ÷!AAñ AAûð* × Ñ ò 	^ô Ø+¨I¨;ð 7UØUXÐTYÐY[ð]ó^ô ^÷1AAñ AAûð6 ×(Ñ(ò 		Lô ð+Ø+/¯9©9°X×5EÑ5EÓ+FÐ*Gð HJðKóLô L÷?AAñ AAûðJ ×&Ñ&ò 	#ô Ø+¨I¨;ð 7!ð "ó#ô #÷QAAñ AAûðJ	#üò4 @÷AAð AAús‘   Ã<:LÄ7!H/ÅB/LÈLÈLÈ/L	È>IÉL	ÉLÉL	É-JÉ>L	É?LÊL	Ê'KËL	ËLËL	Ë'LË5L	Ë6LÌL	Ì	LÌLrT   c           
     ó²  — t        d| «      }t        t        | dd«      «      }| j                  d«      }t	        | j                  d«      «      5 \  }}t        |du xs ||j                  v dt        |j                  «      › d�«       |j                  ||«      }t        |xr |j                  xr |t        v d	t        t        «      › d
|›d�«       |j                  ||||t        |«      ¬«      }t        |d|› d�«       |j                  ||«      j                  }	d|	i}
|dk(  r|	|k7  r
||
d<   d|
d<   t        |||dfi |
¤Žcddd«       S # 1 sw Y   yxY w)z?Transition the task to blocked with a reason a human will read.rT   r-  u2   reason is required â€” explain what input you needr  rµ   Nzkind must be one of z (or omit it)z,goal_mode tasks can only block with kind in z (got u‘   ). If the task is actually finished or cannot proceed for another reason, call kanban_complete instead â€” the completion judge will evaluate it.)r-  r  rD  zcould not block z% (unknown id or not in running/ready)Ú
block_kindr  Úrequested_kindzÎkind='dependency' only waits on an incomplete parent; no parent is open, so this was recorded as needs_input (sticky until a human unblocks) instead of parking in todo where the dispatcher would respawn it.rC  r!  )r¬   rÖ   rô   r0   r¼   ri   ÚVALID_BLOCK_KINDSrz   r¾   r.  Ú_GOAL_MODE_BLOCK_ALLOWED_KINDSÚ
block_taskr    r°  rÐ   )r|   r€   r—   r-  r  r¹   r»   r¿   rÂ   Úlanded_kindrÍ   s              r-   Ú_handle_blockr¶  ä  s€  € ô ˜¨Ó
-€CÜÜ�d˜HÐ&ZÓ[ó]€Fà�8‰8�FÓ€DÜ	�—‘˜Ó!Ó	"ð =¡j r¨4Üˆt�tˆ|Ò;˜t r×';Ñ';Ð;Ø%¤f¨R×-AÑ-AÓ&BÐ%CÀ=ÐQô	Sð �{‰{˜4 Ó%ˆÜ�DÒZ˜TŸ^™^ÒZ°Ô<ZÐ0ZÐ[Ø=ÜÔ7Ó8Ð9¸À¸xð H8ð9ô	:ð
 �]‰]˜4 ¨V¸$ÔP^Ð_bÓPcˆ]ÓdˆÜˆrÐ% c UÐ*OÐPÔQØ—k‘k $¨Ó,×7Ñ7ˆØ# [Ð1ˆØ�<Ò K°4Ò$7à&*ˆEÐ"Ñ#ðTð �&‰Mô
 ˜"˜d C¨Ñ<°eÑ<÷?=÷ =ò =ús   ÁC5EÅErV   c                óh  — t        d| «      }t        t        | dd«      «      }| j                  d«      }t	        |«       |�t        |«      }t        |dud«       t        | j                  d«      ddd	¬
«      }|rt        ||«      }t        ||«      }t        | j                  d«      xs d«      }|r4ddlm}m} t         ||«      d|›ddj                   |«       «      › �«       t        | j                  d«      «      5 \  }	}
t!        d|	j#                  |
|«      ||«       	 |	j%                  |
||||t'        |«      d	¬«      \  }}t        |d|› d|xs d› �«       t-        |	|
|d«      cddd«       S # |	j(                  $ r"}t+        d|› d�«      cY d}~cddd«       S d}~ww xY w# 1 sw Y   yxY w)z6Move implementation into the first-class review phase.rV   r–  ui   summary is required â€” describe what was implemented and how it was verified so the reviewer has contextr¤   Nz'metadata could not be safely serializedrê   rš  TrÞ   Úreviewerr   )Úlist_profile_namesÚprofile_existszreviewer profile z' is not installed. Installed profiles: ru   rµ   )r–  r¤   r¸  rD  Úwith_reasonzAkanban_request_review could not preserve the declared artifacts: z´. Your task is still in-flight (no state change) and its scratch workspace was kept. Fix the artifact path or storage error, then retry kanban_request_review with the same handoff.zcould not request review for rv   z"unknown id or not in running/readyÚreview)r¬   rÖ   rô   r0   rè   rÝ   ri   ræ   rò   r¥   rØ   Úhermes_cli.profilesr¹  rº  r{   r¼   r:  r¾   Úrequest_reviewr    rŸ  r   rÐ   )r|   r€   r—   r–  r¤   rê   r¸  r¹  rº  r¹   r»   rÂ   Úfail_reasonr§  s                 r-   Ú_handle_request_reviewrÀ    sð  € ô Ð/°Ó
6€CÜ”mØˆið 3ó4ó 5€Gð �x‰x˜
Ó#€HÜ˜8Ô$ØÐÜ# HÓ-ˆÜˆx˜tÐ#Ð%NÔOÜ  §¡¨+Ó!6¸À\ÐY]Ô^€IÙÜ# H¨iÓ8ˆÜ-¨c°8Ó<€Hä˜4Ÿ8™8 JÓ/Ò7°4Ó8€HÙßJô 	‰~˜hÓ'Ø" 8 ,ð /&Ø&*§i¡iÑ0BÓ0DÓ&EÐ%FðHô	Iô 
�—‘˜Ó!Ó	"ð 3¡j r¨4ÜÐ*¨B¯K©K¸¸cÓ,BÀCÈÔQð	AØ ×/Ñ/Ø�c 7°XÈÜ .¨sÓ 3Àð 0ó G‰OˆB�ô 	ˆrÐ2°3°%°rØ!ÒIÐ%IÐJðLô 	Mä˜"˜d C¨Ó2÷#3ñ 3øð ×+Ñ+ò 	Aô ØSÐT`ÐSað b?ð @óAô A÷3ñ 3ûð	Aú÷3ð 3ús<   Ä "F(Ä#$E4Å#F(Å4F%ÆF ÆF%ÆF(Æ F%Æ%F(Æ(F1rW   c           	     ó:  — t        d| «      }t        t        | dd«      «      }t        | j	                  d«      «      5 \  }}|j                  |||t        |«      ¬«      \  }}t        |d|› d|xs d› �«       t        |||d	|¬
«      cddd«       S # 1 sw Y   yxY w)z8Return a reviewer-owned running task to its implementer.rW   r-  u2   reason is required â€” describe the changes neededrµ   )r-  rD  zcould not request changes for rv   zinvalid review stateÚready)ÚimplementerN)	r¬   rÖ   rô   r¼   r0   Úrequest_changesr    ri   rÐ   )r|   r€   r—   r-  r¹   r»   rÂ   r¬  s           r-   Ú_handle_request_changesrÅ  ;  s°   € ô Ð0°$Ó
7€CÜÜ�d˜HÐ&ZÓ[ó]€Fä	�—‘˜Ó!Ó	"ð F¡j r¨4Ø×'Ñ'Ø�#˜f´nÀSÓ6Ið (ó K‰
ˆˆFäˆrÐ3°C°5¸¸6Ò;[ÐE[Ð:\Ð]Ô^Ü˜"˜d C¨¸fÔE÷	F÷ Fò Fús   ½A
BÂBÚkanban_heartbeatc           	     ó€  — t        d| «      }ddlm} t        | j	                  d«      «      5 \  }}|j                  ||t        j                  j	                  d«      ¬«       |j                  ||| j	                  d«      t        |«      ¬«      }t        |d	|› d
�«       t        |¬«      cddd«       S # 1 sw Y   yxY w)zÀSignal liveness: extend the claim TTL AND record a heartbeat event.
    Without the claim half, a worker blocked in one long tool call would still
    be reclaimed by ``release_stale_claims``.rÆ  r   r>  rµ   rA  )r@  rC  rB  zcould not heartbeat z (unknown id or not running))r–   N)r¬   r¶   r?  r¼   r0   rH  rJ   rK   rI  r    ri   rÆ   )r|   r€   r—   rN  r¹   r»   rÂ   s          r-   Ú_handle_heartbeatrÈ  H  s¯   € ô
 Ð*¨DÓ
1€CÝ4Ü	�—‘˜Ó!Ó	"ð  ¡j r¨4ð 	×Ñ˜4 ¬b¯j©j¯n©nÐ=WÓ.XÐÔYØ×!Ñ!Ø�#˜DŸH™H VÓ,¼nÈSÓ>Qð "ó SˆäˆrÐ)¨#¨Ð.JÐKÔLÜ˜3Ô÷ ÷  ò  ús   ­A=B4Â4B=Úkanban_commentc           	     ó~  — t        d«       | j                  d«      }t        |d«       t        t	        | d«      «      }t
        j                  j                  d«      xs d}t        | j                  d«      «      5 \  }}|j                  |||t        |«      ¬«      }t        ||¬	«      cd
d
d
«       S # 1 sw Y   y
xY w)z$Append a comment to a task's thread.rÉ  r–   uo   task_id is required (use the current task id if that's what you mean â€” pulls from env but kept explicit here)r  ra  Úworkerrµ   )r  r  )r–   Ú
comment_idN)r‘   r0   ri   rÖ   rô   rJ   rK   r¼   Úadd_commentra   rÆ   )r|   r€   r—   r  r  r¹   r»   Úcids           r-   Ú_handle_commentrÏ  Y  s§   € ô %Ð%5Ô6Ø
�(‰(�9Ó
€CÜ
ˆ3ð Fô Gä”=  vÓ.Ó/€Dô �Z‰Z�^‰^Ð,Ó-Ò9°€FÜ	�—‘˜Ó!Ó	"ð 0¡j r¨4Ø�n‰n˜T 3¨v¼CÀ»IˆnÓFˆÜ˜3¨3Ô/÷0÷ 0ò 0ús   Á;.B3Â3B<c           
     óº   — t        | «      5 \  }}|j                  ||t        |«      ||d| ¬«      }t        ||t	        |«      ¬«      cddd«       S # 1 sw Y   yxY w)z˜Store via ``kanban_db.store_attachment_bytes`` (shared size cap, per-task
    dir, metadata row) so agent, dashboard, and CLI surfaces stay in lockstep.r:   )Úcontent_typeÚuploaded_byrµ   )r–   Úattachment_idÚsizeN)r¼   Ústore_attachment_bytesra   rÆ   r  )rµ   r—   ÚfilenameÚdatarÑ  r¹   r»   Úatt_ids           r-   Ú_store_attachmentrÙ  o  sf   € ô 
�‹ð F™*˜2˜tØ×*Ñ*Ø�#”s˜8“} dØ%°7À%ð +ó Iˆô ˜3¨f¼3¸t»9ÔE÷	F÷ Fò Fús   Œ;AÁAÚkanban_attachc           	     óD  — t        d| «      }t        | d«      }t        | d«      }ddl}ddl}	 |j	                  t        |«      d¬«      }t        | j                  d	«      |||| j                  d
«      «      S # |j                  t        f$ r}t        d|› �«      ‚d}~ww xY w)z)Attach an inline (base64) file to a task.rÚ  rÖ  Úcontent_base64r   NT)Úvalidatez$content_base64 is not valid base64: rµ   rÑ  )r¬   rô   Úbase64ÚbinasciiÚ	b64decodera   ÚErrorr}   rY   rÙ  r0   )	r|   r€   r—   rÖ  Úcontent_b64rÞ  rß  r×  rƒ   s	            r-   Ú_handle_attachrã  y  s¦   € ô ˜¨Ó
.€CÜ˜T :Ó.€HÜ Ð&6Ó7€KÛÛðBØ×Ñ¤ KÓ 0¸4ÐÓ@ˆô ˜TŸX™X gÓ.°°X¸tÀTÇXÁXÈnÓE]Ó^Ð^øð �N‰NœJÐ'ò BÜÐ<¸Q¸CÐ@ÓAÐAûðBús   ®A7 Á7BÂBÂBé   c                ón  — ddl m}m} ddl}ddlm} | }t        t        dz   «      D �]r  } ||«      j                  xs dj                  «       }|dvrt        d|›d	�«      ‚ ||«      st        d
|› �«      ‚g }	d}
|j                  d|ddidd¬«      5 }|j                  r>|j                  j                  d«      }|st        d|› �«      ‚ |||«      }	 ddd«       Œ¸|j                  «        |j                  j                  d«      xs dj!                  d«      d   j#                  «       xs d}|j%                  d«      D ]8  }|
t'        |«      z  }
|
|kD  rt        d|dz  › d�«      ‚|	j)                  |«       Œ: 	 ddd«       dj+                  |	«      fc S  t        d| › �«      ‚# 1 sw Y   Œ-xY w)a–  Fetch ``url`` over http(s) capped at ``max_bytes`` -> ``(data, content_type)``.
    Every hop is SSRF-checked (redirects followed manually) so a model-controlled URL, or a
    public host 302ing, cannot reach loopback/private/cloud-metadata ranges. ``ValueError``
    for bad scheme, blocked target, too many redirects, or a body over the cap (checked
    while streaming, so nothing oversize is buffered).r   )ÚurljoinÚurlparseN)Úis_safe_urlrc  r'  )ÚhttpÚhttpszunsupported URL scheme z; only http/https are allowedz;URL blocked by SSRF protection (private/internal address): ÚGETz
User-Agentzhermes-kanban/attaché   F)ÚheadersÚtimeoutÚfollow_redirectsÚlocationz&redirect without Location header from zcontent-typeú;i   zattachment exceeds z	 MB limitrC   ztoo many redirects fetching )Úurllib.parseræ  rç  ÚhttpxÚtools.url_safetyrè  ÚrangeÚ_MAX_ATTACH_URL_REDIRECTSÚschemerþ   r}   ÚstreamÚis_redirectrí  r0   Úraise_for_statusÚsplitrß   Ú
iter_bytesr  Úappendr{   )ÚurlÚ	max_bytesræ  rç  ró  rè  Úcurrent_urlr6  r÷  ÚchunksÚtotalÚresprð  rÑ  Úchunks                  r-   Ú_download_url_with_capr  ‹  sá  € ÷ /ÛÝ,Ø€KÜÔ,¨qÑ0Ó1ó .ˆÙ˜;Ó'×.Ñ.Ò4°"×;Ñ;Ó=ˆØÐ*Ñ*ÜÐ6°v°jÐ@]Ð^Ó_Ð_Ù˜;Ô'ÜØMÈkÈ]Ð[ó]ð ]à ˆØˆØ�\‰\˜% °|ÐE[Ð6\Ø"$°uð ó >ð 	%ØAEØ×ÒØŸ<™<×+Ñ+¨JÓ7�ÙÜ$Ð'MÈkÈ]Ð%[Ó\Ð\Ù% k°8Ó<�Ø÷	%ð 	%ð ×!Ñ!Ô#Ø ŸL™L×,Ñ,¨^Ó<ÒBÀ×IÑIÈ#ÓNÈqÑQ×WÑWÓYÒaÐ]aˆLØŸ™¨Ó5ò %�Øœ˜U›Ñ#�Ø˜9Ò$Ü$Ð':¸9ÈÑ;UÐ:VÐV_Ð%`ÓaÐaØ—‘˜eÕ$ñ	%÷	%ð �x‰x˜Ó Ð-Ò-ð1.ô2 Ð3°C°5Ð9Ó
:Ð:÷!	%ð 	%ús   ÂAF+ÃBF+Æ+F4	rn   c           	     óÀ  — ddl m} t        d| «      }t        t	        | d«      «      j                  «       }| j                  d«      xs | j                  d«      }|rt        |«      j                  «       sEddlm}m	}  | ||«      j                  j                  dd	«      d
   «      j                  «       xs d}	 t        ||j                  «      \  }}	t'        | j                  d«      |||| j                  d«      xs |	«      S # t        $ r}
t        d|
› �«      cY d}
~
S d}
~
wt         $ r0}
t"        j%                  d«       t        d|› d|
› �«      cY d}
~
S d}
~
ww xY w)zHAttach a file fetched server-side from an http(s) URL (shared size cap).r   r²   rn   rþ  rÖ  rl   )Úunquoterç  ú/rc  éÿÿÿÿÚdownloadzkanban_attach_url: Nz!kanban_attach_url download failedz#kanban_attach_url: failed to fetch rv   rµ   rÑ  )r¶   r³   r¬   ra   rô   rß   r0   rò  r  rç  ÚpathÚrsplitr  ÚKANBAN_ATTACHMENT_MAX_BYTESr}   r   r4   r~   r   rÙ  )r|   r€   r¹   r—   rþ  rÖ  r  rç  r×  Ú
fetched_ctrƒ   s              r-   Ú_handle_attach_urlr  ±  s;  € õ +Ü
Ð+¨TÓ
2€CÜ
Œm˜D %Ó(Ó
)×
/Ñ
/Ó
1€CØ�x‰x˜
Ó#Ò8 t§x¡x°Ó'8€HÙœ3˜x›=×.Ñ.Ô0ç2Ù™8 C›=×-Ñ-×4Ñ4°S¸!Ó<¸RÑ@ÓA×GÑGÓIÒWÈZˆðLÜ1°#°r×7UÑ7UÓVÑˆˆjô Ø�‰�Ó˜3 ¨$°·±¸Ó0HÒ0VÈJóXð Xøô ò 5ÜÐ/°¨sÐ3Ó4Õ4ûÜò LÜ×ÑÐ<Ô=ÜÐ?À¸uÀBÀqÀcÐJÓKÕKûðLús0   Â;D Ä	EÄD!ÄEÄ!EÄ-%EÅEÅEÚkanban_attachmentsc                ó,  — t        | «      }t        | j                  d«      «      5 \  }}t        |||«       t	        j
                  d||j                  ||«      D �cg c]  }t        |t        «      ‘Œ c}dœ«      cddd«       S c c}w # 1 sw Y   yxY w)z@List a task's attachments (read-only; no ownership restriction).rµ   T)rÂ   r–   r�  N)	r˜   r¼   r0   rÀ   rÃ   rÄ   r¥  r  r¦  )r|   r€   r—   r¹   r»   r­  s         r-   Ú_handle_attachmentsr  Ç  s™   € ô ˜4Ó
 €CÜ	�—‘˜Ó!Ó	"ð Z¡j r¨4Ü�r˜4 Ô%Ü�z‰zØ 3à8:×8KÑ8KÈDÐRUÓ8VöXØ34”˜Ô-Õ.òXñYó Z÷Zñ ZùòX÷	Zð Zús   ¦6B
ÁBÁ3B
ÂB
Â
Bc                ó
  — | sy	 ddl m} ddlm}  | |«       dz  d¬«      }	 |j                  | «      r| nd	 |j                  «        S # t        $ r t
        j                  dd¬	«       Y yw xY w# |j                  «        w xY w)
zGReturn a session id only when it is present in this profile's state.db.Nr   )Ú	SessionDB)Úget_hermes_homezstate.dbT)Údb_pathÚ	read_onlyz3Could not open state.db to verify Kanban provenancer*  )	Úhermes_stater  Úhermes_constantsr  r4   r~   rL  Úget_sessionr¸   )rj   r  r  Ústates       r-   Ú_persisted_session_idr  Ó  s|   € áØðÝ*Ý4á¡/Ó"3°jÑ"@ÈDÔQˆðØ"×.Ñ.¨zÔ:‰zÀÐDà�‰�øô ò Ü�‰ÐJÐUYˆÔZÙðûð 	�‰�ús   …A
 ¤A0 Á
 A-Á,A-Á0Brm   c                ó’  — t        d«       t        | d«      }| j                  d«      }t        |d«       | j                  d«      | j                  d«      }}d| v r| d   n| j                  d«      }d	}t	        | d
«      t        | j                  d«      dd«      t	        | d«      }
}	}| j                  d«      | j                  d«      }}t        |xs | d«       t        | j                  d«      xs g dd«      }t        | j                  d«      «      5 \  }}ddlm} ddl	m
} t        «       rt        j                  j                  d«      nd	}|r|j                  ||«      nd	}t        | j                  d«      «      xs6 |r|j                   nd	xs$ t         |«       «      xs t         |dd«      «      }|€*|€(|€&|�$|j"                  r|j"                  |j$                  }}|j'                  |t)        |«      j+                  «       | j                  d«      t)        |«      t-        |«      | j                  d«      xs t        j                  j                  d«      t/        | j                  d«      d«      |||| j                  d«      |||| j                  d«      t/        | j                  d «      «      |	|||
t/        | j                  d!«      «      | j                  d"«      t)        | j                  d#«      xs d$«      t        j                  j                  d%«      xs d&|¬'«      }t1        |j                  ||«      t2        «      }|j5                  ||«      D �cg c]  }|j6                  d(k(  sŒ|‘Œ }}|rd)|d*   j8                  d+   d,œnd-d.i}t;        d1d/|i|¤|¤d0t=        ||«      i¤Žcd	d	d	«       S c c}w # 1 sw Y   y	xY w)2z@Create a (child) task; orchestrator workers use this to fan out.rm   rl   r…  u   assignee is required â€” name the profile that should execute this task (the dispatcher will only spawn tasks with an assignee)r  r	  Úprojectrk   NÚtriageÚskillszskill namesr.  r  Úproviderz-'provider' requires 'model' to be set as wellr  r™  rµ   r   ©Úget_session_env)Ú_current_origin_session_idrI   rj   r¢   r'  r  r†  ÚHERMES_TENANTÚpriorityÚidempotency_keyÚmax_runtime_secondsÚgoal_max_turnsÚcompletion_contractÚinitial_statusÚrunningra  rË  )rl   r  r…  r  r†  r&  r  r	  rk   rµ   Úproject_source_task_idr  Úcreator_task_idr'  r(  r   Úmodel_overrideÚprovider_overrider.  r)  r*  r+  Ú
created_byrj   Údependency_waitTr	  Úparent)ÚgatedÚgated_byr4  Fr–   Ú
subscribedrB   )r‘   rô   r0   ri   r   ræ   r¼   Úgateway.session_contextr#  Útools.async_delegationr$  rG   rJ   rK   r¾   r  rj   rk   rË   Úcreate_taskra   rß   rá   r  r  Ú_CREATED_FIELDSry  r  r  rÆ   Ú_maybe_auto_subscribe)r|   r€   rl   r…  r  r	  rk   r-  r  r   r.  r/  r0  r  r¹   r»   r#  r$  Úself_tidÚ	self_taskrj   Únew_tidrÏ   rƒ   ÚwaitÚgates                             r-   Ú_handle_createrA  å  s›  € ô % _Ô5Ü˜$ Ó(€EØ�x‰x˜
Ó#€HÜ
ˆ8ð Tô Uð &*§X¡XÐ.>Ó%?ÀÇÁÐJZÓA[�N€Nà$-°Ñ$5��i’¸4¿8¹8ÀLÓ;Q€JØ!Ðä˜˜hÓ'Ô)9¸$¿(¹(À8Ó:LÈhÐXeÓ)fÜ˜˜kÓ*ð ˆF€Fð )-¯©°Ó(9¸4¿8¹8ÀJÓ;OÐ%€NÜ
ˆ>Ò2Ð!2Ð2Ð4cÔdÜ˜tŸx™x¨	Ó2Ò8°b¸)ÀZÓP€GÜ	�—‘˜Ó!Ó	"ð &D¡j r¨4Ý;ÝEä2Ô4ô —J‘J—N‘NÐ#7Ô8Ø:>ð 	á3;�B—K‘K  hÔ/Àˆ	ô
 ,¨D¯H©H°\Ó,BÓCò YÙ2;˜)×.Ò.ÀòYä.Ñ/IÓ/KÓLòYô /©Ð?RÐTVÓ/WÓXð 	ð Ð .Ð"8¸^Ð=SØÐ$¨×)=Ò)=Ø5>×5IÑ5IÈ9Ï<É<Ð2�
Ø—.‘.Øœ˜E›
×(Ñ(Ó*°·±¸&Ó1AÌCÐPXËMÜ˜'“N¨4¯8©8°HÓ+=Ò+`ÄÇÁÇÁÐP_ÓA`Ü˜dŸh™h zÓ2°AÓ6Ø)¸.ÐU_ð —(‘(˜7Ó#Ø#9À&Ø$Ø ŸH™HÐ%6Ó7Ü (¨¯©Ð2GÓ)HÓ IÐRXØ)Ð=NØ´¸¿¹ÐBRÓ9SÓ0TØ $§¡Ð)>Ó ?Ü˜tŸx™xÐ(8Ó9ÒF¸YÓGÜ—z‘z—~‘~Ð&6Ó7ÒC¸8ÐPZð! !ó \ˆô" ˜Ÿ™ T¨7Ó3´_ÓEˆØŸ>™>¨$°Ó8ÖX�a¸A¿F¹FÐFWÓ<W’ÐXˆÐXÙJN˜¨4°©8×+;Ñ+;¸HÑ+EÒFÐU\Ð^cÐTdˆÜñ D˜7ð D fð D°ñ DÜ3°D¸'ÓBòD÷K&Dñ &DùòF Y÷G&Dð &Dús%   ÄIN=ÍN8Í1N8Í59N=Î8N=Î=Oc                 ó  — ddl m}   | dd«       | dd«      }}|r|s2 | dd«      xs  t        j                  j	                  dd«      }|syd|}} | d	d«      xs d} | d
d«      xs d} | dd«      xs d} | dd«      xs t        j                  j	                  d«      }|s	 ddlm}  |«       xs d}d|fd|fd | dd«      fd | dd«      ffD �	�
ci c]
  \  }	}
|
r|	|
“Œ }}	}
|j                  «       dk(  rH|rF|xs dj                  «       dv r0d|d<   t        |«      dvrt        |«      |d<   |rt        |«      |d<   t        |||| | dd«      xs d | dd«      xs d||dk7  rdnd|xs d¬ «	      S # t        $ r d}Y ŒÎw xY wc c}
}	w )!a®  ``kanban_db.add_notify_sub`` kwargs for the calling session, or None (CLI/cron/tests).
    Gateway sessions: ``HERMES_SESSION_PLATFORM``/``CHAT_ID`` ContextVars. TUI/desktop:
    those are cleared but the subprocess inherits ``HERMES_SESSION_KEY`` -> ``platform="tui"``
    for the TUI poller. ``HERMES_SESSION_ID`` is deliberately NOT a fallback: it is set for
    every CLI/ACP invocation and would auto-subscribe every CLI run.r   r"  ÚHERMES_SESSION_PLATFORMr'  ÚHERMES_SESSION_CHAT_IDÚHERMES_SESSION_KEYNÚtuiÚHERMES_SESSION_CHAT_TYPEÚHERMES_SESSION_THREAD_IDÚHERMES_SESSION_MESSAGE_IDÚHERMES_SESSION_PROFILEra  )Úget_active_profile_namer=   Ú	thread_idÚ	chat_typeÚscope_idÚHERMES_SESSION_SCOPE_IDÚparent_chat_idÚHERMES_SESSION_PARENT_CHAT_IDÚtelegram>   ÚdmÚdirectÚprivateTÚ telegram_dm_topic_reply_fallback>   r'  rö   Údirect_messages_topic_idÚtelegram_reply_to_message_idÚHERMES_SESSION_USER_IDÚHERMES_SESSION_USER_ID_ALTznotify+wake)	r*   Úchat_idrM  rL  Úuser_idÚuser_id_altÚnotifier_profileÚdelivery_modeÚdelivery_metadata)r7  r#  rJ   rK   r0   r½  rK  r4   rþ   ra   rˆ   )Úenvr*   r[  Úsession_keyrM  rL  Ú
message_idr^  rK  ÚkÚvr`  s               r-   Ú_resolve_notify_targetrf  $  sò  € õ ?ÙÐ5°rÓ:¹CÐ@XÐZ\Ó<]ˆg€HÙ™7ÙÐ.°Ó3Ò_´r·z±z·~±~ÐFZÐ\^Ó7_ˆÙØØ! ;�'ˆÙÐ.°Ó3Ò;°t€IÙÐ.°Ó3Ò;°t€IÙÐ0°"Ó5Ò;¸€JÙÐ3°RÓ8Ò\¼B¿J¹J¿N¹NÐK[Ó<\ÐÙð	)ÝCÙ6Ó8ÒE¸IÐð
 ˜)Ð$ {°IÐ&>Ø™Ð6¸Ó;Ð<Ø™sÐ#BÀBÓGÐHð
÷)Ù��Añ ð	 	
ˆ1‰ð)Ðñ )ð 	�‰Ó˜JÒ&©9Ø’˜b×'Ñ'Ó)Ð-HÑHØ@DÐÐ<Ñ=Üˆy‹> Ñ*Ü<?À	»NÐÐ8Ñ9ÙÜ@CÀJÃÐÐ<Ñ=ÜØ 7°iÈ9ÙÐ,¨bÓ1Ò9°TÙÐ4°bÓ9ÒA¸TØ)Ø'/°5Ò'8‘m¸dØ+Ò3¨tô5ð 5øô ò 	)Ø(Òð	)üó)s   Â#E5 ÃFÅ5FÆFc           
     ó‚  ‡— 	 t        t        «       ddd¬«      sy	 dŠ	 t        «       Š‰€yddlm} t        ˆfd	„|j                  | |«      D «       «      ry |j                  | fd
|i‰¤Ž y# t        $ r Y Œ\w xY w# t        $ r9}t        j                  d|‰r‰d   ndt        ‰xr ‰d   «      «       Y d}~yd}~ww xY w)aR  Subscribe the calling session to completion/block events; True iff a row was
    written (surfaced as ``subscribed`` so an orchestrator can fall back to explicit
    ``kanban_notify-subscribe``). Gated by ``kanban.auto_subscribe_on_create`` (default
    True). Failures are logged and swallowed: bookkeeping must never fail kanban_create.r!   Úauto_subscribe_on_createTr_  FNr   )Úkanban_db_notifyc              3  óx   •K  — | ]1  }|d    ‰d    k(  xr  |d   ‰d   k(  xr |d   xs d‰d   xs dk(  –— Œ3 y­w)r*   r[  rL  r'  NrB   )r)   ÚsubÚtargets     €r-   r.   z(_maybe_auto_subscribe.<locals>.<genexpr>c  sh   øè ø€ ò @àð �:‰ &¨Ñ"4Ñ4ò K¸¸Y¹È6ÐR[ÑK\Ñ9\ò KØ˜Ñ$Ò*¨°°{Ñ0CÒ0IÀrÑJóKñ @ùs   ƒ7:r–   z9_maybe_auto_subscribe failed: %r (platform=%r key_set=%r)r*   r'  r[  )r   r   r4   rf  r¶   ri  r2   Úlist_notify_subsÚadd_notify_subr~   r0  rü   )r»   r–   Ú_kbnÚ_excrl  s       @r-   r;  r;  Q  sä   ø€ ð
Ü”{“} hÐ0JÐTXÕYØð Zð €FðÜ'Ó)ˆØˆ>ØÝ7ô ó @à×/Ñ/°°gÓ>ô@ô @ð Øˆ×Ñ˜DÑ<¨'Ð<°VÒ<Øøô ò Ùðûô  ò Ü�‰ØGØ©�&˜Ò$°B¼¸VÒ=YÈÈyÑHYÓ8Zô	\ô ûð	ús3   ƒA- ŸA< ¬*A< ÁA< Á-	A9Á8A9Á<	B>Â/B9Â9B>Úkanban_unblockc                óˆ  — t        d«       t        d«       | j                  d«      }t        |d«       t	        |«      }t        |«       t        | j                  d«      «      5 \  }}t        |j                  ||«      d|› d�«       t        d	d|it        |j                  ||«      d«      ¤Žcddd«       S # 1 sw Y   yxY w)
zFTransition a blocked task to ready, or todo while parents remain open.rq  r–   ztask_id is requiredrµ   zcould not unblock z (not blocked or unknown))rÉ   NrB   )r‘   r®   r0   ri   ra   r©   r¼   Úunblock_taskrÆ   r  r¾   )r|   r€   r—   r¹   r»   s        r-   Ú_handle_unblockrt  p  s²   € ô %Ð%5Ô6ÜÐ/Ô0Ø
�(‰(�9Ó
€CÜ
ˆ3Ð%Ô&Ü
ˆc‹(€CÜ" 3Ô'Ü	�—‘˜Ó!Ó	"ð P¡j r¨4Üˆr�‰˜t SÓ)Ð-?À¸uÐD]Ð+^Ô_ÜÑO˜3ÐO¤'¨"¯+©+°d¸CÓ*@À+Ó"NÑO÷P÷ Pò Pús   Á$A
B8Â8CÚkanban_linkc                óZ  — t        d«       | j                  d«      }| j                  d«      }t        |xr |d«       t        | j                  d«      «      5 \  }}|j	                  |||t        t        |«      «      ¬«      }t        d
|||dœ|rd|ini ¤Žcd	d	d	«       S # 1 sw Y   y	xY w)uä   Add a parentâ†’child dependency edge after the fact (cycles/self-links/running
    children â†’ ValueError). A worker linking its OWN running card proves ownership
    with its run id so the dependency-block handoff still works.ru  Ú	parent_idÚchild_idz(both parent_id and child_id are requiredrµ   )rw  rx  Úexpected_child_run_id)rw  rx  r4  r5  NrB   )r‘   r0   ri   r¼   Ú
link_tasksr    ra   rÆ   )r|   r€   rw  rx  r¹   r»   r4  s          r-   Ú_handle_linkr{  ~  s¸   € ô
 % ]Ô3Ø—‘˜Ó%€IØ�x‰x˜
Ó#€HÜ
ˆ9Ò!˜Ð#MÔNÜ	�—‘˜Ó!Ó	"ð A¡j r¨4Ø—‘Ø˜I°Ü"0´°X³Ó"?ð ó Aˆô ð A˜Y°Àñ AÙ16�z 9Ñ-¸BñA÷	A÷ Aò Aús   Á?B!Â!B*u   ðŸ“‹u   âœ”u   â�¸u   ðŸ‘€u   â†©u   ðŸ’“u   ðŸ’¬u   ðŸ“Žu   âž•u   â–¶u   ðŸ”—r!   )rã   ÚtoolsetÚschemaÚhandlerÚemojiÚcheck_fn)r‰   rü   )r<   ra   r=   rü   r‰   rü   )rM   rü   r‰   rü   )rh   r   r_   ra   r‰   ÚNone)r…   ra   r‰   r   )r…   ra   r‰   r�  )r“   úOptional[str]r‰   r‚  r‡   )r–   ra   rš   ra   r‰   r‚  )r–   ra   r‰   úOptional[int])r–   ra   r¤   úOptional[dict]r‰   r„  )r—   ra   r‰   r�  )r…   ra   r|   rˆ   r‰   ra   )rµ   r‚  r°   rü   )r—   ra   )rÅ   r   r‰   ra   )r—   ra   rÌ   ra   rÍ   r   r‰   ra   )rÕ   r   r‰   ra   )rÕ   r   r‰   r   )r¤   rˆ   r‰   r„  )rÕ   r   rã   ra   rä   ra   rß   rü   )r¤   r   r‰   r�  )r¤   r   rê   z	list[str]r‰   rˆ   r[   )r|   rˆ   rã   ra   r_   r‚  r‰   r   )r|   rˆ   rã   ra   r‰   rü   )rÕ   r   r=   rƒ  r‰   rƒ  )r  r   r+   ztuple[str, ...]r‰   údict[str, Any])r‰   r…  )r…   ra   r—   ra   r3  ra   r‰   r�  )r:   r   r‰   rü   )r‰   ra   )rþ  ra   rÿ  rž   r‰   ztuple[bytes, Optional[str]])rj   r‚  r‰   r‚  )r‰   zOptional[dict[str, Any]])r»   r   r–   ra   r‰   rü   )†re   Ú
__future__r   rŠ   rÃ   ÚloggingrJ   rE  Ú
contextlibr   Útypingr   r   r   Úagent.redactr   Úhermes_cli.goalsr	   Útools.registryr
   r   r   Úhermes_cli.configr   r   Útools.kanban_tools_schemasr   r   r   r   r   r   r   r   r   r   r   r   r   r   Ú	getLoggerrb   r~   r�  r�  r7   r>   rD   rG   rN   rQ   rS   ry   r«   r4   rY   ri   ro   Ú__annotations__r�   r‘   r”   r˜   r›   r    r¥   r©   r¬   r®   r¼   rÀ   rÆ   rÐ   rÖ   rØ   rÝ   ræ   rè   rò   rô   rý   r   r  rá   rû  rv  r  r|  rx  rz  r¦  r:  r  r  r³  r   r1  r:  rG  r<  rK  rT  rf  rU  rV  rn  r€  r”  r®  r¶  rÀ  rÅ  rÈ  rÏ  rÙ  rã  rö  r  r  r  r  rA  rf  r;  rt  r{  Ú_ORCHESTRATOR_TOOLSÚ_TOOLSÚ_nameÚ_schÚ_handlerÚ_emojiÚ_gateÚregisterrB   rC   r-   ú<module>r™     so  ðòõ #ã Û Û Û 	Û Ý %ß *Ñ *å .Ý 'ß BÑ Bß 2÷/÷ /÷ /÷ /ð 
ˆ×	Ñ	˜8Ó	$€àÐ ØÐ ó
ó6ó@óGó)ð ò(ó ð(ð
 ò)ó ð)ñ !ò "ó Ð ô
.ˆiô .óñ  ¨lÐ;Ó<á" G 9Ó-ñ/Ð Ð+ó óó4Ló8óó\ó
ó]óbó  óFLð Ø8=ô ó ðó"ó.óLó9ó.óð INõ óNó
ôð  $¨t¸eÈ%ÐW\Ñ]€óô8ñ ð?ç?D¹u»wóH€ñ ðYßY^ÑY^ÓY`óbÐ ñ ÐZ×`Ñ`ÓbÓc€Ø2€Ø;€ÙØF×LÑLÓNóPÐ àN€óLó
Dñ "+¨L¸-Ð+HÓ!IÐ ó	.ð WðWñYðOð:ñ<ñ=Ð ó&Vðj (,Ð $Ø&)Ð ˜eÓ )Ø$Ð ó,ðd &)Ð "Ø$'Ð ˜EÓ 'Ø%'Ð �NÓ 'ó%ñT �ÓòCó  ðCñ* �Óò#ó  ð#ñ: Ð"Ó#òRAó $ðRAñj �Ó ò%=ó !ð%=ñP Ð(Ó)ò*3ó *ð*3ñZ Ð)Ó*ò	Fó +ð	Fñ Ð#Ó$ò ó %ð ñ  Ð!Ó"ò0ó #ð0ó*Fñ �Ó!ò_ó "ð_ð Ð ó#;ñL Ð$Ó%òXó &ðXñ* Ð%Ó&òZó 'ðZóñ$ �Ó!ò;Dó "ð;Dó|*5óZñ> Ð!Ó"ò
Pó #ð
Pñ �ÓòAó  ðAñ&   Ð0@Ð AÓBÐ àÐ&¨°fÐ=ØÐ&¨°fÐ=ØÐ.Ð0@À%ÐHØÐ(¨-¸Ð?ØÐ:Ð<RÐTZÐ[ØÐ<Ð>UÐW\Ð]ØÐ0Ð2CÀVÐLØÐ,¨o¸vÐFØÐ*¨N¸FÐCØÐ2Ð4FÈÐOØÐ4Ð6IÈ6ÐRØÐ*¨N¸EÐBØÐ,¨o¸uÐEØÐ&¨°fÐ=ð
?€ð  &,ò &Ñ!€Eˆ4�˜6Ø/4Ð8KÑ/KÑ+ÐQc€EØ€H×Ò˜5¨(¸4ÈÐY_Ø$ö&ñ&rC   