
    sjW                     ~   U d Z ddlZddl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 ddlmZ ddlmZmZmZmZmZ erddlmZ  ej        e          ZdZd	Zd
ZdZdefdZdededefdZddl m!Z"m#Z$ dZ%dZ&da'ee(         e)d<   deeee         f         fdZ*dZ+dZ,dZ-dZ.dedz  defdZ/dedz  de0fdZ1dedz  de0fdZ2dd d!e3e         d"e	d#e4dee         fd$Z5d%ed&edee4         fd'Z6d(ee         de0fd)Z7dee         fd*Z8d+edee4         fd,Z9d-e	dee4         fd.Z:dee4         fd/Z;dee	         fd0Z<d-e	d1edee         fd2Z=da>ee(         e)d3<   d[d-ee	         dee?         fd4Z@d[d-ee	         dee?         fd5ZAd6ZBdaCee(         e)d7<   d[d-ee	         dee(         fd8ZDdefd9ZEdaFee4         e)d:<    ejG                    ZHd; ZId<aJd= ZKd\d#eLdee4         fd?ZMd@e4defdAZNd<aOd]dCdDdEeLddfdFZPdGe4defdHZQdIedefdJZRdKZSde	fdLZTdee         fdMZUd[dNee         deeeef                  fdOZVdPee?         dNee         dQeeef         dReeef         ddf
dSZWd[dNee         deeef         fdTZX	 	 	 	 	 	 	 	 d^dCdDdUed"edPee?         dNee         dVedWe4dXedQeeef         dYeeee         f         fdZZYdS )_zWelcome banner, ASCII art, skills summary, and update check for the CLI.

Pure display functions with no HermesCLI state dependency.
    N)Path)urlparseget_hermes_home)TYPE_CHECKINGAnyDictListOptional)Consolez[1;38;2;255;215;0mz[1mz[2mz[0mtextc                     ddl m} ddlm} 	  | ||                      dS # t          $ r t          |            Y dS w xY w)z:Print ANSI-colored text through prompt_toolkit's renderer.r   )print_formatted_text)ANSIN)prompt_toolkitr   prompt_toolkit.formatted_textr   	Exceptionprint)r   	_pt_print_PT_ANSIs      5/home/agent/.hermes/hermes-agent/hermes_cli/banner.pycprintr   '   sw    @@@@@@>>>>>>	((4..!!!!!   
 	ds   $ A Akeyfallbackreturnc                 p    	 ddl m}  |                                | |          S # t          $ r |cY S w xY w)z5Get a color from the active skin, or return fallback.r   get_active_skin)hermes_cli.skin_enginer   	get_colorr   )r   r   r   s      r   _skin_colorr!   9   s[    ::::::  **3999   s   #& 55)__version____release_date__u  [bold #FFD700]██╗  ██╗███████╗██████╗ ███╗   ███╗███████╗███████╗       █████╗  ██████╗ ███████╗███╗   ██╗████████╗[/]
[bold #FFD700]██║  ██║██╔════╝██╔══██╗████╗ ████║██╔════╝██╔════╝      ██╔══██╗██╔════╝ ██╔════╝████╗  ██║╚══██╔══╝[/]
[#FFBF00]███████║█████╗  ██████╔╝██╔████╔██║█████╗  ███████╗█████╗███████║██║  ███╗█████╗  ██╔██╗ ██║   ██║[/]
[#FFBF00]██╔══██║██╔══╝  ██╔══██╗██║╚██╔╝██║██╔══╝  ╚════██║╚════╝██╔══██║██║   ██║██╔══╝  ██║╚██╗██║   ██║[/]
[#CD7F32]██║  ██║███████╗██║  ██║██║ ╚═╝ ██║███████╗███████║      ██║  ██║╚██████╔╝███████╗██║ ╚████║   ██║[/]
[#CD7F32]╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝╚══════╝      ╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚═╝  ╚═══╝   ╚═╝[/]u  [#CD7F32]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡀⠀⣀⣀⠀⢀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#CD7F32]⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣇⠸⣿⣿⠇⣸⣿⣿⣷⣦⣄⡀⠀⠀⠀⠀⠀⠀[/]
[#FFBF00]⠀⢀⣠⣴⣶⠿⠋⣩⡿⣿⡿⠻⣿⡇⢠⡄⢸⣿⠟⢿⣿⢿⣍⠙⠿⣶⣦⣄⡀⠀[/]
[#FFBF00]⠀⠀⠉⠉⠁⠶⠟⠋⠀⠉⠀⢀⣈⣁⡈⢁⣈⣁⡀⠀⠉⠀⠙⠻⠶⠈⠉⠉⠀⠀[/]
[#FFD700]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⡿⠛⢁⡈⠛⢿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#FFD700]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠿⣿⣦⣤⣈⠁⢠⣴⣿⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#FFBF00]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢿⣿⣦⡉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#FFBF00]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣦⣈⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#CD7F32]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣴⠦⠈⠙⠿⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#CD7F32]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣤⡈⠁⢤⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#B8860B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#B8860B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⠑⢶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#B8860B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠁⢰⡆⠈⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#B8860B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⠈⣡⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]
[#B8860B]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]_available_skills_cachec                     t           t           d         S 	 ddlm}   |             }n# t          $ r i cY S w xY wi }|D ]H}|                    d          pd}|                    |g                               |d                    I|fa |S )a  Return skills grouped by category, filtered by platform and disabled state.

    Delegates to ``_find_all_skills()`` from ``tools/skills_tool`` which already
    handles platform gating (``platforms:`` frontmatter) and respects the
    user's ``skills.disabled`` config list.

    Cached per-process: this feeds only the startup banner, whose snapshot
    is taken once anyway, and the underlying skills-tree walk costs ~100ms.
    ``prefetch_banner_data()`` uses the cache to pay that walk off-thread.
    Nr   )_find_all_skillscategorygeneralname)r$   tools.skills_toolr&   r   get
setdefaultappend)r&   
all_skillsskills_by_categoryskillr'   s        r   get_available_skillsr1   f   s     *&q))666666%%''

   			 02 J J99Z((5I%%h33::5=IIII13s   ' 66i`T  z0https://github.com/NousResearch/hermes-agent.gitz$github.com/nousresearch/hermes-agenturlc                     | sdS |                                  }|                    d          rd|t          d          d         z   }n]|                    d          rd|t          d          d         z   }n-t          |          }|j        r|j        r|j         |j         }|                                                     d          }|                    d          r
|dd         }|                                S )	z>Return ``host/owner/repo`` for common GitHub remote URL forms. zgit@github.com:zgithub.com/Nzssh://git@github.com//.git)	strip
startswithlenr   netlocpathrstripendswithlower)r3   valueparseds      r   _canonical_github_remoterC      s    rIIKKE)** 4c*;&<&<&=&= >>			1	2	2 4c*A&B&B&C&C DD%= 	4V[ 	4}3fk33EKKMM  %%E~~f crc
;;==    c                     | sdS |                                                                  }|                    d          p|                    d          S )NFzgit@zssh://)r9   r@   r:   )r3   rA   s     r   _is_ssh_remoterF      sO     uIIKKEF##Au'7'7'A'AArD   c                 P    t          |           ot          |           t          k    S N)rF   rC   _OFFICIAL_REPO_CANONICAL)r3   s    r   _is_official_ssh_remoterJ      s$    #\#;C#@#@D\#\\rD      timeoutargscwdrM   c                    	 t          j        dg| dddd|t          |                    }n# t          $ r Y d S w xY w|j        dk    rd S |j        pd                                S )NgitTutf-8replacecapture_outputr   encodingerrorsrM   rO   r   r5   
subprocessrunstrr   
returncodestdoutr9   )rN   rO   rM   results       r   _git_stdoutr_      s    NTN C
 
 
    ttAtMR&&(((s   +. 
<<current_rev
target_revc                 X   t          |           rt          |          sdS d|  d| }	 ddl}|j                            |ddd          }|j                            |d	
          5 }t          j        |                                                    d                    }ddd           n# 1 swxY w Y   n# t          $ r Y dS w xY wt          |t                    r|                    d          nd}t          |t                    rt          |t                    s|dk    r|S dS )uZ  Exact behind-count via the GitHub compare API for uncountable graphs.

    Shallow installer clones and ls-remote-only probes know the two tip SHAs
    but have no local history to run ``rev-list --count`` across. GitHub's
    ``GET /repos/<owner>/<repo>/compare/<current>...<target>`` knows the full
    graph regardless of local clone depth and returns ``ahead_by`` — exactly
    the behind count the local graph lost. Unauthenticated, bounded, and
    best-effort: any failure (offline, rate limit, diverged/unknown SHAs)
    returns None so callers keep the honest UPDATE_AVAILABLE_NO_COUNT.
    Nz?https://api.github.com/repos/nousresearch/hermes-agent/compare/...r   zapplication/vnd.github+jsonzhermes-cli-update-check)Acceptz
