
    `gjn                        d Z ddlmZ ddlmZ ddlmZ dddZddZdd	Z	dd
Z
ddZddZddZddZddZddZddZddZd dZddZd!dZd"dZy)#u8  User-initiated edit/delete for journey nodes (learned skills + memories).

The journey graph (``agent.learning_graph``) gives every node a stable id:

- **skills** → the skill name (e.g. ``"debugging-hermes-desktop"``)
- **memories** → ``memory:<source>:<index>`` where ``source`` is ``memory``
  (``MEMORY.md``) or ``profile`` (``USER.md``) and ``index`` is the node's
  position in the combined card list (``MEMORY.md`` cards first, then
  ``USER.md``).

This module maps a node id back to its on-disk home and performs the mutation,
shared by the CLI (``hermes journey delete|edit``), the TUI ``/journey`` overlay
(gateway RPCs), and the desktop GUI (REST). Deleting a skill *archives* it
(recoverable via ``hermes curator restore``); deleting a memory rewrites its
file. Pure stdlib + existing skill/memory helpers.
    )annotations)Path)Anyz	MEMORY.mdzUSER.md)memoryprofilec                ,    | j                  d      rdS dS )Nzmemory:r   skill)
startswith)node_ids    K/root/.hermes/venv/lib/python3.12/site-packages/agent/learning_mutations.pyparse_node_kindr      s    )))48A'A    c                 "    ddl m}   |        dz  S )Nr   get_hermes_homememories)hermes_constantsr   r   s    r   _memories_dirr      s    0z))r   c                    | j                  dd      }t        |      dk7  s|d   dk7  s|d   t        vrt        d|       	 |d   t	        |d         fS # t        $ r}t        d|       |d}~ww xY w)	u7   ``memory:<source>:<index>`` → (source, global_index).:      r   r      zbad memory node id: N)splitlen_MEMORY_FILES
ValueErrorint)r   partsexcs      r   _parse_memory_idr!   $   s    MM#q!E
5zQ%(h.%(-2O/{;<<FQxU1X&& F/{;<#EFs   A 	A3A..A3c                    ddl m}  |       }d|cxk  rt        |      k  sn t        d| d      ||   j	                  d      | k7  rt        d      | dk(  r|S |t        d |D              z
  S )	u   Global card index → position within the source's own file.

    ``_memory_cards`` emits all ``MEMORY.md`` cards before ``USER.md`` cards, so
    a profile card's local index is its global index minus the memory count.
    r   )_memory_cardszmemory index z out of rangesource-   memory node id is stale — refresh the graphr   c              3  J   K   | ]  }|j                  d       dk(  sd  yw)r$   r   r   N)get).0cs     r   	<genexpr>z&_memory_local_index.<locals>.<genexpr>>   s     NA!%%/X2MaNs   ##)agent.learning_graphr#   r   
IndexErrorr'   r   sum)r$   global_indexr#   cardss       r   _memory_local_indexr0   /   s{     3OE)s5z)=mDEE\x(F2HII#NNNNNr   c                    ddl m} t               t        |    z  }|j	                         st        |j                   d      |j                  |      }t        | |      }d|cxk  rt        |      k  st        d       t        d      |||fS )u   Resolve a memory card to its file, all §-delimited entries, and local index.

    Entries come from ``MemoryStore._read_file`` — the same parser the memory
    tool uses — so journey indices stay aligned with what the graph renders.
    r   MemoryStorez
 not foundr%   )
tools.memory_toolr3   r   r   existsr   name
_read_filer0   r   )r$   gidxr3   pathchunkslocals         r   _locate_memoryr<   A   s     .?]622D;;=DII;j122##D)F-E#F#HII $HIIr   c                n    	 t        |       S # t        t        f$ r}dt        |      dcY d}~S d}~ww xY w)zvCurrent content for an edit prefill. ``content`` is the full SKILL.md
    (skills) or the raw memory chunk (memories).FokmessageN)_node_detailr   r,   strr   r    s     r   node_detailrD   V   s6    2G$$
# 2C112s   
 4/44c                n   t        |       dk(  rMt        |       \  }}t        ||      \  }}}||   j                         }dd| |j	                         d   d d |dS ddlm}  ||       }|s	dd|  d	d
S t        |d         dz  }	|	j                         s	dd|  dd
S dd| | |	j                  d      dS )Nr   Tr   P   )r?   kindidlabelcontent)_find_skillFzskill 'z' not foundr>   r9   zSKILL.mdzSKILL.md missing for ''r	   zutf-8)encoding)
r   r!   r<   strip
splitlinestools.skill_manager_toolrK   r   r5   	read_text)
r   r$   r8   _r:   r;   bodyrK   foundskill_mds
             r   rA   rA   _   s    w8+'0)&$765e}""$HGdooFWXYFZ[^\^F_lpqq4 E''+(FGGE&M"Z/H??*@	(KLL %%w%7 r   c                    	 t        |       dk(  rt        |       S t        |       S # t        t        f$ r}dt        |      dcY d }~S d }~ww xY wNr   Fr>   )r   _delete_memory_delete_skillr   r,   rB   rC   s     r   delete_noderZ   |   sN    2*9'*Bh*N~g&jTabiTjj
# 2C112s   & 
& AAAAc                    ddl m} |j                  |       j                  d      rdd|  d|  ddS |j	                  |       \  }}|r
t                ||r
d	|  d
|  dS |dS )Nr   )skill_usagepinnedFrL   u5   ' is pinned — unpin it first (hermes curator unpin )r>   z
archived 'u+   ' — restore with: hermes curator restore )toolsr\   
get_recordr'   archive_skill_clear_skill_cache)r6   r\   r?   r@   s       r   rY   rY      s    !d#''1!D61fgkfllm(noo++D1KB	ik:dV3^_c^d!eyyqxyyr   c                    t        |       \  }}t        ||      \  }}}||= t        ||       dd|j                   dS )NTzdeleted memory from r>   )r!   r<   _write_memoryr6   )r   r$   r8   r9   r:   r;   s         r   rX   rX      sK    #G,LFD(6D&%u$%9$))#EFFr   c                    	 t        |       dk(  rt        | |      S t        | |      S # t        t        f$ r}dt        |      dcY d }~S d }~ww xY wrW   )r   _edit_memory_edit_skillr   r,   rB   )r   rJ   r    s      r   	edit_noderh      sS    21@1IX1U|GW-x[fgnpw[xx
# 2C112s   ( ( AA
A
Ac                    ddl m}  || |      }|j                  d      rt                dd|  ddS d|j                  d	d
      dS )Nr   )rg   successTz	updated 'rL   r>   Ferrorzedit failed)rP   rg   r'   rb   )r6   rJ   _do_editresults       r   rg   rg      sM    @dG$Fzz)4&':;;FJJw$FGGr   c                    t        |       \  }}|j                         }|sdddS t        ||      \  }}}|||<   t        ||       dd|j                   dS )NFu(   empty memory — use delete to remove itr>   Tzupdated memory in )r!   rN   r<   rd   r6   )r   rJ   r$   r8   rS   r9   r:   r;   s           r   rf   rf      sg    #G,LFD==?D(RSS(6D&%F5M$%7		{#CDDr   c                    ddl m} |j                  | |D cg c]#  }|j                         s|j                         % c}       yc c}w )u   Atomic temp-file + rename via the memory tool, so a concurrent reader
    never sees a half-written file (and the §-join stays single-sourced).r   r2   N)r4   r3   _write_filerN   )r9   r:   r3   r)   s       r   rd   rd      s3     .Df"J	1779"JK"Js
   A
A
c                 B    	 ddl m}   | d       y # t        $ r Y y w xY w)Nr    clear_skills_system_prompt_cacheT)clear_snapshot)agent.prompt_builderrs   	Exceptionrr   s    r   rb   rb      s$    I(= s    	N)r   rB   returnrB   )rw   r   )r   rB   rw   ztuple[str, int])r$   rB   r.   r   rw   r   )r$   rB   r8   r   rw   ztuple[Path, list[str], int])r   rB   rw   dict[str, Any])r6   rB   rw   rx   )r   rB   rJ   rB   rw   rx   )r6   rB   rJ   rB   rw   rx   )r9   r   r:   z	list[str]rw   None)rw   ry   )__doc__
__future__r   pathlibr   typingr   r   r   r   r!   r0   r<   rD   rA   rZ   rY   rX   rh   rg   rf   rd   rb    r   r   <module>r      sr   " #  &9=B*FO$*2:2
zG2	H
E Lr   