
    `gj*                    R   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mZmZ ddl	m
Z
 ddlmZ dZ ej                  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d	 	 	 	 	 	 	 d,dZddd-dZd.dZd/dZd0dZ ddd	 	 	 	 	 	 	 	 	 d1d Z!d2d!Z"y)3a  Markdown/QMD export helpers for Hermes sessions.

This module is intentionally filesystem-only: it formats already-exported
SessionDB dictionaries and writes them to user-selected export directories. It
must not mutate state.db or call delete/prune/archive APIs.
    )annotationsN)datetimetimezone)Path)Anyz"hermes sessions export (md/qmd) v1z+- SHA256 of exported body: `([0-9a-f]{64})`c                    | | dk(  ry	 t        |       }t	        j
                  |t        j                        j                         j                  dd      S # t        t        f$ r t        |       cY S w xY w)N )tzz+00:00Z)
float	TypeError
ValueErrorstrr   fromtimestampr   utc	isoformatreplace)valuetss     O/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/session_export_md.py_iso_timestampr      sn    }5\ !!"6@@BJJ8UXYY z" 5zs   A A54A5c                <   | yt        | t              r| rdS dS t        | t        t        f      r't        | t              st	        j
                  | d      S t        | t              rt	        j
                  | d      S t	        j
                  t        |       d      S )NnulltruefalseF)ensure_ascii)
isinstanceboolintr   jsondumpslistr   )r   s    r   _frontmatter_valuer#       sy    }%v+G+%#u&z%/Fzz%e44%zz%e44::c%ju55    c                "    |  dt        |       S )Nz: )r#   )keyr   s     r   _frontmatter_liner'   ,   s    U"'./00r$   c                8   t        | j                  d      xs d      }|j                         }| j                  d      xs | j                  d      }|dk(  r|rd| }t        | j                  d      xs | j                  d            }d	| |rd
|z    S d S )Nrolemessagename	tool_nametoolu	   Tool — 
created_at	timestampz### u    — r	   )r   get
capitalizer   )r*   r)   labelr+   r/   s        r   _message_headingr3   0   s    w{{6"/i0DOOE;;v:'++k":Dv~$D6"w{{<8TGKK<TUI%	9,BCCrBCCr$   c                    | yt        | t              r| j                         S dt        j                  | dd      z   dz   S )Nr	   z```json
F   r   indent
```)r   r   rstripr    r!   )contents    r   _render_contentr;   :   s>    '3~~G%JJWTTr$   c                D    | sydt        j                  | dd      z   dz   S )Nr	   z

## Tool calls

```json
Fr5   r6   r8   )r    r!   )
tool_callss    r   _render_tool_callsr>   B   s(    +djjRW`a.bbelllr$   c                d    t        | j                  d      xs | j                  d      xs d      S )Nid
session_idzunknown-session)r   r0   sessions    r   _session_idrD   H   s*    w{{4 RGKK$=RARSSr$   c                    | j                  d      }t        |t              r#|r!|D cg c]  }t        |t              s| c}S | gS c c}w )Nsegments)r0   r   r"   dict)rC   rF   ss      r   	_segmentsrI   L   sC    {{:&H(D!h#;az!T':;;9 <s
   AAc                8    t        d t        |       D              S )Nc              3  X   K   | ]"  }t        |j                  d       xs g        $ yw)messagesN)lenr0   ).0segs     r   	<genexpr>z!_message_count.<locals>.<genexpr>T   s#     L#s377:&,"-Ls   (*)sumrI   rB   s    r   _message_countrR   S   s    L79KLLLr$   c                   dg}t        |       }t        |       }|dk(  r3|j                  d       dj                  |      j	                         dz   S t        |      dkD  }|D ]  }|r|j                  dt        |       d       t        |j                  d      xs g       D ]  }|j                  t        |      dz          t        |j                  d            }|r|j                  |dz          t        |j                  d	            }|r|j                  |dz          |j                  d
         dj                  |      j	                         dz   S )Nz## Messages
r   z_No messages in this session._

   z## Compression segment: rL   r:   r=   r	   )rI   rR   appendjoinr9   rM   rD   r"   r0   r3   r;   r>   )	rC   partsrF   total_messagesmulti_segmentsegmentr*   rendered_contentr=   s	            r   _render_messagesr]   W   s@   '(E!H#G,N78yy&&(4//MA%M LL3K4H3ILMGKK
39r: 	GLL)'2T9:.w{{9/EF-45+GKK,EFJZ$./LL	 99U""$t++r$   c                  t        |       }| j                  d      xs |}| j                  d      xs | j                  d      }t        | j                  d      xs | j                  d            }t        | j                  d      xs | j                  d            }t        | j                  d            }t        |      }	t        |       }
d	t	        d
|      t	        d| j                  d            t	        d| j                  d            t	        d|      t	        d|      t	        d|      t	        d| j                  d            t	        d|      t	        d| j                  d            t	        dt        | j                  d                  t	        d|
      t	        d| j                  d      xs d      g}| j                  d      r*|j                  t	        d| j                  d                   |j                  t	        d|      t	        d|	      t	        dt              d	dg       dj                  |      d| dg}|j                  d| d       | j                  d      r$|j                  d| j                  d       d       | j                  d      r$|j                  d| j                  d       d       |j                  t        |              |j                  d       |j                  d| d       |j                  d |
 d       |j                  d!| j                  d|
       d       |j                  d"|	 d       |j                  d#       dj                  |      j                         dz   S )$Ntitlebilling_providerprovider
started_atr.   last_active
updated_atended_atz---rA   sourcemodelcwdarchivedmessage_counttool_call_countr   lineage_session_idsformatexported_atexporterr	   rT   z# zSession ID: `z`
z	Source: `zWorking directory: `z## Export verification
- Session id: ``- Exported messages: `z&- Source DB message count at export: `z- Exported at: `z3- SHA256 of exported body: `__SHA256_PLACEHOLDER__`)rD   r0   r   rR   r'   r   rV   extendEXPORTER_VERSIONrW   r]   r9   )rC   fmtrn   rA   r_   ra   rb   rc   re   exported_isorj   frontmatterrX   s                r   _export_body_without_hashrx   o   s
   W%JKK .JE{{-.I'++j2IHL 9 VW[[=VWJ ]!;!Xw{{<?XYKgkk*56H!+.L"7+M 	,
3'7;;w#78(GKK$9:,
3,4*h/'7;;w#78*h/%U!34*d7;;z+B&CD/=9+W[[9J-K-PqQK {{(),-BGKKPeDfgh(C(-6*&67
  YY{#r%^4E	LL=C01{{8yX!6 7s;<{{5+GKK,>+?sCD	LL!'*+	LL+,	LL?:,a01	LL)-:;	LL9'++oWd:e9ffghi	LL#L>34	LLFG99U""$t++r$   c                .    t         j                  d|       S )Nz$- SHA256 of exported body: `pending`)_SHA_LINE_REsub)texts    r   _body_for_digestr}      s    BDIIr$   mdT)ru   include_verificationc               d   |dvrt        d      t        j                         }t        | ||      }|j                  dd      }t	        j
                  |j                  d            j                         }|r|j                  d|      S |j                  dd	      d
   j                         dz   }|S )z:Render a SessionDB export dictionary as Markdown/QMD text.>   r~   qmdfmt must be 'md' or 'qmd')ru   rn   z`__SHA256_PLACEHOLDER__`z	`pending`utf-8__SHA256_PLACEHOLDER__z