User-Agent)headers
   rL   rR   ahead_by)_is_full_shaurllib.requestrequestRequesturlopenjsonloadsreaddecoder   
isinstancedictr+   intbool)r`   ra   r3   urllibreqresppayloadaheads           r   _github_compare_behindrz      s    %% ,z*B*B t	0	0 	0#-	0 	0 n$$77  % 
 
 ^##C#44 	>j!3!3G!<!<==G	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	>   tt'1'4'@'@JGKK
###dE% j&=&= %1**4s5   ?B; ):B/#B; /B33B; 6B37B; ;
C	C	rA   c                     t          | t                    o+t          |           dk    ot          d | D                       S )N(   c              3      K   | ]}|d v V  	dS )0123456789abcdefABCDEFN ).0cs     r   	<genexpr>z_is_full_sha.<locals>.<genexpr>   s(      ==!--======rD   )rq   r[   r;   all)rA   s    r   rh   rh      sF    5# 	>JJ"	>==u=====rD   c                      	 t          j        ddt          dgddddd          } n# t          $ r Y d	S w xY w| j        d
k    s| j        sd	S | j                                        d
         }|pd	S )zCTip SHA of upstream main via HTTPS ls-remote (no auth, no prompts).rQ   z	ls-remotezrefs/heads/mainTrR   rS   rf   )rU   r   rV   rW   rM   Nr   )rY   rZ   _UPSTREAM_REPO_URLr   r\   r]   split)r^   upstream_revs     r   _upstream_main_shar      s    K!35FGdWY
 
 

    ttAV]t=&&((+L4s   #& 
44	local_revc                 l    t                      }|sdS || k    rdS t          | |          }||nt          S )a  Compare an embedded git revision to upstream main via ls-remote.

    Returns 0 if up-to-date, the exact behind-count when the GitHub compare
    API can recover it, ``UPDATE_AVAILABLE_NO_COUNT`` if behind by an unknown
    amount, or ``None`` on failure.
    Nr   )r   rz   UPDATE_AVAILABLE_NO_COUNT)r   r   counteds      r   _check_via_revr     sM     &''L ty  q
 %Y==G)77/HHrD   repo_dirc                    t          g d|           }t          |          rt          ddg|           }|sdS t                      }|dS ||k    rdS t          j        ddd	|dgd
dt          |                     }|j        dk    rdS t          ||          }||nt          S t          ddg|           }|dk    }	 ddl	m
}  ||            g d}	|r|	ddgz  }	|	                    d           t          j        |	d
dt          |                      n# t          $ r Y nw xY w|rbt          ddg|           }t          ddg|           pt          ddg|           }
|r|
sdS ||
k    rdS t          ||
          }||nt          S 	 t          j        g dd
d
dddt          |                     }|j        dk    r&t          |j                                                  S n# t          $ r Y nw xY wdS )z5Count commits behind origin/main in a local checkout.)remotezget-urlorigin)rO   	rev-parseHEADNr   rQ   z
merge-basez--is-ancestorTrK   )rU   rM   rO   z--is-shallow-repositorytrue)clear_stale_git_locks)rQ   fetchr   mainz--depth1z--quietrf   
FETCH_HEADorigin/main)rQ   rev-list--countzHEAD..origin/mainrR   rS   rT   )r_   rJ   r   rY   rZ   r[   r\   rz   r   hermes_cli.gitlockr   r-   r   rs   r]   r9   )r   
origin_urlhead_revr   ancestorr   shallow
is_shallowr   
fetch_argsra   r^   s               r   _check_via_local_gitr     s   <<<(KKKJz** MV4(CCC 	4 *++48##1 >L/<HH
 
 
 !##1 )<@@!-ww3LL ;(ABQQQGF"J 	=<<<<<h''' 877
 	+9c**J)$$$H	
 	
 	
 	
 	

      M V4(CCCl3BBB GK7XFFF 	  	z 	4z!!1
 ):>>!-ww3LL
???dWYH	
 
 
 !!v}**,,--- "   4s&    AD 
D&%D&AG* *
G76G7c            	         t                      } | dz  }t          j                            d          pd}	 ddlm}m}  | |                      dv rdS n# t          $ r Y nw xY wt          j                    }	 |	                                rt          j        |                    d                    }||                    d	d          z
  t          k     rL|                    d
          |k    r3|                    d          t          k    r|                    d          S n# t          $ r Y nw xY w|rt          |          }nut!          t"                    j        j                                        }|dz  	                                s| dz  }|dz  	                                sd}nt)          |          }	 |                    t          j        |||t          d          d           n# t          $ r Y nw xY w|S )a  Check whether a Hermes update is available.

    Two paths: if ``HERMES_REVISION`` is set (nix builds embed it), compare
    it to upstream main via ``git ls-remote``. Otherwise look for a local
    git checkout and count commits behind ``origin/main``.

    Returns the number of commits behind, ``UPDATE_AVAILABLE_NO_COUNT`` (-1)
    if behind but the count is unknown, ``0`` if up-to-date, or ``None`` if
    the check failed or doesn't apply. Cached for 6 hours.
    z.update_checkHERMES_REVISIONNr   )detect_install_methodget_project_root>   aptdockerrR   rV   tsrevverbehindr7   hermes-agent)r   r   r   r   )r   osenvironr+   hermes_cli.configr   r   r   timeexistsrm   rn   	read_text_UPDATE_CHECK_CACHE_SECONDSVERSIONr   r   __file__parentresolver   
write_textdumps)	hermes_home
cache_fileembedded_revr   r   nowcachedr   r   s	            r   check_for_updatesr     sX    "##K.J:>>"344<LMMMMMMMM  !1!1!3!3448III4 J   
 )++C
 	,Z
 4 4g 4 F FGGFfjjq))),GGGJJu%%55JJu%%00zz(+++     4--
 >>(/77996!))++ 	4"^3H6!))++ 	4 FF)(33FJcVLQXYYZZ 	 	
 	
 	
 	
     Ms6   A 
A#"A#:B)D% %
D21D2=3G1 1
G>=G>c                      t          t                    j        j                                        } | dz                                  st                      }|dz  } | dz                                  r| ndS )zReturn the active Hermes git checkout, or None if this isn't a git install.

    Prefers the running code's location over the profile-scoped path
    because ``$HERMES_HOME/hermes-agent/`` may be a stale copy carried
    over by ``--clone-all``.
    r7   r   N)r   r   r   r   r   r   )r   r   s     r   _resolve_repo_dirr     so     H~~$+3355Hv%%'' 0%''/ 6)1133=88=rD   r   c                     	 t          j        ddd|gdddddt          |                     }n# t          $ r Y d	S w xY w|j        d
k    rd	S |j        pd                                }|pd	S )z4Resolve a git revision to an 8-character short hash.rQ   r   z	--short=8TrR   rS   rK   rT   Nr   r5   rX   )r   r   r^   rA   s       r   _git_short_hashr     s    Kc2H
 
 
    ttAt] b''))E=Ds   ,/ 
==_git_banner_state_cachec                 Z    | t           t           d         S t          |           }| |fa |S )u  Return upstream/local git hashes for the startup banner.

    For source installs and dev images this runs ``git rev-parse`` against
    the active checkout.  When no checkout is available — the canonical case
    is the published Docker image, which excludes ``.git`` from the build
    context — we fall back to the baked-in build SHA (see
    ``hermes_cli/build_info.py``) and return it as a frozen
    ``upstream == local`` state with ``ahead=0``.  A built image is by
    definition pinned to one commit, so "ahead" is always zero and the
    banner correctly shows ``· upstream <sha>`` with no carried-commits
    annotation.

    Cached per-process (default ``repo_dir`` only): the state costs 2-3 git
    subprocesses (~100ms) and the checkout revision cannot change under a
    running CLI in a way the banner needs to observe live. The cache also
    lets ``prefetch_banner_data()`` pay this cost off-thread before the
    banner renders.
    Nr   )r   _compute_git_banner_state)r   states     r   get_git_banner_stater     s;    ( 3?&q))%h//E#((LrD   c                 8   | pt                      } | .	 ddlm}  |d          }|r||ddS n# t          $ r Y nw xY wd S t	          | d          }t	          | d          }|r|s.	 ddlm}  |d          }|r||ddS n# t          $ r Y nw xY wd S d}	 t          j        g dd	d	d
ddt          |                     }|j        dk    r*t          |j
        pd                                pd          }n# t          $ r d}Y nw xY w||t          |d          dS )Nr   )get_build_sha   )short)upstreamlocalry   r   r   )rQ   r   r   zorigin/main..HEADTrR   rS   rK   rT   0)r   hermes_cli.build_infor   r   r   rY   rZ   r[   r\   rs   r]   r9   max)r   r   bakedr   r   ry   r^   s          r   r   r   
  s   .,..H	;;;;;;!M***E G$)EAFFFG 	 	 	D	tx77HHf--E 
5 
	;;;;;;!M***E G$)EAFFFG 	 	 	D	tE???H
 
 
 !!-#4466=#>>E    !53ua==IIIs1   / 
<<&B 
BBAC6 6DDz9https://github.com/NousResearch/hermes-agent/releases/tag_latest_release_cachec                 Z   t           	t           pdS | pt                      } | da dS 	 t          j        g ddddddt	          |                     }n# t
          $ r da Y dS w xY w|j        d	k    rda dS |j        pd
                                }|sda dS t           d| }||fa t           S )u  Return ``(tag, release_url)`` for the latest git tag, or None.

    Local-only — runs ``git describe --tags --abbrev=0`` against the
    Hermes checkout. Cached per-process. Release URL always points at the
    canonical NousResearch/hermes-agent repo (forks don't get a link).
    Nr   )rQ   describez--tagsz
--abbrev=0TrR   rS      rT   r   r5   r6   )
r   r   rY   rZ   r[   r   r\   r]   r9   _RELEASE_URL_BASE)r   r^   tagr3   s       r   get_latest_release_tagr   <  s    ($,,.,..H "t777H
 
 
     "tt A "t=B
%
%
'
'C  "t
&
&
&
&C #J  s   *A A#"A#c            
         dt            dt           d} t                      }|s| S |d         }|d         }t          |                    d          pd          }|dk    s||k    r|  d| S |d	k    rd
nd}|  d| d| d| d| d
S )z;Return the version label shown in the startup banner title.zHermes Agent vz ()r   r   ry   r   u    · upstream    commitcommitsu
    · local z (+z	 carried )r   RELEASE_DATEr   rs   r+   )baser   r   r   ry   carried_words         r   format_banner_version_labelr   h  s    6G66|666D ""E Z H'NE		'""'a((EzzX&&//X///$zz88yL^^^^U^^u^^|^^^^rD   _update_resultc                  `    d } t          j        | d          }|                                 dS )z4Kick off update check in a background daemon thread.c                  T    t                      at                                           d S rH   )r   r   _update_check_donesetr   rD   r   _runz#prefetch_update_check.<locals>._run  s%    *,,     rD   T)targetdaemonN)	threadingThreadstart)r   ts     r   prefetch_update_checkr     s9    ! ! ! 	T222AGGIIIIIrD   Fc                  v    t           rdS da dd} t          j        | dd                                           dS )a1  Warm the banner's subprocess/I/O-heavy inputs in a daemon thread.

    ``build_welcome_banner`` needs git state (2-4 ``git rev-parse``/
    ``describe`` subprocesses, ~130ms) and the skills index (a skills-tree
    rglob, ~110ms). Both are cached per-process by their own modules, so
    warming them here while the main thread pays the CPU-bound ``cli`` /
    prompt_toolkit imports overlaps subprocess waits and file I/O (which
    release the GIL) with import work. Idempotent; failures are irrelevant
    because the banner recomputes anything missing.
    NTr   c                      	 t                       n# t          $ r Y nw xY w	 t                       n# t          $ r Y nw xY w	 t                       d S # t          $ r Y d S w xY wrH   )r   r   r   r1   r   rD   r   r   z"prefetch_banner_data.<locals>._run  s    	 """" 	 	 	D		"$$$$ 	 	 	D		 """"" 	 	 	DD	s*    
