§
    øžyjÔK  ã                  óP  — 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mZ ddlmZ  ej        e¦  «        ZdZdZeefZd	Zd9d„Zd:d„Zd;d„Zd<d„Zd=d„Zd>d„Zd?d„Zd@d „ZdAd!„Z dBd"„Z! G d#„ d$¦  «        Z"d%d%d&œdCd)„Z#dBd*„Z$dDd-„Z%d%d%d%d%d.œdEd5„Z&dFd6„Z'dGd8„Z(dS )Hu}  Write-approval gate + pending store for memory and skill writes.

Background
----------
The agent writes to two persistent stores that survive across sessions:

  * **memory** â€” MEMORY.md / USER.md, small (~200 char) declarative entries
  * **skills** â€” SKILL.md + supporting files, potentially huge (10-100 KB)

Both stores are written from two origins:

  * **foreground** â€” a normal agent turn (user is present / chatting)
  * **background_review** â€” the self-improvement review fork that runs after a
    turn and autonomously decides what to save (the source of the
    "wrong assumptions" users complained about)

This module lets the user gate those writes per-subsystem with a boolean
``write_approval``:

  * ``false`` (default) â€” write freely (the pre-gate behaviour)
  * ``true``            â€” require approval: do not commit the write; either
    prompt inline (memory, interactive CLI only) or **stage** it to a pending
    store and surface it for the user to approve or reject out-of-band

The size asymmetry between memory and skills is real and unavoidable: a memory
entry can be reviewed inline in a chat bubble; a 100 KB SKILL.md cannot. So
the gate stages BOTH to disk, but review affordances differ by subsystem
(see ``hermes_cli`` slash handlers): memory shows full content, skills show
metadata + a one-line gist + a ``diff`` escape hatch (CLI/dashboard/file).

Staging is mandatory for background-origin writes (a daemon thread cannot
block on an interactive prompt) and for gateway sessions (no inline prompt
channel â€” review happens via ``/memory pending``). Foreground CLI memory
writes prompt inline via the dangerous-command approval callback; skill
writes always stage (too big to eyeball mid-loop).

Pending records live under ``<HERMES_HOME>/pending/{memory,skills}/<id>.json``
so they survive process restarts and can be reviewed from CLI, gateway, or the
web dashboard.
é    )ÚannotationsN)ÚPath)ÚAnyÚDictÚListÚOptional©Úget_hermes_homeÚmemoryÚskillsÚwrite_approvalÚ	subsystemÚstrÚreturnÚboolc                ó¨   — | t           vrdS 	 ddlm}m}  |¦   «         } ||| t          d¬¦  «        }n# t
          $ r Y dS w xY wt          |¦  «        S )u'  Return whether the approval gate is enabled for ``subsystem``.

    Reads ``<subsystem>.write_approval`` from config.yaml. Defaults to
    ``False`` (gate off â€” writes flow freely) for any unset / invalid value so
    existing installs keep their current behaviour until the user opts in.
    Fr   )Úload_configÚcfg_get)Údefault)Ú_SUBSYSTEMSÚhermes_cli.configr   r   Ú
CONFIG_KEYÚ	ExceptionÚ_normalize_enabled)r   r   r   ÚcfgÚraws        ú:/home/ragecks/.hermes/hermes-agent/tools/write_approval.pyÚwrite_approval_enabledr   J   s†   € ð �Ð#Ð#ØˆuðØ:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Øˆk‰mŒmˆØˆg�c˜9¥j¸%Ð@Ñ@Ô@ˆˆøÝð ð ð Øˆuˆuðøøøå˜cÑ"Ô"Ð"s   �&4 ´
AÁAÚvaluer   c                ó®   — t          | t          ¦  «        r| S t          | t          ¦  «        r(|                      ¦   «                              ¦   «         dv S dS )a  Coerce a config value to a bool. Default (unknown) is False (gate off).

    Accepts real bools and the usual truthy/falsey strings. YAML 1.1 parses
    bare ``on``/``off``/``yes``/``no`` as bools already, so the string branch
    is mostly for hand-edited configs.
    >   Ú1ÚonÚyesÚtrueÚapproveÚenabledF)Ú
