
    i             +       	   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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  ej        e          Zdej        d<   ddlZdd	lm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( ddl)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5 ddl6m7Z7 ddl8m9Z: ddl;m<Z= 	 ddl>m?Z? e?j@        ZAn# eBeCf$ r dZAY nw xY wddlDZDddlEZEddlFmGZGmHZHmIZImJZJ ddlKmLZLmMZM dZNddlOmPZPmQZQ ddlRmSZS  eP            ZT eeU          jV        dz  ZW eSeTeW           deXdeeeXef                  fd ZYd!eXdeZdz  fd"Z[d#eXdeXdz  fd$Z\d%eXde]eX         fd&Z^deeXef         fd'Z_ e_            Z`	 dd(lambZb  ebd)*           n# ec$ r Y nw xY w	 dd+ldmeZe  ee             n# ec$ r Y nw xY w	 dd,lfmgZg  ege`           n# ec$ r Y nw xY w	 dd-lhmiZi e`j                    d.i           j                    d/d          Zk eiekr elek          nd           n# ec$ r Y nw xY w	 dd0lmmnZn  en             n# ec$ r Y nw xY wdd1lompZq dd2lrmsZs dd3ltmuZv dd4lwmxZx dd5lymzZ{ ddl|Z|dd6l}m~Z~ dd7lmZmZ dd8lKmZ dd9lmZmZ dd:lmZmZmZ dd;lmZ dd<lmZ dd=lmZmZ dd>lmZ dd?lmZ dd@lmZ dAadadB ZdaeeeXeXf                  edC<   deeX         fdDZdEedFedefdGZddHeXdeeeXeXf                  fdIZddJeeXeXf         ddfdKZddHeXdMelddfdNZdHeXddfdOZdPZdQZdRZdSZdAdTdUeXdVedeXfdWZ G dX dY          Z edZd[d\T          Z ed]d^          ZdeXfd_Zd`eXde{fdaZd`eXfdbZ eh dc          ZdddlOmZ ddfeXdeXfdgZd#eXdeeXeXf         fdhZdieXdedz  fdjZdkeZddlfdmZdneXddofdpZddqe]e         dreldseldz  deXfdtZdueXdefdvZddweXdz  dxeXdz  deeXe]e         f         fdyZ G dz d{          Zd|Zd}ZdeXfd~Zd`eXdefdZddlmZmZmZmZ  e¦            ZdefdZdeXe]eX         z  eeXdf         z  dz  de]eX         fdZdeXdedefdZ G d d          Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddweXdeXdeXdeXdeXe]eX         z  eeXdf         z  deXdeXdeXdeXdeldededededededeXdedededef*dZedk    r e|j        eͦ           dS dS )aD  
Hermes Agent CLI - Interactive Terminal Interface

A beautiful command-line interface for the Hermes Agent, inspired by Claude Code.
Features ASCII art branding, interactive REPL, toolset selection, and rich formatting.

Usage:
    python cli.py                          # Start interactive mode with all tools
    python cli.py --toolsets web,terminal  # Start with specific toolsets
    python cli.py --skills hermes-agent-dev,github-auth
    python cli.py -q "your question"       # Single query mode
    python cli.py --list-tools             # List available tools and exit
    N)contextmanager)Path)datetime)ListDictAnyOptional1HERMES_QUIET)FileHistory)Style)patch_stdout)Application)LayoutHSplitWindowFormattedTextControlConditionalContainer)	ProcessorTransformationPasswordProcessorConditionalProcessor)	Condition)	Dimension)CompletionsMenu)TextArea)KeyBindings)print_formatted_text)ANSI)CursorShape)CanonicalUsageestimate_usage_costformat_duration_compactformat_token_count_compact)_format_context_lengthformat_banner_version_label)
u   ⠋u   ⠙u   ⠹u   ⠸u   ⠼u   ⠴u   ⠦u   ⠧u   ⠇u   ⠏)get_hermes_homedisplay_hermes_home)load_hermes_dotenvz.env)hermes_homeproject_env	file_pathreturnc                 :   | sg S t          |                                           }|                                s
t          |z  }|                                st
                              d|           g S 	 t          |dd          5 }t          j	        |          }ddd           n# 1 swxY w Y   t          |t                    st
                              d|           g S |S # t          $ r(}t
                              d||           g cY d}~S d}~ww xY w)a\  Load ephemeral prefill messages from a JSON file.
    
    The file should contain a JSON array of {role, content} dicts, e.g.:
        [{"role": "user", "content": "Hi"}, {"role": "assistant", "content": "Hello!"}]
    
    Relative paths are resolved from ~/.hermes/.
    Returns an empty list if the path is empty or the file doesn't exist.
    z#Prefill messages file not found: %srutf-8encodingNz3Prefill messages file must contain a JSON array: %sz+Failed to load prefill messages from %s: %s)r   
expanduseris_absolute_hermes_homeexistsloggerwarningopenjsonload
isinstancelist	Exception)r,   pathfdataes        +/home/agentuser/.hermes/hermes-agent/cli.py_load_prefill_messagesrD   U   s`     		??%%''D #d";;== <dCCC		$g... 	 !9Q<<D	  	  	  	  	  	  	  	  	  	  	  	  	  	  	 $%% 	NNPRVWWWI   DdANNN						sH   6C( B)C( )B--C( 0B-14C( &C( (
D2DDDeffortc                     ddl m}  ||           }| r1|                                 r|t                              d|            |S )zHParse a reasoning effort level into an OpenRouter reasoning config dict.r   )parse_reasoning_effortNz5Unknown reasoning_effort '%s', using default (medium))hermes_constantsrG   stripr7   r8   )rE   rG   results      rC   _parse_reasoning_configrK   r   s\    777777##F++F X&,,.. XV^NPVWWWM    rawc                     t          | pd                                                                          }|r|dv rdS |dv rdS t                              d|            dS )zEParse a persisted service-tier preference into a Responses API value. >   offnonenormaldefaultstandardN>   onfastpriorityrW   z#Unknown service_tier '%s', ignoring)strrI   lowerr7   r8   )rM   values     rC   _parse_service_tier_configr[   {   sl    	rNN  ""((**E EMMMt***z
NN8#>>>4rL   systemc           
         g t                      dt          dz  ddffddt          ddffd}| dk    rdD ]} |           n| d	k    r |d
ddddddd           t          j                            d          t          j                            d          t          j                            d          fD ]*}|sdD ]"} t          j        j        |g|R             #+n |dddddd           S )z<Return likely browser executables for local CDP auto-launch.r?   Nr-   c                 *   | sd S t           j                            t           j                            |                     }|v rd S t           j                            |           r,                    |                                |           d S d S N)osr?   normcasenormpathisfileappendadd)r?   
normalized
candidatesseens     rC   _add_candidatez4_get_chrome_debug_candidates.<locals>._add_candidate   s     	FW%%bg&6&6t&<&<==
F7>>$ 	!d###HHZ     	! 	!rL   namesc                  L    | D ]} t          j        |                      d S r_   )shutilwhich)rj   nameri   s     rC   _add_from_pathz4_get_chrome_debug_candidates.<locals>._add_from_path   s9     	/ 	/DN6<--....	/ 	/rL   Darwin)z</Applications/Google Chrome.app/Contents/MacOS/Google Chromez2/Applications/Chromium.app/Contents/MacOS/Chromiumz</Applications/Brave Browser.app/Contents/MacOS/Brave Browserz>/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft EdgeWindows
chrome.exe
msedge.exe	brave.exechromium.exechromemsedgebravechromiumProgramFileszProgramFiles(x86)LOCALAPPDATA))GoogleChromer   rr   )Chromiumr   rr   )r~   r   ru   )BraveSoftwarezBrave-Browserr   rt   )	MicrosoftEdger   rs   zgoogle-chromezgoogle-chrome-stablezchromium-browserzbrave-browserzmicrosoft-edge)setrX   r`   environgetr?   join)r\   ro   appbasepartsri   rg   rh   s        @@@rC   _get_chrome_debug_candidatesr      s   JUUD!S4Z !D ! ! ! ! ! ! !/s /t / / / / / / 
 	  	 C N3	  
9		,^h	
 	
 	
 JNN>**JNN.//JNN>**
 	; 	;D
   ; ; rw|D95999::::;	;  	35G)9	
 	
 	

 rL   c                     t           dz  } t          t                    j        dz  }|                                 r| }n|}dddddddd	d
g dd
d
g dddddddddddi ddddddddddddddddd d!d"d#d$d%d&dd'ddd(d)d*d+did	d,d-ddddd.ddddd.d/d0g d1ddddd2d3}d}|                                rk	 t          |d4d56          5 }t          j        |          pi }d7d7d7           n# 1 swxY w Y   d8|v }d9|v rt          |d9         t                    r|d9         |d9         d)<   ngt          |d9         t                    rL|d9                             |d9                    d9|d9         v r!d)|d9         vr|d9         d9         |d9         d)<   |d9                             d:          s"|                    d:          }|r||d9         d:<   |d9                             d;          s"|                    d;          }|r||d9         d;<   |D ]p}	|	d9k    r	|	|v rct          ||	         t                    r=t          ||	         t                    r"||	                             ||	                    e||	         ||	<   q|D ]}	|	|vr|	d9k    r||	         ||	<   |                    d<          }
d=|v r;t          |
t                    r|
                    d=          |d=         |d<         d=<   n2# t          $ r%}t                              d>|           Y d7}~nd7}~ww xY wd?d@lm}  ||          }|                    d8i           }dA|v r|dA         |dB<   dC}|                    dD          |v rt$          j                            dEd          }|r4||vr0t$          j                            |          r||dD<   ||d8         dD<   nZ|                    dBd          }|dk    r(t%          j                    |dD<   |dD         |d8         dD<   n|                    dDd7           i dBdFdDdEd+dGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdi}|                                D ]t\  }}||v rk|s|t$          j        vr[||         }t          |t2                    r"d?d7l} |j        |          t$          j        |<   Xt          |          t$          j        |<   u|                    dji           }dkdli}|                                D ]+\  }}||v r"t          ||                   t$          j        |<   ,|                    dmi           }dndodpdqd.drdsdtdud.dvdwdxdyd.dz}|                                D ]h\  }}|                    |i           }t          |t                    s2t          |                    d:d                                                    }t          |                    d9d                                                    }t          |                    d;d                                                    }t          |                    d{d                                                    } |r|dk    r|t$          j        |d:         <   |r|t$          j        |d9         <   |r|t$          j        |d;         <   | r| t$          j        |d{         <   j|                    d|i           }!t          |!t                    rE|!                    d}          }"|".t          |"                                          t$          j        d~<   |S )a:  
    Load CLI configuration from config files.
    
    Config lookup order:
    1. ~/.hermes/config.yaml (user config - preferred)
    2. ./cli-config.yaml (project config - fallback)
    
    Environment variables take precedence over config file values.
    Returns default values if no config file exists.
    config.yamlcli-config.yamlrO   auto)rS   base_urlproviderlocal.<   ,  z*nikolaik/python-nodejs:python3.11-nodejs20z3docker://nikolaik/python-nodejs:python3.11-nodejs20F)env_typecwdtimeoutlifetime_secondsdocker_imagedocker_forward_envsingularity_imagemodal_imagedaytona_imagedocker_volumesdocker_mount_cwd_to_workspacex   )inactivity_timeoutrecord_sessionsT      ?)enabled	threshold      )r   max_simple_charsmax_simple_wordscheap_modelZ   z)You are a helpful, friendly AI assistant.zCYou are a concise assistant. Keep responses brief and to the point.zMYou are a technical expert. Provide detailed, accurate technical information.zSYou are a creative assistant. Think outside the box and offer innovative solutions.zBYou are a patient teacher. Explain concepts clearly with examples.u   You are a kawaii assistant! Use cute expressions like (◕‿◕), ★, ♪, and ~! Add sparkles and be super enthusiastic about everything! Every response should feel warm and adorable desu~! ヽ(>∀<☆)ノu   You are Neko-chan, an anime catgirl AI assistant, nya~! Add 'nya' and cat-like expressions to your speech. Use kaomoji like (=^･ω･^=) and ฅ^•ﻌ•^ฅ. Be playful and curious like a cat, nya~!zArrr! Ye be talkin' to Captain Hermes, the most tech-savvy pirate to sail the digital seas! Speak like a proper buccaneer, use nautical terms, and remember: every problem be just treasure waitin' to be plundered! Yo ho ho!zHark! Thou speakest with an assistant most versed in the bardic arts. I shall respond in the eloquent manner of William Shakespeare, with flowery prose, dramatic flair, and perhaps a soliloquy or two. What light through yonder terminal breaks?zDuuude! You're chatting with the chillest AI on the web, bro! Everything's gonna be totally rad. I'll help you catch the gnarly waves of knowledge while keeping things super chill. Cowabunga!a  The rain hammered against the terminal like regrets on a guilty conscience. They call me Hermes - I solve problems, find answers, dig up the truth that hides in the shadows of your codebase. In this city of silicon and secrets, everyone's got something to hide. What's your story, pal?zhewwo! i'm your fwiendwy assistant uwu~ i wiww twy my best to hewp you! *nuzzles your code* OwO what's this? wet me take a wook! i pwomise to be vewy hewpful >w<a  Greetings, seeker of wisdom. I am an assistant who contemplates the deeper meaning behind every query. Let us examine not just the 'how' but the 'why' of your questions. Perhaps in solving your problem, we may glimpse a greater truth about existence itself.zYOOO LET'S GOOOO!!! I am SO PUMPED to help you today! Every question is AMAZING and we're gonna CRUSH IT together! This is gonna be LEGENDARY! ARE YOU READY?! LET'S DO THIS!)helpfulconcise	technicalcreativeteacherkawaiicatgirlpirateshakespearesurfernoiruwuphilosopherhype)	max_turnsverbosesystem_promptprefill_messages_filereasoning_effortservice_tierpersonalitiesfull	interruptrS   )compactresume_displayshow_reasoning	streamingbusy_input_modeskinr   2   )r   max_tool_calls)r   modelr   api_key)visionweb_extract-   )terminalfileweb)max_iterationsdefault_toolsetsr   r   r   r   )r   r   browsercompressionsmart_model_routingagentdisplayclarifycode_execution	auxiliary
delegationr/   r0   r1   Nr   r   r   r   r   r   z"Failed to load cli-config.yaml: %sr   )_expand_env_varsbackendr   )r   r   r   r   TERMINAL_CWDTERMINAL_ENVTERMINAL_TIMEOUTr   TERMINAL_LIFETIME_SECONDSr   TERMINAL_DOCKER_IMAGEr   TERMINAL_DOCKER_FORWARD_ENVr   TERMINAL_SINGULARITY_IMAGEr   TERMINAL_MODAL_IMAGEr   TERMINAL_DAYTONA_IMAGEssh_hostTERMINAL_SSH_HOSTssh_userTERMINAL_SSH_USERssh_portTERMINAL_SSH_PORTssh_keyTERMINAL_SSH_KEYcontainer_cpuTERMINAL_CONTAINER_CPUcontainer_memoryTERMINAL_CONTAINER_MEMORYcontainer_diskTERMINAL_CONTAINER_DISKcontainer_persistentTERMINAL_CONTAINER_PERSISTENTTERMINAL_DOCKER_VOLUMES&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACETERMINAL_SANDBOX_DIRTERMINAL_PERSISTENT_SHELLSUDO_PASSWORD)r   r   sandbox_dirpersistent_shellsudo_passwordr   r   BROWSER_INACTIVITY_TIMEOUTr   AUXILIARY_VISION_PROVIDERAUXILIARY_VISION_MODELAUXILIARY_VISION_BASE_URLAUXILIARY_VISION_API_KEYAUXILIARY_WEB_EXTRACT_PROVIDERAUXILIARY_WEB_EXTRACT_MODELAUXILIARY_WEB_EXTRACT_BASE_URLAUXILIARY_WEB_EXTRACT_API_KEYAUXILIARY_APPROVAL_PROVIDERAUXILIARY_APPROVAL_MODELAUXILIARY_APPROVAL_BASE_URLAUXILIARY_APPROVAL_API_KEY)r   r   approvalr   securityredact_secretsHERMES_REDACT_SECRETS)r5   r   __file__parentr6   r9   yaml	safe_loadr<   rX   dictupdater   r>   r7   r8   hermes_cli.configr   r`   r   r?   isabsgetcwdpopitemsr=   r:   dumpsrI   rY   )#user_config_pathproject_config_pathconfig_pathdefaults_file_has_terminal_configr@   file_configroot_providerroot_base_urlkeyagent_file_configrB   r   terminal_config_CWD_PLACEHOLDERS_existing_cwdeffective_backendenv_mappings
config_keyenv_varvalr:   browser_configbrowser_env_mappingsauxiliary_configauxiliary_task_envtask_keyenv_maptask_cfgprovr   r   r   security_configredacts#                                      rC   load_cli_configr9     so
    $m3x../2CC    *&)
 
 
   #H"$!VGI -2
 
 #&$
 

 
 

  # "	 
  
 %' "F`lq_ n h {  U \ x {  c H 
 
4 $#*
 
 s
  
 
 #	  #	 
 
 ! ; ; ;
 
q` `HL !&  AD@	Dk3999 6Q"nQ//526 6 6 6 6 6 6 6 6 6 6 6 6 6 6 )3k(A% +%%k'2C88 U3>w3GHW%i00G 4d;; 
UW%,,[-ABBB +g"6669KX_L`;`;`7B77KG7T))4 G$((44 B +
 ; ;  B4AHW%j1G$((44 B +
 ; ;  B4AHW%j1   9 9'>>+%%!(3-66 9:kRUFVX\;];] 9 ,,[-=>>>>(3C(8 # 5 5h&&3'>>$/$4HSM !, 8 8k)),d33 *%))+66B1<[1I!+. 	D 	D 	DNN?CCCCCCCC	D 322222))H ll:r22O
 O##&5i&@
# -5!!%666
~r:: 	1]2CCCVcHdHdC%2OE"*7HZ '' / 3 3J H H G++)+&.=e.D$U++  ##E4000N~ 	% 	7	
 	/ 	; 	9 	- 	1 	' 	' 	' 	%  	1!" 	7#$ 	3%& 	 ?'( 4)Q-7(5  LD  ,1133 3 3
G((( 3G2:,E,E%j1c4(( 3KKK*4$*S//BJw''*-c((BJw' \\)R00N:  499;; B B
G''"%nZ&@"A"ABJw  ||K44 4-31	
 
 9286	
 
 6/53	
 
 , 05577 5 5'#''"55(D)) 	8<<
B//006688HLL"--..4466x||J3344::<<hll9b112288:: 	3DFNN.2BJwz*+ 	1+0BJww'( 	7.6BJwz*+ 	5-4BJwy)* ll:r22O/4(( F $$%56625f++2C2C2E2EBJ./Os=   :K2 C/#K2 /C33K2 6C37G:K2 2
L!<LL!)setup_loggingcli)mode)print_config_warnings)init_skin_from_config)set_tool_preview_max_lenr   tool_preview_length)neuter_async_httpx_del)box)Console)escapePanelText)AIAgent)get_tool_definitionsget_toolset_for_tool)build_welcome_banner)SlashCommandCompleterSlashCommandAutoSuggest)get_all_toolsetsget_toolset_infovalidate_toolset)get_job)cleanup_all_environments)set_sudo_password_callbackset_approval_callback)set_secret_capture_callbackprompt_for_secret)_emergency_cleanup_all_sessionsFc                  Z   t           rdS da 	 t                       n# t          $ r Y nw xY w	 t                       n# t          $ r Y nw xY w	 ddlm}   |              n# t          $ r Y nw xY w	 ddlm}  |             n# t          $ r Y nw xY w	 ddlm	}  |dt          rt          j        ndd	           n# t          $ r Y nw xY w	 t          rGt          t          d
          r4t                              t          t          dd          pg            dS dS dS # t          $ r Y dS w xY w)z"Run resource cleanup exactly once.NTr   )shutdown_mcp_servers)shutdown_cached_clientsinvoke_hookon_session_finalizer;  
session_idplatformshutdown_memory_providerconversation_history)_cleanup_done_cleanup_all_terminalsr>   _cleanup_all_browserstools.mcp_toolr[  agent.auxiliary_clientr\  hermes_cli.pluginsr^  _active_agent_refra  hasattrrc  getattr)r[  r\  _invoke_hooks      rC   _run_cleanupro  c  s     M          777777   
BBBBBB!!!!   BBBBBB*Wh7r7H7S7Snr  ~C  	D  	D  	D  	D  	D    	):<V!W!W 	66)+A4HHNB    	 	 	 	    sd    
))< 
A	A	A 
A+*A+/B   
BB'B9 9
CC
AD 
D*)D*_active_worktreec                      ddl } 	 |                     g dddd          }|j        dk    r|j                                        S n# t
          $ r Y nw xY wdS )z;Return the git repo root for CWD, or None if not in a repo.r   N)gitz	rev-parsez--show-toplevelT   )capture_outputtextr   )
subprocessrun
returncodestdoutrI   r>   )rv  rJ   s     rC   _git_repo_rootrz    s    333dA   
 
 !!=&&((( "   4s   >A 
AAr?   rootc                 T    	 |                      |           dS # t          $ r Y dS w xY w)z@Return True when a resolved path stays within the expected root.TF)relative_to
ValueError)r?   r{  s     rC   _path_is_within_rootr    sB    t   uus    
''	repo_rootc           	      	   ddl }| pt                      } | s t          d           t          d           dS t          j                    j        dd         }d| }d| }t          |           dz  }|                    d	d	
           ||z  }t          |           dz  }d}	 |                                r|	                                nd}	||	
                                vrlt          |d          5 }
|	r*|	                    d          s|
                    d           |
                    | d           ddd           n# 1 swxY w Y   n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w	 |                    dddt%          |          d|dgd	d	d|           }|j        dk    r,t          d|j                                         d           dS n+# t          $ r}t          d| d           Y d}~dS d}~ww xY wt          |           dz  }|                                rc	 t          |                                           }|                                }|	                                
                                D ]}|                                }|r|                    d          r/t          |           |z  }||z  }	 |                    d          }|                    d          }n2# t0          t2          f$ r t                              d|           Y w xY wt5          ||          st                              d|           t5          ||          st                              d |           |                                rM|j                            d	d	
           t=          j        t%          |          t%          |                     _|                                 r_|                                sK|j                            d	d	
           tC          j"        t%          |          t%          |                     n2# t          $ r%}t                              d!|           Y d}~nd}~ww xY wt%          |          || d"}t          d#|            t          d$|            |S )%zCreate an isolated git worktree for this CLI session.

    Returns a dict with worktree metadata on success, None on failure.
    The dict contains: path, branch, repo_root.
    r   Nu?   [31m✗ --worktree requires being inside a git repository.[0mz5  cd into your project repo first, then run hermes -w   hermes-zhermes/
.worktreesTparentsexist_okz
.gitignorez.worktrees/rO   a
zCould not update .gitignore: %srr  worktreere   z-bHEAD   rt  ru  r   r   u$   [31m✗ Failed to create worktree: [0mz.worktreeinclude#F)strictz+Skipping invalid .worktreeinclude entry: %sz5Skipping .worktreeinclude entry outside repo root: %sz9Skipping .worktreeinclude entry that escapes worktree: %sz*Error copying .worktreeinclude entries: %s)r?   branchr  u   [32m✓ Worktree created:[0m z
  Branch: )#rv  rz  printuuiduuid4hexr   mkdirr6   	read_text
splitlinesr9   endswithwriter>   r7   debugrw  rX   rx  stderrrI   resolve
startswithOSErrorr~  r  r8   is_filer  rl   copy2is_dirr`   symlink)r  rv  short_idwt_namebranch_nameworktrees_dirwt_path	gitignore_ignore_entryexistingr@   rB   rJ   include_filerepo_root_resolvedwt_path_resolvedlineentrysrcdstsrc_resolveddst_resolvedinfos                          rC   _setup_worktreer    s    -^--I UVVVEFFFtz||#H"""G%G%%KOOl2Mt444g%G Y,.I!M;,5,<,<,>,>F9&&(((B 3 3 5 555i%% . "H$5$5d$;$; "GGDMMM=,,,---. . . . . . . . . . . . . . .  ; ; ;6::::::::;
Js7||T;OdBI   
 
 !!ZFM<O<O<Q<QZZZ[[[4 "    BBBBCCCttttt
 	??%77L "J!	J!%i!8!8!:!:&00$..00;;== @ @

  0 0 5 5 9oo-o#&;;e;#<#<L#&;;e;#<#<LL,   LL!NPUVVVH ,L:LMM NN#Z\abbb+L:JKK NN#^`efff;;== @J$$TD$AAALS3s884444ZZ\\ @::<< @
(((EEE
3|#4#4c#hh???9@:  	J 	J 	JLLEqIIIIIIII	J G D 

;'
;
;<<<	
${
$
$%%%Ks   $AE 4AE9E E		E E	E 
F E;;F A#G* *
H4HH=B!Q- ,LQ- ,L;8Q- :L;;D1Q- -
R7RRr  c                    | pt           } | sdS ddl}| d         }| d         }| d         }t          |                                          sdS d}	 |                    g dddd	|
          }t          |j                                                  }n# t          $ r d}Y nw xY w|r)t          d| d           t          d|            da dS 	 |                    ddd|dgddd|
           n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w	 |                    ddd|gddd	|
           n3# t          $ r&}t                              d||           Y d}~nd}~ww xY wda t          d| d           dS )u;  Remove a worktree and its branch on exit.

    Preserves the worktree only if it has unpushed commits (real work
    that hasn't been pushed to any remote).  Uncommitted changes alone
    (untracked files, test artifacts) are not enough to keep it — agent
    work lives in commits/PRs, not the working tree.
    Nr   r?   r  r  Frr  logz	--oneliner  z--notz	--remotesT
   r  u2   
[33m⚠ Worktree has unpushed commits, keeping: r  z4  To clean up manually: git worktree remove --force rr  r  remove--force   zFailed to remove worktree: %s-DzFailed to delete branch %s: %su   [32m✓ Worktree cleaned up: )rp  rv  r   r6   rw  boolry  rI   r>   r  r7   r  )r  rv  r  r  r  has_unpushedrJ   rB   s           rC   _cleanup_worktreer    sQ    ##D 6lG(^F[!I==!! 
 LEEEdBG   
 
 FM//1122     WwWWWXXXNWNNOOO9J'9=dBI 	 	
 	
 	
 	
  9 9 94a888888889BHdF+dBI 	 	
 	
 	
 	
  B B B5vqAAAAAAAAB 	
>g
>
>
>?????sC   AB B"!B"C1 1
D ;DD $E 
E3E..E3   max_age_hoursc           
      f   ddl }ddl}t          |           dz  }|                                st	          |            dS  |j                    }||dz  z
  }||dz  dz  z
  }|                                D ]}|                                r|j                            d          s2	 |	                                j
        }	|	|k    rSn# t          $ r Y `w xY w|	|k    }
|
sU	 |                    g dddd	t          |          
          }|j                                        rn# t          $ r Y w xY w	 |                    g dddd	t          |          
          }|j                                        }|                    dddt          |          dgddd| 
           |r|                    ddd|gddd| 
           t                               d|j        |
           s# t          $ r,}t                               d|j        |           Y d}~d}~ww xY wt	          |            dS )u~  Remove stale worktrees and orphaned branches on startup.

    Age-based tiers:
    - Under max_age_hours (24h): skip — session may still be active.
    - 24h–72h: remove if no unpushed commits.
    - Over 72h: force remove regardless (nothing should sit this long).

    Also prunes orphaned ``hermes/*`` and ``pr-*`` local branches that
    have no corresponding worktree.
    r   Nr       r  r  Trs  r  rr  r  z--show-currentrr  r  r  r  r  r  r  r  z$Pruned stale worktree: %s (force=%s)zFailed to prune worktree %s: %s)rv  timer   r6   _prune_orphaned_branchesiterdirr  rn   r  statst_mtimer>   rw  rX   ry  rI   r7   r  )r  r  rv  r  r  nowsoft_cutoffhard_cutoffr  mtimeforcerJ   branch_resultr  rB   s                  rC   _prune_stale_worktreesr  Q  s    KKKOOl2M!!  +++
$)++C-.K*T12K&&(( -K -K||~~ 	UZ%:%:9%E%E 		JJLL)E{"" # 	 	 	H	 $ 
	#MMM#'dA3u:: (   =&&((    	K&NN333#$s5zz +  M #)//11FNN
Hc%jj)D#$	      HdF3#'dBI     LL?USSSS 	K 	K 	KLL:EJJJJJJJJJ	K Y'''''s>   )C


CC#AD''
D43D48B/G))
H3!HHc                    ddl }	 |                    g dddd|           }|j        dk    rdS d |j                                                            d          D             }n# t          $ r Y dS w xY wt                      	 |                    g d	ddd|           }|j                            d          D ]X}|                    d
          rA	                    |                    d
d          d                                                    Yn# t          $ r Y dS w xY w	 |                    g dddd|           }|j                                        }|r	                    |           n# t          $ r Y nw xY w	                    d           fd|D             }|sdS t          dt          |          d          D ]a}	||	|	dz            }
	 |                    g d|
z   ddd|            0# t          $ r%}t                              d|           Y d}~Zd}~ww xY wt                              dt          |                     dS )zDelete local ``hermes/hermes-*`` and ``pr-*`` branches with no worktree.

    These are auto-generated by ``hermes -w`` sessions and PR review
    workflows respectively.  Once their worktree is gone they serve no
    purpose and just accumulate.
    r   N)rr  r  z--format=%(refname:short)Tr  r  c                 ^    g | ]*}|                                 |                                 +S  rI   ).0bs     rC   
<listcomp>z,_prune_orphaned_branches.<locals>.<listcomp>  s2    ZZZaPQPWPWPYPYZ		ZZZrL   r  )rr  r  r=   z--porcelainzbranch refs/heads/   r  rs  mainc                 p    g | ]2}|v|                     d           s|                     d          0|3S )zhermes/hermes-zpr-r  )r  r  active_branchess     rC   r  z,_prune_orphaned_branches.<locals>.<listcomp>  sW       O##\\*++ $/0||E/B/B $ 	
###rL   r   )rr  r  r  r  z%Failed to prune orphaned branches: %szPruned %d orphaned branches)rv  rw  rx  ry  rI   splitr>   r   r  re   rangelenr7   r  )r  rv  rJ   all_branches	wt_resultr  head_resultcurrentorphanedibatchrB   r  s               @rC   r  r    s(    	:::dBI   
 
 !!FZZ6=+>+>+@+@+F+Ft+L+LZZZ    55O	NN666dBI # 
 
	 $**400 	U 	UD344 U##DJJ/CQ$G$G$K$Q$Q$S$STTT	U    	 nn///dA9 % 
 
 $**,, 	)(((        H   1c(mmR(( E E1r6"	ENN'''%/#$	       	E 	E 	ELL@!DDDDDDDD	E LL.H>>>>>sT   'A' 6A' '
A54A5BD 
D%$D%)AE6 6
FFG;;
H*H%%H*z[1;38;2;255;215;0mz[1mr      bold	hex_colorr  c          	         	 t          | dd         d          }t          | dd         d          }t          | dd         d          }|rdnd}d| d	| d
| d
| d	S # t          t          f$ r |rt          ndcY S w xY w)z?Convert a hex color like '#268bd2' to a true-color ANSI escape.r  r     rs     z1;rO   z[z38;2;;mz[38;2;184;134;11m)intr~  
IndexError_ACCENT_ANSI_DEFAULT)r  r  r/   gr  prefixs         rC   _hex_to_ansir    s    I	!A###	!A###	!A###%20v00A0000A0000
# I I I'+H##1HHHHIs   AA A>=A>c                   b    e Zd ZdZdddd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dZ
dS )_SkinAwareAnsizLazy ANSI escape that resolves from the skin engine on first use.

    Acts as a string in f-strings and concatenation.  Call ``.reset()`` to
    force re-resolution after a ``/skin`` switch.
    #FFD700Fr  skin_keyfallback_hexr  c                >    || _         || _        || _        d | _        d S r_   )	_skin_key_fallback_hex_bold_cached)selfr  r  r  s       rC   __init__z_SkinAwareAnsi.__init__  s#    !)
#'rL   r-   c                    | j         y	 ddlm} t           |                                | j        | j                  | j                  | _         n0# t          $ r# t          | j        | j                  | _         Y nw xY w| j         S )Nr   get_active_skinr  )	r  hermes_cli.skin_enginer  r  	get_colorr   r  r  r>   )r  r  s     rC   __str__z_SkinAwareAnsi.__str__	  s    <QBBBBBB+#O%%//@RSS       Q Q Q+D,>TZPPPQ|s   AA *A>=A>otherc                 &    t          |           |z   S r_   rX   r  r  s     rC   __add__z_SkinAwareAnsi.__add__  s    4yy5  rL   c                 &    |t          |           z   S r_   r  r  s     rC   __radd__z_SkinAwareAnsi.__radd__  s    s4yy  rL   Nc                     d| _         dS )z1Clear cache so the next access re-reads the skin.N)r  r  s    rC   resetz_SkinAwareAnsi.reset  s    rL   )r  r-   N)__name__
__module____qualname____doc__rX   r  r  r  r  r  r  r  rL   rC   r  r    s         (UZ ( ( ( (C (d ( ( ( (
 
 
 
 
!S !S ! ! ! !!c !c ! ! ! !     rL   r  response_borderr  T
banner_dim#B8860Bc                  n    	 ddl m}   |                                 dd          S # t          $ r Y dS w xY w)z@Return the active skin accent color for legacy CLI output lines.r   r  	ui_accent#FFBF00)r	  r  r
  r>   r  s    rC   _accent_hexr!  $  sY    ::::::  **;	BBB   yys   #& 
44ru  c                 .    t          j        | pd          S )zSafely render assistant/tool output that may contain ANSI escapes.

    Using Rich Text.from_ansi preserves literal bracketed text like
    ``[not markup]`` while still interpreting real ANSI color codes.
    rO   )	_RichText	from_ansiru  s    rC   _rich_text_from_ansir&  -  s     tzr***rL   c                 >    t          t          |                      dS )a  Print ANSI-colored text through prompt_toolkit's native renderer.

    Raw ANSI escapes written via print() are swallowed by patch_stdout's
    StdoutProxy.  Routing through print_formatted_text(ANSI(...)) lets
    prompt_toolkit parse the escapes and render real colors.
    N)	_pt_print_PT_ANSIr%  s    rC   _cprintr*  6  s     htnnrL   >
   .bmp.gif.ico.jpg.svg.tif.jpeg.tiff.webp.png)	is_termuxcat.pngfilenamec                    t           j                            d          dddg}|D ]D}t           j                            |          r#t           j                            |d|           c S Et           j                            dd|           S )zCReturn a realistic example media path for the current Termux setup.z~/storage/sharedz/sdcardz/storage/emulated/0z/storage/self/primaryPictures)r`   r?   r3   isdirr   )r7  rg   r{  s      rC   _termux_example_image_pathr;  M  s     	-..	J  < <7== 	<7<<j(;;;;;	<7<<*JAAArL   c                    t          | pd                                          } | sdS | d         dv r| d         }d}|t          |           k     ru| |         }|dk    r|dz   t          |           k     r|dz  }=||k    r-| d|         }| |dz   d                                         }||fS |dz  }|t          |           k     u| dd         dfS d}|t          |           k     rX| |         }|dk    r+|dz   t          |           k     r| |dz            d	k    r|dz  }n|d	k    rn|dz  }|t          |           k     X| d|                             d
d	          }| |d                                         }||fS )a6  Split a leading file path token from trailing free-form text.

    Supports quoted paths and backslash-escaped spaces so callers can accept
    inputs like:
      /tmp/pic.png describe this
      ~/storage/shared/My\ Photos/cat.png what is this?
      "/storage/emulated/0/DCIM/Camera/cat 1.png" summarize
    rO   )rO   rO   r   >   "'r  \   N z\ )rX   rI   r  replace)rM   quoteposchtoken	remainders         rC   _split_path_inputrH  [  s    ciR..


 
 C v
1vACHHnnSBTzzcAgC00qU{{AcE
a		N0022	i''1HC CHHnn 122w{
C
C..X::#'CHH,,S1W1D1D1HCC3YY1HC C.. IeS))ECDD	!!I)rL   raw_pathc                    t          | pd                                          }|sdS |                    d          r|                    d          s*|                    d          r1|                    d          r|dd                                         }|sdS t          j                            t          j                            |                    }t          |          }|	                                s8t          t	          j
        dt	          j                                        }||z  }	 |                                }n# t          $ r |}Y nw xY w|                                r|                                sdS |S )a  Resolve a user-supplied local attachment path.

    Accepts quoted or unquoted paths, expands ``~`` and env vars, and resolves
    relative paths from ``TERMINAL_CWD`` when set (matching terminal tool cwd).
    Returns ``None`` when the path does not resolve to an existing file.
    rO   Nr=  r>  r  r  r   )rX   rI   r  r  r`   r?   
expandvarsr3   r   r4   getenvr  r  r>   r6   r  )rI  rF  expandedr?   base_dirresolveds         rC   _resolve_attachment_pathrP    s~    B%%''E t $%.."5"5 $5;K;KC;P;P $UZUcUcdgUhUh $ad!!## tw!!"'"4"4U";";<<H>>D 	.")++>>??$<<>>    ?? H$4$4$6$6 tOs   4E	 	EEevtz
str | Nonec           	         |                      dd          }|                      dd          }|                      dd          }|dk    rd|                      dd	           d
S |dk    rb|                      dd          }|                      dd	          }|                      dd          }d| d| d| d| }|r	|d| dz  }|d
z  }|S |                      dd          }|                      dd	          }d| d| d| d| d
	S )zFormat a process notification event into a [SYSTEM: ...] message.

    Handles both completion events (notify_on_complete) and watch pattern
    match events from the unified completion_queue.
    type
completionra  unknowncommandwatch_disabledz	[SYSTEM: messagerO   ]watch_matchpattern?output
suppressedr   z[SYSTEM: Background process z matched watch pattern "z".
Command: z
Matched output:
z
(z/ earlier matches were suppressed by rate limit)	exit_codez completed (exit code z).
Command: z	
Output:
r   )	rQ  evt_type_sid_cmd_pat_out_supru  _exits	            rC   _format_process_notificationrh    s    wwv|,,H77<++D779i((D###43779b114444=  wwy#&&wwx$$ww|Q'''4 ' '#' '' ' !%' ' 	  	PO$OOOOD GGK%%E778R  D	t 	 		 		 	 	 	 	rL   
user_inputzdict | Nonec                 J   t          | t                    sdS |                                 }|sdS |                    d          p|                    d          p}|                    d          ph|                    d          pS|                    d          p>|                    d          p)|                    d          p|                    d	          }|sdS t	          |          \  }}t          |          }|dS ||j                                        t          v |d
S )a
  Detect if *user_input* starts with a real local file path.

    This catches dragged/pasted paths before they are mistaken for slash
    commands, and also supports Termux-friendly paths like ``~/storage/...``.

    Returns a dict on match::

        {
            "path": Path,          # resolved file path
            "is_image": bool,      # True when suffix is a known image type
            "remainder": str,      # any text after the path
        }

    Returns ``None`` when the input is not a real file path.
    N/~z./z../z"/z"~z'/z'~)r?   is_imagerG  )	r<   rX   rI   r  rH  rP  suffixrY   _IMAGE_EXTENSIONS)ri  strippedstarts_like_pathfirst_tokenrG  	drop_paths         rC   _detect_file_droprt    s]     j#&& t!!H t 	C   	%s##	%t$$	% u%%	% t$$		%
 t$$	% t$$	% t$$   t.x88K(55It $**,,0AA  rL   attached_imagesimage_counterwidthc                 n   | sdS |pt          j        d          j        }dt          dt          dt          fd}|dk     rAt          |           dk    rd	 || d
         j        d           dS d	t          |            dS |dk     r`t          |           dk    rd	 || d
         j        d           dS  || d
         j        d          }t          |           dz
  }d	| d| dS |t          |           z
  dz   d                    fdt          t          |                     D                       S )zFormat the attached-image badge row for the interactive CLI.

    Narrow terminals such as Termux should get a compact summary that fits on a
    single row, while wider terminals can show the classic per-image badges.
    rO   P   r  rn   limitr-   c                 h    t          |           |k    r| n| d t          d|dz
                     dz   S )Nr  r  ...)r  max)rn   r{  s     rC   _truncz/_format_image_attachment_badges.<locals>._trunc  s:    4yyE))ttt4Gc!UQY6G6G4G/H5/PPrL   4   r  u   [📎 r      rY  z images attached]rz      z] [+rA  c              3   *   K   | ]}d |z    dV  dS )u   [📎 Image #rY  Nr  )r  r  r   s     rC   	<genexpr>z2_format_image_attachment_badges.<locals>.<genexpr>  sF         	$q###     rL   )	rl   get_terminal_sizecolumnsrX   r  r  rn   r   r  )ru  rv  rw  r  firstextrar   s         @rC   _format_image_attachment_badgesr    s     r?V-h77?EQS Q Q Q Q Q Q rzz1$$BFF?1#5#:B??BBBB?O,,????rzz1$$BFF?1#5#:B??BBBBq).33O$$q(+++5++++3///!3D88    s?++,,     rL   pasted_textc                 ,    |                                   S )z@Auto-attach clipboard images only for image-only paste gestures.r  )r  s    rC   ,_should_auto_attach_clipboard_image_on_paster    s      """"rL   query	image_argc                 r   | pd}g }t          |t                    rZt          |          }|rI|                    d          r4|                    |d                    |d         pd|d         j         d}|rjt          |          }|t          d|           |j        	                                t          vrt          d	|           |                    |           g }t                      }|D ]@}t          |          }	|	|v r|                    |	           |                    |           A||fS )
z;Collect local image attachments for single-query CLI flows.rO   rm  r?   rG  [User attached image: rY  NzImage file not found: zNot a supported image file: )r<   rX   rt  r   rd   rn   rP  r~  rn  rY   ro  r   re   )
r  r  rX  imagesdroppedexplicit_pathdedupedrh   imgr%  s
             rC   _collect_query_imagesr  #  s^   krGF'3 _#G,, 	_w{{:.. 	_MM'&/***k*^.^wvG[.^.^.^G %0;; AiAABBB%%''/@@@KMKKLLLm$$$GUUD  #hh$;;sGrL   c                   4    e Zd ZdZd Zd Zed             ZdS )ChatConsoleuR  Rich Console adapter for prompt_toolkit's patch_stdout context.

    Captures Rich's rendered ANSI output and routes it through _cprint
    so colors and markup render correctly inside the interactive chat loop.
    Drop-in replacement for Rich Console — just pass this to any function
    that expects a console.print() interface.
    c                 j    ddl m}  |            | _        t          | j        ddd          | _        d S )Nr   )StringIOT	truecolorF)r   force_terminalcolor_system	highlight)ior  _bufferrC  _inner)r  r  s     rC   r  zChatConsole.__init__J  sI    xzz$	
 
 
rL   c                 |   | j                             d           | j                                          t          j        d          j        | j        _         | j        j        |i | | j         	                                }|
                    d                              d          D ]}t          |           d S )Nr   ry  r  )r  seektruncaterl   r  r  r  rw  r  getvaluerstripr  r*  )r  argskwargsr]  r  s        rC   r  zChatConsole.printT  s    !"4X>>F4*6***&&((MM$''--d33 	 	DDMMMM	 	rL   c              /      K   | V  dS )a  Provide a no-op Rich-compatible status context.

        Some slash command helpers use ``console.status(...)`` when running in
        the standalone CLI. Interactive chat routes those helpers through
        ``ChatConsole()``, which historically only implemented ``print()``.
        Returning a silent context manager keeps slash commands compatible
        without duplicating the higher-level busy indicator already shown by
        ``HermesCLI._busy_command()``.
        Nr  )r  _args_kwargss      rC   statuszChatConsole.status^  s       




rL   N)r  r  r  r  r  r  r   r  r  rL   rC   r  r  A  sW         
 
 
   
 
 ^
 
 
rL   r  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]⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀[/]c                     	 ddl m}   |             }n# t          $ r d}Y nw xY w|rt          |dd          nd}|r|                    dd          nd}|r|                    dd	          nd	}|r|                    d
d          nd}|dk    rd}d}n!|r|                    dd          nd}| d}|}t                      }	t          t          j	                    j
        dz
  d          }
|
dk     rd| d| d| dS |
dz
  }d|
z  }|dz
  }|d|                             |          }|	d|                             |          }d| d| d| d| d| d| d| d| d| d| d| d | d!S )"z<Build a compact banner that fits the current terminal width.r   r  Nrn   rS   banner_borderr  banner_titler   r  r  u$   ⚕ NOUS HERMES - AI Agent Frameworku   ⚕ NOUS HERMES
agent_nameHermes Agentz - AI Agent Frameworkr@  X   r  z
[rY  	[/] [dim z]- Nous Research[/]
u   ═z
[bold u   ]╔u   ╗[/]
[bold u	   ]║[/] [z
[/] [bold u   ]║[/]
[bold u   ]║[/] [dim u   ]╚u   ╝[/]
)r	  r  r>   rm  r
  get_brandingr&   minrl   r  r  ljust)r  _skin	skin_nameborder_colortitle_color	dim_colorline1	tiny_liner  version_linewinnerbarcontent_widthline2s                  rC   _build_compact_bannerr    sa   ::::::!!    6;Ivy111	IBGV5???I>>>YL@ET%//.)<<<9K<APi888yII6%		INbU''nEEETb
444	.00LF$&&.2B77A2vvW[WW9WWyWWWWEE
!)CAIM .=.!''66E-(..}==E	1< 	1 	1S 	1 	1	1 	1(3	1 	16;	1 	1GS	1 	1	1 	1,5	1 	18=	1 	1IU	1 	1 	1 	1 $'	1 	1 	1s    ""c                     | r|                      d          sdS |                                 d         }d|dd         vS )a  Return True if *text* looks like a slash command, not a file path.

    Slash commands are ``/help``, ``/model gpt-4``, ``/q``, etc.
    File paths like ``/Users/ironin/file.md:45-46 can you fix this?``
    also start with ``/`` but contain additional ``/`` characters in
    the first whitespace-delimited word.  This helper distinguishes
    the two so that pasted paths are sent to the agent instead of
    triggering "Unknown command".
    rk  Fr   r  N)r  r  )ru  
first_words     rC   _looks_like_slash_commandr    sJ      ts++ uaJ jn$$rL   )scan_skill_commandsbuild_skill_invocation_messagebuild_plan_pathbuild_preloaded_skills_promptc                      	 ddl m}  t           |             j                                                  S # t
          $ r t                      cY S w xY w)zIReturn plugin command names (without slash prefix) for dispatch matching.r   get_plugin_manager)rj  r  r   _plugin_commandskeysr>   r  s    rC   _get_plugin_cmd_handler_namesr    sh    999999%%''8==??@@@   uus   36 AAskills.c                    | sg S t          | t                    r| g}n9t          | t          t          f          rd | D             }nt          |           g}g }t	                      }|D ]_}|                    d          D ]G}|                                }|r||v r|                    |           |                    |           H`|S )zJNormalize a CLI skills flag into a deduplicated list of skill identifiers.c                 0    g | ]}|t          |          S r_   r  r  items     rC   r  z*_parse_skills_argument.<locals>.<listcomp>  s#    GGGDd6Fc$ii6F6F6FrL   ,)	r<   rX   r=   tupler   r  rI   re   rd   )r  
raw_valuesparsedrh   rM   partrf   s          rC   _parse_skills_argumentr    s     	&# #X

	FT5M	*	* #GGFGGG

&kk]
FUUD & &IIcNN 	& 	&DJ t!3!3HHZ   MM*%%%%	& MrL   key_pathrZ   c                    t           dz  }t          t                    j        dz  }|                                r|n|}	 |j                            dd           |                                r?t          |d          5 }t          j        |          pi }ddd           n# 1 swxY w Y   ni }| 	                    d          }|}|dd         D ].}	|	|vst          ||	         t                    si ||	<   ||	         }/|||d         <   d	d
lm}
  |
||           	 t          j        |d           n# t           t"          f$ r Y nw xY wdS # t$          $ r&}t&                              d|           Y d}~dS d}~ww xY w)a  
    Save a value to the active config file at the specified key path.
    
    Respects the same lookup order as load_cli_config():
    1. ~/.hermes/config.yaml (user config - preferred, used if it exists)
    2. ./cli-config.yaml (project config - fallback)
    
    Args:
        key_path: Dot-separated path like "agent.system_prompt"
        value: Value to save
    
    Returns:
        True if successful, False otherwise
    r   r   Tr  r/   Nr   r  r   )atomic_yaml_writei  zFailed to save config: %sF)r5   r   r  r  r6   r  r9   r  r  r  r<   r  utilsr  r`   chmodr  NotImplementedErrorr>   r7   error)r  rZ   r  r  r  r@   configr  r  r%  r  rB   s               rC   save_config_valuer    s     $m3x../2CC&6&=&=&?&?X""EXK"   ===  	k3'' 11**0b1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 F ~~c""9 	# 	#C'!!GCL$)G)G!!clGG!R 	,++++++v...	H[%((((,- 	 	 	D	 t   0!444uuuuusb    A E  B#E #B''E *B'+A3E D5 4E 5E	E E		E 
E>E99E>c                   \   e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 ddedee         dededed	ed
ededededefdZdde	ddfdZ
dee         defdZddee         dedefdZdeeef         fdZededefd            Zedededefd            Zeddeeef         defd             Zddee         defd!Zdd"edee         defd#Zddee         defd$Zddee         defd%Zddee         fd&Zddee         defd'Zd( Zd)edefd*Zdeddfd+Zd, Z d-eddfd.Z!dd/d0eddfd1Z"deddfd2Z#dd3Z$dd4Z%deddfd5Z&dd6Z'dd7Z(d8edefd9Z)defd:Z*e+d;efd<            Z,defd=Z-d>ede.fd?Z/ddddd@dAedBe.dCedDe.dz  def
dEZ0dF Z1defdGZ2dH Z3defdIZ4d8efdJZ5dKede6dedz  fdLZ7d8efdMZ8dN Z9dO Z:dPefdQZ;dRdSdedTe6dUedefdVZ<dW Z=dX Z>dY Z?defdZZ@d[edefd\ZAd] ZBd^ ZCd_efd`ZDda ZEdb ZFdc ZGdddede6e.eef                  fdeZHdfddgdheddedefdiZIdj ZJdkeddfdlZKddmZLdPeddfdnZMdPeddfdoZNdp ZOdq ZPdr ZQddtedue6e         dvededz  fdwZRdxededz  fdyZSddze6d{ed|eddfd}ZTdd~ZUdeddfdZVddeddfdZWdPefdZXddededefdZYd ZZedefd            Z[dPeddfdZ\d_efdZ]d_efdZ^d_efdZ_d Z`d8edefdZad_efdZbd_efdZcd_efdZdedededefd            Zed_efdZfd_efdZgd Zhd Zid_efdZjd_efdZkd-efdZlddPefdZmd Znd Zodd8efdZpddZqd ZrdeddfdZsddkededede.fdZtdedede.fdZudedede.defdZvd Zwd ZxdefdZyd8efdZzd Z{d Z|d Z}d Z~d ZdefdZdRdd8edededefdZdRdd8edede6e         fdZddZd Zddedede.fdZddZddZdeddfdÄZddĄZddńZddTe6dee         fdƄZdǄ Zdeeef         fdȄZdefdɄZdʄ Zdefd˄Zde.eef         fd̄Zdefd̈́Zde6fd΄ZddτZdddМde6fdфZd҄ ZdS )	HermesCLIz
    Interactive CLI for the Hermes Agent.
    
    Provides a REPL interface with rich formatting, command history,
    and tool execution capabilities.
    NFr   toolsetsr   r   r   r   r   r   resumecheckpointspass_session_idc                    t                      | _        t          | _        ||n t          d                             dd          | _        t          d                             dd          }|du rdnt          |          | _        t          d                             dd	          | _        t          d                             d
d          | _	        t          d                             dd          | _
        t          d                             dd          }t          |                                                                          dk    rdnd| _        ||n
| j        dk    | _        t          d                             dd          | _        t          d                             dd          | _        d| _        d| _        d| _        d| _        i | _        t                              di           }t-          |t.                    r,|                    d          p|                    d          pdn|pd}d}|p|p|| _        | j        |k    rPt-          |t.                    r|                    d          pdnd}d|v sd|v rddlm}  ||          }|r|| _        | o| p||k    | _        || _        || _        |p5t          d                             d          pt=          j        d          pd| _         d| _!        | j         | _"        d| _#        d| _$        g | _%        |p5t          d                             dd          pt=          j        dd          pd| _&        | j&        r9d | j&        v r0|p't=          j        d!          pt=          j        d"          | _'        n/|p't=          j        d"          pt=          j        d!          | _'        ||| _(        nt          d#                             d$          rt          d#         d$         | _(        not                              d$          rt          d$         | _(        nBt=          j        d%          r'tS          t=          j        d%                    | _(        nd&| _(        || _*        |rd|vrd'|vr|tW          t                              d(          pi ,                                          fd)|D             }|r1| j        -                    d*d+.                    |           d,           t                              d-i           }t-          |t^                    rd.|i}|
p|                    d.d          | _0        |                    d/d0          | _1        || _2        t=          j        d1d          p t          d#                             d2d          | _3        t          d#                             d3i           | _4        tk          t          d#                             d4d                    | _6        to          t          d#                             d5d                    | _8        ts          t          d#                             d6d                    | _:        t                              d7i           pi }|                    d8          | _;        |                    d9          | _<        |                    d:          | _=        |                    d;          | _>        |                    d<d          | _?        |                    d=          | _@        t                              d>          pt                              d?          pg }t-          |t.                    r/|                    d          r|                    d          r|gng }|| _A        t                              d@i           pi | _B        d| _C        d| _D        d| _E        g | _F        t          jH                    | _I        d| _J        d| _K        	 ddAlLmM}  |            | _K        n2# t          $ r%}t          P                    dB|           Y d}~nd}~ww xY wd| _Q        |	r|	| _R        d| _J        nF| jI        S                    dC          }t          jU                    jV        ddD         }| dE| | _R        t          dFz  | _X        dG| _Y        d| _E        d| _Z        t          j\                    | _]        t          j\                    | _^        d| __        d| _`        d| _a        d| _b        d| _c        d| _d        d| _e        d| _f        d| _g        d| _h        t          jj                    | _k        d| _l        d| _m        d| _n        d| _o        dG| _p        i | _q        d| _r        d| _s        d| _t        g | _u        d| _v        g | _w        d| _x        t          jj                    | _y        d| _z        d| _{        d| _|        d| _}        d| _~        d| _        t          j                    | _        | j        +                                 d| _        i | _        d| _        dS )Ha  
        Initialize the Hermes CLI.

        Args:
            model: Model to use (default: from env or claude-sonnet)
            toolsets: List of toolsets to enable (default: all)
            provider: Inference provider ("auto", "openrouter", "nous", "openai-codex", "zai", "kimi-coding", "minimax", "minimax-cn")
            api_key: API key (default: from environment)
            base_url: API base URL (default: OpenRouter)
            max_turns: Maximum tool-calling iterations shared with subagents (default: 90)
            verbose: Enable verbose logging
            compact: Use compact display mode
            resume: Session ID to resume (restores conversation history from SQLite)
            pass_session_id: Include the session ID in the agent's system prompt
        Nr   r   Ftool_progressallrP   r   r   bell_on_completer   r   r   queuer   r   inline_diffsTrO   r   rS   r   	localhost	127.0.0.1r   )_auto_detect_local_modelr   HERMES_INFERENCE_PROVIDERr   chat_completionsOPENROUTER_BASE_URLopenrouter.aiOPENROUTER_API_KEYOPENAI_API_KEYr   r   HERMES_MAX_ITERATIONSr   *mcp_serversc                 :    g | ]}t          |          |v|S r  )rQ  )r  t	mcp_namess     rC   r  z&HermesCLI.__init__.<locals>.<listcomp>  s2    ]]]Q2B12E2E]!S\J\J\qJ\J\J\rL   z%[bold red]Warning: Unknown toolsets: , [/]r  r   max_snapshotsr   HERMES_EPHEMERAL_SYSTEM_PROMPTr   r   r   r   r   provider_routingsortonlyignoreorderrequire_parametersdata_collectionfallback_providersfallback_modelr   	SessionDBuM   Failed to initialize SessionDB — session will NOT be indexed for search: %s%Y%m%d_%H%M%S   _z.hermes_history        )rC  console
CLI_CONFIGr  r   r   rX   tool_progress_moder   r  r   rI   rY   r   r   streaming_enabled_inline_diffs_enabled_stream_buf_stream_started_stream_box_opened_reasoning_preview_buf_pending_edit_snapshotsr<   r  r   hermes_cli.runtime_providerr  _model_is_default_explicit_api_key_explicit_base_urlr`   rL  requested_provider_provider_sourcer   api_modeacp_commandacp_argsr   r   r   r  enabled_toolsetsr   r  r  r   r  checkpoints_enabledcheckpoint_max_snapshotsr  r   r   rD   prefill_messagesrK   reasoning_configr[   r   _provider_sort_providers_only_providers_ignore_providers_order_provider_require_params_provider_data_collection_fallback_model_smart_model_routing_active_agent_route_signaturer   _apprd  r   r  session_start_resumed_session_dbhermes_stater  r>   r7   r8   _pending_titlera  strftimer  r  r  r5   _history_file_last_invalidate_agent_runningr  Queue_pending_input_interrupt_queue_should_exit_last_ctrl_c_time_clarify_state_clarify_freetext_clarify_deadline_sudo_state_sudo_deadline_modal_input_snapshot_approval_state_approval_deadline	threadingLock_approval_lock_model_picker_state_secret_state_secret_deadline_spinner_text_tool_start_time_pending_tool_info_last_scrollback_tool_command_running_command_status_attached_images_image_counterpreloaded_skills_startup_skills_line_shown_voice_lock_voice_mode
_voice_tts_voice_recorder_voice_recording_voice_processing_voice_continuousEvent_voice_tts_done_status_bar_visible_background_tasks_background_task_counter)r  r   r  r   r   r   r   r   r   r  r  r  _raw_tp_bim_model_config_config_model_DEFAULT_CONFIG_MODEL	_base_urlr  	_detectedinvalidcp_cfgprfbr  rB   timestamp_str
short_uuidr   s                               @rC   r  zHermesCLI.__init__>  sD
   < yy ")"5ww:i;P;T;TU^`e;f;f Y'++OUCC+2e+;+;%%W(3778H&QQ *9 5 9 9:Le T T(3778H%PP)$(():KHH*-d))//*;*;*A*A*C*Cw*N*NwwT_")"5wwD<SW`<` ",I!6!:!:;!N!N &0	%:%>%>~t%T%T" $"'&(#')$ #w33^hivx|^}^}  Y**955Y9J9J79S9SYWY  ER  EX  VX "DmD/D
:...AKM[_A`A`h**:66<"fhIi'';)+C+CPPPPPP44Y??	 +!*DJ &+ "
G2G!G 	 ")"*  '"&&z22y455 	 	 04/**.#% 4'"&&z2664y.33 	 	 = 	e_=="dbi0D&E&EdScIdIdDLL"dbi0@&A&AdRYOcEdEdDL &DNN $$[11 	 '0=DNN^^K(( 	 '4DNNY.// 	  +B!C!CDDDNNDN !) 	dX--#X2E2E Z^^M::@bFFHHIII]]]](]]]G d""#b499U\K]K]#b#b#bccc r22fd## 	)(F#.#N&**Y2N2N (.

?B(G(G%. I6;; <'"&&;; 	 (044_bII !7w##$;R@@!
 !

 !8w##$6;;!
 !
 7w##NB77
 

 ^^.339r ffVnn!vvf~~!#!1!1 "w(*/CU(K(K%)+0A)B)B& ^^011[Z^^DT5U5U[Y[b$ 	H
++GwG"RB! %/NN3H"$M$M$SQS!-1* )-
	 ;=!%\^^	o......(y{{D 	o 	o 	oNNjlmnnnnnnnn	o .2  	>$DO DMM .77HHM)"1"-J!.====DO *,=='*	
 $#kmm %!!""!&!"%)"#"#'n..#' ! !"$'*(**," %!,.+-*/' %>++ # %!&!&(00  """ $(  ?A()%%%s   "`8 8
a'a""a'      ?min_intervalr-   c                     ddl }|                                }t          | d          r7| j        r2|| j        z
  |k    r&|| _        | j                                         dS dS dS dS )uL   Throttled UI repaint — prevents terminal blinking on slow/SSH connections.r   Nr5  )r  	monotonicrl  r5  r=  
invalidate)r  rv  _timer  s       rC   _invalidatezHermesCLI._invalidateL  s    oo4   	#TY 	#C$:O4OT`3`3`$'D!I  """""	# 	# 	# 	#3`3`rL   percent_usedc                 >    |dS |dk    rdS |dk    rdS |dk    rdS dS )	Nclass:status-bar-dim_   zclass:status-bar-criticalrz  zclass:status-bar-badr   zclass:status-bar-warnzclass:status-bar-goodr  )r  r|  s     rC   _status_bar_context_stylez#HermesCLI._status_bar_context_styleT  sG    ))2.."))2**&&rL   r  rw  c                     t          dt          d|pd                    }t          |dz  |z            }dd|z  dt          d||z
            z  z    dS )Nr   d   [u   █   ░rY  )r~  r  round)r  r|  rw  safe_percentfilleds        rC   _build_context_barzHermesCLI._build_context_bar_  sd    1c#|'8q99::s*e344IEFNus1efn/E/E'EFIIIIrL   c                 Z   t          | dd           }t          |dd           p| j        pd}d|v r|                    d          d         n|}|                    d          r
|d d         }t	          |          dk    r|d d	          d
}t          dt          j                    | j        z
  	                                          }||t          |          dd d dddddddddd}|s|S t          |dd          pd|d<   t          |dd          pd|d<   t          |dd          pd|d<   t          |dd          pd|d<   t          |dd          pd|d<   t          |dd          pd|d<   t          |dd          pd|d<   t          |dd          pd|d<   t          |dd           }|r~t          |dd          pd}t          |dd          pd}||d<   |pd |d<   t          |dd          pd|d<   |r4t          dt          dt          ||z  dz                                |d<   |S )Nr   r   rU  rk  r  z.gguf      r}  r  r   )
model_namemodel_shortdurationcontext_tokenscontext_lengthcontext_percentsession_input_tokenssession_output_tokenssession_cache_read_tokenssession_cache_write_tokenssession_prompt_tokenssession_completion_tokenssession_total_tokenssession_api_callscompressionsr  r  r  r  r  r  r  r  context_compressorlast_prompt_tokensr  r  compression_countr  r  r  )rm  r   r  r  r  r~  r   r  r6  total_secondsr#   r  r  )	r  r   r  r  elapsed_secondssnapshot
compressorr  r  s	            rC   _get_status_bar_snapshotz"HermesCLI._get_status_bar_snapshotd  s   
 gt,,eWd33NtzNY
36*3D3Dj&&s++B//*(( 	+%crc*K{b  ("-222KcHLNNT5G$G#V#V#X#XYY$&/@@"#$%%&)**+%&)*$%!"
 
$  	O+25:PRS+T+T+YXY'(,3E;RTU,V,V,[Z[()07?Z\]0^0^0cbc,-18@\^_1`1`1ede-.,3E;RTU,V,V,[Z[()07?Z\]0^0^0cbc,-+25:PRS+T+T+YXY'((/7JA(N(N(SRS$%U$8$??
 	o$Z1EqIINQN$Z1A1EEJN)7H%&)7)?4H%&'.z;NPQ'R'R'WVWH^$ o.1!Se^VdEdhkDk>l>l5m5m.n.n*+rL   ru  c                 l    	 ddl m}  || pd          S # t          $ r t          | pd          cY S w xY w)aV  Return terminal cell width for status-bar text.

        len() is not enough for prompt_toolkit layout decisions because some
        glyphs can render wider than one Python codepoint. Keeping the status
        bar within the real display width prevents it from wrapping onto a
        second line and leaving behind duplicate rows.
        r   
get_cwidthrO   )prompt_toolkit.utilsr  r>   r  )ru  r  s     rC   _status_bar_display_widthz#HermesCLI._status_bar_display_width  s^    	#777777:djb))) 	# 	# 	#tzr??"""	#s    33	max_widthc                    |dk    rdS 	 ddl m} n# t          $ r d}Y nw xY w|                     |          |k    r|S d}|                     |          }||k    r
|d|         S g }d}|D ]F}|r ||          nt	          |          }	||	z   |z   |k    r n|                    |           ||	z  }Gd                    |                                          |z   S )z.Trim status-bar text to a single terminal row.r   rO   r  Nr}  )r  r  r>   r  r  rd   r   r  )
clsru  r  r  ellipsisellipsis_widthoutrw  rE  ch_widths
             rC   _trim_status_bar_textzHermesCLI._trim_status_bar_text  s-    >>2	7777777 	 	 	JJJ	 ((..);;K66x@@&&JYJ'' 	 	B)3@zz"~~~RHx.09<<JJrNNNXEEwws||""$$x//s      ry  rS   c                     	 ddl m}  |            j                                        j        S # t
          $ r t          j        |           j        cY S w xY w)a  Return the live prompt_toolkit width, falling back to ``shutil``.

        The TUI layout can be narrower than ``shutil.get_terminal_size()`` reports,
        especially on Termux/mobile shells, so prefer prompt_toolkit's width whenever
        an app is active.
        r   get_app)prompt_toolkit.applicationr  r]  get_sizer  r>   rl   r  )rS   r  s     rC   _get_tui_terminal_widthz!HermesCLI._get_tui_terminal_width  sl    	=::::::799#,,..66 	= 	= 	=+G44<<<<	=s   +. #AAc                 :    ||                                  }|dk     S )zBHide low-value chrome on narrow/mobile terminals to preserve rows.N@   )r  r  rw  s     rC   _use_minimal_tui_chromez!HermesCLI._use_minimal_tui_chrome  s"    =0022ErzrL   positionc                 r    |dvrt          d|           |dk    rdS |                     |          rdndS )zCReturn the visible height for the top/bottom input separator rules.>   topbottomzUnknown input rule position: r  r  rw  r   )r~  r  )r  r  rw  s      rC   _tui_input_rule_heightz HermesCLI._tui_input_rule_height  sU    ,,,GXGGHHHu100u0==Dqq1DrL   c                 \    t          | dd          sdS |                     |          rdndS )zIReturn the spacer height shown above the status bar while the agent runs.r>  Fr   r  r  )rm  r  r  s     rC   _agent_spacer_heightzHermesCLI._agent_spacer_height  s<    t-u55 	100u0==Dqq1DrL   c                    t          | dd          sdS |                     |          rdS |p|                                 }|rG|dk    rAddl}t	          | j                  dz   }t          d|                    ||z                      S dS )	zPReturn the visible height for the spinner/status text line above the status bar.rR  rO   r   r  r  Nr  r  )rm  r  r  mathr  rR  r~  ceil)r  rw  r  text_lens       rC   _spinner_widget_heightz HermesCLI._spinner_widget_height  s    t_b11 	1''e'44 	1 75577 	7URZZKKK4-..3Hq$))Hu$455666qrL   c                     |p|                                  }|                     |          }| j        r|rdgS dgS | j        r|rdgS dgS |rdgS | j        rdnd}| j        rd	nd}d
d| | dfgS )z>Return the voice status bar fragments for the interactive TUI.r  )class:voice-status-recordingu	    ● REC )r  u    ● REC  Ctrl+B to stop )class:voice-statusu	    ◉ STT )r  u    ◉ Transcribing... )r  u    🎤 Ctrl+B z	 | TTS onrO   z | Continuousr  u    🎤 Voice modeu     —  Ctrl+B to record )r  r  r`  ra  r^  rb  )r  rw  r   ttsconts        rC   _get_voice_status_fragmentsz%HermesCLI._get_voice_status_fragments  s    75577..U.;;  	S GEFFQRR! 	E =;<<CDD 	=;<<!_4kk""&"8@b%']#']t']']']^__rL   c                    	 |                                  }||                                 }|d         }|| dnd}|d         }|dk     r$d|d          d	| }|                     ||          S |d
k     rKd|d          |g}|                    |           |                     d	                    |          |          S |d         r2t          |d                   }t          |d                   }	|	 d| }
nd}
d|d          |
|g}|                    |           |                     d                    |          |          S # t          $ r  dt          | dd          r| j	        nd cY S w xY w)zCReturn a compact one-line session status string for the TUI footer.Nr  %--r  r  u   ⚕ r      · L   r  r  rk  ctx --    │ r   Hermes)
r  r  r  rd   r   r%   r$   r>   rm  r   )r  rw  r  percentpercent_labelduration_labelru  r   	ctx_totalctx_usedcontext_labels              rC   _build_status_bar_textz HermesCLI._build_status_bar_text  s   	U4466H}446601G-4-@wMMMMdM%j1NrzzKh}5KK>KK11$>>>rzz9 799=I^,,,11&++e2D2DeLLL() )28<L3MNN	5h?O6PQQ#+ 9 9i 9 9 (5H]355}mTELL(((--gll5.A.A5III 	U 	U 	UTgt(D(DR$**(TTTTT	Us    A,E /AE  BE 'E21E2c                 \     j         rt           dd           rg S 	                                  }                                 }|d         }|dk     rdd|d         fdd|fd	g}n|d
         }|| dnd}|dk     r)dd|d         fd                     |          |fdd|fd	g}n|d         r2t          |d                   }t          |d                   }| d| }	nd}	                     |          }
dd|d         fdd|	fd|
                     |          fd|
|fdd|fd	g}t           fd|D                       }||k    r:d	                    d |D                       } 
                    ||          }d|fgS |S # t          $ r dd                                  dfgcY S w xY w)NrO  r  r  )class:status-baru    ⚕ zclass:status-bar-strongr  )r~  r  r~  )r  rA  r  r  r  r  r  r  rk  r  )r~  r  )r~  rA  c              3   H   K   | ]\  }}                     |          V  d S r_   )r  )r  r  ru  r  s      rC   r  z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>c  s5      XXwq$d<<TBBXXXXXXrL   rO   c              3       K   | ]	\  }}|V  
d S r_   r  r  r  ru  s      rC   r  z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>e  s&      $?$?gaT$?$?$?$?$?$?rL   r  rA  )re  rm  r  r  r  r%   r$   r  sumr   r  r>   r  )r  r  rw  r  fragsr  r  r  r  r  	bar_styletotal_width
plain_texttrimmeds   `             rC   _get_status_bar_fragmentsz#HermesCLI._get_status_bar_fragments*  sp   ' 	749NPT+U+U 	I=	P4466H 0022E%j1Nrzz1.0GH4+^<- ##45181D7$2::52H]4KL877@@-P8/@1EE   01 1$:8DT;U$V$V	#=hGW>X#Y#Y+3(A(Ai(A(A(0 $ > >w G GI52H]4KL9/?9"D$;$;G$D$DE5"M29/@1E XXXXRWXXXXXKU""WW$?$?$?$?$???
44ZGG+W566L 	P 	P 	P')MT-H-H-J-J)M)M)MNOOOO	Ps   E#F F %F+*F+resolved_providerc           	         | j         pd                                }d}	 ddlm}m} ||vrJ |||          }|r<||k    r6| j        s$| j                            d| d| d| d           || _         |}d	}n# t          $ r Y nw xY w|d
k    r	 ddl	m
}m}  ||| j                  }	|	r9|	|k    r3| j        s!| j                            d| d|	 d           |	| _         |	}d	} ||| j                  }
|
| j        k    r	|
| _        d	}n# t          $ r Y nw xY w|S |dv r	 ddl	m}m}  |||          }	|	r<|	|k    r6| j        s$| j                            d| d|	 d| d           |	| _         |	}d	} |||          }
|
| j        k    r	|
| _        d	}n# t          $ r Y nw xY w|S |dk    r|S d|v rO|                    dd          d         }| j        s!| j                            d| d| d           || _         |}d	}| j        rMd}	 ddlm}  || j        r| j        nd          }|r|d         }n# t          $ r Y nw xY w||k    r	|| _         d	}|S )z2Normalize provider-specific model IDs and routing.rO   Fr   )_AGGREGATOR_PROVIDERSnormalize_model_for_provideru"   [yellow]⚠️  Normalized model 'z' to 'z' for z.[/]Tcopilot)copilot_model_api_modenormalize_copilot_model_id)r   u*   [yellow]⚠️  Normalized Copilot model 'z'.[/]>   opencode-goopencode-zen)normalize_opencode_model_idopencode_model_api_modeu/   [yellow]⚠️  Stripped provider prefix from 'z
'; using 'zopenai-codexrk  r  z' for OpenAI Codex.[/]zgpt-5.3-codex)get_codex_model_idsN)access_token)r   rI   hermes_cli.model_normalizer  r  r  r  r  r>   hermes_cli.modelsr  r  r   r$  r  r  r  hermes_cli.codex_modelsr  )r  r  current_modelchangedr  r  normalized_modelr  r  	canonicalresolved_moder  r  slugr  r  	availables                    rC   _normalize_model_for_providerz'HermesCLI._normalize_model_for_providerl  sR   )r0022	       
 !(===#?#?O`#a#a # #(8M(I(I1 ** F  F  FVf  F  Fn  F  F  F   "2DJ$4M"G 	 	 	D	 	))````````66}dl[[[	 #m!;!;1 **nnn^gnnn   "+DJ$-M"G 6 6}dl [ [ [ DM11$1DM"G   N ???bbbbbbbb778I=YY	 #m!;!;1 ** Pm  P  Pgp  P  P  yJ  P  P  P   "+DJ$-M"G 7 78I= Y Y DM11$1DM"G   N..N - &&sA..q1D) "";m ; ;"; ; ;   DJ MG ! 	,N	GGGGGG//15!G4  	  2%.q\N    ..+
sJ   AA6 6
BBA;D	 	
DD A2F 
F F 
*H5 5
IIc                 ~    |s|                      d           |pd| _        d| _        |                                  dS )z@Called by agent when thinking starts/stops. Updates TUI spinner.Tr  rO   r  N)_flush_reasoning_previewrR  rS  r{  )r  ru  s     rC   _on_thinkingzHermesCLI._on_thinking  sM     	6)))555!ZR #rL   c                 Z    | j         r| j        r| j        S | j        r| j         s| j        S dS )zBReturn the active reasoning display callback for the current mode.N)r   r  _stream_reasoning_deltar   _on_reasoningr  s    rC   _current_reasoning_callbackz%HermesCLI._current_reasoning_callback  sB     	04#9 	0//< 	& 3 	&%%trL   reasoning_textc                    ddl }ddl}|                                }|sdS 	 t          j                    j        }n# t          $ r d}Y nw xY wd}t          d|t          |          z
  dz
            }g }|	                    d|
                    dd	                    }	|	D ]Z}
d
                    d |
                                D                       }|r%|                     |j        ||                     [d	                    |          }|sdS | j        r#t!          dt"           d| t$                      dS |                                }t          |          dk    r7d	                    |dd                   }|dt          |          dz
   dz  }n|}t!          dt"           d| t$                      dS )zARender a buffered reasoning preview as a single [thinking] block.r   Nrz    [thinking] r  r@  z\n\s*\n+
r  rA  c              3   f   K   | ],}|                                 |                                 V  -d S r_   r  r  r  s     rC   r  z4HermesCLI._emit_reasoning_preview.<locals>.<genexpr>  s<      __RVR\R\R^R^_tzz||______rL   r    z[thinking] rs  
  ... ( more lines))retextwraprI   rl   r  r  r>   r~  r  r  rB  r   r  rd   fillr   r*  _DIM_RST)r  r	  r  r  preview_text
term_widthr  
wrap_width
paragraphsraw_paragraphs	paragraphr   linespreviews                 rC   _emit_reasoning_previewz!HermesCLI._emit_reasoning_preview  s   			%++-- 	F	133;JJ 	 	 	JJJ	 Z#f++59::

+|/C/CFD/Q/QRR' 	L 	LIhh__	8L8L8N8N_____G L!!-(-z"J"J"JKKKyy,, 	F< 	>>>,>>>???F''))u::>>iibqb	**G?3u::>????GG"G5T55g5t5566666s   ; A
	A
r  r  c          	      
   t          | dd          }|sdS 	 t          j                    j        }n# t          $ r d}Y nw xY wt          d|t          d          z
  dz
            }d}|r|}d}n^|                    d          }t          d	|d
z            }|dk    r||k    si|                    d          sT|                    d          s?|                    d          s*|                    d          s|                    d          r|d|dz            }||dz   d         }nt          |          |k    rt          d|dz            }t          t          |          t          ||d
z  z   |dz                       }	d}
dD ]'}t          |
|                    |||	                    }
(|
dk    r|d|
dz            }||
dz   d         }|r|
                                n|| _        |r|                     |           dS dS )zFlush buffered reasoning text at natural boundaries.

        Some providers stream reasoning in tiny word or punctuation chunks.
        Buffer them here so the preview path does not print one `[thinking]`
        line per token.
        r  rO   Nrz  (   r     r  r  r  r  

z.
z!
z?
z:
r  r  r@  r  )rA  	r   !r\  r  r  :)rm  rl   r  r  r>   r~  r  rfindr  r  lstripr  r  )r  r  bufr  target_width
flush_text
line_breakmin_newline_flushsearch_start
search_endcutboundarys               rC   r  z"HermesCLI._flush_reasoning_preview	  sf    d4b99 	F	133;JJ 	 	 	JJJ	2zC,@,@@1DEE
 	)JCC4J #B(9 : :R///<<'' 0<<&& 0 <<&& 0 <<&&	 0
 <<&& 0 !!1:>!12
*q.**+S\))"2|q'899 S3||q?P/QS_bcSc+d+dee
 I R RHc399X|Z#P#PQQCC"99!$YsQwYJcAgii.C6@&Icjjlllc# 	5((44444	5 	5s   0 ??c                    |sdS d| _         t          | dd          rdS t          | dd          snd| _        t          j                    j        }d}|dz
  t          |          z
  }t          dt           d	| d
t          |dz
  d          z   dt                      t          | dd          |z   | _        d| j        v rK| j                            dd          \  }| _        t          t           | t                      d| j        v Kt          | j                  dk    r-t          t           | j         t                      d| _        dS dS )u  Stream reasoning/thinking tokens into a dim box above the response.

        Opens a dim reasoning box on first token, streams line-by-line.
        The box is closed automatically when content tokens start arriving
        (via _stream_delta → _emit_stream_text).

        Once the response box is open, suppress any further reasoning
        rendering — a late thinking block (e.g. after an interrupt) would
        otherwise draw a reasoning box inside the response box.
        NTr  F_reasoning_box_opened Reasoning r@  r     ┌─   ─r  r      ┐_reasoning_bufrO   rz  )_reasoning_shown_this_turnrm  r3  rl   r  r  r  r*  r  r~  r  r8  r  )r  ru  r  r_labelr_fillr  s         rC   r  z!HermesCLI._stream_reasoning_delta<	  s     	F*.'4-u55 	F t4e<< 	U)-D&(**2A#GUS\\)FSSSWSec&1*a6H6H.HSSTSSTTT%d,<bAADH d)))(,(;(A(A$(J(J%D$%t)T)4))*** d))) t"##b((t8T08$88999"$D )(rL   c                    t          | dd          rt          | dd          }|r&t          t           | t                      d| _        t          j                    j        }t          t           dd|dz
  z   dt                      d| _        t          | d	d          }|r d| _	        | 
                    |           d
S d
S d
S )z*Close the live reasoning box if it's open.r3  Fr8  rO      └r6  r@     ┘_deferred_contentN)rm  r*  r  r  r8  rl   r  r  r3  r?  _emit_stream_text)r  r)  r  deferreds       rC   _close_reasoning_boxzHermesCLI._close_reasoning_box`	  s    40%88 	1$ 0"55C )4,,d,,---&(#(**2At::Q::D::;;;).D& t%8"==H 1)+&&&x00000	1 	11 1rL   c                 0   |*|                                   |                                  dS |sdS d| _        d}d}t          | dd          |z   | _        t          | d          sd| _        t          | dd	          s|D ]0}d
}	 | j                            ||          }|dk    rn| j        d|         }|d
k    rt          | dd          }nh|                    d          }	|	dk    r*t          | dd          o|	                                dk    }n#||	dz   d         	                                dk    }|r]|r/| 
                    |           |                    d          | _        d| _        | j        |t          |          z   d         | _        n|dz   }t          | dd	          r n2t          | dd	          s| j        }
|D ]V}t          dt          |                    D ]6}| j                            |d|                   r| j        d|          }
 n7W|
rP| 
                    |
           |
                    d          | _        | j        t          |
          d         | _        dS t          | dd	          r|D ]}| j                            |          }|dk    rtd	| _        | j        r&| j        d|         }|r|                     |           | j        |t          |          z   d         }d| _        |r|                     |            dS t%          d |D                       }t          | j                  |k    rA| j        r%| j        d|          }|                     |           | j        | d         | _        dS dS )a  Line-buffered streaming callback for real-time token rendering.

        Receives text deltas from the agent as tokens arrive. Buffers
        partial lines and emits complete lines via _cprint to work
        reliably with prompt_toolkit's patch_stdout.

        Reasoning/thinking blocks (<REASONING_SCRATCHPAD>, <think>, etc.)
        are suppressed during streaming since they'd display raw XML tags.
        The agent strips them from the final response anyway.

        A ``None`` value signals an intermediate turn boundary (tools are
        about to execute).  Flushes any open boxes and resets state so
        tool feed lines render cleanly between turns.
        NT)z<REASONING_SCRATCHPAD>z<think>z<reasoning>z
<THINKING>z
<thinking>z	<thought>)z</REASONING_SCRATCHPAD>z</think>z</reasoning>z</THINKING>z</thinking>z
</thought>_stream_prefiltrO   _stream_last_was_newline_in_reasoning_blockFr   r  r  r  c              3   4   K   | ]}t          |          V  d S r_   r  r  r  s     rC   r  z*HermesCLI._stream_delta.<locals>.<genexpr>	  s(      ::c!ff::::::rL   )_flush_stream_reset_stream_stater  rm  rD  rl  rE  findr'  rI   r@  r  rF  r  r  r   r  _stream_deltar~  )r  ru  
_OPEN_TAGS_CLOSE_TAGStagr.  idx	precedingis_block_boundarylast_nlsafer  r  aftermax_tag_lensafe_reasonings                   rC   rM  zHermesCLI._stream_deltar	  s[    <   $$&&&F 	F# s
y  't->CCdJ t788 	1,0D)t2E:: 7	! ' ' #+.33CFFCbyy $ 4TcT :Iaxx -4D:TVZ,[,[)) #,//$"7"7"b==
 !(.H$ O O !<$-OO$5$5$; .- 1:'A+,,0G0M0M0O0OSU0U-( $ U 229===<E<N<Nt<T<TD9370/3/CC#c((NOO/T,#&7LG#+H 4!6>> E 4!6>> +% " "C"1c#hh// " "/88RaRAA "#'#7!#<D!E"  L**400048MM$4G4GD1+/+?D		

+KD(
 4.66 	"  *//44"99/4D, * @ $ 4TcT :  @ 88??? 0s3xxAE+-D(  2**5111FF $ ::k:::::K4'((;66& A%)%9-K<-%HN00@@@'+';[LMM'J$F9	 	rL   c                 X   |sdS | j         r,t          | dd          rt          | dd          |z   | _        dS |                                  | j        sP|                    d          }|sdS d| _        	 dd	lm}  |            }|                    d
d          }|	                    dd          }n# t          $ r d}d}Y nw xY w	 t          |dd         d          }t          |dd         d          }t          |dd         d          }d| d| d| d| _        n# t          t          f$ r
 d| _        Y nw xY wt          j                    j        }	|	dz
  t%          |          z
  }
t'          dt(           d| dt+          |
dz
  d          z   dt,                      | xj        |z  c_        t          | dd          }d| j        v r\| j                            dd          \  }| _        t'          |rt2           | | t,           n
t2           |            d| j        v ZdS dS )z,Emit filtered text to the streaming display.Nr3  Fr?  rO   r  Tr   r  response_label
   ⚕ Hermesbanner_text#FFF8DCr  r  r  rs  r  z[38;2;r  r  r@     ╭─r6     ╮_stream_text_ansi)r   rm  r?  rB  r  r(  r	  r  r  r
  r>   r  r`  r~  r  rl   r  r  r  r*  _ACCENTr~  r  r  r  _STREAM_PAD)r  ru  r  r  label	_text_hex_r_g_br  r  _tcr  s                rC   r@  zHermesCLI._emit_stream_text	  s    	F
  	741H%#P#P 	%,T3F%K%Kd%RD"F 	!!### & 	T;;t$$D &*D#&BBBBBB'))**+;\JJ!OOM9EE		 & & &$%			&
,1Q3,,1Q3,,1Q3,,)Eb)E)E2)E)E)E)E)E&&
+ , , ,)+&&&,(**2Aq53u::%DRRRRus4!8Q7G7G/GRRDRRSSSD  d/44d&&&%)%5%;%;D!%D%D"D$"X{5C55t555[BXRVBXBXYYY d&&&&&&&s%   5<B2 2CCAD! !D<;D<c                     t          | dd          r9t          | dd          r(d| _        |                     | j                   d| _        |                                  | j        rPt          | dd          }t          |rt           | | j         t           nt           | j                    d| _        | j	        rAt          j                    j        }t          t           dd|dz
  z   d	t                      d
S d
S )zIEmit any remaining partial line from the stream buffer and close the box.rF  FrD  rO   r`     ╰r6  r@     ╯N)rm  rF  r@  rD  rB  r  r*  rb  r  r  rl   r  r  ra  )r  rh  r  s      rC   rJ  zHermesCLI._flush_stream1
  s(   
 4.66 	&74IZ\^;_;_ 	&',D$""4#7888#%D  	!!### 	"$ 3R88CSp{ACA)9A4AAAQ\Np^b^nNpNpqqq!D " 	?(**2Aw==5AE?==t==>>>>>	? 	?rL   c                     d| _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        dS )z3Reset streaming state before each agent invocation.rO   FTN)r  r  r  r`  rD  rF  rE  r3  r8  r  r?  r  s    rC   rK  zHermesCLI._reset_stream_stateH
  s`    $"'!#!#( (,%%*" &(#!#rL   rV  c                 v   |                                                                 }|                    d          rdS |                    d          rdS |                    d          rdS |                    d          rdS |                    d	          rd
S |dk    rdS |                    d          rdS dS )z>Return a user-facing status message for slower slash commands.z/skills searchzSearching skills...z/skills browsezLoading skills...z/skills inspectzInspecting skill...z/skills installzInstalling skill...z/skillszProcessing skills command...z/reload-mcpzReloading MCP servers...z/browserzConfiguring browser...Processing command...)rY   rI   r  )r  rV  	cmd_lowers      rC   _slow_command_statuszHermesCLI._slow_command_statusV
  s    MMOO))++	 011 	)(( 011 	'&& 122 	)(( 122 	)((	** 	211%%--
++ 	,++&&rL   c                     ddl }t          |                                dz            t          t                    z  }t          |         S )z9Return the current spinner frame for slow slash commands.r   Nr  )r  r  rx  r  _COMMAND_SPINNER_FRAMES)r  rz  	frame_idxs      rC   _command_spinner_framez HermesCLI._command_spinner_framei
  sC    ))B.//#6M2N2NN	&y11rL   r  c              #     K   d| _         || _        |                     d           	 t          d|            dV  d| _         d| _        |                     d           dS # d| _         d| _        |                     d           w xY w)zDExpose a temporary busy state in the TUI while a slash command runs.Tr  rv  u   ⏳ NFrO   )rV  rW  r{  r  )r  r  s     rC   _busy_commandzHermesCLI._busy_commandp
  s       !%%c***	////"""EEE$)D!#%D #..... %*D!#%D #....s   A$ $&B
c                    ddl m}m} 	  || j        | j        | j                  }nH# t          $ r;} ||          }t                                          d| d           Y d}~dS d}~ww xY w|	                    d          }|	                    d	          }|	                    d
d          }|	                    d| j
                  }	|	                    d          }
t          |	                    d          pg           }|	                    d          }t          |t                    r|sc|	                    dd          }t          |t                    o|od|v}|rd}t                              d||           nt          d           dS t          |t                    r|st          d           dS || j        k    p
|| j        k    }|| j        k    p |	| j
        k    p|
| j        k    p
|| j        k    }|| _        |	| _
        |
| _        || _        || _        |	                    d          | _        || _        || _        |	                    d          }|rt          |t                    r|| _        | j        sJ|rH	 ddlm}  ||          }|r#|| _        t                              d||           n# t          $ r Y nw xY w|                     |          }|s|s|r| j        d| _        d| _        dS )a  
        Ensure runtime credentials are resolved before agent use.
        Re-resolves provider credentials so key rotation and token refresh
        are picked up without restarting the CLI.
        Returns True if credentials are ready, False on auth failure.
        r   )resolve_runtime_providerformat_runtime_provider_error)	requestedexplicit_api_keyexplicit_base_urlz
[bold red]r  NFr   r   r   
openrouterr$  rV  r  credential_poolsourcerO   r  zno-key-requireduh   No API key for custom endpoint %s (source=%s), using placeholder — local servers typically ignore authua   
⚠️  Provider resolver returned an empty API key. Set OPENROUTER_API_KEY or run: hermes setupuf   
⚠️  Provider resolver returned an empty base URL. Check your provider config or run: hermes setupr   )get_default_model_for_provideru8   No model configured — defaulting to %s for provider %sT)r  ry  rz  r"  r   r!  r>   r  r  r   r$  r=   r<   rX   r7   r  r   r   r   r%  r&  _credential_poolr#  r   r  r  r  r   r   r4  )r  ry  rz  runtimeexcrX  r   r   r  resolved_api_moderesolved_acp_commandresolved_acp_argsresolved_credential_pool_source_has_custom_basecredentials_changedrouting_changedruntime_modelr  _defaultmodel_changeds                        rC   _ensure_runtime_credentialsz%HermesCLI._ensure_runtime_credentials~
  s   	
 	
 	
 	
 	
 	
 	
 	

		..1!%!7"&"9  GG
  	 	 	33C88GMM 9W 9 9 9:::55555	
 ++i((;;z**#KK
LAA#KK
DMBB&{{955 V!4!4!:;;#*;;/@#A#A '3'' 	w 	
 kk(B//G)(C88iXi/aiJi 
+Pg     D E E Eu(C(( 	 	 D E E E5%5RT]9R. 2 DM12#t'772 !DM1	 	 *)/) 8 'H 5 5   G,, 	'Zs;; 	'&DJ
 z 	/ 	
LLLLLL99:KLL !)DJKKR "3      
 ::;LMM   	6? 	6m 	6I_DJ15D.ts&   ( 
A-0A((A-6J< <
K	K	user_messagec                 x   ddl m} ddlm}  ||| j        | j        | j        | j        | j        | j	        | j
        t          | j        pg           t          | dd          d          }t          | dd          }|sd|d<   |S 	  ||                    d	                    }n# t          $ r d}Y nw xY w||d<   |S )
z7Resolve model/runtime overrides for a single user turn.r   )resolve_turn_route)resolve_fast_mode_overridesr  N)r   r   r   r   r$  rV  r  r  r   request_overridesr   )agent.smart_model_routingr  r  r  r3  r   r   r   r   r$  r%  r=   r&  rm  r   r>   )r  r  r  r  router   	overridess          rC   _resolve_turn_agent_configz$HermesCLI._resolve_turn_agent_config
  s   @@@@@@AAAAAA""%< M M M+T]0b11#*41CT#J#J	 	
 
 t^T:: 	)-E%&L	33EIIg4F4FGGII 	 	 	III	%.!"s   B# #B21B2model_overrideruntime_overrideroute_labelr  r  r  r  r  c                   | j         dS |                                 sdS | j        I	 ddlm}  |            | _        n2# t
          $ r%}t                              d|           Y d}~nd}~ww xY w| j        r| j        r| j	        s| j        
                    | j                  }|s>t          d| j         t                      t          t           dt                      dS | j                            | j                  }|rd	 |D             }|| _	        t!          d
 |D                       }	d}
|                    d          rd|d          d}
t%                                          dt)                       dt+          | j                   dt)                       dt+          |
           d|	 d|	dk    rdnd dt!          |           d           nFt%                                          dt)                       dt+          | j                   d           	 | j        j                            d| j        f           | j        j                                         n# t
          $ r Y nw xY w	 |pE| j        | j        | j        | j        | j        t=          | j        pg           tA          | dd          d}|p| j!        }tE          dGi d|d|                    d          d |                    d           d!|                    d!          d"|                    d"          d#|                    d$          d%|                    d&          d'|                    d'          d(| j#        d)| j$        d*| j%        d+| j%         d,| j&        r| j&        ndd-| j'        pdd.| j(        d/| j)        d0|d1| j*        d2| j+        d3| j,        d4| j-        d5| j.        d6| j/        d7| j        d8d9d:| j        d;| j0        d<| 1                                d=| j2        d>| j3        d?| j4        d@| j5        dA| j6        dB| j7        dC| j8        r| j9        nddD| j8        r| j:        nddE| j;        r| j<        nddF| j;        r| j=        nd| _         | j         a>t          | j         _?        ||                    d!          |                    d           |                    d"          |                    d$          t          |                    d&          pdG          f| _A        | jB        r| j        r|	 | j        C                    | j        | jB                   t          dH| jB                    d| _B        n7# t          t
          f$ r#}t          dI|            d| _B        Y d}~nd}~ww xY wdS # t
          $ r0}t%                                          dJ| dK           Y d}~dS d}~ww xY w)Lz
        Initialize the agent on first use.
        When resuming a session, restores conversation history from SQLite.
        
        Returns:
            bool: True if successful, False otherwise
        NTFr   r  uF   SQLite session store not available — session will NOT be indexed: %sz[1;31mSession not found: z@Use a session ID from a previous CLI run (hermes sessions list).c                 D    g | ]}|                     d           dk    |S rolesession_metar`  r  r  s     rC   r  z)HermesCLI._init_agent.<locals>.<listcomp>*  s,    SSS!155==N3R3RA3R3R3RrL   c                 D    g | ]}|                     d           dk    |S r  userr`  r  s     rC   r  z)HermesCLI._init_agent.<locals>.<listcomp>,  s,     P P Pqf8O8O8O8O8OrL   rO   title "r=  [bold u   ]↻ Resumed session[/] [bold]z	[/][bold rY  z[/] ( user messager  sr  z total messages)	]Session . found but has no messages. Starting fresh.[/]CUPDATE sessions SET ended_at = NULL, end_reason = NULL WHERE id = ?r  )r   r   r   r$  rV  r  r  r   r   r   r   r$  r%  rV  r&  r  r  r   r'  verbose_logging
quiet_modeephemeral_system_promptr*  r+  r   r  providers_allowedproviders_ignoredproviders_orderprovider_sortprovider_require_parametersprovider_data_collectionra  rb  r;  
session_dbclarify_callbackreasoning_callbackr  thinking_callbackr(  r)  r  tool_progress_callbacktool_start_callbacktool_complete_callbackstream_delta_callbacktool_gen_callbackr  z  Session title applied: z!  Could not apply pending title: z&[bold red]Failed to initialize agent: r  )Er   r  r8  r9  r  r>   r7   r8   r7  rd  get_sessionra  r*  r  r  get_messages_as_conversationr  r   r  r  r!  _escape_connexecutecommitr   r   r   r$  r%  r=   r&  rm  r   rI  r   r'  r   r   r*  r+  r   r-  r.  r/  r,  r0  r1  _clarify_callbackr  r2  r  r(  r)  r  _on_tool_progressr  _on_tool_start_on_tool_completer  rM  _on_tool_gen_startrk  	_print_fnr  r4  r:  set_session_titler~  )r  r  r  r  r  r  rB   r  restored	msg_count
title_partr  effective_models                rC   _init_agentzHermesCLI._init_agent  s    :!4//11 	5 #l222222#,9;;   l l lgijkkkkkkkkl =  	T-  	d6O  	+77HHL OOOOPPP4ggaegghhhu'DDT_UUH SSxSSS,4) P PH P P PQQ	
##G,, A!@|G'<!@!@!@J##q[]] q q$T_55q q(]]q q-4Z-@-@q q "q q 8AA~~2q q RUU]Q^Q^q q q    ##}[]]}}WT_5M5M}}}   &..Y_&    &--////   N	& < M M M+T]0b11#*41CT#J#J+ +G -:
O  ( ( (%o(I...( !Z000( !Z000	(
 !Z000( $KK	222( !V,,,( !(,= > > >(  $~~( "&!6!6( !%(  $|++( ?C>P(Z(:(:VZ( "&!6!>$( "&!6!6(  "..!(" #4"3#($ #'"6"6%(& #'"8"8'(( !% 5 5)(* #11+(, -1,I,I-(. *.)G)G/(0  ??1(2 3(4  ++5(6 "&!7!77(8 $(#C#C#E#E#E9(<  $33=(> #'"3"3?(@ %)$<$<A(B *.)F)FC(D !% 4 4E(F (,'='=G(H <@;U$_D$7$7[_I(J BFA['et'='=aeK(L =A<R&\d&8&8X\M(N >B=S"]$"9"9Y]O(DJV !%
 $+DJ J''J''J''I&&gkk&))/R002D. " /t'7 //$66tH[\\\M8KMMNNN*.D''"I. / / /CCCDDD*.D''''''/ 4 	 	 	MM O O O OPPP55555	sl   > 
A-A((A-"AI' '
I43I48KV7 :AU> =V7 >V2V-(V7 -V22V7 7
W1%W,,W1c           	      l   | j                                          d}t          | d          r-| j        r&t          | j        d          r| j        j        j        }t          j                    j        }| j	        p|dk     }|r;| j         
                    t                                 |                                  nft          | j        d          }t          j        dt          j                              }t%          | j         | j        ||| j        | j        |           |                                  |r|d	k    r| j         
                                 | j         
                    d
|dd           | j         
                    d           t-          | dd          pd}d|v sd|                                v r| j         
                    d           n9d|v r| j         
                    d           n| j         
                    d           ddlm} t-          | dd          pd} ||          rg| j         
                                 | j         
                    d           | j         
                    d           | j         
                    d           | j         
                                 dS )z0Display the welcome banner in Claude Code style.Nr   r  rz  Tr'  r  r   r  r   r   toolsr'  ra  r  i    u'   [yellow]⚠️  Context length is only r  u?    tokens — this is likely too low for agent use with tools.[/]u[   [dim]   Hermes needs 16k–32k minimum. Tool schemas + system prompt alone use ~4k–8k.[/]r   rO   11434ollamaz?[dim]   Ollama fix: OLLAMA_CONTEXT_LENGTH=32768 ollama serve[/]1234uO   [dim]   LM Studio fix: Set context length in model settings → reload model[/]zb[dim]   Fix: Set model.context_length in config.yaml, or increase your server's context setting[/]r   )is_nous_hermes_non_agenticr   uv   [bold yellow]⚠  Nous Research Hermes 3 & 4 models are NOT agentic and are not designed for use with Hermes Agent.[/]z[dim]   They lack tool-calling capabilities required for agent workflows. Consider using an agentic model (Claude, GPT, Gemini, DeepSeek, etc.).[/]z6[dim]   Switch with: /model sonnet  or  /model gpt5[/])r  clearrl  r   r  r  rl   r  r  r   r  r  _show_statusrJ  r'  r`   rL  r  rL  r   ra   _show_tool_availability_warningsrm  rY   hermes_cli.model_switchr  )	r  ctx_lenr  use_compactr  r   r   r  r  s	            rC   show_bannerzHermesCLI.show_banner  s&    4!! 	Cdj 	CWTZI]5^5^ 	Cj3BG -//7
l5j2o 	L466777 )$:O\`aaaE )NBIKK88C !j!%!6?&    	--///  	w$L   LG'Q G G G   Lm   tZ44:H(""h(..2B2B&B&B""U    8##""e    ""x  
 	GFFFFFT7B//52
%%j11 	L   L9   L\   LH   	rL   c                    | j         r| j        sdS | j                            | j                  }|s?| j                            d| j         d           | j                            d           dS | j                            | j                  }|rd |D             }|| _        t          d |D                       }d}|	                    d          rd	|d          d
}t                      }| j                            d| d| j         d| d| d|dk    rdnd dt          |           d           n6t                      }| j                            d| d| j         d           dS 	 | j        j                            d| j        f           | j        j                                         n# t          $ r Y nw xY wdS )a  Load a resumed session's history from the DB early (before first chat).

        Called from run() so the conversation history is available for display
        before the user sends their first message.  Sets
        ``self.conversation_history`` and prints the one-liner status.  Returns
        True if history was loaded, False otherwise.

        The corresponding block in ``_init_agent()`` checks whether history is
        already populated and skips the DB round-trip.
        Fz[bold red]Session not found: r  zH[dim]Use a session ID from a previous CLI run (hermes sessions list).[/]c                 D    g | ]}|                     d           dk    |S r  r`  r  s     rC   r  z6HermesCLI._preload_resumed_session.<locals>.<listcomp>  s,    OOOaquuV}}/N/N/N/N/NrL   c                 D    g | ]}|                     d           dk    |S r  r`  r  s     rC   r  z6HermesCLI._preload_resumed_session.<locals>.<listcomp>  s,    LLL1AEE&MMV4K4KQ4K4K4KrL   rO   r  r  r=  r  u   ]↻ Resumed session [bold]z[/bold] (r  r  r  r  z total messages)[/]r  r  r  T)r7  r8  r  ra  r  r  r  rd  r  r   r!  r  r  r  r>   )r  r  r  r  r  accent_colors         rC   _preload_resumed_sessionz"HermesCLI._preload_resumed_session  sn    } 	D$4 	5'33DODD 	LDDDD   L-   5#@@QQ 	OO8OOOH(0D%LLLLLMMIJ(( ;:,w"7:::
&==LL6L 6 6T_ 6 66 66 63<>>CCr6 6 x==6 6 6    '==LL0L 0 04? 0 0 0   5	"**"  
 "))++++ 	 	 	D	 ts   .AF3 3
G ?G c                 b   | j         sdS | j        dk    rdS d}d}d}d}dt          dt          fd	}g }d}d}| j         D ]l}	|	                    d
d          }
|	                    d          }|	                    d          pg }|
dk    rL|
dk    rS|
dk    r|dnt          |          }t	          |t
                    rg }|D ]}t	          |t                    rC|                    d          dk    r*|                    |                    dd                     Zt	          |t                    r.|                    d          dk    r|                    d           d                    |          }t          |          |k    r|d|         dz   }|                    d|f           r|
dk    r|dnt          |          } ||          }g }g }|r|                    |           |
                                }t          |          |k    r d                    |d|                   dz   }t          |          |k    r|d|         dz   }|                    |           |rt          |          }g }|D ]^}|                    di           }t	          |t                    r|                    dd          nd}||vr|                    |           _d                    |dd                   }t          |          dk    r|dz  }|dk    rd nd!}d"| d#| d$| d%}|                    |           |                    |           |s|                    dd                    |          f           t          |          dz
  }d                    |          }n|sdS d&}t          |          |d'z  k    rt          |          |d'z  z
  }||d         }|+|r)||z
  }d&|cxk    rt          |          k     r
n nd(|f||<   d&d)lm} d&d*lm} 	 d&d+lm}  |            }|                    d,d-          } |                    d.d/          }!|                    d0d1          }"|                    d2d3          }#n# t$          $ r d-} d/}!d1}"d3}#Y nw xY w |            }|r|                    d4| d5d67           t'          |          D ]\  }$\  }
}|
dk    rw|                    d8d9|! 7           |
                                }%|                    |%d&         dz   d:7           |%dd         D ]}&|                    d;|& dd:7           n|
d(k    rw|                    d<d=|# 7           |
                                }%|                    |%d&         dz   d7           |%dd         D ]}&|                    d>|& dd7           nv|                    d<d9|# 7           |
                                }%|                    |%d&         dz   d:7           |%dd         D ]}&|                    d>|& dd:7           |$t          |          dz
  k     r|                    d            ||d?|! d@dA|" dB| C          }'| j                            |'           dS )DaP  Render a compact recap of previous conversation messages.

        Uses Rich markup with dim/muted styling so the recap is visually
        distinct from the active conversation.  Caps the display at the
        last ``MAX_DISPLAY_EXCHANGES`` user/assistant exchanges and shows
        an indicator for earlier hidden messages.
        Nminimalr  r      r  ru  r-   c                     ddl }|                    dd| |j                  }|                    dd||j                  }|                                S )zRemove <REASONING_SCRATCHPAD>...</REASONING_SCRATCHPAD> blocks
            from displayed text (reasoning model internal thoughts).r   Nz3<REASONING_SCRATCHPAD>.*?</REASONING_SCRATCHPAD>\s*rO   flagsz<REASONING_SCRATCHPAD>.*$)r  subDOTALLrI   )ru  r  cleaneds      rC   _strip_reasoningz<HermesCLI._display_resumed_history.<locals>._strip_reasoning8  sg     IIIffFD	   G
 ff,G29   G ==??"rL   r  rO   content
tool_callsr\   toolr  rS  	image_urlz[image]rA  r}  	assistantr  z ...functionrn   rU  r  r"  z, ...r  callcallsr   tool : rY  r   r@  assistant_lastrE  rG  r  r\  r]  session_labelz#DAA520session_borderz#8B8682ui_okz#8FBC8Fz  ... z earlier messages ...

z
dim italic)styleu     ● You: z	dim bold dimz	         u     ◆ Hermes: zbold z            [dim z]Previous Conversation[/]zdim )r   r  )r  border_stylepaddingr   )rd  r   rX   r   r<   r=   r  rd   r   r  r  
rich.panelrF  	rich.textrH  r	  r  r
  r>   	enumerater  r  )(r  MAX_DISPLAY_EXCHANGESMAX_USER_LENMAX_ASST_LENMAX_ASST_LINESr  entries_last_asst_idx_last_asst_fullmsgr  r  r  ru  r   r  
full_partsr  tc_countrj   tcfnrn   	names_strnoun
tc_summaryskippedadj_idxrF  rH  r  r  _history_text_c_session_label_c_session_border_c_assistant_label_cr  	msg_linesmlpanels(                                           rC   _display_resumed_historyz"HermesCLI._display_resumed_history$  s)    ( 	F )++F "	#3 	#3 	# 	# 	# 	#  , ;	7 ;	7C7762&&Dggi((G..4"Jxv~~v~~$_rr#g,,gt,, +E ' 4 4%dD11 4dhhv6F6F&6P6P!LL&")=)=>>>>'d33 48H8HK8W8W!LL33388E??Dt99|++.6D~....$$$_rr#g,,''--
 '%%d+++ OO--E5zzN22#yy)?@@6I4yy<//#M\M2U:LL&&& 2":HE( / /VVJ33<Fr4<P<P_rvvfi888V_u,,!LL... $		%) 4 4I5zzA~~!W,	%-]]66D!IX!I!IT!I!IY!I!I!IJLL,,,%%j111 SXXe__=>>>!$W!1"%((:"6"6 	F w<</!333'll%:Q%>>Gghh'G %/%$w.GG****c'll*****$4o#F  	%$$$$$""""""	+>>>>>>#O%%E#oomYGGO$	JJ %0@) L L!&)!D!D 	+ 	+ 	+'O( )!*		+  	LL;;;;"    
  )11 	! 	!OA|dv~~]2P>N2P2PQQQ OO--	Yq\D0>>>#ABB- B BBLL!3R!3!3!35LAAAAB)))-5Q=O5Q5QRRR OO--	Yq\D0;;;#ABB- B BBLL!6!6!6!6bLAAAAB -5UAS5U5UVVV OO--	Yq\D0>>>#ABB- E EBLL!6!6!6!6eLDDDD3w<<!###R   E*EEE3 133!
 
 
 	5!!!!!s   !A(R
 
RRc                 0   ddl m} t                      dz  }| xj        dz  c_        t	          j                                        d          }|d| d| j         dz  } ||          r| j                            |           d	S | xj        dz  c_        d
S )zCheck clipboard for an image and attach it if found.

        Saves the image to ~/.hermes/images/ and appends the path to
        ``_attached_images``.  Returns True if an image was attached.
        r   )save_clipboard_imager  r  r  clip_r  r4  TF)	hermes_cli.clipboardr"  r'   rY  r   r  r;  rX  rd   )r  r"  img_dirtsimg_paths        rC   _try_attach_clipboard_imagez%HermesCLI._try_attach_clipboard_image  s     	>=====!##h.q \^^$$_55CRCC$*=CCCC)) 	!((2224q urL   c           	         ddl m} t          | d          r| j        st	          d           dS | j        j        }|j        s/t	          d           t	          d           t	          d           dS t          j        d	t          j	                              }|
                                }t          |          d
k    r
|d
d         ng }|s0|                    |          }t	           |||                     dS |d                                         dk    rt          |          dk     rt	          d           dS |                    |          }|st	          d|            dS |                     |d
         |          }|sdS |                    ||          }	|	d         r|	                    dd          }
|	                    dd          }|
s|st	          d           n|
rt	          d|
            |r|                                }t          |          dk    rNt	          d                    |dd                              t	          dt          |          dz
   d           n+t	          d|            nt	          d|	d                     dS |                    |          }|st	          d|            dS |                     |d         |          }|sdS t          |          d
k    r|d
         nd}|                    |||          }	|	d         r|r%t	          d| d|	d          d|	d                     n!t	          d|	d          d|	d                     t	          d            | j        r%|                                  t	          d!           dS dS t	          d|	d                     dS )"u  Handle /rollback — list, diff, or restore filesystem checkpoints.

        Syntax:
            /rollback                 — list checkpoints
            /rollback <N>             — restore checkpoint N (also undoes last chat turn)
            /rollback diff <N>        — preview changes since checkpoint N
            /rollback <N> <file>      — restore a single file from checkpoint N
        r   )format_checkpoint_listr   z  No active agent session.Nz  Checkpoints are not enabled.z#  Enable with: hermes --checkpointsz3  Or in config.yaml: checkpoints: { enabled: true }r   r  diffr@  z  Usage: /rollback diff <N>z  No checkpoints found for successr  rO   z#  No changes since this checkpoint.r  rz  r  z more lines, showing first 80)u     ❌ r  )r,   u     ✅ Restored z from checkpoint restored_tor  reasonu     ✅ Restored to checkpoint z2  A pre-rollback snapshot was saved automatically.z0  Chat turn undone to match restored file state.)tools.checkpoint_managerr*  rl  r   r  _checkpoint_mgrr   r`   rL  r  r  r  list_checkpointsrY   _resolve_checkpoint_refr+  r   r  r   restorerd  	undo_last)r  rV  r*  mgrr   r   r  r  target_hashrJ   r  r+  
diff_linesr,   s                 rC   _handle_rollback_commandz"HermesCLI._handle_rollback_command  sH    	DCCCCCtW%% 	TZ 	.///Fj({ 	23337888GHHHFi	44JJNNuQRRyy 	..s33K((c::;;;F 7==??f$$4yy1}}3444..s33K 9C99:::66tAwLLK XXc;//Fi  2zz&"--zz&"-- /D /?@@@@ +k4kk*** /%)__%6%6
z??R//!$))JssO"<"<===!"bc*oo.B"b"b"bcccc!+t++...0vg00111F **3// 	555666F2247KHH 	F  #4yy1}}DGG$	S+CC) 	. co	ooF=DYoo]cdl]mooppppaf]6KaavV^O_aabbbFGGG ( J   HIIIIIJ J ,6'?,,-----rL   refc                     	 t          |          dz
  }d|cxk    rt          |          k     rn n||         d         S t          dt          |           d           dS # t          $ r |cY S w xY w)z:Resolve a checkpoint number or hash to a full commit hash.r  r   hashz#  Invalid checkpoint number. Use 1-r   N)r  r  r  r~  )r  r9  r  rQ  s       rC   r2  z!HermesCLI._resolve_checkpoint_refB  s    		c((Q,CC****#k*******"3'//OC<L<LOOOPPPt 	 	 	JJJ	s   <A!  A! !A0/A0c                 T   ddl m}m}m}m} ddlm} |                                }t          |          dk    r|d         	                                nd}|dv r0 |            }	|	s t          d           t          d           d	S t          d
 |             d           t          dddddddddddddd 
           t          dd dd dd dd dd 
           t          |	d          D ]\  }
}|                    dd          }|dk     r| d}n|dk     r
|dz  d d!}n|dz  dz  d"d#}|                    d$          pd%}t          d|
d&d|d'         dd|                    d(d          dd|dd| 
           d	S |d)k    ret          |          d*k    rd                    |d*d	                   nd	} ||+          }|rt          d,|            d	S t          d-           d	S |d.v rt          |          d/k     r=t          d0            |d1          }	|	rt          d2|	d         d'                     d	S |d*         }	 t          |          } |            }	d|cxk    rt          |	          k    rn n|	|dz
           d'         }n"t          d3t          |	           d4           d	S n# t          $ r Y nw xY w ||          r#t          d5|            t          d6           d	S t          d7|            d	S |d8k    rpd9}t          |          d*k    r7	 t          |d*                   }n # t          $ r t          d:           Y d	S w xY w ||;          }t          d<| d=| d>           d	S t          d?|            t          d@           d	S )Auu  Handle /snapshot — lightweight state snapshots for Hermes config/state.

        Syntax:
            /snapshot                  — list recent snapshots
            /snapshot create [label]   — create a snapshot
            /snapshot restore <id>     — restore state from snapshot
            /snapshot prune [N]        — prune to N snapshots (default 20)
        r   )create_quick_snapshotlist_quick_snapshotsrestore_quick_snapshotprune_quick_snapshotsr(   r  r=   )r=   lsz  No state snapshots yet.z&  Create one: /snapshot create [label]Nz  State snapshots (z/state-snapshots/):
r  r  z>3IDz<35rA  Filesz>5Size>10Labelu	   ───ui   ───────────────────────────────────u   ─────u   ──────────u<   ────────────────────
total_size   z Bi   .0fz KB.1fz MBrc  rO   3id
file_countcreater@  )rc  z  Snapshot created: z#  No state files found to snapshot.)r3  rewindr  z(  Usage: /snapshot restore <snapshot-id>r{  z  Most recent: z!  Invalid snapshot number. Use 1-r   z  Restored state from: z:  Restart recommended for state.db changes to take effect.z  Snapshot not found: pruner  z%  Usage: /snapshot prune [keep-count])keepz	  Pruned z old snapshot(s) (keeping z).z  Unknown subcommand: z?  Usage: /snapshot [list|create [label]|restore <id>|prune [N]])hermes_cli.backupr=  r>  r?  r@  rH   r(   r  r  rY   r  r  r   r   r  r~  )r  rV  r=  r>  r?  r@  r(   r   subcmdsnapsr  r  sizesize_strrc  snap_idrQ  rS  deleteds                      rC   _handle_snapshot_commandz"HermesCLI._handle_snapshot_commandO  s/   	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	988888%(ZZ!^^q!!!^##((**E 1222>???T(;(;(=(=TTTUUUOsOOOOOOGOOOOOOgOOPPPLwLL(LLWLLxLL(LLMMM!%++ 	d 	d1uu\1--$;;"&{{{HHK''"&+6666HH"&+"4====Hg,"b1bbb!D'bbblA0F0FbbbHbbb[`bbcccc	d 	d x+.u::>>CHHU122Y'''tE++%888G =6W6677777;<<<<<,,,5zzA~~@AAA,,1555 ><E!HTN<<===AhG	'll,,..))))s5zz)))))#C!GnT2GGKc%jjKKKLLLF     %%g.. :999:::RSSSSS8w8899999wD5zzA~~uQx==DD!   ABBBFF ,+666GIgIIIIIJJJJJ 3633444STTTTTs%   A(J? ?
KK-M M M c                    ddl m} |                                }d |D             }|st          d           dS t          dt	          |           d           |                                }t          d| d	           dS )
u   Handle /stop — kill all running background processes.

        Inspired by OpenAI Codex's separation of interrupt (stop current turn)
        from /stop (clean up background processes). See openai/codex#14602.
        r   process_registryc                 D    g | ]}|                     d           dk    |S )r  runningr`  r  ps     rC   r  z2HermesCLI._handle_stop_command.<locals>.<listcomp>  s,    HHH155??i+G+G1+G+G+GrL   z"  No running background processes.Nz  Stopping z background process(es)...u     ✅ Stopped z process(es).)tools.process_registryr^  list_sessionsr  r  kill_all)r  r^  	processesr`  killeds        rC   _handle_stop_commandzHermesCLI._handle_stop_command  s     	<;;;;;$2244	HHiHHH 	6777FDCLLDDDEEE!**,,4v44455555rL   c                    t                      r/t          dt           dt                       t                      dS ddlm}  |            r^|                                 r)t          | j	                  }t          d| d           dS t          dt           dt                      dS t          dt           d	t                      dS )
u   Handle /paste — explicitly check clipboard for an image.

        This is the reliable fallback for terminals where BracketedPaste
        doesn't fire for image-only clipboard content (e.g., VSCode terminal,
        Windows Terminal with WSL2).
        r  uh   Clipboard image paste is not available on Termux — use /image <path> or paste a local image path like Nr   )has_clipboard_imageu     📎 Image #z attached from clipboardz2(>_<) Clipboard has an image but extraction failedz!(._.) No image found in clipboard)
_is_termux_environmentr*  r  r;  r  r$  rj  r(  r  rX  )r  rj  ns      rC   _handle_paste_commandzHermesCLI._handle_paste_command  s    "## 	8T 8 8-//8158 8  
 F<<<<<<   	H//11 ]-..DDDDEEEEE[T[[UY[[\\\\\FFFFFGGGGGrL   cmd_originalc                 D   d|v r.|                     dd          d                                         nd}|sAt                      rt                      nd}t	          dt
           d| t                      dS t          |          \  }}t          |          }|#t	          dt
           d| t                      dS |j	        
                                t          vr(t	          dt
           d	|j         t                      dS | j                            |           t	          d
|j                    |r#t	          dt
           d| t                      dS t                      r6t	          dt
           dt          |j                   dt                      dS dS )uG   Handle /image <path> — attach a local image file for the next prompt.rA  Nr  rO   z/path/to/image.pngr  z"Usage: /image <path>  e.g. /image z(>_<) File not found: z"(._.) Not a supported image file: u     📎 Attached image: z<Now type your prompt (or use --image in single-query mode): z;Tip: type your next message, or run hermes chat -q --image z "What do you see?")r  rI   rk  r;  r*  r  r  rH  rP  rn  rY   ro  rn   rX  rd   )r  rn  raw_argshint
path_token
_remainder
image_paths          rC   _handle_image_commandzHermesCLI._handle_image_command  s
   >A\>Q>QL&&tQ//288:::WY 	3I3K3Ke-///QeDMMMMtMMNNNF!28!<!<
J-j99
GGGZGGGHHHF""$$,===XXXXRVXXYYYF$$Z000;*/;;<<< 	dmmm[emgkmmnnnnn#%% 	d  c  c  cZtu  vE  [F  [F  c  c  ]a  c  c  d  d  d  d  d	d 	drL   Tannouncer  rw  c                   ddl }ddl}ddlm} d}g }|D ]}	|	                                s|	                                j        dz  }
|r*t          dt           d|	j	         d|
 d	t                      	 |                     |t          |	          |
                    }|                    |          }|                    d          rT|                    dd          }|                    d| d|	 d           |rt          dt           dt                      n:|                    d|	 d           |rt          dt           dt                      H# t           $ rH}|                    d| d|	 d           |rt          dt           dt                      Y d}~d}~ww xY wt#          |t                    r|r|nd}|r d                    |          }|r| d| n|S |pdS )u,  Analyze attached images via the vision tool and return enriched text.

        Instead of embedding raw base64 ``image_url`` content parts in the
        conversation (which only works with vision-capable models), this
        pre-processes each image through the auxiliary vision model (Gemini
        Flash) and prepends the descriptions to the user's message — the
        same approach the messaging gateway uses.

        The local file path is included so the agent can re-examine the
        image later with ``vision_analyze`` if needed.
        r   N)vision_analyze_toolzDescribe everything visible in this image in thorough detail. Include any text, code, data, objects, people, layout, colors, and any other notable visual information.rI  r  u   👁️  analyzing r  zKB)...)r  user_promptr,  analysisrO   z6[The user attached an image. Here's what it contains:
zA]
[If you need a closer look, use vision_analyze with image_url: rY  u   ✓ image analyzedzw[The user attached an image but it couldn't be analyzed. You can try examining it with vision_analyze using image_url: u6   ⚠ vision analysis failed — path included for retryz1[The user attached an image but analysis failed (zA). You can try examining it with vision_analyze using image_url: u5   ⚠ vision analysis error — path included for retryr#  zWhat do you see in this image?)asyncior:   tools.vision_toolsry  r6   r  st_sizer*  r  rn   r  rw  rX   loadsr   rd   r>   r<   r   )r  ru  r  rw  _asyncio_jsonry  analysis_promptenriched_partsr'  size_kbresult_jsonrJ   descriptionrB   	user_textr  s                    rC   _preprocess_images_with_visionz(HermesCLI._preprocess_images_with_vision  s    	#"""::::::8 	  #	d #	dH??$$ mmoo-5G ^\T\\hm\\w\\VZ\\]]]d&ll''#h--_]]]  [11::i(( i"(**Z"<"<K"))2R] 2 2&.2 2 2  
   E CT C CT C CDDD"))2&.2 2 2  
   i gT g gae g ghhh d d d%%. . ."*. . .  
  dbbb\`bbcccd 'tS11BdBDD	 	G[[00F1:Ff--)---F<<<s   6C%E
F/'=F**F/c           
      J   	 ddl m}  |            \  }}d |D             }|r| j                                         | j                            d           |D ]}d                    |d         dd                   }t          |d                   dk    r|d	t          |d                   dz
   d
z  }| j                            d|d          dd                    |d                    d           | j                            d           dS dS # t          $ r Y dS w xY w)z;Show warnings about disabled tools due to missing API keys.r   )check_tool_availabilityc                 "    g | ]}|d          
|S )missing_varsr  )r  us     rC   r  z>HermesCLI._show_tool_availability_warnings.<locals>.<listcomp>5  s"    KKKQ>9JKqKKKrL   u:   [yellow]⚠️  Some tools disabled (missing API keys):[/]r  r  Nr@  z, +z moreu      [dim]• rn   z[/] [dim italic](r  )[/]z*[dim]   Run 'hermes setup' to configure[/])model_toolsr  r  r  r   r  r>   )r  r  r  unavailableapi_key_missingr  	tools_strs          rC   r  z*HermesCLI._show_tool_availability_warnings-  sw   	;;;;;;%<%<%>%>"I{ LK+KKKO Q""$$$""#_```+ | |D $		$w-*; < <I4=))A--!%F3tG}+=+=a+?%F%F%FF	L&&'zd6l'z'zUYU^U^_cdr_sUtUt'z'z'z{{{{""#OPPPPPQ Q  	 	 	DD	s   DD 
D"!D"c                    t          | j        d          }|rt          |          nd}d| j        v r | j                            d          d         n| j        }t          |          dk    r|dd         d	z   }| j        rd
}nd}	 ddlm}  |            }|                    dd          }|                    dd          }|                    dd          }	n# t          $ r	 d\  }}}	Y nw xY wd}
| j        r-d| j        vr$d| d|	 dd
                    | j                   d}
d| d| j         d}| j        r|d| d| j         dz  }| j                            d| d| d| d | d!|	 d| d"|
 |            dS )#z!Show compact startup status line.Tr  r   rk  r  r  N   r}  u   [green bold]●[/]u   [red bold]●[/]r  r  r  r  r   ui_labelz#4dd0e1)r  r   cyanrO   r  z [dim u   ]·[/] [z]toolsets: r  r  u   ]·[/] [dim]provider: u   ]·[/] [dim]auth: r   [rY  r  u   ]·[/] [bold z	 tools[/])rJ  r'  r  r   r  r   r	  r  r
  r>   r   r   r#  r  r  )r  r  
tool_countr  api_indicatorr  r   separator_colorr  label_colortoolsets_infoprovider_infos               rC   r  zHermesCLI._show_statusC  sK    %d6KX\]]]#(/SZZZa
 47$*3D3Ddj&&s++B//$*{b  %crc*U2K < 	/0MM.M	V>>>>>>"?$$D"nn\9EEO>>+yAAL..Y??KK 	V 	V 	V9U6O\;;;	V  	|U$2G%G%G{_{{k{{VZV_V_`d`uVvVv{{{MZZZZZZ  	dcoccI^ccccM. . ., . . . .#. .2=. .@J. ..+. .	
 	
 	
 	
 	
s   AC C-,C-c                 v   i }| j         r5	 | j                             | j                  pi }n# t          $ r i }Y nw xY w|                    d          pd                                }| j        }|                    d          }|r:	 t          j        t          |                    }n# t          $ r
 | j        }Y nw xY w|}dD ]M}|                    |          }|s	 t          j        t          |                    } n# t          $ r Y Jw xY wt          | dd          }t          |dd          pd}	t          | d	d          pd
}
t          | dd          pd}t          t          | dd                    }ddd| j         dt                       g}|r|                    d|            |                    d| d|
 dd|                    d           d|                    d           d|	dd|rdnd g           | j                            d                    |          dd           dS ) z6Show gateway-style status for the current CLI session.r  rO   
started_at)
updated_atlast_updated_atlast_activity_atr   Nr  r   r   rU  r   z	(unknown)r>  FzHermes CLI StatuszSession ID: zPath: zTitle: zModel: r  )z	Created: z%Y-%m-%d %H:%MzLast Activity: zTokens: r  zAgent Running: YesNor  )r  markup)r8  r  ra  r>   r   rI   r6  r   fromtimestampfloatrm  r  r(   rd   extendr;  r  r  r   )r  r  r  
created_atr  r  fieldrZ   r   total_tokensr   r   
is_runningr  s                 rC   _show_session_statuszHermesCLI._show_session_statusk  s    	""#/;;DOLLRPR " " "!" !!'**0b7799'
!%%l33
 	00%3E*4E4EFF

 0 0 0!/


0  
J 	 	E $$U++E %3E%LLAA
    gt,,u&<a@@EA4T22?igt,,;'$(8%@@AA
  ,4?,,,(**,,	
  	,LL*5**+++*e**x***?
++,<==??Ej112BCCEE'|'''=z;eet==
 	 	 	 	499U++uUKKKKKs0   !- <<!B) )B=<B=!D
DDc                     	 ddl m} n# t          $ r Y dS w xY wt          | dd           }t          |dd           pt          | dd           } ||          S )Nr   )model_supports_fast_modeFr   r   )r  r  r>   rm  )r  r  r   r   s       rC   _fast_command_availablez!HermesCLI._fast_command_available  s    	BBBBBBB 	 	 	55	gt,,w--Mw1M1M''...s   	 
slash_commandc                 :    |dk    r|                                  S dS )Nz/fastT)r  )r  r  s     rC   _command_availablezHermesCLI._command_available  s$    G##//111trL   c                    ddl m} 	 ddlm}  |d          }n# t          $ r d}Y nw xY w|pd                                pd}d}t          |          |k    r
|d|         }t          dt           d	d
|z   d	t                      t          t           d|d| dt                      t          t           d	d
|z   d	t                      |
                                D ]\  }}t          dt           d| dt                      |
                                D ]_\  }}|                     |          st                                          dt                       d|ddt          |                      `t           rt          dt           dt           dt          t                      d           t#          t           
                                          D ]O\  }}	t                                          dt                       d|ddt          |	d                               Pt          dt$           dt                      t          dt$           dt                      t'                      r1t          dt$           dt)                       dt           d           dS t          dt$           dt           d           dS ) z3Display help information with categorized commands.r   )COMMANDS_BY_CATEGORY)get_active_help_headerz(^_^)? Available CommandsrO   7   Nr  +-|^
  u   ── u    ──z
    [bold rY  <15z[/] [dim]-[/] u   
  ⚡ zSkill Commandsr  z installed):z<22r  z0Tip: Just type your message to chat with Hermes!r  z$Multi-line: Alt+Enter for a new linezAttach image: /image z- or start your prompt with a local image pathzPaste image: Alt+V (or /paste))hermes_cli.commandsr  r	  r  r>   rI   r  r*  _BOLDr  r  r  r  r  r!  r  _skill_commandssortedr  rk  r;  )
r  r  r  headerinner_widthcategorycommandscmddescr  s
             rC   	show_helpzHermesCLI.show_help  s   <<<<<<	1EEEEEE++,GHHFF 	1 	1 	10FFF	1,B%%''F+Fv;;$$L[L)F7U77S;.777788859969K9999499:::5553,55t55666"6"<"<">"> 	i 	iHh@5@@@@$@@AAA%^^-- i i	T..s33 ##$g$g$g$g$g$gX_`dXeXe$g$ghhhhi
  	^u^^D^^C<P<P^^^___#O$9$9$;$;<<  	T##ffffffPTUbPcHdHdff    	StSSTSSTTTETEEtEEFFF!## 	G  H  H  H4N4P4P  H  H  @D  H  H  H  I  I  I  I  IEEETEEEFFFFFs    ))c                    t          | j        d          }|st          d           dS t                       d}d}|t          |          z
  }t          dd|z  z   dz              t          d	d
|dz  z  z   |z   d
||dz  z
  z  z   d	z              t          dd|z  z   dz              t                       i }t	          |d           D ]}|d         d         }t          |          pd}||vrg ||<   |d                             dd          }	|	                    d          d         }	d|	v r |	d|	                    d          dz            }	||         	                    ||	f           t	          |
                                          D ]G}t          d| d           ||         D ]\  }}	t          d|dd|	            t                       Ht          dt          |           d           t                       dS )z.Display available tools with kawaii ASCII art.Tr  z(;_;) No tools availableNz(^_^)/ Available ToolsN   r  r  r  rA  r@  c                     | d         d         S )Nr  rn   r  )r  s    rC   <lambda>z&HermesCLI.show_tools.<locals>.<lambda>  s    *f0E rL   r%  r  rn   rU  r  rO   r  r   . r  z  [rY  z    * z<20 - z	  Total: u    tools  ヽ(^o^)ノ)rJ  r'  r  r  r  rK  r   r  indexrd   r  )
r  r  r  rw  padr  r  rn   toolsetr  s
             rC   
show_toolszHermesCLI.show_tools  sY   $d6KX\]]] 	,---F 	(c%jj cC%K#%&&&cC3!8$$u,scC1Hn/EEKLLLcC%K#%&&& 5&E&EFFF 
	3 
	3D
#F+D*400=IGh&&$&!
#''r::D::d##A&Dt||1TZZ--112W$$dD\2222 hmmoo.. 	 	G""""###&w/ 4 4
d2t222D223333GGGG9#e**999:::rL   r  c                 4   ddl }ddlm} ddlm} 	 |                    |          }n$# t          $ r |                                }Y nw xY wt          |          dk    r|d         nd}|dvr|                                  dS |dk    r | |dd	
                     dS |dd         }|s;t          d| d           t          d| d           t          d| d           dS |dk    rdnd}d
                    |          }	t          t           | d|	 dt                       | |||d	                     ddlm}
 ddlm}  |
 |            d	          | _        |                                  t          t&           dt                      dS )a`  Handle /tools [list|disable|enable] slash commands.

        /tools (no args) shows the tool list.
        /tools list shows enabled/disabled status per toolset.
        /tools disable/enable saves the change to config and resets
        the session so the new tool set takes effect cleanly (no
        prompt-cache breakage mid-conversation).
        r   N)	Namespace)tools_disable_enable_commandr  rO   )r=   disableenabler=   r;  )tools_actionrb  r@  z(._.) Usage: /tools z <name> [name ...]z  Built-in toolset:  /tools z webz  MCP tool:          /tools z github:create_issuer  	DisablingEnablingr  rA  r}  )r  rj   rb  _get_platform_toolsload_configz0Session reset. New tool configuration is active.)shlexargparser  hermes_cli.tools_configr  r  r~  r  r  r  r   r*  ra  r  r  r  r  r'  new_sessionr  )r  r  r  r  r  r   
subcommandrj   verbrc  r  r  s               rC   _handle_tools_commandzHermesCLI._handle_tools_command  sF    	&&&&&&HHHHHH	 KK$$EE 	  	  	 IIKKEEE	  "%UaU1XXR
:::OOF((	v>>>@ @ @Fabb	 	GGGGHHHAAAABBBQQQQRRRF
 )I55{{:		%  73D33533T33444$$I:UUKKK	M 	M 	M 	@?????111111 3 3KKMM5 I I4OOOOPPPPPs   ( A	A	c                    t                      }t                       d}d}|t          |          z
  }t          dd|z  z   dz              t          dd|dz  z  z   |z   d||dz  z
  z  z   dz              t          dd|z  z   dz              t                       t          |                                          D ]T}t          |          }|rA|d         }|d	         }| j        r|| j        v rd
nd}	t          d|	 d|dd|dd|            Ut                       t          d           t                       t          d           t          d           t                       dS )z1Display available toolsets with kawaii ASCII art.z(^_^)b Available Toolsets:   r  r  r  rA  r@  r  r  z(*)   r  z<18r  z>2z
 tools] - z  (*) = currently enabledz.  Tip: Use 'all' or '*' to enable all toolsetsz0  Example: python cli.py --toolsets web,terminalN)rO  r  r  r  r  rP  r'  )
r  all_toolsetsr  rw  r  rn   r  r  r  markers
             rC   show_toolsetszHermesCLI.show_toolsets2  s   ')) 	+c%jj cC%K#%&&&cC3!8$$u,scC1Hn/EEKLLLcC%K#%&&&<,,..// 	Q 	QD#D))D Q!,/
M* #'"7dDDDY<Y<Y_dO6OODOOO
OOOOOPPP)***>???@AAArL   c                     ddl m} ddlm}  |            } |            }t	                       t	          d|            t	          d|            t	                       dS )z/Display active profile name and home directory.r   rA  get_active_profile_namez  Profile: z  Home:    N)rH   r(   hermes_cli.profilesr  r  )r  r(   r  r   profile_names        rC   _handle_profile_commandz!HermesCLI._handle_profile_commandQ  s    888888??????%%''..00*L**+++%G%%&&&rL   c                    t          j        dd          }t          j        dt          j                              }t          j        dd          }t          dz  }t	          t
                    j        dz  }|                                r|}n|}|                                rdnd	}| j        r*t          | j                  d
k    rd| j        dd         z   nd}t                       d}	d}
|
t          |	          z
  }t          dd|
z  z   dz              t          dd|dz  z  z   |	z   d||dz  z
  z  z   dz              t          dd|
z  z   dz              t                       t          d           t          d| j                    t          d| j                    t          d|            t                       t          d           t          d|            |dk    rWt          j        dd          }t          j        dd          }t          j        d d!          }t          d"| d#| d$|            t          d%|            t          d&| d'           t                       t          d(           t          d)| j                    t          d*| j        rd+                    | j                  nd,            t          d-| j                    t                       t          d.           t          d/| j                            d0                      t          d1| d|            t                       dS )2z4Display current configuration with kawaii ASCII art.r   r   r   r   60r   r   z(loaded)z(not found)r"  z********NzNot set!z(^_^) Configurationr   r  r  r  rA  r@  z  -- Model --z  Model:     z  Base URL:  z  API Key:   z  -- Terminal --z  Environment:  sshr   znot setr   r   22z  SSH Target:   @r&  z  Working Dir:  z  Timeout:      r  z  -- Agent --z  Max Turns:  z  Toolsets:   r  r  z  Verbose:    z  -- Session --z  Started:     z%Y-%m-%d %H:%M:%Sz  Config File: )r`   rL  r  r5   r   r  r  r6   r   r  r  r   r   r   r'  r   r   r6  r;  )r  terminal_envterminal_cwdterminal_timeoutr  r  r  config_statusapi_key_displayr  rw  r  r   r   r   s                  rC   show_configzHermesCLI.show_config^  sx    y99y==9%7>>'-7"8nn36GG""$$ 	.*KK-K&1&8&8&:&:M

<@LrSQUQ]M^M^abMbMb*t|BCC'888hr%c%jj cC%K#%&&&cC3!8$$u,scC1Hn/EEKLLLcC%K#%&&&o*dj**+++-dm--.../o//000 !!!///0005  y!4i@@Hy!4i@@Hy!4d;;HEXEEEE8EEFFF///0004!1444555o/t~//000e4CXctyy)>???^ceefff-t|--...   R 2 ; ;<O P PRRSSS===m==>>>rL   r{  c                       j         sg S 	  j                             ddg|          }n# t          $ r g cY S w xY w fd|D             S )zCReturn recent CLI sessions for in-chat browsing/resume affordances.r;  r  )r  exclude_sourcesr{  c                 P    g | ]"}|                     d           j        k     |#S )rM  )r   ra  )r  r  r  s     rC   r  z3HermesCLI._list_recent_sessions.<locals>.<listcomp>  s/    FFFaquuT{{do'E'E'E'E'ErL   )r8  list_sessions_richr>   )r  r{  sessionss   `  rC   _list_recent_sessionszHermesCLI._list_recent_sessions  s     	I	'::!' ;  HH
  	 	 	III	FFFF8FFFFs   + ::history)r.  r{  r.  c                   |                      |          }|sdS ddlm} t                       |dk    rt          d           nt          d           t                       t          dd	d
dddddddd            t          dd dd dd dd            |D ]}|                    d          pddd         }|                    d          pddd         } ||                    d                    }t          d|d
d|dd|dd|d                     t                       t          d           t                       dS ) zRender recent sessions inline from the active chat TUI.

        Returns True when something was shown, False if no session list was available.
        rQ  Fr   )_relative_timer  uV   (._.) No messages in the current chat yet — here are recent sessions you can resume:z  Recent sessions:r  Titlez<32rA  Previewz<40zLast Activez<13rC  u`   ────────────────────────────────x   ────────────────────────────────────────u'   ─────────────uH   ────────────────────────r  u   —Nr  r  rO   &   last_activerM  zC  Use /resume <session id or title> to continue where you left off.T)r  hermes_cli.mainr  r  r   )	r  r.  r{  r  r  sessionr  r  r  s	            rC   _show_recent_sessionszHermesCLI._show_recent_sessions  s   
 --E-:: 	5222222Yjkkkk&'''K7KKKKKKKKKTKKLLLF:FF
FFZFF*FFGGG 	T 	TG[[))2UCRC8E{{9--3SbS9G(.])C)CDDKRuRRR7RRRRRR74=RRSSSSSTTTtrL   c                    | j         s'|                     d          st          d           dS d}d}dfd}t                       t          d           t          d	           t          d           | j         D ]9}|                    d
d          }|dk    rdz  %|dvr* |             |dz  }|                    d          }|dnt	          |          }|dk    rEt          d| d           t          d|d|          t          |          |k    rdnd            t          d| d           |                    d          pg }|r"|d|         }	t          |          |k    rdnd}
n+|r%t          |          }|dk    rdnd}d| d| d}	d}
nd}	d}
t          d|	 |
            ; |             t                       dS )zDisplay conversation history.r  r.  z"(._.) No conversation history yet.Ni  r   c                  r    sd S dk    rdnd} t          d           t          d d|  d           dd S )	Nr  rX  messagesz

  [Tools]z    (r  z hidden)r   )r  )r  hidden_tool_messagess    rC   flush_tool_summaryz2HermesCLI.show_history.<locals>.flush_tool_summary  s`    '  4 9 999zD-   D.DDdDDDEEE#$   rL   4+--------------------------------------------------+z3|            (^_^) Conversation History           |r  rU  r  r  >   r  r  r  rO   r  z	
  [You #rY  r  r}  z
  [Hermes #r  r  r  z(requested r  r  z(no text response))rd  r  r  r   rX   r  )r  preview_limitvisible_indexr  r  r  r  content_textr  r  rn  r  r  r  s                @rC   show_historyzHermesCLI.show_history  sz   ( 	--Y-?? <:;;;F 	% 	% 	% 	% 	% 	"###LMMM"###, $	, $	,C7769--Dv~~$)$000   QMggi((G!(22c'llLv~~3=333444m<7m#lBSBSVcBcBcikmm   2-222333..4"J 
&~~6"%l"3"3m"C"C  __
!+qvvgA
AA$AAA.**&**++++rL   
event_typec           	          	 ddl m}  ||| j        r| j        j        ndt	          | dd          pd           dS # t
          $ r Y dS w xY w)u   Fire a session-boundary plugin hook (on_session_finalize or on_session_reset).

        Non-blocking — errors are caught and logged.  Safe to call from any
        lifecycle point (shutdown, /new, /reset).
        r   r]  Nrb  r;  r`  )rj  r^  r   ra  rm  r>   )r  r  rn  s      rC   _notify_session_boundaryz"HermesCLI._notify_session_boundary  s    	FFFFFFL48JH4:00D z488AE     
  	 	 	DD	s   8< 
A
	A
c                 b   | j         rt| j        rm	 | j                             | j                   n# t          t          f$ r Y nw xY w| j                             | j                   |                     d           n| j         r|                     d           | j        }| j        r/|r-	 | j        	                    |d           n# t          $ r Y nw xY wt          j                    | _        | j                            d          }t          j                    j        dd         }| d| | _        g | _        d| _        d| _        | j         rL| j        | j         _        | j        | j         _        | j                                          t)          | j         d          rd	| j         _        t)          | j         d
          r,	 d	dlm}  |            | j         _        n# t          $ r Y nw xY wt)          | j         d          r| j                                          | j        re	 | j                            | j        t6          j                            dd          | j        | j        | j         d           n# t          $ r Y nw xY w|                     d           |stC          d           dS dS )zDStart a fresh session with a new session ID and cleared agent state.r_  r  r  Nr  r  F_last_flushed_db_idxr   _todo_store	TodoStore_invalidate_system_promptHERMES_SESSION_SOURCEr;  r   r+  )ra  r  r   model_configon_session_resetz(^_^)v New session started!)"r   rd  flush_memoriesr>   KeyboardInterruptcommit_memory_sessionr  ra  r8  end_sessionr   r  r6  r;  r  r  r  r:  r7  reset_session_staterl  r   tools.todo_toolr#  r!  r$  create_sessionr`   r   r   r   r   r+  r  )r  silentold_session_idrs  rt  r#  s         rC   r  zHermesCLI.new_session  s   : 
	A$3 
	A
))$*CDDDD01    J,,T-FGGG))*?@@@@Z 	A))*?@@@ 	 	 ,,^]KKKK    &\^^*33ODDZ\\%bqb)
*99Z99$&!": 	>$(ODJ!'+'9DJ$J**,,,tz#9:: 423
/tz=11 999999-6Y[[DJ**    Dtz#>?? 7
44666 $33#'?!z~~.EuMM"j.2n040E& &	 4     !   D))*<=== 	1/00000	1 	1sF   0 AA)C 
CCG 
G*)G*#AI7 7
JJc                 "   |                     dd          }t          |          dk    r|d                                         nd}|s8t          d           |                     d          rdS t          d           dS | j        st          d           dS d	d
lm}  ||          }|p|}| j                            |          }|s#t          d|            t          d           dS || j	        k    rt          d           dS 	 | j        
                    | j	        d           n# t          $ r Y nw xY w|| _	        d| _        d| _        | j                            |          }d |pg D             }|| _        	 | j                            |           n# t          $ r Y nw xY w| j        r|| j        _	        | j                                         t'          | j        d          rt          | j                  | j        _        t'          | j        d          r,	 d	dlm}	  |	            | j        _        n# t          $ r Y nw xY wt'          | j        d          r| j                                         |                    d          rd|d          dnd}
t          d | j        D                       }| j        r:t          d| |
 d| d|dk    rdnd dt          | j                   d
           dS t          d| |
 d           dS ) uW   Handle /resume <session_id_or_title> — switch to a previous session mid-conversation.Nr  rO   z&  Usage: /resume <session_id_or_title>r  r  zA  Tip:   Use /history or `hermes sessions list` to find sessions.!  Session database not available.r   )_resolve_session_by_name_or_idz  Session not found: zC  Use /history or `hermes sessions list` to see available sessions.z  Already on that session.resumed_otherTc                 D    g | ]}|                     d           dk    |S r  r`  r  s     rC   r  z4HermesCLI._handle_resume_command.<locals>.<listcomp>x  s,    SSS!155==N3R3RA3R3R3RrL   r   r!  r"  r$  r  r  r=  c                 D    g | ]}|                     d           dk    |S r  r`  r  s     rC   r  z4HermesCLI._handle_resume_command.<locals>.<listcomp>  -    YYYqvRXAXAXAXAXAXrL   u     ↻ Resumed session r  r  r  r  z total)u!    — no messages, starting fresh.)r  r  rI   r*  r  r8  r  r4  r  ra  r,  r>   r7  r:  r  rd  reopen_sessionr   r-  rl  r   r.  r#  r!  r$  r   )r  rn  r   targetr4  rO  	target_idr  r  r#  r  r  s               rC   _handle_resume_commandz HermesCLI._handle_resume_commandL  s   ""4++%(ZZ!^^q!!! 	<===))):: WXXXF 	7888F 	CBBBBB11&99&	'33I>> 	4F44555YZZZF''0111F	((/JJJJ 	 	 	D	 $" #@@KKSSBSSS$,!	++I6666 	 	 	D	 : 	7$-DJ!J**,,,tz#9:: Q25d6O2P2P
/tz=11 999999-6Y[[DJ**    Dtz#>?? 7
446668D8H8H8Q8QY4<04444WY
YYD$=YYYZZ	$ 	g< <J < << <4=NNSS< <122< < <     eYe
eeefffffs6   	 D* *
D76D7?F 
F'&F'H: :
IIc                     | j         st          d           dS | j        st          d           dS |                    dd          }t	          |          dk    r|d                                         nd}t          j                    }|                    d          }t          j
                    j        dd         }| d| }|r|}nFd}	| j        r| j                            | j                  }	|	pd	}
| j                            |
          }| j        }	 | j                            | j        d
           n# t           $ r Y nw xY w	 | j                            |t$          j                            dd          | j        | j        | j        d|           n*# t           $ r}t          d|            Y d}~dS d}~ww xY w| j         D ]}	 | j                            ||                    dd          |                    d          |                    d          p|                    d          |                    d          |                    d          |                    d                     # t           $ r Y w xY w	 | j                            ||           n# t           $ r Y nw xY w|| _        || _        d| _        d| _        | j        r|| j        _        || j        _        | j                                         t?          | j        d          rt	          | j                   | j        _         t?          | j        d          r,	 ddl!m"}  |            | j        _#        n# t           $ r Y nw xY wt?          | j        d          r| j        $                                 t	          d | j         D                       }t          d | d!| d"|dk    rd#nd d$           t          d%|            t          d&|            dS )'u*  Handle /branch [name] — fork the current session into a new independent copy.

        Copies the full conversation history to a new session so the user can
        explore a different approach without losing the original session state.
        Inspired by Claude Code's /branch command.
        u5     No conversation to branch — send a message first.Nr3  r  rO   r  r  r  r  branchedr%  r;  r&  )ra  r  r   r'  parent_session_idz#  Failed to create branch session: r  r  r  	tool_namern   r  tool_call_id	reasoning)ra  r  r  r@  r  rA  rB  Tr   r!  r   r"  r$  c                 D    g | ]}|                     d           dk    |S r  r`  r  s     rC   r  z4HermesCLI._handle_branch_command.<locals>.<listcomp>  r8  rL   u     ⑂ Branched session "z" (r  r  r  z  Original session: z  Branch session:   )%rd  r*  r8  r  r  rI   r   r  r;  r  r  r  get_session_titlera  get_next_title_in_lineager,  r>   r/  r`   r   r   r   r   r+  append_messager  r6  r:  r7  r   r-  rl  r   r.  r#  r!  r$  )r  rn  r   r  r  rs  rt  new_session_idbranch_titlecurrent_titler   r?  rB   r  r#  r  s                   rC   _handle_branch_commandz HermesCLI._handle_branch_command  s    ( 	KLLLF 	7888F""4++*-e**q..eAhnn&&&b lnn_55Z\\%bqb)
)88J88  	L&LL !M T $ 0 B B4? S S ,HD+EEdKKL !O	((*EEEE 	 	 	D		++)z~~&=uEEj&*n(,(=  #4 , 	 	 	 	  	 	 	=!==>>>FFFFF	
 , 	 	C //-00GGI..!ggk22Ecggfoo"ww|44!$!8!8!ggk22 0        	..~|LLLL 	 	 	D	 ) " : 	7$2DJ!'*DJ$J**,,,tz#9:: Q25d6O2P2P
/tz=11 999999-6Y[[DJ**    Dtz#>?? 7
44666YYD$=YYYZZ	J J JJ J09QBJ J J	
 	
 	
 	:'8::;;;7~7788888sb    D9 9
EE
AF 
G$F<<GB)I88
JJ	J% %
J21J2M- -
M:9M:c                    | j         st          d           dS t          j                                        d          }d| d}	 t          |dd          5 }t          j        | j        | j	        
                                | j         d	|d
d           ddd           n# 1 swxY w Y   t          d|            dS # t          $ r}t          d|            Y d}~dS d}~ww xY w)z(Save the current conversation to a file.z(;_;) No conversation to save.Nr  hermes_conversation_z.jsonr  r0   r1   )r   r6  r  r@  F)indentensure_asciiz(^_^)v Conversation saved to: z(x_x) Failed to save: )rd  r  r   r  r;  r9   r:   dumpr   r6  	isoformatr>   )r  	timestampr7  r@   rB   s        rC   save_conversationzHermesCLI.save_conversation
  sf   ( 	2333FLNN++O<<	:):::		0hg666 4!	!Z%)%7%A%A%C%C $ 9  QU	4 4 4 44 4 4 4 4 4 4 4 4 4 4 4 4 4 4 =8==>>>>> 	0 	0 	0.1../////////	0s<   C >B"C "B&&C )B&*C 
C(C##C(c                    | j         st          d           dS d}t          t          | j                   dz
  dd          D ]*}| j         |                             d          dk    r|} n+|t          d           dS | j         |                             dd	          }| j         d|         | _         t          d
|dd          t          |          dk    rdnd	 d           |S )aB  Retry the last user message by removing the last exchange and re-sending.
        
        Removes the last assistant response (and any tool-call messages) and
        the last user message, then re-sends that user message to the agent.
        Returns the message to re-send, or None if there's nothing to retry.
        z(._.) No messages to retry.Nr  r  r  r  z%(._.) No user message found to retry.r  rO   z(^_^)b Retrying: "r   r}  r=  rd  r  r  r  r   )r  last_user_idxr  last_messages       rC   
retry_lastzHermesCLI.retry_last  s    ( 	/0004 s445592rBB 	 	A(+//776AA ! B  9:::4 0?CCIrRR$($=n}n$M!bL"$5bL@Q@QTV@V@Vuu\^bbbcccrL   c           	      R   | j         st          d           dS d}t          t          | j                   dz
  dd          D ]*}| j         |                             d          dk    r|} n+|t          d           dS t          | j                   |z
  }| j         |                             dd	          }| j         d|         | _         t          d
| d|dd          t          |          dk    rdnd	 d           t          | j                   }t          d| d           dS )zRemove the last user/assistant exchange from conversation history.
        
        Walks backwards and removes all messages from the last user message
        onward (including assistant responses, tool calls, etc.).
        z(._.) No messages to undo.Nr  r  r  r  z$(._.) No user message found to undo.r  rO   z(^_^)b Undid z message(s). Removed: "r   r}  r=  r  z! message(s) remaining in history.rT  )r  rU  r  removed_countremoved_msg	remainings         rC   r4  zHermesCLI.undo_last;  s    ( 	.///F s445592rBB 	 	A(+//776AA ! B  8999F D566F/>BB9bQQ %)$=n}n$M!  Bm  B  B[QTRTQTEU  B`cdo`p`psu`u`uW\W\{}  B  B  B  	C  	C  	C122	?9???@@@@@rL   r   r  r  default_indexc                   	
 ddl }ddlm	 dg
	
fd} |j                     |j                    u }| j        r|rddlm} | j        }d| _        | j        	                                 	  ||           || _        | j        	                                 n/# || _        | j        	                                 w xY w |             
d         S )zbRun curses_single_select via run_in_terminal so prompt_toolkit handles terminal ownership cleanly.r   N)curses_single_selectc                  *                d<   d S )N)r\  r   r  )r^  r\  r  rJ   r  s   rC   _pickz+HermesCLI._run_curses_picker.<locals>._pickb  s"    ,,UEWWWF1IIIrL   run_in_terminalF)
rL  hermes_cli.curses_uir^  current_threadmain_threadr5  r  rb  re  ry  )r  r  r  r\  rL  r`  in_main_threadrb  was_visibler^  rJ   s    ```     @@rC   _run_curses_pickerzHermesCLI._run_curses_picker[  s:   ======	X 	X 	X 	X 	X 	X 	X 	X 	X 21337Ly7L7N7NN9 	 	BBBBBB2K',D$I  """'&&&+6(	$$&&&& ,7(	$$&&&&EGGGays   1B "B?prompt_textc                 H   dgfd}| j         rddlm} | j        }d| _        | j                                          	  ||           || _        | j                                          n/# || _        | j                                          w xY w |             d         S )zCPrompt for free-text input safely inside or outside prompt_toolkit.Nc                      	 t                                                     pd d<   d S # t          t          f$ r Y d S w xY w)Nr   )inputrI   r*  EOFError)ri  rJ   s   rC   _askz*HermesCLI._prompt_text_input.<locals>._ask}  sU    !+..4466>$q			%x0   s   &+ A A r   ra  F)r5  r  rb  re  ry  )r  ri  rn  rb  rg  rJ   s    `   @rC   _prompt_text_inputzHermesCLI._prompt_text_inputy  s    	 	 	 	 	 	 9 	BBBBBB2K',D$I  """'%%%+6(	$$&&&& ,7(	$$&&&&DFFFays   A- -"B	providersr  current_providerc                     |                                   t          d t          |          D             d          }d||||||d| _        |                     d           dS )z/Open prompt_toolkit-native /model picker modal.c              3   J   K   | ]\  }}|                     d           |V  dS )
is_currentNr`  )r  r  rb  s      rC   r  z/HermesCLI._open_model_picker.<locals>.<genexpr>  s7      VV$!Q!%%BUBUVAVVVVVVrL   r   r   )stagerp  selectedr  rq  
user_provscustom_provsr  rv  N)_capture_modal_input_snapshotnextr  rO  r{  )r  rp  r  rq  rw  rx  default_idxs          rC   _open_model_pickerzHermesCLI._open_model_picker  s~    **,,,VV)I*>*>VVVXYZZ"#* 0$($
 $
  	c*****rL   c                 h    d | _         |                                  |                     d           d S )Nr  rv  )rO  _restore_modal_input_snapshotr{  r  s    rC   _close_model_pickerzHermesCLI._close_model_picker  s9    #' **,,,c*****rL   persist_globalc                 V   |j         st          d|j                    d S | j        }|j        | _        |j        | _        |j        | _        |j        r|j        | _        |j        | _	        |j
        r|j
        | _
        |j
        | _        |j        r|j        | _        | j        d	 | j                            |j        |j        |j        |j
        |j                   n*# t          $ r}t          d| d           Y d }~nd }~ww xY wd| d|j         d|j        p|j         d| _        |j        p|j        }t          d	|j                    t          d
|            |j        }|r|j        rt          d|j        dd           |j        rt          d|j        dd           |                                r$t          d|                                            t          d|                                            n]	 ddlm}  ||j        |j
        p| j
        |j        p| j        |j                  }t          d|dd           n# t          $ r Y nw xY wd|j
        pd                                v rd|j                                        v p
|j        dk    }	|	rt          d           |j        rt          d|j                    |rBt9          d|j                   |j        rt9          d|j                   t          d           d S t          d           d S )N     ✗ 	new_modelnew_providerr   r   r$       ⚠ Agent swap failed ("); change applied to next session.$[Note: model was just switched from  to  via /. Adjust your self-identification accordingly.]     ✓ Model switched:     Provider:     Context: r   tokens    Max output: 
    Cost:     Capabilities: r   get_model_context_lengthr   r   r   r~  rO   claudeanthropic_messages    Prompt caching: enabled       ⚠ model.defaultmodel.provider#    Saved to config.yaml (--global).       (session only — add --global to persist))r,  r*  error_messager   r  target_providerr   r"  r   r   r   r!  r$  r   switch_modelr>   provider_label_pending_model_switch_note
model_infocontext_window
max_outputhas_cost_dataformat_costformat_capabilitiesagent.model_metadatar  rY   warning_messager  provider_changed)
r  rJ   r  	old_modelr  r  mir  ctxcache_enableds
             rC   _apply_model_switch_resultz$HermesCLI._apply_model_switch_result  s   ~ 	3V133444FJ	%
."("8> 	4!>DL%+^D"? 	6"ODM&,oD#? 	,"ODM:!	]
''$.!'!7"N#_#_ (      ] ] ][C[[[\\\\\\\\]=9 = =&BR = =(BF,B= = = 	'  .H&2H;)9;;<<<111222 	  FD(9DDDDEEE} EC2=CCCCDDD!! 97R^^%5%577888C)?)?)A)ACCDDDD
IIIIII..$#_="N:dl#3	   666667777    fo3::<<<eVM]McMcMeMeAe 7"66 	  	31222! 	97v577888 	Fov/?@@@& L!"2F4JKKK9:::::DEEEEEs+   %8C 
D(D  DAI 
I! I!c                 6   | j         }|sd S |                    dd          }|                    d          }|dk    r|                    d          pg }|t          |          k    r|                                  d S ||                             dg           }|s-	 ddlm}  |d                   }|r|}n# t          $ r Y nw xY wd	|d<   |d
<   ||d<   d|d<   |                     d           d S |d	k    r|                    d
          pi |                    d          pg }t          |          }	t          |          dz   }
||	k    r^d|d<   t          fdt          |                    d          pg           D             d          |d<   |                     d           d S ||
k    r|                                  d S |t          |          k     rddl
m} ||         } ||| j        pd| j        pd| j        pd| j        pd|                    d          |                    d          |                    d          	  	        }|                                  |                     ||           d S |                                  d S d S )Nrv  r   ru  r   rp  models)provider_model_idsr  r   provider_data
model_listr  rv  r  c              3   z   K   | ]5\  }}|                     d                                d           k    1|V  6dS )r  Nr`  )r  r  rb  r  s      rC   r  z;HermesCLI._handle_model_picker_selection.<locals>.<genexpr>  s        *O  *O1cdchchiocpcp  uB  uF  uF  GM  uN  uN  dN  dN!  dN  dN  dN  dN  *O  *OrL   )r  rO   rw  rx  		raw_inputrq  r  current_base_urlcurrent_api_key	is_globalexplicit_provideruser_providerscustom_providers)rO  r   r  r  r  r  r>   r{  rz  r  r  r  r   r   r   r   r  )r  r  staterv  ru  rp  r  r  liveback_idx
cancel_idxr  chosen_modelrJ   r  s                 @rC   _handle_model_picker_selectionz(HermesCLI._handle_model_picker_selection  sA   ( 	F99Z++		'""J		+..4"I3y>>))((***%h/M
 '**8R88J DDDDDD--mF.CDDD *%)
    D$E'N%2E/"",E, !E*#...FG!IIo66<"M<006BJ:HZ1,J8##!+g$(  *O  *O  *O  *O	%))KBXBXB^\^8_8_  *O  *O  *O  QR  %S  %Sj!  c 222:%%((***#j//))@@@@@@)(3%*%)]%8b"&*"2%)]%8b$(L$6B,&3&7&7&?&?#(99\#:#:%*YY~%>%>
 
 
 ((***//GGG$$&&&&&= s   B; ;
CCc                 n	   ddl m}m}m} ddlm} |                    dd          }t          |          dk    r|d                                         nd} ||          \  }}	}
d}d}|s|	s| j	        pd}| j
        r || j
                  nd}d}d}	 ddlm}m}  |            }|                    d	          } ||          }n# t          $ r Y nw xY w	  || j
        pd||d
          }n# t          $ r g }Y nw xY w|s>t!          d           t!          d           t!          d           t!          d           dS |                     |||||           dS  ||| j
        pd| j	        pd| j        pd| j        pd|
|	||	  	        }|j        st!          d|j                    dS | j	        }|j        | _	        |j        | _
        |j        | _        |j        r|j        | _        |j        | _        |j        r|j        | _        |j        | _        |j        r|j        | _        | j        d	 | j                            |j        |j        |j        |j        |j                   n*# t          $ r}t!          d| d           Y d}~nd}~ww xY wd| d|j         d|j        p|j         d| _        |j        p|j        }t!          d|j                    t!          d|            |j        }|r|j         rt!          d|j         dd           |j!        rt!          d|j!        dd           |"                                r$t!          d|#                                            t!          d |$                                            n]	 dd!l%m&}  ||j        |j        p| j        |j        p| j        |j        "          }t!          d|dd           n# t          $ r Y nw xY wd#|j        pd'                                v rd$|j        '                                v p
|j        d%k    }|rt!          d&           |j(        rt!          d'|j(                    |
rBtS          d(|j                   |j*        rtS          d)|j                   t!          d*           dS t!          d+           dS ),u  Handle /model command — switch model for this session.

        Supports:
          /model                              — show current model + usage hints
          /model <name>                       — switch for this session only
          /model <name> --global              — switch and persist to config.yaml
          /model <name> --provider <provider> — switch provider + model
          /model --provider <provider>        — switch to provider, auto-detect model
        r   )r  parse_model_flagslist_authenticated_providers)	get_labelNr  rO   rU  )get_compatible_custom_providersr  rp  r   )rq  r  r  
max_modelsz#  No authenticated providers found.z3  /model <name>                        switch modelz6  /model --provider <slug>             switch provider)rw  rx  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r~  r  r  r  r  r  r  r  r  )+r  r  r  r  hermes_cli.providersr  r  r  rI   r   r   r  r  r  r   r>   r*  r|  r   r   r,  r  r  r  r"  r   r!  r$  r   r  r  r  r  r  r  r  r  r  r  rY   r  r  r  )r  rn  r  r  r  r  r   rp  model_inputr  r  rw  rx  model_displayprovider_displayr  r  cfgrp  rJ   r  r  r  r  r  r  r  s                              rC   _handle_model_switchzHermesCLI._handle_model_switch2  sw    	jiiiiiiiii222222 ""4++'*5zzA~~58>>###2 :K9J89T9T6&
  &	#4 &	 J3)M;?=Wyy777iJLZZZZZZZZ!kmm WW[11
>>sCC   88%)]%8b#-%1!	  		    			  =>>>MNNNPQQQ## %) $    F !!]0b**!]0b L.B$/%)

 

 

 ~ 	3V133444F
 J	%
."("8> 	4!>DL%+^D"? 	6"ODM&,oD#? 	,"ODM :!	]
''$.!'!7"N#_#_ (      ] ] ][C[[[\\\\\\\\]=9 = =&BR = =(BF,B= = = 	'  .H&2H;)9;;<<<111222  	  FD(9DDDDEEE} EC2=CCCCDDD!! 97R^^%5%577888C)?)?)A)ACCDDDD
IIIIII..$#_="N:dl#3	   666667777   
 fo3::<<<eVM]McMcMeMeAe 7"66 	  	31222 ! 	97v577888  	Fov/?@@@& L!"2F4JKKK9:::::DEEEEEsO   2C 
CCC/ /C>=C>18I* *
J4JJAO   
O-,O-
has_imagesc                 (   |r|st          |          sdS 	 ddlm} |                    dd          d                                                             d          } ||          }t          |o
|j        dk              S # t          $ r Y dS w xY w)zGReturn True when /model should be handled immediately on the UI thread.Fr   resolve_commandNr  rk  r   )	r  r  r  r  rY   r(  r  rn   r>   )r  ru  r  r  r   r  s         rC   #_should_handle_model_command_inlinez-HermesCLI._should_handle_model_command_inline  s     	z 	)B4)H)H 	5	;;;;;;::dA&&q)//1188==D!/$''C3G 3444 	 	 	55	s   A+B 
BBc                    ddl m}m}m}m}m}m} ddlm}  || j	                  }|dk    r1	  || j
        | j        | j                  }	n# t          $ r d}	Y nw xY w|}	|                    |	|	          }
t          d| j         d|
            t                        |            }d	 |D             }d
 |D             }|rHt          d           |D ]5}|d         |	k    }|rdnd}t          d|d          d|             ||d                   }|d         dv r ||d                   ni }|r.|r,|r| j        nd} ||||          D ]}t          |           n|r.|D ]*\  }}|r|| j        k    rdnd}t          d| |            +ni|d         dk    rNddl m}  |            }|rt          d|            |rt          d| j         d           t          d           nt          d           t                       7|rNd                    d |D                       }t          d|            t          d           t                       t          d           dS ) zShow current model + provider and list all authenticated providers.

        Shows current model + provider, then lists all authenticated
        providers with their available models.
        r   )curated_models_for_providerlist_available_providersnormalize_provider_PROVIDER_LABELSget_pricing_for_providerformat_model_pricing_table)resolve_providerr   )r|  r}  r~  z
  Current: r  c                 "    g | ]}|d          
|S authenticatedr  ra  s     rC   r  z7HermesCLI._show_model_and_providers.<locals>.<listcomp>  s"    ===!O*<=!===rL   c                 "    g | ]}|d          
|S r  r  ra  s     rC   r  z7HermesCLI._show_model_and_providers.<locals>.<listcomp>	  s"    CCC!/0BCACCCrL   z#  Authenticated providers & models:rM  u    ← activerO   z    [rY  )r~  nous)r  u    ← current      custom)_get_custom_base_urlz      endpoint: z      model: z"      (use hermes model to change)r  c              3   &   K   | ]}|d          V  dS )rc  Nr  ra  s     rC   r  z6HermesCLI._show_model_and_providers.<locals>.<genexpr>)  s&      ;;Qaj;;;;;;rL   z  Not configured: z  Run: hermes setupz0  To change model or provider, use: hermes modelN)r  r  r  r  r  r  r  hermes_cli.authr  r   r"  r   r!  r>   r   r  r   r  r   )r  r  r  r  r  r  r  _resolve_providerraw_providerr  current_labelrp  authedunauthedrb  	is_activer  curatedpricing_map	cur_modelr  midr  current_markerr  
custom_urlrj   s                              rC   _show_model_and_providersz#HermesCLI._show_model_and_providers  s   	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	

 	JIIIII *)$-886!!'+++%)%;&*&=  
  ' ' '&' #G(,,Wg>>>dj>>}>>??? -,..	==Y===CCyCCC 	7888  dGw.	*3;0ag000011155ag>>CDT7NdCdCd66qw???jl @{ @.7 ?

RI : :7K_h i i i $ $d$ @%, > >	T<E)d#QUQ[J[J[bd<s<N<<====> tW((FFFFFF!5!5!7!7J! ?===>>>  HFdjFFFGGG>????>??? 	II;;(;;;;;E.u..///'(((GGG@AAAAAs   A AAc                    t          | t                    r|                     dd          g}|                     d          r|                    d| d                     |                     d          r|                    d| d                     d                    d |D                       S t          |           S )	zEAccept string or dict personality value; return system prompt string.r   rO   tonezTone: r   zStyle: r  c              3      K   | ]}||V  	d S r_   r  ra  s     rC   r  z8HermesCLI._resolve_personality_prompt.<locals>.<genexpr><  s'      3313Q333333rL   )r<   r  r   rd   r   rX   )rZ   r   s     rC   _resolve_personality_promptz%HermesCLI._resolve_personality_prompt3  s     eT"" 	4YY334Eyy   85eFm55777yy!! :7uW~7799999333333335zzrL   c           	         	 ddl m}m}m} ddlm}m} n6# t          $ r)}| j        	                    d| d           Y d}~dS d}~ww xY w	  |            }nK# |$ rC}| j        	                    d| d           | j        	                    d           Y d}~dS d}~ww xY w |            }	|	r|	j
        nd	pd	}
	  |||

          }n0# |$ r(}| j        	                    d|            Y d}~dS d}~ww xY w|s| j        	                    d           dS |                    d            | j        	                                 | j        	                    d|
pd d           | j        	                                 |D ]}t          dt          d|j                            }d}t          t!          ||z                      }d|z  d||z
  z  z   }t          |dz            dd}|j        }|j        r|d|j         dz  }| j        	                    d|dd| d|            | j        	                                 dS )zIShow Google Gemini Code Assist quota usage for the current OAuth account.r   )get_valid_access_tokenGoogleOAuthErrorload_credentials)retrieve_user_quotaCodeAssistErrorz#  [red]Gemini modules unavailable: r  Nz
  [yellow]zB  Run [bold]/model[/] and pick 'Google Gemini (OAuth)' to sign in.rO   )
project_idz  [red]Quota lookup failed:[/] zN  [dim]No quota buckets reported (account may be on legacy/unmetered tier).[/]c                     | j         | j        fS r_   )model_id
token_type)r  s    rC   r  z2HermesCLI._handle_gquota_command.<locals>.<lambda>]  s    AJ#= rL   r  z/  [bold]Gemini Code Assist quota[/]  (project: z(auto / free-tier)r  r        ?r  u   ▓r  r  3dr  r  rY  r  40sr  )agent.google_oauthr  r  r  agent.google_code_assistr  r  ImportErrorr  r  r  r  r~  r  remaining_fractionr  r  r  r  )r  rn  r  r  r  r  r  r  r  credsr  bucketsr  pctrw  r  r  pct_strr  s                      rC   _handle_gquota_commandz HermesCLI._handle_gquota_command?  s   	eeeeeeeeeeUUUUUUUUU 	 	 	LMSMMMNNNFFFFF		1133LL 	 	 	L4C444555LcdddFFFFF	
 ! ""*/7e&&R>B
	)),:NNNGG 	 	 	LFFFGGGFFFFF	  	LopppF 	==>>>rZMo[orrrsss 		F 		FAc3sA$899::CEsU{++,,F&.5EFN#;;CS3Y----GZF| /.q|....LDfDDDCDD7DDEEEEsD    
AAA
A B8BB:C C5C00C5c                    |                     d          }t          |          dk    r}|d                                                                         }|dv rNd| _        d| _        t          dd          rt          d           nt          d           t          d	           dS || j        v r| 	                    | j        |                   | _        d| _        t          d| j                  rt          d
| d           nt          d| d           t          d| j        dd          t          | j                  dk    rdnd d           dS t          d|            t          dd
                    | j                                                              dS t                       t          d           t          d           t          d           t                       t          dddd           | j                                        D ]{\  }}t          |t                    r4|                    d          p|                    dd          dd         }nt!          |          dd         }t          d|dd|            |t                       t          d           t                       dS ) z@Handle the /personality command to set predefined personalities.r  maxsplit)rQ   rS   neutralrO   Nzagent.system_promptz,(^_^)b Personality cleared (saved to config)z((^_^) Personality cleared (session only)u7     No personality overlay — using base agent behavior.z(^_^)b Personality set to '' (saved to config)z(^_^) Personality set to '' (session only)z  "r   r}  r=  z(._.) Unknown personality: z  Available: none, r  r  z1|            (^o^)/ Personalities               |r  rQ   <12z - (no personality overlay)r  r   r   r  z  Usage: /personality <name>)r  r  rI   rY   r   r   r  r  r   r  r   r  r  r<   r  r   rX   )r  r  r   personality_namern   promptr  s          rC   _handle_personality_commandz%HermesCLI._handle_personality_commandm  s   		1	%%u::>>$Qx~~//5577#AAA%'"!
$%:B?? FHIIIIDEEEOPPPPP!T%777%)%E%EdFXYiFj%k%k"!
$%:D<NOO []8H]]]^^^^Y7GYYYZZZgT/4gs4CU?V?VY[?[?[eeacggghhhhhF4DFFGGGRDIId6H6M6M6O6O,P,PRRSSSSS GGG&'''JKKK&'''GGG>v>>>>??? $ 2 8 8 : : 3 3ffd++ /$jj77_6::oWY;Z;Z[^\^[^;_GG!&kk#2#.G14111112222GGG0111GGGGGrL   c           
         ddl }ddlm fd}d }d }|                    |          }t	          |          dk    rat                       t          d           t          d	           t          d           t                       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          r|                    dg           ng }|r
t          d           t          d           |D ]}	|	                    dd          }
t          d|	d         dd         d d!|	d"         d#d!|
d$           |	                    d%          r+t          d&d'                    |	d%                               t          d(|	                    d)d*                      |	                    d+          rt          d,|	d+                     t                       nt          d-           t                       dS |d                                         } ||d.d                   }|dS |dk    r |d|d/         0          }|                    d          r|                    dg           ng }|st          d1           dS t                       t          d2           t          d3           |D ]h}	t          d4|	d                     t          d5|	d6                     t          d7|	                    d8d                      t          d9|	d"          d:|	                    dd           d;           t          d<|	                    d+d=                      |	                    d%          r+t          d>d'                    |	d%                               t          d?|	                    d)d*                      |	                    d@          r0t          dA|	d@          d:|	                    dBd           d;           t                       jdS |dCv rc|dD         }|st          dE           dS |d"         p|d         }|dF         pdG                    |dd                   } ||d%                   }|s|st          dH           dS  |dI||pd|d6         |dJ         |d         |pdK          }|                    d          rt          dL|d                     t          d9|d"                     |                    d%          r+t          d>d'                    |d%                               t          d<|d+                     n%t          dM|                    dN                      dS |dOk    r|dD         }|st          dP           dS |d         }t          |          }|st          dQ|            dS d} ||d%                   } ||dR                   }t           ||dS                             t          |                    d%          p,|                    dT          sg n|                    dT          g          }|dU         rg }n5|r|}n0|sr,fdV|D             }|D ]}||vr|                    |            |dW||d"         |dF         |d6         |dJ         |d         |X          }|                    d          r|dY         }	t          dZ|	d                     t          d9|	d"                     |	                    d%          r,t          d>d'                    |	d%                               n5t          d[           n%t          d\|                    dN                      dS |d]v r{|dD         }|st          d^| d_           dS |d         }|d`v rdan|} ||||dbk    rdcndd          }|                    d          s*t          de| df|                    dN                      dS |dbk    r#t          dg|dY         d6          d:| d;           n|dhk    rNt          di|dY         d6          d:| d;           t          d<|dY                             d+                      nx|djk    r2t          dk|dY         d6          d:| d;           t          dl           n@|                    dmi           }t          dn|                    d6|           d:| d;           dS t          do|            t          dp           dS )qz3Handle the /cron command to manage scheduled tasks.r   N)cronjobc                  8    t          j         di |           S )Nr  )r:   r  )r  cronjob_tools    rC   	_cron_apiz1HermesCLI._handle_cron_command.<locals>._cron_api  s#    :ll44V44555rL   c                     g }| D ]@}t          |pd                                          }|r||vr|                    |           A|S NrO   )rX   rI   rd   )valuesrf   rZ   ru  s       rC   _normalize_skillsz9HermesCLI._handle_cron_command.<locals>._normalize_skills  s`    J , ,5;B''--// ,D
22%%d+++rL   c                    d d d g g g ddd d g d}d}|t          |           k     rS| |         }|dk    r+|dz   t          |           k     r| |dz            |d<   |dz  }n|dk    r+|dz   t          |           k     r| |dz            |d	<   |dz  }n|d
k    rZ|dz   t          |           k     rD	 t          | |dz                      |d<   n # t          $ r t          d           Y d S w xY w|dz  }nu|dk    rA|dz   t          |           k     r+|d                             | |dz                       |dz  }n.|dk    r@|dz   t          |           k     r*|d                             | |dz                       |dz  }n|dk    r@|dz   t          |           k     r*|d                             | |dz                       |dz  }n|dk    rd|d<   |dz  }n|dk    rd|d<   |dz  }n|dk    r*|dz   t          |           k     r| |dz            |d<   |dz  }nP|dk    r*|dz   t          |           k     r| |dz            |d<   |dz  }n |d                             |           |dz  }|t          |           k     S|S )NF)rn   deliverrepeatr  
add_skillsremove_skillsclear_skillsr  r  schedulepositionalsr   z--namer  rn   r@  z	--deliverr#  z--repeatr$  z!(._.) --repeat must be an integerz--skillr  z--add-skillr%  z--remove-skillr&  z--clear-skillsTr'  z--allr  z--promptr  z
--scheduler(  r)  )r  r  r~  r  rd   )tokensoptsr  rF  s       rC   _parse_flagsz4HermesCLI._handle_cron_command.<locals>._parse_flags  s    !# % ! D Ac&kk//q	H$$QV)<)<#)!a%=DLFAAk))a!ec&kk.A.A&,QUmDOFAAj((QUS[[-@-@$),VAE]););X% $ $ $ABBB#tt$ FAAi''AECKK,?,?N))&Q-888FAAm++AF0C0C&--fQUm<<<FAA...1q53v;;3F3F)00A???FAA...+/D(FAAg%%"&DKFAAj((QUS[[-@-@%+AE]DNFAAl**q1us6{{/B/B'-a!e}D$FAA'..u555FAM c&kk//N Ks   ,C C%$C%r  zF+--------------------------------------------------------------------+zD|                      (^_^) Scheduled Tasks                       |z  Commands:z    /cron listzD    /cron add "every 2h" "Check server status" [--skill blogwatcher]zA    /cron edit <job_id> --schedule "every 4h" --prompt "New task"z?    /cron edit <job_id> --skill blogwatcher --skill find-nearbyz2    /cron edit <job_id> --remove-skill blogwatcherz&    /cron edit <job_id> --clear-skillsz    /cron pause <job_id>z    /cron resume <job_id>z    /cron run <job_id>z    /cron remove <job_id>r=   )actionr,  jobsz  Current Jobs:zA  ---------------------------------------------------------------r$  r\  r  job_id   r  z | r(  r  z<8r  z      Skills: r  r  prompt_previewrO   next_run_atz      Next: z3  No scheduled jobs. Use '/cron add' to create one.r@  r  )r-  include_disabledz(._.) No scheduled jobs.zScheduled Jobs:zP--------------------------------------------------------------------------------z  ID: z  Name: rn   z	  State: r  z  Schedule: r  r  z  Next run: zN/Az
  Skills: z
  Prompt: last_run_atz  Last run: last_status>   re   rO  r)  z*(._.) Usage: /cron add <schedule> <prompt>r  rA  z3(._.) Please provide a prompt or at least one skillrO  r#  )r-  r(  r  rn   r#  r$  r  z(^_^)b Created job: z(x_x) Failed to create job: r  editzN(._.) Usage: /cron edit <job_id> [--schedule ...] [--prompt ...] [--skill ...]z(._.) Job not found: r%  r&  skillr'  c                     g | ]}|v|	S r  r  )r  r7  r&  s     rC   r  z2HermesCLI._handle_cron_command.<locals>.<listcomp>Y  s$    aaa%eS`F`F`F`F`F`rL   r  )r-  r/  r(  r  rn   r#  r$  r  jobz(^_^)b Updated job: z  Skills: nonez(x_x) Failed to update job: >   rmrw  pausedeleter  r  z(._.) Usage: /cron z	 <job_id>>   r:  r<  r  r  r;  zpaused from /cron)r-  r/  r.  z(x_x) Failed to z job: z(^_^)b Paused job: r  z(^_^)b Resumed job: rw  z(^_^)b Triggered job: z)  It will run on the next scheduler tick.removed_jobz(^_^)b Removed job: z(._.) Unknown cron command: z8  Available: list, add, edit, pause, resume, run, remove)r  tools.cronjob_toolsr  r  r  r  r   r   rY   rR  r   r=   rd   )r  r  r  r  r!  r,  r*  rJ   r.  r9  
repeat_strr  r+  r)  r(  r  r  r/  r  final_skillsreplacement_skillsr%  existing_skillsr7  r-  removedr  r&  s                             @@rC   _handle_cron_commandzHermesCLI._handle_cron_command  s   ??????	6 	6 	6 	6 	6	 	 	6	 6	 6	p S!!v;;!GGG&'''KLLL&'''GGG-   "###XYYYUVVVSTTTFGGG:;;;,----...*+++-...GGGYf---F-3ZZ	-B-BJ6::fb)))D M'(((o&&&  C!$3!7!7JcXss!3cccC
OcccT^cccdddwwx(( KItyyX/G/GIIJJJB377+;R#@#@BBCCCww}-- CAS-?AABBBGGGG KLLLGGGFAY__&&
|F122J''<FYftE{KKKF-3ZZ	-B-BJ6::fb)))D 0111GGG#$$$(OOO  .s8}..///.V..///9#'''3"7"799:::QS_QQ#8N8NQQQRRRDSWW]E%B%BDDEEE778$$ CAtyyX'?'?AABBBB377+;R#@#@BBCCC77=)) _]]);]]sww}VY?Z?Z]]]^^^F***}-K BCCCJ'9;q>H(^@sxxABB'@'@F&&tH~66F & KLLLY!~&\YH~~  F zz)$$ L?VH-=??@@@9VJ%799:::::h'' FDtyy1A'B'BDDEEE<VM%:<<====JVZZ5H5HJJKKKF}-K fggg ^FvH 6f66777L!2!24>!B!B**4+=>>J 1 1$2G H HIIM"8<<#9#9#{U\H]H]>zbbdldpdpqxdydycz||ON# 3!# 31 3} 3aaaa?aaa' 3 3EL00$++E222Yj)H~&\YH~#	 	 	F zz)$$ 	LUm<S]<<===6S_66777778$$ ,AtyyX'?'?AABBBB*++++JVZZ5H5HJJKKKFMMM}-K AJAAABBB ^F!+/I!I!IXXzFYfV[ael[l[lDWDWrvwwwF::i(( LLLvzz'7J7JLLMMM  NF5M&,ANNVNNNOOOO8##OVE]6-BOOfOOOPPPGVE]%6%6}%E%EGGHHHH5Qve}V/DQQQQQRRRABBBB **]B77UW[[-H-HUUFUUUVVVF9Z99:::HIIIIIrL   c                 B    ddl m}  ||t                                 dS )uD   Handle /skills slash command — delegates to hermes_cli.skills_hub.r   )handle_skills_slashN)hermes_cli.skills_hubrF  r  )r  r  rF  s      rC   _handle_skills_commandz HermesCLI._handle_skills_command  s1    ======C/////rL   c                 N   ddl m}m} t                       t          d           t          d           t          d           t                       	  |            }t          d           t          d           |j        d|j        d|j        d	i}|                                D ]|\  }\  }}|j        	                    |          }|rA|j
        r:|                    |          }	|	r
d
|	j         nd}
t          d|dd|
            et          d|dd| d           }t                       t          d           t          d           |j        }t          d|j                    t          d|j         d           t          d|j         d           t                       t          d           t          d           t                       t          dt#                       d           t                       d"S # t$          $ r}t          d|            t                       t          d           t          d           t          d           t          d            t          d!t#                       d           t                       Y d"}~d"S d"}~ww xY w)#z=Show status of the gateway and connected messaging platforms.r   )load_gateway_configPlatformz>+------------------------------------------------------------+u?   |               (✿◠‿◠) Gateway Status                 |z#  Messaging Platform Configuration:z9  -------------------------------------------------------)TelegramTELEGRAM_BOT_TOKEN)DiscordDISCORD_BOT_TOKEN)WhatsAppWHATSAPP_ENABLEDu    → rO   u       ✓ r  z Enabledu       ○ z Not configured (r  z  Session Reset Policy:z
    Mode: z    Daily reset at: z:00z    Idle timeout: z minutesz  To start the gateway:z    python cli.py --gatewayz  Configuration file: z/config.yamlz   Error loading gateway config: z  To configure the gateway:z!    1. Set environment variables:z$       TELEGRAM_BOT_TOKEN=your_tokenz#       DISCORD_BOT_TOKEN=your_tokenz     2. Or configure settings in N)gateway.configrJ  rK  r  TELEGRAMDISCORDWHATSAPPr  	platformsr   r   get_home_channelrn   default_reset_policyr<  at_houridle_minutesr(   r>   )r  rJ  rK  r  platform_statusrb  rn   r-  pconfighomehome_strpolicyrB   s                rC   _show_gateway_statuszHermesCLI._show_gateway_status  s   @@@@@@@@"###OPPP"###,	((**F7888/""" !#E "B!#CO .=-B-B-D-D L L)/4 *..x88 Lw L!228<<D6:B2ty222HATAAAxAABBBBJTJJJJJJKKKKGGG+,,,/"""0F,v{,,---<<<<===Dv':DDDEEEGGG+,,,/000GGGN+>+@+@NNNOOOGGGGG 	 	 	8Q88999GGG/000566689997888X5H5J5JXXXYYYGGGGGGGGG	s   F1H 
J$B	JJ$c           
      '  ?@ |                                                                 }|                                }ddlm} |                                d                             d          } ||          }|r|j        n|}|dv rdS |dk    r|                                  n3|dk    r|                                  n|dk    r| 	                    |           n|d	k    r| 
                                 n|d
k    r|                                  n|dk    r|                     d           | j        rK| j        j        }|                                 |                    dd           |                                 n| j                                         | j        r|t)                      }	t+          j                    j        }
| j        s|
dk     r"|	                    t5                                 nt7          | j        d          }t;          j        dt;          j                              }d}tA          | d          r-| j!        r&tA          | j!        d          r| j!        j"        j#        }tI          |	| j%        ||| j        | j&        |           tO          d           	 ddl(m)}  |            }	 ddl*m+}  |            ,                    dd          }n# tZ          $ r d}Y nw xY w|	                    d| d| d           n# tZ          $ r Y nw xY w| .                                 t3          d           	 ddl(m)}  |            }	 ddl*m+}  |            ,                    dd          }n# tZ          $ r d}Y nw xY w| j                            d| d| d           n'# tZ          $ r Y nw xY w|dk    r| /                                 n|dk    r_|                    d           }ta          |          dk    r|d                                         }|rW| j1        r>	 dd!l2m3} |4                    |          }n+# tj          $ r}tO          d"|            d}Y d}~nd}~ww xY w|stO          d#           nI| j1        6                    | j&                  ro	 | j1        7                    | j&        |          rtO          d$|            ntO          d%           n# tj          $ r}tO          d"|            Y d}~nd}~ww xY w| j1        8                    |          }|rtO          d&| d'|d(                     n|| _9        tO          d)| d*           nftO          d+           nUtO          d,           nD| j1        rtO          d-| j&                    | j1        6                    | j&                  }|r/|:                    d          rtO          d.|d                     n| j9        rtO          d/| j9                    ntO          d0           ntO          d+           n|d1k    r|                                  nx|d2k    r| ;                    |           n[|d3k    r| <                    |           n>|d4k    r| =                                 n"|d5k    r| >                    |           n|d6k    r| ?                    |           n|d7k    r| @                    |           n|d8k    rB| A                                }|r*tA          | d9          r| jB        C                    |           n|d:k    r| D                                 ng|d;k    r| E                    |           nJ|d<k    r| F                                 n.|d=k    r| G                    |           n|d>k    rW| H                    | I                    |                    5  | J                    |           ddd           n# 1 swxY w Y   n|d?k    r| K                                 n|d@k    r| L                                 n||dAk    r7| jM         | _M        | jM        rdBndC}| j                            dD|            n?|dEk    r| N                                 n#|dFk    r| O                                 n|dGk    r| P                    |           
n|dHk    r| Q                    |           
n|dIk    r| R                    |           
n|dJk    r| S                                 
n|dKk    r| T                    |           
nw|dLk    r| U                                 
n[|dMk    r| V                                 
n?|dNk    r| W                    |           
n"|dOk    r%ddPlXmY}  |            }t3          dQ| dR           	n|dSk    rV| H                    | I                    |                    5  | Z                                 ddd           n# 1 swxY w Y   	n|dTk    r| [                    |           	n~|dUk    rv	 ddVl\m]}  |            }|^                                }|s/t3          dW           t3          dXt                       dY           nt3          dZta          |           d[           |D ]} | d\         rd]nd^}!| d_         rd`| d_          nda}"| d         r| d          dbnda}| dc         r| dc          ddnda}#| :                    de          r| de          dfnda}$dg ||#|$fD             }|rdhdi`                    |           djnda}%| dk         rdl| dk          nda}&t3          d"|! dm| dn          |" |% |&            Ґn+# tZ          $ r}t3          do|            Y d}~n	d}~ww xY w|dpk    r| a                    |           n|dqk    r| b                    |           n|drk    r| c                                 n|dsk    r| d                    |           n|dtk    r| e                    |           nq|duk    r|                    dd          }ta          |          dk    r|d                                         nda}'|'stO          dv           n| jB        C                    |'           | jf        r3tO          dw|'dd          ta          |'          dk    rdxnda            ntO          dy|'dd          ta          |'          dk    rdxnda            n|dzk    r| g                    |           no|d{k    r| h                    |           nR|                                d         }(| ji        :                    d|i           })|(                    d          |)v rV|)|(                    d                   }*|*:                    d}          d~k    r+ddlj}+|*:                    dda          },|,r	 |+k                    |,dddd          }-|-jl                                        p|-jm                                        }.|.r(| j                            t          |.                     n| j                            d           n!# |+jo        $ r | j                            d           Y ntZ          $ r)}| j                            d| d           Y d}~nd}~ww xY w| j                            d|( d           n|*:                    d}          dk    r|*:                    dda                                          }/|/rs|/p                    d          r|/nd|/ }/|ta          |(          d                                         }0|/ dm|0                                 }1| q                    |1          S | j                            d|( d           n| j                            d|( d           n|(                    d          t                      v rddl\ms}2  |2|(                    d                    }3|3r|ta          |(          d                                         }0	  |3|0          }-|-rtO          t          |-                     n# tZ          $ r$}tO          d| t                      Y d}~nd}~ww xY wn|(t          v r|ta          |(          d                                         }4t          |(|4| j&                  }5|5rQt          |(         dn         }6t3          d|6            tA          | d9          r| jB        C                    |5           nBt)                                          d|( d           nddlmx}7 |                                d         @t          |7          t          t                    z  }8@fd|8D             }9ta          |9          dk    r`@fd|9D             }:ta          |:          dk    r|:}9n<t          d |9D                       ??fd|9D             };ta          |;          dk    r|;}9ta          |9          dk    r|9d         }<|<@k    r?tO          d| t                      tO          t           t           dt                      n|                                ta          @          d         }=|<|=z   }>| q                    |>          S ta          |9          dk    rbtO          t           d| t                      tO          t           ddi`                    t          |9                     dt                      n>tO          d| t                      tO          t           t           dt                      dS )z
        Process a slash command.
        
        Args:
            command: The command string (starting with /)
            
        Returns:
            bool: True to continue, False to exit
        r   r  rk  )quitexitqFhelpprofiler  r  r  r  T)r0  rz  r  r   Nr   r  r  uI     ✨ (◕‿◕)✨ Fresh start! Screen cleared and conversation reset.
get_random_tipr  r  r  r  
   ]✦ Tip: r  r  r  r  r  r  r  z@  Title is empty after cleanup. Please use printable characters.z  Session title set: z   Session not found in database.z	  Title 'z' is already in use by session rM  z  Session title queued: z! (will be saved on first message)r3  z$  Usage: /title <your session title>z  Session ID: z	  Title: z  Title (pending): z2  No title set. Usage: /title <your session title>newr  r   r   gquotapersonalityplanretryr@  undor  savecronr  rV  r  	statusbarvisiblehiddenz  Status bar r   yolorB  rV   compressusageinsightsr  pasteimagereload)
reload_envz  Reloaded .env (z var(s) updated)z
reload-mcpr   pluginsr  zNo plugins installed.zDrop plugin directories into z/plugins/ to get started.z	Plugins (z):r   u   ✓u   ✗versionz vrO   z toolshooksz hooksr  z	 commandsc                     g | ]}||S r  r  r  xs     rC   r  z-HermesCLI.process_command.<locals>.<listcomp>  s     J J Jq J J J JrL   r  r  r  r      — rA  rn   zPlugin system error: rollbackr  stop
backgroundbtwr  z  Usage: /queue <prompt>  Queued for the next turn: r}  z
  Queued: r   voicequick_commandsrS  execrV  r  )shellrt  ru  r   z"[dim]Command returned no output[/]z*[bold red]Quick command timed out (30s)[/]z[bold red]Quick command error: z[bold red]Quick command 'z' has no command defined[/]aliasr:  z' has no target defined[/]z6' has unsupported type (supported: 'exec', 'alias')[/])get_plugin_command_handlerz[1;31mPlugin command error: task_idu   
⚡ Loading skill: z#[bold red]Failed to load skill for )COMMANDSc                 >    g | ]}|                               |S r  r  r  c
typed_bases     rC   r  z-HermesCLI.process_command.<locals>.<listcomp>  s*    LLL1<<
3K3KL1LLLrL   c                      g | ]
}|k    |S r  r  r  s     rC   r  z-HermesCLI.process_command.<locals>.<listcomp>  s    CCC11
??Q???rL   c              3   4   K   | ]}t          |          V  d S r_   rH  )r  r  s     rC   r  z,HermesCLI.process_command.<locals>.<genexpr>%  s(      %>%>c!ff%>%>%>%>%>%>rL   c                 :    g | ]}t          |          k    |S r  rH  )r  r  min_lens     rC   r  z-HermesCLI.process_command.<locals>.<listcomp>&  s)    #L#L#L!#a&&G:K:KA:K:K:KrL   z[1;31mUnknown command: z!Type /help for available commandszAmbiguous command: zDid you mean: r\  )~rY   rI   r  r  r  r(  rn   r  r  r  r  r  r  r5  r]  erase_screencursor_gotoflushr  r  r  rl   r  r  r   r  r  rJ  r'  r`   rL  r  rl  r   r  r  rL  r   ra  r*  hermes_cli.tipsrh  r	  r  r
  r>   r  r  r  r8  r9  r  sanitize_titler~  r  r  get_session_by_titler:  r   r<  r  r  r  r  _handle_plan_commandrW  r@  putr4  rJ  rR  rD  rw  rp  rH  r`  r  re  _toggle_verbose_toggle_yolo_handle_reasoning_command_handle_fast_command_manual_compress_show_usage_show_insights_handle_debug_commandrm  ru  r  r|  _reload_mcp_handle_browser_commandrj  r  list_pluginsr(   r   r8  r[  rh  _handle_background_command_handle_btw_commandr>  _handle_skin_command_handle_voice_commandr  rv  rw  ry  r  r&  TimeoutExpiredr  process_commandr  r  rX   r  r  r  r  r   r  r  ra  r  )Ar  rV  ro  rn  _resolve_cmd
_base_word_cmd_defr  r  ccterm_wr  r   r  rh  _tipr  
_tip_colorr   	raw_titler  	new_titlerB   r  r  	retry_msgr  r|  countr  r5  r}  rb  r  r~  r  r  detailr  payloadbase_cmdr  qcmdrv  exec_cmdrJ   r]  r:  	user_argsaliased_commandr  plugin_handleruser_instructionr  
skill_namer  	all_knownmatchesexactshortest	full_namerG  full_cmdr  r  sA                                                                  @@rC   r  zHermesCLI.process_command  s    MMOO))++	}} 	HGGGGG__&&q)0055
<
++%-=HMM:	---5&  NN)##((****'!!&&|4444*$$    (""'!!D)))
 y %i&  """1%%%		""$$$
 y / ]]133;< 6B;;HH24455550$BWdhiiiE)NBIKK@@C"GtW-- O$* OUiAjAj O"&*"?"N( ""j#)-)>#'?'.    deee
>>>>>>)>++D/JJJJJJ%4_%6%6%@%@y%Y%Y

$ / / /%.


/HHDZDD4DDDEEEE    D   """bccc
>>>>>>)>++D/JJJJJJ%4_%6%6%@%@y%Y%Y

$ / / /%.


/L&&'Nz'N'NT'N'N'NOOOO    D)##'!! &&&22E5zzA~~!!HNN,,	  D' E->>>>>>(1(@(@(K(KII) - - -#HHH---(,IIIIII-  ) q#$fgggg!-99$/JJ q2#'#3#E#EdoW`#a#a !P$+,OI,O,O$P$P$P$P$+,N$O$O$O#- 2 2 2 'Q 1 1 1 1 1 1 1 12
 (,'7'L'LY'W'WH' q '(nI(n(n^fgk^l(n(n o o o o6? 3 '(o9(o(o(o p p p p CDDDDBCCCC # 
A>T_>>???".::4?KKG V7;;w#7#7 V >GG,< > >????, V Kd6I K KLLLL TUUUU?@@@@%(""''5555'!!%%l3333*$$**,,,,(""''5555-'',,\::::&  %%l3333'!!))I 3WT+;<< 3#''	222&  NN(""''5555&  ""$$$$&  %%l3333(""##D$=$=l$K$KLL : :++L999: : : : : : : : : : : : : : :+%%%%''''(""%%''''+%%+/+C'CD$!%!9GIIxEL6u667777)##  """"&  +%%**<8888&  %%l3333*$$!!,////'!!*$$----'!!&&(((('!!&&(((('!!&&|4444(""444444JLLE=e===>>>>,&&##D$=$=l$K$KLL # #  """# # # # # # # # # # # # # # #)##((6666)##3AAAAAA((****,, Q1222j:M:O:Ojjjkkkk6c'll666777$ 	Q 	Q*+I,!AE9:9"M"5q|"5"5"529:7 K1W: 5 5 5 59:7 K1W: 5 5 5 5BC%%
BSBS#[a
m#>#>#>#>Y[ J JUE8,D J J J=B!J!9dii&6&6!9!9!9!989'
 J 4'
 4 4 4O6OOAfIOwOOOOPPPP 3 3 31a11222222223*$$)),7777*$$)),7777&  %%'''',&&++L9999%$$\2222'!! &&tQ//E*-e**q..eAhnn&&&bG ]23333#''000& ]m73B3<mRUV]R^R^acRcRcikmmnnnn["[Gr@Q@QuuWY[[\\\\&  %%l3333'!!&&|4444 !((+H![__-=rBBNs##~55%hooc&:&:;88F##v--%%%%#xx	266H nY%/^^ (T%)2 &4 & &F &,]%8%8%:%:%Sfm>Q>Q>S>SF% Y $ 2 23G3O3O P P P P $ 2 23W X X X)8 ] ] ] L../[\\\\\( Y Y Y L../WQR/W/W/WXXXXXXXXY **+lx+l+l+lmmmmXXf%%00!XXh3399;;F m+1+<+<S+A+A!S|6||$0X$@$F$F$H$H	-3*A*Ai*A*A*G*G*I*I#33ODDD**+kx+k+k+kllllL&&  (D8  (D  (D  (D  E  E  E  E%%)F)H)HHHIIIIII!;!;HOOC<P<P!Q!Q! N ,S]]^^ < B B D DIN!/	!:!:! 1#CKK000$ N N N L1 Ld L LMMMMMMMMNN _,,#/H#?#E#E#G#G 4.    ]!0!:6!BJ>*>>???t%566 5+//444MM''([h([([([\\\\
 988888&__..q1
MMC,@,@@	LLLLiLLLw<<!##CCCCCCCE5zzQ"' #&%>%>g%>%>%>">">#L#L#L#Lw#L#L#Lx==A--&.Gw<<1$$
 !(
I J.. Oi O O OPPP4 Y Y YSW Y YZZZZ$0$6$6$8$8Z9I9I$J	#,y#8#33H===\\A%%wLL9LdLLMMMtVV499VG__3M3MVVPTVVWWWWK)KTKKLLLtUWUUtUUVVVts  .L ?$K$ #L $K30L 2K33L 
L"!L"	N4 $M? >N4 ?NN4 N$N4 4
OO8Q 
Q<Q77Q<2AS6 6
T TT8``!`h33h7:h7%E	n0 0
o:oo(Bz: :$|!	|*||B)AC
 C

AC8CAC3C3AC8c                    |                                                     d          }t          |          dk    r|d                                          nd}t          |          }t	          d|| j        d|           }|s#t                                          d           dS t          d	|            t          | d
          r| j
                            |           dS t                                          d           dS )u7   Handle /plan [request] — load the bundled plan skill.r  r  rO   z/planzlSave the markdown plan with write_file to this exact relative path inside the active workspace/backend cwd: )r  runtime_notez3[bold red]Failed to load the bundled /plan skill[/]Nu9     📝 Plan mode queued via skill. Markdown plan target: r@  z?[bold red]Plan mode unavailable: input queue not initialized[/])rI   r  r  r  r  ra  r  r  r*  rl  r@  r  )r  r  r   r  	plan_pathr  s         rC   r  zHermesCLI._handle_plan_command@  s   		!!1!--/25zzA~~58>>+++2#$455	,OH<EH H
 
 
  	MM UVVVFWIWWXXX4)** 	c##C(((((MM abbbbbrL   c           	          |                                                     d          }t          |          dk     s|d                                          s/t          d           t          d           t          d           dS |d                                           xj        dz  c_         j        dt          j                                        d	           d
t          j	                    j
        dd                                           st          d           dS t          d ddd          t                    dk    rdnd d           t          d            t          d                                           fd}t          j        |dd           }| j        <   |                                 dS )u  Handle /background <prompt> — run a prompt in a separate background session.

        Spawns a new AIAgent in a background thread with its own session.
        When it completes, prints the result to the CLI without modifying
        the active session's conversation history.
        r  r  r@  z  Usage: /background <prompt>z9  Example: /background Summarize the top HN stories todayzI  The task runs in a separate session and results display here when done.Nbg_%H%M%Sr  r  z;  (>_<) Cannot start background task: no valid credentials.u     🔄 Background task #z started: "r   r}  rO   r=  z  Task ID: u?     You can continue chatting — results will appear when done.
c                  	   	 t          dFi dd         dd                             d          dd                             d          dd                             d          dd                             d          dd                             d          d	d                             d
          dj        dj        ddddddddj        dj        dj        d                    d          dj        dj        dj	        dj
        dj        dj        dj        } d | _        d t          d!d ffd"}|| _        |                     #          }|r|                    d$d%          nd%}|s"|r |                    d&          rd'|d&          }j        r2j                                         d(d l}|                    d)           t-                       t/                                          d*t1                       d+d, d-           t3          d. d/           t3          d0d d1          t5                    d1k    rd2nd% d3           t/                                          d*t1                       d+d, d-           |r	 d(d4lm}  |            }|                    d5d6          }|                    d7d8          }|                    d9d:          }	n# t>          $ r	 d6}d8}d:}	Y nw xY wt/                      }
|
                    tA          tC          |          d*| d;| d< d=d>||	tD          j#        d?@                     nt3          dA           j$        r=tJ          j&        '                    dB           tJ          j&        (                                 ns# t>          $ rf}j        r2j                                         d(d l}|                    d)           t-                       t3          dC dD|            Y d }~nd }~ww xY wj)        *                    d            j+        sd%_,        j        r-                    d(E           d S d S # j)        *                    d            j+        sd%_,        j        r-                    d(E           w w xY w)GNr   r   r  r   r   r$  r%  rV  r&  r  r   r'  r  Tr  Fra  rb  r;  r  r+  r   r  r  r  r  r  r  r  r  c                      d S r_   r  )_a_kws     rC   r  zNHermesCLI._handle_background_command.<locals>.run_background.<locals>.<lambda>  s     rL   ru  r-   c                 l    j         s)| _        j        rj                                         d S d S d S r_   )r>  rR  r5  ry  )ru  r  s    rC   _bg_thinkingzRHermesCLI._handle_background_command.<locals>.run_background.<locals>._bg_thinking  sN    . 3-1*9 3 I00222223 33 3rL   )r  r  final_responserO   r  Error: r   皙?r  rY  r  r  u     ✅ Background task #z	 completez  Prompt: "r   r}  r=  r  rZ  r[  r  #CD7F32r\  r]   bold]z (background #r  leftr  r"  r  title_alignr  r   rB  r  z  (No response generated)u     ❌ Background task #z	 failed: rv  r  ).rI  r   r   r'  r8  r+  r   r-  r.  r/  r,  r0  r1  r2  r  rX   r  run_conversationr5  ry  r  sleepr  r  r!  r*  r  r	  r  r  r
  r>   rF  r&  rich_boxHORIZONTALSr  sysry  r  r  rf  r  r>  rR  r{  )bg_agentr  rJ   response_tmodr  r  rc  _resp_color
_resp_text_chat_consolerB   r  r  r  task_num
turn_routes               rC   run_backgroundz<HermesCLI._handle_background_command.<locals>.run_backgroundx  sN   h5"   $W--&y155i@@@ (	266zBBB (	266zBBB	
 (	266zBBB !+9 5 9 9) D D D (	266v>>> $(>> &*%:%:  $t %*E  'w #U  $// &*%:%:  "&!2!2!" '1nn5H&I&I&I#$ '+&:&:%& '+&<&<'( %)$9$9)* #'"5"5+, 150M0M-. .2-K-K/0 $(#7#716 &=%<"3s 3t 3 3 3 3 3 3 .:*!22!'# 3  
 @FM6::&6;;;2 ;F ;vzz'/B/B ;:::H
 9 &I((***((((KK%%%##$G$G$G
$G$G$GHHHE(EEEFFFYvcrc{YS[[2=M=MEESUYYYZZZ##$G$G$G
$G$G$GHHH 9	/JJJJJJ / 1 1 % 2 23C\ R R&+oo6G&S&S%*__]I%N%N

$ / / / ,&/%.


/
 %0MMM!'',X66X+XXUXX(XXX$*%0($0 &) ) )     7888 ( 'J$$T***J$$&&& J J J9 &I((***((((KK%%%H(HHQHHIIIIIIIIJ &**7D999* ,)+D&9 5$$!$444445 5	 &**7D999* ,)+D&9 5$$!$44445sX   J&O  *AK= <O  =LO  LB/O  ?Q=  
P0
AP+&Q= +P00Q= =A	STzbg-task-r:  daemonrn   )rI   r  r  r*  rg  r   r  r;  r  r  r  r  r  rL  Threadrf  start)	r  r  r   r  threadr  r  r  r  s	   `    @@@@rC   r  z$HermesCLI._handle_background_commandZ  s    		!!1!--u::>>q!1!1>3444OPPP_```Fq!!%%*%%0R//99RRDJLL<LRaR<PRR //11 	QRRRFs8sssWZ[aWbWbegWgWgeemosssttt'g''(((RSSS44V<<
i	5 i	5 i	5 i	5 i	5 i	5 i	5 i	5 i	5V !K_V]K_K_```*0w'rL   c                 T   	 |                                                     d          }t          |          dk     s|d                                          s/t          d           t          d           t          d           dS |d                                          dt	          j                                        d	           d
t          j                    j	        dd           
                                st          d           dS                                	t           j                  dd         t                    dk    rdndz   }t          d| d            	fd}t          j        |dd           }|                                 dS )u  Handle /btw <question> — ephemeral side question using session context.

        Snapshots the current conversation history, spawns a no-tools agent in
        a background thread, and prints the answer without persisting anything
        to the main session.
        r  r  r@  z  Usage: /btw <question>z<  Example: /btw what module owns session title sanitization?z9  Answers using session context. No tools, not persisted.Nbtw_r  r  r  z0  (>_<) Cannot start /btw: no valid credentials.r   r}  rO   u     💬 /btw: "r=  c            
         	 t          d7i dd         dd                             d          dd                             d          dd                             d          dd                             d          dd                             d          d	d                             d
          dddg dddddddd
j        d
j        d                    d          d
j        d
j        d
j        d
j        d
j        d
j	        d
j
        dd d dd!dd"d} d#	z   }|                     |$          }|r|                    d%          pd&nd&}|s"|r |                    d'          rd(|d'          }
j        r-
j                                         t          j        d)           t!                       |r	 d*d+lm}  |            }|                    d,d-          }n# t(          $ r d-}Y nw xY wt+                                          t-          t/          |          d.| d/d0|t0          j        d12                     nt5          d3           
j        r=t8          j                            d4           t8          j                                         nk# t(          $ r^}
j        r-
j                                         t          j        d)           t!                       t5          d5|            Y d }~nd }~ww xY w
j        r
                     d*6           d S d S # 
j        r
                     d*6           w w xY w)8Nr   r   r  r   r   r$  r%  rV  r&  r  r   r  r'  r  Tr  Fra  rb  r;  r+  r   r  r  r  r  r  r  r  r  r  skip_memoryskip_context_filespersist_sessionzs[Ephemeral /btw side question. Answer using the conversation context. No tools available. Be direct and concise.]

)r  rd  r  r  rO   r  r  r  r   r  r  z#4F6D4Ar  u    bold]⚕ /btw[/]r  r  )r  r  r  rB  r  u     💬 /btw: (no response)r  u     ❌ /btw failed: rv  r  )!rI  r   r+  r   r-  r.  r/  r,  r0  r1  r2  r  r5  ry  r  r  r  r	  r  r
  r>   r  rF  r&  r  r  r*  r  r  ry  r  r  r{  )	btw_agent
btw_promptrJ   r  r  r  r  rB   history_snapshotquestionr  r  r  s           rC   run_btwz.HermesCLI._handle_btw_command.<locals>.run_btw  s   S5#   $W--&y155i@@@ (	266zBBB (	266zBBB	
 (	266zBBB !+9 5 9 9) D D D (	266v>>> $%1 &(R  $t %*E  'w #U &*%:%: "&!2!2  '1nn5H&I&I&I!" '+&:&:#$ '+&<&<%& %)$9$9'( #'"5"5)* 150M0M+, .2-K-K-. $(#7#7/0  $t12 !%34 (,t56 %*E7	>O 
 #33!+)9# 4   DJQFJJ'788>Br ;F ;vzz'/B/B ;:::H 9 %I((***Jt$$$ :0JJJJJJ / 1 1&+oo6G&S&S$ 0 0 0&/0  MM'',X66@+@@@$*%0$0 &) ) )     8999( 'J$$T***J$$&&& 3 3 39 %I((***Jt$$$1a11222222223 9 5$$!$444445 549 5$$!$44445sV   GJ8 &H J8 HJ8 HB&J8 7M 8
L ALM L  M  M$Tzbtw-r  )rI   r  r  r*  r   r  r;  r  r  r  r  r  r=   rd  rL  r  r  )
r  r  r   r  r  r  r  r   r  r  s
   `     @@@@rC   r  zHermesCLI._handle_btw_command  s    		!!1!--u::>>q!1!1>.///RSSSOPPPF8>>##S00::SSTZ\\=Mbqb=QSS//11 	FGGGF44X>>
 9::3B3-CMMB,>,>55BG++++,,,T	5 T	5 T	5 T	5 T	5 T	5 T	5 T	5 T	5l !DT7DTDTUUUrL   portr\   c                    ddl }t          |          }|sdS t          t          dz            }t	          j        |d           |d         }	 |                    |d|  d| d	d
g|j        |j        d           dS # t          $ r Y dS w xY w)a*  Try to launch Chrome/Chromium with remote debugging enabled.

        Uses a dedicated user-data-dir so the debug instance doesn't conflict
        with an already-running Chrome using the default profile.

        Returns True if a launch command was executed (doesn't guarantee success).
        r   NFchrome-debugTr  z--remote-debugging-port=z--user-data-dir=z--no-first-runz--no-default-browser-check)ry  r  start_new_session)	rv  r   rX   r5   r`   makedirsPopenDEVNULLr>   )r  r\   _sprg   data_dirrv   s         rC   _try_launch_chrome_debugz"HermesCLI._try_launch_chrome_debug[  s     	!   1&99
 	5 |n455
Ht,,,,A	II5t551x11$0 {{"&     4 	 	 	55	s   .A> >
BBc                    ddl }|                                                    dd          }t          |          dk    r,|d                                                                         nd}d}t
          j                            dd                                          }|                    d          r|                                                    dd	          }t          |          d	k    r|d	                                         n|}	 dd
l	m
}	  |	             n# t          $ r Y nw xY wt                       d}
	 t          |                    dd          d                             d          d                   }
n# t          t           f$ r Y nw xY wddl}d}	 |                    |j        |j                  }|                    d           |                    d|
f           |                                 d}n# t.          |j        f$ r Y nw xY w|rt          d|
            n||k    rt          d           |                     |
|                                          }|rddl}t9          d          D ]}	 |                    |j        |j                  }|                    d           |                    d|
f           |                                 d} n,# t.          |j        f$ r |                    d           Y w xY w|rt          d|
            nt          d|
 d           t          d           nt          d           t=          t>          dz            }|                                }|dk    rd| d}n|dk    rd | d}nd!| d}t          d"           t          d#|            nt          d$|
 d%|            |t
          j        d<   t                       t          d&           t          d'|            t                       tA          | d(          r| j!        "                    d)           dS dS |d*k    r|rt
          j        #                    dd           	 dd
l	m
}	  |	             n# t          $ r Y nw xY wt                       t          d+           t          d,           t                       tA          | d(          r| j!        "                    d-           dS dS t                       t          d.           t                       dS |dk    rt                       |rt          d/           t          d'|            d}
	 t          |                    dd          d                             d          d                   }
n# t          t           f$ r Y nw xY w	 ddl}|                    |j        |j                  }|                    d           |                    d|
f           |                                 t          d0           n# t.          t          f$ r t          d1           Y n_w xY w	 dd2l	m$}  |            }n# t          $ r d}Y nw xY w|&t          d3|%                                 d4           nt          d5           t                       t          d6           t          d7           t                       dS t                       t          d8           t                       t          d9           t          d:           t          d;           t                       dS )<uP   Handle /browser connect|disconnect|status — manage live Chrome CDP connection.r   Nr  r  zhttp://127.0.0.1:9222BROWSER_CDP_URLrO   connectr@  )cleanup_all_browsersi$  r&  r  rk  Fr  Tu+      ✓ Chrome is already listening on port uI      Chrome isn't running with remote debugging — attempting to launch...r  r   u-      ✓ Chrome launched and listening on port u       ⚠ Chrome launched but port z isn't responding yetuL        Try again in a few seconds — the debug instance may still be startingu#      ⚠ Could not auto-launch Chromer  rp   zMopen -a "Google Chrome" --args --remote-debugging-port=9222 --user-data-dir="z+" --no-first-run --no-default-browser-checkrq   z9chrome.exe --remote-debugging-port=9222 --user-data-dir="z<google-chrome --remote-debugging-port=9222 --user-data-dir="z     Launch Chrome manually:     u      ⚠ Port z is not reachable at u-   🌐 Browser connected to live Chrome via CDPz   Endpoint: r@  uJ  [System note: The user has connected your browser tools to their live Chrome browser via Chrome DevTools Protocol. Your browser_navigate, browser_snapshot, browser_click, and other browser tools now control their real browser — including any pages they have open, logged-in sessions, and cookies. They likely opened specific sites or logged into services before connecting. Please await their instruction before attempting to operate the browser. When you do act, be mindful that your actions affect their real browser — don't close tabs or navigate away from pages without asking.]
disconnectu*   🌐 Browser disconnected from live ChromezL   Browser tools reverted to default mode (local headless or cloud provider)z[System note: The user has disconnected the browser tools from their live Chrome. Browser tools are back to default mode (headless local browser or cloud provider).]zDBrowser is not connected to live Chrome (already using default mode)u.   🌐 Browser: connected to live Chrome via CDPu      Status: ✓ reachableu8      Status: ⚠ not reachable (Chrome may not be running))_get_cloud_provideru   🌐 Browser: z (cloud)u5   🌐 Browser: local headless Chromium (agent-browser)u8      /browser connect      — connect to your live Chromeu.      /browser disconnect   — revert to defaultz)Usage: /browser connect|disconnect|statuszA   connect      Connect browser tools to your live Chrome sessionz1   disconnect   Revert to default browser backendz)   status       Show current browser mode)&rb  rI   r  r  rY   r`   r   r   r  tools.browser_toolr  r>   r  r  rsplitr~  r  socketAF_INETSOCK_STREAM
settimeoutr  closer  r   r  r\   r  r  r  rX   r5   rl  r@  r  r  r  provider_name)r  r  _platr   r  _DEFAULT_CDPr  connect_partscdp_urlr  _portr  _already_openr  	_launchedrz  _wait	_data_dirsys_name
chrome_cmdr  r   s                         rC   r  z!HermesCLI._handle_browser_command  s       		!!$***-e**q..eAhnn$$&&&h.*..!2B77==??>>)$$ j	IIKK--dA66M25m2D2Dq2H2HmA&,,...lGCCCCCC$$&&&&    GGG EGNN32226<<SAA!DEE
+    MMM!MMM&.&2DEEQ		;.///			 $V^,     3LKEKKLLLLL((abbb 99%PP	 +0((((!&r 	- 	-- &fnf>P Q QALLOOOII{E&:;;;GGIII,0M!E '8 - - -!KK,,,,,-$ nUeUUVVVV]]]]^^^lmmmm?@@@ #L>$A B BI$||~~H8++I1:I I I #
 "Y..J1:J J J #
J1:J J J #
 9:::.*..////JUJJJJKKK,3BJ()GGGABBB+'++,,,GGG t-.. 	#''T    	 	 L   
0$777GGGGGG((****    DBCCCdeee4!122 '++n      \]]]H__GGG SFGGG/g//000sA 6 6r : @ @ E Ea HIIEE"J/   DV!MMMfnf6HIIALLOOOII{E2333GGIII45555+ V V VTUUUUUV$FFFFFF2244HH  $ $ $#HHH$ 'M8+A+A+C+CMMMNNNNQRRRGGGLMMMBCCCGGGGG GGG=>>>GGGUVVVEFFF=>>>GGGGGs   D! !
D.-D.AF FF#A"H HH	A"K--&LLR 
R#"R#7AV: :WWA3Y  Y)(Y)-Y> >ZZc                    	 ddl m}m}m} n # t          $ r t          d           Y dS w xY w|                                                    d          }t          |          dk     s|d                                         s |            } |            }t          d|            t          d	           |D ]R}|d
         |k    rdnd}	|d         dk    rd|d          dnd}
t          d|	 d|d
          |
 d|d                     St          d           t          dt                       d           dS |d                                         
                                }d  |            D             }||vrFt          d|            t          dd                    t          |                                dS  ||           t                                           t                                           t!          d|          rt          d| d           nt          d|            t          d            |                                 rt          d!           dS dS )"u8   Handle /skin [name] — show or change the display skin.r   )
list_skinsset_active_skinget_active_skin_namezSkin engine not available.Nr  r  r@  z
  Current skin: z  Available skins:rn   u    ●r  r  r  r  r  rO   r  rA  r  r  z
  Usage: /skin <name>z$  Custom skins: drop a YAML file in z/skins/
c                     h | ]
}|d          S )rn   r  )r  r  s     rC   	<setcomp>z1HermesCLI._handle_skin_command.<locals>.<setcomp>O  s    5551QvY555rL   z  Unknown skin: z  Available: r  zdisplay.skinz  Skin set to: z (saved)z8  Note: banner colors will update on next session start.z  Prompt + TUI colors updated.)r	  r(  r)  r*  r  r  rI   r  r  r(   rY   r   r  ra  r  r  r  _apply_tui_skin_style)r  r  r(  r)  r*  r   r  skinsr  r  r  new_skinr  s                rC   r  zHermesCLI._handle_skin_command7  s   	``````````` 	 	 	.///FF	 		!!1!--u::>>q!1!1>**,,GJLLE0w00111&''' Q Q#$V9#7#7T01(v0E0E,ak,,,,2OFOOQvYOOOQ}=MOOPPPP+,,,Y9L9N9NYYYZZZF8>>##))++55

555	9$$/X//000@$))F9,=,=">">@@AAAF!!!

^X66 	06H6667777.H..///HIII%%'' 	4233333	4 	4s   
 **c                 R   g d}	 |                     | j                  }n# t          $ r d}Y nw xY w||dz   t          |          z           | _        | j        dk    | _        | j        rA| j        | j        _        | j         | j        _        |                                 | j        _	        ddl
m} |j         d|j         d|j         d	|j         d
|j         d|j         d|j         |j         d|j         dd}t#          |                    | j        d                     dS )uB   Cycle tool progress mode: off → new → all → verbose → off.)rP   rj  r  r   r@  r  r   r   ColorszTool progress: OFFu*    — silent mode, just the final response.zTool progress: NEWu'    — show each new tool (skip repeats).zTool progress: ALLu    — show every tool call.zTool progress: VERBOSEu6    — full args, results, think blocks, and debug logs.rO   N)r  r  r~  r  r   r   r  r  r  r  hermes_cli.colorsr2  DIMRESETYELLOWGREENBOLDr*  r   )r  cyclerQ  _Colorslabelss        rC   r  zHermesCLI._toggle_verbose`  ss   000	++d566CC 	 	 	CCC	"'qCJJ(>"?.);: 	O)-DJ&(,$4DJ!,0,L,L,N,NDJ) 	877777knnW]nnnnnnnnnm``w}```!,  S  S  SW]  S  S  S	
 
 	

42B7788888s   ! 00c                 V   ddl }ddlm} t          |j                            d                    }|rD|j                            dd           t          d|j         |j	         d|j
         d           dS d|j        d<   t          d	|j         |j         d
|j
         d           dS )uA   Toggle YOLO mode — skip all dangerous command approval prompts.r   Nr1  HERMES_YOLO_MODEu     ⚠ YOLO mode OFFu.    — dangerous commands will require approval.r
   u     ⚡ YOLO mode ONu2    — all commands auto-approved. Use with caution.)r`   r3  r2  r  r   r   r  r*  r8  REDr5  r7  )r  r`   r:  r  s       rC   r  zHermesCLI._toggle_yolo|  s   			777777rz~~&899:: 	JNN-t444A7< A A A A A A    
 .1BJ)*E7< E E E'- E E E    rL   c                    |                                                     d          }t          |          dk     r| j        }|d}n0|                    d          du rd}n|                    d	d
          }| j        rdnd}t          dt           d| t                      t          dt           d| t                      t          dt           dt                      dS |d                                          
                                }|dv r|d| _        | j        r|                                 | j        _        t          dd           t          dt           dt                      t          dt           dt                      dS |dv r]d| _        | j        r|                                 | j        _        t          dd           t          dt           dt                      dS t          |          }|at          dt           d| t                      t          dt           dt                      t          dt           dt                      dS || _        d| _        t          d|          r$t          dt           d| dt                      dS t          dt           d| dt                      dS )u  Handle /reasoning — manage effort level and display toggle.

        Usage:
            /reasoning              Show current effort level and display state
            /reasoning <level>      Set reasoning effort (none, minimal, low, medium, high, xhigh)
            /reasoning show|on      Show model thinking/reasoning in output
            /reasoning hide|off     Hide model thinking/reasoning from output
        r  r  r@  Nzmedium (default)r   Fznone (disabled)rE   mediumu   on ✓rP   r  zReasoning effort:  zReasoning display: z@Usage: /reasoning <none|minimal|low|medium|high|xhigh|show|hide>)showrU   Tzdisplay.show_reasoningu!   ✓ Reasoning display: ON (saved)z>  Model thinking will be shown during and after each response.)hiderP   u"   ✓ Reasoning display: OFF (saved)(._.) Unknown argument: z5Valid levels: none, minimal, low, medium, high, xhighzDisplay:      show, hidezagent.reasoning_effortu   ✓ Reasoning effort set to 'r  r  )rI   r  r  r+  r   r   r*  ra  r  r  rY   r   r  r  r  rK   )r  r  r   rcleveldisplay_stateargr  s           rC   r  z#HermesCLI._handle_reasoning_command  s    		!!1!--u::>>&Bz*	""e++)x22(,(;FHHMBBBUBDBBCCCJJJ]JDJJKKKeee_ceefffFAhnn$$&& .  "&Dz S040P0P0R0R
-6===III4IIJJJccc]accdddF/!!"'Dz S040P0P0R0R
-6>>>JJJDJJKKKF )-->BBBsBDBBCCCZZZTXZZ[[[===t==>>>F &
5s;; 	\]]]s]]W[]]^^^^^ZZZsZZTXZZ[[[[[rL   c           
      f   |                                  st          d           dS 	 ddlm} t	          | dd          }t	          |dd          pt	          | dd          } ||          rdnd}n# t
          $ r d	}Y nw xY w|                                                    d
          }t          |          dk     s0|d
                                         	                                dk    rS| j
        dk    rdnd}t          dt           | d| t                      t          dt           dt                      dS |d
                                         	                                }|dv rd| _
        d}	d}
nR|dv rd| _
        d}	d}
nBt          dt           d| t                      t          dt           dt                      dS d| _        t          d|	          r't          dt           d| d|
 dt                      dS t          dt           d| d|
 dt                      dS )uU   Handle /fast — toggle fast mode (OpenAI Priority Processing / Anthropic Fast Mode).zv  (._.) /fast is only available for models that support fast mode (OpenAI Priority Processing or Anthropic Fast Mode).Nr   )_is_anthropic_fast_modelr   r   zAnthropic Fast ModezPriority Processingz	Fast moder  r  r@  r  rW   rV   rR   r  r  z!Usage: /fast [normal|fast|status]>   rU   rV   FAST>   rP   rR   NORMALrE  zagent.service_tieru   ✓ z set to z (saved to config)z (session only))r  r*  r  rK  rm  r>   rI   r  r  rY   r   ra  r  r  r   r  )r  r  rK  r   r   feature_namer   r  rI  saved_valuerc  s              rC   r  zHermesCLI._handle_fast_command  s   ++-- 	  M  N  N  NF	'BBBBBBD'400EE7D11QWT7D5Q5QE4L4LU4S4Sn00YnLL 	' 	' 	'&LLL	' 		!!1!--u::>>U1X^^--3355AA#0J>>VVHF@@,@@&@$@@AAAFFFFFGGGFAhnn$$&&.   *D KEE%%% $D"KEEBBBsBDBBCCCFFFFFGGGF
1;?? 	Z[[[l[[E[[UY[[\\\\\XXXlXXEXXRVXXYYYYYs   AA0 0A?>A?c                 l    |sdS t          | dd          |z   | _        |                     d           dS )zCCallback for intermediate reasoning display during tool-call loops.Nr  rO   Fr  )rm  r  r  )r  r	  s     rC   r  zHermesCLI._on_reasoning  sG     	F&-d4Lb&Q&QTb&b#%%E%22222rL   rO   c           	      2   | j         rt          | j                   dk     rt          d           dS | j        st          d           dS | j        j        st          d           dS d}|rU|                                                    dd          }t          |          dk    r|d                                         }t          | j                   }	 dd	lm} dd
l	m
} t          | j                   } ||          }|rt          d| d|dd| d           nt          d| d|dd           | j                            || j        j        pd||pd          \  }	}
|	| _          || j                   } ||| j         ||          }|d         rdnd}t          d| d|d                     t          d|d                     |d         rt          d|d                     dS dS # t          $ r}t          d|            Y d}~dS d}~ww xY w)aZ  Manually trigger context compression on the current conversation.

        Accepts an optional focus topic: ``/compress <focus>`` guides the
        summariser to preserve information related to *focus* while being
        more aggressive about discarding everything else.  Inspired by
        Claude Code's ``/compact <focus>`` feature.
        r"  zE(._.) Not enough conversation to compress (need at least 4 messages).N.(._.) No active agent -- send a message first.z((._.) Compression is disabled in config.rO   r  r   )estimate_messages_tokens_rough)summarize_manual_compressionu   🗜️  Compressing z messages (~r  z tokens), focus: "z"...z tokens)...)approx_tokensfocus_topicnoopu   🗜️u   ✅r  rA  headliner  
token_linenoteu     ❌ Compression failed: )rd  r  r  r   compression_enabledrI   r  r  rS  !agent.manual_compression_feedbackrT  r=   _compress_context_cached_system_promptr>   )r  rn  rV  r   original_countrS  rT  original_historyrU  
compressedr  
new_tokenssummaryiconrB   s                  rC   r  zHermesCLI._manual_compress  s    ( 	C0I,J,JQ,N,NYZZZFz 	BCCCFz- 	<===F  	/ &&((..tQ77E5zzA~~#Ahnn..T677 	4KKKKKKVVVVVV#D$=>>::;KLLM h 5n 5 5-e 5 5"-5 5 5 6 6 6 6 fnff-ffffggg J88 
06B+'/4	 9  MJ )3D%778QRRJ22 )	 G !(:99UD3t33gj1334441',/11222v 1/gfo//000001 1  	4 	4 	42q22333333333	4s   DG/ /
H9HHc                 P    ddl m} ddlm}  |ddd          } ||           dS )	uB   Handle /debug — upload debug report + logs and print paste URLs.r   )run_debug_share)SimpleNamespacer  r  F)r  expirer   N)hermes_cli.debugrf  typesrg  )r  rf  rg  r  s       rC   r  zHermesCLI._handle_debug_command<  sR    444444))))))S%@@@rL   c           
       	   | j         st          d           dS | j         }|j        }|dk    rt          d           dS |                                }|rA|j        r:ddlm} t                       t           ||                     t                       t          |dd          pd}t          |dd          pd}t          |dd          pd}t          |d	d          pd}|j        }	|j	        }
|j
        }|j        }|j        }|j        }|rt          d
||z  d
z            nd}|j        }t!          | j                  }t%          |j        t)          ||||          t          |dd          t          |dd                    }t+          t-          j                    | j        z
                                            }t          d           t          dd            t          d|j                    t          d|d           t          d|d           t          d|d           t          d|d           t          d|	d           t          d|
d           t          d|d           t          d|d           t          d|d           t          d|j        d           t          d|j        d           |j        8|j        d k    rd!nd"}t          d#| d$t;          |j                  d%           n2|j        d&k    rt          d#d&d           nt          d#d'd           t          dd            t          d(|d)d*|d)d+|d,d-           t          d.|            t          d/|            |j        d0k    rt          d1|j                    | j        rht?          j                     !                    t>          j"                   d2D ]3}t?          j         |          !                    t>          j#                   4dS t?          j                     !                    t>          j$                   d3D ]3}t?          j         |          !                    t>          j%                   4dS )4z8Show rate limits (if available) and session token usage.rR  Nr   z,(._.) No API calls made yet in this session.)format_rate_limit_displayr  r  r  r  r  )input_tokensoutput_tokenscache_read_tokenscache_write_tokensr   r   )r   r   u     📊 Session Token Usager  r  z  Model:                     z  Input tokens:              z>10,z  Cache read tokens:         z  Cache write tokens:        z  Output tokens:             z  Prompt tokens (total):     z  Completion tokens:         z  Total tokens:              z  API calls:                 z  Session duration:          rF  z  Cost status:              z  Cost source:              	estimatedrl  rO   z  Total cost:              $z>10.4fincludedzn/az  Current context:  r  z / r  rJ  z%)z  Messages:         z  Compressions:     rU  z(  Note:             Pricing unknown for )openaizopenai._base_clienthttpxhttpcorer|  hpackgrpcmodal)r  	run_agenttrajectory_compressorrq  
hermes_cli)&r   r  r  get_rate_limit_statehas_dataagent.rate_limit_trackerrl  rm  r  r  r  r  r  r  r  r  r  rd  r"   r   r!   r#   r   r  r6  r  r  r  
amount_usdr  r   logging	getLoggersetLevelDEBUGWARNINGINFOERROR)r  r   r  rl_staterl  rm  rn  ro  rp  r  rT  totalr  last_promptr  r  r  r  cost_resultelapsedr  noisyquiet_loggers                          rC   r  zHermesCLI._show_usageD  s`   z 	BCCCF
'A::@AAAF --// 	) 	JJJJJJGGG++H55666GGG u&<a@@EA'>BBGa#E+FJJOa$U,H!LLQPQ,4
*-
 3+9@Gc#g-3555a!3122	)K)+"3#5	   UJ55UJ55

 

 

 *8<>>D<N+N*]*]*_*_``*+++:   ;ek;;<<<AlAAABBBF.?FFFGGGG.@GGGHHHBmBBBCCC;f;;;<<<?j???@@@:e:::;;;:e:::;;;;g;;;<<<E[-?EEEFFFE[-?EEEFFF!-'.+==SS2F___{?U9V9V___````:--@
@@@AAAA;;;;<<<:   O[OOOwOOOCOOOOPPP0Y001113\33444**JU[JJKKK< 	H((777t C C!%((11'/BBBBC C ((666 e H H!,//88GGGGH HrL   	/insightsc                    |                                 }d}d}d}|t          |          k     r||         dk    rb|dz   t          |          k     rL	 t          ||dz                      }n,# t          $ r t	          d||dz                        Y dS w xY w|dz  }n8||         dk    r'|dz   t          |          k     r||dz            }|dz  }n|dz  }|t          |          k     	 dd	lm} dd
lm}  |            } ||          }	|		                    ||          }
t	          |	
                    |
                     |                                 dS # t          $ r}t	          d|            Y d}~dS d}~ww xY w)z7Show usage insights and analytics from session history.r  Nr  z--daysz  Invalid --days value: r@  z--sourcer   r  )InsightsEngine)daysr  z  Error generating insights: )r  r  r  r~  r  r9  r  agent.insightsr  generateformat_terminalr  r>   )r  rV  r   r  r  r  r  r  dbenginereportrB   s               rC   r  zHermesCLI._show_insights  s    #e**nnQx8##AE

(:(:uQU|,,DD!   CU1q5\CCDDDFF QqZ''AECJJ,>,>q1uQQ #e**nn
	7......555555B#^B''F__$v_>>F&((00111HHJJJJJ 	7 	7 	75!55666666666	7s+   A* *%BB(A.E 
E?"E::E?c                 <   ddl }ddl}d} |j                    }|| j        z
  |k     rdS || _        ddlm}  |            }|                                sdS 	 |                                j        }n# t          $ r Y dS w xY w|| j
        k    rdS || _
        	 t          |d          5 }|                    |          pi }	ddd           n# 1 swxY w Y   n# t          $ r Y dS w xY w|	                    d          pi }
|
| j        k    rdS |
| _        t!                       t!          d           t#          j        | j        d	
          }|                                 |                    d           |                                rt!          d           dS dS )ax  Detect mcp_servers changes in config.yaml and auto-reload MCP connections.

        Called from process_loop every CONFIG_WATCH_INTERVAL seconds.
        Compares config.yaml mtime + mcp_servers section against the last
        known state.  When a change is detected, triggers _reload_mcp() and
        informs the user so they know the tool list has been refreshed.
        r   N      @get_config_pathr0   r1   r  u;   🔄 MCP server config changed — reloading connections...Tr:  r  r  r   uL     ⚠️  MCP reload timed out (30s). Some servers may not have reconnected.)r  r  rx  _last_config_checkr  r  r6   r  r  r  _config_mtimer9   r  r>   r   _config_mcp_serversr  rL  r  r  r  r   is_alive)r  r  _yamlCONFIG_WATCH_INTERVALr  _get_config_pathcfg_pathr  r@   new_cfgnew_mcp_reload_threads               rC   _check_config_mcp_changesz#HermesCLI._check_config_mcp_changes  sN    	 #dn((+@@@F"%IIIIII##%%   	F	MMOO,EE 	 	 	FF	 D&&&F #	h111 3Q//!,,23 3 3 3 3 3 3 3 3 3 3 3 3 3 3 	 	 	FF	 ++m,,2d...F#*  	KLLL")#D
 
 
 	B'''""$$ 	b`aaaaa	b 	bsH   A2 2
B ?B C )CC CC CC 
C'&C'c                 x   	 ddl m}m}m}m} |5  t          |                                          }ddd           n# 1 swxY w Y   | j        st          d            |              |            }|5  t          |                                          }ddd           n# 1 swxY w Y   ||z
  }||z
  }	||z  }
|
r2t          dd	                    t          |
                                |r2t          dd	                    t          |                                |	r2t          dd	                    t          |	                                |st          d	           n0t          d
t          |           dt          |           d           | j        xddlm}  |t          | j        d          r| j        j        ndd          | j        _        | j        j        rd | j        j        D             nt                      | j        _        g }|r8|                    dd	                    t          |                                |	r8|                    dd	                    t          |	                                |
r8|                    dd	                    t          |
                                |rt          |           dnd}|rd	                    |          dz   nd}| j                            dd| | dd           | j        7	 | j                            | j        | j                   n# t,          $ r Y nw xY wt          dt          | j        r| j        j        ng            d           dS # t,          $ r}t          d|            Y d}~dS d}~ww xY w) zReload MCP servers: disconnect all, re-read config.yaml, reconnect.

        After reconnecting, refreshes the agent's tool list so the model
        sees the updated tools on the next turn.
        r   )r[  discover_mcp_tools_servers_lockNu   🔄 Reloading MCP servers...u     ♻️  Reconnected: r  u     ➕ Added: u     ➖ Removed: z  No MCP servers connected.u     🔧 z tool(s) available from z
 server(s))rJ  r'  Tr  c                 *    h | ]}|d          d         S )r  rn   r  )r  r  s     rC   r,  z(HermesCLI._reload_mcp.<locals>.<setcomp>&  s/     / / /15D$V,/ / /rL   zAdded servers: zRemoved servers: zReconnected servers: z MCP tool(s) now availablezNo MCP tools availabler  rO   r  z)[SYSTEM: MCP servers have been reloaded. zD. The tool list for this conversation has been updated accordingly.]r  r  u     ✅ Agent updated — z tool(s) availableu     ❌ MCP reload failed: )rh  r[  r  r  r  r   r  rV  r  r   r  r  r   r  rJ  rl  r'  r  valid_tool_namesrd   rd  _persist_sessionr>   )r  r[  r  r  r  old_servers	new_toolsconnected_serversaddedrC  reconnectedrJ  change_partstool_summarychange_detailrB   s                   rC   r  zHermesCLI._reload_mcp  s   N	3````````````  3 3!(--//223 3 3 3 3 3 3 3 3 3 3 3 3 3 3 ( 75666 ! """ +*,,I  9 9$'$8$8!9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 &3E!$55G+k9K RP		&:M:M0N0NPPQQQ B@diiu&>&>@@AAA FD		&//(B(BDDEEE$ l34444jIjjL]H^H^jjjkkk z%<<<<<<#7#7tz+=>>&ITZ%@%@DH#$ $ $
  Z%/1 / /9=9I/ / / /+.55 
+ L R##$Pdiiu6N6N$P$PQQQ V##$T		&//8R8R$T$TUUU ^##$\DIIf[FYFY<Z<Z$\$\]]]LUsc)nnHHHH[sL>JRDIIl33d::PRM%,, i}  iVb  i  i  i. .    z%J//11    !   D lSTZ1W1A1AUW-X-Xlllmmmmm 	3 	3 	31a11222222222	3s   N ">N AN A/N 5"B#N #B''N *B'+I;N '%M N 
MN M6N 
N9N44N9r@  c                     t          | dd          r|                                  d| _        |                                  ddlm}  ||d          }t          d| d| d	           d
S )a/  Called when the model begins generating tool-call arguments.

        Closes any open streaming boxes (reasoning / response) exactly once,
        then prints a short status line so the user sees activity instead of
        a frozen screen while a large payload (e.g. 45 KB write_file) streams.
        r  Fr   get_tool_emojiu   ⚡)rS   u     ┊ z preparing u   …N)rm  rJ  r  rB  agent.displayr  r*  )r  r@  r  emojis       rC   r  zHermesCLI._on_tool_gen_startO  s     4-u55 	,   &+D#!!###000000y%8889999999:::::rL   function_namer  function_argsc                    |dk    rddl }d| _        |r| j        dv r|                    dd          }|                    dd          }| j                            |          }	|	r|	                    d          ni }
|	
|	s| j        |= | j        d	k    r!|| j        k    r|                                  dS || _        	 dd
lm	}  |||
|          }|r| d}t          d|            n# t          $ r Y nw xY w|                                  dS |dk    rdS |r|                    d          sddl }ddlm}  ||          }|p|}ddlm}  |            }|dk    r#t          |          |k    r|d|dz
           dz   }| d| | _        |                                | _        | j                            |g                               ||ni            |                                  | j        sdS |r|                    d          rdS 	 ddlm} t/          j        |ddddd                                           dS # t          $ r Y dS w xY w)a  Called on tool lifecycle events (tool.started, tool.completed, reasoning.available, etc.).

        Updates the TUI spinner widget so the user can see what the agent
        is doing during tool execution (fills the gap between thinking
        spinner and next response).  Also plays audio cue in voice mode.

        On tool.started, records a monotonic timestamp so get_spinner_text()
        can show a live elapsed timer (the TUI poll loop already invalidates
        every ~0.15s, so the counter updates automatically).

        When tool_progress_mode is "all" or "new", also prints a persistent
        stacked line to scrollback on tool.completed so users can see the
        full history of tool calls (not just the current one in the spinner).
        ztool.completedr   Nr  )r  rj  r  is_errorFrj  )get_cute_tool_messagez [error]r  ztool.startedr  r  )get_tool_preview_max_lenr  r}  rA  	play_beepi  gQ?r  )	frequencyr  r  T)r:  r  r  )r  rS  r  r   rT  r  rU  r{  r  r  r*  r>   r  r  r  r  rR  rx  
setdefaultrd   r]  tools.voice_moder  rL  r  r  )r  r  r  r  r  r  rz  r  r  storedstored_argsr  r  r  r  rc  r  _plr  s                      rC   r  zHermesCLI._on_tool_progressc  s6    )))    $'D! !8N!J!J!::j#66!::j%88044]CC/5=fjjmmm2%f%/>*e33Ic8c8c$$&&&F-:*CCCCCC00XVVD 1"&000KKK((((    DF''F 	!9!9#!>!> 	    444444"N=11E,}E>>>>>>**,,CQww3u::++hsQwh%/$)!3!3E!3!3D$)OO$5$5D!#..}bAAHH!.!:    	F 	 8 8 = = 	F	222222 %)taHH   eggggg 	 	 	DD	s$   =,C* *
C76C73I 
IIrA  c                     	 ddl m}  |||          }||| j        |<   dS dS # t          $ r! t                              d|d           Y dS w xY w)z3Capture local before-state for write-capable tools.r   )capture_local_edit_snapshotNz#Edit snapshot capture failed for %sTexc_info)r  r  r  r>   r7   r  )r  rA  r  r  r  r  s         rC   r  zHermesCLI._on_tool_start  s    	^AAAAAA22=-PPH#=E,\::: $# 	^ 	^ 	^LL>X\L]]]]]]	^s   $ 'AAfunction_resultc                     | j                             |d          }	 ddlm}  |||||t                     dS # t
          $ r! t                              d|d           Y dS w xY w)zFRender file edits with inline diff after write-capable tools complete.Nr   )render_edit_diff_with_delta)r  r  print_fnzEdit diff preview failed for %sTr  )r  r  r  r  r*  r>   r7   r  )r  rA  r  r  r  r  r  s          rC   r  zHermesCLI._on_tool_complete  s    /33L$GG	ZAAAAAA''+!        	Z 	Z 	ZLL:MTXLYYYYYY	Zs   : 'A%$A%c                     t           dd          rdS ddlm}m}  |            }|d         sUt	                      r8|                    dd          }d	|v rt          d
          t          d          t          d          |                    d|                    d                    st          d           j        5   j        r	 ddd           dS d _        ddd           n# 1 swxY w Y   i }	 ddl	m
}  |                                di           }n# t          $ r Y nw xY w j         |             _        |                    dd           j        _        |                    dd           j        _         fd}	 ddlm}  |dd           n# t          $ r Y nw xY w	  j                            |           n5# t          $ r(  j        5  d _        ddd           n# 1 swxY w Y    w xY wt           j        dd          rd}	nt	                      rd}	nd }	t#          d!t$           d"t&           d#t(           d$|	 d%t&           
            fd&}
t+          j        |
d'                                           dS )(z*Start capturing audio from the microphone.rB  FNr   )create_audio_recordercheck_voice_requirementsaudio_availabledetailsrO   z'Termux:API Android app is not installedzTermux:API command package detected, but the Android app is missing.
Install/update the Termux:API Android app, then retry /voice on.
Fallback: pkg install python-numpy portaudio && python -m pip install sounddevicezVoice mode requires either Termux:API microphone access or Python audio libraries.
Option 1: pkg install termux-api and install the Termux:API Android app
Option 2: pkg install python-numpy portaudio && python -m pip install sounddevicezzVoice mode requires sounddevice and numpy.
Install with: pip install sounddevice numpy
Or: pip install hermes-agent[voice]stt_availablestt_key_setzVoice mode requires an STT provider for transcription.
Option 1: pip install faster-whisper  (free, local)
Option 2: Set GROQ_API_KEY (free tier)
Option 3: Set VOICE_TOOLS_OPENAI_KEY (paid)Tr  r  silence_thresholdr  silence_durationg      @c                  8    j         5   j        s	 ddd           dS 	 ddd           n# 1 swxY w Y   t          dt           dt                      t           d          r  j        r j                                                                           dS )z>Called by AudioRecorder when silence is detected after speech.Nr  z"Silence detected, auto-stopping...r5  )	r\  r`  r*  r  r  rl  r5  ry  _voice_stop_and_transcriber  s   rC   _on_silencez5HermesCLI._voice_start_recording.<locals>._on_silence  s   !  ,                       GGGGGHHHtV$$ ' '	$$&&&++-----s   	,00r  ip  r  r  r  )on_silence_stopsupports_silence_autostopz8auto-stops on silence | Ctrl+B to stop & exit continuousz#Termux:API capture | Ctrl+B to stopzCtrl+B to stopr  u   ● Recording...rA  (r  c                      	 j         5  j        } d d d            n# 1 swxY w Y   | sd S t          d          r j        rj                                         t          j        d           o)NTr5  333333?)r\  r`  rl  r5  ry  r  r  )still_recordingr  s    rC   _refresh_levelz8HermesCLI._voice_start_recording.<locals>._refresh_level$  s    !% < <&*&;O< < < < < < < < < < < < < < <& E4(( +TY +I((***
4   !s   ""r  )rm  r  r  r  rk  r   RuntimeErrorr\  r`  r  r  r>   r_  _silence_threshold_silence_durationr  r  r*  ra  r  r  rL  r  )r  r  r  reqsr  	voice_cfgr  r  r  _recording_hintr  s   `          rC   _voice_start_recordingz HermesCLI._voice_start_recording  s   4// 	FTTTTTTTT''))%& 	%'' ((9b11<GG&l  
 #h  
 6  
 xx-)@)@AA 	>    	) 	)$ 	) 	) 	) 	) 	) 	) 	) 	) %)D!	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 		555555#))'266II 	 	 	D	 '#8#8#:#:D  3<--@SUX2Y2Y/1:?QSV1W1W.	. 	. 	. 	. 	.	222222I1----- 	 	 	D		 &&{&CCCC 	 	 	! . .(-%. . . . . . . . . . . . . . .	 4')DdKK 	/XOO#%% 	/COO.OTWTTdTTTTTOTTdTTUUU	! 	! 	! 	! 	! 	t<<<BBDDDDDsl   	C,C,,C03C0:$D 
D,+D,F 
F,+F,0G G>G1%G>1G5	5G>8G5	9G>c                 v     j         5   j        s	 ddd           dS d _        d _        ddd           n# 1 swxY w Y   d}d}	  j        ?	  j         5  d _        ddd           n# 1 swxY w Y   t	           d          r  j        r j                                         	 |r3t          j        	                    |          rt          j
        |           n# t          $ r Y nw xY w|sSt           dd          dz    _         j        dk    r.d _        d _        t          t            d	t"                      dS nd _         j        r8|s8 j        s3 fd
}t%          j        |d                                           dS dS dS dS  j                                        }	 ddlm}  |dd           n# t          $ r Y nw xY w|]t          t            dt"                      	  j         5  d _        ddd           n# 1 swxY w Y   t	           d          r  j        r j                                         	 |r3t          j        	                    |          rt          j
        |           n# t          $ r Y nw xY w|sSt           dd          dz    _         j        dk    r.d _        d _        t          t            d	t"                      dS nd _         j        r8|s8 j        s3 fd
}t%          j        |d                                           dS dS dS dS t	           d          r  j        r j                                         t          t            dt"                      d}	 ddlm}  |                                di           }|                    d          }n# t          $ r Y nw xY wddlm}  |||          }	|	                    d          r|	                    dd                                          r|	d                                         }
 j                                         t	           d          r  j        r j                                          j                             |
           d}nk|	                    d          rt          t            dt"                      n7|	                    dd          }t          dt            d| t"                      n8# t          $ r+}t          dt            d| t"                      Y d}~nd}~ww xY w j         5  d _        ddd           n# 1 swxY w Y   t	           d          r  j        r j                                         	 |r3t          j        	                    |          rt          j
        |           n# t          $ r Y nw xY w|sSt           dd          dz    _         j        dk    r.d _        d _        t          t            d	t"                      dS nd _         j        r8|s8 j        s3 fd
}t%          j        |d                                           dS dS dS dS #  j         5  d _        ddd           n# 1 swxY w Y   t	           d          r  j        r j                                         	 |r3t          j        	                    |          rt          j
        |           n# t          $ r Y nw xY w|sUt           dd          dz    _         j        dk    r0d _        d _        t          t            d	t"                       Y dS nd _         j        r7|s6 j        s0 fd
}t%          j        |d                                           w w w w xY w)zFStop recording, transcribe via STT, and queue the transcript as input.NFTr5  _no_speech_countr   r  r  z4No speech detected 3 times, continuous mode stopped.c                  
   	                                   t          d          r"j        rj                                         d S d S d S # t          $ r+} t          t           d|  t                      Y d } ~ d S d } ~ ww xY w)Nr5  Voice auto-restart failed: r  rl  r5  ry  r>   r*  r  r  )rB   r  s    rC   _restart_recordingz@HermesCLI._voice_stop_and_transcribe.<locals>._restart_recording  s    O33555"400 3TY 3 I00222223 3 3 3$ O O O4 M MA Mt M MNNNNNNNNNOs   AA 
B A==Br  r  i  r@  r  zNo speech detected.zTranscribing...r  sttr   )transcribe_recording)r   r,  
transcriptrO   r  Unknown errorr  zTranscription failed: zVoice processing error: )!r\  r`  ra  r_  rl  r5  ry  r`   r?   rc   unlinkr>   rm  r  rb  r*  r  r  rL  r  r  r  r  r  r  r  r   r  rI   rX  r  r@  r  )r  	submittedwav_pathr  r  	stt_modelr  
stt_configr  rJ   r  r  rB   s   `            rC   r  z$HermesCLI._voice_stop_and_transcribe/  sL   
  	* 	*( 	* 	* 	* 	* 	* 	* 	* 	* %*D!%)D"		* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	T	Q#+` ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& (x 8 8 (Ih'''     *(/6H!(L(Lq(P%(A---2D*,-D)t__Y]__```F	 . )*% % Qi Q@U QO O O O O  (:4HHHNNPPPPPQ Q Q Q Q QQ +0022H666666	Cq11111    4::D::;;;F ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& (x 8 8 (Ih'''     *(/6H!(L(Lq(P%(A---2D*,-D)t__Y]__```F	 . )*% % Qi Q@U QO O O O O  (:4HHHNNPPPPPQ Q Q Q Q Qu tV$$ ' '	$$&&&t22D22333 I999999([]]..ub99
&NN733		    >=====))()DDDFzz)$$ HL")E)E)K)K)M)M H#L17799
%++---4(( +TY +I((***#''
333 		I&& H4::D::;;;;

7O<<FTFFFFFGGG 	B 	B 	B@@@q@$@@AAAAAAAA	B ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& (x 8 8 (Ih'''     *(/6H!(L(Lq(P%(A---2D*,-D)t__Y]__```F	 . )*% % Qi Q@U QO O O O O  (:4HHHNNPPPPPQ Q Q Q Q Q5 ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& (x 8 8 (Ih'''     *(/6H!(L(Lq(P%(A---2D*,-D)t__Y]__```FFF	 . )*% % Qi Q@U QO O O O O  (:4HHHNNPPPPQ Q QsS  	99= =	T A--A14A1)5C 
C,+C,T *F> =T >
GT 
G$T 7HHH5I= =
J
	J
.AT ?9N9 8T 9
OT OD>T Y; 
T:!T50Y; 5T::Y; UUU5W
 

WW;^8Z^8Z^8Z3^85\	^8	
\^8\A^8/A	^8c                    | j         sdS | j                                         	 ddlm} ddlm} ddl}t          |          dk    r
|dd         n|}|	                    dd|          }|	                    dd	|          }|	                    d
d|          }|	                    dd	|          }|	                    dd	|          }|	                    dd	|          }|	                    dd||j
                  }|	                    dd||j
                  }|	                    dd|          }|	                    dd|          }|                                }|s	 | j                                         dS t          j        t          j                            t#          j                    d          d           t          j                            t#          j                    ddt'          j        d           d          } |||           t          j                            |          rt          j                            |          dk    r ||           	 t          j        |           |                    dd          d         dz   }t          j                            |          rt          j        |           n# t2          $ r Y nw xY wnR# t4          $ rE}t6                              d|           t;          t<           d | t>                      Y d}~nd}~ww xY w| j                                         dS # | j                                         w xY w)!zGSpeak the agent's response aloud using TTS (runs in background thread).Nr   )text_to_speech_tool)play_audio_filei  z```[\s\S]*?```rA  z\[([^\]]+)\]\([^)]+\)z\1zhttps?://\S+rO   z\*\*(.+?)\*\*z	\*(.+?)\*z`(.+?)`z^#+\s*r  z^\s*[-*]\s+z---+z\n{3,}r#  hermes_voiceTr  tts_r  z.mp3)ru  output_pathr   r  z.oggzVoice TTS playback failed: %szTTS playback failed: ) r^  rd  r  tools.tts_toolr	  r  r	  r  r  r  	MULTILINErI   r   r`   r  r?   r   tempfile
gettempdirr  r;  rc   getsizer  r  r  r>   r7   r8   r*  r  r  )	r  ru  r	  r	  r  tts_textmp3_pathogg_pathrB   s	            rC   _voice_speak_responsezHermesCLI._voice_speak_response  sm    	F""$$$.	'::::::888888III '*$ii$&6&6tETE{{DHvv/h??Hvv6xHHHvvor8<<Hvv.x@@HvvlE8<<Hvvj%::HvviXR\vJJHvvnb(",vOOHvvgr844Hvvi::H~~''H 6  $$&&&&&/ KX%8%:%:NKKVZ[[[[w||#%%~;t}_55;;; H
  X8DDDD w~~h'' 	BGOOH,E,E,I,I)))Ih''''sA66q9FBHw~~h// ,	(+++   D 	= 	= 	=NN:A>>>t;;!;T;;<<<<<<<<	=  $$&&&&&D $$&&&&s\   D9K 9C'K !A&K K 
KK KK M 
L(#;L#M #L((M M!c                 l   |                                                     d          }t          |          dk    r,|d                                                                          nd}|dk    r|                                  d
S |dk    r|                                  d
S |dk    r|                                  d
S |dk    r|                                  d
S |dk    r3| j        r|                                  d
S |                                  d
S t          d|            t          d	           d
S )z*Handle /voice [on|off|tts|status] command.r  r  rO   rU   rP   r  r  zUnknown voice subcommand: z!Usage: /voice [on|off|tts|status]N)
rI   r  r  rY   _enable_voice_mode_disable_voice_mode_toggle_voice_tts_show_voice_statusr]  r*  )r  rV  r   r  s       rC   r  zHermesCLI._handle_voice_command  sP   %%q%1114UaU1X^^%%++---R
##%%%%%5  $$&&&&&5  ""$$$$$8####%%%%%2 *((*****'')))))===>>>788888rL   c           	      D   | j         r t          t           dt                      dS ddlm}m}  |            }|d         sLt          dt           dt                      |d         D ]"}t          d	t           | t                      #dS  |            }|d         s,t          dt           d
t                      |d                             d          D ]"}t          d	t           | t                      #|d         rt                      r^t          dt           dt                      t          d	t           dt                      t          d	t           dt                      nYt          dt           dd                    |d                    t                      t          d	t           dt                      dS | j        5  d| _         ddd           n# 1 swxY w Y   	 ddlm}  |                                di           }|                    dd          r&| j        5  d| _        ddd           n# 1 swxY w Y   n# t"          $ r Y nw xY w| j        rdnd}		 ddlm}  |                                di                               dd          }
|
                                                    dd                              dd           }n# t"          $ r d!}Y nw xY w|                    dd"                                          }t          dt           d#|	 t                      t          d	t           | d$t                      t          d	t           d%t                      t          d	t           d&t                      dS )'z.Enable voice mode after checking requirements.zVoice mode is already enabled.Nr   )r  detect_audio_environmentr  r  z+Voice mode unavailable in this environment:warningsr  z Voice mode requirements not met:r  missing_packagesr  z Option 1: pkg install termux-apizEThen install/update the Termux:API Android app for microphone capturezQOption 2: pkg install python-numpy portaudio && python -m pip install sounddevicezInstall: pip install rA  z#Or: pip install hermes-agent[voice]Tr  r  auto_ttsFz (TTS enabled)rO   
record_keyctrl+bctrl+c-alt+a-c-bCtrl+zVoice mode enabledz to start/stop recordingz#/voice tts  to toggle speech outputz!/voice off  to disable voice mode)r]  r*  r  r  r  r  r	  ra  r  rk  r  r   r\  r  r  r   r^  r>   rY   rB  upper)r  r  r	  	env_checkr8   r  r  r  voice_config
tts_status_raw_ptt_ptt_key_ptt_displays                rC   r	  zHermesCLI._enable_voice_mode  s    	tAA4AABBBFWWWWWWWW -,..	% 	SSSTSSTTT$Z0 4 42T272D223333F''))K  	HHH$HHIIIY--d33 1 1/T/4///0000&' R)++ RP5PP$PPQQQrrrlprrsssy}  A  A  A  Ai5iisxxM_H`?a?aicgiijjjPPP$PPQQQF 	$ 	$#D	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$	555555&;==,,Wb99L
E22 +% + +&*DO+ + + + + + + + + + + + + + + 	 	 	D	 *.@%%b
	555555"{}}(("5599,QQH~~''//>>FFvtTTHH 	 	 	HHH	''g66<<>>BWBB
BDBBCCCGTG<GGGGHHHDTDDdDDEEEBTBBDBBCCCCCs\   G((G,/G,4AI 5I	=I 	II II 
I"!I"1A4K& &K54K5c                    d}| j         5  | j        r'| j        r | j                                         d| _        | j        }d| _        d| _        d| _        ddd           n# 1 swxY w Y   |4|fd}t          j        |d          	                                 d| _        	 ddl
m}  |             n# t          $ r Y nw xY w| j                                         t          dt            d	t"                      dS )
z>Disable voice mode, cancel any active recording, and stop TTS.NFc                 R    	 |                                   d S # t          $ r Y d S w xY wr_   )shutdownr>   )recs    rC   _bg_shutdownz3HermesCLI._disable_voice_mode.<locals>._bg_shutdown)  s:    LLNNNNN    DDs    
&&Tr  r   stop_playbackr  zVoice mode disabled.)r\  r`  r_  cancelr]  r^  rb  rL  r  r  r  r.	  r>   rd  r   r*  r  r  )r  recorderr,	  r.	  s       rC   r	  zHermesCLI._disable_voice_mode  s    	+ 	+$ .)= .$++---(-%+H$D#DO%*D"	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ !)    
 L>>>DDFFF#'D 	666666MOOOO 	 	 	D	  """5T55t5566666s$   AA!!A%(A%#B4 4
C Cc                 n   | j         s t          t           dt                      dS | j        5  | j         | _        ddd           n# 1 swxY w Y   | j        rdnd}| j        r.ddlm}  |            st          t           dt                      t          t           d| d	t                      dS )
z!Toggle TTS output for voice mode.z"Enable voice mode first: /voice onNr   disabledr   )check_tts_requirementszEWarning: No TTS provider available. Install edge-tts or set API keys.z
Voice TTS r   )	r]  r*  r  r  r\  r^  r	  r3	  ra  )r  r  r3	  s      rC   r	  zHermesCLI._toggle_voice_tts;  s    	tEEtEEFFFF 	2 	2"&/1DO	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2"o=:? 	n======))++ n4llfjllmmm755f55t5566666s   A		AAc                    ddl m} ddlm}  |            }t	          dt
           dt                      t	          d| j        rdnd            t	          d	| j        rdnd            t	          d
| j	        rdnd             |            
                    di           
                    dd          }d|                                v r(|                    dd                                          n|}t	          d|            t	          dt
           dt                      |d                             d          D ]}t	          d|            dS )zShow current voice mode status.r   r  )r  r  zVoice Mode Statusz  Mode:      r?  r>  z  TTS:       z  Recording: YESnor  r	  r	  r	  r 	  z  Record key: r  zRequirements:r  r  N)r  r  r  r  r*  r  r  r]  r^  r`  r   rY   rB  r!	  r  )r  r  r  r  _raw_key_display_keyr  s          rC   r	  zHermesCLI._show_voice_statusL  s   111111======''))3U33T33444E(8 CeEEFFFD BUDDEEEJ)> HDJJKKK;==$$Wb1155lHMMELPXP^P^P`P`E`E`x''99??AAAfn///0001u11411222O))$// 	# 	#DM4MM""""	# 	#rL   c                 @   ddl }t                              di                               dd          }t          j                    }| }||s|ng d|d| _        |                                |z   | _        || _        | 	                                 |                                }	 	 |                    d	          }d| _        |S # t          j
        $ ry | j        |                                z
  }	|	dk    rY nY|                                }
|
|z
  d
k    r|
}| 	                                 |
|z
  d
k    r|
}| 	                                 Y nw xY wd| _        d| _        d| _        | 	                                 t          dt           d| dt                      	 dS )a  
        Platform callback for the clarify tool. Called from the agent thread.

        Sets up the interactive selection UI (or freetext prompt for open-ended
        questions), then blocks until the user responds via the prompt_toolkit
        key bindings.  If no response arrives within the configured timeout the
        question is dismissed and the agent is told to decide on its own.
        r   Nr   r   r   )r   choicesrv  response_queueTr  r  r  Fr  z(clarify timed out after u   s — agent will decide)zrThe user did not provide a response within the time limit. Use your best judgement to make the choice and proceed.)r  r  r   r  r?  rD  rx  rF  rE  r{  Emptyr*  r  r  )r  r   r:	  rz  r   r;	  is_open_ended_last_countdown_refreshrJ   r[  r  s              rC   r  zHermesCLI._clarify_callback^  s    	..B//33IsCC# !&3;ww,	
 
 "'!2!2W!<!. 	 #(//"3"3	'''++A+66)*&; ' ' ' 2U__5F5FF	>>Eoo''00C77.1+$$&&&00C77.1+$$&&&'	'& #!&!"[T[[G[[UY[[\\\F	
 	
s   'C 1E9AEEc                 :   ddl }d}t          j                    }|                                  d|i| _        |                                |z   | _        |                                  	 	 |                    d          }d| _        d| _        | 	                                 |                                  |r t          dt           d	t                      nt          dt           d
t                      |S # t          j        $ r; | j        |                                z
  }|dk    rY n|                                  Y nw xY wd| _        d| _        | 	                                 |                                  t          dt           dt                      dS )a%  
        Prompt for sudo password through the prompt_toolkit UI.
        
        Called from the agent thread when a sudo command is encountered.
        Uses the same clarify-style mechanism: sets UI state, waits on a
        queue for the user's response via the Enter key binding.
        r   Nr   r;	  Tr  r  r  u,     ✓ Password received (cached for session)u     ⏭ Skippedu)     ⏱ Timeout — continuing without sudorO   )r  r  r?  ry  rG  rx  rH  r{  r   r~  r*  r  r  r<	  )r  rz  r   r;	  rJ   r[  s         rC   _sudo_password_callbackz!HermesCLI._sudo_password_callback  s    	**,,,n
 $oo//'9	##'++A+66#' &'#22444  """ <YYYSWYYZZZZ:::D::;;;; # # # /%//2C2CC	>>E  """""	#	#$  **,,,JTJJDJJKKKrs   )BC8 81E+EEallow_permanentr  rB	  c                2   ddl }| j        5  d}t          j                    }|||                     ||          d|d| _        |                                |z   | _        |                                  |                                }	 	 |	                    d          }d| _        d| _        |                                  |cddd           S # t          j
        $ rZ | j        |                                z
  }	|	dk    rY n:|                                }
|
|z
  d	k    r|
}|                                  Y nw xY wd| _        d| _        |                                  t          d
t           dt                      	 ddd           dS # 1 swxY w Y   dS )a  
        Prompt for dangerous command approval through the prompt_toolkit UI.

        Called from the agent thread. Shows a selection UI similar to clarify
        with choices: once / session / always / deny. When allow_permanent
        is False (tirith warnings present), the 'always' option is hidden.
        Long commands also get a 'view' option so the full command can be
        expanded before deciding.

        Uses _approval_lock to serialize concurrent requests (e.g. from
        parallel delegation subtasks) so each prompt gets its own turn
        and the shared _approval_state / _approval_deadline aren't clobbered.
        r   Nr   rA	  )rV  r  r:	  rv  r;	  Tr  r  r  r  u!     ⏱ Timeout — denying commanddeny)r  rN  r  r?  _approval_choicesrJ  rx  rK  r{  r   r<	  r*  r  r  )r  rV  r  rB	  rz  r   r;	  r>	  rJ   r[  r  s              rC   _approval_callbackzHermesCLI._approval_callback  s2    	  $	 $	G"[]]N #*11'?1[["0$ $D  ',oo&7&7'&AD#&+oo&7&7#+++///::F+/D(./D+$$&&&!-$	 $	 $	 $	 $	 $	 $	 $	. { + + + $ 7%//:K:K KI A~~//++C44;;25/((***++  $(D &'D#FFFFFGGGI$	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	 $	s=   A=F
9C1D9F3D96F8D99AFFFc                j    |rg dng d}t          |          dk    r|                    d           |S )z7Return approval choices for a dangerous command prompt.)oncer  alwaysrD	  )rH	  r  rD	  F   view)r  rd   )r  rV  rB	  r:	  s       rC   rE	  zHermesCLI._approval_choices  sG    ;Jk7777PkPkPkw<<"NN6"""rL   c                    | j         }|sdS |                    dd          }|                    d          pg }d|cxk    rt          |          k     sn dS ||         }|dk    rrd|d<   d |D             |d<   |d         t          |d                   k    r)t          dt          |d                   d	z
            |d<   |                                  dS |d
                             |           d| _         |                                  dS )zAProcess the currently selected dangerous-command approval choice.Nrv  r   r:	  rK	  T	show_fullc                     g | ]
}|d k    |S )rK	  r  )r  choices     rC   r  z8HermesCLI._handle_approval_selection.<locals>.<listcomp>  s"    QQQ6&@P@P@P@P@PrL   r  r;	  )rJ  r   r  r~  r{  r  )r  r  rv  r:	  chosens        rC   _handle_approval_selectionz$HermesCLI._handle_approval_selection  s5   $ 	F99Z++))I&&,"X,,,,G,,,,F"V!%E+QQWQQQE)Z Ci(8$9$999$'3uY/?+@+@1+D$E$Ej!F##F+++#rL   c                    | j         }|sg S d=dt          dt          t                   dt          dt          dt          f
d}d>d
t          dt          dt          dt          t                   fd}dt          dt          d
t          dt          ddf
d}dt          dt          ddfd}|d         }|d         }|d         }|                    dd          }	|                    dd          }
d}|
st          |          dk    r|n|dd         dz   }ddd d!d"d#} ||d$          }|                     ||d$                     t          |          D ]H\  }}||	k    rd%nd&}|                     || |                    ||           d$d&'                     I |||          }t          d(|d)z
            } |||          }g }t          |          D ]Q\  }}|                    ||          }||	k    rd%nd&} || | |d&'          D ]}|	                    ||f           Rt          j        d*          j        }d+}d,}d-}t          d||z
            }|t          |          z   t          |          z   }||k    }|r|n|}t          d.||z
  t          |          z
            } t          |          | k    r)| d.k    rt          d.| d.z
            nd.}!|d|!         d/gz   }|t          |          z   t          |          z   }"|rdnd.}#||"z
  |#z
  }$t          dt          |$d0                    }$|r |||          ng }%|$d.k     s|%sg }%n4t          |%          |$k    r!t          d.|$d.z
            }!|%d|!         d1gz   }%g }&|&	                    d2d3d4|z  z   d5z   f            ||&d2d6||           |s ||&d2|           |D ]} ||&d2d7||           |s ||&d2|           |D ]\  }}||	k    rd8nd9}' ||&d2|'||           |%r#|s ||&d2|           |%D ]} ||&d2d:||           |&	                    d2d;d4|z  z   d<z   f           |&S )?a  Render the dangerous-command approval panel for the prompt_toolkit UI.

        Layout priority: title + command + choices must always render, even if
        the terminal is short or the description is long. Description is placed
        at the bottom of the panel and gets truncated to fit the remaining row
        budget. This prevents HSplit from clipping approve/deny off-screen when
        tirith findings produce multi-paragraph descriptions or when the user
        runs in a compact terminal pane.
        .   r  
title_textcontent_lines	min_widthr  r-   c           	         t          j        d          j        }t          t	          |           gd |D             z   |dz
  gz             }t          t          |dz   |dz
            |dz
  t          d|dz
                      }|dz   S )Nr  r  c                 ,    g | ]}t          |          S r  rH  r  s     rC   r  zWHermesCLI._get_approval_display_fragments.<locals>._panel_box_width.<locals>.<listcomp>5  s    .S.S.STs4yy.S.S.SrL   r"  r@  r  r  rl   r  r  r~  r  r  )rT	  rU	  rV	  r  	term_colslongestr  s          rC   _panel_box_widthzCHermesCLI._get_approval_display_fragments.<locals>._panel_box_width3  s    0;;CI3z??+.S.S].S.S.SSW`cdWdVeeffGGaKQ77QBPY\]P]H^H^__E19rL   rO   ru  rw  subsequent_indentc                 Z    t          j        | t          d|          dd|          }|pdgS )Nr  F)rw  replace_whitespacedrop_whitespacer^	  rO   r  wrapr~  ru  rw  r^	  wrappeds       rC   _wrap_panel_textzCHermesCLI._get_approval_display_fragments.<locals>._wrap_panel_text9  s=    m!Umm#( %"3  G ?rd"rL   r  content_style	box_widthNc                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S Nr   r@  u   │ u    │
r~  rd   r  r  r  rg	  ru  rh	  r  s         rC   _append_panel_linezEHermesCLI._get_approval_display_fragments.<locals>._append_panel_lineC  l    aQ//KLL,/000LL-K)@)@ABBBLL,122222rL   c                 F    |                      |dd|z  z   dz   f           d S Nu   │rA  u   │
rd   r  r  rh	  s      rC   _append_blank_panel_linezKHermesCLI._get_approval_display_fragments.<locals>._append_blank_panel_lineI  -    LL,y(AG(KLMMMMMrL   rV  r  r:	  rv  r   rM	  Fu   ⚠️  Dangerous CommandrJ	  r}  z
Allow oncezAllow for this sessionzAdd to permanent allowlistDenyzShow full command)rH	  r  rI	  rD	  rK	  r      ❯ r  r^	  r  r@  r  r  rs  r  r  r  u=   … (command truncated — use /logs or /debug for full text)r  u   … (description truncated)zclass:approval-borderu   ╭r6     ╮
zclass:approval-titlezclass:approval-cmdzclass:approval-selectedzclass:approval-choicezclass:approval-descrj     ╯
rS	  r  rO   )rJ  rX   r=   r  r   r  r  r  r~  rd   rl   r  r  r  )(r  r  r]	  rf	  rm	  rs	  rV  r  r:	  rv  rM	  r  cmd_displaychoice_labelspreview_linesr  rO	  r  rh	  inner_text_widthcmd_wrappedchoice_wrappedrc  re	  	term_rowschrome_fullchrome_tightreserved_belowr  mandatory_fulluse_compact_chromechrome_rowsmax_cmd_rowsrS  mandatory_no_descdesc_sep_costavailable_for_descdesc_wrappedr  r   s(                                           rC   _get_approval_display_fragmentsz)HermesCLI._get_approval_display_fragments%  sY    $ 	I	 	 	T#Y 	SV 	hk 	ux 	 	 	 		# 	#3 	#s 	#s 	#TXY\T] 	# 	# 	# 	#	3C 	3 	3SV 	3cf 	3ko 	3 	3 	3 	3	N# 	N# 	NRV 	N 	N 	N 	N 	"M*	"99Z++IIk511	+!*Zc'llb.@.@gggcrclUZFZ /2'
 
 )(b99--k2>>???"7++ 	 	IAv H}}VV$F  !1!1>=,,VV<<>>"&" " "     %$UM::	q)a-00 '&{4DEE 13"7++ 	4 	4IAv!%%ff55E H}}VV$F++v,>u,>,>@Pdhiii 4 4%%q'l33334 ,Y77=	9~566	$s;'7'77#n:M:MM ,i7&8Illk
 1i+5N8K8KKLL{l**/;a/?/?3q,*+++QD%ete,0o/ppK (#k*:*::S=P=PP/6Q&)::]J C(:B$?$?@@JU]''5EFFF[]!!!LL!333q,q011D'.2O1PPL -u	8I/JW/TUVVV5"9;QSXZcddd! 	P$$U,CYOOO" 	i 	iGu&=?SU\^ghhhh! 	P$$U,CYOOO( 	Z 	ZJAw12h--D[Eu&=ugyYYYY 	n% T((0GSSS' n n""5*ACXZaclmmmm-u	8I/JW/TUVVVrL   var_namer  c                 &    t          | |||          S r_   rW  )r  r	  r  metadatas       rC   _secret_capture_callbackz"HermesCLI._secret_capture_callback  s     xBBBrL   c                     | j         t          | dd          sdS 	 | j        j        }|j        |j        d| _         |                                 dS # t          $ r d| _         Y dS w xY w)zITemporarily clear the input buffer and save the user's in-progress draft.Nr5  )ru  cursor_position)rI  rm  r5  current_bufferru  r	  r  r>   )r  r)  s     rC   ry  z'HermesCLI._capture_modal_input_snapshot  s    %1vt9T9T1F	.)*C#&#6* *D& IIKKKKK 	. 	. 	.)-D&&&&	.s   4A A'&A'c                 4   | j         }d| _         |rt          | dd          sdS 	 | j        j        }|                    dd          |_        t          |                    dd          t          |j                            |_        dS # t          $ r Y dS w xY w)zERestore any draft text that was present before a modal prompt opened.Nr5  ru  rO   r	  r   )
rI  rm  r5  r	  r   ru  r  r  r	  r>   )r  r  r)  s      rC   r~  z'HermesCLI._restore_modal_input_snapshot  s    -%)" 	wtVT:: 	F	)*C||FB//CH"%hll3Da&H&H#ch--"X"XC 	 	 	DD	s   A"B	 	
BBrZ   c                     | j         sd S | j         d                             |           d | _         d| _        |                                  d S )Nr;	  r   )rP  r  rQ  r{  )r  rZ   s     rC   _submit_secret_responsez!HermesCLI._submit_secret_response  sW    ! 	F+,00777! !rL   c                 0    |                      d           d S r  )r	  r  s    rC   _cancel_secret_capturez HermesCLI._cancel_secret_capture  s    $$R(((((rL   c                     t          | dd           r2	 | j        j                                         d S # t          $ r Y d S w xY wd S )Nr5  )rm  r5  r	  r  r>   r  s    rC   _clear_secret_input_bufferz$HermesCLI._clear_secret_input_buffer  sd    4&& 		(..00000   	 	s   3 
A Ac                    <=>?@ t           j                                                    sdS                                }|d          j        k    rd _         j        t          t           dt                       	                    |d         |d         |d         |
                    d                    sdS |r-                     t          t                    rnd	|          t          t                    r%d
v r 	 ddlm} ddlm}  | j         j        pd	 j        pd	          } |t+          j                    |          }|j        s|j        r|j        r<t          dt           dt5          |j                   d|j         dt                      |j        D ]#}t          dt           d| t                      $|j        rd                    |j                  pdS |j        n,# t>          $ r}	tA          j!        d|	           Y d}	~	nd}	~	ww xY wt          t                    rddl"m#}
  |
           j$        %                    dd           tM                      '                    dtQ                       dd d           tO          d            	 d> )                                 d! _*        d!}d!<d@d}d?d} j+        ra	 dd"l,m-}m.}m/}m0}m1}  |            } ||          d#k    r |              |             d}n"# td          tf          f$ r Y nt>          $ r Y nw xY w|rwti          j5                    @tm          j7                    }d$t          f< fd%}tm          j8        |@| j9        fd&|id'          }|:                                 d(t          f@fd)?d	= j;        rt          t                    rd*==> ?fd+}tm          j8        |d,          }|:                                 d}|<                                rt{           d-          r	  j>        
                    d./          }|rB j?        s j@        rTtO          d0           ||A                                  j        B                    |           	 t          d1z  }t          |d2          5 }ddlE}|F                    |G                    d3           d4t          |          dd5         d6t5           j        jH                   d7 j        jI         d           t           j        jH                  D ]&\  }}|F                    d8| d9|jI         d           '	 ddd           n# 1 swxY w Y   n# t>          $ r Y nw xY wnVn@# th          jK        $ r  L                    d:;           Y nw xY w|                    d.           |<                                |t          d<          D ]A}|                    d=/           |<                                s nt           d>d!          r nB|<                                r t          P                    d?|jQ                   n|                    d@/           	 ddAlRmS}  |             n# t>          $ r Y nw xY w T                                 |r/@-@U                    d           ||                    dB/           ddlE}t          jW        X                                 |Y                    d:           >r>
                    dC j$                  n j$         _$        >r>
                    dDd	          nd	} | rb>r`>
                    dE          sK>
                    dF          s6	 ddGlZm[}!  |! j\         j]        |  j$                   n# t>          $ r Y nw xY w>rt>
                    dE          s>
                    dF          rJ| sH>
                    dHdI          }"dJ|" }  j^        r&d! _^        t          dt           dKt                      d}#>r5>
                    dL          r >
                    dM          p|}#| r|#r| dNz   } >r>
                    dOd!          nd!}$t           dPd!          }% j_        rJ>rG|%sD>
                    dQ          }&|&r,t          ja                    jb        }dR}'|dSz
  t5          |'          z
  }(t           dT|' dUt          |(dVz
  d          z   dWt           })t           dXdU|dSz
  z   dYt           }*|&d                                e                                }+t5          |+          dZk    rFd                    |+ddZ                   },|,dt           d[t5          |+          dZz
   d\t           z  },n|&d                                },t          d|) dt           |, t           d|*            | rI|$sF	 dd]lfmg}-  |-            }.|.h                    d^d_          }/|.i                    d`da          }0|.i                    dbdc          }1n# t>          $ r	 d_}/da}0dc}1Y nw xY w>o)>
                    dE          p>
                    dF          }2 jj        o	 jk        o|2 }3|rE<rC|2sAt          ja                    jb        }t          dt           dddU|dSz
  z   det                      nX|3rnUtM                      }4|4'                    t          t          |           d|0 df|/ ddg|0|1t          jp        dhi                      jq        r=t          jW        F                    dj           t          jW        X                                 >r>
                    dk          s>
                    dL          sk>
                    dld          }5|5t           j        dmdn          k    r;t           j        dmdn          }6t          dt           do|5 dp|6 dqt                       j+        r3| r1|s/tm          j8         jr        | fdr          :                                 |#rt{           ds          r|#g}7 j>        s                                s`	  j>        t                                }8|8r|7%                    |8           n# th          jK        $ r Y nw xY w j>        s                                `d                    |7          }9t5          |7          }:|9dd<         t5          |9          d<k    rdtnd	z   };|:dVk    rtO          du|: dv|; dw           ntO          dx|; dw            ju        U                    |9           | @'	 @v                    d           n# t>          $ r Y nw xY w||A                                 |+|<                                r|                    dy/           S S S # t>          $ r}	tO          dJ|	            Y d}	~	@'	 @v                    d           n# t>          $ r Y nw xY w||A                                 |,|<                                r|                    dy/           dS dS dS d}	~	ww xY w# @'	 @v                    d           n# t>          $ r Y nw xY w||A                                 |+|<                                r|                    dy/           w w w xY w)za  
        Send a message to the agent and get a response.
        
        Handles streaming output, interrupt detection (user typing while agent
        is working), and re-queueing of interrupted messages.
        
        Uses a dedicated _interrupt_queue (separate from _pending_input) to avoid
        race conditions between the process_loop and interrupt monitoring. Messages
        typed while the agent is running go to _interrupt_queue; messages typed while
        idle go to _pending_input.
        
        Args:
            message: The user's message (str or multimodal content list)
            images: Optional list of Path objects for attached images
            
        Returns:
            The agent's response, or None on error
        N	signaturezInitializing agent...r   r  rc  r  r  rO   r  r   )preprocess_context_referencesr  )r   r   )r   r  r  z[@ context: z	 ref(s), z tokens]u   ⚠ r  zContext injection refused.z(@ context reference expansion failed: %s_sanitize_surrogatesr  r  r  rY  r  r  T)r  F)_load_tts_config_get_provider_import_elevenlabs_import_sounddevicestream_tts_to_speaker
elevenlabssentencec                    s]dj         j        }d}|dz
  t          |          z
  }t          dt           d| dt          |dz
  d          z   d	t                      t          t           |                                             d
S )zCCalled by TTS consumer when a sentence is ready to display + speak.Tu    ⚕ Hermes r@  r  r^  r6  r  r   r_  N)	r  rw  r  r*  ra  r~  r  rb  r  )r	  r  rc  r  _streaming_box_openedr  s       rC   display_callbackz(HermesCLI.chat.<locals>.display_callbackr  s     1 `04- L. . 1us5zz1 ^W ^ ^E ^53taxQRCSCS;S ^ ^X\ ^ ^___{?HOO,=,=??@@@@@rL   r	  )r:  r  r  r  deltac                 :                         |            d S d S r_   )r  )r	  
text_queues    rC   stream_callbackz'HermesCLI.chat.<locals>.stream_callback  s)    !-"u----- .-rL   ui   [Voice input — respond concisely and conversationally, 2-3 sentences max. No code blocks or markdown.] c                     rz   n} t          dd           }|r|dz   | z   } d _        	 j                            | j        d d         j        rnd           d S # t          $ rN}t          j        d|d            t          j        dd	           |          }d
| g ddd|dY d }~d S d }~ww xY w)Nr  r#  r  )r  rd  r	  r  persist_user_messagezrun_conversation raised: %sTr  _summarize_api_errorc                 0    t          |           d d         S )Nr   r  )rB   s    rC   r  z3HermesCLI.chat.<locals>.run_agent.<locals>.<lambda>  s    UXYZU[U[\`]`\`Ua rL   r  r   F)r  r  	api_calls	completedfailedr  )	rm  r  r   r  rd  ra  r>   r  r  )	agent_message_msnr  _summary_voice_prefixrX  rJ   r  r	  s	       rC   rz  z!HermesCLI.chat.<locals>.run_agent  s    ;H U 7 7gt%A4HH ;$(6MM$AM6:D3!Z88%2-1-Fss-K(7 $8E-OWW4 9  FFF ! 
 
 
M"?tTTTTbwtz3IKaKabbcfggH*>H*>*>$&%&%*"&!) FFFFFFF
s   5A% %
B=/AB88B=r  rA  皙?r  u*   
⚡ New message detected, interrupting...interrupt_debug.logr  %H:%M:%Sz interrupt fired: msg=r   z, children=z, parent._interrupt=z  child[z]._interrupt=r  rv  r   皙?rB  z_Agent thread still alive after interrupt (thread %s). Daemon thread will be cleaned up on exit.r  )cleanup_stale_async_clientsr   r  r  r	  partial)maybe_auto_titler  r  r  z+Continuous voice mode stopped due to error.interruptedinterrupt_messagez.

---
_[Interrupted - processing new message]_response_previewedr9  last_reasoningr4  r@  r5  r6  r  r7  r=  r>  r  z  ... (r  r  rZ  r[  r  r  r\  r]  rj  rk  r  r  r  r  r  r	  r	  r   r   u   ⚠ Iteration budget reached (rk  u    ) — response may be incomplete)r:  r  r  r@  r}  u   
⚡ Sending z messages after interrupt: 'r>  u   
⚡ Sending after interrupt: 'rs  )wrV  r	  r  r  r4  r   r*  r  r  r  r   r  r<   rX   agent.context_referencesr	  r  r  r   r   r   r`   r  rM  blocked
referencesr  injected_tokensr	  r   rX  r>   r  r  rz  r	  rd  rd   r  r  r!  rK  r9  r^  r	  r	  r	  r	  r	  r	  r  r  r  r?  rL  rc  r  rd  r  r]  r  rl  rA  rD  rE  r   r   r5   r9   r  r  r;  _active_children_interrupt_requestedr  r<	  r{  r  rm  r7   r8   identri  r	  rJ  r  r  ry  r  r  agent.title_generatorr	  r8  ra  rb  r   rl   r  r  r~  rI   r  r	  r  r  r
  r  r  ra  rF  r&  r  r  r  r	  empty
get_nowaitr@  
put_nowait)Ar  rX  r  r  r	  r  _ctx_len_ctx_resultr  rB   r	  use_streaming_tts
tts_thread
stop_event_load_tts_cfg	_get_provr	  r	  r	  _tts_cfgr	  rz  agent_threadinterrupt_msg_dbg_f_t_ci_ch
_wait_tickr	  rz  r  r	  error_detailpending_messager	  _reasoning_already_shownrB  r:  r;  r_topr_botr  display_reasoningr  r  rc  r  r  is_error_responsealready_streamedr  
_api_calls	_max_iter	all_partsr  combinedrl  r  r	  r	  rJ   r	  r	  sA   ``                                                          @@@@@rC   chatzHermesCLI.chat  s   * 	$D$ABBB //11 	444W==
k"d&HHHDJ :t88$88999%g.'	2"7+(nn-@AA	   
 
 	 4
  	99%gs33;V G
 gs## 	MwMRRRRRRIIIIII33J)<"dlFXVXZ Z Z;;XG G G' 	2;+> 	2"- LK K K3{7M3N3N K K*:K KDHK KL L L )1 : : 8T 8 8q 8$ 8 89999"* _#yy)=>>^B^^)1G M M MH!LLLLLLLLM gs## 	4666666**733G 	!((&W)M)MNNN???
???@@@D@	+F $$&&& /4D+ !&$)!JJ"OJ                -}H y**l::**,,,++---,0)#W-   D    D ! ."[]]
&_..
	As 	A 	A 	A 	A 	A 	A 	A '-0$j$2FG.0@A	  
   """.3 . . . . . . M Jw$<$< G 
        > %+9TJJJL    !M'')) %+4!344 $+ <(,(=(A(A#(A(N(N( "  $2 )d6L ) (!"OPPP)5 * 0 0 0 J00???
%'36K'K%)$__ !l$5$5$5$5$&HHJ0G0G .f .f_bcp_q_qrusuru_v .f .f9<TZ=X9Y9Y.f .fBF*Ba.f .f .f %g %g %g 5>dj>Y4Z4Z %l %lS(*1jC1j1jcNf1j1j1j(k(k(k(k%l!l !l !l !l !l !l !l !l !l !l !l !l !l !l !l $- % % % $%!/"0 !; < < < ((d(;;;;;< !%%c***K '')) %+X ( #())  J %%c%222'0022  t^U;; ((** NN# %*	   !!"!---NNNNNN++----        ! 1Z%;t$$$)OOCO000 !   JKK ^d  )C

:t?X(Y(Y(Yim  jCD% <BIvzz"2B777rH  F 6::h+?+? 

S\H]H] 
FFFFFF$$( 1    !   D  Z6::h// Z6::i3H3H ZRZ Z%zz'?CC3\33 ) Z-2D*XXXRVXXYYY #O ^&**]33 ^"(**-@"A"A"R] ^ ^'*]]HLR!],@%!H!H!HX] (/t5QSX'Y'Y$" Tv T6N T"JJ'788	 T022:A+GUS\\1F#YY7YEC
A<N<N4NYYSWYYE#BBQBBDBBE%OO--88::E5zzB,0IIeCRCj,A,A))-b$-b-bs5zzB-b-b\`-b-bb)),5OO,=,=)RRR$R0AR4RR5RRSSS ! 2 !	+FFFFFF+O--E!../?NNE"'//2CY"O"OK!&	!J!JJJ  + + +(E"+K!*JJJ+
 %+$^

80D0D0]

S\H]H]!#'#7#mD<S#m\mXm $ )> GX 022:AGGGUa!e_GGGGHHHH%  $/MMM!'',X66?+??U???$*%0($0 &) ) )    $ #
  &&&
  """  fjj55 fjj>W>W #ZZQ77
5Er!J!JJJ '
4Db I II<T < <&< <)2< <59< <    8 4E  5"   %'''  2741A#B#B 2,-	/5577  $ 5 @ @ B B  4%,,U333 ;    /5577   99Y//	NN"3B3-CMMB4F4F55BOq55T1TT'TTTUUUUGWGGGHHH#''111 %))$////    D%   %**=*=*?*?%**** &%  	 	 	-A--   444 %))$////    D%   %**=*=*?*?%***** &%%%	 %))$////    D%   %**=*=*?*?%**** &%s  C*H :H 
H+H&&H+60w1 '=L% $w1 %M6w1 8	Mw1 MC7w1 <,V (w1 )?V )V B/U?3V ?VV VV 
V 
VV VV w1 %Ww1 WCw1 Z" !w1 "
Z/,w1 .Z//C0w1  $_ w1 
_w1 _H5w1 Ai w1 i.+w1 -i..H$w1 0s w1 sw1 sB-w1 v
v)(v)1
z;zz
 x* *
x76x7zz
 
{9z$#{9$
z1.{90z11A{9c           	         t                       t          | j                  }|dk    rt          d | j        D                       }t          d | j        D                       }t          j                    | j        z
  }t          t          |                                          d          \  }}t          |d          \  }}|dk    r| d| d| d}	n|dk    r	| d| d}	n| d}	d	}
| j	        r1	 | j	        
                    | j                  }
n# t          $ r Y nw xY wt          d
           t          d| j                    |
rt          d|
 d           t                       t          d| j                    |
rt          d|
            t          d|	            t          d| d| d| d           d	S 	 ddlm}  |d          }n# t          $ r d}Y nw xY wt          |           d	S )z:Print session resume info on exit, similar to Claude Code.r   c                 D    g | ]}|                     d           dk    |S r  r`  r  s     rC   r  z1HermesCLI._print_exit_summary.<locals>.<listcomp>  s-    ]]]1QUU6]]V\E\E\QE\E\E\rL   c                 n    g | ]2}|                     d           dk    s|                     d          0|3S )r  r  r  r`  r  s     rC   r  z1HermesCLI._print_exit_summary.<locals>.<listcomp>  sB    uuuAaeeFmmW]F]F]abafafgsatatF]aF]F]F]rL   r  r   zh m r  NzResume this session with:z  hermes --resume z  hermes -c "r=  zSession:        zTitle:          zDuration:       zMessages:       r  z user, z tool calls))get_active_goodbyeu   Goodbye! ⚕)r  r  rd  r   r  r6  divmodr  r  r8  rD  ra  r>   r	  r	  )r  r  	user_msgsr  r  hoursrG  minutessecondsduration_strsession_titler	  goodbyes                rC   _print_exit_summaryzHermesCLI._print_exit_summary  s   122	q==]](A]]]^^Iuu)BuuuvvJlnnt'99G%c'*?*?*A*A&B&BDIIE9%i44GWqyy"'@@7@@g@@@1")77W777")}}} !M $($4$F$Ft$W$WMM    D -...8t88999 :8}888999GGG6T_66777 :8889993\33444\Y\\)\\J\\\]]]]])EEEEEE,,^<< ) ) )()'NNNNNs$   6D 
D#"D#G G)(G)c                    	 ddl m}  |d          }n# t          $ r d}Y nw xY w|pd                                dz   }	 ddlm}  |            }|dvr| d| }n# t          $ r Y nw xY w|                                }|sdS |                                }|r|d         nd	d
}t          fd|D                       r|                                dz   fS ||fS )u  Return ``(normal_prompt, state_suffix)`` for the active skin.

        ``normal_prompt`` is the full ``branding.prompt_symbol``.
        ``state_suffix`` is what special states (sudo/secret/approval/agent)
        should render after their leading icon.

        When a profile is active (not "default"), the profile name is
        prepended to the prompt symbol: ``coder ❯`` instead of ``❯``.
        r   )get_active_prompt_symbolrv	  rA  r  )rS   r  )rv	  rv	  r  rO   )u   ❯>rr  r  u   ›   »u   →c              3       K   | ]}|v V  	d S r_   r  )r  rE  	candidates     rC   r  z4HermesCLI._get_tui_prompt_symbols.<locals>.<genexpr>   s'      552rY555555rL   )r	  r	  r>   r  r  r  r  any)	r  r	  symbolr  rf  rp  r   arrow_charsr
  s	           @rC   _get_tui_prompt_symbolsz!HermesCLI._get_tui_prompt_symbols  s_   	GGGGGG--f55FF 	 	 	FFF	 "F**,,s2	CCCCCC--//G333#..f.. 	 	 	D	==?? 	"!>  !&.E"IIB	@555555555 	49++--333 v~s    $$A 
A*)A*c                 z    d}t          | dd          }|dS |j        }t          |d          dz  dz  }||         S )z;Return a visual audio level indicator based on current RMS.u    ▁▂▃▄▅▆▇r_  NrO   i@  r  )rm  current_rmsr  )r  _LEVEL_BARSr+	  rmsrG  s        rC   _audio_level_barzHermesCLI._audio_level_bar   sN    .d-t44;2o C"d*5!!rL   c                    |                                  \  }|                     |                                           ddt          dt          dt          ffd}| j        r!|                                 } |dd|          S | j        r |d	d
          S | j        r |dd          S | j        r |dd          S | j	        r |dd          S | j
        r |dd          S | j        r |dd          S | j        r |d|                                           S | j        r |dd          S | j        r |dd          S d|fgS )zFReturn the prompt_toolkit fragments for the current interactive state.r  rO   r   rd  r  c                     r7|}|r+| d|                                                                  }| |dz   fgS |r| | d| d fgS | | d fgS )NrA  )rI   r  )r   rd  r  ru  r   state_suffixs       rC   _state_fragmentz<HermesCLI._get_tui_prompt_fragments.<locals>._state_fragment)   s     - >"44U[[]]44;;==Ds
+,, C4 @ @% @ @, @ @ABBt44l44566rL   zclass:voice-recordingu   ●zclass:voice-processingu   ◉zclass:sudo-promptu   🔐u   🔑zclass:prompt-workingu   ⚠class:clarify-selectedu   ✎r\  u   ⚕zclass:voice-promptu   🎤zclass:promptr|	  )r
  r  r  rX   r`  r
  ra  rG  rP  rJ  rE  rD  rV  rt  r>  r]  )r  r
  r
  r  r   r
  s       @@rC   _get_tui_prompt_fragmentsz#HermesCLI._get_tui_prompt_fragments$   s   #;;==..T5Q5Q5S5S.TT	7 	73 	7c 	7# 	7 	7 	7 	7 	7 	7 	7   	H''))C"?#:E3GGG! 	D"?#;UCCC 	@"?#6??? 	@"?#6??? 	B"?#95AAA! 	D"?#;UCCC 	@"?#93???  	Z"?#94;V;V;X;XYYY 	B"?#95AAA 	A"?#7@@@())rL   c                 d    d                     d |                                 D                       S )z6Return the visible prompt text for width calculations.rO   c              3       K   | ]	\  }}|V  
d S r_   r  r  s      rC   r  z1HermesCLI._get_tui_prompt_text.<locals>.<genexpr>L   s&      LL4tLLLLLLrL   )r   r
  r  s    rC   _get_tui_prompt_textzHermesCLI._get_tui_prompt_textJ   s/    wwLL4+I+I+K+KLLLLLLrL   c                     t          t          | di           pi           }	 ddlm} |                     |                       n# t
          $ r Y nw xY w|S )zFLayer the active skin's prompt_toolkit colors over the base TUI style._tui_style_baser   )"get_prompt_toolkit_style_overrides)r  rm  r	  r
  r  r>   )r  
style_dictr
  s      rC   _build_tui_style_dictzHermesCLI._build_tui_style_dictN   s    '$(92>>D"EE
	QQQQQQ@@BBCCCC 	 	 	D	s   #A 
AAc                     t          | dd          rt          | dd          sdS t          j        |                                           | j        _        |                     d           dS )z=Refresh prompt_toolkit styling for a running interactive TUI.r5  Nr
  Fr  rv  T)rm  PTStyle	from_dictr
  r5  r   r{  r  s    rC   r-  zHermesCLI._apply_tui_skin_styleX   sl    tVT** 	'$@QSW2X2X 	5!+D,F,F,H,HII	c***trL   c                     g S )a#  Return extra prompt_toolkit widgets to insert into the TUI layout.

        Wrapper CLIs can override this to inject widgets (e.g. a mini-player,
        overlay menu) into the layout without overriding ``run()``.  Widgets
        are inserted between the spacer and the status bar.
        r  r  s    rC   _get_extra_tui_widgetsz HermesCLI._get_extra_tui_widgetsb   s	     	rL   c                    dS )a  Register extra keybindings on the TUI ``KeyBindings`` object.

        Wrapper CLIs can override this to add keybindings (e.g. transport
        controls, modal shortcuts) without overriding ``run()``.

        Parameters
        ----------
        kb : KeyBindings
            The active keybinding registry for the prompt_toolkit application.
        input_area : TextArea
            The main input widget, for wrappers that need to inspect or
            manipulate user input from a keybinding handler.
        Nr  )r  kb
input_areas      rC   _register_extra_tui_keybindingsz)HermesCLI._register_extra_tui_keybindingsk   s      rL   )model_picker_widgetspinner_widgetc          	          d t          d          |||||||g|                                 ||	|
||||D             S )zAssemble the ordered list of children for the root ``HSplit``.

        Wrapper CLIs typically override ``_get_extra_tui_widgets`` instead of
        this method.  Override this only when you need full control over widget
        ordering.
        c                     g | ]}||S r_   r  r  s     rC   r  z8HermesCLI._build_tui_layout_children.<locals>.<listcomp>   s,     
 
 
" !# " "!!rL   r   height)r   r
  )r  sudo_widgetsecret_widgetapproval_widgetclarify_widgetr#
  r$
  spacer
status_barinput_rule_top	image_barr!
  input_rule_botvoice_status_barcompletions_menus                  rC   _build_tui_layout_childrenz$HermesCLI._build_tui_layout_childrenz   s    0
 
a   # ,,..      !  !!
 
 
 	
rL   c                 )   \]^_`abcdefg 	 t          j                    j        }|dk    rt          d|dz
  z  dd           n# t          $ r Y nw xY w                                   j        r(                                 r                                  	 ddl	m
}  |            }|                    d	d
          }|                    dd          }n# t          $ r d
}d}Y nw xY w j                            d| d| d           	 ddlm}  |            }	 |                    dd          }n# t          $ r d}Y nw xY w j                            d| d| d           n# t          $ r Y nw xY w j        rT j        sMd                     j                  }	 j                            dt'                       d|	            d _         j                                         d _        t+          j                     _        t+          j                     _        d _        d _        ddlm}
   |
            _        ddlm}  |            }|                                 r|!                                j"        nd _#         j$        %                    d          pi  _&        d _'        d _(        d _)        d _*        d _+        d _,        d _-        d _.        d _/        ta          j1                     _2        d _3        d _4        d _5        d _6        g  _7        d _8        ta          j1                     _9        d _:        d _;        d _<        d _=        d _>        d _?        ta          j@                     _A         jA        B                                 t           jD                   t           jF                   t           jH                   	 ddlImJ}  |d          }|T j$        %                    d i           pi }|%                    d!d          }|rt          d"t           d#t                      n# t          $ r Y nw xY wt                      }|O                    d$           fd%            }|O                    d&d$          d'             }|O                    d(          d)             }|O                    d*d+          d,             }|O                    d-t           fd.          /           fd0            }|O                    d1t           fd2          /           fd3            }|O                    d-t           fd4          /           fd5            }|O                    d1t           fd6          /           fd7            }|O                    d-t           fd8          /           fd9            }|O                    d1t           fd:          /           fd;            }t           fd<          }|O                    d-|/          d=             }|O                    d1|/          d>             }|O                    d?          f fd@            }|O                    dA           fdB            } t           fdC          }!|O                    d&|!dD           fdE            }"|O                    dF          dG             }#	 ddHlmQ}$  |$            %                    dIi           %                    dJdK          }%|%R                                S                    dLdM          S                    dNdO          }&n# t          $ r dP}&Y nw xY w|O                    |&          ffdQ            }'ddRlTmU}( |O                    |(jV        d+          `a fdS            })|O                    dT           fdU            }*|O                    d&dV           fdW            }+ fffdX},ddYlWmX}- t          dZ fjZ        [          }.t          t          dd\d]          |,d^ddt          ffd_          t          t           j_                            |.dt           |-            |.`          a
  
        gg fdb}/|/gja        _b        dg`dgcdgbdga`abcfdc}0gjc        xjd        |0z  c_d        gje        jf        g                    t          t                      t          ffdd          /                      G de dft                    }1ffdg}2gje        jf        g                     |1|2                     ffdh}3ffdi}4ffdj}5ffdk}6t          t          |5          |6dl          }7t          t          |3          |4m          }8ddpt          dqt          t                   drt          dst          dtt          f
du_ddvt          dwt          dxt          dtt          t                   fdyddzt          d{t          dvt          d|t          dtdf
d}]dzt          d|t          dtdfd~\\]_dffd}9t          t          t          |9          d          t          ffd          /          }:\]_ffd};t          t          t          |;          d          t          ffd          /          }<\]_ffd}=t          t          t          |=          d          t          ffd          /          }>ffd}?t          t          t          |?          d          t          ffd          /          }@\]_dffd}At          t          t          |A          d          t          ffd          /          }Bt          dffdd          }Ct          dffdd          }D fffd}Et          t          |E          t          ffd          m          }Fffd}Gt          t          t          |G          d          t          ffd          /          }Ht          t          t          ffd          ddl          t          ffd          /          }I p                    |g           t          dd          }Jt          t           t                    |<|>|@|:|B|7|8|I|C|Fg|D|H|J                              }Ki ddddddddddddddddddddddddddddddddddi ddddddddddddddddēddddǓddddǓdddddd͓ddddГdddddddd֜ _u        t          jw         x                                          }Lt          d|K||Ldddלt          	dt          ini ee _{        ej|        ^^efdل}M|Me_|         fdڄ}Nta          j}        |Ndۦ          }O|O~                                 e fd܄}Pta          j}        |Pdۦ          }Q|Q~                                 t          j        t                     d݄ }R	 ddl}S|S                    |Sj        |R           t	          |Sdަ          r|S                    |Sj        |R           n# t          $ r Y nw xY wd߄ }T	 ddl}U|U                    d           nD# t          $ r6 t          d           t                                                         Y dS w xY w	 t                      5  	 ddl}V|V                                }W|W                    |T           n# t          $ r Y nw xY we                                 ddd           n# 1 swxY w Y   nr# t          t           t"          f$ r Y nVt$          t          f$ rA}Xdt          |X          v sdt          |X          v rt          d|X d           n Y d}X~Xnd}X~Xww xY wd _         j        r=t)           dd          r+	  j                                         n# t          $ r Y nw xY w j        r@ j        r9	  j                             j                   n# t          t           f$ r Y nw xY wt	           d          r9 j<        r2	  j<                                         n# t          $ r Y nw xY wd _<        	 ddlm}Y  |Y             n# t          $ r Y nw xY wt          d           t          d           t          d           t	           d          rp j        ri j        rb	  j                             j        j        d           n;# t          t           f$ r&}Zt<                              d|Z           Y d}Z~Znd}Z~Zww xY w j        rqt)           dd          r_	 ddlm}[  |[d j        j        ddt)           j        dd          t)           j        dd          pd           n# t          $ r Y nw xY wt                                                         dS # d _         j        r=t)           dd          r+	  j                                         n# t          $ r Y nw xY w j        r@ j        r9	  j                             j                   n# t          t           f$ r Y nw xY wt	           d          r9 j<        r2	  j<                                         n# t          $ r Y nw xY wd _<        	 ddlm}Y  |Y             n# t          $ r Y nw xY wt          d           t          d           t          d           t	           d          rp j        ri j        rb	  j                             j        j        d           n;# t          t           f$ r&}Zt<                              d|Z           Y d}Z~Znd}Z~Zww xY w j        rqt)           dd          r_	 ddlm}[  |[d j        j        ddt)           j        dd          t)           j        dd          pd           n# t          $ r Y nw xY wt                                                         w xY w)z=Run the interactive CLI loop with persistent input at bottom.r@  r  r  rO   T)endr  r   r  welcomezAWelcome to Hermes Agent! Type your message or /help for commands.r\  r]  r  rY  r  rg  r  r  r  ri  r  r  z]Activated skills:[/] Fr  r  r  r  N)ensure_installed)log_failuresr  tirith_enabledr  ui   ⚠ tirith security scanner enabled but not available — command scanning will use pattern matching onlyenterc           	      
   j         rS| j        j        j        }j         d                             |           d_         | j                                         dS j        r_| j        j        j        }                    |           | j        j                                         | j                                         dS j	        r/
                                 | j                                         dS j        r/                                 | j                                         dS j        rj        r| j        j        j                                        }|rej        d                             |           d_        d_        | j        j                                         | j                                         dS j        rj        sj        }|d         }|                    d          pg }|t#          |          k     rB|d                             ||                    d_        | j                                         n d_        | j                                         dS | j        j        j                                        }t%          j                  }|s|rQ                    ||          rc                    |          s,d_        | j        j        r| j                                         | j        j                            d           dS t3          j                  }j                                         | j                                         |r||fn|}j        rE|rt9          |          s3j        d	k    r{j                            |           |r|n*d
t#          |           dt#          |          dk    rdnd d}t?          d|dd          t#          |          dk    rdnd            nǉj                             |           	 tB          dz  }	tE          |	d          5 }
ddl#}|
$                    |%                    d           dtM          |          dd         dj         d           ddd           n# 1 swxY w Y   n*# tN          $ r Y nw xY wj                            |           | j        j                            d           dS dS )a  Handle Enter key - submit input.
            
            Routes to the correct queue based on active UI state:
            - Sudo password prompt: password goes to sudo response queue
            - Approval selection: selected choice goes to approval response queue
            - Clarify freetext mode: answer goes to the clarify response queue
            - Clarify choice mode: selected choice goes to the clarify response queue
            - Agent running: goes to _interrupt_queue (chat() monitors this)
            - Agent idle: goes to _pending_input (process_loop monitors this)
            Commands (starting with /) always go to _pending_input so they're
            handled as commands, not sent as interrupt text to the agent.
            r;	  NFrv  r:	  T)r  )append_to_historyr  r   imager  r  rO   z
 attached]r  rz  r}  r	  r  r   r	  z ENTER: queued interrupt msg=r   z, agent_running=r  )(rG  r   r	  ru  r  ry  rP  r	  r  rJ  rQ	  rO  r  rE  rD  rI   r   r  r  rX  r  r  rB  r  rc  r=   r  r>  r  r   r@  r*  rA  r5   r9   r  r  r;  rX   r>   )eventru  r  rv  r:	  r  r  r  r  r	  r	  r	  r  s               rC   handle_enterz#HermesCLI.run.<locals>.handle_enter,!  s     y/4 !1266t<<<#' 	$$&&& ! y/4,,T222	(..000	$$&&& # //111	$$&&& ' 33555	$$&&& % $*= y/4::<< +'(89==dCCC*.D'-2D*I,22444I((*** " 4+A + ,))I..4"c'll***+//0ABBB*.D'I((**** .2D*I((*** 9+06688Dd344J $Gz $G ;;DZ;XX //55 -,0) 9/ -!INN,,,I,22T2JJJF d344%++---	$$&&&,2<4..& 5 59RSW9X9X 5+w66+//888*."v$$4vF4v4vRUV\R]R]abRbRb33hj4v4v4v qwss| qVYZaVbVbegVgVgUUmo q qrrrr-11':::!#/2G#GD!%dC SB 1 1 1 1 "BKK
,C,C *R *Rbefmbnbnorprorbs *R *R:>:M*R *R *R !S !S !SS S S S S S S S S S S S S S S  ) ! ! ! D! '++G444	(...FFFFFI$G $Gs7   2R4 AR(R4 (R,,R4 /R,0R4 4
S SrD  c                 :    | j                             d           dS )z1Alt+Enter inserts a newline for multi-line input.r  Nr	  insert_textr?
  s    rC   handle_alt_enterz'HermesCLI.run.<locals>.handle_alt_enter!  !      ,,T22222rL   zc-jc                 :    | j                             d           dS )zKCtrl+Enter (c-j) inserts a newline. Most terminals send c-j for Ctrl+Enter.r  NrB
  rD
  s    rC   handle_ctrl_enterz(HermesCLI.run.<locals>.handle_ctrl_enter!  rF
  rL   tab)eagerc                 T   | j         }|j        rQ|j        j        }|(|                    d           |j        o|j        j        }|dS |                    |           dS |j        r-|j        j        r!|                    |j        j                   dS |                                 dS )u  Tab: accept completion, auto-suggestion, or start completions.

            Priority:
            1. Completion menu open → accept selected completion
            2. Ghost text suggestion available → accept auto-suggestion
            3. Otherwise → start completion menu

            After accepting a provider like 'anthropic:', the completion menu
            closes and complete_while_typing doesn't fire (no keystroke).
            This binding re-triggers completions so stage-2 models appear
            immediately.
            Nr   )	r	  complete_statecurrent_completiongo_to_completionapply_completion
suggestionru  rC
  start_completion)r?
  r)  rT  s      rC   
handle_tabz!HermesCLI.run.<locals>.handle_tab!  s     &C! ' /B
%((+++!$!3!]8J8]J%F$$Z00000 'CN$7 ' 344444 $$&&&&&rL   upc                  <    t           j                  o j         S r_   r  rD  rE  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  s    tD4G/H/H/gQUQgMg rL   )filterc                     j         rAt          dj         d         dz
            j         d<   | j                                         dS dS )z%Move selection up in clarify choices.r   rv  r  N)rD  r~  r   ry  r?
  r  s    rC   
clarify_upz!HermesCLI.run.<locals>.clarify_up!  sY     " '25a9LZ9X[\9\2]2]#J/	$$&&&&&' 'rL   downc                  <    t           j                  o j         S r_   rU
  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  s    d6I1J1J1iSWSiOi rL   c                     j         rlj                             d          pg }t          |          }t          |j         d         dz             j         d<   | j                                         dS dS )z'Move selection down in clarify choices.r:	  rv  r  N)rD  r   r  r  r   ry  )r?
  r:	  max_idxr  s      rC   clarify_downz#HermesCLI.run.<locals>.clarify_down!  s     " '-11)<<Bg,,25gt?RS]?^ab?b2c2c#J/	$$&&&&&	' 'rL   c                  ,    t           j                  S r_   r  rJ  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  s    tD4H/I/I rL   c                     j         rAt          dj         d         dz
            j         d<   | j                                         d S d S Nr   rv  r  )rJ  r~  r   ry  rX
  s    rC   approval_upz"HermesCLI.run.<locals>.approval_up!  sW    # '36q$:Nz:Z]^:^3_3_$Z0	$$&&&&&' 'rL   c                  ,    t           j                  S r_   r`
  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  s    d6J1K1K rL   c                     j         r^t          j         d                   dz
  }t          |j         d         dz             j         d<   | j                                         d S d S )Nr:	  r  rv  )rJ  r  r  r   ry  )r?
  r]
  r  s     rC   approval_downz$HermesCLI.run.<locals>.approval_down!  sr    # 'd29=>>B36w@TU_@`cd@d3e3e$Z0	$$&&&&&' 'rL   c                  ,    t           j                  S r_   r  rO  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  s    tD4L/M/M rL   c                     j         rOt          dj                             dd          dz
            j         d<   | j                                         d S d S rb
  )rO  r~  r   r   ry  rX
  s    rC   model_picker_upz&HermesCLI.run.<locals>.model_picker_up!  sd    ' '7:1d>V>Z>Z[egh>i>ilm>m7n7n(4	$$&&&&&' 'rL   c                  ,    t           j                  S r_   rh
  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  s    d6N1O1O rL   c                 n   j         }|sd S |                    d          dk    r%t          |                    d          pg           }n't          |                    d          pg           dz   }t          ||                    dd          dz             |d<   | j                                         d S )Nru  r   rp  r  r  rv  r   )rO  r   r  r  r   ry  )r?
  r  r]
  r  s      rC   model_picker_downz(HermesCLI.run.<locals>.model_picker_down!  s    ,E yy!!Z//eii44:;;eii55;<<q@ #GUYYz1-E-E-I J JE*I  """""rL   c                  T     j          o j         o j         o j         o j         S r_   )rD  rJ  rG  rP  rO  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>!  sT    ++  ^D4H0H  ^QUQaMa  ^jnj|f|  ^  FJ  F^  B^ rL   c                 P    | j         j                            | j                   dS )zAUp arrow: browse history when on first line, else move cursor up.r  N)r   r	  auto_uprI  rD
  s    rC   
history_upz!HermesCLI.run.<locals>.history_up "  s(     I$,,59,=====rL   c                 P    | j         j                            | j                   dS )zDDown arrow: browse history when on last line, else move cursor down.rp
  N)r   r	  	auto_downrI  rD
  s    rC   history_downz#HermesCLI.run.<locals>.history_down"  s(     I$..UY.?????rL   zc-cc                    ddl }|                                 }d}d}j        5  j        rj        rj        }d_        d_        d}ddd           n# 1 swxY w Y   |rgt          dt           dt                      t          j	        |j
        d                                           | j                                         dS j        rBj        d                             d	           d_        | j                                         dS j        rM                                 | j        j                                         | j                                         dS j        rBj        d                             d
           d_        | j                                         dS j        rM                                 | j        j                                         | j                                         dS j        rgj        d                             d           d_        d_        | j        j                                         | j                                         dS j        rwj        rp|j        z
  dk     r1t9          d           d_        | j                                         dS |_        t9          d           j                                         dS | j        j        j         sj!        rR| j        j                                         j!        "                                 | j                                         dS d_        | j                                         dS )aV  Handle Ctrl+C - cancel interactive prompts, interrupt agent, or exit.
            
            Priority:
            0. Cancel active voice recording
            1. Cancel active sudo/approval/clarify prompt
            2. Interrupt the running agent (first press)
            3. Force exit (second press within 2s, or when idle)
            r   NFTr  zRecording cancelled.r  r;	  rO   rD	  z7The user cancelled. Use your best judgement to proceed.g       @u   
⚡ Force exiting...u=   
⚡ Interrupting agent... (press Ctrl+C again to force exit))#r  r\  r`  r_  rb  r*  r  r  rL  r  r/	  r  r   ry  rG  r  rP  r	  r	  r  rJ  rO  r  rD  rE  r>  r   rC  r  rB  rc  r   ru  rX  r  )r?
  rz  r  _should_cancel_voice_recorder_refcli_refr  s        rC   handle_ctrl_cz$HermesCLI.run.<locals>.handle_ctrl_c
"  s    !   **,,C
 $)  M$ 0 0+ 00G 0$+$;M/4G,05G-+/(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 $ =T==t==>>> (/  %'''	$$&&&   !1266r:::#' 	$$&&& ! ++---	(..000	$$&&& # $%56::6BBB'+$	$$&&& ' ((***	(..000	$$&&& " #$4599M   '+#).&	(..000	$$&&&" %tz %//#552333(,D%INN$$$F),&VWWW
$$&&&&& 9+0 %D4I %I,22444)//111I((*****(,D%INN$$$$$s   &AAAzc-dc                 H    d_         | j                                         dS )zHandle Ctrl+D - exit.TN)rB  r   rc  rX
  s    rC   handle_ctrl_dz$HermesCLI.run.<locals>.handle_ctrl_df"  s%     !%DINNrL   c                  :    t           j        p j                  S r_   )r  rP  rG  r  s   rC   r  zHermesCLI.run.<locals>.<lambda>m"  s    D+?t/?@@ rL   )rV
  rJ
  c                 B   j         rM                                 | j        j                                         | j                                         dS j        rBj        d                             d           d_        | j                                         dS dS )z'ESC cancels active secret/sudo prompts.Nr;	  rO   )rP  r	  r   r	  r  ry  rG  r  rX
  s    rC   handle_escape_modalz*HermesCLI.run.<locals>.handle_escape_modalp"  s     ! ++---	(..000	$$&&&  !1266r:::#' 	$$&&&	 rL   zc-zc                 8   ddl }|j        dk    r:t          dt           dt                      | j                                         dS ddlddlddl	m
} ddlm}  |                                dd	          }d| d
| dfd} ||           dS )z:Handle Ctrl+Z - suspend process to background (Unix only).r   Nwin32r  z-Suspend (Ctrl+Z) is not supported on Windows.ra  r  r  r  z' has been suspended. Run `fg` to bring z back.c                  z     j         d                                            j        d j                   d S )Nr  r   )r  encodekillSIGTSTP)_sigr  r`   s   rC   _suspendz6HermesCLI.run.<locals>.handle_ctrl_z.<locals>._suspend"  s;    CJJLL)))4<(((((rL   )r  rb  r*  r  r  r   ry  r`   signalr  rb  r	  r  r  )	r?
  r  rb  r  r  r
  r
  r  r`   s	         @@@rC   handle_ctrl_zz$HermesCLI.run.<locals>.handle_ctrl_z~"  s    JJJ|w&&VTVVPTVVWWW	$$&&&%%%%%%%%BBBBBB>>>>>>(**77nUUJ\z\\*\\\C) ) ) ) ) ) ) OH%%%%%rL   r  r  r	  r	  r	  r	  r	  r	  r	  c                    j         sdS j        rnj        5  d_        ddd           n# 1 swxY w Y   | j                                         t          j        j        d          	                                 dS j
        rdS j        sj        sj        rdS j        rdS j                                        s;	 ddlm}  |             j                                         n# t(          $ r Y nw xY wj        5  d_        ddd           n# 1 swxY w Y   fd}t          j        |d          	                                 | j                                         dS )a!  Toggle voice recording when voice mode is active.

            IMPORTANT: This handler runs in prompt_toolkit's event-loop thread.
            Any blocking call here (locks, sd.wait, disk I/O) freezes the
            entire UI.  All heavy work is dispatched to daemon threads.
            NFTr  r   r-	  c                     	                                   t          d          r"j        rj                                         d S d S d S # t          $ r,} t          dt           d|  t                      Y d } ~ d S d } ~ ww xY w)Nr5  r  zVoice recording failed: r  )rB   ry
  s    rC   _start_recordingzDHermesCLI.run.<locals>.handle_voice_record.<locals>._start_recording"  s    N66888"7F33 6 6#L33555556 6 6 6$ N N N LT L L1 Ld L LMMMMMMMMMNs   AA 
B!A>>B)r]  r`  r\  rb  r   ry  rL  r  r  r  r>  rD  rG  rJ  ra  rd  is_setr  r.	  r   r>   )r?
  r.	  r
  ry
  s      rC   handle_voice_recordz*HermesCLI.run.<locals>.handle_voice_record"  sK    & ' /'( 6 605G-6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 	$$&&& "=   %''''' ) F) W-@ GD[ F , F .5577 BBBBBB%/335555$    ( 5 504G-5 5 5 5 5 5 5 5 5 5 5 5 5 5 5N N N N N  (8FFFLLNNN	$$&&&&&s0   -11)C- -
C:9C:DDD)Keysc                    | j         pd}|                    dd                              dd          }t          |          r-                                r| j                                         |rQddlm}  ||          }|                    d          }| j	        }|dk    r|j
                                                            d          sډ	dxx         d	z  cc<   t          d
z  }|                    dd           |d	d          dt          j                                        d           dz  }|                    |d           d	d          d|d	z    d| d}d}|j        dk    r|j
        |j        d	z
           dk    rd}d
d<   |                    ||z              dS |                    |           dS dS )u  Handle terminal paste — detect clipboard images.

            When the terminal supports bracketed paste, Ctrl+V / Cmd+V
            triggers this with the pasted text. We only auto-attach a
            clipboard image for image-only/empty paste gestures so text
            pastes and dictation do not accidentally attach stale images.

            Large pastes (5+ lines) are collapsed to a file reference
            placeholder while preserving any existing user text in the
            buffer.
            rO   r  r  r   r	  rs  rk  r  pastesTr  paste_r  r  .txtr0   r1   [Pasted text #r      lines → rY  N)rA   rB  r  r(  r   ry  rz  r	  r  r	  ru  rI   r  r5   r  r   r  r;  
write_textr	  rC
  )r?
  r  r	  
line_countr)  	paste_dir
paste_fileplaceholderr  _paste_counter_paste_just_collapsedr  s            rC   handle_pastez#HermesCLI.run.<locals>.handle_paste"  s     **K &--fd;;CCD$OOK;KHH 'TMmMmMoMo '	$$&&& 1::::::22;??(..t44
*??38>>+;+;+F+Fs+K+K?"1%%%*%%% ,x 7IOOD4O@@@!*-qnQ6G-q-q(,..JaJabjJkJk-q-q-q!qJ))+)HHH"s>!3D"s"s
UV"s"sfp"s"s"sKF*Q..38C<ORS<S3TX\3\3\!%/3)!,OOF[$899999OOK00000'1 1rL   zc-vc                 f                                     r| j                                         dS dS )a  Fallback image paste for terminals without bracketed paste.

            On Linux terminals (GNOME Terminal, Konsole, etc.), Ctrl+V
            sends raw byte 0x16 instead of triggering a paste.  This
            binding catches that and checks the clipboard for images.
            On terminals that DO intercept Ctrl+V for paste (macOS
            Terminal, iTerm2, VSCode, Windows Terminal), the bracketed
            paste handler fires instead and this binding never triggers.
            Nr(  r   ry  rX
  s    rC   handle_ctrl_vz$HermesCLI.run.<locals>.handle_ctrl_v"  s=     //11 '	$$&&&&&' 'rL   vc                 f                                     r| j                                         dS dS )u  Alt+V — paste image from clipboard.

            Alt key combos pass through all terminal emulators (sent as
            ESC + key), unlike Ctrl+V which terminals intercept for text
            paste.  This is the reliable way to attach clipboard images
            on WSL2, VSCode, and any terminal over SSH where Ctrl+V
            can't reach the application for image-only clipboard.
            Nr
  rX
  s    rC   handle_alt_vz#HermesCLI.run.<locals>.handle_alt_v#  s:     //11 	$$&&&&& rL   c                  ,                                      S r_   )r
  ry
  s   rC   
get_promptz!HermesCLI.run.<locals>.get_prompt!#  s    44666rL   )AutoSuggestFromHistoryc                      t           S r_   )r  r  rL   rC   r  zHermesCLI.run.<locals>.<lambda>)#  s    O rL   )skill_commands_providercommand_filterr  )r  r~  	preferredzclass:input-areac                  ,    t           j                  S r_   )r  rV  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>2#  s    W-E(F(F rL   )history_suggest	completer)
r(
  r  r   	multiline
wrap_lines	read_onlyr  r
  complete_while_typingauto_suggestc                     	 ddl m}  ddlm} j        j        }t          d |	                                                    }	  |             j        	                                j
        |z
  }n,# t          $ r t          j        d          j
        |z
  }Y nw xY w|dk     rd}d}|j        D ]1} ||          }|dk    r|dz  }|t          d| |z             z  }2t          t          |d          d	          S # t          $ r Y dS w xY w)
Nr   r  r  r@  ry  r  r!  r  r  )r  r  r  r  bufferdocumentr~  r
  r]  r  r  r>   rl   r  r  r  )
r  r  docprompt_widthavailable_widthvisual_linesr  
line_widthr!
  r  s
           rC   _input_heightz$HermesCLI.run.<locals>._input_height>#  sl   >>>>>>;;;;;; '0"1jj1J1J1L1L&M&MNN`&-gii&6&?&?&A&A&IL&XOO  ` ` `&,&>x&H&H&PS_&_OOO`"R''&(O I R RD ",D!1!1J!Q$)$A*1O/P(Q(QQ3|Q//333   qqs7   AC> )A1 0C> 1&BC> BA#C> >
DDc                    | j         }t          |          d         z
  }t          |          d<   	d         rd	d<   |                    d          
d<   dS |                    d          }|
d         z
  }|
d<   |dk    p|dk    }|dk    r|r|                    d          sdxx         dz  cc<   t          d	z  }|                    d
d
           |dd          dt          j                                        d           dz  }|	                    |d           d
	d<   dd          d|dz    d| d| _         t          | j                   | _
        dS dS dS dS )u  Detect large pastes and collapse them to a file reference.

            When bracketed paste is available, handle_paste collapses
            large pastes directly.  This handler is a fallback for
            terminals without bracketed paste support.

            Two heuristics (either triggers collapse):
            1. Many characters added at once (chars_added > 1) — works
               when the terminal delivers the paste in one event-loop tick.
            2. Newline count jumped by 4+ in a single text-change event —
               catches terminals that feed characters individually but
               still batch newlines.  Alt+Enter only adds 1 newline per
               event so it never triggers this.
            r   Fr  Nr  r"  rs  rk  r
  Tr  r
  r  r  r
  r0   r1   r
  r  r
  rY  )ru  r  r  r  r5   r  r   r  r;  r
  r	  )r)  ru  chars_addedr
  newlines_addedis_paster
  r
  r
  r
  _prev_newline_count_prev_text_lens           rC   _on_text_changedz'HermesCLI.run.<locals>._on_text_changed`#  s    8Dd))nQ&77K #D		N1$Q' +0%a()-D)9)9#A&D))J'*=a*@@N%/""Q=.A*=HQ8DOOC4H4Hq!!!Q&!!!(83	t<<<&)m.2C)m)mhlnnF]F]^fFgFg)m)m)mm
%%dW%===+/%a(lN1,=llall_illl&)#(mm### rL   c                  T    t           j                  pt           j                  S r_   )r  rG  rP  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>#  s"    D!455Tg>S9T9T rL   c                       e Zd ZdZd Zd ZdS ),HermesCLI.run.<locals>._PlaceholderProcessorz?Render grayed-out placeholder text inside the input when empty.c                     || _         d S r_   )	_get_text)r  get_texts     rC   r  z5HermesCLI.run.<locals>._PlaceholderProcessor.__init__#  s    !)rL   c                     |j         j        s<|j        dk    r1|                                 }|rt	          |j        d|fgz             S t	          |j                  S )Nr   zclass:placeholder)	fragments)r
  ru  linenor
  r   r
  )r  tiru  s      rC   apply_transformationzAHermesCLI.run.<locals>._PlaceholderProcessor.apply_transformation#  sg    {' fBINN>>++D f-I\^bHcGd8deeee%====rL   N)r  r  r  r  r  r
  r  rL   rC   _PlaceholderProcessorr
  #  s8        QQ* * *> > > > >rL   r
  c                      j         rdS j        rdS j        rdS j        rdS j        rdS j        rdS j        rdS j        r$                                } j	        pd}|  d| S j
        rd	S j        rd
S dS )Nz-recording... Ctrl+B to stop, Ctrl+C to cancelztranscribing...u6   type password (hidden), Enter to submit · ESC to skipu4   type secret (hidden), Enter to submit · ESC to skiprO   z%type your answer here and press Enterrn  rA  z5type a message + Enter to interrupt, Ctrl+C to cancelztype or Ctrl+B to record)r`  ra  rG  rP  rJ  rE  rD  rV  rt  rW  r>  r]  )framer  ry
  s     rC   _get_placeholderz'HermesCLI.run.<locals>._get_placeholder#  s    ' GFF( )((" POO$ NMM& r( ?>>% r' +6688 0K4K**&***% ONN" 2112rL   c                     dd l } j        rAt          dt          j        |                                 z
                      }ddd| dfgS j        rAt          dt          j        |                                 z
                      }ddd| dfgS j        rAt          dt          j	        |                                 z
                      }ddd| dfgS j
        rYt          dt          j        |                                 z
                      }j        rd| dnd}j        rd	d|fgS dd|fgS j        r                                }d
d| dfgS g S )Nr   )
class:hintu"     password hidden · Enter to skipzclass:clarify-countdown  (zs))r
  u      secret hidden · Enter to skip)r
  u%     ↑/↓ to select, Enter to confirmrO   )r
  z"  type your answer and press Enterr
  r  u2    command in progress · input temporarily disabled)r  rG  r~  r  rH  rx  rP  rQ  rJ  rK  rD  rF  rE  rV  rt  )rz  r[  	countdownr
  ry
  s       rC   get_hint_textz$HermesCLI.run.<locals>.get_hint_text#  s       " 3w'=@Q@Q'Q#R#RSS	H.0Ci0C0C0CD 
 $ 3w'?%//BSBS'S#T#TUU	F.0Ci0C0C0CD 
 & 3w'AEOODUDU'U#V#VWW	K.0Ci0C0C0CD 
 % 3w'@5??CTCT'T#U#UVV	3:3LT/)////RT	, L2I> 
 L.	: 
 ' 6688!#a#a#a#ab  IrL   c                  v     j         s j        s j        s j        s j        rdS                                  S )Nr  )rG  rP  rJ  rD  rV  r  r
  s   rC   get_hint_heightz&HermesCLI.run.<locals>.get_hint_height#  sU    " g&; w?V ZaZp t{  uM q //111rL   c                     j         } | sg S j        }|dk    r`dd l}|                                |z
  }|dk    r-t	          |dz            t	          |dz            }}| d| d}n|dd}dd|  d| d	fgS dd|  fgS )
Nr   r   r	  r  rK  r
  r  r
  r  )rR  rS  r  rx  r  )txtt0rz  r  _m_selapsed_strry
  s          rC   get_spinner_textz'HermesCLI.run.<locals>.get_spinner_text#  s    'C 	)BAvv$$$$//++b0b== B//Wr\1B1BB%'..2...KK%,"3"3"3"3K%'BC'B'BK'B'B'BCDD!:::.//rL   c                  ,                                      S r_   )r  r
  s   rC   get_spinner_heightz)HermesCLI.run.<locals>.get_spinner_height$  s    11333rL   )r  r(
  r
  )r  r(
  rS	  r  r  rU	  rV	  r  r-   c           	         t          j        d          j        }t          t	          |           gd |D             z   |dz
  gz             }t          t          |dz   |dz
            |dz
  t          d|dz
                      }|dz   S )zBChoose a stable panel width wide enough for the title and content.rX	  c                 ,    g | ]}t          |          S r  rH  r  s     rC   r  z;HermesCLI.run.<locals>._panel_box_width.<locals>.<listcomp>$  s    )N)N)N#d)))N)N)NrL   r"  r@  r  r  rZ	  )r  rU	  rV	  r  r[	  r\	  r  s          rC   r]	  z'HermesCLI.run.<locals>._panel_box_width$  s    0;;CI3u::,)N)N)N)N)NNR[^_R_Q``aaGGaKQ77QBPY\]P]H^H^__E19rL   ru  rw  r^	  c                 Z    t          j        | t          d|          dd|          }|pdgS )Nr  F)rw  break_long_wordsbreak_on_hyphensr^	  rO   rb	  rd	  s       rC   rf	  z'HermesCLI.run.<locals>._wrap_panel_text$  s=    m!Umm!&!&"3  G ?rd"rL   r  rg	  rh	  c                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S rj	  rk	  rl	  s         rC   rm	  z)HermesCLI.run.<locals>._append_panel_line%$  rn	  rL   c                 F    |                      |dd|z  z   dz   f           d S rp	  rq	  rr	  s      rC   rs	  z/HermesCLI.run.<locals>._append_blank_panel_line+$  rt	  rL   c                     "j         } | sg S | d         }|                     d          pg }|                     dd          } !|d          }t          |          D ];\  }}||k    r	"j        sdnd}|                     !| | dd                     <"j        rd	n|t          |          k    rd
nd}|                     !|dd                       d|          }	t          d|	dz
            }
g }|rt          |          D ]B\  }}||k    r	"j        sdnd} !| | |
d          D ]}|                    ||f           Ct          |          }||k    r
"j        sd
}n"j        rd	}nd} !||
d          }n"j        r !d|
          }ng }t          j	        d          j
        }d}d}d}t          d||z
            }|t          |          z   t          |          z   }||k    }|r|n|}t          d||z
  t          |          z
  t          |          z
            }t          |d          } !||
          }t          |          |k    r!t          d|dz
            }|d|         dgz   }g }|                    d           |                    d           |                    dddt          d|	t          d          z
  dz
            z  z   dz   f           |s |d|	           |D ]} |dd||	           |s |d|	           "j        r%|s#|D ]} |dd||	           |s |d|	           |rg|D ]%\  }}||k    r	"j        sd nd} |d|||	           &t          |          }||k    r
"j        sd }n"j        rd!}nd}|D ]} |d|||	           |s |d|	           |                    dd"d|	z  z   d#z   f           |S )$a]  Build styled text for the clarify question/choices panel.

            Layout priority: choices + Other option must always render even if
            the question is very long. The question is budgeted to leave enough
            rows for the choices and trailing chrome; anything over the budget
            is truncated with a marker.
            r   r:	  rv  r   r   rv	  r  rw	  u   ❯ Other (type below)u   ❯ Other (type your answer)z  Other (type your answer)Hermes needs your inputr  r@  z7Type your answer in the prompt below, then press Enter.rx	  rs  r  r  r0  Nu   … (question truncated)class:clarify-border   ╭─ )class:clarify-titler
  r
  rA  r6  r  ry	  zclass:clarify-questionclass:clarify-choicer
  zclass:clarify-active-otherrj  rz	  )rD  r   r  rE  r  r  r~  rd   rl   r  r  r  )#r  r   r:	  rv  r	  r  rO	  r  other_labelrh	  r	  r	  re	  	other_idxother_label_mandother_wrappedr	  r	  r	  r	  r  r	  r	  r	  max_question_rowsquestion_wrappedrS  r  r   other_stylers	  rm	  r]	  rf	  ry
  s#                                 rC   _get_clarify_displayz+HermesCLI.run.<locals>._get_clarify_display.$  s    *E 	Z(Hii	**0bGyyQ//H,,Xr::M&w// h h	6#$==9R=X\$$%5%56I6I6I2ae%f%f%fgggg,3,E 2((7?3w<<7O7O331 
   !1!1+rUY!Z!Z!Z[[[(()BMRRI"1i!m44 57N #!*7!3!3 < <IAv'(H}}W=V}VV\`F#3#3v4Gv4G4GIYmq#r#r#r < <&--q'l;;;;<  LL	y((1J('E$$. D'?$$'C$ 0 01ACSgk l l l* # 0 0M$! !
 !# 0;;AIKLNAy>9::I(3~+>+>>]ASASSN!/)!;*<M,,+K #Ay;'>^ATAT'TWZ[hWiWi'i j j #$5r : ://:JKK#$$'8881/!344#3ETE#:>X=Y#Y ELL<===LLKLLLLL0#Q	TWXqTrTrHruvHvAwAw9w2x  |C  3C  D  E  E  E% S((0F	RRR , p p""5*@BZ\cenoooo% S((0F	RRR( W W, r rG&&u.DF\^egpqqqq) W,,U4JIVVV g"0 a aJAw89XgNg44  nDE&&u.DeWV_````  LL	y((1J(":KK. 9">KK"8K, g gG&&u.DkSZ\effff% S((0F	RRRLL0%59;L2MPW2WXYYYLrL   )r
  c                       j         d uS r_   )rD  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>$  s    W%;4%G rL   c                     j         } | sg S d}d} ||g          }g }|                    d           |                    d|f           |                    dddt          d|t          |          z
  d	z
            z  z   d
z   f            |d|            |dd||            |d|           |                    ddd|z  z   dz   f           |S )Nu   🔐 Sudo Password Requiredz5Enter password below (hidden), or press Enter to skipclass:sudo-borderr
  class:sudo-titler
  rA  r6  r   r  ry	  class:sudo-textrj  rz	  )rG  rd   r~  r  )	r  r  bodyrh	  r  rs	  rm	  r]	  ry
  s	        rC   _get_sudo_displayz(HermesCLI.run.<locals>._get_sudo_display$  s!   'E 	1EJD((77IELL9:::LL,e4555LL-sec!YQTUZQ[Q[E[^_E_>`>`6`/adk/klmmm$$U,?KKKu&9;LdT]^^^$$U,?KKKLL-u	8I/JW/TUVVVLrL   c                       j         d uS r_   )rG  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>$  s    W%8%D rL   c                  (   j         } | sg S d}|                     d          pd|                     dd           }|                     d          pi }|                    d          }d}||g}|r#|                    d	t          |                      ||          }g }|                    d
           |                    d|f           |                    dddt          d|t          |          z
  dz
            z  z   dz   f            	|d|            
|dd||           |r 
|ddt          |          |            	|d|            
|dd||            	|d|           |                    ddd|z  z   dz   f           |S )Nu   🔑 Skill Setup Requiredr  zEnter value for r	  secretr	  re  z2Enter secret below (hidden), ESC or Ctrl+C to skipr  r
  r
  r
  rA  r6  r   r  ry	  r
  rj  rz	  )rP  r   insertrX   rd   r~  r  )r  r  r  r	  	help_textr   rU	  rh	  r  rs	  rm	  r]	  ry
  s            rC   _get_secret_displayz*HermesCLI.run.<locals>._get_secret_display$  s   )E 	/EYYx((`,`uyyU]?^?^,`,`Fyy,,2H V,,IGD#TNM 8$$QI777((>>IELL9:::LL,e4555LL-sec!YQTUZQ[Q[E[^_E_>`>`6`/adk/klmmm$$U,?KKKu&9;LfV_``` m""5*=?PRUV_R`R`bklll$$U,?KKKu&9;LdT]^^^$$U,?KKKLL-u	8I/JW/TUVVVLrL   c                       j         d uS r_   )rP  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>$  s    W%:$%F rL   c                  ,                                      S r_   )r	  r
  s   rC   _get_approval_displayz,HermesCLI.run.<locals>._get_approval_display$  s    ::<<<rL   c                       j         d uS r_   )rJ  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>$  s    W%<D%H rL   c                     j         } | sg S |                     dd          }|dk    rd}g }|                     d          pg D ]}|                    dt          |                    dg                               }|d          d| d	|d
k    rdnd d}|                    d          r|dz  }|                    |           |                    d           d|                     dd           d|                     dd           }n|                     d          pi }|                     d          pg }	d|                    d|                    dd                     }t	          |	          ddgz   }|	rdt          |	           d}nd} ||g|z   dd !          }
t          d"|
d#z
            }g }|                    d$           |                    d%|f           |                    d&d'd(t          d)|
t          |          z
  d*z
            z  z   d+z   f            |d&|
            |d&d,||
            |d&|
           |                     d-d)          }t          |          D ]<\  }}||k    rd.nd/}||k    rd0nd1} ||z   |d12          D ]} |d&|||
           = |d&|
           |                    d&d3d(|
z  z   d4z   f           |S )5Nru  r   u$   ⚙ Model Picker — Select Providerrp  total_modelsr  rn   r  z modelr  r  rO   r  rt  u     ← currentCancelz	Current: r  rU  z on rq  r  r  u   ⚙ Model Picker — r  Provideru   ← BackzSelect a model (z available)z7No models listed for this provider. Use Back or Cancel.rS	  T   )rV	  r  r  r  r
  r
  r
  rA  r6  r   r  ry	  zclass:clarify-hintrv  r
  r
  rv	  r  rw	  rj  rz	  )rO  r   r  rd   r=   r~  r  )r  ru  r  r:	  rb  r  rc  rq  r  r  rh	  r	  r  rv  rQ  rO	  r   r  re	  rs	  rm	  r]	  rf	  ry
  s                      rC   _get_model_picker_displayz0HermesCLI.run.<locals>._get_model_picker_display$  s   /E 	IIgz22E
"">;//52 * *AEE.#aeeHb6I6I2J2JKKE yUUEUU

PRUUUEuu\** 10NN5))))x(((x599_i#H#HxxeiiXjluNvNvxx %		/ : : @b"YY|44:
r0A0A&-J[J[\bdnJoJo0p0prrz**j(-CC UJc*ooJJJDDTD((0@BZ\]]]I"1i!m44ELL<===LL/7888LL0#Q	TWX]T^T^H^abHbAcAc9c2dgn2noppp$$U,BINNNu&<>RTXZcddd$$U,BINNNyyQ//H(11 a aV478OO00I_#&(??//AQeijjj a aG&&u.DeWV_````a$$U,BINNNLL0%59;L2MPW2WXYYYLrL   c                       j         d uS r_   )rO  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>/%  s    W%@%L rL   r6  c                  .                          d          S )Nr  r  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>7%  s    799%@@ rL   zclass:input-rule)charr(
  r   c                  .                          d          S )Nr  r  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda><%  s    799(CC rL   c                  \    j         sg S t          j         j                  } dd|  dfgS )Nzclass:image-badgerA  )rX  r  rY  )badgesry
  s    rC   _get_image_barz%HermesCLI.run.<locals>._get_image_barC%  sF    + 	4(& F )-f---899rL   c                  ,    t           j                  S r_   )r  rX  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>N%  s    T'*B%C%C rL   c                  ,                                      S r_   )r  r
  s   rC   _get_voice_statusz(HermesCLI.run.<locals>._get_voice_statusR%  s    66888rL   r'
  c                       j         S r_   )r]  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>Z%  s
    W%8 rL   c                  ,                                      S r_   )r  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>_%  s    W5V5V5X5X rL   c                       j         S r_   )re  r
  s   rC   r  zHermesCLI.run.<locals>.<lambda>k%  s
    W%@ rL   )r!
  r0  )
max_heightscroll_offset)r)
  r*
  r+
  r,
  r#
  r$
  r-
  r.
  r/
  r0
  r!
  r1
  r2
  r3
  z
input-arear
  z#555555 italicr  zprompt-workingz#888888 italicrq  z
status-barzbg:#1a1a2e #C0C0C0zstatus-bar-strongzbg:#1a1a2e #FFD700 boldzstatus-bar-dimzbg:#1a1a2e #8B8682zstatus-bar-goodzbg:#1a1a2e #8FBC8F boldzstatus-bar-warnzstatus-bar-badzbg:#1a1a2e #FF8C00 boldzstatus-bar-criticalzbg:#1a1a2e #FF6B6B boldz
input-ruler  zimage-badgez#87CEEB boldzcompletion-menuzbg:#1a1a2e #FFF8DCzcompletion-menu.completionz"completion-menu.completion.currentzbg:#333355 #FFD700zcompletion-menu.meta.completionzbg:#1a1a2e #888888z'completion-menu.meta.completion.currentzbg:#333355 #FFBF00zclarify-borderzclarify-titlez#FFD700 boldzclarify-questionz#FFF8DC boldzclarify-choicez#AAAAAAzclarify-selectedzclarify-active-otherz#FFD700 italiczclarify-countdownzsudo-promptz#FF6B6B boldzsudo-borderz
sudo-titlez	sudo-textzapproval-borderzapproval-titlez#FF8C00 boldzapproval-desczapproval-cmdz#AAAAAA italicz#87CEEBz#FF4444 boldz#FFA500 italiczbg:#1a1a2e #87CEEBzbg:#1a1a2e #FF4444 bold)zapproval-choicezapproval-selectedzvoice-promptzvoice-recordingzvoice-processingzvoice-statuszvoice-status-recording)layoutkey_bindingsr   full_screenmouse_supportcursorc                     ddl m}  j        }	 |j        }|j                                        }|r|j        |j        k     rq|j        dk    rf|j        |j        z   dz
  |j        z  }|j        r|j        j        nd}||dz
  z  }|dk    r) | |j	        j
        |j	        j        |z             |_	        n# t          $ r Y nw xY w              d S )Nr   )Pointr  )r  y)prompt_toolkit.data_structuresr(  renderer
_last_sizer]  r  r  _last_screenr(
  _cursor_posr  r)  r>   )	_Ptr+  old_sizenew_sizereflow_factorlast_hr  _original_on_resizer   s	          rC   _resize_clear_ghostsz+HermesCLI.run.<locals>._resize_clear_ghosts%  s*   CCCCCC|H#.#?3355 (8+;;; (1,, ")H,<<q@#+, " $0-44 
 #ma&78Eqyy/2s&24&24u<0 0 0,    !!!!!s   B#B4 4
C Cc                  h   dd l } d}j        sj        s|                     d           $j        r,                    d           |                     d           nJ|                                 }||z
  dk    r|}                    d           |                     d           j        d S d S )Nr   r  r	  rv  r  r	  )r  rB  r5  r  rV  r{  rx  )rz  last_idle_refreshr  r  s      rC   spinner_loopz#HermesCLI.run.<locals>.spinner_loop%  s         #' %y KK$$$( %$$#$666KK$$$$//++C..#55,/)((c(:::KK$$$ ' % % % % %rL   r  c                  `   j         s	 	 j                            d          } n# t          j        $ r j        sΉ                                 	 ddlm} |j	        
                                s|j	                                        }|                    dd          }|                    d          dk    r|                    |          rn+t          |          }|rj                            |           n# t          $ r Y nw xY wY w xY w| sg }t!          | t"                    r| \  } }t!          | t$                    rt'          |           nd }|ry|d	         }|d
         }|d         r:|                    |           |p
d|j         d} t-          d|j                    n't-          d|j                    d| d|rd| ndz   } |sot!          | t$                    rZt/          |           rKt-          d|                                 |           s"d_         j        r                                 Cdd l}	|	                    d          }
t!          | t$                    r"t;          |
                    |                     ng }|rtd }|
                    ||           }|                     d          dz   }tC          |          }dtE                       dd d}tG                       tI                      #                    |           |
%                    |           d&                    fdtO          dtC                    d          D                       }|rStI                      #                    dtE                       dtQ          |           d| d |dk    rd!nd d"| d#           nEtI                      #                    dtE                       dtQ          d$| d%           d           |} n3dtE                       dd d}d| v r| %                    d          d         }|                      d          dz   }tG                       tI                      #                    |           tI                      #                    dtE                       dtQ          |           d&|dz
   d'           nptG                       tI                      #                    |           tI                      #                    dtE                       dtQ          |            d           |r<tC          |          }t-          d(tR           d)| d*|dk    rd!nd d+tT                      d_        +                                 	 ,                    | |pd ,           d-_        d_-        d._.        j/        0                                 d_1        +                                 j2        r<j3        r5j4        s.fd/}tk          j6        |d0          7                                 	 ddlm} |j	        
                                s|j	                                        }|                    dd          }|                    d          dk    r|                    |          rwt          |          }|rj                            |           |j	        
                                nu# t          $ r Y nhw xY w# d-_        d_-        d._.        j/        0                                 d_1        +                                 j2        r<j3        r5j4        s.fd/}tk          j6        |d0          7                                 	 ddlm} |j	        
                                s|j	                                        }|                    dd          }|                    d          dk    r|                    |          rwt          |          }|rj                            |           |j	        
                                w w # t          $ r Y w w xY wxY wn)# t          $ r}tG          d1|            Y d }~nd }~ww xY wj         d S d S )2Nr	  r  r   r]  ra  rO   rS  rT  r?   rG  rm  r  rY  u     📎 Auto-attached image: u     📄 Detected file: z[User attached file: r  u	   
⚙️  Tz,\[Pasted text #\d+: \d+ lines \u2192 (.+?)\]c                     t          |                     d                    }|                                r|                    d          n|                     d          S )Nr  r0   r1   r   )r   groupr6   r  )r  rb  s     rC   _expand_refz8HermesCLI.run.<locals>.process_loop.<locals>._expand_refN&  sO     $QWWQZZ 0 0ADEHHJJ#^1;;;#@#@#@TUT[T[\]T^T^^rL   r  r  r  r  rA  c              3      K   | ]8}|                                          |                                          V  9d S r_   r  )r  r  split_partss     rC   r  z6HermesCLI.run.<locals>.process_loop.<locals>.<genexpr>Y&  s_       5 578]hij]k]q]q]s]s5'N00225 5 5 5 5 5rL   r@  r  u   ]●[/] [bold]z
[/] [dim](z pasted blockr  r  z lines total)[/]z[Pasted text: z lines]z[/] [dim](+z
 lines)[/]r  u   📎 r>
  z	 attachedr  Fr  c                  6   	 j         r/j                            d           t          j        d                                                                             d S # t          $ r+} t          t           d|  t                      Y d } ~ d S d } ~ ww xY w)Nr   r  g333333?r  )r^  rd  waitr  r  r  ry  r>   r*  r  r  )rB   r   r  s    rC   r  z?HermesCLI.run.<locals>.process_loop.<locals>._restart_recording&  s    !['+ %8(,(<(A(A"(A(M(M(M(,
3$($?$?$A$A$A$'NN$4$4$4$4$4'0 ![ ![ ![$+t,Y,YPQ,YSW,Y,Y$Z$Z$Z$Z$Z$Z$Z$Z$Z![s   AA# #
B- BBr  r  )8rB  r@  r   r  r<	  r>  r  rc  r^  completion_queuer	  r	  is_completion_consumedrh  r  r>   r<   r  rX   rt  rd   rn   r*  r  r  r  rc  r  compiler=   finditerr  r  r  r!  r  r  r  r   r  r  r  r  ry  r	  rR  rS  rT  r  rU  r]  rb  r`  rL  r  r  )ri  r^  rQ  _evt_sid_synthsubmit_images
_file_drop
_drop_pathrs  _re_paste_ref_re
paste_refsr<  rM  total_linesn_pastes	_user_barvisible_user_text
first_liner
  rl  r  rB   r>  r   r  s                          @rC   process_loopz#HermesCLI.run.<locals>.process_loop&  s
   ' _)^)!%)%8%<%<S%<%I%I

 ; ! ! !#2 % ::<<<% S S S S S S'7'H'N'N'P'P 	!L*:*K*V*V*X*XC/2ww|R/H/HH'*wwv,'F'FK[KrKrs{K|K|'F(,1Mc1R1R+1 )L,0,?,C,CF,K,K,K#, % % % $% )!, & !  %'M!*e44 ?4>1
M CMZY\B]B]!g!2:!>!>!>cgJ! %/%7
%/%<
%j1 	)00<<<)3)b7bPZP_7b7b7bJ#$T:?$T$TUUUU#$NZ_$N$NOOO E
 E E E8B#J#4
#4#4#4!L '
 & !*Z*E*E !JcdnJoJo ! 9Z 9 9:::#33J?? +04D-"~ + #


  %$$$$'KK0_$`$`MMWXbdgMhMh!pm&<&<Z&H&H!I!I!InpJ! 'p_ _ _ $1#4#4[*#M#M&.nnT&:&:Q&>#&z??$G$G$G
$G$G$G	#++I666&3&9&9*&E&E,/HH 5 5 5 5<A!SEUEUWX<Y<Y5 5 5 - -) - 'MM//!} !} !}QbIcIc !} !})1!} !}GORS||Y[!} !}_j!} !} !}   
 (MM// | | |QvbmQvQvQvIwIw | | |   &.

$G$G$G
$G$G$G	:--)3)9)9$)?)?)BJ)3)9)9$)?)?!)CJ!GGG'MM//	:::'MM//!E !E !EgjFYFY !E !E*4q.!E !E !E   
 "GGG'MM//	:::'MM//0n0n0nV]^hViVi0n0n0nooo % `.. ^T ^ ^ ^ ^A2 ^ ^X\ ^ ^___ +/D'NN$$$)!		*]5Jd	KKK.3+-/*03-/55777572(((  + 
]0F 
]tOd 
][ [ [ [ [ [ &,4FtTTTZZ\\\!OOOOOO&6&G&M&M&O&O D&6&G&R&R&T&T+.77<+D+D#&776??l#B#BGWGnGnowGxGx#B$,)Ec)J)J#) !D$($7$;$;F$C$C$C '7&G&M&M&O&O D  ) ! ! ! D!K /4+-/*03-/55777572(((  + 
]0F 
]tOd 
][ [ [ [ [ [ &,4FtTTTZZ\\\!OOOOOO&6&G&M&M&O&O D&6&G&R&R&T&T+.77<+D+D#&776??l#B#BGWGnGnowGxGx#B$,)Ec)J)J#) !D$($7$;$;F$C$C$C '7&G&M&M&O&O D D D  ) ! ! ! D! ! ) ) )-A--(((((((()} ' _) _) _) _) _)s   ) a; *DB(C=<D=
D
D	D

Da; Da; D,a; Ma; \ 5Ba; C\ a; 
\a; \a; Ba7$Ca'%a7'
a41a73a44a77a; ;
b!bb!c                 T    t                               d|            t                      )z5Handle SIGHUP/SIGTERM by triggering graceful cleanup.z0Received signal %s, triggering graceful shutdown)r7   r  r*  )signumr
  s     rC   _signal_handlerz&HermesCLI.run.<locals>._signal_handler&  s#    LLKVTTT#%%%rL   SIGHUPc                     |                     d          }t          |t                    rdt          |          v rd S t          |t                    rdt          |          v rd S |                     |           d S )N	exceptionzEvent loop is closedis not registered)r   r<   r  rX   KeyErrordefault_exception_handler)loopcontextr  s      rC   _suppress_closed_loop_errorsz3HermesCLI.run.<locals>._suppress_closed_loop_errors&  s}    ++k**C#|,, 1G3s881S1S#x(( -@CHH-L-L**733333rL   zError: stdin (fd 0) is not available.
This can happen with certain Python installations (e.g. uv-managed cPython on macOS).
Try reinstalling Python via pyenv or Homebrew, then re-run: hermes setuprZ  zBad file descriptorz
Error: stdin is not usable (z).
This can happen with certain Python installations (e.g. uv-managed cPython on macOS).
Try reinstalling Python via pyenv or Homebrew, then re-run: hermes setupr>  r_  )cleanup_temp_recordingsr8  	cli_closez!Could not close session in DB: %sr]  on_session_endr   rb  r;  )ra  r	  r	  r   rb  r{	  r|	  r  )rl   r  r  r  r>   r  r7  r  r   r	  r  r  r
  r  r  rh  rZ  r[  r   r!  r>  r  r?  r@  rA  rB  rC  rj  r  _cli_refr  r  r6   r  r  r  r  r   r  r  rD  rE  rF  rG  rH  rI  rJ  rK  rL  rM  rN  rV  rW  rP  rQ  rX  rY  r\  r]  r^  r_  r`  ra  rb  rc  rd  r   rT  r@	  rU  rF	  rV  r	  tools.tirith_securityr8
  r*  r  r  r   re   r   r  rY   rB  prompt_toolkit.keysr
  BracketedPasteprompt_toolkit.auto_suggestr
  rM  r  r   r   r   rX   r<  rN  windowr(
  r
  on_text_changedcontrolinput_processorsrd   r   r   r   r   r   r=   r  r   r"
  r   r   r   r4
  r
  r
  r
  r
  r   _STEADY_CURSORr5  
_on_resizer  r  atexitregisterro  r
  SIGTERMrl  rW  r`   fstatr  r	  r   r|  get_event_loopset_exception_handlerrw  rm  r*  BrokenPipeErrorr[  r   rm  r   rd  r)  r*	  r  r`  r8  r,  ra  r7   r  r^  )hr  _term_linesr  _welcome_skin_welcome_text_welcome_colorrh  r  r  skills_labelr  r  	_cfg_pathr8
  tirith_pathsecurity_cfgr:
  r 
  r@
  rE
  rH
  rR
  rY
  r^
  rc
  rf
  rj
  rm
  _normal_inputrr
  ru
  rz
  r|
  _modal_prompt_activer
  r
  r  r7	  
_voice_keyr
  r
  r
  r
  r
  r
  r
  
_completerr
  r
  r
  r
  r
  r
  r
  r
  r$
  r-
  r
  r,
  r  r)
  r  r*
  r
  r+
  r  r#
  r/
  r1
  r  r0
  r  r2
  r.
  r3
  r"  r   r5  r8  spinner_threadrS  process_threadrV  _signalr_  _os_aio_loop
_stdin_errr`  rB   rn  rs	  rm	  r4  r]	  r
  r
  r
  r
  rf	  r   ry
  r!
  sh   `                                                                                           @@@@@@@@@@@@rC   rw  zHermesCLI.run   s   	 244:KQdkAo.BdCCCC 	 	 	D	 	 = 	0,,.. 0--///	'>>>>>>+O--M)66y  CF  G  GM*44]INNNN 	' 	' 	'_M&NNN	' 	B~BBBBBCCC		666666!>##D'*44\9MM

 ' ' '&


'LFzFFTFFFGGGG 	 	 	D	  	3)H 	399T%:;;LLLLLlLL   /3D+ $#kmm %!!" 	:99999(,% 	JIIIII$$&&	AJAQAQASAS$\INN$4$4$=$=Y\)-)G)G)M2 ),
 #!&!"  %)"  $"#'n.. !&! " ! -/ %>++ # %!&!&(00  """ 	#4#?@@@d5666#D$ABBB

	>>>>>>**>>>K"#{z2>>D"!-!1!12BD!I!I! Z Y Y YRVY Y Z Z Z 	 	 	D	 ]]	j	G j	G j	G j	G 
j	GX 
'	"	"	3 	3 
#	"	3 
	3 	3 
	3 
T	"	"	' 	' 
#	"	'D 
Y'g'g'g'ghh	i	i	' 	' 	' 	' 
j	i	' 
y)i)i)i)ijj	k	k	' 	' 	' 	' 
l	k	' 
Y'I'I'I'IJJ	K	K	' 	' 	' 	' 
L	K	'
 
y)K)K)K)KLL	M	M	' 	' 	' 	' 
N	M	' 
Y'M'M'M'MNN	O	O	' 	' 	' 	' 
P	O	'
 
y)O)O)O)OPP	Q	Q		# 		# 		# 		# 
R	Q		# " ^  ^  ^  ^
 
 
]	+	+	> 	> 
,	+	> 
}	-	-	@ 	@ 
.	-	@ 
Y	% Y	% Y	% Y	% Y	% 
Y	%v 
	 	 	 	 
	
  )@@@@ 
  
 
!5T	B	B	 	 	 	 
C	B	 
	& 	& 
	&(	555555"{}}(("5599,QQH!))11'4@@HHQUVVJJ 	 	 	JJJ	 

		9	' 9	' 9	' 9	' 
	9	't 	-,,,,,	#4	0	0%	1 %	1 %	1 %	1 %	1 %	1 
1	0%	1N 
	' 	' 	' 	' 
	' 
#			 	 	 	 
		" 	7 	7 	7 	7 	7 	GFFFFF +$;$;"5
 
 

 Q777$ F F F FGGD$6 7 788 "&0 6 6 8 8$  
 
 

$	 	 	 	 	 	4 $1
   c!&$	4 $	4 $	4 $	4 $	4 $	4 $	4 $	4L 	))-==))
 	+22 !## TTTT   	
 	
 	
	> 	> 	> 	> 	>I 	> 	> 	>	 	 	 	 	2 	+223H3HIY3Z3Z[[[
+	 +	 +	 +	 +	Z	2 	2 	2 	2 	2	0 	0 	0 	0 	0"	4 	4 	4 	4 	4  ()9::%
 
 
 (77"
 
 
	 	C 	S	 	c 	cf 	ps 	 	 	 		# 	#3 	#s 	#s 	#TXY\T] 	# 	# 	# 	#	3C 	3 	3SV 	3cf 	3ko 	3 	3 	3 	3	N# 	N# 	NRV 	N 	N 	N 	Nx	 x	 x	 x	 x	 x	 x	 x	 x	t .$%9::   GGGGHH
 
 
	 	 	 	 	 	 	 	" +$%677   DDDDEE
 
 
	 	 	 	 	 	 	 	8 -$%899   FFFFGG
 
 
	= 	= 	= 	= 	= /$%:;;   HHHHII
 
 
+	 +	 +	 +	 +	 +	 +	 +	 +	Z 3$%>??   LLLLMM
 
 
  @@@@$
 
 

  CCCC$
 
 
 	: 	: 	: 	: 	: (88CCCCDD
 
 
		9 	9 	9 	9 	9 0$%677   888899
 
 
 *,-X-X-X-XYY !   @@@@AA
 
 

$ 	,,RJ,GGG
 +bJJJ// +"/$3#1(;#1!)#1')#1%5%5 0   
 
,0 
)0 
+0 
 i0 
 .	0 

 $0 
 .0 
  !:0 
 20 
 80 
 80 
 70 
 "#<0 
 )0 
  >!0 
" 3#0 
$ )*>%0 
& 12F'0 
 0 
( ./C)0 
* 67K+0 
. i/0 
0 ^10 
2 30 
4 i50 
6 70 
8 #$490 
:  ;0 
> >?0 
@ 9A0 
B .C0 
D E0 
H yI0 
J nK0 
L ^M0 
N ,O0 
 0 
P  )!/%- 00&?_0 
 0 
 0 
b !$"<"<">">??  

 
 .<-G.))R
 
 	 "n	" 	" 	" 	" 	" 	"< .	% 	% 	% 	% 	%$ #)dKKK`	) `	) `	) `	) `	) `	)F #)dKKK 	%%%	& 	& 	&
	$$$$NN7?O<<<w)) @w~??? 	 	 	D		4 	4 	4	IIaLLLL 	 	 	[  
 NNN$$&&&FF	Q	'  **** //11E//0LMMMM    D			               +_= 	 	 	D'" 
	 
	 
	 #c*oo559NRUV`RaRa9a9a_Z _ _ _        	
	 !%D
 z gd,<eDD J((****    D z d7 J--d.GHHHH!#45   D t.// ,D4H ,(113333    D'+$DDDDDD''))))    't,,,!$''''---t]++ I0@ ITZ II$001FTTTT!#45 I I ILL!DaHHHHHHHHI z gd,<eDD NNNNNN L(#':#8"'$(%dj'4@@!(Z!F!F!O%     !   DNNN$$&&&&&s !%D
 z gd,<eDD J((****    D z d7 J--d.GHHHH!#45   D t.// ,D4H ,(113333    D'+$DDDDDD''))))    't,,,!$''''---t]++ I0@ ITZ II$001FTTTT!#45 I I ILL!DaHHHHHHHHI z gd,<eDD NNNNNN L(#':#8"'$(%dj'4@@!(Z!F!F!O%     !   DNNN$$&&&&s  6A 
AA<C C('C(E) D5 4E) 5EE) E$E) )
E65E6A(Q 
QQ4A4]) )]87]8Az 
zz!z; ;={<;{< }; }/-|?>}/?
}	}/}}/#}; /}33}; 6}37}; :AH6 ;*AH6 *)7% AH6 %**AH6 @A@( @(
A@5@4A@5AAA' A'AA<A;AA<BAB2 B2
AB?B>AB?C
AC C
AC(C'AC(D8%AE EAFE0AFFAFF3AAH H
AHHAHH6!AQ?IAI2I1AQ?I2
AI?I<AQ?I>AI?I?AQ?JAJ1J0AQ?J1AKKAQ?KAKKAQ?K"AK<K;AQ?K<
AL	LAQ?LAL	L	
AQ?LAL%L$AQ?L%
AL2L/AQ?L1AL2L2AAQ?N%AN(N'AQ?N(AO N:AOOAQ?OAO O AQ?O=AAQQ
AQ?Q
AQQAQ?QAQQ'AQ?)NNNNNNFFNFF)ru  )r  )ry  r_   r  )F)r   )NNr|	  )r  )NNN)r  r  r  r  rX   r   r  r  r  r  r{  r	   r  r  r   r   r  staticmethodr  classmethodr  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  rB  rM  r@  rJ  rK  rp  rt  r   rw  r  r  r  r  r  r  r   r(  r8  r=   r2  r[  rh  rm  ru  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r<  rJ  rR  rW  r4  rh  ro  r|  r  r  r  r  r  r  r  r  r  rD  rH  r`  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r	  r  r	  r	  r	  r	  r  r@	  rF	  rE	  rQ	  r	  r	  ry  r~  r	  r	  r	  r	  r	  r
  r
  r
  r
  r
  r-  r
  r"
  r4
  rw  r  rL   rC   r  r  6  s         "! %L* L*L* s)L* 	L*
 L* L* L* L* L* L* L* L* L* L* L*\# # # # # # #	'hsm 	' 	' 	' 	' 	'J Jx} JS JRU J J J J
6$sCx. 6 6 6 6p # # # # # \# 0 0 0 0 0 0 [06 = =sCx = = = = \= Xc] d    E Es E8C= ETW E E E EE E(3- E3 E E E E HSM S     ` `# ` ` ` `$U UHSM US U U U U>@P @P @PDes et e e e eN       $7c $7d $7 $7 $7 $7L 9> /5 /5 /5 /5$ /5 /5 /5 /5b"%C "%D "% "% "% "%H1 1 1 1$J J J JX1Zc 1Zd 1Z 1Z 1Z 1Zf? ? ? ?.$ $ $ $'C 'C ' ' ' '&2 2 2 2 2 /C / / / ^/hT h h h hTs t    @ 48RVko  SW J J JS J4 Jeh J  EI  LP  EP J  \` J J J JXQ Q Qf;$ ; ; ; ;zk" k" k"ZT    &\. \. \. \. \.|3 T cDj    UU UU UU UU UUn6 6 6&H H H2d# d d d d0 [_ A= A= A=3 A= A=SW A=cf A= A= A= A=F  ,&
 &
 &
P3L 3L 3Lj/ / / / /     
$G $G $GL( ( (T2Q 2Q 2Q 2Q 2Qh  >  0 0 0dG G3 GT#s(^8L G G G G 6?R   s s TX    :A A AF3 4     <1 <1 <1 <1|Mg3 Mg4 Mg Mg Mg Mg^m93 m94 m9 m9 m9 m9^0 0 0(  :A A A@  DI c Z]`dZd    <c cDj    0+ +D + +X[ +  EI + + + ++ + + +
LF LF$ LF LF LF LF\=' ='T ='d =' =' =' ='~gF gF gF gF gFR
 
 
 
Z^ 
 
 
 
GB GB GBX 	c 	 	 	 \	,3 ,4 , , , ,\+s + + + +ZsJ sJ sJ sJ sJj0# 0 0 0 0
6 6 6prs rt r r r rhc c c c c4Kc K K K KZrs r r r rh #s #C #D # # # \#Jt3 t t t tl'4 '4 '4 '4 '4R9 9 98  &;\S ;\ ;\ ;\ ;\z)Z )Z )Z )Z )ZV3C 3 3 3 3<4 <4S <4 <4 <4 <4|  UH UH UHn7 7c 7 7 7 7B7b 7b 7b 7brT3 T3 T3t;C ;D ; ; ; ;(I IC I IUX Ipt I I I IV	^3 	^s 	^SW 	^ 	^ 	^ 	^Zc Z# ZVZ Zmp Z Z Z Z(`E `E `EDaQ aQ aQF3'# 3' 3' 3' 3'j9S 9 9 9 9.;D ;D ;Dz7 7 7@7 7 7"# # #$A
 A
 A
F, , , , ,^ 7;5 5 5# 5C 5/35?B5 5 5 5n JN    $ RVWZR[       0X X XtC C Cc CUY C C C C. . . .   S T    ) ) ) )   U+ U+D U+HSM U+ U+ U+ U+n) ) )V%sCx % % % %N
"# 
" 
" 
" 
"$* $* $*LMc M M M MtCH~    t           , !+
 +
 +
" 
#+
 +
 +
 +
ZM' M' M' M' M'rL   r  rd  rz  r  r   r   r   r   r   r   quietr   
list_toolslist_toolsetsgatewayr  r  r  r  r  c                 $   dt           j        d<   |r8ddl}ddlm} t          d           |                     |                       dS |s|s|p|pt                              dd          }d}|rct                      }|rt          |           t                      }|r2|a|d	         t           j        d
<   t          j        t          |           ndS nd}| p|} d}|rt!          |t"                    r d |                    d          D             }nt!          |t&          t(          f          rqg }|D ]l}t!          |t"                    r3|                    d |                    d          D                        J|                    t#          |                     mn$ddlm} t3           |t          d                    }t5          |          }t7          ||||||	|
||||          }|rt9          ||j                  \  }} }!|!r'd                    |!          }"t?          d|"           |rDd                    d |j         |fD                       !                                |_         | |_"        |r/d|d	          d|d          d|d          d}#|j         pd|#z   |_         |r<|#                                 |$                                 tK          j&        d           |r<|#                                 |'                                 tK          j&        d           t          j        tP                     | s|r7tS          | |          \  } }$|rd|_*        |+                                r| }%|$r|,                    | |$d          }%|-                    |%          }&|&d         |j.        k    rd|_/        |0                    |&d          |&d!         |&d"         |&                    d#          $          rd%|j/        _1        d%|j/        _2        d|j/        _3        d|j/        _4        |j/        5                    |%|j6        &          }'t!          |'tn                    r|'                    d'd          nt#          |'          }(|(rt          |(           t          d(|j         tJ          j8        )           tK          j&        t!          |'tn                    r|'                    d*          rd+nd           tK          j&        d+           nh|#                                 | p|$rd,nd})|)r|j9                            d-|)            |:                    | |$pd.           |;                                 dS |                                 dS )/a  
    Hermes Agent CLI - Interactive AI Assistant
    
    Args:
        query: Single query to execute (then exit). Alias: -q
        q: Shorthand for --query
        image: Optional local image path to attach to a single query
        toolsets: Comma-separated list of toolsets to enable (e.g., "web,terminal")
        skills: Comma-separated or repeated list of skills to preload for the session
        model: Model to use (default: anthropic/claude-opus-4-20250514)
        provider: Inference provider ("auto", "openrouter", "nous", "openai-codex", "zai", "kimi-coding", "minimax", "minimax-cn")
        api_key: API key for authentication
        base_url: Base URL for the API
        max_turns: Maximum tool-calling iterations (default: 60)
        verbose: Enable verbose logging
        compact: Use compact display mode
        list_tools: List available tools and exit
        list_toolsets: List available toolsets and exit
        resume: Resume a previous session by its ID (e.g., 20260225_143052_a1b2c3)
        worktree: Run in an isolated git worktree (for parallel agents). Alias: -w
        w: Shorthand for --worktree
    
    Examples:
        python cli.py                            # Start interactive mode
        python cli.py --toolsets web,terminal    # Use specific toolsets
        python cli.py --skills hermes-agent-dev,github-auth
        python cli.py -q "What is Python?"       # Single query mode
        python cli.py -q "Describe this" --image ~/storage/shared/Pictures/cat.png
        python cli.py --list-tools               # List tools and exit
        python cli.py --resume 20260225_143052_a1b2c3  # Resume session
        python cli.py -w                         # Start in isolated git worktree
        python cli.py -w -q "Fix issue #123"     # Single query in worktree
    r
   HERMES_INTERACTIVEr   N)start_gatewayz0Starting Hermes Gateway (messaging platforms)...r  Fr?   r   c                 6    g | ]}|                                 S r  r  rI  s     rC   r  zmain.<locals>.<listcomp>'  s     DDD1QWWYYDDDrL   r  c                 6    g | ]}|                                 S r  r  r  s     rC   r  zmain.<locals>.<listcomp>'  s     )J)J)J!'')))J)J)JrL   r  r;  )r   r  r   r   r   r   r   r   r  r  r  r  r  zUnknown skill(s): r#  c              3      K   | ]}||V  	d S r_   r  )r  r  s     rC   r  zmain.<locals>.<genexpr>'  s;       , ,t,, , , , , ,rL   z?

[System note: You are working in an isolated git worktree at z. Your branch is `r  z`. Changes here do not affect the main working tree or other agents. Remember to commit and push your changes, and create a PR if appropriate. The original repo is at r  z.]rO   rP   rv  r	  r   r  rc  r  r  T)r  rd  r  z
session_id: )r   r	  r  z[image attached]z[bold blue]Query:[/] r?  )<r`   r   r|  gateway.runr  r  rw  r  r   rz  r  r  rp  rn  ro  r  r<   rX   r  r=   r  r  rd   r  r  r  r  r  r  ra  r   r~  r   rI   rZ  r  r  r  rc  r  ro  r  r  r  r  r  r4  r   r  r  suppress_status_outputr  r  r  rd  r  r  r  r	  r	  )*r  rd  rz  r  r  r   r   r   r   r   r   r  r   r  r  r  r  r  r  r  r  r|  r  use_worktreewt_info_repotoolsets_listr  r  parsed_skillsr;  skills_promptloaded_skillsmissing_skillsmissing_displaywt_notesingle_query_imageseffective_queryr  rJ   r  _query_labels*                                             rC   r  r  ;'  s   x (+BJ#$  ------@AAAMMOO$$$  m   I1I
z5(I(I 	"$$E .&u---%''G #* -4V_
>* 17;;;; 	  JQE M Gh$$ 		1DDs0C0CDDDMM4-00 	1M 1 1a%% 1!(()J)JQWWS\\)J)J)JKKKK!((Q0000 	@?????22:uEEFF*622M '  C  17TN8
 8
 8
4}n  	E"ii77OC/CCDDD 	1 & , ,"%"3]!C, , , ! !egg  $1C   @@v@ @29(2C@ @ (/{';	@ @ @ 	 !.4"?    OL!!!  4 4%:5%%H%H"" 1	& &+C"..00 #\"'& &)&H&H+!& 'I ' 'O
 !;;OLL
k*c.OOO $CI??#-g#6%/	%: *7 3&0nn5H&I&I	 #   \ ,0CI(7;CI4 7;CI326CI/ Y77%4-0-E 8  F DNfVZC[C[lvzz*:B???adekalalH (h;3>;;#*MMMM H*VT":":Zvzz(?S?SZQQYZ[[[ HQKKKKOO W;N%V%7%7TVL J!!"H,"H"HIIIHHU#6#>$H???##%%% GGIIIIIrL   __main__r_   )r  )r6  )NNNNNNNNNNFFFFFFNFFFF)r  r  r`   rl   r  r:   rn  r	  r  r  r  
contextlibr   pathlibr   r   typingr   r   r   r	   r  r  r7   r   r  prompt_toolkit.historyr   prompt_toolkit.stylesr   r
  prompt_toolkit.patch_stdoutr   r  r   prompt_toolkit.layoutr   r   r   r   r    prompt_toolkit.layout.processorsr   r   r   r   prompt_toolkit.filtersr   prompt_toolkit.layout.dimensionr   prompt_toolkit.layout.menusr   prompt_toolkit.widgetsr   prompt_toolkit.key_bindingr   prompt_toolkitr   r(  prompt_toolkit.formatted_textr   r)  prompt_toolkit.cursor_shapesr    BLOCKrl  r  AttributeErrorrL  r  agent.usage_pricingr!   r"   r#   r$   hermes_cli.bannerr%   r&   rr  rH   r'   r(   hermes_cli.env_loaderr)   r5   r  r  _project_envrX   rD   r  rK   r[   r=   r   r9  r  hermes_loggingr:  r>   r  r=  r	  r>  r  r?  r   _tplr  ri  rA  richrB  r  rich.consolerC  rich.markuprD  r  r  rF  r  rH  r#  firerz  rI  r  rJ  rK  rL  r  rM  rN  r  rO  rP  rQ  rq  rR  tools.terminal_toolrS  rf  rT  rU  tools.skills_toolrV  hermes_cli.callbacksrX  r  rY  rg  re  rk  ro  rp  __annotations__rz  r  r  r  r  r  r  r  r  r  rb  r  r  ra  r  r!  r&  r*  	frozensetro  r5  rk  r;  r  rH  rP  rh  rt  r  r  r  r  HERMES_AGENT_LOGOHERMES_CADUCEUSr  r  agent.skill_commandsr  r  r  r  r  r   r  r  r
  r  r  r  Firer  rL   rC   <module>r     s      				  



       % % % % % %             , , , , , , , , , , , ,		8	$	$ !
>   / . . . . . 2 2 2 2 2 2 4 4 4 4 4 4 2 2 2 2 2 2 d d d d d d d d d d d d d d o o o o o o o o o o o o , , , , , , 5 5 5 5 5 5 7 7 7 7 7 7 + + + + + + 2 2 2 2 2 2 < < < < < < : : : : : :888888 &NN^$   NNN                 R Q Q Q Q Q Q Q` 
 B A A A A A A A 4 4 4 4 4 4  tH~~$v-  | F F F Fc d4S>.B    :C D4K    C C$J    6 6c 6 6 6 6rUc3h U U U Up
 _
	,,,,,,Mu 	 	 	D		777777 	 	 	D		<<<<<<*%%%% 	 	 	D		666666>>)R((,,-BAFFD$5SSYYYA6666 	 	 	D		====== 	 	 	D	 !                       ) ) ) ) ) )       ' ' ' ' ' '        B B B B B B B B 3 2 2 2 2 2 N N N N N N N N I I I I I I I I I I       S R R R R R Q Q Q Q Q Q Q Q 9 9 9 9 9 9 2 2 2 2 2 2 W W W W W W  ( ( (` .2 (4S>* 1 1 1    t 4 D    ` `s `htCH~.F ` ` ` `F=@ =@DcN =@d =@ =@ =@ =@@F( F(c F(# F(t F( F( F( F(RB? B? B? B? B? B?` 0  27 	I 	I 	IC 	I$ 	I3 	I 	I 	I 	I! ! ! ! ! ! ! !H .*ID
A
A
A~lI..S    +s +y + + + +#     I       A @ @ @ @ @B B BS B B B B(3 (5c? ( ( ( (Vs td{    @$d $| $ $ $ $N-# -- - - - -` T$Z PS \_bf\f ru    B#c #d # # # #
 t d
 eTWY]^bYcTcNd    <( ( ( ( ( ( ( (VF j$(s ( ( ( (`%C %D % % % %,            &%''s    3c?U38_#Dt#K PTUXPY    06 6C 6D 6 6 6 6~~C' ~C' ~C' ~C' ~C' ~C' ~C' ~C'LH 04!+d dd
d d 	d
 $s)OeCHo-d d d d d d d d d d d  !d" #d$ %d& 'd( )d* +d d d dN zDIdOOOOO sm   C 	CCF F&%F&*F; ;GGG G! G!%AH. .H65H6:I II