
    }-jp              
          d Z ddlZddlZddlmZ ddlmZ  ej        e          Z	h dZ
dZdZdd	d
ddddddd	Zdedz  defdZdedefdZd?dedee         dedefdZdefdZdedefdZdedefdZdefd Zdedefd!Zdedefd"Zdedefd#Zdedefd$Zd%edz  d&edz  defd'Zd(eeef         d)edz  dedz  fd*Z d+e!e         de!e         fd,Z"	 	 	 d@d/ed0ed1e#ed2f         dz  de!e         fd3Z$ded4edefd5Z%d6d7d)ed8edefd9Z&dAd/ed)edz  d;edefd<Z'd/ed=e!e         ee         z  deeef         fd>Z(dS )Bz?Shared helpers for reading Hermes Agent sessions from state.db.    N)closing)Path>   slackweixindiscordtelegram      APICLICronDiscordSlackTelegramToolWebUIWeixin)	
api_serverclicronr   r   r   toolwebuir   
raw_sourcereturnc                    t          | pd                                                                          pd}|dk    rd}n2|dk    rd}n)|t          v rd}n|dk    rd}n|dk    rd}n|dk    rd	}nd
}t                              |          }|s0|dk    r(|                    dd                                          nd}|dk    rdn|||dS )a  Return stable source metadata for Hermes Agent session rows.

    ``sessions.source`` is an Agent-level raw value. WebUI needs a smaller,
    durable contract so routes, SSE snapshots, and future sidebar policies do
    not each reimplement raw-source checks.
     unknownr   r   	messagingr   r   r   apiother_ AgentN)r   session_sourcesource_label)strstriplowerMESSAGING_SOURCESSOURCE_LABELSgetreplacetitle)r   rawr$   labels       (/root/hermes-webui/api/agent_sessions.pynormalize_agent_session_sourcer1   !   s    jB


%
%
'
'
-
-
/
/
<9C
g~~ 		!	!	!$					 c""E O14	1A1AC%%++---w "Y..ddC(      rowc                 R    t          |                     d                    }i | |S )Nsource)r1   r+   )r3   
normalizeds     r0   _with_normalized_sourcer7   D   s+    /0A0ABBJ c Z  r2   NULLnamecolumnsfallbackc                 "    | |v rd|  n| d|  S )Nzs.z AS  )r9   r:   r;   s      r0   _optional_colr>   I   s(    '//;;;;(/F/F/F/FFr2   c                 l    t          | pd                                                                          S )Nr   )r&   r'   r(   values    r0   _safe_lowerrB   M   s,    u{!!##))+++r2   rA   c                     t          |           }|sdS |                    d          r*|d t          d                                                    }|S )Nr    session)rB   endswithlenr'   )rA   r5   s     r0   _normalize_source_namerG   Q   sZ    F rz"" 3)#j//))*0022Mr2   c           	      @   t          |                     d                    rdk    rdS dv rdS t          |                     d                    t          |                     d                    t          |                     d                    t          |                     d                    t          |                     d	                    h}|                    d
           |                    d           t          fd|D                       S )zCReturn True when a CLI row looks like framework-generated metadata.r-   untitledT>   cli sessionr   r5   r$   
source_tagr   r%   r   r   c              3   *   K   | ]}| d k    V  dS )rD   Nr=   ).0	candidater-   s     r0   	<genexpr>z0_looks_like_default_cli_title.<locals>.<genexpr>k   s1      RR9u9....RRRRRRr2   )rB   r+   rG   discardaddany)r3   source_candidatesr-   s     @r0   _looks_like_default_cli_titlerT   Z   s   (())E EZ''t&&&t 	swwx0011sww'78899sww|4455sww|4455sww~6677 b!!!%   RRRR@QRRRRRRr2   c                     	 t          dt          t          |                               S # t          t          f$ r Y dS w xY w)Nr   )maxintfloat	TypeError
ValueErrorr@   s    r0   _as_positive_intr[   n   sL    1c%,,''(((z"   qqs   ), A Ac                 
   |                      d          }||                      d          }|G|                      d          pg }t          |t                    rt          d |D                       S dS t	          |          S )Nactual_user_message_countuser_message_countmessagesc              3      K   | ]C}t          t          |t                    r|                    d           n|          dk    ?dV  DdS )roleuser   N)rB   