isinstancer   r   ÚstripÚlower)r   s    r   r   r   \   sS   € õ �%�ÑÔð ØˆÝ�%�ÑÔð YØ�{Š{‰}Œ}×"Ò"Ñ$Ô$Ð(XÐXÐXØˆ5ó    r   c                ó*   — t          ¦   «         dz  | z  S )NÚpendingr	   )r   s    r   Ú_pending_dirr-   n   s   € ÝÑÔ˜yÑ(¨9Ñ4Ð4r*   ÚpayloadúDict[str, Any]ÚsummaryÚoriginc               óF  — t          j        ¦   «         j        dd…         }|| |                     dd¦  «        |pd                     ¦   «         |pdt          j        ¦   «         |dœ}	 t          | ¦  «        }|                     dd¬¦  «         ||› d	�z  }|                     d
¦  «        }| 	                    t          j        |dd¬¦  «        d¬¦  «         t          j        ||¦  «         n5# t          $ r(}	t                               d| |	d¬¦  «         Y d}	~	nd}	~	ww xY w|S )uO  Persist a pending write and return a short record describing it.

    Args:
        subsystem: ``memory`` or ``skills``.
        payload: the exact kwargs needed to replay the write when approved
            (e.g. ``{"action": "add", "target": "user", "content": "..."}``
            for memory, or the full ``skill_manage`` kwargs for skills).
        summary: a one-line human-readable description shown in pending lists.
            For skills this is the LLM/heuristic gist; for memory it can be the
            entry text itself.
        origin: ``foreground`` or ``background_review`` â€” recorded for audit.

    Returns a dict with ``id`` and metadata. Best-effort: on disk failure it
    logs and still returns a record (the write is simply lost, which is the
    safe failure for an approval gate â€” nothing is silently committed).
    Né   ÚactionÚ Ú
foreground)Úidr   r4   r0   r1   Ú
created_atr.   T)ÚparentsÚexist_okú.jsonz	.json.tmpFé   )Úensure_asciiÚindentúutf-8©Úencodingz$Failed to stage pending %s write: %s)Úexc_info)ÚuuidÚuuid4ÚhexÚgetr(   Útimer-   ÚmkdirÚwith_suffixÚ
write_textÚjsonÚdumpsÚosÚreplacer   ÚloggerÚerror)
r   r.   r0   r1   ÚpidÚrecordÚdÚpathÚtmpÚes
             r   Ústage_writerW   r   sA  € õ$ Œ*‰,Œ,Ô
˜2˜A˜2Ô
€CàØØ—+’+˜h¨Ñ+Ô+Ø�M˜r×(Ò(Ñ*Ô*ØÐ(˜LÝ”i‘k”kØðð €FðZÝ˜Ñ#Ô#ˆØ	�Š˜ tˆÑ,Ô,Ð,Ø�c�=�=�=Ñ ˆØ×Ò˜{Ñ+Ô+ˆØ�Š•t”z &°uÀQÐGÑGÔGÐRYˆÑZÔZÐZÝ
Œ
�3˜ÑÔÐÐøÝð Zð Zð ZÝ�ŠÐ;¸YÈÐTXˆÑYÔYÐYÐYÐYÐYÐYÐYøøøøðZøøøà€Ms   Á'BC, Ã,
DÃ6DÄDúList[Dict[str, Any]]c                ó€  — t          | ¦  «        }|                     ¦   «         sg S g }|                     d¦  «        D ]i}	 |                     t	          j        |                     d¬¦  «        ¦  «        ¦  «         Œ?# t          $ r t           	                    d|¦  «         Y Œfw xY w| 
                    d„ ¬¦  «         |S )z;Return all pending records for ``subsystem``, oldest first.ú*.jsonr?   r@   z&Skipping unreadable pending record: %sc                ó.   — |                       dd¦  «        S )Nr8   r   )rF   )Úrs    r   ú<lambda>zlist_pending.<locals>.<lambda>¥   s   € ˜qŸušu \°1Ñ5Ô5€ r*   )Úkey)r-   ÚexistsÚglobÚappendrK   ÚloadsÚ	read_textr   rO   ÚwarningÚsort)r   rS   ÚrecordsÚps       r   Úlist_pendingrh   š   sÐ   € å�YÑÔ€AØ�8Š8‰:Œ:ð Øˆ	Ø$&€GØ�VŠV�HÑÔð Hð Hˆð	HØ�NŠN�4œ: a§k¢k¸7 kÑ&CÔ&CÑDÔDÑEÔEÐEÐEøÝð 	Hð 	Hð 	HÝ�NŠNÐCÀQÑGÔGÐGÐGÐGð	Høøøà‡L‚LÐ5Ð5€LÑ6Ô6Ð6Ø€Ns   Á ;A<Á<%B$Â#B$Ú