1 
>>A 
A A zbanner-data-prefetchr   r)   r   r   N)_banner_data_prefetch_startedr   r   r   )r   s    r   prefetch_banner_datar     sX     % $(!    D'=dKKKQQSSSSSrD         ?c                 F    t                               |            t          S )z:Get result of prefetched check. Returns None if not ready.rL   )r   waitr   rL   s    r   get_update_resultr     s    G,,,rD   r   c                     ddl m}m} | dk    r| dk    rdnd}d|  d| d |             d	S  |            }d
}|r	|d| dz  }|S )z@Render the update warning line for a non-zero ``behind`` result.r   )get_managed_update_commandrecommended_update_commandr   r   r   u   [bold yellow]⚠  u%    behind[/][dim yellow] — run [bold]z[/bold] to update[/]u$   [bold yellow]⚠ update available[/]u   [dim yellow] — run [bold]z
[/bold][/])r   r   r   )r   r   r   commits_wordmanaged_cmdlines         r   _format_update_noticer    s    XXXXXXXXzz#)Q;;xxI] ] ] ] ]*D*D*F*F] ] ]	
 -,..K1D FEkEEEEKrD         >@consoler   max_waitc                      t           rdS da d fd}t          j        |dd                                           dS )zPrint the update warning once the prefetched check completes.

    Used when the banner rendered before the update prefetch finished so
    startup never blocks on git/network. Prints at most once per process.
    NTr   c                      	 t                                         sd S t          } | | dk    rd S                     t	          |                      d S # t
          $ r Y d S w xY w)NrL   r   )r   r   r   r   r  r   )r   r  r  s    r   _wait_and_printz-_defer_update_notice.<locals>._wait_and_print  s    	%**8*<< #F~1MM/7788888 	 	 	DD	s   A A "A 