isinstancedictr+   )rM   msgs     r0   rO   z$_count_user_turns.<locals>.<genexpr>|   s_        *S$2G2GPswwvSQQU[[[ [[[[ r2   r   )r+   rd   listsumr[   )r3   
user_turnsr_   s      r0   _count_user_turnsrj   u   s    455JWW122
77:&&,"h%% 	  #     
 qJ'''r2   c                     t          |                     d                    }|dk    p!t          |                     d                    S )N_compression_segment_countrc   _lineage_root_id)r[   r+   bool)r3   segment_counts     r0   _has_cli_lineagerp      sA    $SWW-I%J%JKKM1ASWW-?%@%@ A AAr2   c                    t          | t                    sdS t          |                     d                    }|dk    rdS |dk    rdS t          |                     d                    }t          |                     d                    }t          |                     d                    }t          |                     d	                    }|dk    s|dk    s|dk    s|dk    rdS t	          |                     d
          o2|t
          vo)|t
          vo |t
          vo|t
          vot          |                     S )zEReturn True for rows that should be treated as CLI-imported sessions.Fr$   r   r   TrK   r   r5   r%   is_cli_session)rd   re   rB   r+   rn   r)   rT   )r3   r5   rK   r   source_namer%   s         r0   is_cli_session_rowrt      sV   c4   u!12233FutSWW\2233JSWW\2233Jcggh//00Ksww~6677LUjE11[E5I5I\]bMbMbt  !! 	/++	///	/ //	/ 00		/
 *#..  r2   c                 D   t          | t                    sdS t          |           sdS t          |                     d          p|                     d                    }|dk    rdS t          |           rdS t          |           sdS t          |           t          k    S )zFReturn whether a CLI-related row should remain visible in the sidebar.FTactual_message_countmessage_countr   )	rd   re   rt   r[   r+   rp   rT   rj   #CLI_MIN_UNTITLED_USER_MESSAGE_COUNT)r3   rw   s     r0   is_cli_session_row_visiblery      s    c4   uc"" t$SWW-C%D%D%`P_H`H`aaMu t(-- tS!!%HHHr2   parentchildc                    | r|sdS t          |                    d          pd                                                                          dk    rdS t          |                     d          pd                                                                          }t          |                    d          pd                                                                          }|r
|r||k    rdS |                     d          dvrdS |                     d          }|d
S 	 t	          |                    d          pd          t	          |          k    S # t
          t          f$ r Y dS w xY w)a  Return True when ``child`` is the next segment of the same conversation.

    Compression rotates session ids automatically. A manual CLI close followed
    by ``hermes -c`` also records a new child session; for sidebar projection it
    should continue the same visible conversation rather than becoming a
    separate child-session row. Plain parent/child links that started before the
    parent's ended boundary remain child sessions.

    Do not collapse lineage across raw sources. A WebUI session that continues
    from a Telegram/CLI/etc. parent must remain visible as its own surface-owned
    conversation; otherwise the tip inherits the root's title/source metadata and
    can disappear under messaging/sidebar policies.
    Fr$   r   forkr5   
end_reason>   	cli_closecompressionended_atNT
started_atr   )r&   r+   r'   r(   rX   rY   rZ   )rz   r{   parent_sourcechild_sourcer   s        r0   _is_continuation_sessionr      su      u
599%&&,"--3355;;==GGu

8,,23399;;AACCMuyy**0b117799??AAL  -<*G*Guzz,'CCCuzz*%%H tUYY|,,122eHooEEz"   uus   $4E E.-E.
rows_by_id
session_idc                    |sdS t          |          }|}|h}t          t          |           dz             D ]}|                     |          }|r|                    d          nd}|r|                     |          nd}|rt	          ||          s|c S ||v r|c S t          |          }t          |          }|                    |           |S )zLReturn the visible lineage root for ``session_id`` by walking continuations.Nrc   parent_session_id)r&   rangerF   r+   r   rQ   )	r   r   root_id
current_idseenr!   current	parent_idrz   s	            r0   _continuation_root_idr      s     t*ooGJ<D3z??Q&'' 
 
..,,8?IGKK 3444T	.7A	***T 	5fgFF 	NNNNNNi..^^
Nr2   rowsc                 8   d | D             i t                      }| D ]}|                    d          }|s                    |g                               |                               |          }t	          ||          r|                    |d                    d|d<   |r|                    d          nd|d<   |r|                    d	          nd|d
<   t          |          }|r||d<   ى                                D ]}|                    d d           dt          dt          t          dz  t          f         ffd}g }| D ])}|d         |v rd}	|}
|                    d          dv r ||          \  }
}	|
r|
                    d          pddk    rU|
|u r#|                    t          |                     |t          |          }dD ]}||
v r|
|         ||<   |                    d          s|
                    d          |d<   |                    d	          s|
                    d	          |d	<   |d         |d<   |
d         |d<   |	|d<   |                    |           +|                    d d           |S )a  Collapse compression chains into one logical sidebar row.

    The visible conversation should still look like the original chain head
    (title and timestamps), while importing should use the latest importable
    segment so the user continues from the current compressed state.
    c                      i | ]}|d          |S idr=   rM   r3   s     r0   
<dictcomp>z/_project_agent_session_rows.<locals>.<dictcomp>   s    111S#d)S111r2   r   r   child_sessionrelationship_typer-   Nparent_titler5   r   _parent_lineage_root_idc                 0    |                      d          pdS )Nr   r   r+   r3   s    r0   <lambda>z-_project_agent_session_rows.<locals>.<lambda>  s    cggl&;&;&@q r2   T)keyreverser3   r   c                    | | d         h|                      d          pddk    r| nd }d}t          t                    dz             D ]x}fd                     d         g           D             }|s||fc S |d                             d                    |dz  }                     d          pddk    r}y||fS )Nr   rv   r   rc   c                 H    g | ]}|d          vt          |          |S r   )r   )rM   r{   r   r   s     r0   
<listcomp>zH_project_agent_session_rows.<locals>.compression_tip.<locals>.<listcomp>  sC       ;d**/GQV/W/W* ***r2   )r+   r   rF   rQ   )	r3   latest_importablero   r!   
candidatesr   r   children_by_parentr   s	        @@r0   compression_tipz4_project_agent_session_rows.<locals>.compression_tip  s   D	{$'GG,B$C$C$HqA#M#MCCSWs:*++ 	, 	,A    #5#9#9'$-#L#L  J  8(-7777 mGHHWT]###QM2338qA==$+! -//r2   rc   r~   >   r   r   rv   r   )r   modelrw   rv   r]   r   r~   last_activityrm   _lineage_tip_idrl   c                 Z    |                      d          p|                      d          pdS )Nr   r   r   r   r   s    r0   r   z-_project_agent_session_rows.<locals>.<lambda>M  s(    00NCGGL4I4INQ r2   )setr+   
setdefaultappendr   rQ   r   valuessortre   tuplerW   )r   continuation_child_idsr3   r   rz   parent_rootchildrenr   	projectedro   tipmergedr   r   r   s                @@r0   _project_agent_session_rowsr      s>    21D111J02 UU = =GG/00	 	%%i44;;C@@@	**#FC00 	="&&s4y1111'6C#$9?"I&**W"5"5"5TC;A#K6::h#7#7#7tC /
IFFK =1<-.&--// P P@@$OOOO0T 0eD4K,<&= 0 0 0 0 0 0 0& I %! %!t9...77<  $@@@!0!5!5C 	sww566;!AA#::T#YY'''c
 	' 	'C czz!#hszz'"" 	/!ggg..F7Ozz(## 	1"wwx00F8%(Y!"$'I !/<+,    NNNN     r2      r   r   db_pathlimitexclude_sources.c           !      Z   t          |           } |                                 sg S |pt          }t          t	          j        t          |                               5 }t          j        |_        |	                                }|
                    d           d |                                D             }|
                    d           d |                                D             }d|vr$|                    d|            g cddd           S t          d|          }t          d	|          }	t          d
|          }
t          d|          }t          d|          }t          d|          }t          d|          }t          d|          }t          d|          }t          d|          }t          d|          }t          d|          }d|v rdnd}dg}g }|rht          d |D                       }|rMd                    d |D                       }|                    d| d           |                    |           |
                    d|	 d| d| d| d| d| d| d| d| d| d|
 d| d| d d!                    |           d"|           t%          d# |                                D                       }d$ |D             }d% |D             }||cddd           S |dt'          d&t)          |                             cddd           S # 1 swxY w Y   dS )'a	  Return agent sessions projected as importable conversations.

    Hermes Agent can create rows in ``state.db.sessions`` before a session has
    any messages, and long conversations can be split into compression-linked
    rows. WebUI cannot import empty rows and should not show compression
    segments as separate conversations, so both the regular ``/api/sessions``
    path and the gateway SSE watcher use this shared projection.

    By default, omit background/internal sources such as ``cron`` from the WebUI
    sidebar. This mirrors Hermes Agent CLI's session-list behaviour: interactive
    views should stay focused on user-facing conversations, while callers that
    need a source-specific diagnostic view can opt out by passing
    ``exclude_sources=None``.
    PRAGMA table_info(sessions)c                     h | ]
}|d          S rc   r=   r   s     r0   	<setcomp>z5read_importable_agent_session_rows.<locals>.<setcomp>s      9993A999r2   zPRAGMA table_info(messages)c                     h | ]
}|d          S r   r=   r   s     r0   r   z5read_importable_agent_session_rows.<locals>.<setcomp>u  r   r2   r5   zagent session listing skipped: state.db at %s has no 'source' column (older hermes-agent?). Agent sessions unavailable. Upgrade hermes-agent to fix this.Nr   r$   r   r~   user_idchat_id	chat_type	thread_idsession_keyorigin_chat_idorigin_user_idplatformra   z2COUNT(CASE WHEN LOWER(m.role) = 'user' THEN 1 END)zCOUNT(m.id)zs.source IS NOT NULLc              3   8   K   | ]}|t          |          V  d S )Nr&   )rM   r5   s     r0   rO   z5read_importable_agent_session_rows.<locals>.<genexpr>  s-      QQV&QS[[QQQQQQr2   z, c              3      K   | ]}d V  dS )?Nr=   )rM   r!   s     r0   rO   z5read_importable_agent_session_rows.<locals>.<genexpr>  s"      (?(?(?(?(?(?(?(?r2   zs.source NOT IN ()z{
            SELECT s.id, s.title, s.model, s.message_count,
                   s.started_at, s.source,
                   z,
                   zM,
                   COUNT(m.id) AS actual_message_count,
                   z AS actual_user_message_count,
                   MAX(m.timestamp) AS last_activity
            FROM sessions s
            LEFT JOIN messages m ON m.session_id = s.id
            WHERE z AND zj
            GROUP BY s.id
            ORDER BY COALESCE(MAX(m.timestamp), s.started_at) DESC
            c                 ,    g | ]}t          |          S r=   )re   r   s     r0   r   z6read_importable_agent_session_rows.<locals>.<listcomp>  s    0U0U0Usc0U0U0Ur2   c                 ,    g | ]}t          |          S r=   )r7   r   s     r0   r   z6read_importable_agent_session_rows.<locals>.<listcomp>  s!    GGGc,S11GGGr2   c                 0    g | ]}t          |          |S r=   )ry   r   s     r0   r   z6read_importable_agent_session_rows.<locals>.<listcomp>  s&    QQQS1KC1P1PQSQQQr2   r   )r   existsloggerr   sqlite3connectr&   Rowrow_factorycursorexecutefetchallwarningr>   r   joinr   extendr   rV   rW   )r   r   logr   conncursession_colsmessage_colsparent_exprsession_source_expr