pending_idúOptional[Dict[str, Any]]c                óÌ   — t          | ¦  «        |› d�z  }|                     ¦   «         sdS 	 t          j        |                     d¬¦  «        ¦  «        S # t
          $ r Y dS w xY w)z.Return a single pending record by id, or None.r;   Nr?   r@   )r-   r_   rK   rb   rc   r   )r   ri   rT   s      r   Úget_pendingrl   ©   sw   € å˜	Ñ"Ô"¨
Ð%9Ð%9Ð%9Ñ9€DØ�;Š;‰=Œ=ð ØˆtðÝŒz˜$Ÿ.š.°'˜.Ñ:Ô:Ñ;Ô;Ð;øÝð ð ð Øˆtˆtðøøøs   ­'A Á
A#Á"A#c                óð   — t          | ¦  «        |› d�z  }	 |                     ¦   «         r|                     ¦   «          dS n4# t          $ r'}t                               d| ||¦  «         Y d}~nd}~ww xY wdS )z4Delete a pending record. Returns True if it existed.r;   Tz#Failed to discard pending %s/%s: %sNF)r-   r_   Úunlinkr   rO   rP   )r   ri   rT   rV   s       r   Údiscard_pendingro   ´   s�   € å˜	Ñ"Ô"¨
Ð%9Ð%9Ð%9Ñ9€DðVØ�;Š;‰=Œ=ð 	Ø�KŠK‰MŒMˆMØ�4ð	øõ ð Vð Vð VÝ�ŠÐ:¸IÀzÐSTÑUÔUÐUÐUÐUÐUÐUÐUøøøøðVøøøàˆ5s   —(A Á
A3ÁA.Á.A3Úintc                óÈ   — t          | ¦  «        }|                     ¦   «         sdS 	 t          d„ |                     d¦  «        D ¦   «         ¦  «        S # t          $ r Y dS w xY w)z9Cheap count of pending records (for notification badges).r   c              3  ó   K  — | ]}d V — ŒdS )é   N© )Ú.0Ú_s     r   ú	<genexpr>z pending_count.<locals>.<genexpr>Æ   s"   è è € Ð/Ð/˜�1Ð/Ð/Ð/Ð/Ð/Ð/r*   rZ   )r-   r_   Úsumr`   r   )r   rS   s     r   Úpending_country   À   st   € å�YÑÔ€AØ�8Š8‰:Œ:ð ØˆqðÝÐ/Ð/˜aŸfšf XÑ.Ô.Ð/Ñ/Ô/Ñ/Ô/Ð/øÝð ð ð Øˆqˆqðøøøs   §+A Á
A!Á A!c                 óF   — 	 ddl m}   | ¦   «         S # t          $ r Y dS w xY w)a=  Return the active write origin: ``foreground`` or ``background_review``.

    Reuses the skill-provenance ContextVar, which the background review fork
    already sets (see ``agent.background_review`` /
    ``AIAgent._spawn_background_review``). Foreground agent turns leave it at
    the default ``foreground``.
    r   ©Úget_current_write_originr6   )Útools.skill_provenancer|   r   r{   s    r   Úcurrent_originr~   Ï   sJ   € ðØCÐCÐCÐCÐCÐCØ'Ð'Ñ)Ô)Ð)øÝð ð ð Øˆ|ˆ|ðøøøs   ‚ ’
 Ÿ c                 ó&   — t          ¦   «         dk    S )NÚbackground_review)r~   rt   r*   r   Úis_backgroundr�   Þ   s   € ÝÑÔÐ2Ò2Ð2r*   c                  ó(   — e Zd ZdZdZdddddœd„ZdS )ÚGateDecisionu‡  Result of evaluating the write gate for a single write attempt.

    Exactly one of the boolean flags is True:
      * ``allow``  â€” proceed with the real write (gate off, or an inline
        approval was granted).
      * ``blocked`` â€” refuse the write (the user denied an inline approval
        prompt). ``message`` explains why; surface it to the agent.
      * ``stage``  â€” do not write; the caller should stage the payload via
        ``stage_write`` (gate on, and no inline prompt is available â€” gateway,
        background review, script, or any skill write). ``message`` is the
        user-facing "staged for approval" note.
    ©ÚallowÚblockedÚstageÚmessageFr5   c               ó>   — || _         || _        || _        || _        d S )Nr„   )Úselfr…   r†   r‡   rˆ   s        r   Ú__init__zGateDecision.__init__ö   s"   € ØˆŒ