A#"A#zupdate-noticer   r   )_deferred_update_notice_startedr   r   r   )r  r  r  s   `` r   _defer_update_noticer    si     ' &*#	 	 	 	 	 	 	 _T  egggggrD   tokensc                    | dk    r5| dz  }t          |          }t          ||z
            dk     r| dS |ddS | dk    r5| dz  }t          |          }t          ||z
            dk     r| dS |ddS t          |           S )uL   Format a token count for display (e.g. 128000 → '128K', 1048576 → '1M').i@B 皙?Mz.1fi  K)roundabsr[   )r  valroundeds      r   _format_context_lengthr    s    y **sW}$$=== }}}}	5un**sW}$$=== }}}}v;;rD   toolset_namec                 L    | sdS |                      d          r
| dd         n| S )zANormalize internal/legacy toolset identifiers for banner display.unknown_toolsNi)r?   )r  s    r   _display_toolset_namer    s=     y   **	SbSrD   r   c                  *    t                      dz  dz  S )Ncachezbanner_snapshot.jsonr   r   rD   r   _banner_snapshot_pathr    s    w&)???rD   c                     ddl } dt           g}	 ddlm}  |            t	                      dz  fD ]p}	 |                                }|                    |j         d|j         d|j	                    D# t          $ r  |                    |j         d           Y mw xY wn# t          $ r Y dS w xY w|                    t          t                               t                      }|r6|                    t          |                    dd	                               |                     d
                    |                              d                                                    S )z8Fingerprint the inputs the banner tool panel depends on.r   Nv)get_config_pathz.env:z:absentr   r5   |rR   )hashlib_BANNER_SNAPSHOT_VERSIONr   r"  r   statr-   r)   st_mtime_nsst_sizeOSErrorr   r[   r   r   r+   sha256joinencode	hexdigest)r%  partsr"  pstr   s         r   banner_snapshot_fingerprintr2    s   NNN+)++,E	555555!/##_%6%6%?@ 	1 	1A1VVXXFFFF"*FFGGGG 1 1 1///000001		1    tt 