ended_exprend_reason_expruser_id_exprchat_id_exprchat_type_exprthread_id_exprsession_key_exprorigin_chat_id_exprorigin_user_id_exprplatform_expruser_message_count_exprwhere_clausesparamsexcludedplaceholdersr   s                             r0   "read_importable_agent_session_rowsr   S  s   ( 7mmG>> 	
-C	W..	/	/ N.4";kkmm 	122299#,,..999122299#,,..999<''KK4 	   #N. N. N. N. N. N. N. N.& $$7FF+,<lKK":|<<
'lCC$Y==$Y==&{LAA&{LAA(EE+,<lKK+,<lKK%j,?? %% A@ 	  00 	(QQQQQQQH (#yy(?(?h(?(?(???$$%H%H%H%HIIIh''' (  !	 
 !  #  #  %  (  (  "       $   ,! ( <<..)  0 3	
 	
 	
6 00U0Ucllnn0U0U0UVV	GGYGGG	QQIQQQ	=[N. N. N. N. N. N. N. N.\ ,#aU,,,-]N. N. N. N. N. N. N. N. N. N. N. N. N. N. N. N. N. N.s    B'L GL /$L  L$'L$ra   c           
         |                      d          |                      d          n|                      d          }|                      d          ||                      d          |                      d          |                      d          ||                      d          |                      d          d u dd	S )	Nr   r   r   r-   r5   r~   F)	r   ra   r-   r5   r   