## Export verification
rU   r   rT   )
r   timerx   r   hashlibsha256encode	hexdigestsplitr9   )rC   ru   r   rn   bodydigest_bodydigestbefore_verifications           r   render_session_markdownr      s     -455))+K$W#;OD,,9;GK^^K..w78BBDF||4f==**%A1EaHOOQTXXr$   ru   c                   |dvrt        d      t        |       }t        | j                  d      xs d      }t	        j
                  dd|      j                  d      j                         }|sd}|dd	 }| d| d
| S )z@Return a deterministic, path-safe filename for a session export.>   r~   r   r   r_   rC   z[^A-Za-z0-9._-]+-z.-_N<   .)r   rD   r   r0   rer{   striplower)rC   ru   rA   r_   slugs        r   safe_session_filenamer      s    
-455W%JG$1	2E66%sE288?EEGD9D\4&#''r$   c                v    t        j                  t        |       j                               j	                         S )N)r   r   r   
read_bytesr   )paths    r   file_sha256r      s'    >>$t*//12<<>>r$   c                |   t        |       }|j                         sy|j                  d      }t        j	                  |      }|syt        j                  t        |      j                  d            j                         }||j                  d      k7  ryt        |      }d| d|vry	d
t        |       d|vryy)N)Fzfile missingr   encoding)Fzsha256 marker missingrU   )Fzsha256 mismatchrr   rq   )Fzmessage count mismatchrp   )Fzsession id mismatch)Tok)r   exists	read_textrz   searchr   r   r}   r   r   grouprR   rD   )r   rC   pr|   matchactualexpected_counts          r   verify_export_filer      s    T
A88:$;;;(D%E-^^,T299'BCMMOFQ'#G,N	/q1=.	W-.a0<+r$   c                z    ddl m dfdt        |       }dD ]  }||v s||    ||         ||<    |S )u  Return a deep copy of a session export dict with secrets redacted.

    Runs every message's content and tool-call arguments through the
    force-mode redaction pass (``agent.redact.redact_sensitive_text``), so
    API keys, tokens, and credentials that appeared in tool output never
    land in plaintext export files. Force mode ignores the user's global
    ``security.redact_secrets`` preference — an explicit ``--redact`` export
    must never emit raw secrets.
    r   )redact_sensitive_textc                   t        | t              r
 | d      S t        | t              r| D cg c]
  } |       c}S t        | t              r*| j	                         D ci c]  \  }}| |       c}}S | S c c}w c c}}w )NT)force)r   r   r"   rG   items)r   vk_cleanr   s      r   r   z#redact_session_data.<locals>._clean   ss    eS!(d;;eT"',-!F1I--eT"-2[[];TQAvayL;; .;s   A>%B)rL   rF   )r   r   returnr   )agent.redactr   rG   )rC   redactedr&   r   r   s      @@r   redact_session_datar      sP     3 G}H' 2(?x}8"8C=1HSM2 Or$   F)ru   r   c                  t        |      j                         }|j                  dd       |t        | |      z  }|j	                         r|st        t        |            |j                  t        | |      d       |S )zWrite a Markdown/QMD export file and return its path.

    Raises FileExistsError when the destination exists and force=False.
    Tparentsexist_okr   r   r   )	r   