LLW ""E 2S7B//00111>>#((5//0099::DDFFFs5   #B$ A A65B$ 6'B B$ B  B$ $
B21B2enabled_toolsetsc                    	 t          j        t                                          d                    }n# t          $ r Y dS w xY wt          |t                    sdS t                      }|r|                    d          |k    rdS |                    d          t          | pg           k    rdS |                    d          }|                    d          }|                    d          }t          |t                    r*t          |t                    rt          |t                    sdS t          |                    d	          t                    sdS |S )
zBReturn the stored banner snapshot when its fingerprint is current.rR   r   Nfingerprintr3  toolstoolset_mapavailabilityr/   )rm   rn   r  r   r   rq   rr   r2  r+   sortedlist)r3  blobfpr6  r7  r8  s         r   load_banner_snapshotr=  2  sX   z/11;;W;MMNN   ttdD!! t	$	&	&B -((B..txx"##v.>.D"'E'EEEtHHWE((=))K88N++LeT"" *[$*G*G lD11tdhh344d;; tKs   47 
AAr6  r8  r7  c                    t                      }|sdS |t          |pg           d | D             ||                    dg           t          |                    dg                     t          |                    dg                     dt	                      d}t                      }	 ddl}ddl}|j        	                    d	d	
           |
                    t          |j                  d          \  }	}
|                    |	dd          5 }t          j        ||           ddd           n# 1 swxY w Y   |                    |
|           dS # t           $ r Y dS w xY w)zCPersist the banner tool panel inputs for next launch (best-effort).Nc                     g | ]R}t          |t                    |                    d i                               d          @d d|d          d         iiSS )functionr)   )rq   rr   r+   r   r   s     r   
<listcomp>z(save_banner_snapshot.<locals>.<listcomp>W  sq     
 
 
!T""
 ()uuZ'<'<'@'@'H'H
&!J-"789
 
 
rD   unavailable_toolsets
lazy_toolsdisabled_toolsrC  rD  rE  )r5  r3  r6  r7  r8  r/   r   T)parentsexist_okz.banner_snap.)dirprefixwrR   r   )r2  r9  r+   r:  r1   r  r   tempfiler   mkdirmkstempr[   fdopenrm   dumprS   r   )r6  r3  r8  r7  r<  rx   r=   _os	_tempfilefdtmpfhs               r   save_banner_snapshotrV  J  s    
%	&	&B "#3#9r::
 

 
 

 #$0$4$45KR$P$P|//bAABB"<#3#34Db#I#IJJ
 

 344 G  !""D	$$$$$666##DK(8(8#QQCZZC'Z22 	#bIgr"""	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	#C   s7   *A(E D4(E 4D88E ;D8<E 