updated_atr~   activearchivedr   )r3   ra   r   s      r0   _lineage_report_rowr     s    (+
(;(;(G$$$SWWUaMbMbJggdmm!!''(##ggl++ ggl++''*%%-
 
 
r2   F)foundr   c                    d|| | | ddg g dd
S )NFr   
mutationr   r   lineage_keytip_session_idtotal_segmentsmaterialized_segmentssegmentsr   manual_reviewr=   )r   r   s     r0   _empty_lineage_reportr    s/     !$!"  r2      max_hopsc                    t          |pd                                          }|st          d          S t          |           } |                                 st          |          S 	 t          t          j        t          |                               5 }t          j        |_	        |
                                                    d           d                                 D             }h d}|                    |          st          |          cddd           S t          d|          t          d|          t          d|          t          d	|d
          t          d|          t          d|          t          d|          dt           dz  dt          dz  ffd} ||          }|st          |          cddd           S |g}	|}
|h}d}t!          t#          dt%          |                              D ]{}|
                    d          } ||          }|r||v rt)          |o||v           } nAt+          ||
          s n/|	                    |           |                    |           |}
|d}d |	D             }g }|	D ]}                    d d d d d d d d|d         f                                           D ]D}t          |          }|d         |v rt+          ||          rd}/|                    |           E	 ddd           n# 1 swxY w Y   n# t0          $ r t          |          cY S w xY w|	r|	d         d         n|}|	r|	d         d         n|}dd|||t3          |	          t3          |	          d t5          |	          D             d |D             |d
S )a  Return a bounded, read-only lifecycle report for a session lineage.

    This helper intentionally reports only facts that can be derived from
    ``state.db.sessions`` without mutating WebUI JSON, archiving rows, or
    deleting historical segments. It mirrors the sidebar continuation rules so
    a future UI/PR can explain which rows are hidden compression/cli-close
    segments and which child-session branches remain distinct.
    r   r   c                     h | ]
}|d          S r   r=   r   s     r0   r   z.read_session_lineage_report.<locals>.<setcomp>      ===sCF===r2   >   r   r~   r   Nr5   r$   r-   r   0r   r~   r   row_idr   c                     | sd S                      d d d	 d d d d d| f                                           }|rt          |          nd S )N=
                    SELECT s.id,
                           ,
                           z\
                    FROM sessions s
                    WHERE s.id = ?
                    )r   fetchonere   )