expandusermkdirr   r   FileExistsErrorr   
write_textr   )rC   
output_dirru   r   out_dirr   s         r   write_session_markdownr      sp     :))+GMM$M.*7<<D{{}Uc$i((OO+G=OPKr$   c                  t        |       j                         }|j                  dd       t        |      }t        |      |j	                  d      xs t        |      gt        |      |t        |      t        |      t        j                         d}|dz  }|j                  dd      5 }|j                  t        j                  |d	d
      dz          d d d        |S # 1 sw Y   |S xY w)NTr   rl   )rA   rl   r   rm   rj   r   rn   zmanifest.jsonlar   r   F)r   	sort_keysrT   )r   r   r   rD   r0   r   rR   r   r   openwriter    r!   )	r   rC   r   ru   r   export_pathentrymanifestfhs	            r   append_manifest_entryr     s    :))+GMM$M.t*K!'*&{{+@A[kRYFZE[K '0k*yy{E ))H	sW	- O
EFMNOOOOs   -+C""C,)r   r   r   r   )r&   r   r   r   r   r   )r*   dict[str, Any]r   r   )r:   r   r   r   )r=   r   r   r   )rC   r   r   r   )rC   r   r   zlist[dict[str, Any]])rC   r   r   r   )rC   r   ru   r   rn   r   r   r   )r|   r   r   r   )rC   r   ru   r   r   r   r   r   )rC   r   ru   r   r   r   )r   
Path | strr   r   )r   r   rC   r   r   ztuple[bool, str])rC   r   r   r   )
rC   r   r   r   ru   r   r   r   r   r   )
r   r   rC   r   r   r   ru   r   r   r   )#__doc__
__future__r   r   r    r   r   r   r   pathlibr   typingr   rt   compilerz   r   r#   r'   r3   r;   r>   rD   rI   rR   r]   rx   r}   r   r   r   r   r   r   r    r$   r   <module>r      s   #   	  '  7 rzzHIZ	61DUmTM,01,hJ
 ,0d%(GK  BF 
(?&: DHW\)3=@PT	 r$   