E%$E%c                    ddl m}m} | pg }  |d          \  }}d | D             rfd|D             }t                      }t                      }|D ]}|                    dd          }|                    |i           }	|                    d	g           }
|	                    d
          r|                    |
           o|                    |
           |t          |          t          |          dS )u  Compute the banner's toolset-availability payload.

    Returns ``{"unavailable_toolsets": [...], "lazy_tools": [...],
    "disabled_tools": [...]}`` — the exact inputs ``build_welcome_banner``
    needs to annotate disabled/lazy tools. Split out so the result can be
    snapshotted to disk and replayed on the next launch without importing
    ``model_tools`` (see ``load_banner_snapshot``).
    r   )check_tool_availabilityTOOLSET_REQUIREMENTST)quietc                 ,    h | ]}t          |          S r   r[   rA  s     r   	<setcomp>z/compute_toolset_availability.<locals>.<setcomp>      444a3q66444rD   c                     g | ]=}t          |                    d |                    dd                              v ;|>S )idr)   r5   )r[   r+   )r   item_enabled_tss     r   rB  z0compute_toolset_availability.<locals>.<listcomp>  sR      
  
  
488D$((62"6"67788KGG GGGrD   r)   r5   r6  check_fnrF  )model_toolsrX  rY  r   r+   updater9  )r3  rX  rY  _rC  rE  rD  ra  r  ts_reqtools_in_tsrb  s              @r   compute_toolset_availabilityri  q  sS    JIIIIIII'-255DAAAA 54#3444K 
 
  
  
  
1 
  
  
 UUN J$ / /xx++%)),;;hhw++::j!! 	/k****!!+.... 4Z(( 00  rD   model
session_idcontext_lengthproviderr/   c                    ddl m} ddlm} |ddlm} |pg }|pg }|	t          |          }	|	                    dg           }t          |	                    dg                     }t          |	                    dg                     }d	 |D             }|	                    d
          }|
                    dd           |
                    dd           t          dd          }t          dd          }t          dd          }t          dd          }	 ddlm}  |            }t          |d          r|j        r|j        nt           }n# t"          $ r d}t           }Y nw xY wd|dg}|pd                                                                dk    rH|}d}	 ddlm} ddlm}  | |                                d          pi           }|                    di                               |          }|r\|                    d          pi } t1          |                     d           pd          }!d!|!v r|!                    d!          d"         n|!}n# t"          $ r d}Y nw xY wt5          |          d#k    r|dd$         d%z   }|rd&| d'| d(| d)nd}"|rd&| d'| d*t7          |           d+nd}#|                    d,| d-| d)|" |# d&| d'| d.           n|pd                                r,|pd                                                                d/k    r|                    d0| d1           nd!|v r|                    d!          d"         n|}$|$                    d2          r
|$dd3         }$t5          |$          d#k    r|$dd$         d%z   }$|rd&| d'| d*t7          |           d+nd}#|                    d,| d*|$ d)|# d&| d'| d.           t=          j        d4          r|                    d5| d6           |                    d7| d*| d)           |r|                    d7| d8| d)           d9                     |          }%d:| d;g}&i }'|D ]S}(|(d<         d=         })tC           ||)          pd>          }*|'"                    |*g                               |)           T|D ]}+|+                    d?|+                    d=d/                    },tC          |,          }-|-|'vrg |'|-<   |+                    d@g           D ]'})|)|'|-         vr|'|-                             |)           (tG          |'$                                          }.|.ddA         }/t5          |.          dAz
  }0|/D ]}*|'|*         }1g }2tG          |1          D ]Z}3|3|v r|2                    dB|3 d)            |3|v r|2                    dC|3 d)           >|2                    d,| d*|3 d)           [dD                     |2          }4t5          dD                     tG          |1                              dEk    r g }5d}6tG          |1          D ]\}3|6t5          |3          z   dFz   dGk    r|5                    d%            n+|5                    |3           |6t5          |3          dFz   z  }6]g }2|5D ]v}3|3d%k    r|2                    dH           |3|v r|2                    dB|3 d)           <|3|v r|2                    dC|3 d)           Z|2                    d,| d*|3 d)           wdD                     |2          }4|&                    d7| d*|* dI|4            |0dk    r|&                    d7| dJ|0 dK           g }7	 ddlm}8 tK           |8            pi                     dL                    }9n# t"          $ r dM}9Y nw xY wdN}:|9s1	 ddOl&m'}; tK           |;                      }:n# t"          $ r dM}:Y nw xY w|9s|:r$	 ddPl(m)}<  |<            }7n# t"          $ r g }7Y nw xY w|7rj|&                    d           |&                    d:| dQ           |7D ]8}=|=                    dR          }>|=dS         r>|&                    d7| d*|=d=          dT| dU|=dV          dW| dX| d*|=d@          dY           ^|=                    dZ          s|>dZk    r/|&                    d7| d*|=d=          d[|=dV          dW| d\	           |>d]k    r,|&                    d7| d*|=d=          d[|=dV          d^           |>d_k    r0|&                    d7| d*|=d=          d[|=dV          dW| d`	           |&                    dB|=d=          d[|=dV          da           :|&                    d           |&                    d:| db           | pdc|v }?|?r<|
tU                      }
tW          dd |
,                                D                       }@ni }
d}@t[          j.                    j/        }Ata          tc          |Adez            dfz
  dg          }B|?s|&                    d7| dh           n|