r  r3   r   r   r   r   r   source_exprstarted_expr
title_exprs
     r0   	fetch_onez.read_session_lineage_report.<locals>.fetch_one  s      4'  0  '	 
 )  (  '  ,   I   llnn$'1tCyyyT1r2   Fr   Tc                     h | ]
}|d          S r   r=   r   s     r0   r   z.read_session_lineage_report.<locals>.<setcomp>)  s    9993t9999r2   r  r  z
                    FROM sessions s
                    WHERE s.parent_session_id = ?
                    ORDER BY s.started_at DESC
                    r   c                 D    g | ]\  }}t          ||d k    rdnd          S )r   r   hidden_segmentr   )rM   idxr3   s      r0   r   z/read_session_lineage_report.<locals>.<listcomp>U  sC     
 
 
S  cQhhUU<LMM
 
 
r2   c                 .    g | ]}t          |d           S )r   r  r   s     r0   r   z/read_session_lineage_report.<locals>.<listcomp>Y  s#    UUU3(o>>UUUr2   r   )r&   r'   r  r   r   r   r   r   r   r   r   r   r   issubsetr>   re   r   rV   rW   r+   rn   r   r   rQ   	ExceptionrF   	enumerate)r   r   r
  sidr   r   requiredr  targetr  r   r   r  _hopr   rz   segment_ids
