
    iO             /       f   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ZddlZddlZddlZddlmZmZ ddlmZ ddlmZ d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/m0Z0 ddl1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9 ddl:m;Z; ddl<m=Z= ddl>m?Z? ddl@mAZB ddlCmDZE 	 ddlFmGZG eGjH        ZIn# eJeKf$ r dZIY nw xY wddlLZLddlMZMddlNmOZOmPZPmQZQmRZR ddlSmTZTmUZU dZVddlWmXZXmYZY ddlZm[Z[m\Z\m]Z] ddl^m_Z_ ddl`maZambZb  eX            Zc eed          je        dz  Zf e_ecef            d!Zgd"ehd#ehfd$Zid%ed#ehfd&Zjd%ed#ehfd'Zkd(ehd#eeehef                  fd)Zld*ehd#emdz  fd+Znd,ehd#ehdz  fd-Zod#eehef         fd.Zp ep            Zq	 dd/lrmsZs  esd01           n# et$ r Y nw xY w	 dd2lumvZv  ev             n# et$ r Y nw xY w	 dd3lwmxZx  exeq           n# et$ r Y nw xY w	 dd4lymzZz eq{                    d5i           {                    d6d          Z| eze|r e}e|          nd           n# et$ r Y nw xY w	 dd7l~mZ  e             n# et$ r Y nw xY wdd8lmZ dd9lmZ dd:lmZ dd;lmZ dd<lmZ ddlZdd=lmZ dd>lmZmZ dd?lSmZ dd@lmZmZ ddAlmZmZmZ ddBlmZ ddClmZ ddDlmZmZ ddElmZ ddFlmZ ddGlmZ dHadadI Zdaeeehehf                  edJ<   d#eeh         fdKZdLedMed#efdNZddOehd#eeehehf                  fdPZddQeehehf         d#dfdRZddSZddTZddOehdVe}d#dfdWZdOehd#dfdXZdYZdZZd[Zd\ZdHd]d^ehd_ed#ehfd`Z G da db          Z edcddde]          Z edfdg          Zd#ehfdhZd"ehd#efdiZd"ehd#ehfdjZdd"ehdlehfdmZd"ehfdnZ eh do          ZddplWmZ ddrehd#ehfdsZd,ehd#eehehf         fdtZduehd#edz  fdvZdwemd#dxfdyZdzehd#d{fd|Zdd}ee         d~e}de}dz  d#ehfdZdehd#efdZd"ehd#ehfdZ ej        d          Z ej        d          Z ej        d          Z ej        d          Z ej        d          ZdZd"ehd#eehef         fdZd"ehd#ehfdZddehdz  dehdz  d#eehee         f         fdZ G d d          ZdZdZd#ehfdZd"ehd#efdZddlmZmZmZ  e            Zd#efdZdeheeh         z  eehdf         z  dz  d#eeh         fdZdehded#efdZ G d d          Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddehdehdehdehdeheeh         z  eehdf         z  dehdehdehdehde}dededededededehdedededededef.dZedk    r ej        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)unquoteurlparse)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)DEFAULT_BROWSER_CDP_URLmanual_chrome_debug_commandtry_launch_chrome_debug)load_hermes_dotenv)base_url_host_matchesis_truthy_valuez.env)hermes_homeproject_env)REASONING_SCRATCHPADthinkthinking	reasoningthoughttextreturnc                 x   | }t           D ]}t          j        d| d| dd|t          j        t          j        z            }t          j        d| dd|t          j        t          j        z            }t          j        d| dd|t          j                  }dD ]8}t          j        d| d	| dd|t          j        t          j        z            }9t          j        d
d|t          j        t          j        z            }t          j        dd|t          j                  }|                                S )u  Remove reasoning/thinking blocks from displayed text.

    Handles every case:
      * Closed pairs ``<tag>…</tag>`` (case-insensitive, multi-line).
      * Unterminated open tags that run to end-of-text (e.g. truncated
        generations on NIM/MiniMax where the close tag is dropped).
      * Stray orphan close tags (``stuff</think>answer``) left behind by
        partial-content dumps.

    Covers the variants emitted by reasoning models today: ``<think>``,
    ``<thinking>``, ``<reasoning>``, ``<REASONING_SCRATCHPAD>``, and
    ``<thought>`` (Gemma 4).  Must stay in sync with
    ``run_agent.py::_strip_think_blocks`` and the stream consumer's
    ``_OPEN_THINK_TAGS`` / ``_CLOSE_THINK_TAGS`` tuples.

    Also strips tool-call XML blocks some open models leak into visible
    content (``<tool_call>``, ``<function_calls>``, Gemma-style
    ``<function name="…">…</function>``). Ported from
    openclaw/openclaw#67318.
    <z>.*?</z>\s* flagsz>.*$z</)	tool_call
tool_callstool_resultfunction_callfunction_callsz\b[^>]*>.*?</zg(?:(?<=^)|(?<=[\n\r.!?:]))[ \t]*<function\b[^>]*\bname\s*=[^>]*>(?:(?:(?!</function>).)*)</function>\s*zP</(?:tool_call|tool_calls|tool_result|function_call|function_calls|function)>\s*)_REASONING_TAGSresubDOTALL
IGNORECASEstrip)r8   cleanedtagtc_tags       (/home/ubuntu/.hermes/hermes-agent/cli.py_strip_reasoning_tagsrN   h   ss   * G 
 
&%%%C%%%)bm+	
 
 
 &NNN)bm+	
 
 
 &#OOO-	
 
 
6 
 
&222f222)bm+	
 
 
 f	3 	i"-'  G f[
m	  G ==??    contentc                     | dS t          | t                    r| S t          | t                    r+d | D             }d                    d |D                       S t          |           S )Nr<   c                     g | ]S}t          |t                    r<|                    d           dk    0t          |                    dd                    TS )typer8   r<   )
isinstancedictgetstr.0parts     rM   
<listcomp>z._assistant_content_as_text.<locals>.<listcomp>   sc     
 
 
$%%
 +/((6*:*:f*D*D $$%%*D*D*DrO   
c              3      K   | ]}||V  	d S N rY   ps     rM   	<genexpr>z-_assistant_content_as_text.<locals>.<genexpr>   s'      //qQ///////rO   )rT   rW   listjoin)rP   partss     rM   _assistant_content_as_textrf      s    r'3 '4   0
 

 
 

 yy//E//////w<<rO   c                 :    t          t          |                     S r^   )rN   rf   )rP   s    rM   _assistant_copy_textrh      s     !;G!D!DEEErO   	file_pathc                 :   | 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loadrT   rc   	Exception)ri   pathfdataes        rM   _load_prefill_messagesr}      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_constantsr   rI   rs   rt   )r~   r   results      rM   _parse_reasoning_configr      s\    777777##F++F X&,,.. XV^NPVWWWMrO   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.r<   >   offnonenormaldefaultstandardN>   onfastpriorityr   z#Unknown service_tier '%s', ignoring)rW   rI   lowerrs   rt   )r   values     rM   _parse_service_tier_configr      sl    	rNN  ""((**E EMMMt***z
NN8#>>>4rO   c                     t           dz  } t          t                    j        dz  }t          j                            d          dk    }|                                 r|s| }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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.d/ddddd0d1i id2}d}|                                rk	 t          |d3d45          5 }t          j
        |          pi }d6d6d6           n# 1 swxY w Y   d7|v }d8|v rt          |d8         t                    r|d8         |d8         d(<   ngt          |d8         t                    rL|d8                             |d8                    d8|d8         v r!d(|d8         vr|d8         d8         |d8         d(<   |d8                             d9          s"|                    d9          }|r||d8         d9<   |d8                             d:          s"|                    d:          }	|	r|	|d8         d:<   |D ]p}
|
d8k    r	|
|v rct          ||
         t                    r=t          ||
         t                    r"||
                             ||
                    e||
         ||
<   q|D ]}
|
|vr|
d8k    r||
         ||
<   |                    d;          }d<|v r;t          |t                    r|                    d<          |d<         |d;         d<<   n2# t          $ r%}t                               d=|           Y d6}~nd6}~ww xY wd>d?lm}  ||          }|                    d7i           }d@|v r|d@         |dA<   dB}|                    dC          |v rt          j                            dDd          }|r4||vr0t          j                            |          r||dC<   ||d7         dC<   nZ|                    dAd          }|dk    r(t	          j                    |dC<   |dC         |d7         dC<   n|                    dCd6           i dAdEdCdDd*dFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidj}|                                D ]t\  }}||v rk|s|t          j        vr[||         }t          |t2                    r"t5          j        |          t          j        |<   Xt          |          t          j        |<   u|                    dki           }dldmi}|                                D ]+\  }}||v r"t          ||                   t          j        |<   ,|                    dni           }dodpdqdrd-dsdtdudvd-dwdxdydzd-d{}|                                D ]h\  }}|                    |i           }t          |t                    s2t          |                    d9d                                                    }t          |                    d8d                                                    }t          |                    d:d                                                    }t          |                    d|d                                                    } |r|dk    r|t          j        |d9         <   |r|t          j        |d8         <   |r|t          j        |d:         <   | r| t          j        |d|         <   j|                    d}i           }!t          |!t                    rE|!                    d~          }"|".t          |"                                          t          j        d<   |S )u  
    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.

    If HERMES_IGNORE_USER_CONFIG=1 is set (via ``hermes chat --ignore-user-config``),
    the user config at ``~/.hermes/config.yaml`` is skipped entirely and only the
    built-in defaults plus the project-level ``cli-config.yaml`` (if any) are used.
    Credentials in ``.env`` are still loaded — this flag only suppresses
    behavioral/config settings.
    config.yamlcli-config.yamlHERMES_IGNORE_USER_CONFIGr   r<   auto)r   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	thresholdZ   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	interruptr   )compactresume_displayshow_reasoning	streamingbusy_input_modeskinr   2   )r   max_tool_calls)r   modelr   api_key)visionweb_extract-   )max_iterationsr   r   r   r   seen)r   terminalbrowsercompressionagentdisplayclarifycode_execution	auxiliary
delegation
onboardingrk   rl   rm   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vercel_runtimeTERMINAL_VERCEL_RUNTIME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TERMINAL_CONTAINER_PERSISTENTTERMINAL_DOCKER_VOLUMES&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE TERMINAL_DOCKER_RUN_AS_HOST_USERTERMINAL_SANDBOX_DIRTERMINAL_PERSISTENT_SHELLSUDO_PASSWORD)container_persistentr   r   docker_run_as_host_user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)rq   r   __file__parentosenvironrV   rr   ru   yaml	safe_loadrT   rW   rU   updaterx   rs   rt   hermes_cli.configr   ry   isabsgetcwdpopitemsrc   rv   dumpsrI   r   )#user_config_pathproject_config_pathignore_user_configconfig_pathdefaults_file_has_terminal_configrz   file_configroot_providerroot_base_urlkeyagent_file_configr|   r   terminal_config_CWD_PLACEHOLDERS_existing_cwdeffective_backendenv_mappings
config_keyenv_varvalbrowser_configbrowser_env_mappingsauxiliary_configauxiliary_task_envtask_keyenv_maptask_cfgprovr   r   r   security_configredacts#                                      rM   load_cli_configr@     sz
   $ $m3x../2CC (CDDK    *); *&)
 
 
   #H"$!VGI -2
 
 #&$
 

 
 

 %' "F`lq_ n h {  U \ x {  c H 
 
4 $#*
 
 s
  
 
 #	  #	 
 
 !
 
 B
s^ ^HH !&  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 	3 	' 	' 	' 	%" 	1#$ 	7%& 	3'( !@3)Q#E-7(9  LH  ,1133 3 3
G((( 3G2:,E,E%j1c4(( 3*.*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=   L +DL DL DG:L 
M L;;M )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                     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          rwt          t          d
          rdt          t          dd          }t          |t                    rt                              |           dS t                                           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_finalizerB  
session_idplatformshutdown_memory_provider_session_messages)_cleanup_done_cleanup_all_terminalsrx   _cleanup_all_browserstools.mcp_toolrc  agent.auxiliary_clientrd  hermes_cli.pluginsrf  _active_agent_refri  hasattrgetattrrT   rc   rk  )rc  rd  _invoke_hook_session_msgss       rM   _run_cleanuprx    s7     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 	= $$57JDQQM-.. =!::=IIIII!::<<<<<	= 	= 	= 	=    sj    
))< 
A	A	A 
A+*A+/B   
BB'B9 9
CC
A!E -E 
EE_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_outputr8   r   )
subprocessrun
returncodestdoutrI   rx   )r~  r   s     rM   _git_repo_rootr    s    333dA   
 
 !!=&&((( "   4s   >A 
AAry   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)ry   r  s     rM   _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/r<   ar\   zCould not update .gitignore: %sr{  worktreeaddz-bHEAD   r}  r8   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)ry   branchr  u   [32m✓ Worktree created:[0m z
  Branch: )#r~  r  printuuiduuid4hexr   mkdirrr   	read_text
splitlinesru   endswithwriterx   rs   debugr  rW   r  stderrrI   resolve
startswithOSErrorr  r  rt   is_filer  shutilcopy2is_dirr  symlink)r  r~  short_idwt_namebranch_nameworktrees_dirwt_path	gitignore_ignore_entryexistingrz   r|   r   include_filerepo_root_resolvedwt_path_resolvedlineentrysrcdstsrc_resolveddst_resolvedinfos                          rM   _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   ry   r  r  Fr{  logz	--oneliner  z--notz	--remotesT
   r  u2   
[33m⚠ Worktree has unpushed commits, keeping: r  z4  To clean up manually: git worktree remove --force r{  r  remove--force   zFailed to remove worktree: %s-DzFailed to delete branch %s: %su   [32m✓ Worktree cleaned up: )ry  r~  r   rr   r  boolr  rI   rx   r  rs   r  )r  r~  r  r  r  has_unpushedr   r|   s           rM   _cleanup_worktreer  Z  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c           
      8   | dS 	 ddl m} ddlm}  |            }	 |                     d          sL|                     |dz            }|                     dd           |rt                              d	|           n2# t          $ r%}t          
                    d
|           Y d}~nd}~ww xY w |                                d          pi }|                    dd          sdS |                     t          |                    dd                    t          |                    dd                    t          |                    dd                    |dz             dS # t          $ r&}t          
                    d|           Y d}~dS d}~ww xY w)u  Call ``SessionDB.maybe_auto_prune_and_vacuum`` using current config.

    Reads the ``sessions:`` section from config.yaml via
    :func:`hermes_cli.config.load_config` (the authoritative loader that
    deep-merges DEFAULT_CONFIG, so unmigrated configs still get default
    values). Honours ``auto_prune`` / ``retention_days`` /
    ``vacuum_after_prune`` / ``min_interval_hours``, and delegates to the
    DB. Never raises — maintenance must never block interactive startup.
    Nr   load_config)r)   ghost_session_prune_v1sessions)sessions_dirr   z"Pruned %d empty TUI ghost sessionszGhost session prune skipped: %s
auto_pruneFretention_daysr   min_interval_hours   vacuum_after_pruneT)r  r  vacuumr  z%state.db auto-maintenance skipped: %s)r  r  r   r)   get_metaprune_empty_ghost_sessionsset_metars   r  rx   r  rV   maybe_auto_prune_and_vacuumintr  )
session_db_load_full_config_get_hermes_home_hermes_home_maintpruned
_prune_exccfgexcs           rM   _run_state_db_auto_maintenancer    s    CFFFFFFHHHHHH--//		H&&'?@@ N#>>!3j!@ ?   ##$<cBBB NKK DfMMM 	H 	H 	HLL:JGGGGGGGG	H ! ""&&z228bww|U++ 	F..sww'7<<=="377+?#D#DEE 4d;;<<+j8	 	/ 	
 	
 	
 	
 	
  C C C<cBBBBBBBBBCsH   E) A!A? >E) ?
B.	B)$E) )B..8E) (A?E) )
F3FFc            
         	 ddl m}   |                                 d          pi }|                    dd          sdS ddlm}  |t          |                    dd	                    t          |                    d
d                    t          |                    dd                               dS # t          $ r&}t          	                    d|           Y d}~dS d}~ww xY w)ua  Call ``checkpoint_manager.maybe_auto_prune_checkpoints`` using current config.

    Reads the ``checkpoints:`` section from config.yaml via
    :func:`hermes_cli.config.load_config`. Honours ``auto_prune`` /
    ``retention_days`` / ``delete_orphans`` / ``min_interval_hours``.
    Never raises — maintenance must never block interactive startup.
    r   r  checkpointsr  FN)maybe_auto_prune_checkpointsr     r  r  delete_orphansT)r  r  r  z'checkpoint auto-maintenance skipped: %s)
r  r  rV   tools.checkpoint_managerr  r  r  rx   rs   r  )r  r  r  r  s       rM    _run_checkpoint_auto_maintenancer    s&   EFFFFFF  ""&&}55;ww|U++ 	FIIIIII$$sww'7;;<<"377+?#D#DEE(8$ ? ?@@	
 	
 	
 	
 	
 	

  E E E>DDDDDDDDDEs   ;B8 A7B8 8
C(C##C(r  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  Tr|  r  r{  r  z--show-currentr{  r  r  r  r  r  r  r  z$Pruned stale worktree: %s (force=%s)zFailed to prune worktree %s: %s)r~  timer   rr   _prune_orphaned_branchesiterdirr  namer  statst_mtimerx   r  rW   r  rI   rs   r  )r  r  r~  r  r  nowsoft_cutoffhard_cutoffr  mtimeforcer   branch_resultr  r|   s                  rM   _prune_stale_worktreesr    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)r{  r  z--format=%(refname:short)Tr  r  c                 ^    g | ]*}|                                 |                                 +S r_   rI   )rY   bs     rM   r[   z,_prune_orphaned_branches.<locals>.<listcomp>4  s2    ZZZaPQPWPWPYPYZ		ZZZrO   r\   )r{  r  rc   z--porcelainzbranch refs/heads/   r  r|  mainc                 p    g | ]2}|v|                     d           s|                     d          0|3S )zhermes/hermes-zpr-r  )rY   r  active_branchess     rM   r[   z,_prune_orphaned_branches.<locals>.<listcomp>R  sW       O##\\*++ $/0||E/B/B $ 	
###rO   r   )r{  r  r  r  z%Failed to prune orphaned branches: %szPruned %d orphaned branches)r~  r  r  r  rI   splitrx   setr  r  rangelenrs   r  )r  r~  r   all_branches	wt_resultr  head_resultcurrentorphanedibatchr|   r  s               @rM   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     r|  r  z1;r<   [z38;2;;mz[38;2;184;134;11m)r  r  
IndexError_ACCENT_ANSI_DEFAULT)r  r  rk   gr  prefixs         rM   _hex_to_ansir   z  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       rM   __init__z_SkinAwareAnsi.__init__  s#    !)
#'rO   r9   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)  rx   )r+  r/  s     rM   __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^   rW   r+  r3  s     rM   __add__z_SkinAwareAnsi.__add__  s    4yy5  rO   c                 &    |t          |           z   S r^   r5  r6  s     rM   __radd__z_SkinAwareAnsi.__radd__  s    s4yy  rO   Nc                     d| _         dS )z1Clear cache so the next access re-reads the skin.N)r*  r+  s    rM   resetz_SkinAwareAnsi.reset  s    rO   )r#  r9   N)__name__
__module____qualname____doc__rW   r  r,  r2  r7  r9  r<  r_   rO   rM   r"  r"    s         (UZ ( ( ( (C (d ( ( ( (
 
 
 
 
!S !S ! ! ! !!c !c ! ! ! !     rO   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)r0  r/  r1  rx   r.  s    rM   _accent_hexrH    sY    ::::::  **;	BBB   yys   #& 
44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.
    r<   )	_RichText	from_ansir8   s    rM   _rich_text_from_ansirM    s     tzr***rO   c                    t          | pd          j        }t          j        dd|t          j                  }t          j        dd|t          j                  }t          j        dd|          }t          j        dd|          }t          j        dd|          }t          j        d	d|          }t          j        d
d|          }t          j        dd|          }t          j        dd|          }t          j        dd|          }t          j        dd|          }t          j        dd|          }t          j        dd|          }t          j        dd|          }|                    d          S )z;Best-effort markdown marker removal for plain-text display.r<   z^\s{0,3}(?:[-*_]\s*){3,}$r=   z^\s{0,3}#{1,6}\s+z(```+|~~~+)z	`([^`]*)`\1z!\[([^\]]*)\]\([^\)]*\)z\[([^\]]+)\]\([^\)]*\)z\*\*\*([^*]+)\*\*\*z(?<!\w)___([^_]+)___(?!\w)z\*\*([^*]+)\*\*z(?<!\w)__([^_]+)__(?!\w)z\*([^*]+)\*z(?<!\w)_([^_]+)_(?!\w)z~~([^~]+)~~\n{3,}

r\   )rM  plainrE   rF   	MULTILINErI   )r8   rR  s     rM   _strip_markdown_syntaxrT    sI    ,,2EF/U",OOOEF'U",GGGEF>2u--EF<..EF-ue<<EF,eU;;EF)5%88EF0%??EF%ue44EF.u==EF>5%00EF,eU;;EF>5%00EF9fe,,E;;trO   renderrD  c                 ,   ddl m} t          |pd                                                                          }|dk    rt          t          |                     S |dk    rt          | pd          S t          | pd          j        } ||          S )zGRender final assistant content as markdown, stripped text, or raw text.r   )MarkdownrU  rI   r   r<   )	rich.markdownrW  rW   rI   r   rJ  rT  rM  rR  )r8   rD  rW  normalized_moderR  s        rM   _render_final_assistant_contentrZ    s    &&&&&&$*(++113399;;O'!!/55666%#DJB/// ,,2E8E??rO   c                 0    	 ddl m}m n-# t          $ r  t	          t                                Y dS w xY wd}	  |            }n# t          $ r d}Y nw xY w|t          |dd          st	          t                                dS 	 |j        }n# t          $ r d}Y nw xY w|t	          t                                dS ddl}	 |	                                
                                }n# t          $ r d}Y nw xY w||u r2|                                rt	          t                                dS  fd}	 |                    |           dS # t          $ r3 	 t	          t                                Y dS # t          $ r Y Y dS w xY ww xY w)u1  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.

    When called from a background thread while a prompt_toolkit
    ``Application`` is running (the common case for the self-improvement
    background review's ``💾 …`` summary, curator summaries, and other
    bg-thread emissions), a direct ``_pt_print`` races with the input
    area's redraw and the line can end up visually buried behind the
    prompt.  Route those cases through ``run_in_terminal`` via
    ``loop.call_soon_threadsafe``, which pauses the input area, prints
    the line above it, and redraws the prompt cleanly.
    r   )get_app_or_nonerun_in_terminalN_is_runningFc                      	   fd           d S # t           $ r3 	 t          t                               Y d S # t           $ r Y Y d S w xY ww xY w)Nc                  <    t          t                               S r^   )	_pt_print_PT_ANSIrL  s   rM   <lambda>z,_cprint.<locals>._schedule.<locals>.<lambda>  s    Ihtnn$=$= rO   )rx   ra  rb  )r]  r8   s   rM   	_schedulez_cprint.<locals>._schedule  s    	O====>>>>> 	 	 	(4..))))))   	s$    
A=
AAAA)prompt_toolkit.applicationr\  r]  rx   ra  rb  ru  loopasyncioget_event_loop_policyget_event_loop
is_runningcall_soon_threadsafe)r8   r\  apprf  _asynciocurrent_looprd  r]  s   `      @rM   _cprintro    s@    OOOOOOOOO   (4..!!! Co    {'#}e<<{(4..!!!x   |(4..!!!5577FFHH    t 1 1(4..!!!     !!),,,,,   	htnn%%%%%% 	 	 	DDD	sk    &77
A AAB B#"B#&C2 2D DE 
F#F
FFFF>
   .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  ry   ro   isdirrd   )r|  
candidatesr  s      rM   _termux_example_image_pathr  ;  s     	-..	J  < <7== 	<7<<j(;;;;;	<7<<*JAAArO   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
    r<   )r<   r<   r      "'r  \   N \ )rW   rI   r  replace)r   quoteposchtoken	remainders         rM   _split_path_inputr  I  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)rO   raw_pathc                 \   t          | pd                                          }|sdS |                    d          r|                    d          s*|                    d          r1|                    d          r|dd                                         }|                    dd          }|sdS |}|                    d	          rg	 t          |          }|j        d
k    r9t          |j        pd          }|j	        rt          j        dk    rd|j	         | }n# t          $ r |}Y nw xY wt          j                            t          j                            |                    }t          j        dk    r|                    dd          }t          |          dk    rZ|d         dk    rN|d         dk    rB|d                                         r(d|d                                          d|dd          }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.
    r<   Nr  r  r  r  r  r  file://filentz//r  /r  :r  r   z/mnt/r   )rW   rI   r  r  r  r   schemer   ry   netlocr  r  rx   
expandvarsro   r  isalphar   r   rp   getenvr  r  rr   r  )r  r  expandedparsed
normalizedry   base_dirresolveds           rM   _resolve_attachment_pathr  t  s    B%%''E t $%.."5"5 $5;K;KC;P;P $UZUcUcdgUhUh $ad!!##MM%%%E tH	"" 	e__F}&&"6;#4"55= >RW__=FM=8==H 	 	 	HHH	w!!"'"4"4X">">??H	w$%%dC00
z??aJqMS$8$8Z]c=Q=QV`abVcVkVkVmVm=QGz!}2244GGz!""~GGH>>D 	.")++>>??$<<>>    ?? H$4$4$6$6 tOs%   
AD D-,D-I0 0I?>I?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 [IMPORTANT: ...] message.

    Handles both completion events (notify_on_complete) and watch pattern
    match events from the unified completion_queue.
    rS   
completionri  unknowncommandwatch_disabledz[IMPORTANT: messager<   ]watch_matchpattern?output
suppressedr   z[IMPORTANT: 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:
rV   )	r  evt_type_sid_cmd_pat_out_supr8   _exits	            rM   _format_process_notificationr    s    wwv|,,H77<++D779i((D###7cggi447777=  wwy#&&wwx$$ww|Q'''d ' '#' '' ' !%' ' 	  	PO$OOOOD GGK%%E778R  D	$ 	 		 		 	 	 	 	rO   
user_inputzdict | Nonec                    t          | t                    sdS |                                 }|sdS |                    d          p9|                    d          p#|                    d          p|                    d          p|                    d          pt	          |          dk    o/|d         d	k    o#|d
         dv o|d                                         p|                    d          p|                    d          pv|                    d          pa|                    d          pLt	          |          dk    o9|d         dv o/|d
         d	k    o#|d         dv o|d                                         }|sdS t          |          }|$||j                                        t          v ddS t          |          \  }}t          |          }|d|v r|d         dvr{d t          |          D             }t          |          D ]R}|d|                                         }	t          |	          }
|
#|
}||dz   d                                         } nS|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.
    Nr  ~z./z../r  r  r  r  r  )r  r  r   z"/z"~z'/z'~   )r  r  r<   )ry   is_imager  r  r  c                 $    g | ]\  }}|d k    |S )r  r_   )rY   idxr  s      rM   r[   z%_detect_file_drop.<locals>.<listcomp>  s!    OOO73R3YY3YYYrO   )rT   rW   rI   r  r  r  r  suffixr   _IMAGE_EXTENSIONSr  	enumeratereversedrstrip)r  strippedstarts_like_pathdirect_pathfirst_tokenr  	drop_pathspace_positionsr  	candidater  s              rM   _detect_file_dropr    s3     j#&& t!!H t 	C   
	Ns##
	Nt$$
	N u%%
	N y))	
	N
 MMQn8A;##5n(1+:TnYabcYdYlYlYnYn
	N t$$
	N t$$
	N t$$
	N t$$
	N MMQ  M8A;*#<  M!PSAS  MX`abXcgrXr  Mw  AB  xC  xK  xK  xM  xM   t*844K#*00226GG
 
 	
 /x88K(55ISH__!J1N1NOOi.A.AOOOO,, 	 	C #--//I/	::H#$	$S1WYY/5577	 $ t $**,,0AA  rO   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.
    r<   P   r  r  limitr9   c                 h    t          |           |k    r| n| d t          d|dz
                     dz   S )Nr  r  ...)r  max)r  r  s     rM   _truncz/_format_image_attachment_badges.<locals>._trunc  s:    4yyE))ttt4Gc!UQY6G6G4G/H5/PPrO   4   r  u   [📎 r      r  z images attached]r      z] [+r  c              3   *   K   | ]}d |z    dV  dS )u   [📎 Image #r  Nr_   )rY   r  bases     rM   rb   z2_format_image_attachment_badges.<locals>.<genexpr>)  sF         	$q###     rO   )	r  get_terminal_sizecolumnsrW   r  r  r  rd   r
  )r  r  r  r  firstextrar  s         @rM   _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?++,,     rO   pasted_textc                 ,    |                                   S )z@Auto-attach clipboard images only for image-only paste gestures.r   )r  s    rM   ,_should_auto_attach_clipboard_image_on_paster  /  s      """"rO   c                 b   | s| S |                      dd                               dd                               dd                               dd          } t          j        dd|           } t          j        dd|           } t          j        d	d|           } t          j        d
d|           } | S )a  Strip leaked bracketed-paste wrapper markers from user-visible text.

    Defensive normalization for cases where terminal/prompt_toolkit parsing
    fails and bracketed-paste markers end up in the buffer as literal text.

    We strip canonical wrappers unconditionally and also handle degraded
    visible forms like ``[200~`` / ``[201~`` and ``00~`` / ``01~`` when they
    look like wrapper boundaries, not arbitrary user content.
    z[200~r<   z[201~z^[[200~z^[[201~z(^|[\s\n>:\]\)])\[200~rO  z\[201~(?=$|[\s\n<\[\(\):;.,!?])z(^|[\s\n>:\]\)])00~z01~(?=$|[\s\n<\[\(\):;.,!?]))r  rE   rF   rL  s    rM   &_strip_leaked_bracketed_paste_wrappersr  4  s       	["%%	b	!	!	B			B			 	 6+UD99D64b$??D6(%66D612t<<DKrO   z\x1b\[\d+;\d+Rz\^\[\[\d+;\d+Rz\x1b\[<\d+;\d+;\d+[Mm]z\^\[\[<\d+;\d+;\d+[Mm]z<\d+;\d+;\d+[Mm]zK[?1006l[?1003l[?1002l[?1000l[?1004l[?2004l[?1049l[<u[>4m[0m[?25hc                    | s| dfS d| v }d| v }d| v od| v od| v pd| v }|s|s|s| dfS d}|rAt                               d|           } t                              d|           \  } }|p|d	k    }|rAt                              d|           } t
                              d|           \  } }|p|d	k    }|r&t                              d|           \  } }|p|d	k    }| |fS )
u  Strip leaked terminal control-response sequences from user input.

    Covers Cursor Position Report (CPR / DSR) responses — ``ESC[<row>;<col>R``
    and the visible ``^[[<row>;<col>R`` form. These are replies the terminal
    sends back to queries prompt_toolkit makes during ``_on_resize`` /
    ``_request_absolute_cursor_position``. When the input parser drops one
    (resize storms, multiplexer focus changes, slow PTYs) the response
    lands in the input buffer as literal text and corrupts what the user
    typed.

    Also strips leaked SGR mouse-report fragments (``ESC[<...M/m`` and
    degraded visible forms). Returns ``(cleaned_text, had_mouse_reports)``
    so callers can trigger an in-place terminal mode recovery when needed.
    Fr  z^[r;   r  Mr  r<   r   )_DSR_CPR_ESC_RErF   _SGR_MOUSE_ESC_REsubn_DSR_CPR_VISIBLE_RE_SGR_MOUSE_VISIBLE_RE_SGR_MOUSE_BARE_RE)r8   has_eschas_visiblehas_bare_mousehad_mouse_reportscounts         rM   *_strip_leaked_terminal_responses_with_metar  l  s8     U{oG$,KD[QSD[QcTk6PSD[N { n U{ ;""2t,,',,R66e-: ;"&&r400+00T::e-: ;(--b$77e-:"""rO   c                 *    t          |           \  }}|S )z2Compatibility wrapper returning only cleaned text.)r  )r8   rJ   _s      rM    _strip_leaked_terminal_responsesr    s    ;DAAJGQNrO   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.r<   r  ry   r  [User attached image: r  NzImage file not found: zNot a supported image file: )rT   rW   r  rV   appendr  r  r  r  r   r  r	  r  )