ØˆŒØˆŒ
ØˆŒˆˆr*   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__r‹   rt   r*   r   rƒ   rƒ   æ   sG   € € € € € ðð ð 9€Ià %¨u¸EÈ2ð ð ð ð ð ð ð r*   rƒ   r5   )Úinline_summaryÚinline_detailr‘   r’   c               ót  — t          | ¦  «        st          d¬¦  «        S t          ¦   «         }| t          k    s|r'| t          k    rdnd}t          dd| › d|› d�¬¦  «        S t	          ¦   «         r9t          ||¦  «        }|du rt          d¬¦  «        S |d	u rt          dd
¬¦  «        S t          dd¬¦  «        S )u˜  Decide what to do with a pending write for ``subsystem``.

    Args:
        subsystem: ``memory`` or ``skills``.
        inline_summary: short description used as the inline approval prompt
            header (memory foreground path only).
        inline_detail: full content shown in the inline prompt (memory entries
            are small; skills never take the inline path).

    Decision matrix:
        gate off (default)                    â†’ allow (writes flow freely)
        gate on, memory + interactive CLI     â†’ inline approve/deny prompt
        gate on, memory + gateway/script/bg   â†’ stage
        gate on, skills (any origin)          â†’ stage (too big to review inline)

    Note: there is no config-driven "blocked" outcome â€” the gate only ever
    delays a write for approval, never silently refuses it. ``blocked`` is
    still produced when the user *actively denies* an inline prompt.
    T)r…   z/skills pendingz/memory pendingzStaged for approval (u6   .write_approval is on). Not yet saved â€” review with ú.)r‡   rˆ   Fz6Memory write denied by user. The change was not saved.)r†   rˆ   ua   Staged for approval (memory.write_approval is on). Not yet saved â€” review with /memory pending.)r   rƒ   r�   ÚSKILLSÚ_interactive_approval_availableÚ_prompt_inline_memory_approval)r   r‘   r’   Ú
backgroundÚwhereÚgranteds         r   Úevaluate_gater›   ý   s  € õ* " )Ñ,Ô,ð (Ý $Ð'Ñ'Ô'Ð'å‘”€Jð •FÒÐ˜jÐØ%.µ&Ò%8Ð%8Ð!Ð!Ð>OˆÝØð:¨	ð :ð :Ø16ð:ð :ð :ð
ñ 
ô 
ð 	
õ 'Ñ(Ô(ð Ý0°ÀÑOÔOˆØ�dˆ?ˆ?Ý dÐ+Ñ+Ô+Ð+Ø�eÐÐÝØØPðñ ô ð õ Øð=ðñ ô ð r*   c                 óJ   — 	 ddl m}   | ¦   «         duS # t          $ r Y dS w xY w)uæ  True when a foreground memory write can be approved inline.

    Inline prompting requires a per-thread approval callback registered by the
    interactive CLI (``tools.terminal_tool.set_approval_callback``). Every
    other surface stages instead:

    * **Gateway/API sessions** â€” the dangerous-command ``/approve`` round-trip
      lives in the pending-approval queue (``submit_pending`` +
      ``_await_gateway_decision``), which ``prompt_dangerous_approval`` never
      reaches; trying to prompt from a gateway session would hit the
      ``input()`` fallback and silently deny. Staging gives the user a real
      review affordance (``/memory pending``) instead.
    * Scripts, cron, and background threads â€” no user present.
    r   ©Ú_get_approval_callbackNF)Útools.terminal_toolrž   r   r�   s    r   r–   r–   ;  sO   € ðØ>Ð>Ð>Ð>Ð>Ð>Ø%Ð%Ñ'Ô'¨tÐ3Ð3øÝð ð ð Øˆuˆuðøøøs   ‚ ”