child_rows	child_rowr{   r   tip_idr   r   r   r   r   r  r  r  s                         @@@@@@@@r0   read_session_lineage_reportr*    s    jB


%
%
'
'C )$R(((7mmG>> *$S)))]*W_S\\2233 Z	-t&{D++--CKK5666==cllnn===L@@@H$$\22 2,S11Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- (,??K"/0@,"O"O&w==J(|SIIL&z<@@J+L,GGO'(;\JJK2#* 2 2 2 2 2 2 2 2 2 2 2 2 2 2* Ys^^F 2,S11QZ	- Z	- Z	- Z	- Z	- Z	- Z	- Z	-T xHG5D!Mc!S]]3344 % %#KK(;<<	"9-- d!2!2$()HyD7H$I$IME/@@ E'''###  $99999K%'J" - -'  0  '	 
 )  (  '  ,   D\O    "% - -I OOET{k11 />> !
 )- %%e,,,,-#-}Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	- Z	-v  * * *$S)))))* %-5hrl4  #G"*3Xa[F h--!$X
 
%h//
 
 
 VU*UUU&  sQ   0.M B MM +B-MM %EM7M MM 
MM M+*M+session_idsc           
         d |pg D             }t          |           } |r|                                 si S 	 t          t          j        t          |                               5 }t          j        |_        |                                }|	                    d           d |
                                D             }d|vsd|vri cddd           S t          d|          }d}i }t          |          }	t          d	          D ]}