r  r  r  imagesdroppedexplicit_pathdedupedr   imgr,  s
             rM   _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rO   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  _bufferrK  _inner)r+  r  s     rM   r,  zChatConsole.__init__  sI    xzz$	
 
 
rO   c                 |   | j                             d           | j                                          t          j        d          j        | j        _         | j        j        |i | | j         	                                }|
                    d                              d          D ]}t          |           d S )Nr   r  r\   )r  seektruncater  r  r  r  r  r  getvaluer  r  ro  )r+  argskwargsr  r  s        rM   r  zChatConsole.print  s    !"4X>>F4*6***&&((MM$''--d33 	 	DDMMMM	 	rO   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      rM   statuszChatConsole.status  s       




rO   N)r>  r?  r@  rA  r,  r  r   r  r_   rO   rM   r  r    sW         
 
 
   
 
 ^
 
 
rO   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.  Nr  r   banner_borderr#  banner_titlerG  rC  rD  u$   ⚕ NOUS HERMES - AI Agent Frameworku   ⚕ NOUS HERMES
agent_nameHermes Agentz - AI Agent Frameworkr  X   r  z
[r  	[/] [dim z]- Nous Research[/]
u   ═z
[bold u   ]╔u   ╗[/]
[bold u	   ]║[/] [z
[/] [bold u   ]║[/]
[bold u   ]║[/] [dim u   ]╚u   ╝[/]
)r0  r/  rx   ru  r1  get_brandingr(   minr  r  r  ljust)r/  _skin	skin_nameborder_colortitle_color	dim_colorline1	tiny_liner  version_linewinnerbarcontent_widthline2s                  rM   _build_compact_bannerr1     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".
    r  Fr   r  N)r  r  )r8   
first_words     rM   _looks_like_slash_commandr4  0  sJ      ts++ uaJ jn$$rO   )scan_skill_commandsbuild_skill_invocation_message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)rr  r:  r	  _plugin_commandskeysrx   r9  s    rM   _get_plugin_cmd_handler_namesr=  O  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^   r5  rY   items     rM   r[   z*_parse_skills_argument.<locals>.<listcomp>`  s#    GGGDd6Fc$ii6F6F6FrO   ,)	rT   rW   rc   tupler	  r  rI   r  r  )r>  
raw_valuesr  r   r   rZ   r  s          rM   _parse_skills_argumentrF  X  s     	&# #X

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

&kk]
FUUD & &IIcNN 	& 	&DJ t!3!3HHZ   MM*%%%%	& MrO   key_pathr   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  rk   Nr   r  r   )atomic_yaml_writei  zFailed to save config: %sF)rq   r   r  r  rr   r  ru   r  r  r  rT   rU   utilsrI  r  chmodr  NotImplementedErrorrx   rs   error)rG  r   r#  r$  r&  rz   configr<  r  r,  rI  r|   s               rM   save_config_valuerO  p  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defdZdde	ddfdZ
ddZdee         defdZddee         dedefdZeddee	         d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defd,Zddee         fd-Zddee         defd.Zd/ Z d0edefd1Z!d eddfd2Z"d3 Z#d4eddfd5Z$dd6d7eddfd8Z%d9edefd:Z&d edz  defd;Z'd9eddfd<Z(d eddfd=Z)dd>Z*dd?Z+d eddfd@Z,ddAZ-ddBZ.dCedefdDZ/defdEZ0e1dFefdG            Z2ddefdHZ3defdIZ4dJede5fdKZ6ddddLdMedNe5dOe5dz  defdPZ7dQ Z8defdRZ9dS Z:defdTZ;dCefdUZ<dVede=dedz  fdWZ>dCefdXZ?dY Z@dZ ZAd[ ZBd eddfd\ZCd]eddfd^ZDd_eddfd`ZEd_efdaZFdbdcd edde=deedefdfZGdg ZHdh ZIdi ZJdefdjZKdkedefdlZLdm ZMdn ZNdoefdpZOdq ZPdr ZQds ZRddtede=e5eef                  fduZSdvddwd]edtedefdxZTdy ZUdzeddfd{ZVdd|ZWd_eddfd}ZXd_eddfd~ZYd ZZd Z[d Z\ddede=e         dededz  fdZ]dededz  fdZ^dde=dededdfdZ_ddZ`e	 	 	 ddedededededededeeef         fd            ZadeddfdZbddeddfdZcd_efdZddd ededefdZedd ededefdZfd Zgd Zhedefd            Zid_eddfdZjdoefdZkdoefdZldoefdZmdoefdZndoefdZod ZpdCedefdZqdoefdZredededefd            ZsdoefdZtd ZudoeddfdZvddZwdoefdZxd_eddfdZyd Zzd Z{doefdZ|doefdZ}doefdZ~d4efdZd d_efdZd Zd ZddCefdZddZd d_eddfdZd ZddÄZdeddfdńZddzededede5fdɄZdedede5fd˄Zdedede5defd̈́Zd΄ Zdτ Zd efdЄZdCefdфZdefd҄Zdӄ ZdԄ ZdՄ Zdք Zdׄ Zdefd؄ZdbdٜdCedededefd܄ZdbdٜdCedede=e         fd݄ZddބZd߄ Zddedede5fdZddZddZdeddfdZddZddZddde=dee         fdZd Zdeeef         fdZdefdZd ZdefdZde5eef         fdZdefdZde=fdZddZdddde=f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   resumer  pass_session_idignore_rulesc                 \    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          t          d                             dd                                                                                    }|dk    rd| _        n|dk    rd| _        nd| _        ||n
| j        dk    | _        t          d                             dd          | _        t          t          d                             dd                                                                                    pd| _        | j        dvrd| _        t          d                             dd          | _        t          d                             di           }t%          |t&                    si }	 t)          |                    dd                    }n# t*          t,          f$ r d}Y nw xY w	 t)          |                    dd                    }n# t*          t,          f$ r d}Y nw xY wt/          d|          | _        t/          d|          | _        d| _        d| _        d| _        d| _        i | _        d| _        d| _         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tO          j(        d&          pd'| _)        d| _*        | j)        | _+        d(| _,        d| _-        g | _.        |p5t          d                             d!d          ptO          j(        d)d          pd| _/        | j/        rEta          | j/        d*          r0|p'tO          j(        d+          ptO          j(        d,          | _1        n/|p'tO          j(        d,          ptO          j(        d+          | _1        ||| _2        nt          d-                             d.          rt          d-         d.         | _2        not                              d.          rt          d.         | _2        nBtO          j(        d/          r't)          tO          j(        d/                    | _2        nd0| _2        || _3        t          d-                             d1          pg | _4        |rd|vr{d2|vrwtk          t                              d3          pi 6                                            fd4|D             }|r,| 7                    d5d68                    |           d7           t                              d8i           }t%          |tr                    rd9|i}|
p|                    d9d          | _:        |                    d:d;          | _;        || _<        |p"tN          j=                            d<          d=k    | _>        tO          j(        d>d          p t          d-                             d?d          | _?        t          d-                             d@i           | _@        t          t          d-                             dAd                    | _B        t          t          d-                             dBd                    | _D        t          t          d-                             dCd                    | _F        t                              dDi           pi }|                    dE          | _G        |                    dF          | _H        |                    dG          | _I        |                    dH          | _J        |                    dId          | _K        |                    dJ          | _L        t                              dK          pt                              dL          pg }t%          |t&                    r/|                    d%          r|                    d          r|gng }|| _M        d| _N        d| _O        d| _P        g | _Q        t          jS                    | _T        d| _U        d| _V        d| _W        d| _X        	 ddMlYmZ}  |            | _X        n2# t          $ r%}t          ]                    dN|           Y d}~nd}~ww xY wt          | jX                   t                       d| _`        |	r|	| _a        d| _U        nF| jT        b                    dO          }t          jd                    je        ddP         }| dQ| | _a        t          dRz  | _g        d| _h        d| _P        d| _i        t          jk                    | _l        t          jk                    | _m        d| _n        d| _o        d| _p        d| _q        d| _r        d| _s        d| _t        d| _u        d| _v        d| _w        t          jy                    | _z        d| _{        d| _|        d| _}        d| _~        d| _        i | _        d| _        d| _        d| _        g | _        d| _        g | _        d| _        t          jy                    | _        d| _        d| _        d| _        d| _        d| _        d| _        t          j                    | _        | j        5                                 d| _        i | _        d| _        dS )Sa  
        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allr   r   r   bell_on_completer   r   r   queuesteerr   r   final_response_markdownrI   >   r   rI   rU  inline_diffsTuser_message_previewfirst_linesr  
last_linesr  r   r<           r   r   r   	localhost	127.0.0.1)_auto_detect_local_modelr   HERMES_INFERENCE_PROVIDERr   chat_completionsOPENROUTER_BASE_URLopenrouter.aiOPENROUTER_API_KEYOPENAI_API_KEYr   r   HERMES_MAX_ITERATIONSr   disabled_toolsets*mcp_serversc                 :    g | ]}t          |          |v|S r_   )rY  )rY   t	mcp_namess     rM   r[   z&HermesCLI.__init__.<locals>.<listcomp>^  s2    ]]]Q2B12E2E]!S\J\J\qJ\J\J\rO   z%[bold red]Warning: Unknown toolsets: , [/]r  r   max_snapshotsr   HERMES_IGNORE_RULESr   HERMES_EPHEMERAL_SYSTEM_PROMPTr   r   r   r   r   provider_routingsortonlyignoreorderrequire_parametersdata_collectionfallback_providersfallback_model	SessionDBuM   Failed to initialize SessionDB — session will NOT be indexed for search: %s%Y%m%d_%H%M%S   r  z.hermes_history)rK  console
CLI_CONFIGrN  rV   r   rW   tool_progress_moder   rY  r   rI   r   r   r   streaming_enabledr\  _inline_diffs_enabledrT   rU   r  	TypeErrorr  r   user_message_preview_first_linesuser_message_preview_last_lines_stream_buf_stream_started_stream_box_opened_reasoning_preview_buf_pending_edit_snapshots_last_input_mode_recovery!_input_mode_recovery_notice_shownr   hermes_cli.runtime_providerrd  _model_is_default_explicit_api_key_explicit_base_urlr  r  requested_provider_provider_sourcer   api_modeacp_commandacp_argsr   r/   r   r   enabled_toolsetsrl  r	  r<  _console_printrd   r  checkpoints_enabledcheckpoint_max_snapshotsrT  r  rU  r   r   r}   prefill_messagesr   reasoning_configr   r   _provider_sort_providers_only_providers_ignore_providers_order_provider_require_params_provider_data_collection_fallback_model_active_agent_route_signaturer   _appconversation_historyr   r  session_start_resumed_prompt_start_time_prompt_duration_session_dbhermes_stater  rx   rs   rt   r  r  _pending_titleri  strftimer  r  r  rq   _history_file_last_invalidate_agent_runningrZ  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   rR  r   r   r   r   r   r   rS  r  rT  rU  _raw_tp_bim_ump_ump_first_lines_ump_last_lines_model_config_config_model_DEFAULT_CONFIG_MODEL	_base_urlrd  	_detectedinvalidcp_cfgprfbr  r|   timestamp_str
short_uuidrq  s!                                   @rM   r,  zHermesCLI.__init__  s*   > 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 :i(,,->LLMMSSUU[[]]7??#*D  W__#*D  #.D ")"5wwD<SW`<` ",I!6!:!:;!N!N'*y!%%&?II(
 (

%''%%''(%$ 	$ '/III+2D( &0	%:%>%>~t%T%T" )$(()?DD$%% 	D	!"488M1#=#=>>:& 	! 	! 	! 	!	 !$((<";";<<OO:& 	  	  	 OOO	 03A7G0H0H-/21o/F/F, $"'&(#')$),&16. #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24=/RR 	e"dbi0D&E&EdScIdIdDLL"dbi0@&A&AdRYOcEdEdDL &DNN $$[11 	 '0=DNN^^K(( 	 '4DNNY.// 	  +B!C!CDDDNNDN !)!+G!4!8!89L!M!M!SQS 	eX--#X2E2E Z^^M::@bFFHHIII]]]](]]]G e##$cDIIV]L^L^$c$c$cddd r22fd## 	)(F#.#N&**Y2N2N (.

?B(G(G%.
 )XBJNN;P,Q,QUX,X 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!
 .2* )-
	 ;=!%\^^ 48'*	o......(y{{D 	o 	o 	oNNjlmnnnnnnnn	o 	't'7888
 	)*** .2  	>$DO DMM .77HHM)"1"-J!.====DO *,=='*	
 $#kmm %!!""!&!"%)"#"#'n..#' ! !"$'*(**," %!,.+-*/' %>++ # %!&!&(00  """ $(  ?A()%%%s<   /#J J)(J)-#K K'&K'g% %
h/hh      ?min_intervalr9   c                     t          j                    }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  N)r  	monotonicrt  r  r  
invalidate)r+  r  r  s      rM   _invalidatezHermesCLI._invalidate  sy    n4   	#TY 	#C$:O4OT`3`3`$'D!I  """""	# 	# 	# 	#3`3`rO   c                    t          | dd          }|sdS 	 |j        }|j        }|                                 |                                 |                    dd           |                                 |                    d           n# t          $ r Y nw xY w	 |	                                 dS # t          $ r Y dS w xY w)u  Force a clean full-screen repaint of the prompt_toolkit UI.

        Used to recover from terminal buffer drift caused by external
        redraws we can't detect — e.g. macOS cmux / tmux tab switches,
        ``clear`` issued from a subshell, or SSH window restores. These
        wipe or repaint the terminal without firing SIGWINCH, so
        prompt_toolkit's tracked ``_cursor_pos`` no longer matches reality
        and the next incremental redraw stacks on top of stale content
        (ghost status bars, duplicated prompts).

        Bound to Ctrl+L and exposed as the ``/redraw`` slash command,
        matching the standard terminal-UX convention (bash, zsh, fish,
        vim, htop).
        r  Nr   Fleave_alternate_screen)