rhtG          |
$                                          D ]D}CtG          |
|C                   }Dt5          |C          dFz   }Eta          |B|Ez
  di          }Fg d}6}Gte          |D          D ]\  }H}3|GrdDnd}It5          |I          t5          |3          z   }Jt5          |D          |Hdjz   z
  }K|Kdk    rt5          dk|K dl          nd}L|GrF|6|Jz   |Lz   |Fk    r:t5          |D          t5          |G          z
  }M|G                    dm|M dl            n|G                    |3           |6|Jz  }6dD                     |G          }N|&                    d7| d*|C dn| d*|N d)	           Fn|&                    d7| do           |&                    d           |7rtW          dp |7D                       nd}Ot5          |           dq|@ drg}P|Or|P                    |O ds           |P                    dt           	 ddul3m4}Q ddlm}8  |Q |8                      dvk    r|&                    d:| dw| dx| dy           n# t"          $ r Y nw xY w	 ddzl5m6}R  |R            }S|Sr%|Sd{k    r|&                    d:| d|| d*|S d)           n# t"          $ r Y nw xY w|&                    d7| d*d}                     |P           d)           	 to          d~          }T|T)tp          9                                stu          |            n*|T(|Tdk    r"|&                    tw          |T                     n# t"          $ r Y nw xY wd9                     |&          }U|<                    |%|U           t          dd          }Vt          dd          }Wt{                      }Xt}                      }Y|Yr|Y\  }Z}[d:|V d|[ d*|X d}\n	d:|V d*|X d)}\ |||\|Wd
          }]| ?                                 t[          j.                    j/        }^|^dk    rP|rt          |d          r|j@        r|j@        nt          }_| ?                    |_           | ?                                 | ?                    |]           dS )a  Build and print a welcome banner with caduceus on left and info on right.

    Args:
        console: Rich Console instance.
        model: Current model name.
        cwd: Current working directory.
        tools: List of tool definitions.
        enabled_toolsets: List of enabled toolset names.
        session_id: Session identifier.
        get_toolset_for_tool: Callable to map tool name -> toolset name.
        context_length: Model's context window size in tokens.
        provider: Active provider id. When ``"moa"``, ``model`` is a MoA
            preset name and the banner renders the aggregator instead of a
            bare model slug.
        availability: Optional precomputed result of
            ``compute_toolset_availability`` (e.g. replayed from the banner
            snapshot). When provided together with ``get_toolset_for_tool``,
            this function performs no ``model_tools`` import at all.
    r   )Panel)TableN)get_toolset_for_toolrC  rD  rE  c                 ,    h | ]}t          |          S r   r\  rA  s     r   r]  z'build_welcome_banner.<locals>.<setcomp>  r^  rD   )r      )paddingleftcenter)justifyrightbanner_accentz#FFBF00