"¡"ÚdetailúOptional[bool]c                ó`  — 	 ddl m} n# t          $ r Y dS w xY w |¦   «         }|€dS |                      ¦   «         pd}|                     ¦   «         }d|› �}|r|n|}	  |||d¬¦  «        }n3# t          $ r&}	t                               d|	¦  «         Y d}	~	dS d}	~	ww xY w|d	v rd
S |dk    rdS dS )uo  Prompt the user inline to approve a memory write.

    Returns True (approved), False (denied), or None (no interactive prompt
    available / prompt failed â†’ caller should stage instead).

    Reuses the per-thread CLI approval callback registered for dangerous
    commands (``tools.terminal_tool.set_approval_callback``). The callback is
    invoked directly â€” NOT via ``prompt_dangerous_approval`` â€” because that
    wrapper falls back to ``input()`` (deadlock-prone under prompt_toolkit,
    see #15216) and converts callback errors into a silent deny; here a
    failed prompt must stage the write instead.
    r   r�   NzSave to memory?zSave to memory: F)Úallow_permanentz(Inline memory approval prompt failed: %s>   ÚonceÚsessionTÚdeny)rŸ   rž   r   r(   rO   rP   )
r0   r    rž   ÚcallbackÚheaderÚbodyÚdescriptionÚcommandÚchoicerV   s
             r   r—   r—   Q  s  € ðØ>Ð>Ð>Ð>Ð>Ð>Ð>øÝð ð ð Øˆtˆtðøøøð &Ð%Ñ'Ô'€HØÐð ˆtà�]Š]‰_Œ_Ð1Ð 1€FØ�<Š<‰>Œ>€DØ- VÐ-Ð-€KØÐ&ˆdˆd €Gð
Ø�˜' ;ÀÐFÑFÔFˆˆøÝð ð ð Ý�ŠÐ?ÀÑCÔCÐCØˆtˆtˆtˆtˆtøøøøðøøøð Ð$Ð$Ð$ØˆtØ�ÒÐØˆuð ˆ4s$   ‚	 ‰
–ÁA- Á-
BÁ7BÂB)ÚcontentÚ	file_pathÚ
old_stringÚ
new_stringr4   Únamer­   r®   r¯   r°   c          	     óö  — | dv rs|rqt          |¦  «        }t          |¦  «        dk    rt          |¦  «        dz  dz   › d�nt          |¦  «        › d�}| dk    rdnd}|r|› d|› d	|› d
|› d�S |› d|› d|› d�S | dk    rK|pd}	|r|                     d¦  «        dz   nd}
|r|                     d¦  «        dz   nd}d|› d|	› d|› d|
› d�	S | dk    r	d|› d|› d�S | dk    r	d|› d|› d�S | dk    rd|› d�S | › d|› d�S )ug  Build a one-line human gist for a pending skill write.

    Heuristic, no model call â€” the gist surfaces enough to decide approve/reject
    in a chat bubble, while the full diff stays behind /skills diff (CLI/
    dashboard/file). For create/edit it pulls the frontmatter ``description:``;
    for patch/write_file it describes the size of the change.
    >   ÚeditÚcreatei   rs   z KBz charsr´   Úrewritez 'u   ' â€” z (ú)z' (ÚpatchúSKILL.mdÚ
r   zpatch 'z' z (+z/-z lines)Ú
write_filezwrite z in 'ú'Úremove_filezremove z from 'Údeleteúdelete skill ')Ú_frontmatter_descriptionÚlenÚcount)r4   r±   r­   r®   r¯   r°   ÚdescÚsizeÚverbÚtargetÚremovedÚaddeds               r   Ú
skill_gistrÈ   „  sÆ  € ð Ð#Ð#Ð#¨Ð#Ý'¨Ñ0Ô0ˆÝ36°w±<´<À4Ò3GÐ3G•#�g‘,”, $Ñ&¨Ñ*Ð/Ð/Ð/Ð/ÕPSÐT[ÑP\ÔP\ÐMdÐMdÐMdˆØ! XÒ-Ð-ˆxˆx°9ˆØð 	:ØÐ9Ð9˜dÐ9Ð9¨$Ð9Ð9°$Ð9Ð9Ð9Ð9ØÐ*Ð*˜$Ð*Ð* 4Ð*Ð*Ð*Ð*Ø�ÒÐØÐ(˜jˆØ0:ÐA�*×"Ò" 4Ñ(Ô(¨1Ñ,Ð,ÀˆØ.8Ð?�
× Ò  Ñ&Ô&¨Ñ*Ð*¸aˆØE˜ÐEÐE ÐEÐE¨EÐEÐE°WÐEÐEÐEÐEØ�ÒÐØ/˜	Ð/Ð/¨Ð/Ð/Ð/Ð/Ø�ÒÐØ2˜Ð2Ð2¨4Ð2Ð2Ð2Ð2Ø�ÒÐØ' Ð'Ð'Ð'Ð'ØÐÐ˜ÐÐÐÐr*   c                óÒ   — ddl }|                     d| |j        ¦  «        }|sdS |                     d¦  «                             ¦   «                              d¦  «        }|dd…         S )zBExtract the ``description:`` value from SKILL.md YAML frontmatter.r   Nz^description:\s*(.+)$r5   rs   z'"éŒ   )ÚreÚsearchÚ	MULTILINEÚgroupr(   )r­   rË   ÚmrÂ   s       r   r¿   r¿   £  sg   € à€I€I€IØ
�	Š	Ð*¨G°R´\ÑBÔB€AØð ØˆrØ�7Š7�1‰:Œ:×ÒÑÔ×#Ò# EÑ*Ô*€DØ���Œ:Ðr*   rR   c                óh  — ddl }|                      di ¦  «        }|                     dd¦  «        }|                     dd¦  «        }|dk    r|                     d¦  «        pdS 	 dd	lm} n# t          $ r d}Y nw xY wd}d
}|�‡ ||¦  «        }|rz|d         }	|dk    r|	d
z  }
n(|dv r|                     d¦  «        pd
}|	|z  }
|}n|	d
z  }
	 |
                     ¦   «         r|
                     d¬¦  «        }n# t          $ r d}Y nw xY w|dk    r|                     d¦  «        pd}n«|dk    rP|                     d¦  «        pd}|                     d¦  «        pd}|r|                     ||¦  «        nd|›d|›d�}nU|dk    r|                     d¦  «        pd}n7|dk    rd|                     d¦  «        › d|› d�S |dk    rd|› d�S d|› d |› d!�S |                     | 	                    d"¬#¦  «        | 	                    d"¬#¦  «        d$|› �d%|› �¬&¦  «        }d 
                    |¦  «        }|pd'S )(aF  Build a full unified diff (or full content) for a staged skill write.

    Used by /skills diff <id> on a surface that can render it (CLI pager, web
    dashboard, or by opening the pending JSON file). For create this is the new
    file content; for edit/patch it is a unified diff against the current
    on-disk skill.
    r   Nr.   r4   r5   r±   r´   r­   )Ú_find_skillr¸   rT   r³   >   r·   rº   r®   r?   r@   r·   r¯   r°   z(patch u    â†’ r¶   rº   Úfile_contentr¼   zremove file: z from skill 'r»   r½   r¾   ú(z on 'z')T)Úkeependsza/zb/)ÚfromfileÚtofilez(no textual change))ÚdifflibrF   Útools.skill_manager_toolrÑ   r   r_   rc   rN   Úunified_diffÚ
splitlinesÚjoin)rR   r×   r.   r4   r±   rÑ   ÚcurrentÚtarget_labelÚfoundÚbaserg   ÚrelÚnewÚold_sÚnew_sÚdiffÚtexts                    r   Úskill_pending_diffræ   ­  s  € ð €N€N€NØ�jŠj˜ BÑ'Ô'€GØ�[Š[˜ 2Ñ&Ô&€FØ�;Š;�v˜rÑ"Ô"€Dà�ÒÐØ—’˜IÑ&Ô&Ð,¨"Ð-ðØ8Ð8Ð8Ð8Ð8Ð8Ð8øÝð ð ð Øˆˆˆðøøøð €GØ€LØÐØ�˜DÑ!Ô!ˆØð 	Ø˜”=ˆDØ˜ÒÐØ˜:Ñ%��ØÐ2Ð2Ð2Ø—k’k +Ñ.Ô.Ð<°*�Ø˜3‘J�Ø"��à˜:Ñ%�ðØ—8’8‘:”:ð <ØŸkšk°7˜kÑ;Ô;�GøøÝð ð ð Ø���ðøøøð �ÒÐØ�kŠk˜)Ñ$Ô$Ð*¨ˆˆØ	�7Ò	Ð	Ø—’˜LÑ)Ô)Ð/¨RˆØ—’˜LÑ)Ô)Ð/¨RˆØ/6Ð^ˆg�oŠo˜e UÑ+Ô+Ð+Ð<^ÀeÐ<^Ð<^ÐTYÐ<^Ð<^Ð<^ˆˆØ	�<Ò	Ð	Ø�kŠk˜.Ñ)Ô)Ð/¨RˆˆØ	�=Ò	 Ð	 ØM˜wŸ{š{¨;Ñ7Ô7ÐMÐMÀdÐMÐMÐMÐMØ	�8Ò	Ð	Ø' Ð'Ð'Ð'Ð'à(�6Ð(Ð( Ð(Ð(Ð(Ð(à×ÒØ×Ò DÐÑ)Ô)Ø�Š ˆÑ%Ô%Ø$�lÐ$Ð$Ø"�LÐ"Ð"ð	  ñ ô €Dð �7Š7�4‰=Œ=€DØÐ(Ð(Ð(s$   Á%A, Á,A;Á:A;Ã*C9 Ã9DÄD)r   r   r   r   )r   r   r   r   )r   r   r   r   )
r   r   r.   r/   r0   r   r1   r   r   r/   )r   r   r   rX   )r   r   ri   r   r   rj   )r   r   ri   r   r   r   )r   r   r   rp   )r   r   )r   r   )r   r   r‘   r   r’   r   r   rƒ   )r0   r   r    r   r   r¡   )r4   r   r±   r   r­   r   r®   r   r¯   r   r°   r   r   r   )r­   r   r   r   )rR   r/   r   r   ))r�   Ú
__future__r   rK   ÚloggingrM   rG   rC   Úpathlibr   Útypingr   r   r   r   Úhermes_constantsr
   Ú	getLoggerrŒ   rO   ÚMEMORYr•   r   r   r   r   r-   rW   rh   rl   ro   ry   r~   r�   rƒ   r›   r–   r—   rÈ   r¿   ræ   rt   r*   r   ú<module>rî      sl  ðð'ð 'ðR #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø Ð Ð Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à ,Ð ,Ð ,Ð ,Ð ,Ð ,à	ˆÔ	˜8Ñ	$Ô	$€ð 
€Ø	€Ø�vÐ€ð €
ð#ð #ð #ð #ð$ð ð ð ð$5ð 5ð 5ð 5ð%ð %ð %ð %ðPð ð ð ðð ð ð ð	ð 	ð 	ð 	ðð ð ð ðð ð ð ð3ð 3ð 3ð 3ðð ð ð ð ñ ô ð ð. <>Ø')ð;ð ;ð ;ð ;ð ;ð ;ð|ð ð ð ð,,ð ,ð ,ð ,ðf :<Ø "°bØ!#ð ð  ð  ð  ð  ð  ð>ð ð ð ð@)ð @)ð @)ð @)ð @)ð @)r*   