ru  rendererr  reset_attributeserase_screencursor_gotoflushr<  rx   r  )r+  rl  r  outs       rM   _force_full_redrawzHermesCLI._force_full_redraw	  s     dFD)) 	F	|H/C  """OOAq!!!IIKKK NN%N8888 	 	 	D		NN 	 	 	DD	s$   A6B 
BBB5 5
CC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-criticalr  zclass:status-bar-badr   zclass:status-bar-warnzclass:status-bar-goodr_   )r+  r   s     rM   _status_bar_context_stylez#HermesCLI._status_bar_context_style%	  sG    ))2.."))2**&&rO   r  r  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   █   ░r  )r  r"  round)r+  r   r  safe_percentfilleds        rM   _build_context_barzHermesCLI._build_context_bar0	  sd    1c#|'8q99::s*e344IEFNus1efn/E/E'EFIIIIrO   prompt_start_timeprompt_durationlivec                    | |dk    rdS | t          j                     | z
  n|}t          d|          }t          |dz            }|dz  }t          |dz            }|dz  }t          |dz            }t          |dz            }|dk    r| d| d	| d
}	nD|dk    r|r| d	| d| dn| d	| d
}	n(|dk    r|r| d| dn| d
}	nt          |           d}	|rdnd}
|
 d|	 S )uE  Format per-prompt elapsed time for the status bar.

        Always returns a string — shows 0s on fresh start before first turn.
        Keeps seconds visible at all scales so it increments smoothly:
            59s → 1m → 1m 1s → ... → 1m 59s → 2m → 2m 1s → ...
            59m 59s → 1h → 1h 0m 1s → ...
            23h 59m 59s → 1d → 1d 0h 1m → ...

        Emoji prefix: ⏱ when turn is live, ⏲ when frozen or fresh start.
        Uses width-1 (no variation selector) glyphs so the status bar stays
        aligned in monospace terminals.
        Nra  u   ⏲ 0siQ r  r   r   zd h r  m su   ⏱u   ⏲r  )r  r  r  )r  r  r  elapseddays	remaininghoursminutessecondstime_stremojis              rM   _format_prompt_elapsedz HermesCLI._format_prompt_elapsed5	  sr    $C)?)?85F5R$)++ 111Xgc7##7e#$$eO	I%&&$	i2o&&i"n%%!8855%557555HHQYY<C_%88788g8888EI_I_U\I_I_I_HHq[[3:M'//W////7HHg,,)))H(5$$($$$rO   c                 $   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
  	                                          }i d|d|dt          |          d|                     t          | dd           t          | dd          t          | dd           d u          dddd dd ddddd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   r  r  r  z.gguf      r  ra  
model_namemodel_shortdurationprompt_elapsedr  r  )r  context_tokensr   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compressionscontext_compressorlast_prompt_tokenscompression_countr  )ru  r   r  r  r  r  r   r  r  total_secondsr%   r  r"  r	  )	r+  r   r!  r"  elapsed_secondssnapshot
compressorr%  r&  s	            rM   _get_status_bar_snapshotz"HermesCLI._get_status_bar_snapshot[	  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
*
;
 /@@
 d992D990#66T#7>>dJ :  	
 a
 d
 t
 #A
 $Q
 (
 )!
  $Q!
" (#
$ #A%
&  '
( A)
.  	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*+rO   r8   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_cwidthr<   )prompt_toolkit.utilsr;  rx   r  )r8   r;  s     rM   _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   r<   r:  Nr  )r<  r;  rx   r=  r  r  rd   r  )
clsr8   r>  r;  ellipsisellipsis_widthr  r  r  ch_widths
             rM   _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      r  r   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)re  rG  r  get_sizer  rx   r  r  )r   rG  s     rM   _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@   )rI  r+  r  s     rM   _use_minimal_tui_chromez!HermesCLI._use_minimal_tui_chrome	  s"    =0022ErzrO   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: rP  r  r  r   )r  rM  )r+  rN  r  s      rM   _tui_input_rule_heightz HermesCLI._tui_input_rule_height	  sU    ,,,GXGGHHHu100u0==Dqq1DrO   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   rR  r  )ru  rM  rL  s     rM   _agent_spacer_heightzHermesCLI._agent_spacer_height	  s<    t-u55 	100u0==Dqq1DrO   c                     |                                  }|sdS |                     |          rdS |p|                                 }|rE|dk    r?ddl}|                     |          }t          d|                    ||z                      S dS )zPReturn the visible height for the spinner/status text line above the status bar.r   rR  r  Nr  )_render_spinner_textrM  rI  mathr=  r  ceil)r+  r  spinner_linerX  
text_widths        rM   _spinner_widget_heightz HermesCLI._spinner_widget_height	  s    0022 	1''e'44 	175577 	9URZZKKK77EEJq$))J$677888qrO   c                    t          | dd          }|sdS t          | dd          pd}|dk    rXt          j                    |z
  }|dk    r-t          |dz            t          |dz            }}| d| d}n|dd}d	| d
| dS d	| S )zCReturn the live spinner/status text exactly as rendered in the TUI.r  r<   r  r   r   r  r  .1f    ())ru  r  r  r  )r+  txtt0r  _m_selapsed_strs          rM   rW  zHermesCLI._render_spinner_text	  s    dOR00 	2T-q116Q66n&&+G"}}W]++S2->->B!#nnrnnn!(////.......CzzrO   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.rR  )class:voice-status-recordingu	    ● REC )rh  u    ● REC  Ctrl+B to stop )class:voice-statusu	    ◉ STT )ri  u    ◉ Transcribing... )ri  u    🎤 Ctrl+B z	 | TTS onr<   z | Continuousri  u    🎤 Voice modeu     —  Ctrl+B to record )rI  rM  r  r  r  r  )r+  r  r   ttsconts        rM   _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']']']^__rO   c                 B   	 |                                  }||                                 }|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          }|r|                    |           |                     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%  r  ctx --r$      │ r   Hermes)r8  rI  rD  r  rd   r'   r&   rV   rx   ru  r   )r+  r  r6  percentpercent_labelduration_labelr8   re   	ctx_totalctx_usedcontext_labelr$  s               rM   _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(((%\\*:;;N -^,,,--gll5.A.A5III 	U 	U 	UTgt(D(DR$**(TTTTT	Us    A,E4 /AE4  B3E4 4'FF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g
}|                    d          }|r,|	                    d           |	                    d|f           |	                    d	           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)Nr  r#  r  )class:status-baru    ⚕ zclass:status-bar-strongr"  )r  rp  r  )r}  r  r'  rn  ro  rq  r&  r%  r  rr  )r  rs  )r  r  r$  c              3   H   K   | ]\  }}                     |          V  d S r^   )r=  )rY   r  r8   r+  s      rM   rb   z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>u
  s5      XXwq$d<<TBBXXXXXXrO   r<   c              3       K   | ]	\  }}|V  
d S r^   r_   rY   r  r8   s      rM   rb   z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>w
  s&      $?$?gaT$?$?$?$?$?$?rO   r}  r  )r  ru  r8  rI  r  r'   r&   r  rV   r  sumrd   rD  rx   r{  )r+  r6  r  rw  fragsru  rv  rx  ry  rz  	bar_styler$  total_width
plain_texttrimmeds   `              rM   _get_status_bar_fragmentsz#HermesCLI._get_status_bar_fragments7
  s   ' 	749NPT+U+U 	IB	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/@E &.\\2B%C%CN% O%FGGG&<n%MNNNLL!:;;;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   F;G G %HHresolved_providerc           	         | j         pd                                }d}	 ddlm}m} ||vrE |||          }|r7||k    r1| j        s|                     d| d| d| d           || _         |}d	}n# t          $ r Y nw xY w|d
k    r	 ddlm	}m
}  ||| j                  }	|	r4|	|k    r.| j        s|                     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}  |||          }	|	r7|	|k    r1| j        s|                     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 rJ|                    dd          d         }| j        s|                     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.r<   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-codexr  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  rx   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                    rM   _normalize_model_for_providerz'HermesCLI._normalize_model_for_provider~
  sJ   )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A1 1
A>=A>A6C? ?
DDA-F 
FF6*H! !
H.-H.c                 ~    |s|                      d           |pd| _        d| _        |                                  dS )z@Called by agent when thinking starts/stops. Updates TUI spinner.Tr  r<   ra  N)_flush_reasoning_previewr  r  r  )r+  r8   s     rM   _on_thinkingzHermesCLI._on_thinking
  sM     	6)))555!ZR #rO   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    rM   _current_reasoning_callbackz%HermesCLI._current_reasoning_callback
  sB     	04#9 	0//< 	& 3 	&%%trO   reasoning_textc                 x   |                                 }|sdS 	 t          j                    j        }n# t          $ r d}Y nw xY wd}t          d|t          |          z
  dz
            }g }t          j        d|	                    dd                    }|D ]^}d	
                    d
 |                                D                       }	|	r)|                    t          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.Nr    [thinking] r  r  z\n\s*\n+
r\   r  c              3   f   K   | ],}|                                 |                                 V  -d S r^   r   rY   r  s     rM   rb   z4HermesCLI._emit_reasoning_preview.<locals>.<genexpr>  s<      __RVR\R\R^R^_tzz||______rO   rR  r_  z[thinking] r|  
  ... ( more lines))rI   r  r  r  rx   r  r  rE   r  r  rd   r  r  textwrapfillr   ro  _DIM_RST)r+  r  preview_text
term_widthr  
wrap_width
paragraphsraw_paragraphs	paragraphr   linespreviews               rM   _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   3 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  r<   Nr  (   r  r  r\   r  r  r  rQ  z.
z!
z?
z:
r  r  r  r  )r  	r   !r  rC  r  r  )ru  r  r  r  rx   r  r  rfindr  r"  lstripr  r  )r+  r  bufr  target_width
flush_text
line_breakmin_newline_flushsearch_start
search_endcutboundarys               rM   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 ??r  c                    |                     d          }t          |          dk    r"dt                       dt          |           dS t	          t          | dd                    }t	          t          | dd                    }t          d|          }t          d	|          }|d
|         }t          d	t          |          t          |          z
            }t          ||          }|r|| d
         ng }t          |          t          |          z
  t          |          z
  }	|	d	k     rd	}	g }dt                       dt          |d	                    dg}
|
                    d |dd
         D                        |	d	k    r&|	dk    rdnd}|
	                    d|	 d| d           |
                    d |D                        d
                    |
          S )z5Format the submitted user-message scrollback preview.r\   r  [bold    ]●[/] [bold]rs  r  r  r  r   Nc              3   <   K   | ]}d t          |           dV  dS z[bold]rs  N_escaper  s     rM   rb   zCHermesCLI._format_submitted_user_message_preview.<locals>.<genexpr>b  s4      NNT8gdmm888NNNNNNrO   r  r  z[dim]... (+z more )[/]c              3   <   K   | ]}d t          |           dV  dS r  r  r  s     rM   rb   zCHermesCLI._format_submitted_user_message_preview.<locals>.<genexpr>h  s4      JJT8gdmm888JJJJJJrO   )r  r  rH  r  r  ru  r  r"  extendr  rd   )r+  r  r  r_  r`  headremaining_after_head
tail_counttailhidden_middle_countpreview_linesnouns               rM   &_format_submitted_user_message_previewz0HermesCLI._format_submitted_user_message_previewK  s     &&u::??QKMMQQ9L9LQQQQ'$(JANNOO'H!LLMM
![))J''
\k\""1c%jj3t99&<==%9::
&08uj[\\""b!%jj3t994s4yy@"""#D H[]]GG'$q'2B2BGGG
 	NNT!""XNNNNNN""0A55667D  !T/B!T!T$!T!T!TUUUJJTJJJJJJyy'''rO   c                     t          |t                    rd|vr|pdS t          j        d          }d }|                    ||          S )z@Expand [Pasted text #N -> file] placeholders into file contents.[Pasted text #r<   ,\[Pasted text #\d+: \d+ lines \u2192 (.+?)\]c                    t          |                     d                    }	 |                    d          S # t          t          f$ r3 t
                              d|           |                     d          cY S w xY w)Nr  rl   rm   z8Paste file gone or unreadable, returning placeholder: %sr   )r   groupr  r  IOErrorrs   rt   )matchry   s     rM   _expand_refz7HermesCLI._expand_paste_references.<locals>._expand_refq  s~    A''D&~~w~777W% & & &Y[_```{{1~~%%%&s   : AA>=A>)rT   rW   rE   compilerF   )r+  r8   paste_ref_rer  s       rM   _expand_paste_referencesz"HermesCLI._expand_paste_referencesk  s`    $$$ 	(8(D(D:2z"QRR		& 		& 		& T222rO   c                    t                                          dt                       dd d           t          |pd          }d|v r6t                                          |                     |                     d	S t                                          dt                       dt          |           d           d	S )
z=Render a user message using the normal chat scrollback style.r  r  x   ────────────────────────────────────────rs  r<   r\   r  r  N)r  r  rH  rW   r  r  )r+  r  r8   s      rM   _print_user_message_previewz%HermesCLI._print_user_message_preview~  s    ???
???@@@:#$$4<<MM K KD Q QRRRRRMM X X Xgdmm X X XYYYYYrO   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_bufr<   r  )_reasoning_shown_this_turnru  r  r  r  r  r  ro  r  r  r  r  r  )r+  r8   r,  r_labelr_fillr  s         rM   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 )(rO   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.r  Fr  r<      └r  r     ┘_deferred_contentN)ru  ro  r  r  r  r  r  r  r  r  _emit_stream_text)r+  r  r,  deferreds       rM   _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 1rO   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_prefiltr<   _stream_last_was_newline_in_reasoning_blockFr   r  r\   r  c              3   4   K   | ]}t          |          V  d S r^   r  rY   rp  s     rM   rb   z*HermesCLI._stream_delta.<locals>.<genexpr>@  s(      ::c!ff::::::rO   )_flush_stream_reset_stream_stater  ru  r  rt  r  findr  rI   r  r  r   r  r
  r   r  _stream_deltar  )r+  r8   
_OPEN_TAGS_CLOSE_TAGSrK   r  r  	precedingis_block_boundarylast_nlsafer  r-  aftermax_tag_lensafe_reasonings                   rM   r  zHermesCLI._stream_delta  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	 	rO   c                    |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 rv| j                            dd          \  }| _        | j        dk    rt5          |          }t'          |rt6           | | t,           n
t6           |            d| j        v tdS dS )z,Emit filtered text to the streaming display.Nr  Fr  r<   r\   Tr   r.  response_label
   ⚕ Hermesbanner_text#FFF8DCr  r  r  r|  r  z[38;2;r  r  r     ╭─r     ╮_stream_text_ansirI   )r   ru  r  r  r  r  r0  r/  r!  r1  rx   r  r  r  r  r  r  r  r  ro  _ACCENTr  r  r  r  r\  rT  _STREAM_PAD)r+  r8   r/  r$  label	_text_hex_r_g_br,  r  _tcr  s                rM   r  zHermesCLI._emit_stream_textI  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$"+w66-d33X{5C55t555[BXRVBXBXYYY	 d&&&&&&&s%   5<B2 2CCAD! !D<;D<c                 8   t          | dd          r9t          | dd          r(d| _        |                     | j                   d| _        |                                  | j        rlt          | dd          }| j        dk    rt          | j                  n| j        }t          |rt           | | t           n
t           |            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.r   Fr  r<   r  rI      ╰r  r     ╯N)ru  r   r  r  r  r  r\  rT  ro  r  r  r  r  r  r  r  )r+  r   r  r,  s       rM   r  zHermesCLI._flush_stream~  sI   
 4.66 	&74IZ\^;_;_ 	&',D$""4#7888#%D  	!!### 	"$ 3R88C?C?[_f?f?f)$*:;;;lpl|DX{5C55t555[BXRVBXBXYYY!D " 	?(**2Aw==5AE?==t==>>>>>	? 	?rO   c                     d| _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        dS )z3Reset streaming state before each agent invocation.r<   FTN)r  r  r  r  r  r   r  r  r  r  r  r;  s    rM   r  zHermesCLI._reset_stream_state  s`    $"'!#!#( (,%%*" &(#!#rO   r  c                    |                                                                 }|                    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k    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/reload-skillsz/reload_skillszReloading skills...z/browserzConfiguring browser...Processing command...)r   rI   r  )r+  r  	cmd_lowers      rM   _slow_command_statuszHermesCLI._slow_command_status  s    MMOO))++	 011 	)(( 011 	'&& 122 	)(( 122 	)((	** 	211%%--(((I9I,I,I((
++ 	,++&&rO   c                     t          t          j                    dz            t          t                    z  }t          |         S )z9Return the current spinner frame for slow slash commands.r  )r  r  r  r  _COMMAND_SPINNER_FRAMES)r+  	frame_idxs     rM   _command_spinner_framez HermesCLI._command_spinner_frame  s5    ((2-..5L1M1MM	&y11rO   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.Tra  r  u   ⏳ NFr<   )r  r  r  r  )r+  r  s     rM   _busy_commandzHermesCLI._busy_command  s       !%%c***	////"""EEE$)D!#%D #..... %*D!#%D #....s   A$ $&B
c                 $   t          | dd          }|s t          t           dt                      dS | j        r t          t           dt                      dS | j        s| j        s| j        s| j        r t          t           dt                      dS |pt          |dd          }| t          t           dt                      dS 	 t          |d	d
          }| 	                    |          }||k    rBt          |d	          r2d| _        ||_        t          |d          rt          |          |_        d| _        |                    d           dS # t           $ r+}t          t           d| t                      Y d}~dS d}~ww xY w)z3Open the active input buffer in an external editor.r  Nz=External editor is only available inside the interactive CLI.FzAWait for the current command to finish before opening the editor.z3Finish the active prompt before opening the editor.current_bufferz<No active input buffer is available for the external editor.r8   r<   Tcursor_position)validate_and_handlez Failed to open external editor: )ru  ro  r  r  r  r  r  r  r  r  rt  _skip_paste_collapser8   r  r2  open_in_editorrx   )r+  bufferrl  target_bufferexisting_textexpanded_textr  s          rM   _open_external_editorzHermesCLI._open_external_editor  s   dFD)) 	t``Z^``aaa5  	tdd^bddeee5 	t1 	T5I 	TM` 	tVVPTVVWWW5F'#/?"F"F t__Y]__```5	#M62>>M 99-HHM--'-2P2P-,0)%2"=*;<< G474F4FM1 )-D%((U(CCC4 	 	 	tHHSH$HHIII55555	s   BE 
F$ F

Fc                    ddl m}m} d}d}	  || j        | j        | j                  }n# t          $ r}|}Y d}~nd}~ww xY w|
|ddlm} t          ||          rt          | j
        t                    r| j
        ng }|D ]}|                    d          pd                                                                }	|                    d          pd                                }
|	r|
sk	  ||		          }t                              d
||	|
           t#          d|	 d|
            |	| _        |
| _        d} n# t          $ r Y w xY w|6|r ||          nd}t'                                          d| d           dS |                    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          }|rTt          |t,                    r?| j         p-| j        | j        k    p| j        |                    d          k    }|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_errorN)	requestedexplicit_api_keyexplicit_base_url)	AuthErrorr   r<   r   )r>  zEPrimary provider auth failed (%s). Falling through to fallback: %s/%su7   ⚠️  Primary auth failed — switching to fallback:  / zProvider resolution failed.z
[bold red]rs  Fr   r   
openrouterr  r  r  credential_poolsourcerh  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  r<  r=  r  r  r  rx   hermes_cli.authrA  rT   r  rc   rV   rI   r   rs   rt   ro  r   r  r  r  rW   r  r   r   r   r  r  _credential_poolr  r  rF  r  r  r   r  )r+  r<  r=  _primary_excruntimer  rA  	_fb_chain_fb_fb_provider	_fb_modelr  r   r   r  resolved_api_moderesolved_acp_commandresolved_acp_argsresolved_credential_pool_source_has_custom_basecredentials_changedrouting_changedruntime_modelshould_use_runtime_modelrF  _defaultmodel_changeds                               rM   _ensure_runtime_credentialsz%HermesCLI._ensure_runtime_credentials  s   	
 	
 	
 	
 	
 	
 	
 	

 	..1!%!7"&"9  GG
  	 	 	LLLLLL	 ?|7111111,	22 !4>t?SUY4Z4ZbD00`b	$ ! !C$'GGJ$7$7$=2#D#D#F#F#L#L#N#NL!$!1!1!7R > > @ @I' !y ! !":":\"R"R"Rc(,	     vZf v vkt v vwww2>/%.
'+$ ! ! ! ! ?EQt33LAAAWtGMM 9W 9 9 9:::5++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;; 	+ J 2
dm+2
gkk&111 %
 ( +*

 z 	/ 	
LLLLLL99:KLL !)DJKKR "3      
 ::;LMM   	6? 	6m 	6I_DJ15D.ts7   , 
A=A2AE
EE6P 
PPuser_messagec                    ddl m} | j        | j        | j        | j        | j        t          | j        pg           t          | dd          d}| j
        || j
        |d         |d         |d         |d	         t          |d
                   fd}t          | dd          }|sd|d<   |S 	  ||d                   }n# t          $ r d}Y nw xY w||d<   |S )aL  Build the effective model/runtime config for a single user turn.

        Always uses the session's primary model/provider.  If the user has
        toggled `/fast` on and the current model supports Priority
        Processing / Anthropic fast mode, attach `request_overrides` so the
        API call is marked accordingly.
        r   )resolve_fast_mode_overridesrH  Nr   r   r   r  r  r  rD  r   r   r  r  r  )r   rJ  	signaturer   request_overridesr   )r  r^  r   r   r   r  r  rc   r  ru  r   rD  rx   )r+  r\  r^  rJ  router   	overridess          rM   _resolve_turn_agent_configz$HermesCLI._resolve_turn_agent_config{  s*    	BAAAAA |',"--&t-?FF
 
 Z

#
#
#	"gfo&&
 
 t^T:: 	)-E%&L	33E'NCCII 	 	 	III	%.!"s   )B; ;C
	C
model_overrideruntime_overridera  rf  rg  ra  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                  }n# t
          $ r
 | j        }Y nw xY w|r|| j        k    ryt!                                          d	t           d
t%          | j                   dt%          |           d           || _        | j        
                    | j                  }|r|}| 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           tC          | dd          d }|p| j"        }tG          dMi 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'         d0| j(        r| j(        ndd1| j)        pdd2| j*        d3| j+        d4|d5| j,        d6| j-        d7| j.        d8| j/        d9| j0        d:| j1        d;| j        d<d=d>| j        d?| j2        d@| 3                                dA| j4        dB| j5        dC| j6        dD| j7        dE| j8        dF| j9        dG| j9        dH| j:        dI| j;        r| j<        nddJ| j;        r| j=        nddK| j>        r| j?        nddL| j>        r| j@        nd| _         | j         aAt          | j         _B        ||                    d$          |                    d#          |                    d%          |                    d'          t          |                    d)          pdM          f| _D        | jE        r| j        r| j         r	 | j         F                                 | j         jG        rC| j        H                    | j        | jE                   t          dN| jE                    d| _E        n0# t          t
          f$ r}t          dO|            Y d}~nd}~ww xY wdS # t
          $ r0}t!                                          dP| dQ           Y d}~dS d}~ww xY w)Rz
        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).r  	]Session  was compressed into 2; resuming the descendant with your transcript.[/]c                 D    g | ]}|                     d           dk    |S rolesession_metar  rY   r  s     rM   r[   z)HermesCLI._init_agent.<locals>.<listcomp>  s,    SSS!155==N3R3RA3R3R3RrO   c                 D    g | ]}|                     d           dk    |S rn  userr  rp  s     rM   r[   z)HermesCLI._init_agent.<locals>.<listcomp>  s,     P P Pqf8O8O8O8O8OrO   r<   title "r  r  u   ]↻ Resumed session[/] [bold]z	[/][bold r  z[/] ( user messager  r  rr  z total messages). found but has no messages. Starting fresh.[/]CUPDATE sessions SET ended_at = NULL, end_reason = NULL WHERE id = ?rH  r_  r   r   r   r   r  r  r  r  r  rD  r   r  rl  verbose_logging
quiet_modeephemeral_system_promptr  r  r   ra  providers_allowedproviders_ignoredproviders_orderprovider_sortprovider_require_parametersprovider_data_collectionri  rj  rB  r  clarify_callbackreasoning_callbackr  thinking_callbackr  r  rT  skip_context_filesskip_memory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: rs  )Jr   r[  r  r  r  rx   rs   rt   r  r  get_sessionri  ro  r  r  resolve_resume_session_idr  r  r  get_messages_as_conversationr  rV   rH  _connexecutecommitr   r   r   r  r  rc   r  ru  r   rQ  r   r  rl  r   r   r  r  r   r  r  r  r  r  r  _clarify_callbackr  r  r  r  r  rT  rU  _on_tool_progressr  _on_tool_start_on_tool_completer  r  _on_tool_gen_startrs  	_print_fnrD  r  r  _ensure_db_session_session_db_createdset_session_titler  )r+  rf  rg  ra  r  r|   ro  resolved_idresolved_metarestored	msg_count
title_partrJ  effective_models                 rM   _init_agentzHermesCLI._init_agent  sS	    :!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 = 1	T- 1	d6O 1	+77HHL OOOOPPP4ggaegghhhu.".HHYY . . ."o. 	1{do==##& & &wt'?'? & &{++& & &  
 #. $ 0 < <T_ M M  1#0L'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_&    &--////   U	& < 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+ #'"8"8+ !%+  $|+++ ?C>P(Z(:(:VZ+ "&!6!>$+  "&!6!6!+" "..#+$ #4"3%+& #'"6"6'+( #'"8"8)+* !% 5 5++, #11-+. -1,I,I/+0 *.)G)G1+2  ??3+4 5+6  ++7+8 "&!7!79+: $(#C#C#E#E#E;+>  $33?+@ #'"3"3A+B %)$<$<C+D *.)F)FE+F !% 4 4G+H $(#4#4I+J !--K+L (,'='=M+N <@;U$_D$7$7[_O+P BFA['et'='=aeQ+R =A<R&\d&8&8X\S+T >B=S"]$"9"9Y]U+DJ\ !%
 $+DJ J''J''J''I&&gkk&))/R002D. " 	Et'7 	EDJ 	EEJ11333z5 3(::4?DL_``` QD<O Q QRRR.2+"I. E E ECCCDDDDDDDDE 4 	 	 	MM O O O OPPP55555	s~   > 
A-A((A-(D DD AL% %
L21L26K Z2 A(Z  ?Z2  Z-Z(#Z2 (Z--Z2 2
[,<%[''[,c           	         | j                                          d}t          | d          r-| j        r&t          | j        d          r| j        j        j        }t          j                    j        }| j	        p|dk     }|r6| 
                    t                                 |                                  nft          | j        d          }t          j        dt          j                              }t%          | j         | j        ||| j        | j        |           |                                  |r|d	k    r| 
                                 | 
                    d
|dd           | 
                    d           t-          | dd          pd}d|v sd|                                v r| 
                    d           n/d|v r| 
                    d           n| 
                    d           ddlm} t-          | dd          pd} ||          rS| 
                                 | 
                    d           | 
                    d           | 
                    d           | 
                                 dS )z0Display the welcome banner in Claude Code style.Nr   r1  r  Tr  rz  r   r  r   r   toolsr  ri  r&  i    u'   [yellow]⚠️  Context length is only rC  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   r<   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  clearrt  r   r1  r&  r  r  r  r   r  r1  _show_statusrR  r  r  r  r  rT  r   ri   _show_tool_availability_warningsru  r   hermes_cli.model_switchr  )	r+  ctx_lenr  use_compactr  r   r   r  r!  s	            rM   show_bannerzHermesCLI.show_bannerK  s    4!! 	Cdj 	CWTZI]5^5^ 	Cj3BG -//7
l5j2o 	 5 7 7888 )$:O\`aaaE )NBIKK88C !j!%!6?&    	--///  	w$!!!G'Q G G G   m   tZ44:H(""h(..2B2B&B&B##U    8####e    ##x  
 	GFFFFFT7B//52
%%j11 	!!!9   \   H   	rO   c                    | j         r| j        sdS | j                            | j                  }|s5|                     d| j         d           |                     d           dS 	 | j                            | j                  }n# t          $ r
 | j        }Y nw xY w|rV|| j        k    rK|                     d| j         d| d           || _        | j                            | j                  }|r|}| j                            | j                  }|rd |D             }|| _        t          d	 |D                       }d
}|
                    d          rd|d          d}t                      }|                     d| d| j         d| d| d|dk    rdnd
 dt          |           d           n1t                      }|                     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: rs  zH[dim]Use a session ID from a previous CLI run (hermes sessions list).[/]z[dim]Session rj  rk  c                 D    g | ]}|                     d           dk    |S rm  r  rp  s     rM   r[   z6HermesCLI._preload_resumed_session.<locals>.<listcomp>  s,    OOOaquuV}}/N/N/N/N/NrO   c                 D    g | ]}|                     d           dk    |S rr  r  rp  s     rM   r[   z6HermesCLI._preload_resumed_session.<locals>.<listcomp>  s,    LLL1AEE&MMV4K4KQ4K4K4KrO   r<   rt  ru  r  r  u   ]↻ Resumed session [bold]z[/bold] (rv  r  r  rr  z total messages)[/]ri  rw  rx  T)r  r  r  ri  r  r  rx   r  r  r  rV   rH  r  r  r  )r+  ro  r  r  r  r  r  accent_colors           rM   _preload_resumed_sessionz"HermesCLI._preload_resumed_session  s0    } 	D$4 	5'33DODD 	DDDD   -   5	**DDT_UUKK 	* 	* 	*/KKK	* 	-;$/99S S SS S S   *DO ,88IIM -,#@@QQ 	OO8OOOH(0D%LLLLLMMIJ(( ;:,w"7:::
&==L6L 6 6T_ 6 66 66 63<>>CCr6 6 x==6 6 6    '==L0L 0 04? 0 0 0   5	"**"  
 "))++++ 	 	 	D	 ts%   (B BB*AH/ /
H<;H<c                 <   | j         sdS | j        dk    rdS d}d}d}d}g }d}d}| j         D ]p}|                    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          |
          }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                    |          }r|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-          } |                    d.d/          }!|                    d0d1          }"n# t&          $ r d+}d-} d/}!d1}"Y nw xY w |            }|r|                    d2| d3d45           t)          |          D ]\  }#\  }	}|	dk    rw|                    d6d7|  5           |                                }$|                    |$d$         dz   d85           |$dd         D ]}%|                    d9|% dd85           n|	d&k    rw|                    d:d;|" 5           |                                }$|                    |$d$         dz   d5           |$dd         D ]}%|                    d<|% dd5           nv|                    d:d7|" 5           |                                }$|                    |$d$         dz   d85           |$dd         D ]}%|                    d<|% dd85           |#t          |          dz
  k     r|                    d            ||d=|  d>d?|! d@|A          }&|                     |&           dS )BaP  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  rn  r<   rP   r@   systemtoolrs  rS   r8   	image_urlz[image]r  r  	assistantr\   z ...functionr  r  rr  r  z, ...r  callcallsr   tool : r  r   r  assistant_lastrM  rO  r.  r  r  session_label#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  )rt  border_stylepaddingr  )r  r   rV   rW   rT   rc   rU   r  rd   r  rN   r  
rich.panelrN  	rich.textrP  r0  r/  r1  rx   r  r  )'r+  MAX_DISPLAY_EXCHANGESMAX_USER_LENMAX_ASST_LENMAX_ASST_LINESentries_last_asst_idx_last_asst_fullmsgrn  rP   r@   r8   re   rZ   
full_partsr  tc_countnamestcfnr  	names_strr  
tc_summaryskippedadj_idxrN  rP  r/  r$  _history_text_c_session_label_c_session_border_c_assistant_label_cr  	msg_linesmlpanels'                                          rM   _display_resumed_historyz"HermesCLI._display_resumed_history  s    ( 	F )++F " , ;	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,,,T22
 '%%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!
 
 
 	E"""""s   A(Q< <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  ry  TF)	hermes_cli.clipboardr  r)   r  r   r  r  r  r  )r+  r  img_dirtsimg_paths        rM   _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 urO   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  r<   z#  No changes since this checkpoint.r\   r  r  z more lines, showing first 80)u     ❌ rM  )ri   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.)r  r  rt  r   r  _checkpoint_mgrr   r  r  r  r  r  list_checkpointsr   _resolve_checkpoint_refr  rV   r  rd   restorer  	undo_last)r+  r  r  mgrr   re   r  r  target_hashr   r  r  
diff_linesri   s                 rM   _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'?,,-----rO   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+  r  r  r  s       rM   r  z!HermesCLI._resolve_checkpoint_ref  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  rc   )rc   lsz  No state snapshots yet.z&  Create one: /snapshot create [label]Nz  State snapshots (z/state-snapshots/):
r_  r  z>3IDz<35r  Filesz>5Size>10Labelu	   ───ui   ───────────────────────────────────u   ─────u   ──────────u<   ────────────────────
total_size   z Bi   .0fz KBr^  z MBr  r<   3id
file_countcreater  )r  z  Snapshot created: z#  No state files found to snapshot.)r  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  r   r*   r  r  r   r  r  rV   rd   r  r  )r+  r  r  r  r  r  r*   re   subcmdsnapsr  r  sizesize_strr  snap_idr  r  deleteds                      rM   _handle_snapshot_commandz"HermesCLI._handle_snapshot_command  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`   s     rM   r[   z2HermesCLI._handle_stop_command.<locals>.<listcomp>g  ,    HHH155??i+G+G1+G+G+GrO   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        rM   _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5rO   c           	         ddl m}m} |                                }d |D             }d |D             }t	          dt          |                      |D ]k}|                    dd          dd	         } ||                    d
d                    }t	          d|                    dd           d| d|            l|rt	          dt          |                      t          | dd          }	t	          d|	rdnd            dS )u>   Handle /agents — show background processes and agent status.r   )format_uptime_shortr#  c                 D    g | ]}|                     d           dk    |S r%  r  r`   s     rM   r[   z4HermesCLI._handle_agents_command.<locals>.<listcomp>v  r'  rO   c                 D    g | ]}|                     d           dk    |S r%  r  r`   s     rM   r[   z4HermesCLI._handle_agents_command.<locals>.<listcomp>w  s,    III!AEE(OOy,H,HA,H,H,HrO   z  Running processes: r  r<   Nr  uptime_secondsr  ri  r  rp  z  Recently finished: r  Fz	  Agent: r&  idle)r(  r/  r#  r)  ro  r  rV   ru  )
r+  r/  r#  r+  r&  finishedra   cmdupagent_runnings
             rM   _handle_agents_commandz HermesCLI._handle_agents_commandq  sO   PPPPPPPP$2244	HHiHHHIIyIII6G66777 	H 	HA%%	2&&ss+C$$QUU+;Q%?%?@@BF155s33FFFFFFGGGG 	=;CMM;;<<<&6>>DBIIFDDEEEEErO   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_environmentro  r  r  r  r  r:  r  r  r  )r+  r:  ns      rM   _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GrO   c                 @   t          j        |                    d                                        d          }d| d}t	          | dd          }|rt	          |dd          nd}|r;t          |d          r+|                    |           |                                 dS |r;t          |d	          r+|                    |           |                                 dS t          j
                            |           t          j
                                         dS )
z-Copy *text* to terminal clipboard via OSC 52.rl   asciiz]52;c;r  Nr  	write_rawr  )base64	b64encodeencodedecoderu  rt  rA  r  r  sysr  )r+  r8   payloadseqr  r  s         rM   _write_osc52_clipboardz HermesCLI._write_osc52_clipboard  s   "4;;w#7#788??HH(7(((dFD))14>h---$ 	gfk22 	S!!!LLNNNF 	gfg.. 	LLLLNNNF

rO   r  c                   t          j                    }|| j        z
  dk     rdS || _        t          | dd          }|rt          |dd          nd}	 |r?t	          |d          r/|                    t                     |                                 n|r?t	          |d          r/|                    t                     |                                 nBt          j
                            t                     t          j
                                         n# t          $ r Y dS w xY wt                              d|           | j        s(d| _        t          d	t            d
t"                      dS dS )z@Best-effort reset when leaked mouse reports indicate mode drift.r   Nr  r  rA  r  z-Recovered terminal input modes after leak: %sTr_  ziRecovered terminal input modes after leaked mouse reports. If this repeats, run /new or restart this tab.)r  r  r  ru  rt  rA  _TERMINAL_INPUT_MODE_RESET_SEQr  r  rF  r  rx   rs   rt   r  ro  r  r  )r+  r  r  r  r  s        rM   _recover_terminal_input_modesz'HermesCLI._recover_terminal_input_modes  s   n//#55F),&dFD))14>h---$	 #'&+66 #  !?@@@ #GFG44 #;<<<
  !?@@@
  """ 	 	 	FF	 	FOOO5 	59D2HT H HAEH H    	 	s   CD 
D%$D%cmd_originalc                    |                     d          }t          |          dk    r|d                                         nd}d | j        D             }|st	          d           dS |rp	 t          |          dz
  }n # t          $ r t	          d           Y dS w xY w|dk     s|t          |          k    r"t	          d	t          |           d
           dS nt          |          dz
  }|dk    r[t          ||                             d                    s3|dz  }|dk    r(t          ||                             d                    3|dk     rt	          d           dS t          ||                             d                    }|st	          d           dS 	 | 	                    |           t	          d|dz    d           dS # t          $ r}t	          d|            Y d}~dS d}~ww xY w)u=   Handle /copy [number] — copy assistant output to clipboard.r  maxsplitr<   c                 D    g | ]}|                     d           dk    |S )rn  r  r  rp  s     rM   r[   z2HermesCLI._handle_copy_command.<locals>.<listcomp>  s,    ZZZ1QUU6]]k=Y=YQ=Y=Y=YrO   z  Nothing to copy yet.Nz  Usage: /copy [number]r   z!  Invalid response number. Use 1-r   rP   z-  Nothing to copy in assistant responses yet.z-  Nothing to copy in that assistant response.z  Copied assistant response #z to clipboardz  Clipboard copy failed: )r  r  rI   r  ro  r  r  rh   rV   rI  rx   )r+  rM  re   argr  r  r8   r|   s           rM   _handle_copy_commandzHermesCLI._handle_copy_command  sN   ""A".."%e**q..eAhnnbZZ 9ZZZ	 	,---F 	#hhl   1222 Qww#Y//MC	NNMMMNNN 0 i..1$C((#7	#8J8J98U8U#V#V(q ((#7	#8J8J98U8U#V#V(QwwGHHH#IcN$6$6y$A$ABB 	CDDDF	5''---JC!GJJJKKKKK 	5 	5 	5333444444444	5s*   -B   BB"+G 
G6G11G6c                 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.r  Nr  r<   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   r;  r  ro  r  r  r  r  r  r   r  r  r  r  )r+  rM  raw_argshint
path_token
_remainder
image_paths          rM   _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rO   Tannouncer  r\  c                   ddl }ddlm} d}g }|D ]}|                                s|                                j        dz  }	|r*t          dt           d|j         d|	 d	t                      	 |
                     |t          |          |
                    }
t          j        |
          }|                    d          rT|                    dd          }|                    d| d| d           |rt          dt           dt                      n:|                    d| d           |rt          dt           dt                      G# 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.r  r_  u   👁️  analyzing r  zKB)...)r  user_promptr  analysisr<   z6[The user attached an image. Here's what it contains:
zA]
[If you need a closer look, use vision_analyze with image_url: r  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 retryrQ  zWhat do you see in this image?)rg  tools.vision_toolsr^  rr   r  st_sizero  r  r  r  r  rW   rv   loadsrV   r  rx   rT   rd   )r+  r8   r  r\  rm  r^  analysis_promptenriched_partsr  size_kbresult_jsonr   descriptionr|   	user_textr  s                   rM   _preprocess_images_with_visionz(HermesCLI._preprocess_images_with_vision  s    	#"""::::::8 	  #	d #	dH??$$ mmoo-5G ^\T\\hm\\w\\VZ\\]]]d&ll''#h--_]]]  K00::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   2C$E
F*"=F%%F*c           
      "   	 ddl m}  |            \  }}d |D             }|r|                                  |                     d           |D ]}d                    |d         dd                   }t	          |d                   dk    r|d	t	          |d                   dz
   d
z  }|                     d|d          dd                    |d                    d           |                     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_   )rY   us     rM   r[   z>HermesCLI._show_tool_availability_warnings.<locals>.<listcomp>V  s"    KKKQ>9JKqKKKrO   u:   [yellow]⚠️  Some tools disabled (missing API keys):[/]rr  r  Nr  z, +z moreu      [dim]• r  z[/] [dim italic](rn  r  z*[dim]   Run 'hermes setup' to configure[/])model_toolsrl  r  rd   r  rx   )r+  rl  r  unavailableapi_key_missingrB  	tools_strs          rM   r  z*HermesCLI._show_tool_availability_warningsN  so   	;;;;;;%<%<%>%>"I{ LK+KKKO R##%%%##$`aaa+ } }D $		$w-*; < <I4=))A--!%F3tG}+=+=a+?%F%F%FF	''({tF|({({VZV_V_`des`tVuVu({({({||||##$PQQQQQR R  	 	 	DD	s   C: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  }|                     d| d| d| d | d!|	 d| d"|
 |            dS )#z!Show compact startup status line.Tr  r   r  r  r  N   r  u   [green bold]●[/]u   [red bold]●[/]r.  rC  rD  rF  rG  ui_labelr  )rD  rG  cyanr<   rX  z [dim u   ]·[/] [z]toolsets: rr  rs  u   ]·[/] [dim]provider: u   ]·[/] [dim]auth: r_   [r  r   u   ]·[/] [bold z	 tools[/])rR  r  r  r   r  r   r0  r/  r1  rx   rd   r   r  r  )r+  r  
tool_countr"  api_indicatorr/  r   separator_colorr  label_colortoolsets_infoprovider_infos               rM   r  zHermesCLI._show_statusd  sI    %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                 l   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           |                     d                    |          dd           dS ) z6Show gateway-style status for the current CLI session.rt  r<   
started_at)
updated_atlast_updated_atlast_activity_atr   Nr.  r   r   r  r   z	(unknown)r  FzHermes CLI StatuszSession ID: zPath: zTitle: zModel: r  ra  z	Created: z%Y-%m-%d %H:%MzLast Activity: zTokens: rC  zAgent Running: YesNor\   )r  markup)r  r  ri  rx   rV   rI   r  r   fromtimestampfloatru  r  r*   r  r  r  r  rd   )r+  ro  rt  
created_atr  r  fieldr   r   total_tokensr   r   rj  r  s                 rM   _show_session_statuszHermesCLI._show_session_status  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==
 	 	 	 	DIIe,,eLLLLLs0   !- <<!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  rx   ru  )r+  r  r   r   s       rM   _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     rM   _command_availablezHermesCLI._command_available  s$    G##//111trO   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          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 Commandsr<   7   Nr\   +-|^
  u   ── u    ──z
    [bold r  <15z[/] [dim]-[/] u   
  ⚡ zSkill Commandsr  z installed):z<22rh  z0Tip: Just type your message to chat with Hermes!r_  z$Multi-line: Alt+Enter for a new linez-Draft editor: Ctrl+G (Alt+G in VSCode/Cursor)zAttach image: /image z- or start your prompt with a local image pathzPaste image: Alt+V (or /paste))hermes_cli.commandsr  r0  r  rx   rI   r  ro  _BOLDr  r!  r  r  r  rH  r  _skill_commandssortedr  r;  r  )
r+  r  r  headerinner_widthcategorycommandsr5  descr  s
             rM   	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NTNNNNOOO!## 	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  r  r  c                     | d         d         S )Nr  r  r_   )rp  s    rM   rc  z&HermesCLI.show_tools.<locals>.<lambda>
  s    *f0E rO   r,  r  r  r  rh  r<   r\   r   . r  z  [r  z    * z<20 - z	  Total: u    tools  ヽ(^o^)ノ)rR  r  r  r  r  rS  rV   r  indexr  r<  )
r+  r  rt  r  padrR  r  r  toolsetr  s
             rM   
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:::rO   r5  c                 n    ddl }ddlm} ddlm ddlm ddlm d|ddf fd	}	 |	                    |          }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)redirect_stdoutr  )tools_disable_enable_commandnsr9   c                 @   t          dd           |            dS  G d d          } |            } |          5   |            ddd           n# 1 swxY w Y   |                                                                D ]}t          |           dS )a  Run tools_disable_enable_command, routing its ANSI-colored
            print() output through _cprint when inside the interactive TUI
            so escapes aren't mangled by patch_stdout's StdoutProxy into
            garbled '?[32m...?[0m' text.

            Outside the TUI (standalone mode, tests), call straight through
            so real stdout / pytest capture works as expected.
            r  Nc                       e Zd ZdefdZdS )FHermesCLI._handle_tools_command.<locals>._run_capture.<locals>._TTYBufr9   c                     dS )NTr_   r;  s    rM   isattyzMHermesCLI._handle_tools_command.<locals>._run_capture.<locals>._TTYBuf.isattyA  s    4rO   N)r>  r?  r@  r  r  r_   rO   rM   _TTYBufr  @  s/         D            rO   r  )ru  r  r  ro  )r  r  r  r  r  r  r+  r  s       rM   _run_capturez5HermesCLI._handle_tools_command.<locals>._run_capture/  s    tVT**2,,R000
         (       '))C %% 1 1,,R0001 1 1 1 1 1 1 1 1 1 1 1 1 1 11133   s   AA"Ar  r<   )rc   disableenablerc   rB  )tools_actionrj  r  z(._.) Usage: /tools z <name> [name ...]z  Built-in toolset:  /tools z webz  MCP tool:          /tools z github:create_issuer  	DisablingEnablingrr  r  r  )r  r  rj  _get_platform_toolsr  z0Session reset. New tool configuration is active.)shlexargparser  
contextlibr  r  r  hermes_cli.tools_configr  r  r  r  r  r  rd   ro  r  r  r  r  r  r  new_sessionr  )r+  r5  r  r  r  re   
subcommandr  verbr  r  r  r  r  r  s   `           @@@rM   _handle_tools_commandzHermesCLI._handle_tools_command   s    	&&&&&&......HHHHHH	Y 	4 	 	 	 	 	 	 	 	 	6	 KK$$EE 	  	  	 IIKKEEE	  "%UaU1XXR
:::OOFLGGGHHH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YYJeeTTTUUU 	@?????111111 3 3KKMM5 I I4OOOOPPPPPs   A 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  r  r  ry  rh  z(*)   r_  z<18rx  z>2z
 tools] - z  (*) = currently enabledz.  Tip: Use 'all' or '*' to enable all toolsetsz0  Example: python cli.py --toolsets web,terminalN)rW  r  r  r  r<  rX  r  )
r+  all_toolsetsrt  r  r  r  r  ry  r  markers
             rM   show_toolsetszHermesCLI.show_toolsetso  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rO   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   r  get_active_profile_namez  Profile: z  Home:    N)r   r*   hermes_cli.profilesr  r  )r+  r*   r  r   profile_names        rM   _handle_profile_commandz!HermesCLI._handle_profile_command  s    888888??????%%''..00*L**+++%G%%&&&rO   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  r  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:   rr  rX  z  Verbose:    z  -- Session --z  Started:     z%Y-%m-%d %H:%M:%Sz  Config File: )r  r  r  rq   r   r  r  rr   r   r  r  r   r   r   r  rd   r   r  r  )r+  terminal_envterminal_cwdterminal_timeoutr#  r$  r&  config_statusapi_key_displayrt  r  r  r   r   r   s                  rM   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==>>>rO   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.rB  r  )rE  exclude_sourcesr  c                 P    g | ]"}|                     d           j        k     |#S )r  )rV   ri  )rY   r  r+  s     rM   r[   z3HermesCLI._list_recent_sessions.<locals>.<listcomp>  s/    FFFaquuT{{do'E'E'E'E'ErO   )r  list_sessions_richrx   )r+  r  r  s   `  rM   _list_recent_sessionszHermesCLI._list_recent_sessions  s     	I	'::!' ;  HH
  	 	 	III	FFFF8FFFFs   + ::history)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.
        r  Fr   )_relative_timer  uV   (._.) No messages in the current chat yet — here are recent sessions you can resume:z  Recent sessions:r_  Titlez<32r  Previewz<40zLast Activez<13r	  u`   ────────────────────────────────r  u'   ─────────────uH   ────────────────────────rt  u   —Nr  r  r<   &   last_activer  zC  Use /resume <session id or title> to continue where you left off.T)r  hermes_cli.mainr  r  rV   )	r+  r  r  r  r  sessionrt  r  r  s	            rM   _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trO   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  r  messagesz

  [Tools]z    (r  z hidden)r   )r  )r  hidden_tool_messagess    rM   flush_tool_summaryz2HermesCLI.show_history.<locals>.flush_tool_summary  s`    '  4 9 999zD-   D.DDdDDDEEE#$   rO   4+--------------------------------------------------+z3|            (^_^) Conversation History           |rn  r  r  r  >   rs  r  rP   r<   rs  z	
  [You #r  r  r  z
  [Hermes #r@   r  r  z(requested r  ra  z(no text response))r  r  r  rV   rW   r  )r+  preview_limitvisible_indexr  r  rn  rP   content_textr@   r  r  ry  r  r  s                @rM   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.**&**++++rO   
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   re  Nrj  rB  rh  )rr  rf  r   ri  ru  rx   )r+  r  rv  s      rM   _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                    | j         r<| j        r5| 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         r| 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        r}	 d| j         _        | j                            | j        t4          j                            dd          | j        | j        | j        d           d| j         _        n# t          $ r Y nw xY w	 tA          | j         dd          }| |!                    | j        |pddd           n# t          $ r Y nw xY w|                     d           |stE          d           dS dS )zDStart a fresh session with a new session ID and cleared agent state.rg  r  r  Nr  r  F_last_flushed_db_idxr   _todo_store	TodoStore_invalidate_system_promptHERMES_SESSION_SOURCErB  r   r  )ri  rE  r   model_configT_memory_managerr<   parent_session_idr<  r  on_session_resetz(^_^)v New session started!)#r   r  commit_memory_sessionr   ri  r  end_sessionrx   r   r  r  r  r  r  r  r  r  reset_session_statert  r  tools.todo_toolr  r  r  r  create_sessionr  r  rV   r   r   r  ru  on_session_switchr  )r+  silentold_session_idr  r  r  _mms          rM   r  zHermesCLI.new_sessionK  sR   : 	A$3 	A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 5:DJ2$33#'?!z~~.EuMM"j.2n040E& &	 4    6:DJ22    D
dj*;TBB?))*8*>B",	 *       ))*<=== 	1/00000	1 	1sI   1B 
BB
F% %
F21F2+A+I 
I$#I$(8J! !
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        	                    |          }n# t          $ r |}Y nw xY w|r<||k    r6t          d| d| d           |}| j                            |          }	|	r|	}|| j        k    rt          d           dS | j        }
	 | 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                                         	 t5          | j        dd          }||                    ||
pddd           n# t          $ r Y nw xY w|                    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  r<   z&  Usage: /resume <session_id_or_title>rS  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
  Session rj  z/; resuming the descendant with your transcript.z  Already on that session.resumed_otherTc                 D    g | ]}|                     d           dk    |S rm  r  rp  s     rM   r[   z4HermesCLI._handle_resume_command.<locals>.<listcomp>  s,    SSS!155==N3R3RA3R3R3RrO   r  r  r  r  r
  Fr  rt  ru  r  c                 D    g | ]}|                     d           dk    |S rr  r  rp  s     rM   r[   z4HermesCLI._handle_resume_command.<locals>.<listcomp>  -    YYYqvRXAXAXAXAXAXrO   u     ↻ Resumed session r  rv  r  rr  z total)u!    — no messages, starting fresh.)r  r  rI   ro  r  r  r  r  r  r  rx   ri  r  r  r  r  r  reopen_sessionr   r  rt  r  r  r  r  r  ru  r  rV   )r+  rM  re   targetr  r  	target_idro  r  r  r  r  r  r  r  r  s                   rM   _handle_resume_commandz HermesCLI._handle_resume_command  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	$*DDYOOKK 	$ 	$ 	$#KKK	$ 	-;)33AY A A[ A A A   $I ,88CCM -,''0111F	((/JJJJ 	 	 	D	 $" #@@KKSSBSSS$,!	++I6666 	 	 	D	 : 	$-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
dj*;TBB?))!*8*>B#'	 *        9E8H8H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fsZ   -D DD< F 
F*)F*2H 
HHJ. .
J;:J;-3L! !
L.-L.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        _        t=          | j        d          r2t=          | j        d          r| j        j        d| dz  | 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        &                                 	 tO          | j        d#d          }||(                    ||pdd$d	%           n# t           $ r Y nw xY w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.Nr  r  r<   r  r  r  r  branchedr  rB  r  )ri  rE  r   r	  r  z#  Failed to create branch session: rn  rs  rP   	tool_namer  r@   tool_call_idr6   )ri  rn  rP   r$  r@   r%  r6   Tsession_log_filelogs_dirsession_.jsonr  r  r   r  r  r
  Fr  c                 D    g | ]}|                     d           dk    |S rr  r  rp  s     rM   r[   z4HermesCLI._handle_branch_command.<locals>.<listcomp>  r  rO   u     ⑂ Branched session "z" (rv  r  ra  z  Original session: z  Branch session:   ))r  ro  r  r  r  rI   r   r  r  r  r  r  get_session_titleri  get_next_title_in_lineager  rx   r  r  r  rV   r   r   r  append_messager  r  r  r  r   rt  r'  r&  r  r  r  r  r  r  ru  r  )r+  rM  re   r  r  r  r  new_session_idbranch_titlecurrent_titler  r  r|   r  r  r  r  s                    rM   _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	 ) " : #	$2DJ!'*DJ$ tz#566 74:z;Z;Z J'*J^*J*J*JJ 
+ J**,,,tz#9:: Q25d6O2P2P
/tz=11 999999-6Y[[DJ**    Dtz#>?? 7
44666
dj*;TBB?))&*;*Ar#'	 *        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8st    D9 9
EE
AF 
G$F<<GB)I88
JJ	J% %
J21J2N5 5
OO43P( (
P54P5c                    | j         st          d           dS t          j                                        d          }t                      dz  dz  }	 |                    dd           n-# t          $ r }t          d| d	|            Y d}~dS d}~ww xY w|d
| dz  }	 t          |dd          5 }t          j
        | j        | j        | j                                        | j         d|dd           ddd           n# 1 swxY w Y   t          d|            | j        rt          d| j                    dS dS # t          $ r}t          d|            Y d}~dS d}~ww xY w)a  Save the current conversation to a JSON snapshot under ~/.hermes/sessions/saved/.

        The snapshot is a convenience export for sharing or off-line inspection;
        every message is already persisted incrementally to the SQLite session
        DB, so the live session remains resumable via ``hermes --resume <id>``
        regardless of whether the user ever runs ``/save``.
        z(;_;) No conversation to save.Nr  r  savedTr  z&(x_x) Failed to create save directory r  hermes_conversation_r)  r,  rl   rm   )r   ri  r  r  r  F)indentensure_asciiz'(^_^)v Conversation snapshot saved to: z5       Resume the live session with: hermes --resume z(x_x) Failed to save: )r  r  r   r  r  r)   r  rx   ru   rv   dumpr   ri  r  	isoformat)r+  	timestamp	saved_dirr|   ry   rz   s         rM   save_conversationzHermesCLI.save_conversation  s#    ( 	2333FLNN++O<<	#%%
2W<		OOD4O8888 	 	 	K9KKKKLLLFFFFF	 B)BBBB	0dC'222 4a	!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 BDBBCCC a_do__`````a a 	0 	0 	0.1../////////	0sU   A, ,
B6BB#E 5AD9E D		E D	3E 
E+E&&E+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  rn  rs  z%(._.) No user message found to retry.rP   r<   z(^_^)b Retrying: "r   r  r  r  r  r
  r  rV   )r+  last_user_idxr  last_messages       rM   
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rO   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  rn  rs  z$(._.) No user message found to undo.rP   r<   z(^_^)b Undid z message(s). Removed: "r   r  r  r_  z! message(s) remaining in history.r=  )r+  r>  r  removed_countremoved_msgr  s         rM   r  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???@@@@@rO   r   rt  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)rD  r   r_   )rF  rD  r!  r   rt  s   rM   _pickz+HermesCLI._run_curses_picker.<locals>._pick  s"    ,,UEWWWF1IIIrO   r]  F)
r  hermes_cli.curses_uirF  current_threadmain_threadr  re  r]  r  r  )r+  rt  r!  rD  r  rH  in_main_threadr]  was_visiblerF  r   s    ```     @@rM   _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   KeyboardInterruptEOFError)rP  r   s   rM   _askz*HermesCLI._prompt_text_input.<locals>._ask  sU    !+..4466>$q			%x0   s   &+ A A r   rI  F)r  re  r]  r  r  )r+  rP  rV  r]  rN  r   s    `   @rM   _prompt_text_inputzHermesCLI._prompt_text_input
  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  )rY   r  ra   s      rM   rb   z/HermesCLI._open_model_picker.<locals>.<genexpr>%  s7      VV$!Q!%%BUBUVAVVVVVVrO   r   r   )stagerX  selectedr  rY  
user_provscustom_provsra  r.  N)_capture_modal_input_snapshotnextr  r  r  )r+  rX  r  rY  r_  r`  default_idxs          rM   _open_model_pickerzHermesCLI._open_model_picker"  s~    **,,,VV)I*>*>VVVXYZZ"#* 0$($
 $
  	c*****rO   c                 h    d | _         |                                  |                     d           d S )Nra  r.  )r  _restore_modal_input_snapshotr  r;  s    rM   _close_model_pickerzHermesCLI._close_model_picker1  s9    #' **,,,c*****rO   r  r  r^  scroll_offsetr<  	term_rowsreserved_belowpanel_chromemin_visiblec                     t          |||z
  |z
            }||k    rd|fS |}| |k     r| }n| ||z   k    r| |z
  dz   }t          dt          |||z
                      }||fS )u  Resolve (scroll_offset, visible) for the /model picker viewport.

        ``reserved_below`` matches the approval / clarify panels — input area,
        status bar, and separators below the panel. ``panel_chrome`` covers
        this panel's own borders + blanks + hint row. The remaining rows hold
        the scrollable list, with the offset slid to keep ``selected`` on screen.
        r   r  )r  r"  )	r^  rh  r<  ri  rj  rk  rl  max_visiblevisibles	            rM   _compute_model_picker_viewportz(HermesCLI._compute_model_picker_viewport6  s    " +y>'AL'PQQa4Km##$MM000$w.2MAs=!g+>>??g%%rO   persist_globalc                 R   |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        }	 ddlm}  ||j        |j        |j
        p| j
        pd|j        p| j        pd|| j        rt+          | j        dd           nd           }|rt          d|dd           n# t          $ r Y nw xY w|r||j        rt          d|j        dd           |                                r$t          d|                                            t          d|                                            t5          |j
        pdd          rd|j                                        v p
|j        dk    }	|	rt          d           |j        rt          d|j                    |rBt;          d|j                   |j        rt;          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: r   resolve_display_context_lengthr<   _config_context_lengthr   r   
model_infoconfig_context_length    Context: rC   tokens    Max output: 
    Cost:     Capabilities: rh  claudeanthropic_messages    Prompt caching: enabled       ⚠ model.defaultmodel.provider#    Saved to config.yaml (--global).       (session only — add --global to persist))r  ro  error_messager   ru  target_providerr   r  r   r  r   r  r  r   switch_modelrx   provider_label_pending_model_switch_noter  r  r  ru  
max_outputhas_cost_dataformat_costformat_capabilitiesr/   r   warning_messagerO  provider_changed)
r+  r   rq  	old_modelr  r  mir  ctxcache_enableds
             rM   _apply_model_switch_resultz$HermesCLI._apply_model_switch_resultR  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
 	NNNNNN00 &?DM?R<$,<"]a]g&qgdj:RTX&Y&Y&Ymq  C  866666777 	 	 	D	 	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 #6?#8b/JJsx[a[k[q[q[s[sOs 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)A0G 
G'&G'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 )Nr^  r   r]  r   rX  models)provider_model_idsr  r   provider_data
model_listra  r.  r  c              3   z   K   | ]5\  }}|                     d                                d           k    1|V  6dS )r  Nr  )rY   r  ra   r  s      rM   rb   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rO   )r  r<   r_  r`  		raw_inputrY  r  current_base_urlcurrent_api_key	is_globalexplicit_provideruser_providerscustom_providers)r  rV   r  rg  r  r  rx   r  rb  r  r  r  r   r   r   r   r  )r+  rq  stater^  r]  rX  r  r  r  back_idx
cancel_idxr  chosen_modelr   r  s                 @rM   _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                 ^	   ddl m}m}m} ddlm} |                    dd          }t          |          dk    r|d                                         nd} ||          \  }}	}
d}d}	 ddl	m
}m}  |            }|                    d          } ||          }n# t          $ r Y nw xY w|s|	s| j        pd	}| j        r || j                  nd	}	  || j        pd| j        pd| 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        }ddl m }  ||j        |j        |j        p| j        pd|j        p| j        pd|| j        rtC          | j        dd          nd          }|rt#          d|dd            |r||j"        rt#          d!|j"        dd            |#                                r$t#          d"|$                                            t#          d#|%                                            tM          |j        pdd$          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  r<   )get_compatible_custom_providersr  rX  r  r   )rY  r  r  r  r  
max_modelsz#  No authenticated providers found.z3  /model <name>                        switch modelz6  /model --provider <slug>             switch provider)r_  r`  r  rs  rt  rw  rx  ry  rz  r{  r|  r}  r~  r  r  r  r  rC  r  r  r  r  rh  r  r  r  r  r  r  r  r  )+r  r  r  r  hermes_cli.providersr  r  r  rI   r  r  r  rV   rx   r   r   r   ro  rd  r   r  r  ru  r  r  r  r  r  r   r  r  r  r  ru  r  r  r  r  r/   r   r  rO  r  )r+  rM  r  r  r  r  re   rU  model_inputr  rq  r_  r`  r  r  r  model_displayprovider_displayrX  r   r  r  r  r  r  r  r  s                              rM   _handle_model_switchzHermesCLI._handle_model_switch  s]    	jiiiiiiiii222222 ""4++'*5zzA~~58>>###2 :K9J89T9T6& 
	VVVVVVVV+--C--J::3??LL 	 	 	D	  	#4 	 J3)M;?=Wyy777i
88%)]%8b%)]%8b"&*"2#-%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
 JJJJJJ,,"_;;N8dl8bY]Yc"m'$*6NPT"U"U"Uim
 
 
  	42C2222333 	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 #6?#8b/JJsx[a[k[q[q[s[sOs 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<   *2B 
B*)B*&C; ;D
	D
=8I6 6
J JJ
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  r  r   )	r4  r  r  r  r   r  r  r  rx   r+  r8   r  r  r  r5  s         rM   #_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                 N   |r|st          |          sdS t          | dd          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)	u  Return True when /steer should be dispatched immediately while the agent is running.

        /steer MUST bypass the normal _pending_input → process_loop path when
        the agent is active, because process_loop is blocked inside
        self.chat() for the duration of the run.  By the time the queued
        command is pulled from _pending_input, _agent_running has already
        flipped back to False, and process_command() takes the idle
        fallback — delivering the steer as a next-turn message instead of
        injecting it mid-run.  Dispatching inline on the UI thread calls
        agent.steer() directly, which is thread-safe (uses _pending_steer_lock).
        Fr  r   r  Nr  r  r[  )
r4  ru  r  r  r  r   r  r  r  rx   r  s         rM   #_should_handle_steer_command_inlinez-HermesCLI._should_handle_steer_command_inline  s      	z 	)B4)H)H 	5t-u55 	5	;;;;;;::dA&&q)//1188==D!/$''C3G 3444 	 	 	55	s   A+B 
B$#B$c                 N    t          | dd          rt                      S | j        S )z<Use prompt_toolkit-safe Rich rendering once the TUI is live.r  N)ru  r  r  r;  s    rM   _output_consolezHermesCLI._output_console  s(    4&& 	!== |rO   c                 D     |                                  j        |i | dS )z.Print through the active command-safe console.N)r  r  )r+  r  r  s      rM   r  zHermesCLI._console_print  s,    $$d5f55555rO   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   r<   tonezTone: r  zStyle: r\   c              3      K   | ]}||V  	d S r^   r_   r`   s     rM   rb   z8HermesCLI._resolve_personality_prompt.<locals>.<genexpr>  s'      3313Q333333rO   )rT   rU   rV   r  rd   rW   )r   re   s     rM   _resolve_personality_promptz%HermesCLI._resolve_personality_prompt  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rO   c           	      *   	 ddl m}m}m} ddlm}m} n1# t          $ r$}|                     d| d           Y d}~dS d}~ww xY w	  |            }nA# |$ r9}|                     d| d           |                     d           Y d}~dS d}~ww xY w |            }	|	r|	j	        nd	pd	}
	  |||

          }n+# |$ r#}|                     d|            Y d}~dS d}~ww xY w|s|                     d           dS |
                    d            |                                  |                     d|
pd d           |                                  |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  }|                     d|dd| d|            |                                  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: rs  Nz
  [yellow]zB  Run [bold]/model[/] and pick 'Google Gemini (OAuth)' to sign in.r<   )
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    rM   rc  z2HermesCLI._handle_gquota_command.<locals>.<lambda>  s    AJ#= rO   r  z/  [bold]Gemini Code Assist quota[/]  (project: z(auto / free-tier)ra  ra  g      ?r  u   ▓r  r  3drn  rx  r  r  40sr_  )agent.google_oauthr  r  r  agent.google_code_assistr  r  ImportErrorr  r  rx  r  r"  remaining_fractionr  r	  r  r  )r+  rM  r  r  r  r  r  r  r  credsr  bucketsr  pctr  r  r.  pct_strr  s                      rM   _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 	 	 	 Nc N N NOOOFFFFF		1133LL 	 	 	 5S 5 5 5666 deeeFFFFF	
 ! ""*/7e&&R>B
	)),:NNNGG 	 	 	 G# G GHHHFFFFF	  	 pqqqF 	==>>>sjNp\psssttt 		G 		GAc3sA$899::CEsU{++,,F&.5EFN#;;CS3Y----GZF| /.q|.... Ev E E ES E EG E EFFFFsB    
A>A
A B.BB+B9 9C!>CC!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  rO  )r   r   neutralr<   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, rr  r  z1|            (^o^)/ Personalities               |r_  r   <12z - (no personality overlay)rh  r   r   r  z  Usage: /personality <name>)r  r  rI   r   r   r   rO  r  r   r  rd   r<  r!  rT   rU   rV   rW   )r+  r5  re   personality_namer  promptr  s          rM   _handle_personality_commandz%HermesCLI._handle_personality_command  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GGGGGrO   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_   )rv   rc  )r  cronjob_tools    rM   	_cron_apiz1HermesCLI._handle_cron_command.<locals>._cron_api#  s#    :ll44V44555rO   c                     g }| D ]@}t          |pd                                          }|r||vr|                    |           A|S Nr<   )rW   rI   r  )valuesr  r   r8   s       rM   _normalize_skillsz9HermesCLI._handle_cron_command.<locals>._normalize_skills&  s`    J , ,5;B''--// ,D
22%%d+++rO   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)r  deliverrepeatr>  
add_skillsremove_skillsclear_skillsrX  r  schedulepositionalsr   z--namer  r  r  z	--deliverr  z--repeatr  z!(._.) --repeat must be an integerz--skillr>  z--add-skillr  z--remove-skillr  z--clear-skillsTr  z--allrX  z--promptr  z
--scheduler  r  )r  r  r  r  r  )tokensoptsr  r  s       rM   _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"z8    /cron edit <job_id> --skill blogwatcher --skill mapsz2    /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>rc   )actionr  jobsz  Current Jobs:zA  ---------------------------------------------------------------r  r  r  job_id   r  z | r  r  z<8r>  z      Skills: rr  z      prompt_previewr<   next_run_atz      Next: z3  No scheduled jobs. Use '/cron add' to create one.r  rX  )r   include_disabledz(._.) No scheduled jobs.zScheduled Jobs:zP--------------------------------------------------------------------------------z  ID: z  Name: r  z	  State: r  z  Schedule: r  ra  z  Next run: zN/Az
  Skills: z
  Prompt: last_run_atz  Last run: last_status>   r  r  r  z*(._.) Usage: /cron add <schedule> <prompt>r  r  z3(._.) Please provide a prompt or at least one skillr  r  )r   r  r  r  r  r  r>  z(^_^)b Created job: z(x_x) Failed to create job: rM  editzN(._.) Usage: /cron edit <job_id> [--schedule ...] [--prompt ...] [--skill ...]z(._.) Job not found: r  r  skillr  c                     g | ]}|v|	S r_   r_   )rY   r
  r  s     rM   r[   z2HermesCLI._handle_cron_command.<locals>.<listcomp>  s$    aaa%eS`F`F`F`F`F`rO   r  )r   r  r  r  r  r  r  r>  jobz(^_^)b Updated job: z  Skills: nonez(x_x) Failed to update job: >   rmr  pausedeleter  rS  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: rS  z(^_^)b Resumed job: r  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  rV   rd   r   rZ  r	  rc   r  )r+  r5  r  r  r  r  r  r   r  r  
repeat_strr  r  r  r  r  r>  r  r  final_skillsreplacement_skillsr  existing_skillsr
  r   removedr  r  s                             @@rM   _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LMMM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IrO   c                     ddl }|r|                    |          dd         ng }|sdg}	 ddlm}  ||           dS # t          $ r Y dS t
          $ r}t          d|            Y d}~dS d}~ww xY w)zHandle /curator slash command.

        Delegates to hermes_cli.curator so the CLI and the `hermes curator`
        subcommand share the same handler set.
        r   Nr  r  )cli_mainz(._.) curator: )r  r  hermes_cli.curatorr  
SystemExitrx   r  )r+  r5  r  r  r  r  s         rM   _handle_curator_commandz!HermesCLI._handle_curator_command  s     	),4S!!!""%%" 	 ZF	+333333HV 	 	 	 DD 	+ 	+ 	+)C))*********	+s   ? 
A2	A2A--A2c                    ddl m} |                                }|                    d          r|                    d          }|                    d          r)|t          d          d                                         }	  ||          }n# t          $ r}d| }Y d}~nd}~ww xY w|rt          |           dS dS )u#  Handle the /kanban command — delegate to the shared kanban CLI.

        The string form passed here is the user's full ``/kanban ...``
        including the leading slash; we strip it and hand the remainder
        to ``kanban.run_slash`` which returns a single formatted string.
        r   )	run_slashr  kanbanNz(._.) kanban error: )hermes_cli.kanbanr  rI   r  r  r  rx   r  )r+  r5  r  restr  r  s         rM   _handle_kanban_commandz HermesCLI._handle_kanban_command)  s     	0/////yy{{??3 	$;;s##D??8$$ 	1H'..00D	2Yt__FF 	2 	2 	21C11FFFFFF	2 	&MMMMM	 	s   B 
B)B$$B)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_hubr$  r  )r+  r5  r$  s      rM   _handle_skills_commandz HermesCLI._handle_skills_command>  s1    ======C/////rO   c                 \   ddl m}m} t                       t          d           t          d           t          d           t                       	  |            }t          d           t          d           |j        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)SlackSLACK_BOT_TOKEN)WhatsAppWHATSAPP_ENABLEDu    → r<   u       ✓ r  z Enabledu       ○ z Not configured (ra  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.configr(  r)  r  TELEGRAMDISCORDSLACKWHATSAPPr!  	platformsrV   r   get_home_channelr  default_reset_policyrD  at_houridle_minutesr*   rx   )r+  r(  r)  rN  platform_statusrj  r  r4  pconfighomehome_strpolicyr|   s                rM   _show_gateway_statuszHermesCLI._show_gateway_statusC  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   F8H 
J+B	J&&J+c           
      +  BC |                                                                 }|                                }ddlm} |                                d                             d          } ||          }|r|j        n|}|dv rdS |dk    r|                                  nB|dk    r|                                  n&|dk    r| 	                    |           n	|d	k    r| 
                                 n|d
k    r|                                  n|dk    r5|                                  t          dt           dt                      n|dk    r|                     d           | j        rK| j        j        }|                                 |                    dd           |                                 n| j                                         | j        r|t1                      }	t3          j                    j        }
| j        s|
dk     r"|	                    t=                                 nt?          | j         d          }tC          j"        dtC          j#                              }d}tI          | d          r-| j%        r&tI          | j%        d          r| j%        j&        j'        }tQ          |	| j)        ||| j         | j*        |           t          d           	 ddl+m,}  |            }	 ddl-m.}  |            /                    dd          }n# t`          $ r d}Y nw xY w|	                    d| d| d           n# t`          $ r Y nw xY w| 1                                 t;          d           	 ddl+m,}  |            }	 ddl-m.}  |            /                    dd          }n# t`          $ r d}Y nw xY w| 2                    d| d| d           n # t`          $ r Y nw xY w|d k    r| 3                                 n|d!k    r_|                    d"#          }ti          |          d"k    r|d"                                         }|rW| j5        r>	 dd$l6m7} |8                    |          }n+# tr          $ r}t          d|            d}Y d}~nd}~ww xY w|st          d%           n"| j5        :                    | j*                  ro	 | j5        ;                    | j*        |          rt          d&|            nt          d'           n# tr          $ r}t          d|            Y d}~nd}~ww xY w| j5        <                    |          }|rt          d(| d)|d*                     n[|| _=        t          d+| d,           n?t          d-           n.t          d.           n| j5        rt          d/| j*                    | j5        :                    | j*                  }|r/|>                    d!          rt          d0|d!                     n| j=        rt          d1| j=                    nt          d2           n~t          d-           nm|d3k    r|                                  nQ|d4k    r| ?                    |           n4|d5k    r| @                    |           n|d6k    r| A                    |           n|d7k    r| B                    |           n|d8k    rB| C                                }|r*tI          | d9          r| jD        E                    |           n|d:k    r| F                                 ny|d;k    r| G                    |           n\|d<k    r| H                                 n@|d=k    r| I                    |           n#|d>k    r| J                    |           n|d?k    r| K                    |           n|d@k    rW| L                    | M                    |                    5  | N                    |           ddd           n# 1 swxY w Y   n|dAk    r| O                                 np|dBk    r| P                                 nT|dCk    r2| jQ         | _Q        | jQ        rdDndE}| 2                    dF|            n|dGk    r| R                                 n |dHk    r| S                    |           n|dIk    r| T                                 n|dJk    r| U                    |           n|dKk    r| V                    |           n|dLk    r| W                    |           np|dMk    r| X                                 nT|dNk    r| Y                    |           n7|dOk    r| Z                    |           n|dPk    r| [                                 n|dQk    r| \                                 n|dRk    r| ]                    |           n|dSk    r%ddTl^m_}  |            }t;          dU| dV           n|dWk    r| `                    |           n}|dXk    rV| L                    | M                    |                    5  | a                                 ddd           n# 1 swxY w Y   n!|dYk    r| b                    |           n|dZk    rv	 dd[lcmd}  |            }|e                                }|s/t;          d\           t;          d]t                       d^           nt;          d_ti          |           d`           |D ]} | da         rdbndc}!| dd         rde| dd          ndf}"| d         r| d          dgndf}| dh         r| dh          dindf}#| >                    dj          r| dj          dkndf}$dl ||#|$fD             }|rdmdng                    |           dondf}%| dp         rdq| dp          ndf}&t;          d|! dr| ds          |" |% |&            Ґ	n# t`          $ r}t;          dt|            Y d}~	nd}~ww xY w|duk    r| h                    |           	nj|dvk    r| i                    |           	nM|dwk    r| j                                 	n1|dxk    r| k                                 	n|dyk    r| l                    |           n|dzk    r|                    dd"          }ti          |          d"k    r|d"                                         ndf}'|'st          d{           n| jD        E                    |'           | jm        r3t          d||'dd          ti          |'          dk    rd}ndf            nFt          d~|'dd          ti          |'          dk    rd}ndf            n|dk    rS|                    dd"          }ti          |          d"k    r|d"                                         ndf}'|'st          d           n| jm        r| j%        tI          | j%        d          r	 | j%        n                    |'          }(|(r3t          d|'dd          ti          |'          dk    rd}ndf            nAt          d           n0# t`          $ r})t          d|)            Y d})~)nd})~)ww xY w| jD        E                    |'           t          d|'dd          ti          |'          dk    rd}ndf            n|dk    r| o                    |           n|dk    r| p                    |           n|dk    r| q                    |           nb|dk    r| r                    |           nE|                                d         }*| js        >                    di           }+|*                    d          |+v r3|+|*                    d                   },|,>                    d          dk    rddlt}-|,>                    ddf          }.|.r	 |-u                    |.dddd          }/|/jv                                        p|/jw                                        }0|0r#| 2                    t          |0                     n| 2                    d           n# |-jy        $ r | 2                    d           Y nt`          $ r$}| 2                    d| d           Y d}~nd}~ww xY w| 2                    d|* d           n|,>                    d          dk    r|,>                    ddf                                          }1|1rs|1z                    d          r|1nd|1 }1|ti          |*          d                                         }2|1 dr|2                                 }3| {                    |3          S | 2                    d|* d           n| 2                    d|* d           n|*                    d          t                      v rddlcm}}4m~}5  |4|*                    d                    }6|6r|ti          |*          d                                         }2	  |5 |6|2                    }/|/rt          t          |/                     n# t`          $ r$}t          d| t                      Y d}~nd}~ww xY wn|*t           v r|ti          |*          d                                         }7t          |*|7| j*                  }8|8rRt           |*         ds         }9t;          d|9            tI          | d9          r| jD        E                    |8           nJt1                                          d|* d           n#ddlm}: |                                d         Ct          |:          t          t                     z  };Cfd|;D             }<ti          |<          d"k    raCfd|<D             }=ti          |=          d"k    r|=}<n=t	          d |<D                       BBfd|<D             }>ti          |>          d"k    r|>}<ti          |<          d"k    r|<d         }?|?Ck    r@t          d| t                      t          t           t
           dt                      n|                                ti          C          d         }@|?|@z   }A| {                    |A          S ti          |<          d"k    rdt          t
           d| t                      t          t           ddng                    t          |<                     dt                      n?t          d| t                      t          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  r  )quitexitqFhelpprofiler  rR  rN  redrawr_  u   ✓ UI redrawnr  T)r  r  r  r   Nr   r1  r  uI     ✨ (◕‿◕)✨ Fresh start! Screen cleared and conversation reset.
get_random_tipr.  rC  rD  r  
   ]✦ Tip: rs  r  rt  r  rO  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 r  z  Session title queued: z! (will be saved on first message)r  z$  Usage: /title <your session title>z  Session ID: z	  Title: z  Title (pending): z2  No title set. Usage: /title <your session title>newrS  r   gquotapersonalityretryr  undor  savecroncuratorr  r>  r7  r  	statusbarro  hiddenz  Status bar r   footeryolor6   r   compressusageinsightscopyr  pasteimagereload)
reload_envz  Reloaded .env (z var(s) updated)z
reload-mcpzreload-skillsr   pluginsr9  zNo plugins installed.zDrop plugin directories into z/plugins/ to get started.z	Plugins (z):r   u   ✓u   ✗versionz vr<   z toolshooksz hooksr  z	 commandsc                     g | ]}||S r_   r_   rY   xs     rM   r[   z-HermesCLI.process_command.<locals>.<listcomp>v  s     J J Jq J J J JrO   r  rr  ra  rM      — r  r  zPlugin system error: rollbackr6  stopagents
backgroundrZ  z  Usage: /queue <prompt>  Queued for the next turn: r  z
  Queued: r[  z  Usage: /steer <prompt>u9     ⏩ Steer queued — arrives after the next tool call: z!  Steer rejected (empty payload).z  Steer failed: z)  No agent running; queued as next turn: goalr   voicebusyquick_commandsrS   execr  r  )shellr}  r8   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_handlerresolve_plugin_command_resultz[1;31mPlugin command error: task_idu   
⚡ Loading skill: z#[bold red]Failed to load skill for )COMMANDSc                 >    g | ]}|                               |S r_   r  rY   c
typed_bases     rM   r[   z-HermesCLI.process_command.<locals>.<listcomp>  s*    LLL1<<
3K3KL1LLLrO   c                      g | ]
}|k    |S r_   r_   ry  s     rM   r[   z-HermesCLI.process_command.<locals>.<listcomp>  s    CCC11
??Q???rO   c              3   4   K   | ]}t          |          V  d S r^   r  )rY   rz  s     rM   rb   z,HermesCLI.process_command.<locals>.<genexpr>  s(      %>%>c!ff%>%>%>%>%>%>rO   c                 :    g | ]}t          |          k    |S r_   r  )rY   rz  min_lens     rM   r[   z-HermesCLI.process_command.<locals>.<listcomp>  s)    #L#L#L!#a&&G:K:KA:K:K:KrO   z[1;31mUnknown command: z!Type /help for available commandszAmbiguous command: zDid you mean: r  )r   rI   r  r  r  r  r  r  r  r  r  r  r  ro  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r1  rR  r  r  r  r  rt  r   r1  r&  rT  r   ri  hermes_cli.tipsrJ  r0  r/  r1  rx   r  r  r  r  r  r  r  sanitize_titler  r  r  get_session_by_titler  rV   r!  r  r  r  r@  r  putr  r1  r;  r  r  r"  r/  r(  r&  rA  r  r  _toggle_verbose_handle_footer_command_toggle_yolo_handle_reasoning_command_handle_fast_command_manual_compress_show_usage_show_insightsrS  _handle_debug_commandr=  rZ  r  r_  _confirm_and_reload_mcp_reload_skills_handle_browser_commandrr  r:  list_pluginsr*   rd   r  r   r-  r8  _handle_background_commandr  r[  _handle_goal_command_handle_skin_command_handle_voice_command_handle_busy_commandrN  r~  r  r  r  rM  TimeoutExpiredr  process_commandr=  rs  rt  rW   r  r6  rw  r	  r"  r  r  )Dr+  r  r'  rM  _resolve_cmd
_base_word_cmd_defr  r  ccterm_wr  r   r  rJ  _tipr/  
_tip_colorre   	raw_titler  	new_titler|   r  r  	retry_msgr  r_  r  r:  r  r`  ra   r  ra  rb  r  detailrM  rG  acceptedr  base_cmdro  qcmdr~  exec_cmdr   r  r  	user_argsaliased_commandrs  rt  plugin_handleruser_instructionr  
skill_namerw  	all_knownmatchesexactshortest	full_namer  full_cmdr  r{  sD                                                                     @@rM   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*$$    (""("" ##%%%333T33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

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


/''(O
(O(Od(O(O(OPPPP    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-'',,\::::'!!))I 3WT+;<< 3#''	222&  NN(""''5555&  ""$$$$&  %%l3333)##((6666(""''5555(""##D$=$=l$K$KLL : :++L999: : : : : : : : : : : : : : :+%%%%''''(""%%''''+%%+/+C'CD$!%!9GIIxE 7 7 78888)##  """"(""''5555&  +%%**<8888&  %%l3333*$$!!,////'!!*$$----&  %%l3333'!!&&(((('!!&&(((('!!&&|4444(""444444JLLE=e===>>>>,&& ((6666/))##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'!! &&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[[\\\\'!! !&&tQ//E*-e**q..eAhnn&&&bG x23333$ x)?GDJX_D`D`)?E#z//88H   E  !O\cdgegdg\h  !Osvw~ss  CE  tE  tEjojo  KM  !O  !O  P  P  P  P CDDDD ! 6 6 64s44555555556 #''000vGCRCLv[^_f[g[gjl[l[lRWRWrtvvwwww&  %%l3333&  %%l3333'!!&&|4444&  %%l3333 !((+H![__-=rBBNs##~55%hooc&:&:;88F##v--%%%%#xx	266H oZ%/^^ (T%)2 &4 & &F &,]%8%8%:%:%Sfm>Q>Q>S>SF% Z $ 3 34H4P4P Q Q Q Q $ 3 34X Y Y Y)8 ^ ^ ^ //0\]]]]]( Z Z Z //0XRS0X0X0XYYYYYYYYZ ++,m,m,m,mnnnnXXf%%00!XXh3399;;F n+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++,l,l,l,lmmmm''  )EH  )E  )E  )E  F  F  F  F%%)F)H)HHH        "<!;HOOC<P<P!Q!Q! 	N ,S]]^^ < B B D DIN!>!>*N955" " " 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;  )M :$L M L.+M -L..M 
MMO* $N: 9O* :O	O* O		O* *
O87O8.R
 

R2R--R2(AT, ,
U6UU/aaaj<<k k .E	p9 9
q qq z: :
{!{{!ABAC CADC.	ADC7ADDADJ2AK K
AK<KAK7K7AK<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  rO  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  r<   r  z  Task ID: u?     You can continue chatting — results will appear when done.
c                  $   t          j                   t          j                   	 t	          j                   n# t          $ r Y nw xY w	 t          dGi 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        r-j                                         t7          j        d(           t;                       t=                                          d)t?                       d*d+ d,           tA          d- d.           tA          d/d d0          tC                    d0k    rd1nd% d2           t=                                          d)t?                       d*d+ d,           |r	 d3d4l"m#}  |            }|$                    d5d6          }|%                    d7d8          }|%                    d9d:          }n# t          $ r	 d6}d8}d:}Y nw xY wt=                      }	|	                    tM          tO          |j(        ;          d)| d<| d= d>d?||tR          j*        d@A                     ntA          dB           j+        r=tX          j-        .                    dC           tX          j-        /                                 nn# t          $ ra}
j        r-j                                         t7          j        d(           t;                       tA          dD dE|
            Y d }
~
nd }
~
ww xY w	 t          d            t          d            t	          d            n# t          $ r Y nw xY wj0        1                    d            j2        sd%_3        j        r4                    d3F           d S d S # 	 t          d            t          d            t	          d            n# t          $ r Y nw xY wj0        1                    d            j2        sd%_3        j        r4                    d3F           w w xY w)HNr   r   rJ  r   r   r  r  r  r  r  r   r  rz  Try  Fri  rj  rB  r  r  r   ra  r|  r}  r~  r  r  r  r  c                      d S r^   r_   )_a_kws     rM   rc  zNHermesCLI._handle_background_command.<locals>.run_background.<locals>.<lambda>a  s     rO   r8   r9   c                 l    j         s)| _        j        rj                                         d S d S d S r^   )r  r  r  r  )r8   r+  s    rM   _bg_thinkingzRHermesCLI._handle_background_command.<locals>.run_background.<locals>._bg_thinkingc  sN    . 3-1*9 3 I00222223 33 3rO   )r\  rv  final_responser<   rM  Error: g?r  r  r  rs  u     ✅ Background task #z	 completez  Prompt: "r   r  r  r   r.  r  r  rB  #CD7F32r  r  rC   bold]z (background #r  leftr  r  rt  title_alignr  r  rJ  r  z  (No response generated)r@  u     ❌ Background task #z	 failed: r.  r_   )5r\  _sudo_password_callbackr]  _approval_callbackr^  _secret_capture_callbackrx   rQ  rV   r   r  r  r  r   r  r  r  r  r  r  r  r  rW   r  run_conversationr  r  r  sleepr  r  rH  ro  r  r0  r/  r!  r1  rN  rZ  r\  rich_boxHORIZONTALSrY  rF  r  r  r  r  r   r  r  r  )bg_agentr  r   responser/  r$  r  _resp_color
_resp_text_chat_consoler|   r  r+  rv  task_num
turn_routes              rM   run_backgroundz<HermesCLI._handle_background_command.<locals>.run_background>  s5   &t'CDDD!$"9:::+D,IJJJJ   l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((***Jt$$$##$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!''7tGcdddX+XXUXX(XXX$*%0($0 &) ) )     7888 ( 'J$$T***J$$&&& J J J9 %I((***Jt$$$H(HHQHHIIIIIIIIJ.t444)$////5555    D&**7D999* ,)+D&9 5$$!$444445 5.t444)$////5555    D&**7D999* ,)+D&9 5$$!$44445s   A   
AAJ!P 3AM P MP MB6P T 
Q;AQ61T 6Q;;T ?-R- -
R:9R:V	-T76V7
UVUAVTzbg-task-)r  daemonr  )rI   r  r  ro  r  r   r  r  r  r  r  r[  rd  r  Threadr  start)	r+  r5  re   r  threadr  rv  r  r  s	   `    @@@@rM   r  z$HermesCLI._handle_background_command   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<<
s	5 s	5 s	5 s	5 s	5 s	5 s	5 s	5 s	5j !K_V]K_K_```*0w'rO   portr  c                 "    t          | |          S )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-   )r  r  s     rM   _try_launch_chrome_debugz"HermesCLI._try_launch_chrome_debug  s     'tV444rO   c                 <   ddl }|                                                    dd          }t          |          dk    r,|d                                                                         nd}t
          }t          j                            dd                                          }|	                    d          r|                                                    dd          }t          |          dk    r|d                                         n|}t          d	|v r|nd
|           }	|	j        dvr8t                       t          d|	j        pd d           t                       dS 	 |	j        p|	j        dv rdnd}
n?# t          $ r2 t                       t          d|            t                       Y dS w xY w|	j        s0t                       t          d|            t                       dS |	j        }|	j        	                    d          r|	                                }n+|	                    dddd                                          }	 ddlm}  |             n# t*          $ r Y nw xY wt                       ddl}d}	 |                    |j        |j                  }|                    d           |                    ||
f           |                                 d}n# t8          |j        f$ r Y nw xY w|rt          d|
            n||k    ryt          d           |                     |
|                                          }|rtA          d          D ]}	 |                    |j        |j                  }|                    d           |                    ||
f           |                                 d} n+# t8          |j        f$ r tC          j"        d           Y w xY w|rt          d|
            nt          d|
 d           t          d            n|t          d!           |                                }tG          |
|          }|r"t          d"           t          d#|            n%t          d$           nt          d%|
 d&|            |s-t                       t          d'           t                       dS |t          j        d<   	 dd(lm$}  |d)           n# t*          $ r Y nw xY wt                       t          d*           t          d+|            t                       tK          | d,          r| j&        '                    d-           dS dS |d.k    r|rt          j        (                    dd           	 dd/lm}m)}  |d)            |             n# t*          $ r Y nw xY wt                       t          d0           t          d1           t                       tK          | d,          r| j&        '                    d2           dS dS t                       t          d3           t                       dS |dk    rt                       |rt          d4           t          d+|            d5}
	 tU          |+                    d6d          d7                             d8          d                   }
n# t          tX          f$ r Y nw xY w	 ddl}|                    |j        |j                  }|                    d           |                    d9|
f           |                                 t          d:           n# t8          t*          f$ r t          d;           Y n_w xY w	 dd<lm-}  |            }n# t*          $ r d}Y nw xY w|&t          d=|.                                 d>           nt          d?           t                       t          d@           t          dA           t                       dS t                       t          dB           t                       t          dC           t          dD           t          dE           t                       dS )FuP   Handle /browser connect|disconnect|status — manage live Chrome CDP connection.r   Nr  r  BROWSER_CDP_URLr<   connectr  z://zhttp://>   wswsshttphttpsu'      ⚠ Unsupported browser url scheme: z	(missing)z( (expected one of: http, https, ws, wss)>   r  r  i  r  u$      ⚠ Invalid port in browser url: u$      ⚠ Missing host in browser url: z/devtools/browser/)ry   paramsr  fragment)cleanup_all_browsersFTu+      ✓ 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 Chromez     Launch Chrome manually:     z<     No Chrome/Chromium executable found in this environmentu      ⚠ Port z is not reachable at uW   Browser not connected — start Chrome with remote debugging and retry /browser connect)_ensure_cdp_supervisorr   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.]
disconnect)r  _stop_cdp_supervisoru*   🌐 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 CDPi$  r  r  r  rc  u      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)/rj  rI   r  r  r   r+   r  r  rV   r  r   r  r  r  r  hostnamery   geturl_replacetools.browser_toolr  rx   socketAF_INETSOCK_STREAM
settimeoutr  closer  r   r  r  r
  r  r  r,   r  rt  r  r  r   r  r  rsplitr  r  provider_name)r+  r5  _platre   rF   _DEFAULT_CDPr  connect_partscdp_url
parsed_cdp_port_hostr  r  _already_openr  	_launched_waitsys_name
chrome_cmdr  r  r  r   s                           rM   r  z!HermesCLI._handle_browser_command  s	       		!!$***-e**q..eAhnn$$&&&h.*..!2B77==??>>)$$ ~	IIKK--dA66M25m2D2Dq2H2HmA&,,...lG!Ug-=-=''CVWCVCVWWJ (FFF>j>O>^S^ > > >   "a:3DHX3X3XCC^`   FWFFGGG	
 & FWFFGGG'E))*>?? $++--$--	 .  
 &(( CCCCCC$$&&&&    GGG MMM!MMM&.&2DEEQ		5%.)))			 $V^,     !LKEKKLLLLL((abbb 99%PP	 ^!&r 	, 	,, &fnf>P Q QALLOOOIIuen555GGIII,0M!E '8 , , , JsOOOOO,$ nUeUUVVVV]]]]^^^lmmmm?@@@$||~~H!<UH!M!MJ! ^=>>>2j223333\]]]]JUJJJJKKK  oppp,3BJ()EEEEEE&&y1111   GGGABBB+'++,,,GGG t-.. 	#''T    	 	 L   
0$777]]]]]]]]((333((****    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   .F 8F?>F?I, ,
I98I9A"K4 4LL3A"O%O?>O?5T 
TT+W	 	
WW*A[- -\ \A3]9 9 ^^ ^1 1_ ?_ c                    	 ddl m} ddlm} n-# t          $ r }t          j        d|           Y d}~dS d}~ww xY wt          | dd          pd}|sdS t          | dd          }|t          |dd          |k    r|S 	  |            pi }|                    d	          pi }t          |                    d
d          pd          }n# t          $ r d}Y nw xY w |||          }	|	| _
        |	S )zReturn the GoalManager bound to the current session_id.

        Cached on ``self._goal_manager`` and rebound lazily when
        ``session_id`` changes (e.g. after /new or a compression-driven
        session split).
        r   )GoalManagerr  zgoal manager unavailable: %sNri  r<   _goal_managergoalsr   r  )ri  default_max_turns)hermes_cli.goalsr 	  r  r  rx   loggingr  ru  rV   r  r	  )
r+  r 	  r  r  sidr  r  	goals_cfgr   r  s
             rM   _get_goal_managerzHermesCLI._get_goal_manager  sX   	4444445555555 	 	 	M8#>>>44444	 dL$//52 	44$77GHlD$I$IS$P$PO	+--%2C((.BIIMM+r::@bAAII 	 	 	III	 kSIFFF 
s#    
949>AC CCc                 ^   |pd                                                     dd          }t          |          dk    r|d                                          nd}|                                 }|!t	          dt
           dt                      dS |                                }|r|dk    r&t	          d|                                            dS |dk    rQ|	                    d	          }| t	          dt
           d
t                      nt	          d|j
                    dS |dk    rn|                                }| t	          dt
           dt                      n6t	          d|j
                    t	          dt
           dt                      dS |dv r[|                                }|                                 |rt	          d           nt	          dt
           dt                      dS 	 |                    |          }n*# t          $ r}t	          d|            Y d}~dS d}~ww xY wt	          d|j         d|j
                    t	          dt
           dt                      	 | j                            |j
                   dS # t&          $ r Y dS w xY w)zBDispatch /goal subcommands: set / status / pause / resume / clear.r<   Nr  r_  z&Goals unavailable (no active session).r  r  zuser-pausedr  zNo goal set.u     ⏸ Goal paused: rS  zNo goal to resume.u     ▶ Goal resumed: z`Send any message (or press Enter on an empty prompt is a no-op; type 'continue' to kick it off).)r  rh  doneu     ✓ Goal cleared.zNo active goal.z  Invalid goal: u     ⊙ Goal set (z-turn budget): zAfter each turn, a judge model will check if the goal is done. Hermes keeps working until it is, you pause/clear it, or the budget is exhausted. Use /goal status, /goal pause, /goal resume, /goal clear.)rI   r  r  r	  ro  r  r  r   status_liner  rl  rS  has_goalr  r	  r  r   r  r  rx   )	r+  r5  re   rR  r  r   r  hadr  s	            rM   r  zHermesCLI._handle_goal_command  s"   !!##))$22"%e**q..eAhnnb$$&&;KKKTKKLLLF		  	ex'',**,,---FGII]I33E}5T55t556666:ej::;;;FHJJLLE};T;;T;;<<<<;uz;;<<<J J JCGJ J   F---,,..CIIKKK :-....8T88$88999F	GGCLLEE 	 	 	,s,,---FFFFF	 	O5?OO5:OOPPPZ Z ZSWZ Z	
 	
 	
	##EJ///// 	 	 	DD	s*   >H 
H;H66H;=J 
J,+J,c                    |                                  }||                                sdS 	 t          | dd          | j                                        sdS n# t
          $ r Y nw xY wd}	 | j        pg }t          |          D ]}|                    d          dk    rj|                    dd          }t          |t                    r,d |D             }d                    d	 |D                       }nt          |pd          } nn# t
          $ r d}Y nw xY w|                    |d
          }|                    d          pd}|rt          d|            |                    d          ra|                    d          }|rL	 | j                            |           dS # t
          $ r }	t!          j        d|	           Y d}	~	dS d}	~	ww xY wdS dS )u  Hook run after every CLI turn. Judges + maybe re-queues.

        Safe to call when no goal is set — returns quickly.

        Preemption is automatic: if a real user message is already in
        ``_pending_input`` we skip judging (the user's new input takes
        priority and we'll re-judge after that turn). If judge says done,
        mark it done and tell the user. If judge says continue and we're
        under budget, push the continuation prompt onto the queue.
        Nr  r<   rn  r  rP   c                     g | ]D}t          |t                    r-|                    d           dv .|                    dd          ES )rS   )r8   output_textr8   r<   )rT   rU   rV   r`   s     rM   r[   z=HermesCLI._maybe_continue_goal_after_turn.<locals>.<listcomp>  sZ     ! ! ! !)!T22! 89uuV}}H_7_7_ EE&"--7_7_7_rO   r\   c              3      K   | ]}||V  	d S r^   r_   r  s     rM   rb   z<HermesCLI._maybe_continue_goal_after_turn.<locals>.<genexpr>  s'      1H1Ha1H!1H1H1H1H1H1HrO   T)user_initiatedr  r_  should_continuecontinuation_promptz$goal continuation enqueue failed: %s)r	  	is_activeru  r  emptyrx   r  r  rV   rT   rc   rd   rW   evaluate_after_turnro  r  r	  r  )
r+  r  last_responsehistr  rP   re   decisionr  r  s
             rM   _maybe_continue_goal_after_turnz)HermesCLI._maybe_continue_goal_after_turn  sm    $$&&;cmmoo;F	t-t44@ /5577 A 	 	 	D	 	,2D~~  776??k11!ggi44G!'400 	;! !%,! ! !
 )-		1H1HU1H1H1H(H(H(+GMr(:(:E 2  	 	 	MMM	 **=*NNll9%%+ 	 JJJ<<)** 	O\\"788F OO'++F33333  O O OM"H#NNNNNNNNNO	O 	OO Os<   *A 
A('A(.BD DDF* *
G4GG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  rO  r  z
  Current skin: z  Available skins:r  u    ●r_  rE  rs  r  ra  r<   r  r  rf  rh  z
  Usage: /skin <name>z$  Custom skins: drop a YAML file in z/skins/
c                     h | ]
}|d          S )r  r_   )rY   r  s     rM   	<setcomp>z1HermesCLI._handle_skin_command.<locals>.<setcomp>D  s    5551QvY555rO   z  Unknown skin: z  Available: rr  zdisplay.skinz  Skin set to: z (saved)z8  Note: banner colors will update on next session start.z  Prompt + TUI colors updated.)r0  r	  r	  r	  r  r  rI   r  r  r*   r   rd   r  r  r<  r  rO  _apply_tui_skin_style)r+  r5  r	  r	  r	  re   r  skinsr  r  rE  new_skinr  s                rM   r  zHermesCLI._handle_skin_command,  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                    ddl m} ddlm} d}	 |pd                                                    dd          }t          |          dk    r,|d                                                                         }n# t          $ r d}Y nw xY w |            pi }|	                    d          pi 	                    d          pi }t          |	                    d	d
                    }|	                    d          pg d}	|dv r@|rdnd}
t          d|j         d|j         d|
 dd                    |	                      dS |dv rd}n"|dv rd
}n|dk    r| }nt          d           dS t          d|          r8|r|j         d|j         n|j         d|j         }
t          d|
            dS t          d           dS )u   Toggle or inspect ``display.runtime_footer.enabled`` from the CLI.

        Usage:
            /footer           → toggle
            /footer on|off    → explicit
            /footer status    → show current state
        r   r  Colorsr<   Nr  r   runtime_footerr   Ffields)r   context_pctr   )r  r  ONOFFr_  zRuntime footer:r  z
  Fields: rr  )r   r  truer   T)r   r  false0z   Usage: /footer [on|off|status]zdisplay.runtime_footer.enabledz  Runtime footer: z6  Failed to save runtime_footer setting to config.yaml)r  r  hermes_cli.colorsr'	  rI   r  r  r   rx   rV   r  ro  BOLDRESETrd   rO  GREENDIM)r+  rM  r  _ColorsrR  re   r  
footer_cfgr  r)	  r  	new_states               rM   r  z HermesCLI._handle_footer_commandU  sf    	211111777777 	!'R..0066tQ??E5zzA~~Ahnn&&,,.. 	 	 	CCC	 kmm!rwwy))/R445EFFL"
z~~i7788))L-L-L-L/!!#.DDE1W\ 1 1'- 1 1% 1 1!YYv..1 1   F///II444IIBYY#II6777F=yII 	N7@ 87=33GM3337777  00011111LMMMMMs   A)A: :B	B	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.)r   rL  rX  r   r  r  r   r   r&	  z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.r<   N)r  r  r  r  r   r   ry  rz  r  r  r0	  r'	  r4	  r2	  YELLOWr3	  r1	  ro  rV   )r+  cycler  r5	  labelss        rM   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   Nr&	  HERMES_YOLO_MODEu     ⚠ YOLO mode r,	  u.    — dangerous commands will require approval.r   u     ⚡ YOLO mode r+	  u2    — all commands auto-approved. Use with caution.)r  r0	  r'	  r0   r  rV   r   ro  r1	  REDr2	  r3	  )r+  r  r5	  r  s       rM   r  zHermesCLI._toggle_yolo  s   			777777!"*..1C"D"DEE 	JNN-t444A7< A A A A A A    
 .1BJ)*E7< E E E'- E E E    rO   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  rO  r  Nzmedium (default)r   Fznone (disabled)r~   mediumu   on ✓r   r_  zReasoning effort:  zReasoning display: z@Usage: /reasoning <none|minimal|low|medium|high|xhigh|show|hide>)showr   Tzdisplay.show_reasoningu!   ✓ Reasoning display: ON (saved)z>  Model thinking will be shown during and after each response.)hider   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  rV   r   ro  r  r  r  r   r   r  r  rO  r   )r+  r5  re   rcleveldisplay_staterR  r  s           rM   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[[[[[rO   c                    |                                                     d          }t          |          dk     s0|d                                                                          dk    rt	          dt
           d| j         t                      | j        dk    rd}n| j        d	k    rd
}nd}t	          dt           d| t                      t	          dt           dt                      dS |d                                                                          }|dvrBt	          dt           d| t                      t	          dt           dt                      dS || _        t          d|          rX|dk    rd}n|d	k    rd}nd}t	          dt
           d| dt                      t	          dt           | t                      dS t	          dt
           d| dt                      dS )u  Handle /busy — control what Enter does while Hermes is working.

        Usage:
            /busy               Show current busy input mode
            /busy status        Show current busy input mode
            /busy queue         Queue input for the next turn instead of interrupting
            /busy steer         Inject Enter mid-run via /steer (after next tool call)
            /busy interrupt     Interrupt the current run on Enter (default)
        r  rO  r  r  r_  zBusy input mode: rZ  zqueues for next turnr[  z.steers into current run (after next tool call)zinterrupts current runzEnter while busy: z+Usage: /busy [queue|steer|interrupt|status]N>   rZ  r[  r   rC	  zdisplay.busy_input_modez6Enter will queue follow-up input while Hermes is busy.zNEnter will steer your message into the current run (after the next tool call).z:Enter will interrupt the current run while Hermes is busy.u   ✓ Busy input mode set to 'r  r  )
rI   r  r  r   ro  r  r   r  r  rO  )r+  r5  re   	_behaviorrR  behaviors         rM   r  zHermesCLI._handle_busy_command  s$    		!!1!--u::>>U1X^^--3355AAOOO43GOOOPPP#w..2		%00L		4	BBBBDBBCCCPPP$PPQQQFAhnn$$&&555BBBsBDBBCCCPPP$PPQQQF"6<< 
	[g~~SkW\\\c\\VZ\\]]]//x///00000YYYcYYSWYYZZZZZrO   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  rO  r  r  r   r   r   r_  r  z!Usage: /fast [normal|fast|status]>   r   r   FAST>   r   r   NORMALrC	  zagent.service_tieru   ✓ z set to z (saved to config)z (session only))r  ro  r  rK	  ru  rx   rI   r  r  r   r   r  r  r  r   rO  )r+  r5  rK	  r   r   feature_namere   r  rR  saved_valuer  s              rM   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  r<   Fr  )ru  r  r  )r+  r  s     rM   r  zHermesCLI._on_reasoningJ  sG     	F&-d4Lb&Q&QTb&b#%%E%22222rO   r<   c           
      d   | 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          5  	 d	d
lm	} d	dl
m} t          | j                   }t          | j        dd          pd}t          | j        dd          pd}	 ||||	          }
|rt          d| d|
dd| d           nt          d| d|
dd           | j                            |d|
|pd          \  }}|| _         t          | j        dd          r-| j        j        | j        k    r| j        j        | _        d| _         || j         ||	          } ||| j         |
|          }|d         rdnd}t          d| d|d                     t          d|d                     |d         rt          d|d                     n)# t"          $ r}t          d |            Y d}~nd}~ww xY wddd           dS # 1 swxY w Y   dS )!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.r<   r  zCompressing context...r   )estimate_request_tokens_rough)summarize_manual_compression_cached_system_promptr  )r   r  u   🗜️  Compressing z messages (~rC  z tokens), focus: "z"...z tokens)...)approx_tokensfocus_topicri  noopu   🗜️u   ✅r_  r  headliner  
token_linenoteu     ❌ Compression failed: )r  r  r  r   compression_enabledrI   r  r/  agent.model_metadatarS	  !agent.manual_compression_feedbackrT	  rc   ru  _compress_contextri  r  rx   )r+  rM  rW	  re   original_countrS	  rT	  original_history_sys_prompt_toolsrV	  
compressedr  
new_tokenssummaryiconr|   s                    rM   r  zHermesCLI._manual_compressQ  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 899 A	8 A	8@8NNNNNNZZZZZZ#'(A#B#B 
 &dj2I2NNTRT Wd;;Ct = =$"- ! ! !
  l 9. 9 9mi 9 9&19 9 9 : : : : j.jjmjjjjkkk !%
 < <$"/ + 3t	 != ! !
A -7) DJd;;/
-@@&*j&;DO*.D'::-"-   

 76$-!	  %,FO>yy7477'*"5778885gl3556666? 53'&/33444 8 8 86166777777778AA	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8 A	8s=   (J%*FI/.J%/
J9JJ%JJ%%J),J)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.debugri	  typesrj	  )r+  ri	  rj	  r  s       rM   r  zHermesCLI._handle_debug_command  sR    444444))))))S%@@@rO   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                    t          |dd          pt          | dd          }t          |dd          pt          | dd          }t          |d2d          pt          | d2d          }dd3lm}m } d}|rtB          j"        #                    d45          5 }	 |$                    ||||6          %                    d78          }n## tB          j"        j&        tN          f$ r d}Y nw xY wddd           n# 1 swxY w Y   d9  ||          D             }|r"t                       |D ]}t          |           | j(        rhtS          j*                    +                    tR          j,                   d:D ]3}tS          j*        |          +                    tR          j-                   4dS tS          j*                    +                    tR          j.                   d;D ]3}tS          j*        |          +                    tR          j/                   4dS )<z8Show 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:          r  z  Cost status:              z  Cost source:              	estimatedr  r<   z  Total cost:              $z>10.4fincludedzn/az  Current context:  rC  rB  r  r  z%)z  Messages:         z  Compressions:     r  z(  Note:             Pricing unknown for r   )fetch_account_usagerender_account_usage_linesr  )max_workers)r   r   g      $@r   c                     g | ]}d | S )r_  r_   r  s     rM   r[   z)HermesCLI._show_usage.<locals>.<listcomp>  s    ^^^d^^^rO   )openaizopenai._base_clienthttpxhttpcorerg  hpackgrpcmodal)r  	run_agenttrajectory_compressorrR  
hermes_cli)0r   r  r/  get_rate_limit_statehas_dataagent.rate_limit_trackerro	  ru  r,  r-  r.  r1  r2  r&  r"  r3  r  r  r$   r   r#   r%   r   r  r  r4  r  rE  
amount_usdr  agent.account_usagerw	  rx	  
concurrentfuturesThreadPoolExecutorsubmitr   TimeoutErrorrx   r   r	  	getLoggersetLevelDEBUGWARNINGINFOERROR) r+  r   r  rl_statero	  rp	  rq	  rr	  rs	  r  r  totalr7  last_promptr  r  r0  r  cost_resultr  r  r   r   r   rw	  rx	  account_snapshot_poolaccount_linesr  noisyquiet_loggers                                    rM   r  zHermesCLI._show_usage  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 5*d33VwtZQU7V7V5*d33VwtZQU7V7V%D11SWT9d5S5SWWWWWWWW 	,#6616EE ,,',||+X!)7 (4 ( ( fTf** %$ #*7C , , ,'+$$$,, , , , , , , , , , , , , , , _^1K1KL\1]1]^^^ 	GGG%  d< 	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s6   R*-Q;:R*;RR*RR**R.1R.	/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)r  rE  z  Error generating insights: )r  r  r  r  r  r  r  agent.insightsr	  generateformat_terminalr  rx   )r+  r  re   r  rE  r  r  r	  dbenginereportr|   s               rM   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}t          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_pathrl   rm   rn  u;   🔄 MCP server config changed — reloading connections...Tr  r  r  rz	  uL     ⚠️  MCP reload timed out (30s). Some servers may not have reconnected.)r  r  r  _last_config_checkr  r	  rr   r  r  r  _config_mtimeru   r  rx   rV   _config_mcp_serversr  r  r  _reload_mcpr  rd   is_alive)r+  _yamlCONFIG_WATCH_INTERVALr  _get_config_pathcfg_pathr  rz   new_cfgnew_mcp_reload_threads              rM   _check_config_mcp_changesz#HermesCLI._check_config_mcp_changesG  sC    	 #n((+@@@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                 v   	 t                      }t          |t                    r|                    d          nd}d}t          |t                    r#t	          |                    dd                    }n# t
          $ r d}Y nw xY w|sV|                     |                     |                    5  |                                  ddd           n# 1 swxY w Y   dS t                       t          d           t                       t          d           t          d           t          d           t          d	           t                       t          d
           t          d           t          d           t                       | 
                    d          }|t          d           dS |                                                                }|dv rd}n#|dv rd}n|dv rd}nt          d| d           dS |dk    rt          d           dS |dk    r>t          dd          rt          d           t          d           nt          d           |                     |                     |                    5  |                                  ddd           dS # 1 swxY w Y   dS )uD  Interactive /reload-mcp — confirm with the user, then reload.

        Reloading MCP tools invalidates the provider prompt cache for the
        active session (tool schemas are baked into the system prompt).
        The next message re-sends full input tokens — can be expensive on
        long-context or high-reasoning models.

        Three options: Approve Once, Always Approve (persists
        ``approvals.mcp_reload_confirm: false`` so future reloads run
        without this prompt), Cancel.  Gated by
        ``approvals.mcp_reload_confirm`` — default on.
        	approvalsNTmcp_reload_confirmu9   ⚠️  /reload-mcp — Prompt cache invalidation warningzB  Reloading MCP servers rebuilds the tool set for this session andz?  invalidates the provider prompt cache.  The next message willz@  re-send full input tokens (can be expensive on long-context orz  high-reasoning models).u#     [1] Approve Once   — reload nowuG     [2] Always Approve — reload now and silence this prompt permanentlyu2     [3] Cancel         — leave MCP tools unchangedzChoice [1/2/3]: u&   🟡 /reload-mcp cancelled (no input).)r   onceapproveyesyokr	  )2alwaysrememberr	  )r  cancel	nevermindnor<  r<   r	  u   🟡 Unrecognized choice 'z'. /reload-mcp cancelled.u0   🟡 /reload-mcp cancelled. MCP tools unchanged.zapprovals.mcp_reload_confirmFu<   🔒 Future /reload-mcp calls will run without confirmation.zE   Re-enable via `approvals.mcp_reload_confirm: true` in config.yaml.u4   ⚠️  Couldn't persist opt-out — reloading once.)r@  rT   rU   rV   r  rx   r/  r(  r	  r  rW  rI   r   rO  )r+  rM  r  r	  confirm_requiredr   
choice_rawchoices           rM   r  z!HermesCLI._confirm_and_reload_mcp  so   	$!##C0:30E0EO,,,4I#)T** S#'	6JD(Q(Q#R#R  	$ 	$ 	$#	$   	##D$=$=l$K$KLL # #  """# # # # # # # # # # # # # # #F 	IJJJRSSSOPPPPQQQ)***3444WXXXBCCC%%&899;:;;;FYY[[&&((
CCCFF666FFFFFFFMsMMMNNNFXDEEEFX !?GG NTUUU]^^^^LMMM 9 9, G GHH 	 		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s6   A4A7 7BB3CCCJ..J25J2c                 t   	 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        vt          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   )rc  discover_mcp_tools_servers_lockNu   🔄 Reloading MCP servers...u     ♻️  Reconnected: rr  u     ➕ Added: u     ➖ Removed: z  No MCP servers connected.u     🔧 z tool(s) available from z
 server(s)r  Tr  c                 *    h | ]}|d          d         S )r  r  r_   )rY   r  s     rM   r!	  z(HermesCLI._reload_mcp.<locals>.<setcomp>  s/     / / /15D$V,/ / /rO   zAdded servers: zRemoved servers: zReconnected servers: z MCP tool(s) now availablezNo MCP tools availabler  r<   rs  z,[IMPORTANT: MCP servers have been reloaded. zD. The tool list for this conversation has been updated accordingly.]rn  rP   u     ✅ Agent updated — z tool(s) availableu     ❌ MCP reload failed: )rp  rc  r	  r	  r	  r	  r<  r  r  rd   r  r  r   rR  rt  r  r  valid_tool_namesr  r  _persist_sessionrx   )r+  rc  r	  r	  r	  old_servers	new_toolsconnected_serversaddedr  reconnectedchange_partstool_summarychange_detailr|   s                  rM   r	  zHermesCLI._reload_mcp  s   M	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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%,, l-  lYe  l  l  l. .    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'+I9N %%M 
N 
MN M6N 
N7N22N7c                 T   	 ddl m} | j        st          d            |            }|                    dg           }|                    dg           }|                    dd          }|s&|s$t          d           t          d| d	           d
S dt
          dt          fd}|r/t          d           |D ]}t          d ||                      |r/t          d           |D ]}t          d ||                      t          d| d	           dg}|rM|                    d           |                    d           |D ] }|                     ||                     !|rM|                    d           |                    d           |D ] }|                     ||                     !|                    d           |                    d           d                    |          | _	        d
S # t          $ r}	t          d|	            Y d
}	~	d
S d
}	~	ww xY w)u  Reload skills: rescan ~/.hermes/skills/ and queue a note for the
        next user turn.

        Skills don't need to live in the system prompt for the model to use
        them (they're invoked via ``/skill-name``, ``skills_list``, or
        ``skill_view`` at runtime), so this does NOT clear the prompt cache.
        It rescans the slash-command map, prints the diff for the user, and
        — if any skills were added or removed — queues a one-shot note that
        gets prepended to the next user message. This preserves message
        alternation (no phantom user turn injected out of band) and keeps
        prompt caching intact.
        r   )reload_skillsu   🔄 Reloading skills...r	  r  r	  z  No new skills detected.u     📚 z skill(s) availableNrB  r9   c                 x    |                      dd          }|                      dd          }|rd| d| nd| S )Nr  r<   rh  z    - r  r  )rB  nmr  s      rM   	_fmt_linez+HermesCLI._reload_skills.<locals>._fmt_line8  sO    XXfb))xxr2204G,,,d,,,-2--GrO   u     ➕ Added Skills:r_  u     ➖ Removed Skills:z[USER INITIATED SKILLS RELOAD:r<   zAdded Skills:zRemoved Skills:z,Use skills_list to see the updated catalog.]r\   u     ❌ Skills reload failed: )agent.skill_commandsr	  r  r  rV   rU   rW   r  rd   _pending_skills_reload_noterx   )
r+  r	  r   r	  r  r	  r	  rB  sectionsr|   s
             rM   r  zHermesCLI._reload_skills  s   9	6::::::( 20111"]__FJJw++EjjB//GJJw**E  1222::::;;;H H H H H H
  2+,,,! 2 2D0yy001111 2-...# 2 2D0yy0011116E666777 99H 5###000! 5 5DOOIIdOO4444 5### 1222# 5 5DOOIIdOO4444OOBOOJKKK/3yy/B/BD,,, 	6 	6 	6444555555555	6s   BH  E,H   
H'
H""H'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   ⚡)r   u     ┊ z preparing u   …N)ru  r  r  r  agent.displayr	  ro  )r+  r$  r	  r  s       rM   r  zHermesCLI._on_tool_gen_startg  s     4-u55 	,   &+D#!!###000000y%8889999999:::::rO   function_namer  function_argsc                 (   |dk    rd| _         |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	 t          | dd          s| j        dk    r|dk    rddlm}m}m}m}  |t"          |          sud| _        t          dt&            |             t(                       |t*          dz  |           dt"                              di                               di           |<   n# t          $ r Y nw xY w|                                  dS |dk    rdS |r|                    d          sddlm}  ||          }|p|}ddlm}  |            }|dk    r#t5          |          |k    r|d|dz
           dz   }| d| | _        t9          j                    | _         | j                            |g                               ||ni            |                                  | j        sdS |r|                    d          rdS 	 ddl m!} tE          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.completedra  )rX  rL  r#  is_errorFr   NrL  )get_cute_tool_messagez [error]r_  _long_tool_hint_firedrX  g      >@)TOOL_PROGRESS_FLAGis_seen	mark_seentool_progress_hint_cliTr   r   r   ztool.startedr  r	  )get_tool_preview_max_lenr  r  r  	play_beepi  gQ?r  )	frequencyr#  r  )r  r  r  )%r  r  rV   r  r   r  r  r	  r	  ro  rx   ru  agent.onboardingr	  r	  r	  r	  r  r	  r  r  rq   
setdefaultr  r	  r	  r  r  r  r  r  r  tools.voice_moder	  r  r  r  )r+  r  r	  r  r	  r  r#  r	  storedstored_argsr	  r  r	  r	  r	  r	  r	  r  r  r	  _plr	  s                         rM   r  zHermesCLI._on_tool_progress{  s<    )))$'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#D*A5IIv 3u<<$,,             'wz3EFF v9=D6#$O$O/E/E/G/G$O$O$OPPP%Il]&BDVWWWquJ11,CCNNvWYZZ[mn    DF''F 	!9!9#!>!> 	444444"N=11E,}E>>>>>>**,,CQww3u::++hsQwh%/$)!3!3E!3!3D$(N$4$4D!#..}bAAHH!.!:    	F 	 8 8 = = 	F	222222 %)taHH   eggggg 	 	 	DD	s7   ;,C( (
C54C59B4F. .
F;:F;3L 
LLr%  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  rx   rs   r  )r+  r%  r	  r	  r	  r6  s         rM   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	  r6  print_fnzEdit diff preview failed for %sTr	  )r  r   r	  r 
  ro  rx   rs   r  )r+  r%  r	  r	  r	  r6  r 
  s          rM   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         sct	                      r8|                    dd          }d	|v rt          d
          t          d          t          dt          j         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}                                 r%	 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'}
t1          j        |
d(                                           dS ))z*Start capturing audio from the microphone.r  FNr   )create_audio_recordercheck_voice_requirementsaudio_availabledetailsr<   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 sounddevicez9Voice mode requires sounddevice and numpy.
Install with: z! -m pip install sounddevice numpy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  rm  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...r  )	r  r  ro  r  r  rt  r  r  _voice_stop_and_transcriber;  s   rM   _on_silencez5HermesCLI._voice_start_recording.<locals>._on_silence2   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...r  (ra  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)NTr  333333?)r  r  rt  r  r  r  r  )still_recordingr+  s    rM   _refresh_levelz8HermesCLI._voice_start_recording.<locals>._refresh_levelS   s    !% < <&*&;O< < < < < < < < < < < < < < <& E4(( +TY +I((***
4   !s   ""r	  )ru  r	  r
  r
  r;  rV   RuntimeErrorrF  
executabler  r  r  r  rx   r  _silence_threshold_silence_duration_voice_beeps_enabledr	  r  ro  r  r  r  r  r  )r+  r
  r
  reqsr
  	voice_cfgr  r
  r	  _recording_hintr
  s   `          rM   _voice_start_recordingz HermesCLI._voice_start_recording  sB   4// 	FTTTTTTTT''))%& 	%'' ((9b11<GG&l  
 #h  
 S!$S S S   xx-)@)@AA 	>    	) 	)$ 	) 	) 	) 	) 	) 	) 	) 	) %)D!	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 		555555#))'266II 	 	 	D	 '#8#8#:#:D  3<--@SUX2Y2Y/1:?QSV1W1W.	. 	. 	. 	. 	. $$&& 	666666	Cq11111   	 &&{&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::C>C>$D- -
D:9D:-G 
GGG. .H ?HH H	H H	H c                      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                                        }                                 r%	 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.NFTr  _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)Nr  Voice auto-restart failed: r
  rt  r  r  rx   ro  r  r  )r|   r+  s    rM   _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  
transcriptr<   rM  Unknown errorr\   zTranscription failed: zVoice processing error: )"r  r  r  r  rt  r  r  r  ry   isfileunlinkrx   ru  r 
  r  ro  r  r  r  r  r  rh  r
  r	  r	  r  r  rV   r&
  rI   r  r  r  r  )r+  	submittedwav_pathr$
  r	  	stt_modelr  
stt_configr&
  r   r'
  rM  r|   s   `            rM   r
  z$HermesCLI._voice_stop_and_transcribe^   sb   
  	* 	*( 	* 	* 	* 	* 	* 	* 	* 	* %*D!%)D"		* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	U	Q#+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S +0022H ((** ::::::I155555    D 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 >G T 
GT G$T HH#&H#5J 
JJAT 9O T 
OT OD>T Z 
U#!U	Z 	UZ U,,U03U0(5W 
W+*W+_Z+_+Z//_2Z/33_'5\_
\*'_)\**A_A	_c                    | j         sdS | j                                         	 ddlm} ddlm} t          |          dk    r
|dd         n|}t          j	        dd|          }t          j	        dd	|          }t          j	        d
d|          }t          j	        dd	|          }t          j	        dd	|          }t          j	        dd	|          }t          j	        dd|t          j
                  }t          j	        dd|t          j
                  }t          j	        dd|          }t          j	        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]*?```r  z\[([^\]]+)\]\([^)]+\)rO  zhttps?://\S+r<   z\*\*(.+?)\*\*z	\*(.+?)\*z`(.+?)`z^#+\s*r=   z^\s*[-*]\s+z---+rP  rQ  hermes_voiceT)r  tts_r  z.mp3)r8   output_pathr   r  z.oggzVoice TTS playback failed: %szTTS playback failed: ) r  r  r  tools.tts_toolr0
  r	  r1
  r  rE   rF   rS  rI   r	  r  makedirsry   rd   tempfile
gettempdirr  r  r)
  getsizer*
  r  r  rx   rs   rt   ro  r  r  )r+  r8   r0
  r1
  tts_textmp3_pathogg_pathr|   s           rM   _voice_speak_responsezHermesCLI._voice_speak_response   sR    	F""$$$-	'::::::888888 '*$ii$&6&6tETE{{DHv/h??Hv6xHHHvor8<<Hv.x@@HvlE8<<Hvj%::HviXR\JJJHvnb(",OOOHvgr844Hvi::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\   D5K 5C'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  rO  r<   r   r   rj  r  zUnknown voice subcommand: z!Usage: /voice [on|off|tts|status]N)
rI   r  r  r   _enable_voice_mode_disable_voice_mode_toggle_voice_tts_show_voice_statusr  ro  )r+  r  re   r  s       rM   r  zHermesCLI._handle_voice_command   sP   %%q%1114UaU1X^^%%++---R
##%%%%%5  $$&&&&&5  ""$$$$$8####%%%%%2 *((*****'')))))===>>>788888rO   c                     	 ddl m}  |                                di           }t          |t                    r#t          |                    dd                    S n# t          $ r Y nw xY wdS )zBReturn whether CLI voice mode should play record start/stop beeps.r   r  rm  beep_enabledT)r  r  rV   rT   rU   r  rx   )r+  r  r
  s      rM   r
  zHermesCLI._voice_beeps_enabled!  s    	555555#))'266I)T** AIMM.$??@@@A 	 	 	D	ts   AA 
A,+A,c                     | 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                      nGt          dt           dt          j         dd                    |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: z -m pip install r  Tr  rm  auto_ttsFz (TTS enabled)r<   
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  ro  r  r  r	  r
  rF
  r  r  r;  r  rF  r
  rd   r  r  r  rV   r  rx   r   r  upper)r+  r
  rF
  	env_checkrt   r
  r  r  voice_config
tts_status_raw_ptt_ptt_key_ptt_displays                rM   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&' )++ P5PP$PPQQQrrrlprrsssy}  A  A  A  A}5}}3>}}SVS[S[\`as\tSuSu}w{}}~~~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"AI #H7+I 7H;;I >H;?I 
IIA4K K#"K#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^   )shutdownrx   )recs    rM   _bg_shutdownz3HermesCLI._disable_voice_mode.<locals>._bg_shutdownb!  s:    LLNNNNN    DDs    
&&Tr	  r   stop_playbackr\   zVoice mode disabled.)r  r  r  r	  r  r  r  r  r  r  r	  r_
  rx   r  r	  ro  r  r  )r+  recorderr]
  r_
  s       rM   r@
  zHermesCLI._disable_voice_modeT!  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  ro  r  r  r  r  r5
  rc
  r  )r+  r  rc
  s      rM   rA
  zHermesCLI._toggle_voice_ttst!  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: YESr	  rm  rJ
  rK
  rL
  rQ
  z  Record key: r  zRequirements:r
  r  N)r  r  r	  r
  ro  r  r  r  r  r  rV   r   r  rR
  r  )r+  r  r
  r
  _raw_key_display_keyr  s          rM   rB
  zHermesCLI._show_voice_status!  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""""	# 	#rO   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   )questionchoicesr^  response_queueTr  rz	  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  rV   rZ  r  r  r  r  r  r  Emptyro  r  r  )r+  ri
  rj
  _timer   rk
  is_open_ended_last_countdown_refreshr   r  r  s              rM   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   rk
  Tr  rz	  r\   u,     ✓ Password received (cached for session)u     ⏭ Skippedu)     ⏱ Timeout — continuing without sudor<   )r  rZ  r  ra  r  r  r  r  rV   rf  ro  r  r  rl
  )r+  rm
  r   rk
  r   r  s         rM   r  z!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_permanentrh  rr
  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   rq
  )r  rh  rj
  r^  rk
  Tr  rz	  r	  r\   u!     ⏱ Timeout — denying commanddeny)r  r  rZ  r  _approval_choicesr  r  r  r  rV   rl
  ro  r  r  )r+  r  rh  rr
  rm
  r   rk
  ro
  r   r  r  s              rM   r  z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.)r	  r  r	  rt
  )r	  r  rt
  F   view)r  r  )r+  r  rr
  rj
  s       rM   ru
  zHermesCLI._approval_choices?"  sG    ;Jk7777PkPkPkw<<"NN6"""rO   c                 H   | j         }|sdS |                    dd          }|                    d          }t          |t                    s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.Nr^  r   rj
  rx
  T	show_fullc                     g | ]
}|d k    |S )rx
  r_   )rY   r	  s     rM   r[   z8HermesCLI._handle_approval_selection.<locals>.<listcomp>V"  s"    QQQ6&@P@P@P@P@PrO   r  rk
  )r  rV   rT   rc   r  r  r  r  )r+  r  r^  rj
  chosens        rM   _handle_approval_selectionz$HermesCLI._handle_approval_selectionF"  sG   $ 	F99Z++))I&&'4(( 	G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+++#rO   c                    | j         }|sg S dBdt          dt          t                   dt          dt          dt          f
d}dCd
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 ]~\  }}|                    ||          }|d*k     rt          |d+z             }n|d*k    rd,}nd-}||	k    rd%| d.}nd&| d.} || | |d/'          D ]}|	                    ||f           t          j        d0          j        }d1}d2}d3}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|"         d4gz   }| t          |          z   t          |          z   }#|rdnd+}$||#z
  |$z
  }%t          dt          |%d5                    }%|r |||          ng }&|%d+k     s|&sg }&n4t          |&          |%k    r!t          d+|%d+z
            }"|&d|"         d6gz   }&g }'|'	                    d7d8d9|z  z   d:z   f            ||'d7d;||           |s ||'d7|           |D ]} ||'d7d<||           |s ||'d7|           |D ]\  }}||	k    rd=nd>}( ||'d7|(||           |&r#|s ||'d7|           |&D ]} ||'d7d?||           |'	                    d7d@d9|z  z   dAz   f           |'S )Da  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.
        .   rq  
title_textcontent_lines	min_widthr>  r9   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_   r  r  s     rM   r[   zWHermesCLI._get_approval_display_fragments.<locals>._panel_box_width.<locals>.<listcomp>p"  s    .S.S.STs4yy.S.S.SrO   r  r  r  r  r  r  r  r  r  r"  )r
  r
  r
  r>  	term_colslongestr-  s          rM   _panel_box_widthzCHermesCLI._get_approval_display_fragments.<locals>._panel_box_widthn"  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rO   r<   r8   r  subsequent_indentc                 Z    t          j        | t          d|          dd|          }|pdgS )Nr  F)r  replace_whitespacedrop_whitespacer
  r<   r  wrapr  r8   r  r
  wrappeds       rM   _wrap_panel_textzCHermesCLI._get_approval_display_fragments.<locals>._wrap_panel_textt"  s=    m!Umm#( %"3  G ?rd"rO   r  content_style	box_widthNc                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S Nr   r  u   │ u    │
r  r  r#  r  r  r
  r8   r
  r  s         rM   _append_panel_linezEHermesCLI._get_approval_display_fragments.<locals>._append_panel_line~"  l    aQ//KLL,/000LL-K)@)@ABBBLL,122222rO   c                 F    |                      |dd|z  z   dz   f           d S Nu   │r  u   │
r  r  r  r
  s      rM   _append_blank_panel_linezKHermesCLI._get_approval_display_fragments.<locals>._append_blank_panel_line"  -    LL,y(AG(KLMMMMMrO   r  rh  rj
  r^  r   rz
  Fu   ⚠️  Dangerous Commandrw
  r  z
Allow oncezAllow for this sessionzAdd to permanent allowlistDenyzShow full command)r	  r  r	  rt
  rx
  r      ❯ r_  r
  r  r  	   r  r/	  r  r  r  r  r  r|  r  r  u=   … (command truncated — use /logs or /debug for full text)r  u   … (description truncated)zclass:approval-borderu   ╭r     ╮
zclass:approval-titlezclass:approval-cmdzclass:approval-selectedzclass:approval-choicezclass:approval-descr"     ╯
r
  rq  r<   )r  rW   rc   r  rV   r  r  r  r  r  r  r  r  r"  ))r+  r  r
  r
  r
  r
  r  rh  rj
  r^  rz
  rt  cmd_displaychoice_labelsr  r  r	  r  r
  inner_text_widthcmd_wrappedchoice_wrappedr  
num_prefixr
  ri  chrome_fullchrome_tightrj  r  mandatory_fulluse_compact_chromechrome_rowsmax_cmd_rowsr  mandatory_no_descdesc_sep_costavailable_for_descdesc_wrappedr  r  s)                                            rM   _get_approval_display_fragmentsz)HermesCLI._get_approval_display_fragments`"  s    $ 	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1uu QZZ

a 

 
H}}.
...,j,,,++v,>u,>,>@Pdjkkk 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rO   var_namer  c                 &    t          | |||          S r^   r_  )r+  r
  r  metadatas       rM   r  z"HermesCLI._secret_capture_callback#  s     xBBBrO   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.Nr  )r8   r2  )r  ru  r  r1  r8   r2  r<  rx   )r+  r  s     rM   ra  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.Nr  r8   r<   r2  r   )
r  ru  r  r1  rV   r8   r"  r  r2  rx   )r+  r6  r  s      rM   rf  z'HermesCLI._restore_modal_input_snapshot#  s    -%)" 	wtVT:: 	F	)*C||FB//CH"%hll3Da&H&H#ch--"X"XC 	 	 	DD	s   A"B	 	
BBr   c                     | j         sd S | j         d                             |           d | _         d| _        |                                  d S )Nrk
  r   )r  r  r  r  )r+  r   s     rM   _submit_secret_responsez!HermesCLI._submit_secret_response"#  sW    ! 	F+,00777! !rO   c                 0    |                      d           d S r  )r
  r;  s    rM   _cancel_secret_capturez HermesCLI._cancel_secret_capture*#  s    $$R(((((rO   c                     t          | dd           r2	 | j        j                                         d S # t          $ r Y d S w xY wd S )Nr  )ru  r  r1  r<  rx   r;  s    rM   _clear_secret_input_bufferz$HermesCLI._clear_secret_input_buffer-#  sd    4&& 		(..00000   	 	s   3 
A Ac                 $   FGHIJ t           j                                                    sdS                                }|d          j        k    rd _         j        t          t           dt                       	                    |d         |d         |
                    d                    sdS |r	 dd	lm}m} dd
lm}  | j        pd                                 j        pd                                 |                      }n.# t&          $ r!}t)          j        d|           d}Y d}~nd}~ww xY w|dk    rY	 t-          t.                    rnd}	d |D             }
 ||	|
          \  }}|r/t          dt           dt1          |           dt                      t3          d |D                       rSd                    d |
D                       }t          dt           dt1          |           d| t                      |n-                     t-          t.                    rnd|          n# t&          $ rL}t)          j        d|                                t-          t.                    rnd|          Y d}~n5d}~ww xY w                     t-          t.                    rnd|          t-          t.                    rCdv r>	 ddlm} ddlm }  | j         j!        pd j"        pd j        rtG           j        dd          nd          } |tI          j%                    |          }|j&        s|j'        r|j(        r<t          dt           dt1          |j(                   d |j)         d!t                      |j*        D ]#}t          dt           d"| t                      $|j'        rd#                    |j*                  pd$S |j+        n,# t&          $ r}t)          j        d%|           Y d}~nd}~ww xY wt-          t.                    rdd&l,m-}  |           j.        /                    d'd(           ta                      1                    d)te                       d*d+ d,           tc          d-.           	 dH 3                                 d/ _4        d/}d/FdJd}dId} j5        ra	 dd0l6m7}m8}m9}m:}m;}  |            } ||          d1k    r |              |             d-}n"# tx          tz          f$ r Y nt&          $ r Y nw xY w|rwt}          j?                    Jt          jA                    }d2t.          fF fd3}t          jB        |J| jC        fd4|id-5          }|D                                 d6t.          fJfd7IdG jE        rt-          t.                    rd8GGH Ifd9}t          jF                     _G        d: _H        t          jB        |d-;          } | D                                 d}!| I                                rt           d<          r	  jK        
                    d=>          }!|!r= jL        s jM        rTtc          d?           ||N                                  j        O                    |!           	 t          d@z  }"t          |"dA          5 }#|#R                    t          jS        dB           dCt/          |!          ddD         dEt1           j        jT                   dF j        jU         d#           t           j        jT                  D ]&\  }$}%|#R                    dG|$ dH|%jU         d#           '	 ddd           n# 1 swxY w Y   n# t&          $ r Y nw xY wnVn@# t|          jW        $ r  X                    dIJ           Y nw xY w|                     d=           | I                                |!t          dK          D ]A}&|                     dL>           | I                                s ntG           dMd/          r nB| I                                r t                              dN| j[                   n|                     dO>            jG        5t          d:t          jF                     jG        z
             _H        d _G        	 ddPl]m^}'  |'             n# t&          $ r Y nw xY w _                                 |r/J-J`                    d           ||                    dQ>           t          jb        c                                 t          jd        dI           HrH
                    dR j.                  n j.         _.         j        rCtG           j        dSd          r- j        je         je        k    r j        je         _e        d _f        HrH
                    dTd          nd}(|(rHrH
                    dU          sH
                    dV          sw	 ddWlgmh})  j        rtG           j        dXd          nd}* |) ji         je        |( j.        |* j         j         j!         j"         jj        dYZ           n# t&          $ r Y nw xY wHrtH
                    dU          sH
                    dV          rJ|(sHH
                    d[d\          }+d]|+ }( jk        r&d/ _k        t          d#t           d^t                      d},Hr5H
                    d_          r H
                    d`          p|!},|(r|,r|(daz   }(HrH
                    dbd/          nd/}-tG           dcd/          }. jl        rJHrG|.sDH
                    dd          }/|/r,t          jn                    jo        }de}0|dfz
  t1          |0          z
  }1t           dg|0 dht          |1diz
  d          z   djt           }2t           dkdh|dfz
  z   dlt           }3|/                                p                                }4t1          |4          dmk    rFd#                    |4ddm                   }5|5d#t           dnt1          |4          dmz
   dot           z  }5n|/                                }5t          d#|2 d#t           |5 t           d#|3            |(rP|-sM	 ddplqmr}6  |6            }7|7s                    dqdr          }8|7t                    dsdt          }9|7t                    dudv          }:n# t&          $ r	 dr}8dt}9dv}:Y nw xY wHo)H
                    dU          pH
                    dV          }; ju        o	 jv        o|; }<|rEFrC|;sAt          jn                    jo        }t          d#t           dwdh|dfz
  z   dxt                      n_|<rn\ta                      }=|=1                    t          t          |( jz        y          d)|9 dz|8 d,d{|9|:t          j|        d|}                      j}        r=t          jb        R                    d~           t          jb        c                                 HrH
                    d          sH
                    d_          skH
                    dd          }>|>tG           j        dd          k    r;tG           j        dd          }?t          d#t           d|> d|? dt                       j5        r3|(r1|s/t          jB         j~        |(fd-          D                                 |,rt           d          r|,g}@ jK                                        s`	  jK                                        }A|Ar|@/                    |A           n# t|          jW        $ r Y nw xY w jK                                        `d#                    |@          }Bt1          |@          }C|BddK         t1          |B          dKk    rdndz   }D|Cdik    rtc          d|C d|D d           ntc          d|D d            j        `                    |B           HrH
                    d          nd}E|Er_t           d          rO|EddD         t1          |E          dDk    rdndz   }Dtc          d|D d            j        `                    |E           |(J'	 J                    d           n# t&          $ r Y nw xY w||N                                 |+|I                                r|                    d>           S S S # t&          $ r}tc          d]|            Y d}~J'	 J                    d           n# t&          $ r Y nw xY w||N                                 |,|I                                r|                    d>           dS dS dS d}~ww xY w# J'	 J                    d           n# t&          $ r Y nw xY w||N                                 |+|I                                r|                    d>           w w w xY w)a  
        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
        Nr`  zInitializing agent...r   rJ  ra  re  r   )build_native_content_partsdecide_image_input_moder  r<   z5image_routing decision failed, defaulting to text: %sr8   nativec                 ,    g | ]}t          |          S r_   r5  r`   s     rM   r[   z"HermesCLI.chat.<locals>.<listcomp>w#  s    %=%=%=c!ff%=%=%=rO   r_  u   ⚠ skipped z unreadable image path(s)c              3   H   K   | ]}|                     d           dk    V  dS )rS   r  Nr  r`   s     rM   rb   z!HermesCLI.chat.<locals>.<genexpr>#  s1      HHA155==K7HHHHHHrO   rr  c              3   >   K   | ]}t          |          j        V  d S r^   )r   r  r`   s     rM   rb   z!HermesCLI.chat.<locals>.<genexpr>#  s*      .T.TtAww|.T.T.T.T.T.TrO   u   📎 attaching z, image(s) natively (model supports vision): z4native image attach failed, falling back to text: %sr  )preprocess_context_references)get_model_context_lengthr  )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_surrogatesrs  r	  r  r  r  rs  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  r  r  r   r  N)	r  r  r  ro  r  r  r  r  r  )r
  r,  r  r  _streaming_box_openedr+  s       rM   display_callbackz(HermesCLI.chat.<locals>.display_callback#  s     1 `04- L. . 1us5zz1 ^W ^ ^E ^53taxQRCSCS;S ^ ^X\ ^ ^___{?HOO,=,=??@@@@@rO   r
  )r  r  r  r  deltac                 :                         |            d S d S r^   )r  )r
  
text_queues    rM   stream_callbackz'HermesCLI.chat.<locals>.stream_callback#  s)    !-"u----- .-rO   ui   [Voice input — respond concisely and conversationally, 2-3 sentences max. No code blocks or markdown.] c                  d   t          j                   t          j                   	 t	          j                   n# t          $ r Y nw xY wrz   n} t          dd           }|r|dz   | z   } d _        t          dd           }|r|dz   | z   } d _	        	 j
                            | j        d d         	j        rnd           nZ# t          $ rM}t          j        d|d            t          j
        d	d
           |          }d| g ddd|dY d }~nd }~ww xY w	 t          d            t          d            t	          d            d S # t          $ r Y d S w xY w# 	 t          d            t          d            t	          d            w # t          $ r Y w w xY wxY w)Nr  rQ  r	  r  )r\  r  r
  rv  persist_user_messagezrun_conversation raised: %sTr	  _summarize_api_errorc                 0    t          |           d d         S )Nr   r5  )r|   s    rM   rc  z3HermesCLI.chat.<locals>.run_agent.<locals>.<lambda>-$  s    UXYZU[U[\`]`\`Ua rO   r  r   F)r  r  	api_calls	completedfailedrM  )r\  r  r]  r  r^  r  rx   ru  r  r	  r   r  r  ri  r	  rM  )
agent_message_msn_srnr  _summary_voice_prefixr  r   r+  r
  s
        rM   r	  z!HermesCLI.chat.<locals>.run_agent	$  sX    +4+GHHH%d&=>>>/0MNNNN    D;H U 7 7gt%A4HH ;$(6MM$AM6:D3 t%BDII <$(6MM$AM7;D4!Z88%2-1-Fss-K(7 $8E-OWW4 9  FF ! 
 
 
M"?tTTTTbwtz3IKaKabbcfggH*>H*>*>$&%&%*"&!) FFFFFF
24888-d3333D99999$   	24888-d3333D9999$   sx   A   
AA5C E/ 
D+AD&!E/ &D++E/ /-E 
E,+E,/F/1-FF/
F,)F/+F,,F/ra  r	  r  皙?rz	  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
  r.  r   皙?r  z_Agent thread still alive after interrupt (thread %s). Daemon thread will be cleaned up on exit.r  )cleanup_stale_async_clientsr   r  ri  r  r
  partial)maybe_auto_title_emit_auxiliary_failure)r   r   r   r   r  )failure_callbackmain_runtimerM  r(
  r  z+Continuous voice mode stopped due to error.interruptedinterrupt_messagez.

---
_[Interrupted - processing new message]_response_previewedr  last_reasoningr  r  r  r  r  r  r  r  r  z  ... (r  r.  r  r  rB  r  r  r  r"  r#  rC  r  r  r  r  r@  r
  r
  r   r   u   ⚠ Iteration budget reached (r  u    ) — response may be incomplete)r  r  r  r  r  u   
⚡ Sending z messages after interrupt: 'r  u   
⚡ Sending after interrupt: 'pending_steeru/   
⏩ Delivering leftover /steer as next turn: 'r|  )r^  r  r[  rd  r  r   ro  r  r  r  rV   agent.image_routingr
  r
  r  r  r   rI   r   rx   r	  r  rT   rW   r  anyrd   rj  rt   agent.context_referencesr
  r]	  r
  r   r   ru  r  r  r  blocked
referencesinjected_tokensrG
  r  r	  r
  r  r  r  r  rH  r  r  r  r5
  r
  r
  r
  r
  r
  r  r  rZ  r  r  r  r  r  r  r  r  r  r  r	  rt  r  r  r  r	  r   rq   ru   r  r  _active_children_interrupt_requestedr  rl
  r  r
  rs   identr  rq  r
  r  r  rF  r  r  r  ri  r  agent.title_generatorr
  r  r  r  r   r  r  r  r  r0  r/  r!  r1  r  r  r  rN  rZ  r\  r  r  rY  r=
  r	  
get_nowaitr  
put_nowait)Kr+  r  r  r  r
  r
  r  	_img_mode_img_exc_text_for_parts_img_str_paths_parts_skipped
_img_namesr
  r
  _ctx_len_ctx_resultr,  r|   r
  use_streaming_tts
tts_thread
stop_event_load_tts_cfg	_get_provr
  r
  r
  _tts_cfgr
  r	  agent_threadinterrupt_msg_dbg_f_ci_ch
_wait_tickr
  r  r
  _title_failure_cberror_detailpending_messager
  _reasoning_already_shownr6   r  r  r_topr_botr  display_reasoningr/  r$  r  r  r  is_error_responsealready_streamedr  
_api_calls	_max_iter	all_partsr  combinedr<  r  _leftover_steerr
  r
  r   r
  r
  sK   ``                                                                    @@@@@rM   chatzHermesCLI.chat4#  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(nn-@AA   
 
 	
 4  1	#        :9999933](b//11Z%2,,..KMM 		
  # # #UW_```"						# H$$1;GS1I1I&QggrO%=%=f%=%=%=N'A'A'&( ($FH   aaa3x==aa[_aa   HHHHHHH %)YY.T.T^.T.T.T%T%T
K K Kc&kk K K8BKDHK K   #) #'"E"E'1'3'?'?GGGR# # !   O$Z\deee"AA#-gs#;#;CV GGGGGG ==)'377?GGR 
 gs## 	MwMRRRRRRIIIIII33J)<"dlFXVXaeak*u'$*>VX\*]*]*]quw w w <;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H	+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 
5 5 5 5 5 5 5 5 5x '+ikkD#$'D!$+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$&HHj0I0I .f .faderasastwuwtwax .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 $- % % % $%!-". !; < < < ((d(;;;;;< !%%c***I '')) $+V ( #())  J %%c%222'0022  t^U;; ((** NN# %*	   !!"!--- &2(+Ct?V1V(W(W%*.'NNNNNN++----        ! 1Z%;t$$$)OOCO000 JJt ^d  )C

:t?X(Y(Y(Yim  jCD% 
+DJd;;+ J)T_<<"&*"7&*# <BIvzz"2B777rH  F 6::h+?+? 

S\H]H] FFFFFF ).
$=t) ) ))- & %$( 1):%)Z(,(,'+|(,& &     !   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!''7tGcddd?+??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Mfjj999O 9741A#B#B 9)#2#.3;O;ORT;T;T%%Z\]SSSSTTT#''888 %))$////    D%   %**=*=*?*?%**** &%  	 	 	-A--   444 %))$////    D%   %**=*=*?*?%***** &%%%	 %))$////    D%   %**=*=*?*?%**** &%s?  AD 
E!D==EC>I 
J"AJJ".DO? 7O? ?
P(	P##P(30AE $=T" !AE "U3AE 5	U>AE  UDAE ,^4 AE ?^4 ^" B*^
^" ^^" ^^" !^4 "
^/,^4 .^//^4 2AE 4%_AE _DAE $c5 4AE 5
d?AE dD5AE 8A%j AE 
j+(AE *j++H5AE !At4 3AE 4uAE uH+AE 30~$ #AE $~63AE 5~66D'AE C AC6C6
ADDADE
AG!EAGE'AG$ E.AF F
AFFAFGAG!G!AG$ G$AIG(AG>G=AIG>
AHHAIH
AHHAAI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 rr  r  rp  s     rM   r[   z1HermesCLI._print_exit_summary.<locals>.<listcomp>%  s-    ]]]1QUU6]]V\E\E\QE\E\E\rO   c                 n    g | ]2}|                     d           dk    s|                     d          0|3S )rn  r  r@   r  rp  s     rM   r[   z1HermesCLI._print_exit_summary.<locals>.<listcomp>%  sB    uuuAaeeFmmW]F]F]abafafgsatatF]aF]F]F]rO   r  r   r  r  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  r  r   r  r  divmodr  r4  r  r+  ri  rx   r0  r.  )r+  r  	user_msgsr@   r  r  r  r  r  duration_strsession_titler.  goodbyes                rM   _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_symbolr
  r  r  )r   custom)r
  r
  r  r<   )u   ❯>ru	  r  u   ›   »u   →c              3       K   | ]}|v V  	d S r^   r_   )rY   r  r  s     rM   rb   z4HermesCLI._get_tui_prompt_symbols.<locals>.<genexpr>%  s'      552rY555555rO   )r0  r6  rx   r  r  r  r  r
  )	r+  r6  symbolr  rG  r  re   arrow_charsr  s	           @rM   _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  Nr<   i@  r  )ru  current_rmsr"  )r+  _LEVEL_BARSr\
  rmsrE	  s        rM   _audio_level_barzHermesCLI._audio_level_bar%  sN    .d-t44;2o C"d*5!!rO   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.rR  r<   r  rg	  r  c                     r7|}|r+| d|                                                                  }| |dz   fgS |r| | d| d fgS | | d fgS )Nr  )rI   r  )r  rg	  r  r8   r   state_suffixs       rM   _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6rO   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=  rM  rI  rW   r  rB  r  r  r  r  r  r  r  r,  r  r  )r+  r;  rF  r.  r   rE  s       @@rM   _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@@@())rO   c                 d    d                     d |                                 D                       S )z6Return the visible prompt text for width calculations.r<   c              3       K   | ]	\  }}|V  
d S r^   r_   r  s      rM   rb   z1HermesCLI._get_tui_prompt_text.<locals>.<genexpr>
&  s&      LL4tLLLLLLrO   )rd   rH  r;  s    rM   _get_tui_prompt_textzHermesCLI._get_tui_prompt_text&  s/    wwLL4+I+I+K+KLLLLLLrO   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)rU   ru  r0  rN  r  rx   )r+  
style_dictrN  s      rM   _build_tui_style_dictzHermesCLI._build_tui_style_dict&  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.r  NrM  Fra  r.  T)ru  PTStyle	from_dictrP  r  r  r  r;  s    rM   r"	  zHermesCLI._apply_tui_skin_style&  sl    tVT** 	'$@QSW2X2X 	5!+D,F,F,H,HII	c***trO   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    rM   _get_extra_tui_widgetsz HermesCLI._get_extra_tui_widgets &  s	     	rO   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      rM   _register_extra_tui_keybindingsz)HermesCLI._register_extra_tui_keybindings)&  s      rO   )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_   rA  s     rM   r[   z8HermesCLI._build_tui_layout_children.<locals>.<listcomp>P&  s,     
 
 
" !# " "!!rO   r   height)r   rU  )r+  sudo_widgetsecret_widgetapproval_widgetclarify_widgetrZ  r[  spacer
status_barinput_rule_top	image_barrX  input_rule_botvoice_status_barcompletions_menus                  rM   _build_tui_layout_childrenz$HermesCLI._build_tui_layout_children8&  s    0
 
a   # ,,..      !  !!
 
 
 	
rO   c                 D-   klmnopqrstuv 	 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                     d| d| d           	 ddlm}m}m}m}	m}
  | j        |          s |            rz	 |                    dd          }n# t          $ r d}Y nw xY w                     d| d |
             d           	 ddlm}  |	 |            |           n# t          $ r Y nw xY wn# t          $ r Y nw xY w	 ddlm}  |            }	 |                    dd          }n# t          $ r d}Y nw xY w                     d| d| d           n# t          $ r Y nw xY w	 ddlm}  |t7          d           fd           n# t          $ r Y nw xY w j        rO j        sHd                     j                  }                     dt?                       d|            d _                                          d _         tC          j"                     _#        tC          j"                     _$        d _%        d _&        ddl'm(}   |            _)        ddlm}  |            }|*                                r|+                                j,        nd  _-         j        .                    d!          pi  _/        d  _0        d" _1        d _2        d _3        d" _4        d _5        d" _6        d" _7        d _8        ts          j:                     _;        d _<        d _=        d" _>        d _?        g  _@        d _A        ts          j:                     _B        d _C        d _D        d" _E        d _F        d _G        d _H        ts          jI                     _J         jJ        K                                 t           jM                   t           jO                   t           jQ                   	 dd#lRmS}  |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                      }|X                    d)           fd*            }|X                    d+d)          d,             }|X                    d-          d.             }t           fd/          }|X                    d0|1          |X                    d+d2|1          ufd3                        }|X                    d4d5          d6             }|X                    d7t           fd8          1           fd9            } |X                    d:t           fd;          1           fd<            }! fd=}"t          d>          D ]U}#|#dk    rd?n|#dz
  }$ |X                    t          |#          t           fd@          1           |"|$                     V|X                    d7t           fdA          1           fdB            }%|X                    d:t           fdC          1           fdD            }&|X                    d7t           fdE          1           fdF            }'|X                    d:t           fdG          1           fdH            }(|X                    d+t           fdI          dJ           fdK            }) fdL}*t          d>          D ]U}#|#dk    rd?n|#dz
  }$ |X                    t          |#          t           fdM          1           |*|$                     Vt           fdN          }+|X                    d7|+1          dO             },|X                    d:|+1          dP             }-|X                    dQ           fdR            }.|X                    dS          u fdT            }/|X                    dU           fdV            }0t           fdW          }1|X                    d+|1dJ           fdX            }2|X                    dY          dZ             }3	 dd[lm\}4  |4            .                    d\i           .                    d]d^          }5|5]                                ^                    d_d`          ^                    dadb          }6n# t          $ r dc}6Y nw xY w|X                    |6          ufdd            }7ddel_m`}8 |X                    |8ja        d5          op fdf            }9|X                    dg           fdh            }:|X                    d+di           fdj            }; uufdk}<ddllbmc}= t          dm uje        n          }>t          t          ddodp          |<dqddt          ufdr          t          t           ji                            |>dt           |=            |>s          t
  
        vduvjk        _l        v fdv}?|?vjm        _n        dgodgrdgqdgpd _o        opqr fdw}@vjk        xjp        |@z  c_p        vjq        jr        s                    t          t                      t          ufdx          1                      G dy dzt                    }Aufd{}Bvjq        jr        s                     |A|B                     ufd|}Cufd}}Dufd~}Eufd}Ft          t          |E          |Fd          }Gt          t          |C          |D          }Hddt          dt          t                   dt          dt          dt          f
dnddt          dt          dt          dt          t                   fdsdt          dt          dt          dt          dd"f
dldt          dt          dd"fdkklnsufd}It          t          t          |I          d          t          ufd          1          }Jklnufd}Kt          t          t          |K          d          t          ufd          1          }Lklnufd}Mt          t          t          |M          d          t          ufd          1          }Nufd}Ot          t          t          |O          d          t          ufd          1          }Pklnsufd}Qt          t          t          |Q          d          t          ufd          1          }Rt          dufdd          }St          dufdd          }T uufd}Ut          t          |U          t          ufd                    }Vufd}Wt          t          t          |W          d          t          ufd          1          }Xt          t          t          ufd          dd          t          ufd          1          }Y |                    |v           t          dd          }Zt          t                               |L|N|P|J|R|G|H|Y|S|Vv|T|X|Z                              }[i 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 _        t          j                                                   }\t          d|[||\dddt          
dt          ini tt _        tj        mmtfd}]|]t_         fd}^ts          j        |^d          }_|_                                 t fd}`ts          j        |`d          }a|a                                 t          j        t                      fd}b	 dd"l}c|c                    |cj        |b           t!          |cd          r|c                    |cj        |b           n# t          $ r Y nw xY wd }d	 t%          j        d           nD# t(          $ r6 t          d           t                                                         Y d"S w xY w	 t-                      5  	 dd"l}e|e                                }f|f                    |d           n# t          $ r Y nw xY wt                                 d"d"d"           n# 1 swxY w Y   n# t6          t8          t:          f$ r Y nt<          t(          f$ rz}gt?          |gt(                    r"tA          |gdd"          tB          j        k    rn7dt          |g          v sdt          |g          v rt          d|g d           n Y d"}g~gnd"}g~gww xY wd _%         j        r=tA           dd          r+	  j                                         n# t          $ r Y nw xY wt!           d          r9 jE        r2	  jE                                         n# t          $ r Y nw xY wd" _E        	 ddlm}h  |h             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          t8          f$ r&}itV                              d|i           Y d"}i~ind"}i~iww xY w j        rwtA           dd          re	 dd l'm}j  |jd j        j        ddtA           j        dd"          tA           j        dd"          pd           n# t          $ r Y nw xY wt                                                         d"S # d _%         j        r=tA           dd          r+	  j                                         n# t          $ r Y nw xY wt!           d          r9 jE        r2	  jE                                         n# t          $ r Y nw xY wd" _E        	 ddlm}h  |h             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          t8          f$ r&}itV                              d|i           Y d"}i~ind"}i~iww xY w j        rwtA           dd          re	 dd l'm}j  |jd j        j        ddtA           j        dd"          tA           j        dd"          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  r<   T)endr  r   r.  welcomezAWelcome to Hermes Agent! Type your message or /help for commands.r  r  r  r  rs  )OPENCLAW_RESIDUE_FLAGdetect_openclaw_residuer	  r	  openclaw_residue_hint_clirC  rD  r	  rI  r  rK  )maybe_run_curatorinfc                 6                         d|  d          S )Nu   [dim #6b7684]💾 rs  )r  )r  r+  s    rM   rc  zHermesCLI.run.<locals>.<lambda>&  s%    t':':1111( ( rO   )idle_for_seconds
on_summaryrr  r  z]Activated skills:[/] Fr9  ra  rn  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        rM                                 | j        j                                         | 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|r                    ||          rc                    |          s,d_        | j        j        r| j                                         | j        j                            d           dS                     ||          r7                    |           | j        j                            d           dS t5          j                  }j                                         | j                                         |r||fn|}j        r|rt;          |          sj        }|d	k    r|s|sd
}nd}		 j        <tA          j        d	          r't%          j        !                    |                    }	n;# tD          $ r.}
tG          dtH           d|
 dtJ                      d}	Y d}
~
nd}
~
ww xY w|	rE|dd         t#          |          dk    rdndz   }tG          dtL           d| dtJ                      nd
}|d
k    r{j'                            |           |r|n*dt#          |           dt#          |          dk    rdnd d}tG          d|dd          t#          |          dk    rdnd            n|dk    rj(                            |           	 tR          dz  }tU          |d          5 }|+                    tY          j-        d           dt]          |          dd         dj         d            ddd           n# 1 swxY w Y   n# tD          $ r Y nw xY w	 d!d"l/m0}m1}m2}m3}  |th          |          sttG          dtH            |j                   tJ                       |tR          d#z  |           dth          5                    d$i           5                    d%i           |<   n*# tD          $ 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.
            rk
  NFr^  rj
  T)r  )append_to_historyr[  rZ  r_  zSteer failed (u   ) — queued for next turn.r  r  r<   u   ⏩ Steered: 'r  r   imager  r  z
 attached]rk  r   r
  r  r
  z ENTER: queued interrupt msg=r   z, agent_running=r\   r   )BUSY_INPUT_FLAGbusy_input_hint_clir	  r	  r   r   r   )6r  rl  r1  r8   r  r  r  r
  r<  r  r}
  r  r  r  r  rI   rV   r  r  r  r  r  r  rj  rD  r  rc   r  r  r4  r   r   rt  r[  rx   ro  r  r  r  r  r  rq   ru   r  r  r  rW   r	  r~  r  r	  r	  r  r	  )eventr8   r  r^  rj
  r  r  rG  _effective_moder  r  r  r  r  r~  r  r	  r	  r+  s                     rM   handle_enterz#HermesCLI.run.<locals>.handle_enter'  s0     y/4 !1266t<<<#' 	$$&&& ! y/4,,T222	(..000	$$&&& # //111	$$&&& ' 33555	(..000	$$&&& % $*= 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 VGz VG ;;DZ;XX //55 -,0) 9/ -!INN,,,I,22T2JJJF ;;DZ;XX ((...I,22T2JJJF d344%++---	$$&&&,2<4..& 95 959RSW9X9X 95&*&:O&'11 " : :.5OO',H1#':#9gdjRY>Z>Z#9/3DJ4D4DT4J4J/K/KH#, 1 1 1 '(gT(g(g(g(gae(g(g h h h+01  ( :*.ss)D		BuuTV*W '(TW(T(TG(T(Td(T(T U U U U29&'11+//888*."v$$4vF4v4vRUV\R]R]abRbRb33hj4v4v4v qwss| qVYZaVbVbegVgVgUUmo q qrrrr(K77-11':::!#/2G#GD!%dC SB "DM*,E,E *R *Rdghodpdpqtrtqtdu *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!             'wz?CC s#$`$`/B/B4CW/X/X$`Z^$`$`aaa%Il]&BOTTTnrJ11,CCNNvWYZZ[jk$    '++G444	(...FFFFFmVG VGsc   AQ 
R"$RR>W; AW/#W; /W33W; 6W37W; ;
XXBZ 
Z+*Z+rL  c                 :    | j                             d           dS )z1Alt+Enter inserts a newline for multi-line input.r\   Nr1  insert_textr  s    rM   handle_alt_enterz'HermesCLI.run.<locals>.handle_alt_enter'  !      ,,T22222rO   zc-jc                 :    | j                             d           dS )zKCtrl+Enter (c-j) inserts a newline. Most terminals send c-j for Ctrl+Enter.r\   Nr  r  s    rM   handle_ctrl_enterz(HermesCLI.run.<locals>.handle_ctrl_enter'  r  rO   c                  D     j          o j         o j         o j         S r^   )r  r  r  r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>'  s0    ++|D4H0H|QUQaMa|jnj|f| rO   zc-g)filterr  c                 <                         | j                   dS )zQCtrl+G (or Alt+G in VSCode/Cursor) opens the current draft in an external editor.N)r:  r1  )r  cli_refs    rM   handle_open_in_editorz,HermesCLI.run.<locals>.handle_open_in_editor'  s"     ))%*>?????rO   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   )	r1  complete_statecurrent_completiongo_to_completionapply_completion
suggestionr8   r  start_completion)r  r  r  s      rM   
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 $$&&&&&rO   r6  c                  <    t           j                  o j         S r^   r  r  r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>'  s    tD4G/H/H/gQUQgMg rO   c                     j         rAt          dj         d         dz
            j         d<   | j                                         dS dS )z%Move selection up in clarify choices.r   r^  r  N)r  r  rl  r  r  r+  s    rM   
clarify_upz!HermesCLI.run.<locals>.clarify_up'  sY     " '25a9LZ9X[\9\2]2]#J/	$$&&&&&' 'rO   downc                  <    t           j                  o j         S r^   r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>'  s    d6I1J1J1iSWSiOi rO   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.rj
  r^  r  N)r  rV   r  r"  rl  r  )r  rj
  max_idxr+  s      rM   clarify_downz#HermesCLI.run.<locals>.clarify_down'  s     " '-11)<<Bg,,25gt?RS]?^ab?b2c2c#J/	$$&&&&&	' 'rO   c                       fd}|S )Nc                    j         rj        sj                             d          pg }t          |          k     rOj         d                             |                    d _         d_        | j                                         d S t          |          k    r&d_        | j                                         d S d S d S d S )Nrj
  rk
  FT)r  r  rV   r  r  rl  r  )r  rj
  r  r+  s     rM   handlerzDHermesCLI.run.<locals>._make_clarify_number_handler.<locals>.handler'  s    & /t/E /"155i@@FBGS\\))+,<=AA'#,OOO.2+16.	,,.....G,,15.	,,...../ / / / -,rO   r_   r  r  r+  s   ` rM   _make_clarify_number_handlerz3HermesCLI.run.<locals>._make_clarify_number_handler'  s)    / / / / / / NrO   r  r
  c                  <    t           j                  o j         S r^   r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>(  s    tD<O7P7P7oY]YoUo rO   c                  ,    t           j                  S r^   r  r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>(  s    tD4H/I/I rO   c                     j         rAt          dj         d         dz
            j         d<   | j                                         d S d S Nr   r^  r  )r  r  rl  r  r  s    rM   approval_upz"HermesCLI.run.<locals>.approval_up(  sW    # '36q$:Nz:Z]^:^3_3_$Z0	$$&&&&&' 'rO   c                  ,    t           j                  S r^   r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>(  s    d6J1K1K rO   c                     j         r^t          j         d                   dz
  }t          |j         d         dz             j         d<   | j                                         d S d S )Nrj
  r  r^  )r  r  r"  rl  r  )r  r  r+  s     rM   approval_downz$HermesCLI.run.<locals>.approval_down(  sr    # 'd29=>>B36w@TU_@`cd@d3e3e$Z0	$$&&&&&' 'rO   c                  ,    t           j                  S r^   r  r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>#(  s    tD4L/M/M rO   c                     j         rOt          dj                             dd          dz
            j         d<   | j                                         d S d S r  )r  r  rV   rl  r  r  s    rM   model_picker_upz&HermesCLI.run.<locals>.model_picker_up#(  sd    ' '7:1d>V>Z>Z[egh>i>ilm>m7n7n(4	$$&&&&&' 'rO   c                  ,    t           j                  S r^   r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>)(  s    d6N1O1O rO   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 )Nr]  r   rX  r  r  r^  r   )r  rV   r  r"  rl  r  )r  r  r  r+  s      rM   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  """""rO   c                  ,    t           j                  S r^   r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>5(  s    48P3Q3Q rO   )r  r  c                                                       | j        j                                         | j                                         dS )zESC closes the /model picker.N)rg  rl  r1  r<  r  r  s    rM   model_picker_escapez*HermesCLI.run.<locals>.model_picker_escape5(  sH     $$&&&I$**,,,I  """""rO   c                       fd}|S )Nc                     j         rWt          j         d                   k     r;j         d<                                    | j                                         d S d S d S )Nrj
  r^  )r  r  r}
  rl  r  )r  r  r+  s    rM   r  zEHermesCLI.run.<locals>._make_approval_number_handler.<locals>.handler>(  sq    ' +C#d6J96U2V2V,V,V7:D(433555I((*****+ +,V,VrO   r_   r  s   ` rM   _make_approval_number_handlerz4HermesCLI.run.<locals>._make_approval_number_handler=(  s)    + + + + + +
 NrO   c                  ,    t           j                  S r^   r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>H(  s    tD<P7Q7Q rO   c                  T     j          o j         o j         o j         o j         S r^   )r  r  r  r  r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>O(  sT    ++  ^D4H0H  ^QUQaMa  ^jnj|f|  ^  FJ  F^  B^ rO   c                 P    | j         j                            | j                   dS )zAUp arrow: browse history when on first line, else move cursor up.r  N)rl  r1  auto_uprR  r  s    rM   
history_upz!HermesCLI.run.<locals>.history_upR(  s(     I$,,59,=====rO   c                 P    | j         j                            | j                   dS )zDDown arrow: browse history when on last line, else move cursor down.r  N)rl  r1  	auto_downrR  r  s    rM   history_downz#HermesCLI.run.<locals>.history_downW(  s(     I$..UY.?????rO   zc-lc                 0                                      dS )uZ  Ctrl+L: force a clean full-screen repaint.

            Recovers the UI after external terminal buffer drift — tmux /
            cmux tab switches, ``clear`` from a subshell, SSH window
            restores, etc. — that prompt_toolkit can't detect on its own.
            Matches the universal bash/zsh/fish/vim/htop convention.
            N)r  r  s    rM   handle_ctrl_lz$HermesCLI.run.<locals>.handle_ctrl_l\(  s     ##%%%%%rO   zc-cc                    t          j                     }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)
            FNTr\   zRecording cancelled.r	  rk
  r<   rt
  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  r  ro  r  r  r  r  r	  r  rl  r  r  r  r  r
  r1  r<  r  r  rg  r  r  r  r   r  r  r  rD  r   r8   r  r  )r  r  _should_cancel_voice_recorder_refr  r+  s       rM   handle_ctrl_cz$HermesCLI.run.<locals>.handle_ctrl_cg(  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                     | j         j        }|j        r|                                 dS j        rdS d_        | j                                          dS )u  Ctrl+D: delete char under cursor (standard readline behaviour).
            Only exit when the input is empty — same as bash/zsh. Pending
            attached images count as input and block the EOF-exit so the
            user doesn't lose them silently.
            NT)rl  r1  r8   r  r  r  rD  )r  r  r+  s     rM   handle_ctrl_dz$HermesCLI.run.<locals>.handle_ctrl_d(  sZ     )*Cx !

& !$(!	     rO   c                  :    t           j        p j                  S r^   )r  r  r  r;  s   rM   rc  zHermesCLI.run.<locals>.<lambda>(  s    D+?t/?@@ rO   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.Nrk
  r<   )r  r
  rl  r1  r<  r  r  r  r  s    rM   handle_escape_modalz*HermesCLI.run.<locals>.handle_escape_modal(  s     ! ++---	(..000	$$&&&  !1266r:::#' 	$$&&&	 rO   zc-zc                 .   t           j        dk    r:t          dt           dt                      | j                                         dS 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).win32r\   z-Suspend (Ctrl+Z) is not supported on Windows.Nr   rI  r.  r  r  z' has been suspended. Run `fg` to bring z back.c                      t          j        d                                           t          j        d j                   d S )Nr  r   )r  r  rD  killSIGTSTP)_sigr  s   rM   _suspendz6HermesCLI.run.<locals>.handle_ctrl_z.<locals>._suspend(  s7    CJJLL)))4<(((((rO   )rF  rj  ro  r  r  rl  r  signalre  r]  r0  r/  r!  )r  r]  r/  r  r  r  r  s        @@rM   handle_ctrl_zz$HermesCLI.run.<locals>.handle_ctrl_z(  s     |w&&VTVVPTVVWWW	$$&&&!!!!BBBBBB>>>>>>(**77nUUJ\z\\*\\\C) ) ) ) ) ) OH%%%%%rO   r  rm  rJ
  rK
  rL
  rM
  rN
  rO
  rP
  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)Nr  r\   zVoice recording failed: r#
  )r|   r  s    rM   _start_recordingzDHermesCLI.run.<locals>.handle_voice_record.<locals>._start_recording1)  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  r  rl  r  r  r  r
  r  r  r  r  r  r  r  is_setr	  r_
  r	  rx   )r  r_
  r  r  s      rM   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                    t          j                    }t          | j        pd          }| j        pd}|                    dd                              dd          }t          |          }t          |          \  }}|r                    d           t          |          r-	                                r| j
                                         |rNd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              n|                    |           t          j                    |z
  dz  }|dk    rDt6                              d|||r|                    d          dz   ndt:          j                   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.
            r<   r  r\   z1mouse reports leaked into bracketed paste payloadr  r   r
  r|  r  r  pastesTr  paste_r  r  .txtrl   rm   r  r      lines → r  g     @@g     @@zSlow bracketed-paste handler: %.1fms to process %d bytes (%d lines) on %s. If the input becomes unresponsive after this, attach this log line to the bug report.N)r  perf_counterr  r{   r  r  r  rL  r  r  rl  r  r	  r
  r  r1  r8   rI   r  rq   r  r   r  r  
write_textr2  r  rs   rt   rF  rj  )r  _paste_handler_start_paste_raw_sizer  _had_mouse_reportsr
  
line_countr  	paste_dir
paste_fileplaceholderr  _paste_handler_elapsed_ms_paste_counter_paste_just_collapsedr+  s                rM   handle_pastez#HermesCLI.run.<locals>.handle_paste=)  s   " $(#4#6#6 !%*"233O**K &--fd;;CCD$OOK@MMK.XYd.e.e+K+! o22:m2nnn;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OOK000)-):)<)<?S)SW](]%(500D .#3>EK%%d++a//AL     10rO   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  rl  r  r  s    rM   handle_ctrl_vz$HermesCLI.run.<locals>.handle_ctrl_vz)  s=     //11 '	$$&&&&&' 'rO   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  r  s    rM   handle_alt_vz#HermesCLI.run.<locals>.handle_alt_v)  s:     //11 	$$&&&&& rO   c                  ,                                      S r^   )rH  r  s   rM   
get_promptz!HermesCLI.run.<locals>.get_prompt)  s    44666rO   )AutoSuggestFromHistoryc                      t           S r^   )r  r_   rO   rM   rc  zHermesCLI.run.<locals>.<lambda>)  s    O rO   )skill_commands_providercommand_filterr  )r"  r  	preferredzclass:input-areac                  ,    t           j                  S r^   )r  r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>)  s    W-E(F(F rO   )history_suggest	completer)
r_  r  r  	multiline
wrap_lines	read_onlyr  r  complete_while_typingauto_suggestz.mdc                     	 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   rF  r:  r  r  r  r  r  r  )re  rG  r<  r;  r6  documentr  rK  r  rH  r  rx   r  r  r  r"  )
rG  r;  docprompt_widthavailable_widthvisual_linesr  
line_widthrX  r+  s
           rM   _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                 .   t          | j                  }t          |          \  }}|r                    d           || j        k    rat	          | j        t          |                    }dd<   || _        || _        t          |          d<   |                    d          d<   dS t          |          d         z
  }t          |          d<   d         sj        r&d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.
            z'mouse reports leaked into prompt bufferr  Tr   r\   NFr  r  r|  r  r  r  r  r  r  r  rl   rm   r  r  r  r  )r  r8   r  rL  r"  r2  r  r  r4  r  rq   r  r   r  r  r  )r  r8   r  cursorchars_addedr  newlines_addedis_paster  r  r  r  _prev_newline_count_prev_text_lenr+  s             rM   _on_text_changedz'HermesCLI.run.<locals>._on_text_changed)  sd    :#(CCD'QRV'W'W$D$! e22:c2dddsxS0#d))<<+/%a(&,#$'IIq!)-D)9)9#A&d))nQ&77K #D		N1$Q' 4+D +0%a(,1))-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### rO   c                  T    t           j                  pt           j                  S r^   )r  r  r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>*  s"    D!455Tg>S9T9T rO   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     rM   r,  z5HermesCLI.run.<locals>._PlaceholderProcessor.__init__!*  s    !)rO   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  r8   linenor  r   r"  )r+  tir8   s      rM   apply_transformationzAHermesCLI.run.<locals>._PlaceholderProcessor.apply_transformation$*  sg    {' fBINN>>++D f-I\^bHcGd8deeee%====rO   N)r>  r?  r@  rA  r,  r%  r_   rO   rM   _PlaceholderProcessorr  *  s8        QQ* * *> > > > >rO   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 skipr<   z%type your answer here and press Enterr&  r  u9   msg=interrupt · /queue · /bg · /steer · Ctrl+C cancelztype or Ctrl+B to record)r  r  r  r  r  r  r  r  r,  r  r  r  )framer  r  s     rM   _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**&***% SRR" 2112rO   c                     j         r@t          dt          j        t	          j                    z
                      } ddd|  dfgS j        r@t          dt          j        t	          j                    z
                      } ddd|  dfgS j        r@t          dt          j	        t	          j                    z
                      } ddd|  dfgS j
        rXt          dt          j        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-countdownr`  zs))r+  u      secret hidden · Enter to skip)r+  u%     ↑/↓ to select, Enter to confirmr<   )r+  z"  type your answer and press Enterr+  r_  u2    command in progress · input temporarily disabled)r  r  r  r  r  r  r  r  r  r  r  r  r  r  r,  )r  	countdownr(  r  s      rM   get_hint_textz$HermesCLI.run.<locals>.get_hint_textJ*  s   " 3w'=@P@P'P#Q#QRR	H.0Ci0C0C0CD 
 $ 3w'?$.BRBR'R#S#STT	F.0Ci0C0C0CD 
 & 3w'ADNDTDT'T#U#UVV	K.0Ci0C0C0CD 
 % 3w'@4>CSCS'S#T#TUU	3:3LT/)////RT	, L2I> 
 L.	: 
 ' 6688!#a#a#a#ab  IrO   c                  v     j         s j        s j        s j        s j        rdS                                  S )Nr  )r  r  r  r  r  rU  r  s   rM   get_hint_heightz&HermesCLI.run.<locals>.get_hint_heightu*  sU    " g&; w?V ZaZp t{  uM q //111rO   c                  >                                     } | sg S d| fgS )Nr+  )rW  )rZ  r  s    rM   get_spinner_textz'HermesCLI.run.<locals>.get_spinner_text|*  s/    "7799L 	!<011rO   c                  ,                                      S r^   )r\  r  s   rM   get_spinner_heightz)HermesCLI.run.<locals>.get_spinner_height*  s    11333rO   )rP   r_  r  )rP   r_  r
  rq  rt  r
  r
  r>  r9   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.r
  c                 ,    g | ]}t          |          S r_   r  r  s     rM   r[   z;HermesCLI.run.<locals>._panel_box_width.<locals>.<listcomp>*  s    )N)N)N#d)))N)N)NrO   r  r  r  r  r
  )rt  r
  r
  r>  r
  r
  r-  s          rM   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rO   r8   r  r
  c                 Z    t          j        | t          d|          dd|          }|pdgS )Nr  F)r  break_long_wordsbreak_on_hyphensr
  r<   r
  r
  s       rM   r
  z'HermesCLI.run.<locals>._wrap_panel_text*  s=    m!Umm!&!&"3  G ?rd"rO   r  r
  r
  c                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S r
  r
  r
  s         rM   r
  z)HermesCLI.run.<locals>._append_panel_line*  r
  rO   c                 F    |                      |dd|z  z   dz   f           d S r
  r
  r
  s      rM   r
  z/HermesCLI.run.<locals>._append_blank_panel_line*  r
  rO   c                  	   %j         } | sg S | d         }|                     d          pg }|                     dd          } $|d          }t          |          D ]h\  }}|dk     rt          |dz             }n|dk    rd}nd	}||k    r%j        sd
| d}nd| d}|                     $| | dd                     it          |          dz   }	|	dk     rt          |	          }
n|	dk    rd}
nd	}
%j        rd
|
 dn|t          |          k    rd
|
 dnd|
 d}|                     $|dd                      #d|          }t          d|dz
            }g }|rt          |          D ]o\  }}|dk     rt          |dz             }n|dk    rd}nd	}||k    r%j        sd
| d}nd| d} $| | |d          D ]}|                    ||f           pt          |          }|dz   }	|	dk     rt          |	          }
n|	dk    rd}
nd	}
||k    r%j        sd
|
 d}n%j        rd
|
 d}nd|
 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|           |r|D ]%\  }}||k    r	%j        sd$nd#} "|d|||           &t          |          }|dz   }	|	dk     rt          |	          }
n|	dk    rd}
nd	}
||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.
            ri
  rj
  r^  r   r   r
  r  r/	  r  r
  r  r_  r  r
  r  z. Other (type below)z. Other (type your answer)Hermes needs your inputr  r  z7Type your answer in the prompt below, then press Enter.r
  r|  r  r  Nu   … (question truncated)class:clarify-border   ╭─ )class:clarify-titler<  r>  r  r  r
  zclass:clarify-questionclass:clarify-choicerG  zclass:clarify-active-otherr"  r
  )r  rV   r  rW   r  r  r  r  r  r  r  r  r"  )&r  ri
  rj
  r^  r  r  r	  r
  r  	other_numother_num_prefixother_labelr
  r
  r
  r
  	other_idxother_label_mandother_wrappedri  r
  r
  rj  r  r
  r
  r
  max_question_rowsquestion_wrappedr  r  r  other_styler
  r
  r
  r
  r  s&                                    rM   _get_clarify_displayz+HermesCLI.run.<locals>._get_clarify_display*  so    *E 	Z(Hii	**0bGyyQ//H,,Xr::M&w// j j	6q55!$QUJJ!VV!$JJ!$J==)B=2J222FF0*000F$$%5%56I6I6I2ag%h%h%hiiiiGq(I2~~#&y>>  b#&  #& AHAZ G='====LTX[\cXdXdLdLdH,HHHHF*FFF 
   !1!1+rU[!\!\!\]]](()BMRRI"1i!m44 57N &#!*7!3!3 < <IAv1uu%(QZZ

a%(

%(
H}}W-F}!6
!6!6!6!4j!4!4!4#3#3v4Gv4G4GIYms#t#t#t < <&--q'l;;;;<  LL	%M	r>>'*9~~$$"__'*$$'*$y((1J('Z.>'Z'Z'Z$$. Y'T.>'T'T'T$$'X,<'X'X'X$ 0 01ACSgm n n n* # 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	%M	r>>'*9~~$$"__'*$$'*$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LrO   )r  c                       j         d uS r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>W+  s    W%;4%G rO   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-titlerO  r  r  r   r  r
  class:sudo-textr"  r
  )r  r  r  r  )	r  rt  bodyr
  r  r
  r
  r
  r  s	        rM   _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LrO   c                       j         d uS r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>r+  s    W%8%D rO   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
  rF  z2Enter secret below (hidden), ESC or Ctrl+C to skipr  rN  rP  rO  r  r  r   r  r
  rQ  r"  r
  )r  rV   insertrW   r  r  r  )r  rt  r  r
  	help_textrR  r
  r
  r  r
  r
  r
  r  s            rM   _get_secret_displayz*HermesCLI.run.<locals>._get_secret_displayu+  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LrO   c                       j         d uS r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>+  s    W%:$%F rO   c                  ,                                      S r^   )r
  r  s   rM   _get_approval_displayz,HermesCLI.run.<locals>._get_approval_display+  s    ::<<<rO   c                       j         d uS r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>+  s    W%<D%H rO   c                  >   j         } | sg S |                     dd          }|dk    rd}g }|                     d          }t          |t                    r|n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
            }|                     d$d%          }	 d%d&lm}  |            j	        
                                j        }n)# t          $ r t          j        d'          j        }Y nw xY wt                               ||                     d(d%          t	          |          |          \  }}|| d(<   g }|                    d)           |                    d*|f           |                    d+d,d-t          d%|t	          |          z
  d.z
            z  z   d/z   f            |d+|            |d+d0||            |d+|           t%          |||z             D ]A}||         }||k    rd1nd2}||k    rd3nd4} ||z   |d45          D ]} |d+|||           B |d+|           |                    d+d6d-|z  z   d7z   f           |S )8Nr]  r   u$   ⚙ Model Picker — Select ProviderrX  total_modelsr  r  r  z modelr  r  r<   ra  r\  u     ← currentCancelz	Current: r  r  z on rY  r  r  u   ⚙ Model Picker — r  Provideru   ← BackzSelect a model (z available)z7No models listed for this provider. Use Back or Cancel.r
  T   )r
  r>  r  r  r^  r   rF  r
  _scroll_offsetr=  r@  r>  r  r  r  r
  zclass:clarify-hintrG  rA  r
  r_  r
  r"  r
  )r  rV   rT   rc   r  r  r  re  rG  r  rH  rowsrx   r  r  r  rQ  rp  r
  )r  r]  rt  rj
  
_providersra   r  r  rV  r  r  r
  r
  r^  rG  ri  rh  ro  r  r  r	  r  r  r
  r
  r
  r
  r
  r  s                           rM   _get_model_picker_displayz0HermesCLI.run.<locals>._get_model_picker_display+  su   /E 	IIgz22E
"">"YY{33
'1*d'C'CK * *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yyQ//HF>>>>>>#GII,5577<		 F F F"4Y??E			F%.%M%M%))$4a88#g,,	& &"M7 '4E"#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]MG,CDD a a 478OO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Ls   ',H #H:9H:c                       j         d uS r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>+  s    W%@%L rO   r  c                  .                          d          S )NrP  rS  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>+  s    799%@@ rO   zclass:input-rule)charr_  r  c                  .                          d          S )NrQ  ri  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>+  s    799(CC rO   c                  \    j         sg S t          j         j                  } dd|  dfgS )Nzclass:image-badger  )r  r  r  )badgesr  s    rM   _get_image_barz%HermesCLI.run.<locals>._get_image_bar+  sF    + 	4(& F )-f---899rO   c                  ,    t           j                  S r^   )r  r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>	,  s    T'*B%C%C rO   c                  ,                                      S r^   )rl  r  s   rM   _get_voice_statusz(HermesCLI.run.<locals>._get_voice_status,  s    66888rO   r^  c                       j         S r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>,  s
    W%8 rO   c                  ,                                      S r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>,  s    W5V5V5X5X rO   c                       j         S r^   )r  r  s   rM   rc  zHermesCLI.run.<locals>.<lambda>&,  s
    W%@ rO   )rX  r  )
max_heightrh  )r`  ra  rb  rc  rZ  r[  rd  re  rf  rg  rX  rh  ri  rj  z
input-arear  z#555555 italicr  zprompt-workingz#888888 italicrV  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_supportr  c                  ,   j         } 	 | j        }|                                 |                                 |                    dd           |                                 |                     d           n# t          $ r Y nw xY w              d S )Nr   Fr  )r  r  r  r  r  r  r<  rx   )r  r  _original_on_resizerl  s     rM   _resize_clear_ghostsz+HermesCLI.run.<locals>._resize_clear_ghosts,  s    |Ho $$&&&  """1%%%		 e<<<<   !!!!!s   A/A: :
BBc                       j         sk j        st          j        d           # j        r+                     d           t          j        d           nt          j        d            j         id S d S )Nr
  r.  r
  )r  r  r  r  r  r  r;  s   rM   spinner_loopz#HermesCLI.run.<locals>.spinner_loop,  s    ' $y JsOOO( 	$$$#$666JsOOOO JsOOO ' $ $ $ $ $rO   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$                    r9t'          |           } t)          |           \  } }|r                    d	
           t!          | t$                    rt-          |           nd }|ry|d         }|d         }	|d         r:|                    |           |	p
d|j         d} t3          d|j                    n't3          d|j                    d| d|	rd|	 ndz   } |sot!          | t$                    rZt5          |           rKt3          d|                                 |           s"d_         j        r                                 t=          j        d          }
t!          | t$                    r"tA          |
!                    |                     ng }|r"                    |           } tG                       $                    |            |r<tK          |          }t3          dtL           d| d|dk    rdnd dtN                      d_        (                                 	 )                    | |pd            d_        d_*        d_+        j,        -                                 d_.        (                                 	 /                                 n,# t          $ r}ta          j1        d |           Y d }~nd }~ww xY wj2        r<j3        r5j4        s.fd!}tk          j6        |d"          7                                 	 ddlm} |j	        
                                s|j	                                        }|                    dd          }|                    d          dk    r|                    |          rwt          |          }|rj                            |           |j	        
                                n# t          $ r Y nw xY w# d_        d_*        d_+        j,        -                                 d_.        (                                 	 /                                 n,# t          $ r}ta          j1        d |           Y d }~nd }~ww xY wj2        r<j3        r5j4        s.fd!}tk          j6        |d"          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n2# t          $ r%}tp          9                    d#|           Y d }~nd }~ww xY wj         d S d S )$Nr
  rz	  r   r"  ri  r<   rS   r  z)mouse reports leaked into submitted inputr  ry   r  r  r  r  u     📎 Auto-attached image: u     📄 Detected file: z[User attached file: r\   u	   
⚙️  Tr  r_  u   📎 r}  r  r  z	 attachedr  Fra  z!goal continuation hook failed: %sc                  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   rz	  g333333?r"
  )r  r  waitr  r  r
  r  rx   ro  r  r  )r|   rl  r+  s    rM   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	  z2process_loop unhandled error (msg may be lost): %s):r  r  rV   rZ  rl
  r  r	  r(  r#  completion_queuer	  r  is_completion_consumedr  r  rx   rT   rD  rW   r  r  rL  r  r  r  ro  r4  r  rj  rD  rE   r  rc   finditerr  r  r  r  r  r  r  r*  r  r  r  r  r  r	  r	  r  r  r  r  r  r  r  rs   rt   )r  r#  r  _evt_sid_synthsubmit_imagesr  
_file_drop
_drop_pathrX  _paste_ref_re
paste_refsr<  	_goal_excr$
  r|   rl  r+  s                   rM   process_loopz#HermesCLI.run.<locals>.process_loop,  s   ' K\J\!%)%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22 s%KJ%W%W
9cdn9o9o6
$6- s >>Fq>rrr 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-"~ + #


  %'J/^$_$_MMWXbdgMhMh!pm&<&<Z&H&H!I!I!InpJ! O%)%B%B:%N%N
GGG44Z@@@ % `.. ^T ^ ^ ^ ^A2 ^ ^X\ ^ ^___ +/D'NN$$$4!		*]5Jd	KKK.3+-/*03-/55777572(((Z @@BBBB( Z Z Z#M*MyYYYYYYYYZ  + 
]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!a /4+-/*03-/55777572(((Z @@BBBB( Z Z Z#M*MyYYYYYYYYZ  + 
]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! ! \ \ \NN#WYZ[[[[[[[[\U ' K\ K\ K\ K\ K\s  ( [ *DB(C<;D<
D	DD		D[ D[ E:[ C [ 4T0 A	[ O, +[ ,
P6P[ PA[ CT [ 
T-)[ ,T--[ 0A
[;V[
V9V4/[4V99A[ C[[
[[[[[ 
\!\\c                    t                               d|            	 t          dd          rt          dd          rtj                            d|             	 t          t          j        dd                    }n# t          t          f$ r d	}Y nw xY w|d
k    rt          j        |           n# t          $ r Y nw xY wt                      )u  Handle SIGHUP/SIGTERM by triggering graceful cleanup.

            Calls ``self.agent.interrupt()`` first so the agent daemon
            thread's poll loop sees the per-thread interrupt and kills the
            tool's subprocess group via ``_kill_process`` (os.killpg).
            Without this, the main thread dies from KeyboardInterrupt and
            the daemon thread is killed with it — before it can run one
            more poll iteration to clean up the subprocess, which was
            spawned with ``os.setsid`` and therefore survives as an orphan
            with PPID=1.

            Grace window (``HERMES_SIGTERM_GRACE``, default 1.5 s) gives
            the daemon time to: detect the interrupt (next 200 ms poll) →
            call _kill_process (SIGTERM + 1 s wait + SIGKILL if needed) →
            return from _wait_for_process.  ``time.sleep`` releases the
            GIL so the daemon actually runs during the window.
            z0Received signal %s, triggering graceful shutdownr   Nr  Freceived signal HERMES_SIGTERM_GRACE1.5      ?r   )rs   r  ru  r   r   r  r  r  r  r  r  r  rx   rT  )signumr(  _gracer+  s      rM   _signal_handlerz&HermesCLI.run.<locals>._signal_handlerT-  s    $ LLKVTTT
4$// +GDBRTY4Z4Z +J(()DF)D)DEEE%!&ry1G'O'O!P!P%z2 % % %!$%zz
6***   #%%%s5   ?B5 "B  B5 BB5 BB5 5
CCSIGHUPc                 f   |                     d          }t          |t                    rdt          |          v rd S t          |t                    rdt          |          v rd S t          |t
                    r!t          |dd           t          j        k    rd S | 	                    |           d S )N	exceptionzEvent loop is closedis not registerederrno)
rV   rT   r
  rW   KeyErrorr  ru  r  EIOdefault_exception_handler)rf  contextr  s      rM   _suppress_closed_loop_errorsz3HermesCLI.run.<locals>._suppress_closed_loop_errors-  s    ++k**C#|,, 1G3s881S1S#x(( -@CHH-L-L#w'' GC$,G,G59,T,T**733333rO   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 setupr  r  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_recordingsr  	cli_closez!Could not close session in DB: %sre  on_session_endr   rj  rB  )ri  r
  r
  r   rj  r
  r
  r_   )r  r  r  r  rx   r  r  r  r  r0  r/  r!  r1  r  r	  ro  rp  r	  r	  rq  rN  r  r	  r  rJ  agent.curatorrr  r  r  r  rd   rH  r  rZ  r  r  r  r  r  rr  r:  _cli_refrr   r  r  r	  rV   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  r^  r  tools.tirith_securityrw  ro  r  r  r   r  r   r
  rW   r  r   r  prompt_toolkit.keysr  BracketedPasteprompt_toolkit.auto_suggestr  rU  r  r   r   r   r  rV  r6  tempfile_suffixwindowr_  r4  on_text_changedcontrolinput_processorsr  r   r   r   r   r   rc   r  r   rY  r   r   r   rk  rM  rR  rS  rP  r   _STEADY_CURSORr  
_on_resizer  r  atexitregisterrx  r  SIGTERMrt  r  r  fstatr  r4  r   rg  ri  set_exception_handlerr  rU  rT  BrokenPipeErrorr  rT   ru  r  r  r   r   r[
  r	  r  r  r  ri  rs   r  rf  )wr+  _term_linesr/  _welcome_skin_welcome_text_welcome_colorro  rp  r	  r	  rq  _resid_color_get_cfg_path_residrJ  r  r  rr  skills_labelr:  r	  	_cfg_pathrw  tirith_pathsecurity_cfgry  rW  r  r  r  _editor_filterr  r  r  r  r  _num_idxr  r  r  r  r  r  _normal_inputr  r  r  r  r  _modal_prompt_activer  r  r  rf
  
_voice_keyr  r  r  r  r  r  r  
_completerr  r  r&  r)  r-  r/  r1  r3  r[  rd  rK  rc  rS  r`  rY  ra  r\  rb  rf  rZ  rf  rh  rn  rg  rq  ri  re  rj  rv  r  r|  r~  spinner_threadr  process_threadr  _signalr  _aio_loop
_stdin_errr  r|   rv  r
  r
  r{  r
  r  r  r  r  r
  rl  r  rX  sw   `                                                                                                          @@@@@@@@@@@@rM   r  zHermesCLI.rune&  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	' 	CCCCCCDDD	              74;(=>> 
CZCZC\C\ 
-#0#:#:<#S#SLL  - - -#,LLL-##$W$W$W7P7P7R7R$W$W$WXXXXXXXXXI11335JKKKK    D 	 	 	D			666666!>##D'*44\9MM

 ' ' '&


' G
 G Gd G G GHHHH 	 	 	D			777777!&u         	 	 	D	  	3)H 	399T%:;;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	 ]]	]	G ]	G ]	G ]	G 
]	G~ 
'	"	"	3 	3 
#	"	3 
	3 	3 
	3 #||||
 
 
n	-	-	#n	5	5	@ 	@ 	@ 	@ 
6	5 
.	-	@ 
T	"	"	' 	' 
#	"	'D 
Y'g'g'g'ghh	i	i	' 	' 	' 	' 
j	i	' 
y)i)i)i)ijj	k	k	' 	' 	' 	' 
l	k	'	 	 	 	 	" "II 	V 	VD		11taxDqBFF3t99Y/o/o/o/o%p%pFqq  sO  sO  PT  sU  sU  V  V  V  V 
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		# 
+Q+Q+Q+Q!R!RZ^	_	_	# 	# 	# 	# 
`	_	#	 	 	 	 	 "II 	y 	yD		11taxDSBFF3t99Y/Q/Q/Q/Q%R%RFSSTqTqrvTwTwxxxx " ^  ^  ^  ^
 
 
]	+	+	> 	> 
,	+	> 
}	-	-	@ 	@ 
.	-	@ 
	& 	& 	& 	& 
	& 
X	% X	% X	% X	% X	% 
X	%t 
	! 	! 	! 	! 
	!   )@@@@ 
  
 
!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	0:	x 
	' 	' 	' 	' 
	' 
#			 	 	 	 
		" 	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$  
 
 

& -2
)	 	 	 	 	 	4 $1
   c!&$)!.	4 .	4 .	4 .	4 .	4 .	4 .	4 .	4 .	4` 	))-==))
 	+22 !## TTTT   	
 	
 	
	> 	> 	> 	> 	>I 	> 	> 	>	 	 	 	 	2 	+223H3HIY3Z3Z[[[
)	 )	 )	 )	 )	V	2 	2 	2 	2 	2	2 	2 	2 	2 	2	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d	 d	 d	 d	 d	 d	 d	 d	 d	L .$%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
 
 
<	 <	 <	 <	 <	 <	 <	 <	 <	| 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L	\ L	\ L	\ L	\ L	\ L	\^ #)dKKK 	%%%	& 	& 	& 	& 	&@	$$$$NN7?O<<<w)) @w~??? 	 	 	D			4 		4 		4
	HQKKKK 	 	 	[  
 NNN$$&&&FF	M	'  **** //11E//0LMMMM    D			               +_= 	 	 	D'" 	 	 	 *g.. 	7:wPT3U3UY^Yb3b3b$J77;PTWXbTcTc;c;c_Z _ _ _    	 !%D
 z gd,<eDD J((****    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$$&&&&&g !%D
 z gd,<eDD J((****    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$$&&&&sH  6A 
AA<C C('C()F, 2E	 F, 	EF, E'F,  F F, 
F(%F, 'F((F, ,
F98F9=H G% $H %G41H 3G44H 
H! H!%#I	 	
II3A(T 
T)(T)A4f8 8ggB.AAC: C:
ADDADDAD$ D$=AE%E$AE%E)AG$ E8AGE:-AF(F'AGF(
AF5F2AGF4AF5F5AGGAG$ GAGGAG$ GAGG AG$ G#AR G$AJG>AR H AJHA0AJJAR JAJJAR J0AK
 K

AKKAKK3AL L
ALLALL%AL6 L6
AMMAMN%AN9 N9AO1OAO,O,AO1PAAQ" Q"
AQ/Q.AQ/R!AZR9ASSAZS
AS SAZSAS S AZS<ATTAZT
AT#T AZT"AT#T#
AZT.AT?T>AZT?
AUU	AZUAUUAAZV%AWWAZWAW:WAW5W0AZW5AW:W:AZXAAY+Y*AZY+
AY8Y5AZY7AY8Y8'AZ)NNNNNNFFNFFF)r  r=  )r  )F)r  r^   )r   )NN)r  r  r  r
  )r	  )NNN)r>  r?  r@  rA  rW   r   r  r  r,  r  r  r  r   r  r  staticmethodr  r	   r
   r8  r=  classmethodrD  rD  rI  rM  rS  rU  r\  rW  rl  r{  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r(  r,  r   r/  r:  r[  rU   rd  r  r  r  r  r  r  rc   r  r   r-  r8  r=  rI  rL  rS  rZ  rj  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r!  r1  r;  r@  r  rO  rW  rd  rg  rp  r  r  r  r  r  r  r  r  r  r  r  r  r"  r&  rA  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?
  r@
  rA
  rB
  r  r  r  ru
  r}
  r
  r  ra  rf  r
  r
  r
  r*  r4  r=  rB  rH  rK  rP  r"	  rU  rY  rk  r  r_   rO   rM   rQ  rQ    s          "! %"A* A*A* s)A* 	A*
 A* A* A* A* A* A* A* A* A* A* A* A*F
# # # # # # #" " " "H	'hsm 	' 	' 	' 	' 	'J Jx} JS JRU J J J J
 #% #%(5/ #%TY #%ae #%ru #% #% #% \#%J;$sCx. ; ; ; ;z # # # # # \# 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    c     ` `# ` ` ` `$ U  UHSM  US  U  U  U  UDEP EP EPNes et e e e eN       !7c !7d !7 !7 !7 !7F 9> /5 /5 /5 /5$ /5 /5 /5 /5b( ( ( ( ( (@3S4Z 3C 3 3 3 3&Zc Zd Z Z Z Z"%C "%D "% "% "% "%H1 1 1 1$J J J JX3Zc 3Zd 3Z 3Z 3Z 3Zj? ? ? ?0$ $ $ $'C 'C ' ' ' '*2 2 2 2 2
 /C / / / ^/ D    BLT L L L L\*s *t * * * *X 48RVy} b b bS b4 bkorvkv b  CG b b b bHQ Q QfK$ K K K KZ\# \# \#|T    &\. \. \. \. \.|3 T cDj    UU UU UU UU UUn6 6 6&F F F(H H H23 4    "s t    >$5 $5 $5 $5 $5 $5Ld# d d d d0 [_ @= @= @=3 @= @=SW @=cf @= @= @= @=D  ,&
 &
 &
P3M 3M 3Mj/ / / / /     
%G %G %GN( ( (TMQ MQ MQ MQ MQ^  >  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     J1 J1 J1 J1Xng3 ng4 ng ng ng ng`C93 C94 C9 C9 C9 C9J!0 !0 !0F  :A A A@  DI c Z]`dZd    <c cDj    0+ +D + +X[ +  EI + + + ++ + + +
   & &&& & 	&
 & & & 
sCx& & & \&6OF OF$ OF OF OF OFb=' ='T ='d =' =' =' ='~eF eF eF eF eFN
 
 
 
Z^ 
 
 
 
   Z^    0  6 6 6 	c 	 	 	 \	,3 ,4 , , , ,\+s + + + +ZsJ sJ sJ sJ sJj+3 + + + +,#    *0# 0 0 0 0
7 7 7rbs bt b b b bHUc U U U Un 5s 5C 5D 5 5 5 \5H3 H H H HZ  B@ @ @ @ @ @D8O 8O 8O 8Ot'4 '4 '4 '4 '4R2N3 2N4 2N 2N 2N 2Nh9 9 98  &;\S ;\ ;\ ;\ ;\z([ ([ ([ ([ ([T)Z )Z )Z )Z )ZV3C 3 3 3 3]8 ]8S ]8 ]8 ]8 ]8~  lH lH lH\7 7c 7 7 7 7B6b 6b 6b 6bpE EC E E E E ENS3 S3 S3jF6 F6 F6 F6X;C ;D ; ; ; ;(` `C ` `UX `pt ` ` ` `D	^3 	^s 	^SW 	^ 	^ 	^ 	^Zc Z# ZVZ Zmp Z Z Z Z(`E `E `EDbQ bQ bQH2'# 2' 2' 2' 2'h9S 9 9 9 9.	d 	 	 	 	:D :D :Dx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[       4b b bHC C Cc CUY C C C C. . . .   S T    ) ) ) )   N	+ N	+D N	+HSM N	+ N	+ N	+ N	+`) ) )V%sCx % % % %N
"# 
" 
" 
" 
"$* $* $*LMc M M M MtCH~    t           , !+
 +
 +
" 
#+
 +
 +
 +
ZF' F' F' F' F'rO   rQ  rE  r]  rR  r   r   r   r   r   r   quietr   
list_toolslist_toolsetsgatewayrS  r  r,  r  rT  r%  rU  c                 V  - 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                     -fd}%	 ddl)}&|&)                    |&j*        |%           tW          |&d          r|&)                    |&j,        |%           n# tZ          $ r Y nw xY w| s|rmt]          | |          \  } }'|rd-_/        -0                                r| }(|'r-1                    | |'d           }(-2                    |(          })|)d!         -j3        k    rd-_4        -5                    |)d"         |)d#         |)                    d$          %          r;d&-j4        _6        d&-j4        _7        d-j4        _8        d-j4        _9        -j4        :                    |(-j;        '          }*ty          -j4        d(d          r&-j4        j        -j        k    r-j4        j        -_        t!          |*tz                    r|*                    d)d          nt#          |*          }+|+rt          |+           t          d*-j         tJ          j>        +           tK          j&        t!          |*tz                    r|*                    d,          rd-nd           tK          j&        d-           nh-#                                 | p|'rd.nd},|,r-j?                            d/|,            -@                    | |'pd0           -A                                 dS -                                 dS )1a  
    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  Fry   r   c                 6    g | ]}|                                 S r_   r   r  s     rM   r[   zmain.<locals>.<listcomp>Z.  s     DDD1QWWYYDDDrO   rC  c                 6    g | ]}|                                 S r_   r   rd  s     rM   r[   zmain.<locals>.<listcomp>`.  s     )J)J)J!'')))J)J)JrO   r  rB  )r   rR  r   r   r   r   r   r   rS  r  rT  rU  ru  rr  zUnknown skill(s): rQ  c              3      K   | ]}||V  	d S r^   r_   rX   s     rM   rb   zmain.<locals>.<genexpr>.  s;       , ,t,, , , , , ,rO   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.]r<   c                 ~   t                               d|            	 t          dd           }|o|                    d|             	 t	          t          j        dd                    }n# t          t          f$ r d}Y nw xY w|dk    rt          j
        |           n# t          $ r Y nw xY wt                      )Nz'Received signal %s in single-query moder   r  r  r  r  r   )rs   r  ru  r   r  r  r  r  r  r  r  rx   rT  )r  r(  _agentr  rB  s       rM   _signal_handler_qzmain.<locals>._signal_handler_q.  s    >GGG	S'400F!  !<F!<!<===!"29-CU#K#KLLFF!:. ! ! ! FFF!A::Jv&&& 	 	 	D	!!!s5   +B! 
"A- ,B! -B B! BB! !
B.-B.r  r   r[  r`  r   rJ  ra  re  T)r\  r  ri  r  z
session_id: )r  r
  r  z[image attached]z[bold blue]Query:[/] r  )Br  r  rg  gateway.runr  r  r  r  rV   r  r  r  ry  r  r  r  rT   rW   r  rc   rD  r  r  r  r  r  rF  rQ  r7  ri  rd   r  r   rI   r  r  r  rF  rD  r  rx  r  r  rt  r  rx   r  r  r[  rj  rd  r  r   r  rz  suppress_status_outputr  r  r  r  ru  rU   r  r  r*  r4  ).r  rE  r]  rR  r>  r   r   r   r   r   r   r  r   r  r  r  rS  r  r,  r  rT  r%  rU  rg  r  use_worktreewt_info_repotoolsets_listrp  r  parsed_skillsskills_promptloaded_skillsmissing_skillsmissing_displaywt_noter  r  single_query_imageseffective_queryr  r   r  _query_labelrB  s.                                                @rM   r  r  -  sI   | (+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!!!"" " " " "    w(9:::7H%% 	>NN7>+<===     < <%:5%%H%H"" 9	& &+C"..00 +\"'& &)&H&H+!& 'I ' 'O
 !;;OLL
k*c.OOO $CI??#-g#6%/	%:&0nn5H&I&I #    \
 ,0CI(7;CI4 7;CI326CI/ Y77%4-0-E 8  F  	<>>>I0CNBB),)=CMfVZC[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???##%%% GGIIIIIs   A
N 
N N __main__r^   r=  )r  )rU  )r{  )NNNNNNNNNNFFFFFFNFFFFFF)rA  r	  r  r  rF  rv   rE   concurrent.futuresr	  rB  r  r  r7
  r  r  r  urllib.parser   r   r  r   pathlibr   r   typingr   r	   r
   r   r	  r>  rs   r  r  prompt_toolkit.historyr   prompt_toolkit.stylesr   rR  prompt_toolkit.patch_stdoutr   re  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    ra  prompt_toolkit.formatted_textr!   rb  prompt_toolkit.cursor_shapesr"   BLOCKr  r  AttributeErrorr  rZ  agent.usage_pricingr#   r$   r%   r&   hermes_cli.bannerr'   r(   r*  r   r)   r*   hermes_cli.browser_connectr+   r,   r-   hermes_cli.env_loaderr.   rJ  r/   r0   rq   r  r  _project_envrD   rW   rN   rf   rh   r}   rU   r   r   r@  r  hermes_loggingrA  rx   r  rE  r0  rF  r	  rG  rV   _tplr  rq  rI  richrJ  r  rich.consolerK  rich.markuprL  r  r  rN  r  rP  rJ  firer	  rQ  rp  rR  rS  rT  r  rU  rV  rR  rW  rX  rY  rR  rZ  tools.terminal_toolr[  rn  r\  r]  tools.skills_toolr^  hermes_cli.callbacksr`  r  ra  ro  rm  rs  rx  ry  __annotations__r  r  r  r  r  r  r  r  r  r  r  r  r  r   r"  r  r  rH  rM  rT  rZ  ro  	frozensetr  rz  r;  r  rD  r  r  r  r  rc   r  r  r  r  r  r  r  r  r  rK  r  r  r  r  HERMES_AGENT_LOGOHERMES_CADUCEUSr1  r4  r	  r5  r6  r7  r  r	  r=  rF  r
  rO  rQ  r  Firer_   rO   rM   <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         
 5 4 4 4 4 4 8 8 8 8 8 8 8 8  tH~~$v-  | F F F FE E E E E EP     F# F# F F F Fc d4S>.B    :C D4K    C C$J    ^c3h ^ ^ ^ ^B _

	,,,,,,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  0 0 0p .2 (4S>* 1 1 1    t 4 D    ` `s `htCH~.F ` ` ` `F=@ =@DcN =@d =@ =@ =@ =@@'C 'C 'C 'CTE E E E.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 + + + +     * # S    H# H H H H^ I       A @ @ @ @ @B B BS B B B B(3 (5c? ( ( ( (V,s ,td{ , , , ,^$d $| $ $ $ $NA# A- A A A AH T$Z PS \_bf\f ru    B#c #d # # # #
     @ "*.// bj!233 BJ899 "
#<== 
  RZ 344 
 (#S (#U39=M (# (# (# (#V3 3     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~|X' |X' |X' |X' |X' |X' |X' |X'Hr 04!$/U UU
U U 	U
 $s)OeCHo-U U U U U U U U U U U  !U" #U$ %U& 'U( )U* +U, -U. /U U U Up zDIdOOOOO sm   C+ +	C76C7G GG G1 1G98G9=H HHAI$ $I,+I,0J J	J	