banner_dimz#B8860Bbanner_textz#FFF8DCsession_borderz#8B8682r   banner_heror5   moa)load_config)normalize_moa_configpresets
aggregatorrj  r6   r2         rc   z [dim u   ]·[/] [dim z]agg z[/]]z context[/][z]MoA: z]Nous Research[/]r  z&[bold red]no model configured[/] [dim u"   ]— run /model or hermes setup[/]z.ggufHERMES_YOLO_MODEu    [bold red]⚠ YOLO mode[/] [dim u%   ]— all approval prompts bypassed[/]z[dim z
]Session: 
z[bold z]Available Tools[/]r@  r)   otherr`  r6  r   z[red]z[yellow]z, -   rs  *   z[dim]...[/]z:[/] z](and z more toolsets...)[/]mcp_serversTF)$get_portable_mcp_server_names_nowait)get_mcp_statusz]MCP Servers[/]status	connectedz[/] [z](	transportz
)[/] [dim u	   ]—[/] [z tool(s)[/]disabledz
[/] [dim](u   ]— disabled[/]
connectingu   )[/] [yellow]— connecting[/]
configuredu   ]— configured[/]u   )[/] [red]— failed[/]z]Available Skills[/]skillsc              3   4   K   | ]}t          |          V  d S rH   )r;   r   ss     r   r   z'build_welcome_banner.<locals>.<genexpr>  s(      GGa3q66GGGGGGrD   g333333?rf      z]Skills toolset disabled[/]   r   z, +z more+z:[/] [z]No skills installed[/]c              3   *   K   | ]}|d          
dV  dS )r  r   Nr   r  s     r   r   z'build_welcome_banner.<locals>.<genexpr>  s+      @@a;@@@@@@@rD   z toolsz skillsz MCP serversz/help for commands)get_current_runtimecodex_app_serverz]Runtime:[/] [z]codex app-server[/] [dim z,](terminal/file ops/MCP run inside codex)[/])get_active_profile_namedefaultz]Profile:[/] [u    · r  rL   banner_titlez#FFD700banner_borderz#CD7F32z][link=z
[/link][/])titleborder_stylert  _   banner_logo)B
rich.panelro  
rich.tablerp  rd  rq  ri  r+   r   grid
add_columnr!   r   r   hasattrr}  HERMES_CADUCEUSr   r9   r@   r   r  hermes_cli.moa_configr  r[   r   r;   r  r-   r?   r   getenvr,  r  r,   r9  keysrt   hermes_cli.pluginsr  tools.mcp_toolr  r1   sumvaluesshutilget_terminal_sizecolumnsr   rs   	enumeratehermes_cli.codex_runtime_switchr  hermes_cli.profilesr  r   r   is_setr  r  add_rowr   r   r   r  HERMES_AGENT_LOGO)`r  rj  rO   r6  r3  rk  rq  rl  rm  r8  r/   ro  rp  rC  rD  rE  rb  layout_tableaccentdimr   session_colorr   _bskin_hero
left_linespreset_name	agg_labelr  r  _moa_preset_agg_amagg_strctx_strmodel_shortleft_contentright_linestoolsets_dicttool	tool_nametoolsetra  
toolset_iddisplay_namesorted_toolsetsdisplay_toolsetsremaining_toolsets
tool_namescolored_namesr)   	tools_strshort_nameslength
mcp_status	_load_cfg_has_native_mcp_has_portable_mcpr  r  srvr  _skills_enabledtotal_skills
_term_cols_right_col_widthr'   skill_names_prefix_len_availr/  i_sep_needed_after_ind_len	remaining
skills_strmcp_connectedsummary_partsr  r  _profile_namer   right_contenttitle_colorborder_colorversion_labelrelease_info_tag_urltitle_markupouter_panel
term_width_logos`                                                                                                   r   build_welcome_bannerr    sT   8 !           #444444KRE'-234DEE'++,BBGG\%%lB7788J))*:B??@@N44#3444K::f:--LFH555GV444 )44F
lI
.
.C}i00D 0)<<M :::::: ""&-fm&D&DpI[p""ap        eRJB%%''500 		555555BBBBBB''(9(9%(@(@(FBGGDhhy"--11+>>G F{{<006B$((7++1r2225**CIIcNN2..#	 	 	 	III	{b  %crc*U2KHQYD3DDCDDiDDDDWYiwe3eeCee2H2X2Xeeee}{f{{K{{G{W{{TW{{eh{{{||||""$$ 	s"(;(;(=(=(C(C(E(E(R(R @@ @ @   
 36,,%++c**2..EK##G,, /)#2#.;"$$)#2#.6m{  Disiiii6L^6\6\iiii  BDGq&qq;qq7qq#qq[^qqqrrr	y#$$ igSggghhh,c,,C,,,--- LJ-JJ:JJJKKK99Z((L7F7778K%'M @ @$V,	'(<(<Y(G(G(R7SS  "--44Y????$ > >XXdDHHVY$?$?@@
,Z88},,*,M,''2.. 	> 	>Il ;;;l+229===	> ]//1122O&rr*_--1# !D !D"7+
:&& 	; 	;D~%%$$%6T%6%6%67777##$$%9%9%9%9::::$$%9%9%9%9%9%9::::IIm,,	tyy
++,,--22KFz** ( (CII%)B..&&u---E""4(((#d))a-'M# ? ?5==!((7777^++!(():):):):;;;;Z''!(()=D)=)=)=>>>>!(()=T)=)=D)=)=)=>>>>		-00IB3BBBByBBCCCCAW3WW.@WWWXXX J>>>>>>		 1r66}EEFF    %	%OOOOOO $%I%I%K%K L L 	% 	% 	% $	% + 	555555'))JJ 	 	 	JJJ	  2;F;;;<<< 	 	CWWX&&F; ""KC K K#f+ K KD K KC<L K KK K*.K K14WK K K    $$ *(<(<""2C 2 2#f+ 2 2[9I 2 22 2 2    <''""1C 1 1#f+ 1 1[9I 1 1 1    <''""4C 4 4#f+ 4 4[9I 4 44 4 4   
 ""*CK * *3{3C * * *   
 r<<<<===
 'DH,CO %!5!7!7GG+=+D+D+F+FGGGGG )++3J3zC/0025r:: AC3CCCDDDD	 A1668899 	U 	UH !3H!=>>Kh--!+K)K7<<F6E$[11 " "4$,tt"d))c$ii/[))QU37=zz32V222333q Vg-86AA #K 0 03u:: =ILL!5Y!5!5!5666ET"""'!5))JSsSSXSSTSSJSSSTTTT)	U, 	?3???@@@rDNUC@@:@@@@@@TUME

***|,D,D,DEM =;;;<<<-...	GGGGGG>>>>>>yy{{++/AAAJ J Jt J JJ J J      ??????//11 	Y]i77WWWdWW]WWWXXX    DsDDV[[%?%?DDDEEE"4000>"4";";"="=> ))))FaKK4V<<===    IIk**M}555ni88K	::L/11M)++L A!
dTTTDTT=TTT@@@m@@@%!	  K MMOOO)++3JR&,}1O1O}TZTf}""l}eMM+s   5E E'&E'!B;I I,+I,2^9 9___. ._=<_=` `%$`%!Ar$ $
r10r157s- -
s:9s:-A%v 
v v rH   )r   )r  )NNNNNNNN)Z__doc__rm   loggingr   r  rY   r   r   pathlibr   urllib.parser   hermes_constantsr   typingr   r   r	   r
   r   rich.consoler   	getLogger__name__logger_GOLD_BOLD_DIM_RSTr[   r   r!   
hermes_clir"   r   r#   r   r  r  r$   tuple__annotations__r1   r   r   r   rI   rC   rt   rF   rJ   r:  rs   r_   rz   rh   r   r   r   r   r   r   r   rr   r   r   r   r   r   r   r   Eventr   r   r   r   floatr   r  r  r  r  r  r&  r  r2  r=  rV  ri  r  r   rD   r   <module>r     s       				                 ! ! ! ! ! ! , , , , , , ; ; ; ; ; ; ; ; ; ; ; ; ; ;  %$$$$$$		8	$	$ 	!    $S C C     P O O O O O O OF j, ,0 % / / /d3S	>2    B '   G A #*     &Bd
 Bt B B B B]t ] ] ] ] ] ?@ ) ) )d3i ) ) )HSM ) ) ) )*# # ## # # # #L $     HSM         Ic Ihsm I I I I(h4 hHSM h h h hVE8C= E E E EP>8D> > > > >d  #    ( ,0 % / / / 8D> Xd^    8+J +J +J(4. +J +J +J +J\ P )- x - - -)! )!Xd^ )!x )! )! )! )!X_S _ _ _ _, !% $ $ $$Y_&&    !& T T TB u x}    # #    & #(  ) u     >3 3    "     2  @t @ @ @ @GXc] G G G G, 49 cSVh@X    0$:$3i$ sCx.$ c3h	$
 
$ $ $ $N* *49 *SRUX * * * *\ .27;+/.2/3)-8<DHV V) VC Vc V $T
V+/9V &)V
 *-V $'V (,CH~V .2#tCy.-AV V V V V VrD   