|	s nt          |	          }t                      }	t          d
t          |          |          D ]}||||z            }d                    dt          |          z            }|	                    d| d| d|           |
                                D ]}t#          |          ||d         <   |D ]J}|                    |i                               d          }|r||vr||	vr|	                    |           Kddd           n# 1 swxY w Y   n# t(          $ r i cY S w xY wi }|D ]}|                    |          }|s|                    d          }|r|                    |          nd}|r|r|                    |i           }||d<   t-          ||          sd|d<   |                    d          |d<   |                    d          |d<   t          |                    d          pd                                                                          }t          |                    d          pd                                                                          }|r|r||k    rd|d<   t3          ||          }|r||d<   g|}|}d}|h}	 |                    |          }|r|                    d          nd}|r|                    |          nd}|r||v rn0t-          ||          sn|}|}|                    |           |dz  }~||k    r |                    |i           }||d<   ||d<   |S )a$  Return compression-lineage metadata for known WebUI sidebar sessions.

    WebUI sessions are persisted as JSON files, but Hermes Agent also mirrors
    them into ``state.db.sessions`` for insights/session history. Compression
    and cross-surface continuation create parent chains there. ``/api/sessions``
    needs to surface that lineage to the sidebar so client-side collapse can
    group logical continuations without mutating or deleting any session files.

    Missing DBs, old schemas, or incomplete rows degrade to an empty mapping.
    c                 0    h | ]}|t          |          S r=   r   )rM   r"  s     r0   r   z0read_session_lineage_metadata.<locals>.<setcomp>i  s#    ===3=c#hh===r2   r   c                     h | ]
}|d          S r   r=   r   s     r0   r   z0read_session_lineage_metadata.<locals>.<setcomp>s  r  r2   r   r~   Nr$   i  r	  r   ,r   z0
                        SELECT s.id, s.source, z, s.title, s.started_at, s.parent_session_id, s.ended_at, s.end_reason
                        FROM sessions s
                        WHERE s.id IN (z)
                        r   r   r   r-   r   r5   r   r   T_cross_surface_child_sessionr   rc   rm   rl   )r   r   r   r   r   r&   r   r   r   r   r   r>   r   r   rg   rF   r   re   r+   rQ   r   r   r   r'   r(   r   )r   r+  wantedr   r   r   r   IN_CHUNKr   to_fetchr%  
fetch_listichunkr   r3   r"  r   metadata
parent_rowentryr   r   r   r   r   ro   r   r   rz   s                                 r0   read_session_lineage_metadatar:  ^  sx    >=;#4"===F7mmG )) 	8W_S\\2233 5	0t&{D++--CKK5666==cllnn===L",66,l:Z:Z5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 #00@,"O"O$ H$&D6{{H b		 0 0 E!(^^
55q#j//8<< 4 4A&qX~6E#&88C#e**,<#=#=LKK0C  )5  
     #||~~ 4 4*.s))SY4 & 0 0C $b 1 1 5 56I J JI  0Yd%:%:yPX?X?X Y///0e5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0 5	0l    			 !#H +@ +@hhsmm 	GG/00	,5?TXXi(((4
 	 	''R00E)2E%&+J<< -<)*(2w(?(?n%)3)A)Ao& #JNN8$<$<$B C C I I K K Q Q S S"3778#4#4#:;;AACCIIKK  A\ Am|6S6S<@E893D)DD C7BE34
u	hhz**G<CM$7888I,5?TXXi(((4F Y$..+FG<< G"JHHYQM	 c>>''R00E(/E$%2?E./OsC   .H1 %A"H%H1 EH%H1 %H))H1 ,H)-H1 1I ?I )r8   )r   Nr   )r	  ))__doc__loggingr   
contextlibr   pathlibr   	getLogger__name__r   r)   CLI_MIN_UNTITLED_MESSAGE_COUNTrx   r*   r&   re   r1   r7   r   r>   rB   objectrG   rn   rT   rW   r[   rj   rp   rt   ry   r   r   rg   r   r   r   r   r  r*  r:  r=   r2   r0   <module>rC     s:   E E              		8	$	$    "# &' # 
 
 sTz  d        F! !$ ! ! ! !
G G Gc#h G# G3 G G G G,# , , , ,& S    St S S S S S(s    (4 (C ( ( ( ( B$ B4 B B B B
D T    8ID IT I I I I(!TD[ ! ! ! ! ! !Hd39o 3: RUX\R\    *]d4j ]T$Z ] ] ] ]D .?	g. g.g.g. 38_t+	g.
 
$Zg. g. g. g.VT       =B   c T d      3: QT ^b    Dx4 xd3i#c(>R xW[\_ae\eWf x x x x x xr2   