
    Jj)L             /       2   U d Z 	 ddlZn# e$ r Y nw xY w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 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/Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z; ddl<m=Z=m>Z>m?Z?m@Z@ ddlAmBZB ddlCmDZD ddlEmFZF ddlGmHZH ddlImJZJ ddlKmLZM ddlNmOZP 	 ddlQmRZR eRjS        ZTn# eUeVf$ r dZTY nw xY w	 ddlWmXZXmYZYmZZZ  eZ              eX              eY             [Z[X[Yn# e[$ r Y nw xY wddl\Z\ddl]Z]d Z^d Z_d Z`d  Zad! Zbd" Zcd# Zddd$lemfZfmgZg d%Zhdd&limjZjmkZk dd'llmmZmmnZnmoZompZp dd(lqmrZr dd)lsmtZtmuZu  ej            Zv eew          jx        d*z  Zy erevey+           d,Zzd-e{d.e{fd/Z|d0ed.e{fd1Z}d0ed.e{fd2Z~d3e{d.eee{ef                  fd4Zd5ee{ef         d.e{fd6Zd.edz  fd7Zd8e{d.e{dz  fd9Zd.ee{ef         fd:Z e            Z	 dd;lmZ  ed<=           n# e[$ r Y nw xY w	 dd>lmZ  e             n# e[$ r Y nw xY w	 dd?lmZ  ee           n# e[$ r Y nw xY w	 dd@lmZ e                    dAi                               dBd          Z eer ee          nd           n# e[$ r Y nw xY w	 ddClmZ e                    dAi                               dDdE          Z e ee                     n# e[$ r Y nw xY w	 ddlZddlmZ  G dF dG          Zej                            d e                       n# e[$ r Y nw xY wddHlmZ ddIlmZ ddJlmZ ddKlmZ ddLlmZ dM ZdN ZdO ZddPlemZ ddQlmZmZ dR ZdS ZdT ZdUe{d.dfdVZdW ZddXlmZ dY ZdZ Zd[ Zd\ Zd] Zd^a e            Zee{dz           ed_<   dZd^ad^ad"d`Zd"daZÐd#dbedz  d.dfdcZdEdddeefdfZdUe{dz  d.efdgZd<dhdidUe{dz  dje{dke{d.dfdlZdmdndke{d.dfdoZdhdndke{d.dfdpZʐd"dqZːd"drZdae ee{e{f                  eds<   dte e{         d.e e{         fduZd.e e{         fdvZdwedxed.efdyZdze{d.efd{ZҐd$dze{d|ed.e ee{e{f                  fd}ZӐd%de{ded.efdZԐd%de{ded.efdZՐd%dze{de{defdZ֐d#dee{e{f         d.dfdZאd"dZؐd"dZِd&dze{ded.dfdZdze{d.dfdZdZdZdZdZd^dde{ded.e{fdZdaedz  ed<    ej        d          Z ej        d          Z e            Zde{d.edz  fdZd.e{dz  fdZd.efdZdddddddddddddZee{e{f         ed<   de{d.e{fdZd e                                D             Zd"dZ e             	 ej                                        r#ej                                        r
 e             n# e[$ r Y nw xY w G d d          Z edddE          ZdZde{d.e{fdZde{d.e{fdZd.e{fdZd-e{d.efdZd-e{d.e{fdZ ej        d          Zd-e{d.e{fdZd.efdZd'd-e{de{fdZdEad^ad^a da et                    ad.efdZd(ded.dfdZd"dZed             Zd"dZd-e{d.dfdZd"dÄZ	d-e{fdĄZ
de{fdƄZd)d-e{d.dfdȄZ eh dɣ          ZddlimZ d*de{d.e{fd̈́Zd8e{d.ee{e{f         fd΄Zde{d.edz  fdЄZde{d.dfdӄZd#dԐee         dededz  d.e{fdׄZde{d.efdلZd-e{d.e{fdڄZd"dۄZ ej        dܦ          Z ej        dݦ          Z ej        dަ          Z ej        dߦ          Z ej        d          ZdZd.efdZd"dZ d"dZ!d.efdZ"d Z#d-e{d.ee{ef         fdZ$d-e{d.e{fdZ%dddee{         ee{df         z  de{deded.ef
dZ&d#de{dz  de{dz  d.ee{ee         f         fdZ' ej        d          Z( G d d          Z)dZ*dZ+d.e{fdZ,d-e{d.efdZ-da.da/d.efdZ0d.efdZ1d Z2d Z3d.efdZ4d  Z5d.efdZ6de{ee{         z  ee{df         z  dz  d.ee{         fdZ7de{de8d.efdZ9 G d de)e+          Z:d<dd	e{d.dfd
Z;	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d+de{de{de{de{de{ee{         z  ee{df         z  de{de{de{de{dede e         dededededede{dedededededef.d Z<e"d!k    rddl=Z= e=j>        e<           dS dS (,  a  
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 --list-tools             # List available tools and exit
    N)deque)unquoteurlparse)contextmanager)Pathdatetime)ListDictAnyOptional1HERMES_QUIET)get_fallback_chain)CLIAgentSetupMixin)CLICommandsMixin)FileHistory)Style)patch_stdout)Application)LayoutHSplitWindowFormattedTextControlConditionalContainerWindowAlign)	ProcessorTransformationPasswordProcessorConditionalProcessor)	Condition)	Dimension)CompletionsMenu)TextArea)KeyBindings)print_formatted_text)ANSI)CursorShape)install_ctrl_enter_alias"install_ignored_terminal_sequencesinstall_shift_enter_aliasc                      ddl m}  || i |S )Nr   )CanonicalUsage)agent.usage_pricingr-   )argskwargs_CanonicalUsages      )/home/rurouni/.hermes/hermes-agent/cli.pyr-   r-   ]   s)    EEEEEE?D+F+++    c                      ddl m}  || i |S )Nr   )estimate_usage_cost)r.   r5   )r/   r0   _estimate_usage_costs      r2   r5   r5   c   s*    OOOOOO0000r3   c                  8   t          | r| d         n|                    dd                    }|dk     r|ddS |dz  }|dk     r|ddS |dz  }|dk     r;t          |dz            }|rt          |           d	| dnt          |           d
S |dz  }|ddS )Nr   seconds        <   .0fsm   h h.1fd)floatgetint)r/   r0   r8   minuteshoursremaining_mindayss          r2   format_duration_compactrJ   i   s    tCDGGIs)C)CDDG||     lG||     bLErzzGbL))4AW#e**000000#e**GWGWGWW2:D>>>>r3   c                     t          | r| d         n|                    dd                    }t          |          }|dk     rt          |          S |dk     rdnd}d}|D ]`\  }}||k    rU||z  }|dk     r|d}	n|d	k     r|d
}	n|d}	d|	v r(|	                    d                              d          }	| |	 | c S a|dS )Nr   value  - ))i ʚ;B)i@B M)rM   K
   z.2fd   rA   r;   .0,)rE   rD   absstrrstrip)
r/   r0   rL   	abs_valuesignunits	thresholdsuffixscaledtexts
             r2   format_token_count_compactrb   x   s   4;QVZZ%;%;<<EE

I55zz!))33DBE" + +	6	!!*F{{ #  d{{{{3''..s33*D*&***** " <<r3   c                      ddl m}  || i |S )Nr   )is_table_divider)agent.markdown_tablesrd   )r/   r0   _is_table_dividers      r2   rd   rd      s*    KKKKKKd-f---r3   c                      ddl m}  || i |S )Nr   )looks_like_table_row)re   rh   )r/   r0   _looks_like_table_rows      r2   rh   rh      s*    SSSSSS  $1&111r3   c                      ddl m}  || i |S )Nr   )realign_markdown_tables)re   rk   )r/   r0   _realign_markdown_tabless      r2   rk   rk      s*    YYYYYY##T4V444r3   )_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is_browser_debug_readymanual_chrome_debug_commandtry_launch_chrome_debug)load_hermes_dotenv)base_url_host_matchesfast_safe_loadz.env)hermes_homeproject_env)REASONING_SCRATCHPADthinkthinking	reasoningthoughtra   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*rO   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)ra   cleanedtagtc_tags       r2   _strip_reasoning_tagsr      ss   * G 
 
&%%%C%%%)bm+	
 
 
 &NNN)bm+	
 
 
 &#OOO-	
 
 
6 
 
&222f222)bm+	
 
 
 f	3 	i"-'  G f[
m	  G ==??r3   contentc                     | dS t          | t                    r| S t          | t                    r+d | D             }d                    d |D                       S t          |           S )NrO   c                     g | ]S}t          |t                    r<|                    d           dk    0t          |                    dd                    TS typera   rO   )
isinstancedictrD   rY   .0parts     r2   
<listcomp>z._assistant_content_as_text.<locals>.<listcomp>  sc     
 
 
$%%
 +/((6*:*:f*D*D $$%%*D*D*Dr3   
c              3      K   | ]}||V  	d S N r   ps     r2   	<genexpr>z-_assistant_content_as_text.<locals>.<genexpr>  s'      //qQ///////r3   r   rY   listjoinr   partss     r2   _assistant_content_as_textr   
  s    r'3 '4   0
 

 
 

 yy//E//////w<<r3   c                 :    t          t          |                     S r   )r   r   )r   s    r2   _assistant_copy_textr     s     !;G!D!DEEEr3   	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loadr   r   	Exception)r   pathfdataes        r2   _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configc                    t          j        dd                                          }|r|S t          |                     dd          pd                                          }|r|S |                     di           }t          |t                    r7t          |                    dd          pd                                          S dS )zResolve the prefill file path from env/config.

    ``prefill_messages_file`` at the top level is the canonical config key.
    ``agent.prefill_messages_file`` remains a legacy fallback for older CLI and
    godmode-generated configs.
    HERMES_PREFILL_MESSAGES_FILErO   prefill_messages_fileagent)osgetenvr   rY   rD   r   r   )r   env_path	top_level	agent_cfgs       r2   _resolve_prefill_messages_filer   >  s     y7<<BBDDH FJJ6;;ArBBHHJJI 

7B''I)T"" M9==!8"==CDDJJLLL2r3   c                     ddl m}  ||           }| r>t          |                                           r|t                              d|            |S )u   Parse a reasoning effort level into an OpenRouter reasoning config dict.

    Accepts the raw config value (string or YAML boolean — ``false``/``off``
    parse as thinking disabled, see parse_reasoning_effort).
    r   )parse_reasoning_effortNz5Unknown reasoning_effort '%s', using default (medium))hermes_constantsr   rY   r   r   r   )effortr   results      r2   _parse_reasoning_configr   Q  sh     877777##F++F X#f++##%% X&.NPVWWWMr3   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.rO   >   offnonenormaldefaultstandardN>   onfastpriorityr   z#Unknown service_tier '%s', ignoring)rY   r   lowerr   r   )r   rL   s     r2   _parse_service_tier_configr   ^  sl    	rNN  ""((**E EMMMt***z
NN8#>>>4r3   c                  z   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)d*ddddd+dd)dd,d-d.did
d/d0ddddd1ddddd1d2d3ddddd4d5i id6}d}|                                r	 t          |d7d89          5 }d:d;l	m
}  |t          |          pi           }d<d<d<           n# 1 swxY w Y   d=|v }d>|v rt          |d>         t                    r|d>         |d>         d,<   ngt          |d>         t                    rL|d>                             |d>                    d>|d>         v r!d,|d>         vr|d>         d>         |d>         d,<   |D ]p}	|	d>k    r	|	|v rct          ||	         t                    r=t          ||	         t                    r"||	                             ||	                    e||	         ||	<   q|D ]}	|	|vr|	d>k    r||	         ||	<   |                    d?          }
d@|v r;t          |
t                    r|
                    d@          |d@         |d?         d@<   n2# t           $ r%}t"                              dA|           Y d<}~nd<}~ww xY wd:dBl	m}  ||          }d:dClm} |                    |          }|                    d=i           }dD|v r|dD         |dE<   dF}|                    dEd          }|dk    r(t	          j                    |dG<   |dG         |d=         dG<   n-|                    dG          |v r|                    dGd<           i dEdHdGdId.dJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdndodpdqdrds}t          j                            dt          dk    }|                                D ]\  }}||v r|dIk    r&|rt          ||                   t          j        |<   5|s|t          j        vrb||         }t          |t4          t          f          r"t7          j        |          t          j        |<   t          |          t          j        |<   |                    dui           }dvdwi}|                                D ]+\  }}||v r"t          ||                   t          j        |<   ,|                    dxi           }dydzd{d|d1d}d~ddd1ddddd1d}|                                D ]h\  }}|                    |i           }t          |t                    s2t          |                    dd                                                    }t          |                    d>d                                                    }t          |                    dd                                                    }t          |                    dd                                                    } |r|dk    r|t          j        |d         <   |r|t          j        |d>         <   |r|t          j        |d         <   | r| t          j        |d         <   j|                    di           }!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   rO   auto)r   base_urlproviderlocalrU   ,  z*nikolaik/python-nodejs:python3.11-nodejs20z3docker://nikolaik/python-nodejs:python3.11-nodejs20F)env_typecwd	home_modelifetime_secondsdocker_imagedocker_forward_envsingularity_imagemodal_imagedaytona_imagedocker_volumesdocker_mount_cwd_to_workspacex   zhost.docker.internal)rewrite_loopback_urlsloopback_host_alias)inactivity_timeoutrecord_sessionsenginecamofoxT      ?)enabledr^   Z   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_promptr   reasoning_effortservice_tierpersonalitiesfullrS         	interruptr   )compactresume_displayresume_exchangesresume_max_user_charsresume_max_assistant_charsresume_max_assistant_linesresume_skip_tool_onlyshow_reasoningreasoning_full	streamingbusy_input_modepersistent_outputpersistent_output_max_linespersist_promptsskintimeout2   )r$  max_tool_calls)r   modelr   api_key)visionweb_extract-   )max_iterationsr'  r   r   r(  seen)r'  terminalbrowsercompressionr   displayclarifycode_execution	auxiliary
delegation
onboardingr   r   r   r   )_normalize_root_model_keysNr.  r'  r   r  z"Failed to load cli-config.yaml: %s)_expand_env_vars)managed_scopebackendr   )rU   r   r   r   TERMINAL_ENVTERMINAL_CWDTERMINAL_TIMEOUTr   TERMINAL_HOME_MODEr   TERMINAL_LIFETIME_SECONDSr   TERMINAL_DOCKER_IMAGEr   TERMINAL_DOCKER_FORWARD_ENVr   TERMINAL_SINGULARITY_IMAGEr   TERMINAL_MODAL_IMAGEr   TERMINAL_DAYTONA_IMAGEssh_hostTERMINAL_SSH_HOSTssh_userTERMINAL_SSH_USERssh_portTERMINAL_SSH_PORTssh_keyTERMINAL_SSH_KEYcontainer_cpuTERMINAL_CONTAINER_CPUcontainer_memoryTERMINAL_CONTAINER_MEMORYcontainer_diskTERMINAL_CONTAINER_DISKTERMINAL_CONTAINER_PERSISTENTTERMINAL_DOCKER_VOLUMESTERMINAL_DOCKER_ENVTERMINAL_DOCKER_EXTRA_ARGS&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACETERMINAL_DOCKER_NETWORK TERMINAL_DOCKER_RUN_AS_HOST_USER(TERMINAL_DOCKER_PERSIST_ACROSS_PROCESSESTERMINAL_DOCKER_ORPHAN_REAPERTERMINAL_SANDBOX_DIRTERMINAL_PERSISTENT_SHELLSUDO_PASSWORD)container_persistentr   
docker_envdocker_extra_argsr   docker_networkdocker_run_as_host_userdocker_persist_across_processesdocker_orphan_reapersandbox_dirpersistent_shellsudo_password_HERMES_GATEWAYr/  r   BROWSER_INACTIVITY_TIMEOUTr4  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   r   r(  securityredact_secretsHERMES_REDACT_SECRETS)r   r   __file__parentr   environrD   r   r   hermes_cli.configr7  rw   r   rY   r   updater   r   r   r8  
hermes_clir9  apply_managed_overlaygetcwdpopitemsr   r   dumpsr   r   )#user_config_pathproject_config_pathignore_user_configconfig_pathdefaults_file_has_terminal_configr   r7  file_configkeyagent_file_configr   r8  r9  terminal_config_CWD_PLACEHOLDERSeffective_backendenv_mappings_is_gateway
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#                                      r2   load_cli_configr  h  ss
   $ $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
Uo oHj !&  4D3	Dk3999 RQHHHHHH889J9J9PbQQR R R R R R R R R R R R R R R
 )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   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 )(((((228<<H ll:r22O
 O##&5i&@
# -'++J@@G##!#&5e&<U##			U	#	#'8	8	8E4((("N"~" 	%" 	)	"
 	7" 	/" 	;" 	9" 	-" 	1" 	'" 	'" 	'" 	%"" 	1#"$ 	7%"& 	3'"( !@3+9)Q3#E+U ?-7(C" " "LN *..!233s:K+1133 3 3
G((.(( &)/**E&F&F
7#( 3G2:,E,E%j1cD$<00 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=   'J/ 9!D&J/ &D**J/ -D*.F J/ /
K9KK)setup_loggingclimode)print_config_warnings)init_skin_from_config)set_tool_preview_max_lenr1  tool_preview_length)set_friendly_tool_labelsfriendly_tool_labelsTc                       e Zd ZdZdZddZdS )_AsyncHttpxDelNeuteraP  Defer ``AsyncHttpxClientWrapper.__del__`` neutering until import.

        Saves ~166ms on cold CLI start where openai is never used (e.g.
        ``hermes --help`` paths inside the chat command flow).  See
        ``agent.auxiliary_client.neuter_async_httpx_del`` for full rationale
        on why ``__del__`` must be a no-op.
        TNc                    | j         r|dk    rd S d| _         	 t          j                            |            n# t          $ r Y nw xY wt          j        |          }||j        d S |j        j        fd}||j        _        |S )Nopenai._base_clientFc                 |     |            	 t          | dd           }|
d |_        d S d S # t          $ r Y d S w xY w)NAsyncHttpxClientWrapperc                     d S r   r   selfs    r2   <lambda>zG_AsyncHttpxDelNeuter.find_spec.<locals>._patched_exec.<locals>.<lambda>0  s    4 r3   )getattr__del__r   )modulecls
_orig_execs     r2   _patched_execz5_AsyncHttpxDelNeuter.find_spec.<locals>._patched_exec+  sf    
6"""!&*CTJJC&7&7 '    DDs   - 
;;)	_armed_httpx_neuter_sys	meta_pathremove
ValueError_httpx_neuter_imp_util	find_specloaderexec_module)r  fullnamer   targetspecr  r  s         @r2   r  z_AsyncHttpxDelNeuter.find_spec  s    ; (.C"C"Ct  DK!+2248888   )3H==D|t{2t0J     '4DK#Ks   9 
AANN)__name__
__module____qualname____doc__r  r  r   r3   r2   r  r    s9        	 	 	 	 	 	 	 	r3   r  )box)Console)escape)Panel)Textc                      ddl m}  || i |S )Nr   )AIAgent)	run_agentr  )r/   r0   _AIAgents      r2   r  r  C  s)    ------8T$V$$$r3   c                  >    ddl m} ddlm}  |              || i |S )Nr   )wait_for_mcp_discovery)get_tool_definitions)hermes_cli.mcp_startupr  model_toolsr  )r/   r0   r  _get_tool_definitionss       r2   r  r  I  sK    ======IIIIII  $1&111r3   c                      ddl m}  || i |S )Nr   )get_toolset_for_tool)r  r  )r/   r0   _get_toolset_for_tools      r2   r  r  Q  s*    IIIIII  $1&111r3   )build_welcome_banner)SlashCommandCompleterSlashCommandAutoSuggestc                      ddl m}  || i |S )Nr   )get_all_toolsets)toolsetsr  )r/   r0   _get_all_toolsetss      r2   r  r  [  *    >>>>>>d-f---r3   c                      ddl m}  || i |S )Nr   )get_toolset_info)r  r  )r/   r0   _get_toolset_infos      r2   r  r  a  r  r3   c                      ddl m}  || i |S )Nr   validate_toolset)r  r  )r/   r0   _validate_toolsets      r2   r  r  g  r  r3   
session_idc                 (    ddl m}  ||            dS )zCKeep process-local session-id consumers aligned after CLI switches.r   )set_current_session_idN)gateway.session_contextr  )r  r  s     r2   _sync_process_session_idr  m  s+    >>>>>>:&&&&&r3   c                      ddl m}  || i |S )Nr   )get_job)cronr  )r/   r0   _get_jobs      r2   r  r  t  s)    ((((((8T$V$$$r3   prompt_for_secretc                      ddl m}  || i |S )Nr   )cleanup_all_environments)tools.terminal_toolr  )r/   r0   r  s      r2   _cleanup_all_terminalsr  }  s*    <<<<<<##T4V444r3   c                      ddl m}  || i |S )Nr   )set_sudo_password_callback)r  r  )r/   r0   _set_sudo_password_callbacks      r2   r  r    s*    ]]]]]]&&7777r3   c                      ddl m}  || i |S )Nr   set_approval_callback)r  r  )r/   r0   _set_approval_callbacks      r2   r  r    s*    SSSSSS!!426222r3   c                      ddl m}  || i |S )Nr   )set_secret_capture_callback)tools.skills_toolr  )r/   r0   _set_secret_capture_callbacks      r2   r  r    s*    ]]]]]]''8888r3   c                      ddl m}  || i |S )Nr   )_emergency_cleanup_all_sessions)tools.browser_toolr	  )r/   r0   r	  s      r2   _cleanup_all_browsersr    s*    BBBBBB**D;F;;;r3   F,_single_query_finalize_attempted_session_idsc                  
    da dS )zDRecord that the TUI app started, so _run_cleanup resets input modes.TN)_tui_input_modes_activer   r3   r2   _mark_tui_input_modes_activer    s     #r3   c                  t   t           rdS t          j                            d          dk    rdS da t          j                            dd                                          dv } 	 dd	lm}  |             n,# t          $ r t          	                    d
d           Y nw xY w	 ddl
m}  |t          d           n,# t          $ r t                              dd           Y nw xY w	 ddlm} ddlm}  | |            |            dS # t          $ r  t                              dd           Y dS w xY w)zERun Termux-deferred agent discovery before the first real agent turn.NHERMES_DEFER_AGENT_STARTUPr   THERMES_ACCEPT_HOOKSrO   >   r   r   yestruer   )discover_pluginsz/plugin discovery failed at deferred CLI startupexc_info)start_background_mcp_discoveryztermux-cli-mcp-discovery)r   thread_namez1MCP tool discovery failed at deferred CLI startup)register_from_configload_config)accept_hooksz6shell-hook registration failed at deferred CLI startup)_deferred_agent_startup_doner   r}  rD   r   hermes_cli.pluginsr  r   r   r   r  r  debugagent.shell_hooksr  r~  r  )_accept_hooksr  r  r  r  s        r2   _prepare_deferred_agent_startupr#    s    $ 	z~~233s::#' JNN#8"==CCEE J M
777777 
 
 
= 	 	
 	
 	
 	
 	



IIIIII&&2	
 	
 	
 	
 	
  
 
 
? 	 	
 	
 	
 	
 	


	
::::::111111[[]]GGGGGG 
 
 
D 	 	
 	
 	
 	
 	
 	

s6   &A7 7&B B $B= =&C&%C&*!D &D76D7	timeout_sc                 X     =	 t          t          j        dd                     n# t          t          f$ r d Y nw xY w dk    rdS t          j                            d          rdS  fd}	 t          j        |dd	
          	                                 dS # t          $ r Y dS w xY w)uQ  Guarantee the process actually exits once shutdown has begun.

    Two hang classes have kept "dead" CLI processes alive for minutes:

      1. A cleanup step wedged on network I/O (memory provider
         ``on_session_end``, MCP teardown, remote terminal cleanup).
      2. Interpreter teardown blocked joining non-daemon threads —
         stdlib ``ThreadPoolExecutor`` workers are joined unconditionally
         by ``concurrent.futures``' atexit hook even after
         ``shutdown(wait=False)``, so one tool thread wedged on a socket
         held the process open forever (#27563 class).

    The shared daemon pool (``tools.daemon_pool``) removes the main cause
    of (2); this watchdog is the backstop for both. It arms a daemon
    timer when ``_run_cleanup`` starts; if the process is still alive
    after ``timeout_s`` it flushes logging/stdio and calls ``os._exit(0)``.
    Daemon threads keep running through ``Py_FinalizeEx``'s thread joins,
    so the timer fires even when the main thread is stuck in teardown.

    Tune with ``HERMES_EXIT_WATCHDOG_S`` (seconds); ``0`` disables.
    NHERMES_EXIT_WATCHDOG_S30      >@r   PYTEST_CURRENT_TESTc                     t          j                   	 t                              d           n# t          $ r Y nw xY w	 dd l} |                                  n# t          $ r Y nw xY wt          j        t          j	        fD ]'}	 |
                                 # t          $ r Y $w xY wt          j        d           d S )Nui   Exit watchdog fired after %.0fs — forcing process exit (a cleanup step or non-daemon thread is wedged).r   )timesleepr   r   r   loggingshutdownsysstdoutstderrflushr   _exit)_lg_streamr$  s     r2   	_watchdogz%_arm_exit_watchdog.<locals>._watchdog   s    
9	NNC   
  	 	 	D		!!!!LLNNNN 	 	 	D	
CJ/ 	 	G   
s2   3 
A A A 
A*)A*B
B*)B*Tzexit-watchdog)r  daemonname)rC   r   r   	TypeErrorr  r}  rD   	threadingThreadstartr   )r$  r6  s   ` r2   _arm_exit_watchdogr=    s    , 	bi(@$GGHHII:& 	 	 	III	A~~ 
z~~+,,     .T	
 	
 	

%'''''   s   "( >>0)B 
B)(B)notify_session_finalizer?  c                 `   t           rdS da t                       t                       	 t                       n# t          $ r Y nw xY w	 ddlm}  |d           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| r6t          rt          j        nd}t          |          rt!          |d	d
           	 t          rt#          t          d          rt%          t          dd          }t'          |t(                    r[t*                              dt%          t          dd          pdt/          |                     t                              |           dS t*                              dt%          t          dd          pd           t                                           dS dS dS # t          $ r(}t*                              d|d           Y d}~dS d}~ww xY w)z"Run resource cleanup exactly once.NTr   )interrupt_allzCLI shutdownreason)shutdown_mcp_servers)shutdown_cached_clientsr  r.  r  platformrC  shutdown_memory_provider_session_messageszECLI cleanup calling memory shutdown for session %s with %d message(s)r  z	<unknown>zOCLI cleanup calling memory shutdown for session %s without session message listz&CLI cleanup memory shutdown failed: %sr  )_cleanup_doner=  #_reset_terminal_input_modes_on_exitr  r   tools.async_delegationrA  r  tools.mcp_toolrD  BaseExceptionagent.auxiliary_clientrE  _active_agent_refr  %_should_emit_cleanup_session_finalize_notify_session_finalizehasattrr  r   r   r   infolenrH  r   )r?  _interrupt_async_delegationsrD  rE  cleanup_session_id_session_msgsr   s          r2   _run_cleanuprY    s     M
  ()))       XXXXXX$$N;;;;;      777777   
BBBBBB!!!!     =NX.99TX01CDD 	$-!   
S 	=):<V!W!W 	= $$57JDQQM-.. =[-|TBBQk&&  
 "::=IIIIIe-|TBBQk   "::<<<<<)	= 	= 	= 	=*  S S S?TRRRRRRRRRSsw   8 
AA	A 
A)(A)-A< <
B	B	B 
B+*B+/C   
CC	B G; +A
G; ;
H-H((H-c                 .    t           sdS | dS | t           vS )NTF)r  )r  s    r2   rQ  rQ  o  s&    7 tuIIIr3   r.  )rG  rC  rG  rC  c                 T    	 ddl m}  |d| ||           d S # t          $ r Y d S w xY w)Nr   invoke_hookon_session_finalizerF  )r  r]  r   )r  rG  rC  _invoke_hooks       r2   rR  rR  w  sl    	BBBBBB!!		
 	
 	
 	
 	
 	
        
''keyboard_interruptrB  c                    t          | dd          }|dS 	 |                    |                    dd                     n# t          $ r Y nw xY wt          |dd          pt          | dd          }|r	 || _        n# t          $ r Y nw xY w	 ddlm}  |d|t          |d	d
          pd
t          |dd
          pd
t          |dd
          pd
ddt          |dd          t          |dd          pd|
  
         dS # t          $ r Y dS w xY w)zEBest-effort on_session_end hook for interrupted non-interactive runs.r   N_ r  r   r\  on_session_end_current_task_idrO   _current_turn_id_current_api_request_idFTr'  rG  r  )	r  task_idturn_idapi_request_id	completedinterruptedr'  rG  rC  )r  r  replacer   r  r  r]  )r  rC  r   r  r_  s        r2   _emit_interrupted_session_endro    s   C$''E}sC001111    d33WwsLRV7W7WJ 	'CNN 	 	 	D	BBBBBB!E#5r::@bE#5r::@b"5*CRHHNB%$//UJ55>	
 	
 	
 	
 	
 	
    s6   )A 
AA6A> >
B
BA.C? ?
DDc                <   t          | dd           }t          |dd           pt          | dd           }|t          v rd S 	 t          |t          |dd           pd|           t                              |           d S # t                              |           w xY w)Nr   r  rG  r  rF  )r  r  rR  add)r  rC  r   r  s       r2   %_notify_single_query_session_finalizerr    s    C$''Ed33WwsLRV7W7WJAAAE !UJ55>	
 	
 	
 	
 	588DDDDD488DDDDs    #A? ?Bc                     	 t          |            t          d           |                                  dS # |                                  w xY w)zGClose one-shot CLI resources before releasing the active session lease.Fr>  N)rr  rY  _release_active_sessionr  s    r2   _finalize_single_queryrv    sV    &-c222U3333##%%%%%##%%%%s	   7 Ac                     t           sdS da 	 t          j        } | D|                                 r0|                     t
                     |                                  dS n# t          $ r Y nw xY w	 t          ddd          5 }|                    t
                     |                                 ddd           dS # 1 swxY w Y   dS # t          $ r Y dS w xY w)u  Best-effort: disable focus reporting + mouse tracking on TUI exit so they
    don't leak into the next shell session sharing the tab.

    prompt_toolkit restores these on a clean teardown, but Ctrl+C, SIGTERM /
    SIGHUP and crashes can bypass its unwind, leaving the modes enabled. The
    terminal then emits raw ``ESC[I`` / ``ESC[O`` focus events and fragmented
    SGR mouse reports as visible text in whatever runs next in the same tab
    (#36823). Called from ``_run_cleanup`` (atexit-registered + invoked on the
    normal / EOF / interrupt exit paths) this covers normal quit, Ctrl+C and
    SIGTERM/SIGHUP. ``kill -9`` is uncatchable, and the kanban worker's
    ``os._exit(0)`` path bypasses ``atexit``; neither runs this — but both are
    non-TTY / non-TUI, so there is nothing to reset there.

    Gated on ``_tui_input_modes_active`` so one-shot non-TUI CLI runs (which
    share ``_run_cleanup`` via ``atexit``) never emit these codes. Writes to the
    controlling terminal directly: by exit, prompt_toolkit's own output is torn
    down, so ``sys.stdout`` is the real fd; falls back to ``/dev/tty`` when
    stdout is redirected away from the terminal.
    NFz/dev/ttywasciir   )	r  r/  r0  isattywrite_TERMINAL_INPUT_MODE_RESET_SEQr2  r   r   )streamttys     r2   rK  rK    s=   * #  $&--//LL7888LLNNNF   *cG444 	II4555IIKKK	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	    sH   AA   
A-,A-1C /B?2C ?CC CC 
CC_active_worktreer   c                 *   | s| S t           j        dk    r| S ddl}|                    d|           }|rd|                    d          |                    d          }}|                                 d|                    dt          d	                     S |                    d
|           }|rd|                    d          |                    d          }}|                                 d|                    dt          d	                     S | S )a  Translate a Git Bash-style path (``/c/Users/...``) to the native
    Windows form (``C:\Users\...``) that Python's ``subprocess.Popen``
    and ``pathlib.Path`` accept.

    No-op on non-Windows and for paths that already look native.  Git on
    native Windows normally emits forward-slash Windows paths
    (``C:/Users/...``) which both bash and Python handle, but certain
    configurations (Git Bash shells, MSYS2, WSL-mounted repos) surface
    ``/c/...`` or ``/cygdrive/c/...`` variants.
    win32r   Nz^/([a-zA-Z])/(.*)$      z:\/\   z#^/(?:cygdrive|mnt)/([a-zA-Z])/(.*)$)r/  rG  r   matchgroupupperrn  chr)r   _rer=   driverests        r2   _normalize_git_bash_pathr    s     
|w		'++A Aggajj!''!**t++--@@DLLc"gg$>$>@@@		8!<<A Aggajj!''!**t++--@@DLLc"gg$>$>@@@Hr3   c                      ddl } 	 |                     g dddd          }|j        dk    r&t          |j                                                  S n# t          $ r Y nw xY wdS )a  Return the git repo root for CWD, or None if not in a repo.

    Runs through :func:`_normalize_git_bash_path` so callers can pass
    the result directly to ``Path``/``subprocess.Popen(cwd=...)`` on
    Windows without hitting ``C:\c\Users\...`` style resolution
    mistakes.
    r   N)git	rev-parsez--show-toplevelT   )capture_outputra   r$  )
subprocessrun
returncoder  r0  r   r   )r  r   s     r2   _git_repo_rootr    s     333dA   
 
 !!+FM,?,?,A,ABBB "   4s   AA 
A A r   rootc                 T    	 |                      |           dS # t          $ r Y dS w xY w)z@Return True when a resolved path stays within the expected root.TF)relative_tor  )r   r  s     r2   _path_is_within_rootr  ,  sB    t   uur`  	repo_rootc                     ddl d fd	}	  |g d          }|j        dk    rl|j                                        }|rQd|v rM|                    dd          d         } |d||                    dd          d         gd	
           || dfS n2# t
          $ r%}t                              d|           Y d}~nd}~ww xY w	  |g d          }d}|j        dk    r.|j                                                            ddd          }|s |g dd	
          }|j        	                                D ]h}	|	                                }	|	
                    d          r=|	                    dd          d                                         }
|
r|
dk    rd|
z   } ni|r4d|v r0|                    dd          \  }} |d||gd	
           || dfS n2# t
          $ r%}t                              d|           Y d}~nd}~ww xY wdS )u  Resolve the freshest base ref to branch a new worktree from.

    The standalone clone's ``HEAD`` can lag the remote by hundreds of commits
    (the ``~/.hermes/hermes-agent`` clone is updated only by ``hermes update``,
    not on every session). Branching a worktree from that stale ``HEAD`` roots
    every new branch on an old base — so the PR diff GitHub computes against
    current ``main`` balloons with unrelated changes, and the agent has to
    discover the staleness via the pre-push gate and rebase. Branching from the
    freshly-fetched remote tip instead means the worktree starts current.

    Strategy (each step falls back to the next on failure):
      1. If the current branch tracks an upstream, fetch and use that upstream
         ref — so a deliberate feature-branch worktree tracks its own remote,
         not the default branch.
      2. Else fetch the remote's default branch (``origin/HEAD`` → e.g.
         ``origin/main``) and use it.
      3. Else fall back to ``HEAD`` (offline, no remote, or detached) — the
         old behavior, never worse than before.

    Returns ``(base_ref, label)`` where *base_ref* is a git revision suitable
    for ``git worktree add ... <base_ref>`` and *label* is a short
    human-readable description for the session banner.
    r   N   c                 >                         dg| dd|          S )Nr  Tr  ra   r$  r   )r  )r/   r$  r  r  s     r2   _gitz$_resolve_worktree_base.<locals>._gitO  s0    ~~NTNdG  
 
 	
r3   )r  z--abbrev-refz--symbolic-full-namez@{upstream}r  r  fetch   r$  z
 (fetched)z-worktree base: upstream resolution failed: %s)zsymbolic-refz--quietzrefs/remotes/origin/HEADrO   zrefs/remotes/)remoteshoworiginzHEAD branch::	(unknown)zorigin/z3worktree base: default-branch resolution failed: %s)HEADu'   HEAD (local — could not reach remote))r  )r  r  r0  r   splitr   r   r   rn  
splitlines
startswith)r  r  upupstreamr  r   head_refdefault_refr  line_branchbranchr  s   `           @r2   _resolve_worktree_baser  5  s   0 
 
 
 
 
 
 

ITVVVWW=Ay((H 9C8OO!Q//2gvx~~c1'='=a'@A2NNNNH!8!8!888 I I IDaHHHHHHHHIO4OOOPP!##"///1199/2qQQK 	4444bAAAD..00  zz||??>22 "jja00399;;G  :7k#9#9&/'&9E  	;3+--(..sA66NFFD'66*B7777; : : ::: O O OJANNNNNNNNO =<s1   BB 
CB>>CDG 
H#HH	sync_basec           
         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rnt          |d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|rt#          |           \  }}nd\  }}	 |                    dddt'          |          d||gd	d	d|           }|j        dk    r|dk    rft                              d||j                                                   d\  }}|                    dddt'          |          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  }|                                r	 t          |                                           }|                                }|	                                
                                D ]}|                                }|r|                    d           r/t          |           |z  }||z  }	 |                    d!"          }|                    d!"          }n2# t4          t6          f$ r t                              d#|           Y w xY wt9          ||          st                              d$|           t9          ||          st                              d%|           |                                rM|j                            d	d	
           t?          j         t'          |          t'          |                     _|!                                r|                                s|j                            d	d	
           	 tE          j#        t'          |          t'          |                     # t4          tH          f$ r}tJ          j&        d&k    rt          '                    d'|           	 t?          j(        t'          |          t'          |          d	d!(           n5# t          $ r'}t                              d)|||           Y d}~n	d}~ww xY w Y d}~d}~ww xY wn2# t          $ r%}t                              d*|           Y d}~nd}~ww xY w	 |                    ddd+d,d-tE          j)                     t'          |          gd	d	d.|            t                              d/|tE          j)                               n2# t          $ r%}t                              d0|           Y d}~nd}~ww xY wt'          |          || |d1}t          d2|            t          d3|            t          d4|            |S )5u  Create 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.

    When *sync_base* is True (default), the worktree branches from the
    freshly-fetched remote tip rather than the (possibly stale) local ``HEAD``
    — see ``_resolve_worktree_base``. Set ``worktree_sync: false`` in config to
    branch from local ``HEAD`` (the pre-#10760-followup behavior).
    r   Nu?   [31m✗ --worktree requires being inside a git repository.[0mz5  cd into your project repo first, then run hermes -w   hermes-zhermes/
.worktreesTparentsexist_okz
.gitignorez.worktrees/rO   ar   r   r   zCould not update .gitignore: %s)r  u'   HEAD (local — worktree_sync disabled)r  worktreerq  z-br  r  r  z:worktree add from %s failed (%s); retrying from local HEAD)r  u&   HEAD (fallback — remote base failed)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: %sr  uN   .worktreeinclude: symlink failed (%s) — falling back to copytree on Windows.)symlinksdirs_exist_okz<.worktreeinclude: copy fallback also failed for %s -> %s: %sz*Error copying .worktreeinclude entries: %slockz--reasonzhermes pid=rS   zWorktree locked: %s (pid=%s)z(git worktree lock failed (non-fatal): %s)r   r  r  baseu   [32m✓ Worktree created:[0m z
  Branch: z
  Base:   )*r  r  printuuiduuid4hexr   mkdirr   	read_textr  r   endswithr{  r   r   r   r  r  rY   r  r   r1  r   resolver  OSErrorr  r  is_filer|  shutilcopy2is_dirr   symlinkNotImplementedErrorr/  rG  rT  copytreegetpid)r  r  r  short_idwt_namebranch_nameworktrees_dirwt_path	gitignore_ignore_entryexistingr   r   base_ref
base_labelr   include_filerepo_root_resolvedwt_path_resolvedr  entrysrcdstsrc_resolveddst_resolved_sym_err	_copy_errrT  s                               r2   _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w777 .1 "H$5$5d$;$; "GGDMMM=,,,---. . . . . . . . . . . . . . .  ; ; ;6::::::::;  Q5i@@**P*Js7||T;QdBI   
 
 !! 6!!Pfm1133   (X$*#Js7||T;PXY#'dBI (    A%%^@S@S@U@U^^^___t   BBBBCCCttttt
 	??%77L ?J>	J!%i!8!8!:!:&00$..00;;== 9& 9&

  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&Js<'8'8#c((CCCC ')<= & & &"|w66 &%K$,!" !" !"
!&$*O(+L(9(9(+C156;	%& %& %& %& %& (1 !& !& !&$*NN)G(+S)%& %& %& %& %& %& %& %&!& !&+&I9&t  	J 	J 	JLLEqIIIIIIII	J
DJ
4O")++4O4OQTU\Q]Q]^dBI 	 	
 	
 	
 	3WbikkJJJJ D D D?CCCCCCCCD G	 D 

;'
;
;<<<	
${
$
$%%%	
#z
#
#$$$Ks  $AE 6AE;E EE EE 
FE==F CI= =
J%J  J%B!V8 2,NV8 ,OV8 ODV8 /T V8 V2+V-?2U21V-2
V#<VV-V##V-'V8 -V22V8 8
W'W""W'+A.Y 
Z	$ZZ	rS   worktree_pathr$  c                 T   ddl }	 |                    g ddd||           }|j        dk    rdS |j                                        sdS |                    g ddd||           }|j        dk    rdS t          |j                                                  S # t          $ r Y dS w xY w)aQ  Return whether a worktree has commits not reachable from any remote branch.

    ``git log HEAD --not --remotes`` compares against remote-tracking refs under
    ``refs/remotes/*``. If a repo has no remote-tracking refs yet, there is no
    usable remote baseline to compare against, so treat it as having no
    "unpushed" commits.
    r   N)r  zfor-each-refz--format=%(refname)zrefs/remotesTr  F)r  logz	--oneliner  z--notz	--remotes)r  r  r  r0  r   boolr   )r  r$  r  remote_refsr   s        r2   _worktree_has_unpushed_commitsr  (  s      nnJJJdG % 
 
 !Q&&4!'')) 	5EEEdG   
 
 !!4FM''))***   tts"   'B B 
'B 3%B 
B'&B'c                     ddl }	 |                    g ddd||           }|j        dk    rdS t          |j                                                  S # t          $ r Y dS w xY w)zReturn whether a worktree has uncommitted changes (staged, unstaged, or
    untracked).

    Fails SAFE: on any error returns True so callers do not delete a worktree
    whose state they cannot determine.
    r   N)r  status--porcelainTr  )r  r  r  r  r0  r   r   )r  r$  r  r   s       r2   _worktree_is_dirtyr  G  s     	,,,dG   
 
 !!4FM''))***   tts   'A %A 
A#"A#c                    ddl }ddl}	 |                    g ddd||           }|j        dk    rdS n# t          $ r Y dS w xY wt          |                                          }d}|j                                        D ];}|	                    d          r\	 t          |t          d          d                                                                                   }b# t          $ r d}Y pw xY w|dk    s|	                    d	          r||k    r|t          d          d                                         }	 |j        d
|	          }
|
s dS t          |
                    d                    }|t          j                    k    r dS 	 ddlm}  ||          rdndc S # t          $ r Y  dS w xY w=dS )um  Classify a worktree's git lock as live, dead, or absent.

    ``hermes -w`` locks each worktree with reason ``hermes pid=<pid>`` so a
    concurrent hermes process' startup prune leaves an in-use worktree alone.
    But a *crashed* session leaves the lock behind forever, and
    ``git worktree remove --force`` (single ``-f``) refuses to remove a locked
    worktree — so dead-locked worktrees accumulate indefinitely. This lets the
    pruner tell the two apart:

    - ``"live"``  — locked and the owning pid is still running (skip it).
    - ``"dead"``  — locked but the owning pid is gone, or the reason isn't a
                    parseable hermes lock (safe to unlock + reap).
    - ``None``    — not locked at all.

    Fails SAFE toward ``"live"``: if git can't be queried at all we cannot
    prove the worktree is safe to touch, so we report it as live.
    r   Nr  r  r   r  Tr  livez	worktree lockedzlocked zhermes pid=(\d+)deadr  )_pid_exists)r   r  r  r  r   r   r  r0  r  r  rU  r   searchrE   r  r   r  gateway.statusr  )r  r  r$  r   r  r   r  currentr  rC  r=   pidr  s                r2   _worktree_lock_is_liver   \  s:   $ III666dG   
 
 !!6 "   vv -  ((**F"G((**  ??;'' 	tC$4$4$5$56<<>>??GGII   X!;!;&  #h--..)//11F	-v66A 
 vvaggajj//Cbikk!!vv666666!,S!1!1=vvv===   vvv# ( 4s4   '4 
AAAC##C21C2F**
F98F9rT  c                 0   | pt           } | sdS ddl}| d         }| d         }| d         }t          |                                          sdS t	          |d          }|r)t          d| d	           t          d
|            da dS 	 |                    ddd|gddd|           n2# t          $ r%}t          	                    d|           Y d}~nd}~ww xY w	 |                    ddd|dgddd|           n2# t          $ r%}t          	                    d|           Y d}~nd}~ww xY w	 |                    ddd|gddd|           n3# t          $ r&}t          	                    d||           Y d}~nd}~ww xY wda t          d| d	           dS )u;  Remove a worktree and its branch on exit.

    Preserves the worktree only if it has unpushed commits (real work
    that hasn't been pushed to any remote).  Uncommitted changes alone
    (untracked files, test artifacts) are not enough to keep it — agent
    work lives in commits/PRs, not the working tree.
    Nr   r   r  r  rS   r  u2   
[33m⚠ Worktree has unpushed commits, keeping: r  z4  To clean up manually: git worktree remove --force r  r  unlockTr  z*git worktree unlock failed (non-fatal): %sr  --force   zFailed to remove worktree: %s-DzFailed to delete branch %s: %su   [32m✓ Worktree cleaned up: )
r  r  r   r   r  r  r  r   r   r   )rT  r  r  r  r  has_unpushedr   s          r2   _cleanup_worktreer    sl    ##D 6lG(^F[!I==!! 1'2FFFL WwWWWXXXNWNNOOOFJ'2dBI 	 	
 	
 	
 	
  F F FA1EEEEEEEEF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
>
>
>?????sH   
B) )
C3CCC< <
D+D&&D+/E 
E>E99E>c           
      X   | 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          sG|                                 }|                     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   r  ro   ghost_session_prune_v1sessionssessions_dirr   z"Pruned %d empty TUI ghost sessionszGhost session prune skipped: %s orphaned_compression_finalize_v1z*Finalized %d orphaned compression sessionsz'Orphan compression finalize skipped: %s
auto_pruneFretention_daysr   min_interval_hoursr>   vacuum_after_pruneT)r  r  vacuumr  z%state.db auto-maintenance skipped: %s)r~  r  r   ro   get_metaprune_empty_ghost_sessionsset_metar   rT  r   r   &finalize_orphaned_compression_sessionsrD   maybe_auto_prune_and_vacuumrE   r  )

session_db_load_full_config_get_hermes_home_hermes_home_maintpruned
_prune_exc	finalized_finalize_exccfgexcs
             r2   _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		S&&'IJJ &MMOO	##$FLLL KKDi    	S 	S 	SLLBMRRRRRRRR	S ! ""&&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ss   G9 A!A? >G9 ?
B.	B)$G9 )B..G9 2AD G9 
D>D94G9 9D>>8G9 8A?G9 9
H)H$$H)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                    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max_total_size_mb  )r  r  r(  r)  z'checkpoint auto-maintenance skipped: %s)
r~  r  rD   tools.checkpoint_managerr&  rE   r  r   r   r   )r  r!  r&  r"  s       r2    _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$ ? ?@@!#''*=s"C"CDD		
 	
 	
 	
 	
 	
  E E E>DDDDDDDDDEs   ;C BC 
D
$DD
r>   max_age_hoursc           
      &   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    }
t          t          |          d          r|
snt          t          |          d          rt          | t          |          d          }|d	k    r!t                               d
|j                   |dk    re	 |                    dddt          |          gddd|            n8# t          $ r+}t                               d|j        |           Y d}~nd}~ww xY w	 |                    g ddddt          |                    }|j                                        }|                    dddt          |          dgddd|           }|j        dk    r:t                               d|j        |j                                                   |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 )uX  Remove stale worktrees and orphaned branches on startup.

    Age-based tiers (aggressive cleanup keeps ``.worktrees/`` from growing
    unbounded):
    - 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).

    Lock handling (orthogonal to age): ``hermes -w`` locks each worktree with
    reason ``hermes pid=<pid>`` so a concurrent hermes process leaves an in-use
    worktree alone. A *live*-locked worktree is skipped at any age; a
    *dead*-locked one (owning pid gone — a crashed session) is unlocked first
    so ``git worktree remove --force`` can actually reap it, otherwise those
    leftovers accumulate forever (``remove --force`` refuses a locked tree).

    Branch deletion is gated on ``git worktree remove`` succeeding, so a failed
    removal never orphans the branch (which would drop easy reachability of any
    commits still in the worktree).

    Also prunes orphaned ``hermes/*`` and ``pr-*`` local branches that
    have no corresponding worktree.
    r   Nr    r  r  r  r  r  z!Skipping live-locked worktree: %sr  r  r  r  TrS   r  z%Failed to unlock dead worktree %s: %sr  r  z--show-currentr  r  r  z Failed to remove worktree %s: %sr  r  z$Pruned stale worktree: %s (force=%s)zFailed to prune worktree %s: %s)r  r+  r   r   _prune_orphaned_branchesiterdirr  r8  r  statst_mtimer   r  rY   r  r   r   r   r  r0  r   r  r1  )r  r-  r  r+  r  nowsoft_cutoffhard_cutoffr  mtimeforce
lock_stater   branch_resultr  remove_results                   r2   _prune_stale_worktreesr=  '  s   . KKKOOl2M!!  +++
$)++C-.K*T12K&&(( GK GK||~~ 	UZ%:%:9%E%E 		JJLL)E{"" # 	 	 	H	 $ *#e**a@@@ 	 	E

A666 	 ,Is5zz1MMM
LL<ejIIIUJ#e**=#'dBI       U U UDejRSTTTTTTTTU	K&NN333#$s5zz +  M #)//11F&NN
Hc%jj)D#$	 +  M '1,, 6J 4 : : < <    HdF3#'dBI     LL?USSSS 	K 	K 	KLL:EJJJJJJJJJ	K Y'''''sJ   )C


CC.+F
G$!G

GB1K	AK		
K?!K::K?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)TrS   r  c                 ^    g | ]*}|                                 |                                 +S r   r   )r   bs     r2   r   z,_prune_orphaned_branches.<locals>.<listcomp>  s2    ZZZaPQPWPWPYPYZ		ZZZr3   r   r  zbranch refs/heads/r  r0  r  mainc                 p    g | ]2}|v|                     d           s|                     d          0|3S )zhermes/hermes-zpr-r  )r   rA  active_branchess     r2   r   z,_prune_orphaned_branches.<locals>.<listcomp>  sW       O##\\*++ $/0||E/B/B $ 	
###r3   r%  )r  r  r  r  z%Failed to prune orphaned branches: %szPruned %d orphaned branches)r  r  r  r0  r   r  r   setr  rq  rangerU  r   r   )r  r  r   all_branches	wt_resultr  head_resultr  orphanedibatchr   rF  s               @r2   r1  r1    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;0m[1mr      bold	hex_colorrR  c          	          t          |           } 	 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)zConvert a hex color like '#268bd2' to a true-color ANSI escape.

    Auto-remaps known dark-mode-tuned colors to readable light-mode
    equivalents when running on a light terminal (see
    _maybe_remap_for_light_mode + _LIGHT_MODE_REMAP).
    r  r     r  r'  z1;rO   [z38;2;;r=   z[38;2;184;134;11m)_maybe_remap_for_light_moderE   r  
IndexError_ACCENT_ANSI_DEFAULT)rS  rR  r   grA  prefixs         r2   _hex_to_ansir]    s     ,I66I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. .BB_LIGHT_MODE_CACHEz^(1|true|on|yes|y)$z^(0|false|off|no|n)$hex_strc                    | pd                                                     d          }t          |          dk    rd                    d |D                       }t          |          dk    st	          d |D                       sd S 	 t          |dd         d	          t          |dd
         d	          t          |d
d         d	          }}}n# t          $ r Y d S w xY wd|z  d|z  z   d|z  z   dz  S )NrO   r  r  c              3       K   | ]	}|d z  V  
dS )r  Nr   r   cs     r2   r   z&_luminance_from_hex.<locals>.<genexpr>  s&      %%aAE%%%%%%r3      c              3      K   | ]}|d v V  	dS )0123456789abcdefABCDEFNr   rb  s     r2   r   z&_luminance_from_hex.<locals>.<genexpr>  s(      GGa#;;GGGGGGr3   r   r  rU     gz6?g,C?g]m{?g     o@)r   lstriprU  r   allrE   r  )r_  r<   r   r[  rA  s        r2   _luminance_from_hexrj    s   	B&&s++A
1vv{{GG%%1%%%%%
1vv{{#GGQGGGGG{ta!fb//3q1vr??C!A#OOa1   tt QJ!#fqj0E99s   AC 
C"!C"c                     t           j                                        rt           j                                        sdS t	          d dD                       rdS 	 ddl} ddl}t           j                                        }|                     |          }n# t          $ r Y dS w xY w	 	 |
                    |           n?# t          $ r2 Y 	 |                     || j        |           dS # t          $ r Y dS w xY ww xY w	 t           j                            d           t           j                                         n?# t          $ r2 Y 	 |                     || j        |           dS # t          $ r Y dS w xY ww xY wddl}t!          j                    dz   }d}t!          j                    |k     r|                    |gg g |t!          j                    z
            \  }}}|sK	 t%          j        |d          }	n# t(          $ r Y n,w xY w|	sn%||	z  }d	|v sd
|v rnt!          j                    |k     t+          j        d|          }
|
s1	 	 |                     || j        |           dS # t          $ r Y dS w xY wdt.          dt0          fd} ||
                    d                     ||
                    d                     ||
                    d                    }}}d|d|d|d	 |                     || j        |           S # t          $ r Y S w xY w# 	 |                     || j        |           w # t          $ r Y w w xY wxY w)uZ  Ask the terminal for its background color via OSC 11.

    Most modern terminals reply with ]11;rgb:RRRR/GGGG/BBBB\
    within a few ms.  We wait up to 100ms total before giving up.
    Returns "#RRGGBB" or None on timeout / non-tty.

    Skipped over SSH: the round-trip routinely exceeds our 100ms budget, so a
    late reply lands after prompt_toolkit has grabbed the tty — its payload
    leaks in as typed text and the BEL terminator reads as Ctrl+G (open
    editor), trapping the user in a stray editor. Remote sessions fall back to
    COLORFGBG / env hints / the dark default instead.
    Nc              3   T   K   | ]#}t           j                            |          V  $d S r   r   r}  rD   r   vs     r2   r   z*_query_osc11_background.<locals>.<genexpr>2  0      
R
R2:>>!
R
R
R
R
R
Rr3   SSH_CONNECTION
SSH_CLIENTSSH_TTYr   z]11;?\皙?r3   @   s   \   s0   rgb:([0-9a-fA-F]+)/([0-9a-fA-F]+)/([0-9a-fA-F]+)r@   r   c                 j    t          | d          }t          |           dz  }|r|dz  d|z  dz
  z  ndS )NrU  rg     r  r   )rE   rU  )r@   ro  bitss      r2   normz%_query_osc11_background.<locals>.norm[  s?    Ar

Aq66A:D59@AG!t)q11q@r3   r  r  r  r  02X)r/  stdinrz  r0  anytermiosr~  fileno	tcgetattrr   	setcbreak	tcsetattr	TCSAFLUSHr{  r2  selectr+  	monotonicr   readr  r   r  bytesrE   r  )r  r~  fdoldr  deadlinebufr   rc  chunkr=   r{  r[  rA  s                 r2   _query_osc11_backgroundr  #  s?    9 SZ%6%6%8%8 t

R
R&Q
R
R
RRR t


Y##   tt.	MM" 	 	 	N	b'"3S99999 	 	 	DD	U		J.///J 	 	 	D	b'"3S99999 	 	 	DD	K	 	>##c)n))mmRD"b(T^=M=M2MNNGAq! B    5LCC7c>> n)) IJCPP 		b'"3S99999 	 	 	DD		AE 	Ac 	A 	A 	A 	A
 $qwwqzz""DD$4$4dd1771::6F6Fa1(1((!(((((
	b'"3S9999 	 	 	D		b'"3S9999 	 	 	D	s   ;B 
B%$B%*C  ?L   
C<
L  C* *
C87C8;C<<L   =D> =L  >
E:L  
E( (
E65E69E::A*L  %G; :L  ;
HL  HAL  I* *
I87I8;A7L  3L
LL M"L?>M?
M	MMMc                     t           t           S d} 	 dD ]}t          j                            |          pd                                                                }t                              |          rd} | a | c S t                              |          r| a | c S t          j                            d          pd                                                                }|dk    rd} | a | S |dk    r| a | S t          j                            d          pd}t          |          }|
|d	k    } | a | S t          j                            d
          pd                                }|rbd|v r|
                    d          d         n|}|                                r-t          |          }|dv rd} | a | S d|cxk    rdk     rn n| a | S t                      }	|	rt          |	          }
|

|
d	k    } | a | S t          j                            d          pd                                }|t          v rd} n# t          $ r d} Y nw xY w| a | S )NF)HERMES_LIGHTHERMES_TUI_LIGHTrO   THERMES_TUI_THEMElightdarkHERMES_TUI_BACKGROUNDr   	COLORFGBGrW  rB  >   r'  r  r   rU  TERM_PROGRAM)r^  r   r}  rD   r   r   _TRUE_REr  	_FALSE_RErj  r  isdigitrE   r  _LIGHT_DEFAULT_TERM_PROGRAMSr   )r   varro  themebg_hintbg_lumcfgbglastbgbg_colorlumtps               r2   _detect_light_moder  l  s   $  F57 	 	C$$*113399;;A~~a   $*!q!! $*!  2339r@@BBHHJJGF &MF?? &M*..!899?R$W--s]F &M,,299;; 
	"+.%<<5;;s##B''UD||~~ "YY==!F(.%!M<<<<R<<<<<(.%!M*,, 	%h//C$*!jnn^,,299;;---F   MsD   A*H6 =H6 AH6 /	H6 9;H6 5BH6 8H6 *H6 7>H6 6IIz#1A1A1Az#9A6B00z#8A5A00z#5C4500z#6B4F00z#24292Fz#0F1B26z#8A4F1Az#3A2A00)#FFF8DC#FFD700#FFBF00#B8860B#DAA520z#F1E6CFz#c9d1d9z#EAF7FFz#F5F5F5z#FFF0D4#CD7F32z#FFEFB5_LIGHT_MODE_REMAPc                     t                      s| S | r|                     d          s| S |                                 }|t          v rt          |         S | S )zoIf we're in light mode, remap a dark-mode-tuned color to a
    higher-contrast equivalent.  No-op in dark mode.r  )r  r  r  _LIGHT_MODE_REMAP_UPPER)rS  r  s     r2   rX  rX    sg       I0055 OOE'''&u--r3   c                 >    i | ]\  }}|                                 |S r   )r  )r   kro  s      r2   
<dictcomp>r    s&    NNNDAq17799aNNNr3   c                      	 ddl m}  n# t          $ r Y dS w xY wt          | dd          rdS | j        d	fd	}|| _        d| _        dS )
zuWrap SkinConfig.get_color at import time so EVERY skin color read goes
    through the light-mode remap.  Idempotent.r   )
SkinConfigN!_hermes_light_mode_hook_installedFrO   c                 b     | ||          }	 t          |          S # t          $ r |cY S w xY wr   )rX  r   )r  r  fallbackrL   _orig_get_colors       r2   _wrapped_get_colorz9_install_skin_light_mode_hook.<locals>._wrapped_get_color  sM    c844	.u555 	 	 	LLL	s    ..TrO   )hermes_cli.skin_enginer  r   r  	get_colorr  )r  r  r  s     @r2   _install_skin_light_mode_hookr    s    5555555   z>FF  *O      .J37J000s   
 
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.
    r  FrQ  skin_keyfallback_hexrR  c                >    || _         || _        || _        d | _        d S r   )	_skin_key_fallback_hex_bold_cached)r  r  r  rR  s       r2   __init__z_SkinAwareAnsi.__init__	  s#    !)
#'r3   r   c                    | j         y	 ddlm} t           |                                | j        | j                  | j                  | _         n0# t          $ r# t          | j        | j                  | _         Y nw xY w| j         S )Nr   get_active_skinrQ  )	r  r  r  r]  r  r  r  r  r   )r  r  s     r2   __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   rY   r  r  s     r2   __add__z_SkinAwareAnsi.__add__	  s    4yy5  r3   c                 &    |t          |           z   S r   r  r  s     r2   __radd__z_SkinAwareAnsi.__radd__	  s    s4yy  r3   Nc                     d| _         dS )z1Clear cache so the next access re-reads the skin.N)r  r  s    r2   resetz_SkinAwareAnsi.reset	  s    r3   )r  r   N)r  r  r  r  rY   r  r  r  r  r  r  r   r3   r2   r  r    s         (UZ ( ( ( (C (d ( ( ( (
 
 
 
 
!S !S ! ! ! !!c !c ! ! ! !     r3   r  response_borderr  [2;3mr<   c                     ddl }	 |j                                        rd|  dnt          |           S # t          $ r t          |           cY S w xY w)zGBold if stdout is a real TTY; plain text otherwise (slash-worker safe).r   NrO  r  r/  r0  rz  rY   r   r<   _syss     r2   _br  *	  sm    '+{'9'9';';G#####QG   1vv   -4 AAc                     ddl }	 |j                                        rd|  dnt          |           S # t          $ r t          |           cY S w xY w)z9Dim-italic if stdout is a real TTY; plain text otherwise.r   Nr  r  r  r  s     r2   _dr  3	  sm    )-););)=)=I%1%%%%3q66I   1vvr  c                  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_accentr  )r  r  r  r   r  s    r2   _accent_hexr  <	  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.
    rO   )	_RichText	from_ansira   s    r2   _rich_text_from_ansir  E	  s     tzr***r3   c                 4   t          | pd          j        }t          j        dd|t          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.rO   z^\s{0,3}(?:[-_]\s*){3,}$r   z^\s{0,3}(?:\*\s*){3}\s*$z^\s{0,3}#{1,6}\s+z(```+|~~~+)z	`([^`]*)`\1z!\[([^\]]*)\]\([^\)]*\)z\[([^\]]+)\]\([^\)]*\)z\*\*\*([^*]+)\*\*\*z(?<!\w)___([^_]+)___(?!\w)z\*\*([^*]+)\*\*z(?<!\w)__([^_]+)__(?!\w)z\*([^\s*][^*]*?[^\s*])\*z(?<!\w)_([^_]+)_(?!\w)z~~([^~]+)~~\n{3,}

r   )r  plainr   r   	MULTILINEr   )ra   r  s     r2   _strip_markdown_syntaxr  N	  si    ,,2E F.ENNNEF.ENNNE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.u==EF,eU;;EF>5%00EF9fe,,E;;tr3   z)(?i)(?:\b[a-z]:\\|\\\\)[^\s`]*\\\.[^\s`]*c                     d| vr| S dt           j        t                   dt          fd}t                              ||           S )af  Keep Windows path separators before hidden directories in Markdown.

    CommonMark treats ``\.`` as an escaped literal dot, so Rich Markdown would
    render ``D:\repo\.ai`` as ``D:\repo.ai``.  Doubling only that separator
    inside Windows path-looking tokens preserves the path without changing
    ordinary markdown escapes like ``1\. not a list``.
    z\.r  r   c                 T    t          j        dd|                     d                    S )Nz(?<!\\)\\(?=\.)z\\\\r   )r   r   r  )r  s    r2   _protectz=_preserve_windows_dot_segments_for_markdown.<locals>._protect|	  s!    v('5;;q>>BBBr3   )r   MatchrY   !_WINDOWS_PATH_WITH_DOT_SEGMENT_REr   )ra   r  s     r2   +_preserve_windows_dot_segments_for_markdownr  q	  sZ     DC C# C C C C -004@@@r3   c                      	 t          j        d          j        } n# t          $ r d} Y nw xY wt	          d| t          t                    z
  dz
            S )a  Display cells available inside the streamed response box.

    The streaming path indents every line by ``_STREAM_PAD`` (4 cells)
    inside an open response panel.  The realigner uses this number as
    its budget when deciding whether to keep a horizontal table or
    fall back to vertical key-value rendering.  We subtract a small
    safety margin so terminal-resize races don't push a borderline
    table into mid-cell soft-wrap.
    P   r>   r  r  r  )r  get_terminal_sizecolumnsr   maxrU  _STREAM_PADcolss    r2   _terminal_width_for_streamingr  	  sb    '119   r4#k***Q.///s    ++renderr  c                    ddl m} 	 t          j        d          j        }n# t
          $ r d}Y nw xY wt          d|dz
            }t          |pd                                          	                                }|dk    r*t          t          t          |           |                    S |d	k    rt          | pd
          S t          | pd
          j        }t          |          }t          ||          } ||          S )zGRender final assistant content as markdown, stripped text, or raw text.r   )Markdownr  r  r     r  r   r   rO   )rich.markdownr  r  r  r  r   r  rY   r   r   r  rk   r  r  r  r  )ra   r  r  r  panel_widthnormalized_moder  s          r2   _render_final_assistant_contentr  	  s#   &&&&&&'119   b$)$$K$*(++113399;;O'!! #$:4$@$@+NN
 
 	
 %#DJB/// !,,2E7>>E#E;77E8E??s   " 11r  maxlenc                 n    	 t          dt          |                     S # t          t          f$ r Y dS w xY w)NrS   r  )r  rE   r9  r  rL   s    r2   _coerce_output_history_limitr  	  sD    2s5zz"""z"   sss    44r   c                 l    t          |           at          |          at	          t                    adS )z<Configure recent CLI output replayed after terminal redraws.r  N)r  _OUTPUT_HISTORY_ENABLEDr  _OUTPUT_HISTORY_MAX_LINESr   _OUTPUT_HISTORYr   	max_liness     r2   _configure_output_historyr  	  s3     #7mm <Y G G#<===OOOr3   c                  8    t                                            d S r   )r  clearr   r3   r2   _clear_output_historyr  	  s    r3   c               #   8   K   t           } da 	 d V  | a d S # | a w xY wNT)_OUTPUT_HISTORY_SUPPRESSED)	old_values    r2   _suspend_output_historyr  	  s?       +I!%/%."""Y"....s    c                 h    t           rt          st          rd S t                              |            d S r   )r  _OUTPUT_HISTORY_REPLAYINGr  r  append)r  s    r2   _record_output_history_entryr  	  s9    " &? C] 5!!!!!r3   c                     t           rt          st          rd S t          |                               dd                              d          }|sd S |                                D ]}t          |           d S )NrO   r   )r  r  r  rY   rn  rZ   r  r  )ra   
normalizedr  s      r2   _record_output_historyr"  	  s    " &? C] T""4,,33D99J %%'' + +$T****+ +r3   c                     t           rt          sdS da	 g } t          t                    D ]y}t	          |          rF	  |            }n# t
          $ r Y )w xY wt          |t                    r|                                }n|g}| 	                    d |D                        z| r/t          t          d                    |                                n# t
          $ r Y nw xY wdadS # daw xY w)zARepaint recent output above the prompt after a full screen clear.NTc              3   4   K   | ]}t          |          V  d S r   r  r   r  s     r2   r   z)_replay_output_history.<locals>.<genexpr>
  s(      !>!>#d))!>!>!>!>!>!>r3   r   F)r  r  r  tuplecallabler   r   rY   r  extend	_pt_print_PT_ANSIr   )rendered_linesr  liness      r2   _replay_output_historyr-  	  s=    # /  $*?++ 
	? 
	?E  !EGGEE    HeS)) /!,,..E!!!>!>!>!>!>>>>> 	; htyy8899:::    %*!!!E!))))sM   'C 
AC 
AC ABC C* 
C# C* "C##C* *C.c                     t                      	 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          sQ	 t          t                                n1# t          $ r$ 	 t                      n# t          $ r Y nw xY wY nw xY w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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                      	 dd l } dd l} fd          }|A|                    |          s|                    |          r|                     |           d S d S d S # t
          $ r Y d S w xY w)Nr   c                  <    t          t                               S r   )r)  r*  r  s   r2   r  z,_cprint.<locals>._schedule.<locals>.<lambda>h
  s    9Xd^^+D+D r3   )asyncioinspectisawaitableiscoroutineensure_futurer   )_aio_inspectcoror0  ra   s      r2   	_schedulez_cprint.<locals>._scheduleZ
  s    		""""&&&&"?#D#D#D#DEEDX%9%9$%?%?8CWCWX\C]C]""4(((((    	 	 	DD	s   AA   
A.-A.)r"  prompt_toolkit.applicationr/  r0  r   r)  r*  r  r  loopr4  get_running_loopRuntimeError
is_runningcall_soon_threadsafe)ra   r/  appr>  _asynciocurrent_loopr<  r0  s   `      @r2   _cprintrF  
  s     4   OOOOOOOOO   (4..!!! Co    {'#}e<<{		htnn%%%% 	 	 	d   	 	x   |(4..!!!	
  0022       t 1 1(4..!!!     ,!!),,,,,   	htnn%%%%%% 	 	 	DDD	s    &AA
A A&%A&=B 
C%B54C5
C?CCCCC C%$C%D" "D>0D>=D>>F 
G F??
G	GGGnotec                    t          |pd                                          }|s| S t          | t                     r| r| d|  n|S t          | t                    rt          |           }t	          |          D ]o\  }}t          |t
                    rU|                    d          dk    r<t          |          }|                    dd          }|r| d| n||d<   |||<   |c S pd|dg|S | S )u;  Prepend a one-shot system-style note to a user message.

    ``message`` is normally a plain string, but when the user attaches an image
    to a vision-capable model it becomes a list of OpenAI-style content parts
    (text + ``image_url`` blocks). Naively doing ``note + "\n\n" + message``
    then raises ``TypeError: can only concatenate str (not "list") to str`` —
    e.g. running ``/model ...`` (which queues a model-switch note) and then
    sending a pasted image in the same turn.

    Returns the message with ``note`` prepended:
      * ``str``  → ``f"{note}\n\n{message}"`` (just ``note`` when empty)
      * ``list`` → note folded into the first text part, or inserted as a new
        leading ``{"type": "text"}`` part when there is no text part.
    Unknown shapes are returned unchanged (fail-open).
    rO   r  r   ra   )r   ra   )rY   r   r   r   	enumerater   rD   )messagerG  r   rM  r   mergedra   s          r2   _prepend_note_to_messagerL  y
  s)     tzr??  ""D '3 ;)0:$%%G%%%d:'4   
8W '' 	 	GAt$%% $((6*:*:f*D*Ddzz&"--8<!FD!4!4d!4!4!4$v!a..777Nr3   rO   c                     	 ddl m}  |            }n# t          $ r d}Y nw xY w|"t          |dd          rt	          |            dS t          |            dS )aZ  Print normally unless prompt_toolkit owns the live terminal.

    Bare ``print()`` output is swallowed by ``patch_stdout`` while an
    interactive ``Application`` is running, so ``/sessions`` and ``/history``
    would render nothing. Route through ``_cprint`` (prompt_toolkit-native)
    in that case, and fall back to ``print`` otherwise.
    r   r/  Nr1  F)r=  r/  r   r  rF  r  )ra   r/  rC  s      r2   _cli_visible_printrO  
  s    >>>>>>o    73u==d    "">
   .bmp.gif.ico.jpg.svg.tif.jpeg.tiff.webp.png)	is_termuxcat.pngfilenamec                    t           j                            d          dddg}|D ]D}t           j                            |          r#t           j                            |d|           c S Et           j                            dd|           S )zCReturn a realistic example media path for the current Termux setup.z~/storage/sharedz/sdcardz/storage/emulated/0z/storage/self/primaryPictures)r   r   r   isdirr   )r]  
candidatesr  s      r2   _termux_example_image_pathrb  
  s     	-..	J  < <7== 	<7<<j(;;;;;	<7<<*JAAAr3   c                    t          | pd                                          } | sdS | d         dv r| d         }d}|t          |           k     ru| |         }|dk    r|dz   t          |           k     r|dz  }=||k    r-| d|         }| |dz   d                                         }||fS |dz  }|t          |           k     u| dd         dfS d}|t          |           k     rX| |         }|dk    r+|dz   t          |           k     r| |dz            d	k    r|dz  }n|d	k    rn|dz  }|t          |           k     X| d|                             d
d	          }| |d                                         }||fS )a6  Split a leading file path token from trailing free-form text.

    Supports quoted paths and backslash-escaped spaces so callers can accept
    inputs like:
      /tmp/pic.png describe this
      ~/storage/shared/My\ Photos/cat.png what is this?
      "/storage/emulated/0/DCIM/Camera/cat 1.png" summarize
    rO   )rO   rO   r      '"r  \r  Nrd  \ )rY   r   rU  rn  )r   quoteposchtoken	remainders         r2   _split_path_inputrn  
  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)r3   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 n# t2          $ r Y dS w xY w|S )a  Resolve a user-supplied local attachment path.

    Accepts quoted or unquoted paths, expands ``~`` and env vars, and resolves
    relative paths from ``TERMINAL_CWD`` when set (matching terminal tool cwd).
    Returns ``None`` when the path does not resolve to an existing file.
    rO   Nrf  re  r  rB  rh  rd  file://filentz//rg  r  r  r  r  r   z/mnt/r<  )rY   r   r  r  rn  r   schemer   r   netlocr   r8  r   
expandvarsr   rU  isalphar   r   r   r   r  r  r   r  r  )ro  rl  expandedparsedr!  r   base_dirresolveds           r2   _resolve_attachment_pathr|  
  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 	.")++>>??$<<>>      	(8(8(:(: 	4	   ttOs7   
AD D-,D-I0 0I?>I?(J. .
J<;J<
user_inputzdict | Nonec                    t          | t                    sdS |                                 }|sdS |                    d          p|                    d          py|                    d          pc|                    d          pM|                    d          p7t	          |          dk    o/|d         d	k    o#|d
         dv o|d                                         p|                    d          p|                    d          p|                    d          p|                    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../rq  r  r  r  r  >   r  rg  r   z"/z"~z'/z'~z"./z"../z'./z'../rg  rd  rO   )r   is_imagerm  rd  c                 $    g | ]\  }}|d k    |S )rd  r   )r   idxrk  s      r2   r   z%_detect_file_drop.<locals>.<listcomp>l  s!    OOO73R3YY3YYYr3   )r   rY   r   r  rU  rw  r|  r_   r   _IMAGE_EXTENSIONSrn  rI  reversedrZ   )r}  strippedstarts_like_pathdirect_pathfirst_tokenrm  	drop_pathspace_positionsrj  	candidater{  s              r2   _detect_file_dropr  6  s     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 u%%	N v&&	N u%%	N v&&	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  r3   attached_imagesimage_counterwidthc                 n   | sdS |pt          j        d          j        }dt          dt          dt          fd}|dk     rAt          |           dk    rd	 || d
         j        d           dS d	t          |            dS |dk     r`t          |           dk    rd	 || d
         j        d           dS  || d
         j        d          }t          |           dz
  }d	| d| dS |t          |           z
  dz   d                    fdt          t          |                     D                       S )zFormat the attached-image badge row for the interactive CLI.

    Narrow terminals such as Termux should get a compact summary that fits on a
    single row, while wider terminals can show the classic per-image badges.
    rO   r  r8  limitr   c                 h    t          |           |k    r| n| d t          d|dz
                     dz   S )Nr  r  ...)rU  r  )r8  r  s     r2   _truncz/_format_image_attachment_badges.<locals>._trunc  s:    4yyE))ttt4Gc!UQY6G6G4G/H5/PPr3   4   r  u   [📎 r   r  ]z images attached]r      z] [+rd  c              3   *   K   | ]}d |z    dV  dS )u   [📎 Image #r  Nr   )r   rM  r  s     r2   r   z2_format_image_attachment_badges.<locals>.<genexpr>  sF         	$q###     r3   )	r  r  r  rY   rE   rU  r8  r   rH  )r  r  r  r  firstextrar  s         @r2   _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?++,,     r3   pasted_textc                 ,    |                                   S )z@Auto-attach clipboard images only for image-only paste gestures.r@  )r  s    r2   ,_should_auto_attach_clipboard_image_on_paster    s      """"r3   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~rO   [201~z^[[200~z^[[201~z(^|[\s\n>:\]\)])\[200~r  z\[201~(?=$|[\s\n<\[\(\):;.,!?])z(^|[\s\n>:\]\)])00~z01~(?=$|[\s\n<\[\(\):;.,!?]))rn  r   r   r  s    r2   &_strip_leaked_bracketed_paste_wrappersr    s       	["%%	b	!	!	B			B			 	 6+UD99D64b$??D6(%66D612t<<DKr3   c                  H   	 ddl mc m}  ddlm ddlm t          | dd          rdS ddt          d	dffd
| j	        _
        d| _        t                              d           dS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)u  Patch prompt_toolkit to recover from torn bracketed-paste sequences.

    prompt_toolkit's ``Vt100Parser.feed()`` buffers all input while waiting
    for the ESC[201~ end mark.  If a terminal drops that end mark (terminal
    race, torn write, SSH glitch, macOS sleep/wake), input appears frozen
    forever — the only recovery used to be killing the tab.

    This patch wraps ``Vt100Parser.feed`` so that bracketed-paste mode
    flushes buffered content as a normal ``BracketedPaste`` event after
    ``_BP_TIMEOUT_S`` seconds without an end marker, then resumes normal
    parsing.  See upstream issue #16263.

    The patch is idempotent — repeated calls are no-ops via the
    ``_hermes_bp_timeout_patched`` sentinel on the module.
    r   NKeys)KeyPress_hermes_bp_timeout_patchedF       @r   r   c                 f   | j         rZ| xj        |z  c_        d}|| j        v r| j                            |          }| j        d |         }|                      j        |                     d| _         | j        |t          |          z   d          }d| _        d | _        |r | |           d S d S t          | dd           }t          j	                    }|	|| _        d S ||z
  
k    rp| j        }d| _         d| _        d | _        |rT|                      j        |                     t                              d||z
  t          |                     d S d S d S t          |          D ]=\  }}	| j         r | ||d                      d S | j                            |	           >d S )Nr  FrO   _hermes_bp_startuw   Bracketed-paste timeout (%.1fs) — flushed %d bytes without end mark. Terminal may have dropped ESC[201~ (see #16263).)_in_bracketed_paste_paste_bufferindexfeed_key_callbackBracketedPasterU  r  r  r+  r  r   r   rI  _input_parsersend)self_parserr   end_mark	end_indexpaste_content	remainingbp_startr5  rM  rc  _BP_TIMEOUT_S_PtKeyPress_PtKeys_patched_vt100_feeds             r2   r  zA_apply_bracketed_paste_timeout_patch.<locals>._patched_vt100_feed  s@   . /6))T1))&{888 + 9 ? ? I II$/$=jyj$IM11#G$:MJJ   7<K3 + 9!CMM122!I 13K-37K0  D++KCCCCCD D  '{4FMMH.**C'7:444x-77(3(A:?74617;4( 
'99 +G,BM R R   #NN!0 !$h #M 2 2     87

 
 &dOO 6 6DAq"6 ++KabbBBB-2215555	6 6r3   Tz:Applied Vt100Parser bracketed-paste timeout patch (#16263)z)Bracketed-paste timeout patch skipped: %s)!prompt_toolkit.input.vt100_parserinputvt100_parserprompt_toolkit.keysr  (prompt_toolkit.key_binding.key_processorr  r  rY   Vt100Parserfeedr  r   r   r   )
_vt100_modr"  r  r  r  r  s     @@@@r2   $_apply_bracketed_paste_timeout_patchr    s    @G>>>>>>>>>777777TTTTTT:;UCC 	F0	63 0	64 0	6 0	6 0	6 0	6 0	6 0	6 0	6 0	6 0	6d ':
#04
-QRRRRR G G G@#FFFFFFFFFGs   &A1 AA1 1
B!;BB!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                  `   t           j        dk    rdS t          d dD                       rdS t          j                            d          rdS t          j                            d          st          j                            d          rdS t          j                            dd	                                          d
k    rdS t          j                            dd	                                          dk    rdS dt          j                            dd	                                          v rdS dD ]v} 	 t          | ddd          5 }d|                                                                v r	 ddd            dS 	 ddd           n# 1 swxY w Y   g# t          $ r Y sw xY wdS )a  Detect environments where Ctrl+Enter must produce a newline, not submit.

    Windows Terminal, WSL, SSH sessions, Ghostty, and some modern terminals
    deliver Ctrl+Enter/Ctrl+J as bare LF (c-j). On those terminals c-j must
    NOT be bound to submit;
    binding it to submit makes Ctrl+Enter (intended as 'newline like Alt+Enter')
    submit instead. Local POSIX TTYs that deliver Enter as LF (docker exec,
    some thin PTYs without SSH) still need c-j bound to submit, so we keep
    that binding for those.

    See issue #22379.
    r  Tc              3   T   K   | ]#}t           j                            |          V  $d S r   rm  rn  s     r2   r   z/_preserve_ctrl_enter_newline.<locals>.<genexpr>>  rp  r3   rq  
WT_SESSIONGHOSTTY_RESOURCES_DIRGHOSTTY_BIN_DIRTERMrO   zxterm-ghosttyr  ghostty	microsoftWSL_DISTRO_NAME)z/proc/versionz/proc/sys/kernel/osreleaser   r   ignore)r   errorsNF)
r/  rG  r~  r   r}  rD   r   r   r  r  )r   r   s     r2   _preserve_ctrl_enter_newliner  /  s    |wt

R
R&Q
R
R
RRR t	z~~l## t	z~~-.. "*..AR2S2S t	z~~fb!!''))_<<t	z~~nb))//11Y>>tbjnn%6;;AACCCCt<  	awx@@@  A!&&((.."2"222                 2                               	 	 	H	5s<   :F*F7FFF	FF	F
F+*F+c                      |                      d          |           t          j        dk    r.t                      s" |                      d          |           dS dS dS )u  Bind terminal Enter forms to the submit handler.

    Enter is always submit. On POSIX we also bind c-j (LF) to submit because
    some thin PTYs (docker exec, certain SSH flavors) deliver Enter as LF
    instead of CR — without this, Enter appears dead on those terminals.

    Exception: on Windows, WSL, SSH sessions, Windows Terminal, and Ghostty,
    c-j is the wire encoding of Ctrl+Enter (a distinct keystroke from
    plain Enter / c-m). We leave c-j unbound there so the c-j newline
    handler registered separately can fire — giving the user an
    Enter-involving newline keystroke without terminal settings changes.
    See _preserve_ctrl_enter_newline() and issue #22379.
    enterr  c-jN)rq  r/  rG  r  )kbhandlers     r2   _bind_prompt_submit_keysr  U  se     BFF7OOG
|w'C'E'Eug r3   c                 B    	 d| j         _        dS # t          $ r Y dS w xY w)zGLet prompt_toolkit fall back from CPR without printing into the prompt.N)renderercpr_not_supported_callbackr   )rC  s    r2   #_disable_prompt_toolkit_cpr_warningr  h  s9    26///   s    
c                      t           j                            dd          dk    rdS t          d dD                       rdS dS )u  Detect terminals where CPR (ESC[6n) replies are likely to leak.

    The CPR leak in #13870 is environment-specific: it shows up over SSH +
    cloudflared/mux tunnels and slow PTYs, where the terminal's
    ``ESC[<row>;<col>R`` reply round-trips slowly enough to race past the input
    parser and land in the display as raw ``20;1R`` text (and the pending-CPR
    future can stall the renderer, freezing the prompt). On a local terminal the
    reply returns instantly and cleanly, so CPR works fine and there is nothing
    to fix — we leave prompt_toolkit's default behavior untouched there.

    We only suppress CPR on a remote/tunneled link (SSH env vars) or when the
    user has explicitly opted out via prompt_toolkit's own ``PROMPT_TOOLKIT_NO_CPR``
    escape hatch. Keeping this narrow (not the broader WSL/Ghostty/Windows set
    that ``_preserve_ctrl_enter_newline`` keys on) means the only behavior change
    lands exactly where the bug reproduces.
    PROMPT_TOOLKIT_NO_CPRrO   r   Tc              3   T   K   | ]#}t           j                            |          V  $d S r   rm  rn  s     r2   r   z)_terminal_may_leak_cpr.<locals>.<genexpr>  rp  r3   rq  F)r   r}  rD   r~  r   r3   r2   _terminal_may_leak_cprr  p  sO    " 
z~~-r22c99t

R
R&Q
R
R
RRR t5r3   c                 ~     	 ddl ddlm}m ddlm  fd} | |d          S # t          $ r Y dS w xY w)u  Build a Vt100_Output that never sends Cursor Position Report queries.

    prompt_toolkit's renderer sends ``ESC[6n`` (Device Status Report) to learn
    the cursor row before painting in non-fullscreen mode; the terminal replies
    ``ESC[<row>;<col>R``. Over SSH + cloudflared/mux tunnels and some slow PTYs
    these replies race past the input parser and land in the display as raw text
    like ``20;1R21;1R``, and the pending-CPR future can stall the renderer so the
    prompt appears frozen after the agent's final answer (see #13870).

    Constructing the output with ``enable_cpr=False`` makes the renderer mark CPR
    ``NOT_SUPPORTED`` up front, so ``ESC[6n`` is never sent and no CPR response
    can leak. This is the root-cause counterpart to the input-side scrubbing in
    ``_strip_leaked_terminal_responses`` — that cleans leaks after the fact; this
    stops them at the source. The UI is otherwise identical (prompt_toolkit uses
    its heuristic available-height fallback, which it already relies on whenever a
    terminal doesn't answer CPR).

    This is only invoked on terminals flagged by ``_terminal_may_leak_cpr()`` —
    CPR is a layout hint, not a speed optimization, and it works fine locally, so
    we leave the upstream default in place on local terminals and only suppress it
    where the leak actually reproduces.

    Note: ``Vt100_Output.from_pty()`` does NOT expose ``enable_cpr`` in
    prompt_toolkit 3.x, so we reproduce its ``get_size`` setup and call the
    constructor directly. Returns ``None`` on any failure so the caller falls back
    to prompt_toolkit's default output (CPR enabled, but input-side scrubbing
    still protects against leaks).
    r   N)Vt100_Output	_get_size)Sizec                      d x} }	                                             \  } }n## t          j        t          t          f$ r Y nw xY w | pd|pd          S )Nr>   r  )rowsr  )r  r  UnsupportedOperationAttributeErrorr  )r  r  r  r  _ior0  s     r2   _get_term_sizez2_build_cpr_disabled_output.<locals>._get_term_size  sx    !!D7 )	&--// : :ggS5~zR   4TZRB????s    ( AAF)
enable_cpr)ioprompt_toolkit.output.vt100r  r  prompt_toolkit.data_structuresr  r   )r0  r  r  r  r  r  s   `  @@@r2   _build_cpr_disabled_outputr    s    :GGGGGGGG777777	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ |FNuEEEE   tts   '. 
<<c                    | 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.
    FrV  z^[r   rW  rQ   r=   rO   r   )_DSR_CPR_ESC_REr   _SGR_MOUSE_ESC_REsubn_DSR_CPR_VISIBLE_RE_SGR_MOUSE_VISIBLE_RE_SGR_MOUSE_BARE_RE)ra   has_eschas_visiblehas_bare_mousehad_mouse_reportscounts         r2   *_strip_leaked_terminal_responses_with_metar    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-:"""r3   c                 *    t          |           \  }}|S )z2Compatibility wrapper returning only cleaned text.)r  )ra   r   rc  s      r2    _strip_leaked_terminal_responsesr    s    ;DAAJGQNr3   r  )
max_heightr,  .prompt_textterminal_columnsr  c          	         	 ddl m} n# t          $ r d }Y nw xY w	 t          |pd          }n# t          t
          f$ r d}Y nw xY wt          d|          }t          d ||pd                    }d}t          | pdg          D ]C\  }}	 ||	pd          }
|
|dk    r|ndz   }|dk    r|dz  }+|t          d| |z             z  }Dt          t          |d          t          dt          |pd                              S )u,  Estimate classic prompt_toolkit input rows using live terminal cells.

    The TextArea prompt is injected with prompt_toolkit's BeforeInput
    processor, which means it consumes cells only on logical line 0. After a
    narrow resize, that first row can leave only one input cell beside an icon
    prompt such as ``⚔ ``, while continuation rows use the full terminal width.
    Never substitute a fake wide fallback here: under- or over-allocating the
    TextArea height leaves stale prompt/input cells visible at the bottom of the
    terminal.
    r   
get_cwidthc                 $    t          | pd          S NrO   rU  r
  s    r2   r  z,_estimate_tui_input_height.<locals>.<lambda>  s    3u{#3#3 r3   r  rO   )	prompt_toolkit.utilsr  r   rE   r9  r  r  rI  min)r,  r  r  r  r  r  prompt_widthvisual_linesr  r  
line_widthdisplay_widths               r2   _estimate_tui_input_heightr    sm   "43333333 4 4 433


4&+!,,z"    !WooGq**[%6B7788LL 2$// A At  Z
++
"eqjjllaHAALLCm^w%>#?@@@LLs<##SC
a,@,@%A%ABBBs   	 / AAquery	image_argc                 r   | pd}g }t          |t                    rZt          |          }|rI|                    d          r4|                    |d                    |d         pd|d         j         d}|rjt          |          }|t          d|           |j        	                                t          vrt          d	|           |                    |           g }t                      }|D ]@}t          |          }	|	|v r|                    |	           |                    |           A||fS )
z;Collect local image attachments for single-query CLI flows.rO   r  r   rm  [User attached image: r  NzImage file not found: zNot a supported image file: )r   rY   r  rD   r  r8  r|  r  r_   r   r  rG  rq  )
r  r  rJ  imagesdroppedexplicit_pathdedupedr-  imgr  s
             r2   _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r3   z\x1b\][\s\S]*?(?:\x07|\x1b\\)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)rr  force_terminalcolor_system	highlight)r  r  _bufferr  _inner)r  r  s     r2   r  zChatConsole.__init__D  sI    xzz$	
 
 
r3   c                    | j                             d           | j                                          t          j        d          j        | j        _         | j        j        |i | | j         	                                }t                              d|          }|                    d                              d          D ]}t          |           d S )Nr   r  rO   r   )r  seektruncater  r  r  r   r  r  getvalue_OSC_ESCAPE_REr   rZ   r  rF  )r  r/   r0   outputr  s        r2   r  zChatConsole.printN  s    !"4X>>F4*6***&&((  ##B//MM$''--d33 	 	DDMMMM	 	r3   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      r2   r  zChatConsole.status\  s       




r3   N)r  r  r  r  r  r  r   r  r   r3   r2   r  r  ;  sW         
 
 
   
 
 ^
 
 
r3   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                  L   	 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          j                            d          dk    rddl	m
}	 ddl	m}
 d|
 d|	 d}n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  Nr8  r   banner_borderr  banner_titler  
banner_dimr  u$   ⚕ NOUS HERMES - AI Agent Frameworku   ⚕ NOUS HERMES
agent_nameHermes Agentz - AI Agent FrameworkHERMES_FAST_STARTUP_BANNERr   )__release_date__)__version__zHermes Agent v ()r  X   r  z
[r  	[/] [dim z]- Nous Research[/]
u   ═z
[bold u   ]╔u   ╗[/]
[bold u	   ]║[/] [z
[/] [bold u   ]║[/]
[bold u   ]║[/] [dim u   ]╚u   ╝[/]
)r  r  r   r  r  get_brandingr   r}  rD   r  r1  r2  rn   r  r  r  r  ljust)r  _skin	skin_nameborder_colortitle_color	dim_colorline1	tiny_liner.  _release_date_versionversion_linerx  innerbarcontent_widthline2s                    r2   _build_compact_bannerrG    s   ::::::!!    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		z~~233s::@@@@@@666666DDDMDDD244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rP  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  )ra   
first_words     r2   _looks_like_slash_commandrJ    sJ      ts++ uaJ jn$$r3   c                  >    t           ddlm}   |             a t           S )Nr   scan_skill_commands)_skill_commandsagent.skill_commandsrM  rL  s    r2   _ensure_skill_commandsrP    s.    <<<<<<--//r3   c                      t                      S r   )rP  r   r3   r2   get_skill_commandsrR    s    !###r3   c                      ddl m}  || i |S )Nr   )build_skill_invocation_message)rO  rT  r/   r0   _impls      r2   rT  rT    )    LLLLLL5$!&!!!r3   c                      ddl m}  || i |S )Nr   )build_preloaded_skills_prompt)rO  rY  rU  s      r2   rY  rY    s)    KKKKKK5$!&!!!r3   c                  >    t           ddlm}   |             a t           S )Nr   get_skill_bundles)_skill_bundlesagent.skill_bundlesr\  )rV  s    r2   r\  r\    s+    BBBBBBr3   c                      ddl m}  || i |S )Nr   )build_bundle_invocation_message)r^  r`  rU  s      r2   r`  r`    rW  r3   c                      	 ddl m}  t           |                                                       S # t          $ r t                      cY S w xY w)zIReturn plugin command names (without slash prefix) for dispatch matching.r   get_plugin_commands)r  rc  rG  keysr   rb  s    r2   _get_plugin_cmd_handler_namesre    se    ::::::&&((--//000   uus   .1 AAskillsc                    | sg S t          | t                    r| g}n9t          | t          t          f          rd | D             }nt          |           g}g }t	                      }|D ]_}|                    d          D ]G}|                                }|r||v r|                    |           |                    |           H`|S )zJNormalize a CLI skills flag into a deduplicated list of skill identifiers.c                 0    g | ]}|t          |          S r   r  r   items     r2   r   z*_parse_skills_argument.<locals>.<listcomp>  s#    GGGDd6Fc$ii6F6F6Fr3   rW   )	r   rY   r   r&  rG  r  r   rq  r  )rf  
raw_valuesry  r-  r   r   r!  s          r2   _parse_skills_argumentrl    s     	&# #X

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

&kk]
FUUD & &IIcNN 	& 	&DJ t!3!3HHZ   MM*%%%%	& Mr3   key_pathrL   c                    t           dz  }t          t                    j        dz  }|                                r|n|}	 |j                            dd           ddlm}  ||| |           	 t          j	        |d           n# t          t          f$ r Y nw xY wdS # t          $ r&}t                              d|           Y d	}~d
S d	}~ww xY w)a  
    Save a value to the active config file at the specified key path.
    
    Respects the same lookup order as load_cli_config():
    1. ~/.hermes/config.yaml (user config - preferred, used if it exists)
    2. ./cli-config.yaml (project config - fallback)
    
    Args:
        key_path: Dot-separated path like "agent.system_prompt"
        value: Value to save
    
    Returns:
        True if successful, False otherwise
    r   r   Tr  r   )atomic_roundtrip_yaml_updatei  zFailed to save config: %sNF)r   r   r{  r|  r   r  utilsro  r   chmodr  r  r   r   error)rm  rL   r  r  r  ro  r   s          r2   save_config_valuers    s     $m3x../2CC&6&=&=&?&?X""EXK   === 	766666$$[(EBBB	H[%((((,- 	 	 	D	 t   0!444uuuuus<    /B 0B B BB BB 
C)C

Cc                   N   e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 dEdedee         dededed	ed
ee         dededededefdZ	dFdddededefdZ
dGdZdHdeddfdZdGdZdGdZdGdZdddeddfd ZdGd!ZdId#eddfd$ZdJd#eddfd&Zd'ee         defd(Zed)edefd*            ZdKd'ee         d,edefd-ZedLd.ee         d/ed0edefd1            Zed2ee         d3edefd4            Zdeeef         fd5Zed6edefd7            Zed6ed8edefd9            Z edMd;e!eef         defd<            Z"dNd,ee         defd=Z#edNd,ee         defd>            Z$dNd?ed,ee         defd@Z%dNd,ee         defdAZ&dNd,ee         defdBZ'defdCZ(dDZ)dEZ*dGdFZ+dOdHedIeddfdJZ,dGdKZ-defdLZ.dHede/fdMZ0dN Z1defdOZ2dGdPZ3dGdQZ4dGdRZ5defdSZ6dTe7ddfdUZ8dNd,ee         fdVZ9dNd,ee         defdWZ:dX Z;dYedefdZZ<d6eddfd[Z=dGd\Z>dGd]Z?d^eddfd_Z@d` ZAdaeddfdbZBddcddeddfdeZCdfedefdgZDd6edz  defdhZEdfeddfdiZFd6eddfdjZGdGdkZHdGdlZId6eddfdmZJdGdnZKdGdoZLdpedefdqZMdefdrZNeOdsefdt            ZPdNdefduZQdGdvZRdGdwZSdGdxZTdGdyZUdz ZVd{ ZWdd|d}eXd~eddfdZYde/e         fdZZdefdZ[dede/dedz  fdZ\d6eddfdZ]deddfdZ^ddd6ede/dedefdZ_d Z`d Zad ZbdefdZcdedefdZdd Zed Zfd Zgd ZhdKdede/eXeef                  fdZidd+ddededefdZjd ZkdeddfdZldee         defdZmdPdZnd6edefdZod Zpd ZqdQdedefdZredefd            Zsd6eddfdZtdRdede/e         dededz  fdZudededz  fdZvdddedede/e!eeef                  dededz  f
dZwdedz  ddfdZxdedz  de/e!eeef                  dedz  fdZyd ZzdSde/dededdfdZ{defdZ|deddfdZ}dGdÄZ~e	 	 	 dTdededededededede!eef         fd̄            Zdeddfd̈́ZdLdeddfd΄ZdefdЄZdeddfdфZdLd6ededefdӄZdLd6ededefdԄZdՄ Zdք Zedefdׄ            Zd؄ ZdpedefdلZedededefd܄            Zd݄ ZdGdބZdGd߄Zd ZdededdfdZdefdZd ZdaefdZdUdefdZd ZdefdZd ZdVdpefdZdddeddfdZd Zd+ddefdZd ZdefdZd Zd Zd Zd Zd Zd Zd Zd Zd ZdWdpefd ZdGdZ eh d          Zedee         de!eef         fd            Z	 dNdpededee         dee         fdZdUdeddfdZd ZdGdZd	eddfd
ZdXdedededeXfdZdededeXfdZdededeXdefdZd Zd Zd6eddfdZd6efdZdefdZd Zd Zd Zd Zdededededdf
dZd  Zdefd!Zdd"dped#ed$edefd%Zdd"dped$ede/e         fd&Zd'ed(eXd)edefd*ZdGd+ZÐd, ZĐdNd-ed.edeXfd/ZŐdGd0ZƐdGd1ZǐdGd2Zdeddfd3ZɐdGd4ZʐdGd5ZːdNde/dee         fd6Z̐d7 Z͐d8 Zΐd9 Zde!eef         fd:Zdefd;Zѐd< Zdefd=ZdeXeef         fd>Zdefd?Zde/fd@Z֐dGdAZddddBde/fdCZؐdD ZdS (Y  	HermesCLIz
    Interactive CLI for the Hermes Agent.
    
    Provides a REPL interface with rich formatting, command history,
    and tool execution capabilities.
    NFr'  r  r   r(  r   r  r  r  resumer%  pass_session_idignore_rulesc                 z  $ t                      | _        t          | _        ||n t          d                             dd          | _        t          d                             dd          }|du rdnt          |          | _        t          d                             dd	          | _        t          d                             d
d          | _	        t          d                             dd          | _
        t          d                             dd          | _        t          t          d                             dd          t          d                             dd                     t          t          d                             dd                                                                                    }|dk    rd| _        n|dk    rd| _        nd| _        |t!          |          nd| _        t          d                             dd          | _        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 }	 t1          |                    dd                    }n# t2          t4          f$ r d}Y nw xY w	 t1          |                    dd                    }n# t2          t4          f$ r d}Y nw xY wt7          d |          | _        t7          d!|          | _        d"| _        d| _        d| _         d"| _!        g | _"        d| _#        i | _$        d#| _%        d| _&        t                              d$i           }t-          |t.                    r,|                    d%          p|                    d$          pd"n|pd"}d"}|p|p|| _'        tP          j)                            d&          }|r4	 t1          |          | _*        nn# t4          t2          f$ r
 d| _*        Y nTw xY wt-          |t.                    r4|                    d'          }t-          |t0                    r|nd| _*        nd| _*        | 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tQ          j0        d-          pd.| _1        d| _2        | j1        | _3        d/| _4        d| _5        g | _6        |p5t          d$                             d(d"          ptQ          j0        d0d"          pd| _7        | j7        rEtq          | j7        d1          r0|p'tQ          j0        d2          ptQ          j0        d3          | _9        n/|p'tQ          j0        d3          ptQ          j0        d2          | _9        ||| _:        nt          d4                             d5          rt          d4         d5         | _:        nt                              d5          rt          d5         | _:        nbtQ          j0        d6          rG	 t1          tQ          j0        d6d"                    | _:        n%# t2          t4          f$ r
 d7| _:        Y nw xY wd7| _:        || _;        t          d4                             d8          pg | _<        |rd|vr{d9|vrwt{          t                              d:          pi >                                          $$fd;|D             }|r,| ?                    d<d=@                    |           d>           t                              d?i           }t-          |t                     rd@|i}|
p|                    d@d          | _A        |                    dAdB          | _B        |                    dCdD          | _C        |                    dEdF          | _D        || _E        |p"tP          j)                            dG          dHk    | _F        tQ          j0        dId"          p t          d4                             dJd"          | _G        t          d4                             dKi           | _H        t          t          t                              | _K        t          t          d4                             dLd"                    | _M        t          t          d4                             dMd"                    | _O        t                              dNi           pi }|                    dO          | _P        |                    dP          | _Q        |                    dQ          | _R        |                    dR          | _S        |                    dSd          | _T        |                    dT          | _U        t                              dUi           pi }|                    dV          }d| _V        |dWvr?	 t          |          }d#|cxk    rdXk    r
n n|| _V        n# t2          t4          f$ r Y nw xY wt          t                    | _Y        d| _Z        d| _[        d| _\        d| _]        d| _^        g | __        t          ja                    | _b        d| _c        d| _d        d#| _e        d| _f        d| _g        d| _h        	 d!dYlimj}   |             | _g        n# t          $ rw}!d| _h        t          m                    dZ|!           	 t          d[          n                    d\|! d]           n"# t          $ r t          d^|!            Y nw xY wY d}!~!nd}!~!ww xY wt          | jg                   t                       d| _q        |	r|	| _r        d| _c        nF| jb        s                    d_          }"t          ju                    jv        dd`         }#|" da|# | _r        t          dbz  | _x        d#| _y        d| _^        d| _z        t          j|                    | _}        t          j|                    | _~        d| _        d| _        d| _        d| _        d!| _        d| _        d| _        d!| _        d| _        d!| _        d| _        d| _        d!| _        t          j                    | _        d| _        d!| _        d| _        d| _        d| _        d| _        d!| _        d"| _        d#| _        i | _        d"| _        d| _        d"| _        d| _        d"| _        d| _        dc| _        dd| _        i | _        d!| _        t          j                    | _        d#| _        d| _        d| _        d"| _        d#| _        d| _        d| _        g | _        d!| _        g | _        d| _        d| _        t          j                    | _        d| _        d| _        d| _        d| _        d| _        d| _        t          j                    | _        | j        =                                 d| _        d| _        t          j                    | _        d| _        d| _        d| _        d| _        i | _        d!| _        dS )ea  
        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
        Nr1  r  Ftool_progressri  r   r  r  bell_on_completer  r  r   Tr!  r  r  r  r  queuesteerr  
timestampsfinal_response_markdownr   >   r   r   r  inline_diffsuser_message_previewfirst_linesr  
last_linesr  r   rO   r9   r'  r   HERMES_MAX_TOKENS
max_tokensr   	localhostz	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   r  )r   t	mcp_namess     r2   r   z&HermesCLI.__init__.<locals>.<listcomp>  s2    ]]]Q2B12E2E]!S\J\J\qJ\J\J\r3   z%[bold red]Warning: Unknown toolsets: , [/]r%  r   max_snapshotsr  r)  r*  max_file_size_mbrS   HERMES_IGNORE_RULESr   HERMES_EPHEMERAL_SYSTEM_PROMPTr  r  r  r  provider_routingsortonlyr  orderrequire_parametersdata_collection
openroutermin_coding_score>   NrO         ?	SessionDBuM   Failed to initialize SessionDB — session will NOT be indexed for search: %sr1  u   [bold yellow]⚠ Session store unavailable[/bold yellow] — this conversation will [bold]NOT be saved[/bold] to disk and cannot be resumed later. Searching past sessions is also disabled.
  Reason: z\
  Fix the state.db store (e.g. `hermes update` to rebuild the venv) to restore persistence.ux   WARNING: Session store unavailable — this conversation will NOT be saved to disk and cannot be resumed later. Reason: %Y%m%d_%H%M%Srd  rc  z.hermes_history   gffffff?)r  console
CLI_CONFIGr   rD   r  rY   tool_progress_moder  r{  r  r  r  r   r   r  r  r  streaming_enabledshow_timestampsr  _inline_diffs_enabledr   r   rE   r9  r  r   user_message_preview_first_linesuser_message_preview_last_lines_stream_buf_stream_started_stream_box_opened_reasoning_preview_buf_stream_table_buf_in_stream_table_pending_edit_snapshots_last_input_mode_recovery!_input_mode_recovery_notice_shownr'  r   r}  r  hermes_cli.runtime_providerr  _model_is_default_explicit_api_key_explicit_base_urlr   requested_provider_provider_sourcer   api_modeacp_commandacp_argsr   rv   r(  r  enabled_toolsetsr  rG  rd  _console_printr   checkpoints_enabledcheckpoint_max_snapshotscheckpoint_max_total_size_mbcheckpoint_max_file_size_mbrw  rx  r  r  r   r   prefill_messagesr   reasoning_configr   r  _provider_sort_providers_only_providers_ignore_providers_order_provider_require_params_provider_data_collection_openrouter_min_coding_scorerC   r   _fallback_model_active_agent_route_signaturer   _tool_callbacks_installed_tirith_security_checked_appconversation_historyr	   r5  session_start_resumed_prompt_start_time_prompt_duration_last_turn_finished_at_session_db_session_db_unavailablehermes_stater  r   r   r   r  r#  r,  _pending_titler  strftimer  r  r  r   _history_file_last_invalidate_agent_runningr|  Queue_pending_input_interrupt_queue_last_turn_interrupted_should_exit_delete_session_on_exit_pending_relaunch_last_ctrl_c_time_clarify_state_clarify_freetext_clarify_deadline_sudo_state_sudo_deadline_modal_input_snapshot_approval_state_approval_deadliner:  Lock_approval_lock_slash_confirm_state_slash_confirm_deadline_model_picker_state_pending_resume_sessions_pending_agent_seed_secret_state_secret_deadline_spinner_text_tool_start_time_pending_tool_info_last_scrollback_tool_command_running_command_status_pet_renderer	_pet_slug_pet_enabled	_pet_cols
_pet_scale_pet_frames_cache_pet_frame_idx	_pet_lock_pet_cfg_checked_pet_anim_running_pet_anim_thread
_pet_event_pet_event_until_pet_reasoning_pet_turn_error_attached_images_image_counterpreloaded_skills_startup_skills_line_shown_active_session_lease_voice_lock_voice_mode
_voice_tts_voice_recorder_voice_recording_voice_processing_voice_continuousEvent_voice_tts_done_status_bar_visible#_status_bar_suppressed_after_resize_resize_recovery_lock_resize_recovery_timer_resize_recovery_pending_status_bar_unsuppress_timer_last_resize_width_background_tasks_background_task_counter)%r  r'  r  r   r(  r   r  r  r  rv  r%  rw  rx  _raw_tp_bim_ump_ump_first_lines_ump_last_lines_model_config_config_model_DEFAULT_CONFIG_MODEL_env_mt_mt	_base_urlr  	_detectedinvalidcp_cfgpr_or_cfg
_raw_score_fr  r   timestamp_str
short_uuidr  s%                                       @r2   r  zHermesCLI.__init__T  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 )3778H%PP!y)--.A4HH +//0MsSS	
 	
 	
 	
 :i(,,->LLMMSSUU[[]]7??#*D  W__#*D  #.D  )0(;tG}}} ",I!6!:!:;!N!N))488uMM'*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
*..!455 		#'"%g,,	* ' ' '"&'t,, 	###L11C%/S%9%9CcctDOO"DO:...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.// 	 $!$RY/F%K%K!L!Lz* $ $ $!#$  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%,2JJ7JC,P,P)+1::6H"+M+M(.
 )XBJNN;P,Q,QUX,X I6;; <'"&&;; 	 (044_bII !7*:66!
 !

 !8w##$6;;!
 !
 7w##NB77
 

 ^^.339r ffVnn!vvf~~!#!1!1 "w(*/CU(K(K%)+0A)B)B&
 ..r228b[[!344
=A)Z'':&&"#########8:D5z*     2*==
 .2* %)
).&(-%	 ;=!%\^^ 48'*7;#',$	......(y{{D 	 	 	 ,0D(NNjlmnnn
 t$$$**r "#r r r       NJKN N    )	> 	't'7888
 	)*** .2  	>$DO DMM .77HHM)"1"-J!.====DO *,=='*	
 $#kmm %
 ',#!
 (-$
 48!""!&!"%)"#"#'n..$(!'($#'  )-% $( ! !"$'*(**," %! " "' !$')#$"))'*', $!'*$)%*,.+-*/'%)" %>++ # %!&!&(00  """ $(  490%.^%5%5"&*#(-% -1)
 #' ?A()%%%s   #L2 2MM#M0 0NNR R10R1"']
 
]%$]%&k= =lln0 0
p1:"p,'pp,p$!p,#p$$p,,p1r  r  surfacer1  r   c                   | j         dS 	 ddlm}  || j        || j                  \  }}n3# t
          $ r&}t                              d|           Y d}~dS d}~ww xY w|r9|rt          |t          j
                   n|                     d| d	           d
S || _         	 t          j        | j                   n# t
          $ r Y nw xY wdS )z8Claim a global active-session slot for this CLI process.NTr   )try_acquire_active_session)r  r>  r   z'Failed to claim active session slot: %srr  z
[bold red]r  F)r  hermes_cli.active_sessionsr@  r  r   r   r   r   r  r/  r1  r  atexitregisterrt  )r  r>  r1  r@  leaserJ  r"  s          r2   _claim_active_sessionzHermesCLI._claim_active_session$  s+   %14
	MMMMMM77?{  NE77
  	 	 	NNDcJJJ44444	  	 ?gCJ/////##$=$=$=$=>>>5%*"	OD89999 	 	 	D	ts&   !- 
AAA#B= =
C
	C
c                     t          | dd           }|d S 	 |                                 n,# t          $ r t                              dd           Y nw xY wd | _        d S # d | _        w xY w)Nr  z%Failed to release active session slotTr  )r  releaser   r   r   r  )r  rE  s     r2   rt  z!HermesCLI._release_active_session@  s    5t<<=F	.MMOOOO 	Q 	Q 	QLL@4LPPPPP	Q *.D&&&D&----s&   , A! &AA! AA! !	A*      ?min_intervalc                     t          | dd          rdS t          j                    }t          | d          rA| j        r<|t          | dd          z
  |k    r&|| _        | j                                         dS dS dS dS )u  Throttled UI repaint for high-frequency background updates.

        Use this for spinner frames, streaming token flushes, and other
        repaints that can fire many times per second — the throttle prevents
        terminal blinking on slow/SSH connections, and the resize-recovery
        guard avoids stamping footer/status-bar chrome into scrollback while a
        SIGWINCH reflow is in flight.

        Do NOT use this for user-blocking modal prompts (approval / clarify /
        sudo). Those are rare, one-shot, user-blocking events that must paint
        immediately; route them through ``self._app.invalidate()`` directly, the
        same way the modal key-binding handlers already do. Sending a modal's
        entry paint through this throttle lets an unrelated background repaint
        within the 250ms window — or an in-flight resize — silently drop it, so
        the prompt never renders and times out unseen (#41098).
        r%  FNr  r  r9   )r  r+  r  rS  r  r  
invalidate)r  rJ  r5  s      r2   _invalidatezHermesCLI._invalidateK  s    " 43U;; 	Fn4   	#TY 	#C'$HZ\_:`:`4`eq3q3q$'D!I  """""	# 	# 	# 	#3q3qr3   c                 |    t          | dd          }|(	 |                                 dS # t          $ r Y dS w xY wdS )uA  Immediate, unthrottled repaint for user-blocking modal prompts.

        Background-thread callbacks (approval / clarify / sudo) set their modal
        state then call this to make the panel visible at once. It deliberately
        bypasses the ``_invalidate`` throttle and resize-recovery guard — a
        modal the user is actively waiting on must never be dropped — mirroring
        the direct ``event.app.invalidate()`` the modal key-binding handlers
        already use. See ``_invalidate`` for why the throttle must not gate
        these paints (#41098).
        r  N)r  rL  r   r  rC  s     r2   
_paint_nowzHermesCLI._paint_nowc  s^     dFD))?         ?s   + 
99c                     t          | dd          }|sdS |                     |           t                       	 |                                 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  N)r  _clear_prompt_toolkit_screenr-  rL  r   rO  s     r2   _force_full_redrawzHermesCLI._force_full_redrawu  s     dFD)) 	F))#...   	NN 	 	 	DD	s   A 
AAc                 r    	 ddl m}  |             n# t          $ r Y nw xY w|                                  dS )u  Recover the terminal after an interrupted agent turn (#33271).

        When the user interrupts a running turn by typing a new message,
        prompt_toolkit may have an in-flight ``CSI 6n`` cursor-position query
        whose reply (``ESC[<row>;<col>R``) arrives on stdin after the input
        parser has torn down. The reply then leaks as literal text
        (``^[[19;1R``) and the VT100 parser can stall in a partial-escape
        state, accepting no further keystrokes — the terminal appears frozen.

        Two steps recover a sane state:
          1. ``flush_stdin()`` drains stray escape bytes from the OS input
             buffer (``termios.tcflush(TCIFLUSH)``; no-op on non-TTY).
          2. ``_force_full_redraw()`` drops prompt_toolkit's cached
             screen/cursor state and forces a clean repaint.

        Both steps are independently safe and self-guard, so a failure of one
        never prevents the other.
        r   )flush_stdinN)hermes_cli.curses_uirU  r   rS  )r  rU  s     r2   !_recover_terminal_after_interruptz+HermesCLI._recover_terminal_after_interrupt  s^    &	888888KMMMM 	 	 	D	!!!!!s    
  rebuild_scrollbackrY  c                h   	 |j         }|j        }|                                 |                                 |r'	 |                    d           n# t
          $ r Y nw xY w|                    dd           |                                 |                    d           dS # t
          $ r Y dS w xY w)z;Clear the terminal and reset prompt_toolkit renderer state.z[3Jr   F)leave_alternate_screenN)	r  r&  reset_attributeserase_screen	write_rawr   cursor_gotor2  r  )r  rC  rY  r  outs        r2   rR  z&HermesCLI._clear_prompt_toolkit_screen  s    	|H/C  """! MM),,,,    DOOAq!!!IIKKK NN%N88888 	 	 	DD	s5   8B# A B# 
AB# AAB# #
B10B1c                 \   d| _         	 |                                 }n# t          $ r d}Y nw xY wt          | dd          }|duo||k    }|r7	 |                     |d           t                       n# t          $ r Y nw xY w||| _         |             |                     |           dS )uN  Recover a resized classic CLI without desynchronizing cursor state.

        Unlike _force_full_redraw, we do NOT clear the physical screen or
        scrollback here.  The startup banner and tool summary are printed
        before prompt_toolkit owns the live chrome, so they live in normal
        terminal scrollback.  Erasing the screen on SIGWINCH removes that
        startup UI and ``_replay_output_history`` cannot reconstruct it
        (the banner was never added to ``_OUTPUT_HISTORY``).

        Let prompt_toolkit's own resize path run with its renderer cursor
        cache intact. Its Application._on_resize() starts with
        renderer.erase(leave_alternate_screen=False), which needs the cached
        cursor position to move back to the live prompt origin before
        erase_down(). Resetting the renderer before that erase loses the
        origin and can leave stale prompt glyphs after a narrow resize.

        We also flag ``_status_bar_suppressed_after_resize`` so the dynamic
        status bar and input separator rules stay hidden while the terminal
        reflow settles.  On column shrink the terminal reflows already-rendered
        status bar rows into scrollback before prompt_toolkit can erase them;
        drawing a fresh full-width bar immediately makes the old and new
        versions look duplicated (#19280, #22976).

        Suppression alone is not enough on a WIDTH change.  prompt_toolkit's
        ``renderer.erase()`` does ``cursor_up(_cursor_pos.y)`` + ``erase_down()``
        using the ``_cursor_pos.y`` cached from the LAST render at the OLD
        width (renderer.py).  When the column count shrinks, the terminal
        reflows each already-painted full-width chrome row into 2+ physical
        rows, so the cached ``y`` undershoots: ``cursor_up`` does not climb
        past the reflowed rows and ``erase_down`` leaves the stale bar stranded
        ABOVE the live origin.  The next paint then stacks a fresh bar below it
        — the duplicated-status-bar report (two bars, two elapsed readings).
        Suppression hides the *new* bar but never erases the already-reflowed
        *old* one, so the ghost survives the whole suppression window.

        Fix: on a width change, wipe the visible viewport with ``erase_screen``
        (CSI 2J) BEFORE delegating to prompt_toolkit's resize, then let its
        repaint redraw from a clean origin.  This is banner-safe: 2J clears
        only the visible screen, NOT scrollback history (that is CSI 3J, which
        we do not send here — ``rebuild_scrollback=False``), so the startup
        banner that scrolled into history is preserved and
        ``_replay_output_history`` is not needed.  Row-count-only changes skip
        the clear (no reflow, so no ghost) to avoid an unnecessary repaint.

        The suppression is transient: a short follow-up timer clears it and
        repaints once the reflow has settled, so the bar returns on its own
        during idle.  Previously the flag was only cleared on the next
        *submitted* user input, so a resize/reflow (tmux pane change, SSH
        window restore, font zoom) followed by idle left the status bar hidden
        indefinitely even while the refresh clock kept ticking (the dynamic
        chrome rendered at height 0 on every repaint).  The next-submit clear
        at the input loop remains as a fast path.
        TNr'  FrX  )r"  _get_tui_terminal_widthr   r  rR  r-  r'  _schedule_status_bar_unsuppress)r  rC  original_on_resize	new_width
prev_widthwidth_changeds         r2   _recover_after_resizezHermesCLI._recover_after_resize  s    l 480	4466II 	 	 	III	T#7>>
 "-I)z2I 	11#%1PPP&((((    &/D#,,S11111s    --%A4 4
B Bffffff?delayc                 6    	 t           dd          }|&	 |                                 n# t          $ r Y nw xY w fdfd}t          j        ||          }d|_        | _        |                                 dS # t          $ r d _        Y dS w xY w)zClear the post-resize status-bar suppression after the reflow settles.

        Debounced: a fresh resize cancels the pending unsuppress and restarts
        the timer, so a resize storm only repaints the bar once it stops.
        r&  Nc                  b    d_         	                                   d S # t          $ r Y d S w xY w)NF)r"  rL  r   )rC  r  s   r2   _clearz9HermesCLI._schedule_status_bar_unsuppress.<locals>._clear  sH    ;@8NN$$$$$    DDs     
..c                      	 t          dd           } n# t          $ r d } Y nw xY w| (	 |                                d S # t          $ r Y nw xY w              d S )Nr>  )r  r   rB  )r>  rm  rC  s    r2   _firez8HermesCLI._schedule_status_bar_unsuppress.<locals>._fire%  s     "355DD       DDD #11&999$   s    $$A 
AATF)	r  cancelr   r:  Timerr7  r&  r<  r"  )r  rC  rj  	old_timerro  timerrm  s   ``    @r2   rc  z)HermesCLI._schedule_status_bar_unsuppress  s    "	=&DdKKI$$$&&&&    D           OE511EEL05D-KKMMMMM 	= 	= 	=7<D4444	=s-   B . B 
;B ;AB BBQ?c                     	 t           dd          }t           dd          t          j                     _         fd5  |&	 |                                 n# t
          $ r Y nw xY wd _        t          j        |fd          d_         _	        
                                 ddd           dS # 1 swxY w Y   dS # t
          $ r! d _                                        Y dS w xY w)zHDebounce resize redraws so footer chrome is not stamped into scrollback.r$  Nr#  c                       fd}	 j         }n# t          $ r d }Y nw xY w|(	 |                    |           d S # t          $ r Y nw xY w |             d S )Nc                      5  t          dd           ur	 d d d            d S d _        d_        d d d            n# 1 swxY w Y                                   d S )Nr$  F)r  r$  r%  rh  )rC  r  rd  r  	timer_refs   r2   _run_recoveryzPHermesCLI._schedule_resize_recovery.<locals>._timer_fired.<locals>._run_recoveryD  s     > >"4)A4HHPYYY"> > > > > > > > 7;38=5	> > > > > > > > > > > > > > >
 ..s4FGGGGGs   A A  AA)r>  r   rB  )rx  ry  r>  rC  r  rd  r  s   `  r2   _timer_firedz9HermesCLI._schedule_resize_recovery.<locals>._timer_firedC  s    H H H H H H H H H 8DD       DDD #11-@@@$   s    $$A 
AATc                                  S r   r   )rz  rs  s   r2   r  z5HermesCLI._schedule_resize_recovery.<locals>.<lambda>_  s    ||E7J7J r3   F)r  r:  r  r#  rp  r   r%  rq  r7  r$  r<  rh  )r  rC  rd  rj  rr  rz  r  rs  s   ```  @@@r2   _schedule_resize_recoveryz#HermesCLI._schedule_resize_recovery:  s   )	@&>EEI4!8$??D| ~''-1*               *  
 
(!((****$   04-!/J/J/J/J/JKK#.3+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  	@ 	@ 	@,1D)&&s,>??????	@s[   AC CA)(C)
A63C5A66AC;C CC CC 'D ?D 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  class:status-bar-badr%  class:status-bar-warnzclass:status-bar-goodr   )r  r}  s     r2   _status_bar_context_stylez#HermesCLI._status_bar_context_styleg  sG    ))2.."))2**&&r3   r  c                 &    | dk    rdS | dk    rdS dS )z=Return a style class reflecting context compression pressure.rS   r  r  r  r  r   r  s    r2   _compression_count_stylez"HermesCLI._compression_count_styler  s(     B;;))A::**%%r3   rS   r  c                     t          dt          d|pd                    }t          |dz  |z            }dd|z  dt          d||z
            z  z    dS )Nr   rT   [   █   ░r  )r  r  round)r  r}  r  safe_percentfilleds        r2   _build_context_barzHermesCLI._build_context_bar{  sd    1c#|'8q99::s*e344IEFNus1efn/E/E'EFIIIIr3   prompt_start_timeprompt_durationr  c                    | |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.
        Nr9   u   ⏲ 0siQ r/  r:   r   zd r?   r=   m r<   u   ⏱u   ⏲rd  )r+  r  rE   )r  r  r  elapsedrI   r  rG   rF   r8   time_stremojis              r2   _format_prompt_elapsedz HermesCLI._format_prompt_elapsed  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$$($$$r3   last_finished_at	turn_livec                 z    |s| dS t          dt          j                    | z
            }dt          |           S )u'  Format time since the last final agent response for the status bar.

        Returns an empty string while a turn is live (the per-prompt elapsed
        timer covers that case) or before the first turn has completed.
        Compact read-out: ``✓ 42s`` / ``✓ 3m`` / ``✓ 1h 12m``.
        NrO   r9   u   ✓ )r  r+  rJ   )r  r  idles      r2   _format_idle_sincezHermesCLI._format_idle_since  sI      	(023	&66775-d33555r3   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|                     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dddd#}	 t          | d$d           }|rt	          |          |d%<   n# t          $ r Y nw xY w	 dd&lm} |                                |d'<   n# t          $ r Y nw xY w	 dd(lm}  |            |d)<   n# t          $ r Y nw xY w|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           }	|	rt          |	d+d          pd}
|
dk     rd}
t          |	dd          pd}|dk     rd}|
|d<   |pd |d<   t          |	d,d          pd|d"<   |r4t          dt'          d-t)          |
|z  d-z                                |d<   |S ).Nr   r'  unknownr  rB  z.gguf      r  r9   
model_namemodel_shortdurationprompt_elapsedr  r  )r  
idle_sincer  )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)active_background_tasksactive_background_processesactive_background_subagentsr(  r  process_registryr  )active_countr  context_compressorlast_prompt_tokenscompression_countrT   )r  r'  r  r  rU  r  r	   r5  r  total_secondsrJ   r  r  r   tools.process_registryr  count_runningrL  r  r  r  )r  r   r  r  elapsed_secondssnapshotbg_tasksr  _async_active_count
compressorr  r  s               r2   _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 :  	
 $116==!$(<dCC4O 2  
 a
 d
 t
  #A!
" $Q#
$ (%
& )!'
( $Q)
* (+
, #A-
.  /
0 A1
2 ()+,+,7
 
 
B	t%8$??H D69(mm23 	 	 	D	
	??????6F6T6T6V6VH233 	 	 	D		RRRRRR6I6I6K6KH233 	 	 	D	  	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*+s6   
%F0 0
F=<F=G 
G,+G,0H 
HHra   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   r   rO   )r  r  r   rU  )ra   r  s     r2   _status_bar_display_widthz#HermesCLI._status_bar_display_width  s^    	#777777:djb))) 	# 	# 	#tzr??"""	#s    33	max_widthc                    |dk    rdS 	 ddl m} n# t          $ r d}Y nw xY w|                     |          |k    r|S d}|                     |          }||k    r
|d|         S g }d}|D ]F}|r ||          nt	          |          }	||	z   |z   |k    r n|                    |           ||	z  }Gd                    |                                          |z   S )z.Trim status-bar text to a single terminal row.r   rO   r   Nr  )r  r  r   r  rU  r  r   rZ   )
r  ra   r  r  ellipsisellipsis_widthr`  r  rk  ch_widths
             r2   _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)r=  r  r&  get_sizer  r   r  r  )r   r  s     r2   rb  z!HermesCLI._get_tui_terminal_widthH  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.Nrv  )rb  r  r  s     r2   _use_minimal_tui_chromez!HermesCLI._use_minimal_tui_chromeV  s"    =0022Erzr3   c                     | -	 t          j        d          j        } n# t          $ r d} Y nw xY wt	          dt          | pd                    S )uR  Return the full viewport width for printed scrollback box rules.

        Previously this clamped to ``max(32, min(width, 56))`` as a defense
        against terminal-emulator reflow on column-shrink (#25975, salvaging
        #24403).  That clamp made response/reasoning borders look stubby on
        any modern wide terminal.  We now trust the prompt_toolkit
        ``_output_screen_diff`` monkey-patch landed in #26137 (salvaging
        #25981) to keep chrome out of scrollback in the first place, and
        accept that an aggressive column-shrink may visually reflow already
        printed Panel borders — that's a cosmetic artifact of stamped
        scrollback history, not a live-render bug.

        A small floor (32 cols) is kept so the box still renders on tiny
        terminals without negative ``'─' * (w - 2)`` math.
        Nr  r  r  )r  r  r  r   r  rE   r  s    r2   _scrollback_box_widthzHermesCLI._scrollback_box_width\  sc    " =0::B   2s5;B''(((s    --positionc                     |dvrt          d|           t          | dd          rdS |dk    rdS |                     |          rdndS )	zCReturn the visible height for the top/bottom input separator rules.>   topbottomzUnknown input rule position: r"  Fr   r  r  r  )r  r  r  )r  r  r  s      r2   _tui_input_rule_heightz HermesCLI._tui_input_rule_heightt  so    ,,,GXGGHHH4>FF 	1u100u0==Dqq1Dr3   c                 \    t          | dd          sdS |                     |          rdndS )zIReturn the spacer height shown above the status bar while the agent runs.r  Fr   r  r  )r  r  r  s     r2   _agent_spacer_heightzHermesCLI._agent_spacer_height~  s<    t-u55 	100u0==Dqq1Dr3   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   r  rS   Nr  )_render_spinner_textr  rb  mathr  r  ceil)r  r  spinner_liner  
text_widths        r2   _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qr3   c                    t          | dd          }|sdS t          | dd          pd}|dk    rZt          j                    |z
  }|dk    r/t          |dz            t          |dz            }}|dd|dd}n|d	d}d
| d| dS d
| S )zCReturn the live spinner/status text exactly as rendered in the TUI.r  rO   r  r   r:   02dr=   r<   z5.1f    (r4  )r  r+  r  rE   )r  txtt0r  _m_selapsed_strs          r2   r  zHermesCLI._render_spinner_text  s    dOR00 	2T-q116Q66n&&+G"}}W]++S2->->B "$333"3333 ")0000.......Czzr3   g{Gz?g      @c                    	 ddl m}m} ddlm} ddlm}  |            }t          |                    d          t                    r|                    di           ni }t          |                    d          t                    r|                    di           ni }t          |                    d                    }t          |                    dd	          pd	          }	t          |                    d
|j                  p|j                  }
|                    |
|                    dd                    }|sH| j        5  d| _        d| _        | j                                         ddd           n# 1 swxY w Y   dS |                    |	          }||j        sH| j        5  d| _        d| _        | j                                         ddd           n# 1 swxY w Y   dS | j        5  | j        &| j        |j        k    s| j        |k    s| j        |
k    r` |t          |j                  d|
|          | _        |j        | _        || _        |
| _        | j                                         d| _        d| _        ddd           dS # 1 swxY w Y   dS # t8          $ r3 | j        5  d| _        d| _        ddd           Y dS # 1 swxY w Y   Y dS w xY w)u   (Re)resolve the active pet from config — picks up live enable/disable/

        switch made via ``/pet`` or ``hermes pets`` without a restart, mirroring
        the TUI's steady poll. Cheap and fail-open: any problem disables the pet.
        r   )	constantsstore)PetRendererr  r1  petr   slugrO   scaleunicode_colsFNunicode)r  r  r  T)	agent.petr  r  agent.pet.renderr  r~  r  r   rD   r   r  rY   rC   DEFAULT_SCALEresolve_colsr  r  r  r	  r  resolve_active_petr   r  r  r  r  spritesheetr
  r   )r  r  r  r  r  r!  r1  pet_cfgr   r  r  r  r  s                r2   _pet_resolve_configzHermesCLI._pet_resolve_config  s   1	*22222222444444555555+--C0:3779;M;Mt0T0T\cggi,,,Z\G0:7;;u;M;Mt0T0T\gkk%,,,Z\G7;;y1122Gw{{62..4"55D'++gy/FGGb9KbccE))%^Q1O1OPPD ^ 3 3(-D%)-D&*002223 3 3 3 3 3 3 3 3 3 3 3 3 3 3 **400C{#*{^ 3 3(-D%)-D&*002223 3 3 3 3 3 3 3 3 3 3 3 3 3 3  ) ) &.~11~--%//)4CO,,9EX\* * *D& &)XDN%)DN&+DO*00222*+D'$(!!) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )"  	* 	* 	* * *$)!%)"* * * * * * * * * * * * * * * * * * * *	*s   EJ& 	(E=1J& =FJ& FJ& 
%J& /(G#J& #G''J& *G'+J& 0J& 7BJJ& JJ&  J!J& &K#7KK#K	K#K	K#"K#皙?statesecsc                 J    || _         t          j                    |z   | _        dS )zEBriefly force a transient reaction (wave/jump/failed) before resting.N)r  r+  r  r  )r  r  r   s      r2   
_pet_flashzHermesCLI._pet_flash  s$     $ 0 04 7r3   c                 (   | j         sdS ddlm} | j        r|                     d           dS 	 t          | j        dd          }|r ||                                          nd}n# t          $ r d}Y nw xY w|                     |rdnd           dS )	zPFlash the end-of-turn beat: failed on error, jump on a finished plan, else wave.Nr   )todos_all_donefailed_todo_storeFjumpwave)	r  agent.pet.stater  r  r  r  r   r  r   )r  r  r  dones       r2   _pet_react_turn_endzHermesCLI._pet_react_turn_end  s      	F222222 	OOH%%%F	DJt<<E38C>>%**,,///eDD 	 	 	DDD	$2F33333s   7A' 'A65A6c                 2   | j         r#t          j                    | j        k     r| j         S d| _         ddlm} t          | j        p%| j        p| j	        p| j
        pt          | dd                    } ||t          | dd          | j                  j        S )	a5  Map current CLI activity to a pet animation state.

        A transient reaction beat (wave/jump/failed) wins while it's live;
        otherwise the steady state comes from the shared
        :func:`agent.pet.state.derive_pet_state` so the CLI can't drift from the
        TUI/desktop priority order.
        rO   r   )derive_pet_stater  Nr  F)awaiting_inputbusyr}   )r  r+  r  r  r	  r  r  r  r  r  r  r  r  rL   )r  r  r  s      r2   _derive_pet_statezHermesCLI._derive_pet_state  s     ? 	#t~//$2GGG?"444444
   ;";; !; t3T::
 
  )/77)
 
 
 		r3   c                      j                                       }||S  j        g S 	                               pd} fdt	          |          D             }n# t
          $ r g }Y nw xY w| j         <   |S )z6Return (and cache) the half-block grids for one state.Nr  c                 J    g | ]}                     |j                    S )r  )cellsr  )r   rM  r  r  r  s     r2   r   z-HermesCLI._pet_frames_for.<locals>.<listcomp>'  s-    YYYqX^^E14>^BBYYYr3   )r	  rD   r  frame_countrH  r   )r  r  cachedr  gridsr  s   ``   @r2   _pet_frames_forzHermesCLI._pet_frames_for  s    '++E22M%I	((//41EYYYYYYERWLLYYYEE 	 	 	EEE	(-u%s   4A# #A21A2c                    | j         5  | j        r| j        g cddd           S |                                 }|                     |          }|sg cddd           S || j        t          |          z           }ddd           n# 1 swxY w Y   g }t          |          D ]\  }}|r|                    d           |D ]\  }}|\  }	}
}}|\  }}}}|dk    }|dk    }|s|s|                    d           9|r.|r,|                    d|	d|
d|dd|d|d|ddf           i|r"|                    d|	d|
d|ddf           |                    d|d|d|dd	f           |S )
zEReturn prompt_toolkit FormattedText for the current pet frame, or [].N)rO   r   r  )rO   rd  zfg:#02xz bg:#u   ▀u   ▄)	r  r  r  r  r  r
  rU  rI  r  )r  r  r  gridfragsyrowr  r  trtgtbtabrr  bbbatop_opbot_ops                      r2   _pet_fragmentszHermesCLI._pet_fragments-  s   ^ 	; 	;$ (:(B	; 	; 	; 	; 	; 	; 	; 	; **,,E((//E 	; 	; 	; 	; 	; 	; 	; 	; ,s5zz9:D	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; oo 	K 	KFAs )Z(((" K KV!$BB!'BBrr 	Kf 	KLL++++ K KLL"^"^"^"^"^"^"^"^b"^"^b"^"^VX"^"^"^`e!fgggg K LL"A"A"A"A"A"A"A"A5!IJJJJLL"A"A"A"A"A"A"A"A5!IJJJJK s   B,BBBBc                 $   | j         5  | j        r| j        	 ddd           dS |                     |                                           }|r|d         s	 ddd           dS t          |d                   cddd           S # 1 swxY w Y   dS )uE   Visible rows for the pet window — 0 collapses it when no pet shows.Nr   )r  r  r  r  r  rU  )r  r  s     r2   _pet_widget_heightzHermesCLI._pet_widget_heightM  s   ^ 	! 	!$ (:(B	! 	! 	! 	! 	! 	! 	! 	! (()?)?)A)ABBE a 	! 	! 	! 	! 	! 	! 	! 	! uQx==	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!s   B2B$BB	B	c                    | j         rt          j        | j                   t          j                    }|| j        z
  | j        k    r|| _        |                                  | j        si| j	        5  | xj
        dz  c_
        ddd           n# 1 swxY w Y   t          | dd          }|&	 |                                 n# t          $ r Y nw xY w| j         dS dS )zAAdvance the frame + invalidate on a timer while a pet is enabled.r  Nr  )r  r+  r,  _PET_FRAME_INTERVALr  r  _PET_CFG_INTERVALr  r  r  r
  r  rL  r   )r  r5  rC  s      r2   _pet_anim_loopzHermesCLI._pet_anim_loopW  sK   $ 	Jt/000.""CT**d.DDD(+%((***$  ) )##q(##) ) ) ) ) ) ) ) ) ) ) ) ) ) )$--CNN$$$$    D $ 	 	 	 	 	s$   1BBB-C 
CCc                     | j         rd S |                                  d| _         t          j        | j        d          | _        | j                                         d S )NTr  r7  )r  r  r:  r;  r-  r  r<  r  s    r2   _pet_start_animzHermesCLI._pet_start_animj  sc    ! 	F  """!% ) 08KTX Y Y Y##%%%%%r3   c                 `    d| _         | j        }||                    d           d | _        d S )NF333333?r  )r  r  r   )r  threads     r2   _pet_stop_animzHermesCLI._pet_stop_animr  s:    !&&KKK$$$ $r3   c                 (    t          | dd          pdS )u  Return the configured voice push-to-talk key formatted for UI.

        Shared helper so every voice-facing status line / placeholder /
        recording hint advertises the SAME label as the registered
        prompt_toolkit binding.

        Cached at startup (see ``set_voice_record_key_cache``) rather
        than re-read per render. Two reasons (Copilot round-13 on
        #19835):

        * The prompt_toolkit binding is registered once at session
          start via ``@kb.add(_voice_key)``; re-reading config per
          render meant the status bar could advertise a new shortcut
          after a config edit while the actual binding was still the
          startup chord — exactly the display/binding drift this PR
          is trying to eliminate.
        * The label is on the hot render path (status bar + composer
          placeholder invalidated every 150ms during recording), so
          reading config on every call added avoidable UI overhead.
        _voice_record_key_display_cacheNCtrl+B)r  r  s    r2   _voice_record_key_labelz!HermesCLI._voice_record_key_labely  s    * t>EEQQr3   raw_keyc                 d    	 ddl m}  ||          | _        dS # t          $ r d| _        Y dS w xY w)zPopulate the voice label cache from a raw ``voice.record_key``.

        Called at CLI startup after the prompt_toolkit binding is
        registered so the cached label always matches the live binding.
        r   )"format_voice_record_key_for_statusr7  N)hermes_cli.voicer;  r6  r   )r  r9  r;  s      r2   set_voice_record_key_cachez$HermesCLI.set_voice_record_key_cache  s_    	<KKKKKK3U3UV]3^3^D000 	< 	< 	<3;D0000	<s    //c                 (   |p|                                  }|                     |          }|                                 }| j        r|rdgS dd| dfgS | j        r|rdgS dgS |r	dd	| d
fgS | j        rdnd}| j        rdnd}dd| | d| dfgS )z>Return the voice status bar fragments for the interactive TUI.r  )class:voice-status-recordingu	    ● REC r?  u
    ● REC  z	 to stop )class:voice-statusu	    ◉ STT )r@  u    ◉ Transcribing... r@  u    🎤 rd  z	 | TTS onrO   z | Continuousu    🎤 Voice modeu     —  z to record )rb  r  r8  r  r  r  r  )r  r  r  labelttsconts         r2   _get_voice_status_fragmentsz%HermesCLI._get_voice_status_fragments  s   75577..U.;;,,..  	U GEFF35R%5R5R5RSTT! 	E =;<<CDD 	?)+<E+<+<+<=>>!_4kk""&"8@b%'^#'^t'^'^E'^'^'^_``r3   c                 .   	 |                                  }||                                 }|d         }|| dnd}|d         }|                                 }|dk     r+d|d          d	| }|r|d
z  }|                     ||          S |dk     r"d|d          |g}|                    dd          }	|	r|                    d|	            |                    dd          }
|
r|                    d|
            |                    dd          }|r|                    d|            |                    dd          }|r|                    d|            |                    |           |r|                    d           |                     d	                    |          |          S |d         r2t          |d                   }t          |d                   }| d| }nd}|                    dd          }	d|d          ||g}|	r|                    d|	            |                    dd          }
|
r|                    d|
            |                    dd          }|r|                    d|            |                    dd          }|r|                    d|            |                    |           |                    d          }|r|                    |           |                    d          }|r|                    |           |r|                    d           |                     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      · u    · ⚠ YOLOL   r  r      🗜️ r     ▶ r     ⚙ r     ⛓    ⚠ YOLOr  r  r  ctx --r  r      │ r'  Hermes)r  rb  _is_session_yolo_activer  rD   r  r   rm   rb   r   r  r'  )r  r  r  percentpercent_labelduration_labelyolo_activera   r   r  bg_countbg_proc_countbg_subagent_count	ctx_totalctx_usedcontext_labelr  r  s                     r2   _build_status_bar_textz HermesCLI._build_status_bar_text  s4   @	U4466H}446601G-4-@wMMMMdM%j1N6688KrzzKh}5KK>KK +N*D11$>>>rzz9 799=I'||NA>> <LL!:L!:!:;;;#<<(A1EE 4LL!2!2!2333 (-JA N N  9LL!7!7!7888$,LL1NPQ$R$R!$ =LL!;(9!;!;<<<^,,, -LL,,,11&++e2D2DeLLL() )28<L3MNN	5h?O6PQQ#+ 9 9i 9 9 (#<<::L5H]355}mTE 8666777||$=qAAH 0.H..///$LL)FJJM 53M33444 (-JA N N  97$577888LL(((%\\*:;;N -^,,,!l33J )Z((( )Z(((--gll5.A.A5III 	U 	U 	UTgt(D(DR$**(TTTTT	Us    BM* 
D(M* 3F6M* *'NNc           	      &     j         rt           dd           rg S 	                                  }                                 }|d         }                                 }|dk     rSdd|d         fdd|fg}|r*|                    d           |                    d	           |                    d
           nQ|d         }|| dnd}|dk     r|                    dd          }|                    dd          }	|                    dd          }
|                    dd          }dd|d         fd                     |          |fg}|rB|                    d           |                                         |          d| f           |	r/|                    d           |                    dd|	 f           |
r/|                    d           |                    dd|
 f           |r/|                    d           |                    dd| f           |	                    dd|fg           |r*|                    d           |                    d	           |                    d
           n|d         r2t          |d                   }t          |d                   }| d| }nd}                     |          }|                    dd          }|                    dd          }	|                    dd          }
|                    dd          }dd|d         fdd|fd|                     |          fd||fg}|rB|                    d           |                                         |          d| f           |	r/|                    d           |                    dd|	 f           |
r/|                    d           |                    dd|
 f           |r/|                    d           |                    dd| f           |	                    dd|fg           |                    d          }|r,|                    d           |                    d|f           |                    d          }|r,|                    d           |                    d|f           |r*|                    d           |                    d	           |                    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  rH  r  )zclass:status-bar-yolorN  )r_  rd  r  rF  rG  rI  r  r   r  r  r  rJ  rK  rL  rM  r  r  r  rO  )r  rP  )r  rd  r  r  c              3   H   K   | ]\  }}                     |          V  d S r   )r  )r   rc  ra   r  s      r2   r   z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>d  s5      XXwq$d<<TBBXXXXXXr3   rO   c              3       K   | ]	\  }}|V  
d S r   r   r   rc  ra   s      r2   r   z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>f  s&      $?$?gaT$?$?$?$?$?$?r3   r_  rd  )r!  r  r  rb  rR  r  rD   r  r  r(  rm   rb   r  sumr   r  r   r]  )r  r  r  rU  rV  r  rS  rT  r  rW  rX  rY  rZ  r[  r\  	bar_styler  r  total_width
plain_texttrimmeds   `                    r2   _get_status_bar_fragmentsz#HermesCLI._get_status_bar_fragments  s   ' 	749NPT+U+U 	Iu	P4466H 0022E%j1N6688Krzz1.0GH4+^<	  HLL!ABBBLL!FGGG67777"#45181D7$2::#+<<#B#BL'||,EqIIH$,LL1NPQ$R$RM(05RTU(V(V%52H]4KL877@@-P	E $ o%EFFFd&C&CL&Q&QSl^jSlSl%mnnn U%EFFF&?ARARAR%STTT$ Z%EFFF&?AWAWAW%XYYY( ^%EFFF&?A[HYA[A[%\]]]LL8/@"    # L%EFFF%JKKKLL!:;;;; 01 1$:8DT;U$V$V	#=hGW>X#Y#Y+3(A(Ai(A(A(0 $ > >w G GI#+<<#B#BL'||,EqIIH$,LL1NPQ$R$RM(05RTU(V(V%52H]4KL9/?9"D$;$;G$D$DE5"M2	E $ o%FGGGd&C&CL&Q&QSl^jSlSl%mnnn U%FGGG&?ARARAR%STTT$ Z%FGGG&?AWAWAW%XYYY( ^%FGGG&?A[HYA[A[%\]]]LL9/@"   
 &.\\2B%C%CN% O%FGGG&<n%MNNN!)l!;!;J! K%FGGG&<j%IJJJ" L%FGGG%JKKK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   UU( &U( (%VV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.rO   Fr   )_AGGREGATOR_PROVIDERSnormalize_model_for_provideru"   [yellow]⚠️  Normalized model 'z' to 'z' for z.[/]Tcopilot)copilot_model_api_modenormalize_copilot_model_id)r(  u*   [yellow]⚠️  Normalized Copilot model 'z'.[/]>   opencode-goopencode-zen)normalize_opencode_model_idopencode_model_api_modeu/   [yellow]⚠️  Stripped provider prefix from 'z
'; using 'zopenai-codexr  r  z' for OpenAI Codex.[/]zgpt-5.3-codex)get_codex_model_idsN)access_token)r'  r   hermes_cli.model_normalizerk  rl  r  r  r   hermes_cli.modelsrn  ro  r(  r  rr  rs  r  hermes_cli.codex_modelsrt  )r  ri  current_modelchangedrk  rl  normalized_modelrn  ro  	canonicalresolved_moderr  rs  r  fallback_modelrt  	availables                    r2   _normalize_model_for_providerz'HermesCLI._normalize_model_for_providerm  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r9  rO   r9   N)_flush_reasoning_previewr  r  rM  r  ra   s     r2   _on_thinkingzHermesCLI._on_thinking  sM     	6)))555!ZR #r3   c                     	 t          |dd          pd}|sdS t          |dd          pd}t          | d          sg | _        | j                            ||f           dS # t          $ r Y dS w xY w)u  Queue an out-of-band AgentNotice for rendering at the next clean boundary.

        Notices fire from inside the agent turn (cold-start seed during _init_agent,
        per-turn _capture_credits after the API call) — printing immediately races the
        streaming response and the line gets buried behind the prompt (see _cprint's
        bg-thread caveat). So we QUEUE here and flush in _flush_credit_notices(), called
        right after run_conversation returns. Fail-soft: never break the turn.
        ra   rO   NlevelrT  _pending_credit_notices)r  rS  r  r  r   )r  noticera   r  s       r2   
_on_noticezHermesCLI._on_notice  s    		662..4"D FGV44>E4!:;; 2/1,(//>>>>> 	 	 	DD	s   A! AA! !
A/.A/c                     	 t          | dd          }|sdS g | _        |D ]E\  }}dddt          d                    |t                    }t	          d| | t
                      FdS # t          $ r Y dS w xY w)zPrint any queued credit notices as level-colored lines. Called at turn end
        (after run_conversation) where _cprint paints cleanly above the prompt.r  Nz[31mz[33mz[32m)rr  warnsuccessrT  r  )r  r  _DIMrD   rF  _RSTr   )r  pendingr  ra   colors        r2   _flush_credit_noticeszHermesCLI._flush_credit_notices  s    	d$=tDDG +-D(& 2 2t'&) 	 
 #eT""  0U0D0$0011112 2  	 	 	DD	s   A( AA( (
A65A6r  c                     dS )uA  Notice cleared. The REPL prints lines (no persistent slot to wipe), so
        this drops any still-queued notice with that key is not tracked by key here;
        it's a no-op for rendering — kept so the agent's clear callback is bound
        symmetrically with the show callback (and so future REPL UIs can hook it).Nr   )r  r  s     r2   _on_notice_clearzHermesCLI._on_notice_clear  s	    
 	r3   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    r2   _current_reasoning_callbackz%HermesCLI._current_reasoning_callback  sB     	04#9 	0//< 	& 3 	&%%tr3   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   rd  c              3   f   K   | ],}|                                 |                                 V  -d S r   r@  r%  s     r2   r   z4HermesCLI._emit_reasoning_preview.<locals>.<genexpr>$  s<      __RVR\R\R^R^_tzz||______r3   r  r  z[thinking] r  z
  ... (z more lines))r   r  r  r  r   r  rU  r   r  rn  r   r  r  textwrapfillr  rF  r  r  )r  r  preview_text
term_widthr\  
wrap_width
paragraphsraw_paragraphs	paragraphr  r,  previews               r2   _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  r9  c          	      
   t          | dd          }|sdS 	 t          j                    j        }n# t          $ r d}Y nw xY wt          d|t          d          z
  dz
            }d}|r|}d}n^|                    d          }t          d	|d
z            }|dk    r||k    si|                    d          sT|                    d          s?|                    d          s*|                    d          s|                    d          r|d|dz            }||dz   d         }nt          |          |k    rt          d|dz            }t          t          |          t          ||d
z  z   |dz                       }	d}
dD ]'}t          |
|                    |||	                    }
(|
dk    r|d|
dz            }||
dz   d         }|r|
                                n|| _        |r|                     |           dS dS )zFlush buffered reasoning text at natural boundaries.

        Some providers stream reasoning in tiny word or punctuation chunks.
        Buffer them here so the preview path does not print one `[thinking]`
        line per token.
        r  rO   Nr  (   r  rg  r   rU  r  rB  r  z.
z!
z?
z:
r  r  r  r  )rd  	rU   !?rW   rW  r  )r  r  r  r  r   r  rU  rfindr  r  rh  r  r  )r  r9  r  r  target_width
flush_text
line_breakmin_newline_flushsearch_start
search_endcutboundarys               r2   r  z"HermesCLI._flush_reasoning_preview7  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                 N   t          | dd          r*dt          j                                        d           dnd}|                    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  Fz [dim]%H:%Mr  rO   r   r  [bold    ]●[/] [bold]r  r  r  r   Nc              3   <   K   | ]}d t          |           dV  dS z[bold]r  N_escaper%  s     r2   r   zCHermesCLI._format_submitted_user_message_preview.<locals>.<genexpr>  s4      NNT8gdmm888NNNNNNr3   r  r,  z[dim]... (+z more )[/]c              3   <   K   | ]}d t          |           dV  dS r  r  r%  s     r2   r   zCHermesCLI._format_submitted_user_message_preview.<locals>.<genexpr>  s4      JJT8gdmm888JJJJJJr3   )r  r	   r5  r  r  rU  r  r  rE   r  r  r(  r  r   )r  r}  	ts_suffixr,  r  r  headremaining_after_head
tail_counttailhidden_middle_countpreview_linesnouns                r2   &_format_submitted_user_message_previewz0HermesCLI._format_submitted_user_message_previewh  sV    t.66?:X\^^,,W55::::<> 	   &&u::??\KMM\\9L9L\\QZ\\\'$(JANNOO'H!LLMM
![))J''
\k\""1c%jj3t99&<==%9::
&08uj[\\""b!%jj3t994s4yy@"""#D S[]]RR'$q'2B2BRRyRR
 	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'''r3   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 #rO   ,\[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  r   r   z8Paste file gone or unreadable, returning placeholder: %sr   )r   r  r  r  IOErrorr   r   )r  r   s     r2   _expand_refz7HermesCLI._expand_paste_references.<locals>._expand_ref  s~    A''D&~~w~777W% & & &Y[_```{{1~~%%%&s   : AA>=A>)r   rY   r   compiler   )r  ra   paste_ref_rer  s       r2   _expand_paste_referencesz"HermesCLI._expand_paste_references  s`    $$$ 	(8(D(D:2z"QRR		& 		& 		& T222r3   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   ────────────────────────────────────────r  rO   r   r  r  N)r  r  r  rY   r  r  )r  r}  ra   s      r2   _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Yr3   c                    |sdS d| _         t          | dd          rdS t          | dd          sjd| _        |                                 }d}|dz
  t	          |          z
  }t          dt           d	| d
t          |dz
  d          z   dt                      t          | dd          |z   | _	        d| j	        v rK| j	        
                    dd          \  }| _	        t          t           | t                      d| j	        v Kt	          | j	                  dk    r-t          t           | j	         t                      d| _	        dS dS )u  Stream reasoning/thinking tokens into a dim box above the response.

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

        Once the response box is open, suppress any further reasoning
        rendering — a late thinking block (e.g. after an interrupt) would
        otherwise draw a reasoning box inside the response box.
        NTr  F_reasoning_box_opened Reasoning r  r      ┌─   ─r  r      ┐_reasoning_bufrO   r  )_reasoning_shown_this_turnr  r  r  rU  rF  r  r  r  r  r  )r  ra   rx  r_labelr_fillr  s         r2   r  z!HermesCLI._stream_reasoning_delta  s     	F*.'4-u55 	F t4e<< 	U)-D&**,,A#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 )(r3   c                    t          | dd          rt          | dd          }|r&t          t           | t                      d| _        |                                 }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  rO      └r  r     ┘_deferred_contentN)	r  rF  r  r  r  r  r  r  _emit_stream_text)r  r  rx  deferreds       r2   _close_reasoning_boxzHermesCLI._close_reasoning_box  s    40%88 	1$ 0"55C )4,,d,,---&(#**,,At::Q::D::;;;).D& t%8"==H 1)+&&&x00000	1 	11 1r3   c                    |*|                                   |                                  dS |sdS d| _        d}d}t          | dd          |z   | _        t          | d          sd| _        t          | dd	          s0| j                                        }|D ]?}|                                }d
}	 |                    ||          }|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At          | dd	          s| j        }|D ]e}|                                }t          dt          |                    D ]1}|                    |d|                   r| j        d|          } n2f|rP|                     |           |                    d          | _        | j        t          |          d         | _        dS t          | dd	          r3| j                                        }|D ]}|                    |                                          }|dk    rtd	| _        | j        r&| j        d|         }|r|                     |           | j        |t          |          z   d         }d| _        |r|                     |            dS t'          d |D                       }t          | j                  |k    rA| j        r%| j        d|          }|                     |           | j        | d         | _        dS dS )a  Line-buffered streaming callback for real-time token rendering.

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

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

        A ``None`` value signals an intermediate turn boundary (tools are
        about to execute).  Flushes any open boxes and resets state so
        tool feed lines render cleanly between turns.
        NT)z<REASONING_SCRATCHPAD>z<think>z<reasoning>z
<THINKING>z
<thinking>z	<thought>)z</REASONING_SCRATCHPAD>z</think>z</reasoning>z</THINKING>z</thinking>z
</thought>_stream_prefiltrO   _stream_last_was_newline_in_reasoning_blockFr   rB  r   r  c              3   4   K   | ]}t          |          V  d S r   r  r   r  s     r2   r   z*HermesCLI._stream_delta.<locals>.<genexpr>g  s(      ::c!ff::::::r3   )_flush_stream_reset_stream_stater  r  r  rS  r  r   findr  r   r  r  r  rU  rH  r  r  _stream_deltar  )r  ra   
_OPEN_TAGS_CLOSE_TAGSprefilt_lowerr   	tag_lowerr  r  	precedingis_block_boundarylast_nlsaferM  rC  aftermax_tag_lensafe_reasonings                     r2   r  zHermesCLI._stream_delta  s    <   $$&&&F 	F# s
y  't->CCdJ t788 	1,0D)t2E:: <	 !06688M! ( (IIKK	 #+',,YEEC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 #		I"1c#hh// " "(11)BQB-@@ "#'#7!#<D!E"  L**400048MM$4G4GD1+/+?D		

+KD(
 4.66 	 06688M"  #((55"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$F;	 	r3   c                     |sdS  j         r,t           dd          rt           dd          |z    _        dS                                    j        s|                    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 j        r+| dt!          j                                        d           }                                 }	|	dz
  t(                              |          z
  }
t-          dt.           d| dt1          |
dz
  d          z   dt2                       xj        |z  c_        t           dd          dt6          ddffdd" fd }d j        v rω j                            dd          \  } _         j        rDt=          |          st?          |          r j         !                    |           l |             n1t=          |          r" j         !                    |           d _         j"        d!k    rtG          |          } |           d j        v dS dS )#z,Emit filtered text to the streaming display.Nr  Fr  rO   r   Tr   r  response_label
   ⚕ Hermesbanner_textr  r  r  rU  r  r'  z[38;2;rW  r=   rd  r  r     ╭─r     ╮_stream_text_ansiprinted_liner   c                 d    t          rt            |  t           n
t           |             d S r   )rF  r  r  )r  _tcs    r2   	_emit_onez.HermesCLI._emit_stream_text.<locals>._emit_one  sB    h{=C==t===[JhZfJhJhiiiiir3   c                     j         } g _         d_        | sd S d                    |           }j        dk    rt	          |          }t          |t                                }|                    d          D ]} |           d S )NFr   r   )r  r  r   r  r  rk   r  r  )r  joinedblocklnr  r  s       r2   _flush_table_bufz5HermesCLI._emit_stream_text.<locals>._flush_table_buf  s    (C%'D"$)D!  YYs^^F+w66/77+F4Q4S4STTEkk$''  	" r3   r   r  )$r  r  r  r  r  rh  r  r  r7  r  r   rE   r  r  rY  r  r	   r5  r  r  ru  r  rF  _ACCENTr  r  r  rY   r  r  rh   rd   r  r  r  r  )r  ra   r  r9  rA  	_text_hex_r_gr  rx  r  r
  r  r  r  s   `            @@r2   r  zHermesCLI._emit_stream_textp  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&&
+ , , ,)+&&&,# F EE8<>>#:#:7#C#CEE**,,Aq59>>uEEEDRRRRus4!8Q7G7G/GRRDRRSSSD  d/44	jC 	jD 	j 	j 	j 	j 	j 	j	 	 	 	 	 	 	$ d&&&%)%5%;%;D!%D%D"D$" $ 
'-- 1A$1G1G *11$777 ! """"%d++ &--d333(,%+w66-d33IdOOO- d&&&&&&&s%   8<B5 5CC
AD$ $D?>D?c                 f   t          | dd          r9t          | dd          r(d| _        |                     | j                   d| _        |                                  t          | dd          }| j        r_t          | dd          rNt          | j                  st          | j                  r&| j        	                    | j                   d| _        t          | dd          rd	
                    | j                  }g | _        d| _        | j        d
k    rt          |          }t          |t                                }|                    d	          D ]0}t#          |rt$           | | t&           n
t$           |            1| j        r[| j        d
k    rt          | j                  n| j        }t#          |rt$           | | t&           n
t$           |            d| _        | j        r=|                                 }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  rO   r  r  r  Nr   r      ╰r  r     ╯)r  r  r  r  r  r  rh   rd   r  r  r   r  r  r  rk   r  r  rF  r  r  r  r  r  )r  r  r  r  r	  r  rx  s          r2   r  zHermesCLI._flush_stream  s   
 4.66 	&74IZ\^;_;_ 	&',D$""4#7888#%D  	!!###d/44 	"0%88	" &d&677	" <LDL\;];]	"
 "))$*:;;;!D 4,d33 	ZYYt566F%'D"$)D!+w66/77+F4Q4S4STTEkk$'' Z Z3X;77R7777{DXTVDXDXYYYY 	"?C?[_f?f?f)$*:;;;lpl|DX{5C55t555[BXRVBXBXYYY!D " 	?**,,Aw==5AE?==t==>>>>>	? 	?r3   c                     d| _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        g | _        d| _        dS )z3Reset streaming state before each agent invocation.rO   FTN)r  r  r  r  r  r  r  r  r  r  r  r  r  r  s    r2   r  zHermesCLI._reset_stream_state  sp    $"'!#!#( (,%%*" &(#!#!# %r3   commandc                    |                                                                 }|                    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   r   r  )r  r  	cmd_lowers      r2   _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((
++ 	,++&&r3   c                     t          t          j                    dz            t          t                    z  }t          |         S )z9Return the current spinner frame for slow slash commands.rS   )rE   r+  r  rU  _COMMAND_SPINNER_FRAMES)r  	frame_idxs     r2   _command_spinner_framez HermesCLI._command_spinner_frame&  s5    ((2-..5L1M1MM	&y11r3   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.Tr9   rJ  u   ⏳ NFrO   )r  r  rM  r  )r  r  s     r2   _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t           dd          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          }|*t          |d          r|                    |f f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.r  z3Finish the active prompt before opening the editor.current_bufferz<No active input buffer is available for the external editor.ra   rO   Tcursor_position)validate_and_handleadd_done_callbackc                 .                         |          S r   )_submit_editor_buffer)_trA  r  s     r2   r  z1HermesCLI._open_external_editor.<locals>.<lambda>^  s    0J0J10M0M r3   z Failed to open external editor: )r  rF  r  r  r  r  r  r  r  r  rS  _skip_paste_collapsera   rU  r!  open_in_editorr#  r   )r  bufferrC  target_bufferexisting_textexpanded_texttaskr"  s   `       r2   _open_external_editorzHermesCLI._open_external_editor9  sA   dFD)) 	t``Z^``aaa5  	tdd^bddeee5 	t1 	T5I 	WUY[qswMxMx 	  }A  }P 	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% !//E/JJDGD2E$F$F&&!.MMMMM   4 	 	 	tHHSH$HHIII55555	s   B7F 
G" GGc                    	 t          |dd          pd                                }n# t          $ r Y dS w xY w|sdS t          | dd          }t          |          r	 |                     |          s$d| _        ||j        r|                                 n8# t          $ r+}t          dt           d| t                      Y d}~nd}~ww xY w|                     |           ||                                 n1# |                     |           ||                                 w w xY wdS | j        rt| j        dk    r| j                            |          n| j                            |           |dd	         t%          |          d	k    rd
ndz   }t          d|            n| j                            |           |                     |           ||                                 dS dS )aV  Submit the draft an external editor left in ``buffer``.

        Invoked from the Ctrl+G done-callback so saving the editor sends the
        prompt (TUI parity) instead of leaving it sitting in the input area.
        Mirrors the idle/queue branches of the `enter` keybinding handler:
        an empty save is ignored (never submits a blank turn), a slash command
        is dispatched, otherwise the text is routed through the same input
        queues the normal Enter path uses. Runs on the prompt_toolkit event
        loop via the Task callback, so it must be cheap and non-blocking.
        ra   rO   Nr  Tr  zCommand failed: r  r  r    Queued for the next turn: )r  r   r   rJ  process_commandr  rA  exitrF  r  r  _reset_input_bufferrL  r  r  r  putr  rU  )r  r)  ra   rC  r"  r  s         r2   r%  zHermesCLI._submit_editor_buffere  sM   	FFB//52<<>>DD 	 	 	FF	 	 FdFD)) %T** 	
%++D11 #(,D%3>


 @ @ @>T>>3>>>????????@ ((000?NN$$$ ((000?NN$$$$ #F  	* 04/C{/R/RD!%%d+++X\XkXoXoptXuXu3B3iCIINN55CG<7<<====##D)))  (((?NN ?s<   %( 
669B C< 
C"!CC< CC< <.D*c                     	 |                     d           dS # t          $ r 	 d|_        Y dS # t          $ r Y Y dS w xY ww xY w)z@Clear an input buffer after a programmatic submit (best-effort).Tappend_to_historyrO   N)r  r   ra   )r  r)  s     r2   r3  zHermesCLI._reset_input_buffer  sr    	LL4L00000 	 	 	    	s    
A/
>A>Ac                    t          | dd          rdS t          | j                   t          | j                   t          | j                   	 ddlm}  || j                   n# t          $ r Y nw xY wd| _
        dS )z4Install tool callbacks that need the live prompt UI.r  FNr   r  T)r  r  _sudo_password_callbackr  _approval_callbackr  _secret_capture_callbacktools.computer_use_tool_computer_use_approval_callbackImportErrorr  )r  
_set_cu_cbs     r2   _install_tool_callbacksz!HermesCLI._install_tool_callbacks  s    44e<< 	F"4#?@@@d5666#D$ABBB	SSSSSSJt;<<<< 	 	 	D	)-&&&s   A( (
A54A5c                 R   t          | dd          rdS d| _        	 ddlm}m}  |d          }|` |            rX| j                            di           pi }|                    d	d          }|r%t          d
t           dt                      dS dS dS dS # t          $ r Y dS w xY w)zFCheck tirith availability once before tools can run terminal commands.r  FNTr   )ensure_installedis_platform_supported)log_failuresrx  tirith_enabledr  ui   ⚠ tirith security scanner enabled but not available — command scanning will use pattern matching only)r  r  tools.tirith_securityrB  rC  r   rD   rF  r  r  r   )r  rB  rC  tirith_pathsecurity_cfgrE  s         r2   _ensure_tirith_securityz!HermesCLI._ensure_tirith_security  s   43U;; 	F(,%	UUUUUUUU**>>>K"'<'<'>'>"#{z2>>D"!-!1!12BD!I!I! UT U UNRU U    	 #""" 
  	 	 	DD	s   A4B 
B&%B&c                     	 ddl m}m}  |            } ||          }|rt          |t          j        d           dS dS # t          $ r Y dS w xY w)ay  Show a startup banner if any unacked security advisories match.

        Renders a single bold-red box on stderr (so piped stdout remains
        clean) listing the worst hit and pointing at ``hermes doctor``.
        Banner-cache rate-limits this to once per 24h per advisory; full
        remediation lives behind ``hermes doctor`` so the banner stays
        small.
        r   )detect_compromisedstartup_bannerT)rr  r2  N)hermes_cli.security_advisoriesrK  rL  r  r/  r1  r   )r  rK  rL  hitsbanners        r2   _show_security_advisoriesz#HermesCLI._show_security_advisories  s    	        &%''D#^D))F ; f3:T::::::; ;  	 	 	 DD	s   ;A 
AAc           
      d   | j                                          d}t          | d          r-| j        r&t          | j        d          r| j        j        j        }t          j                    j        }| j	        p|dk     }|r6| 
                    t                                 |                                  nlt          | j        d          }t          j        dt          j                              }t%          | j         | j        ||| j        | j        || j                   t          j                            d	          d
k    r|                                  ddlm} |r||k     r| 
                                 | 
                    d|dd           | 
                    d|dd           t7          | dd          pd}d|v sd|                                v r| 
                    d| d           n/d|v r| 
                    d           n| 
                    d           ddlm} t7          | dd          pd}	 ||	          rS| 
                                 | 
                    d           | 
                    d           | 
                    d           | 
                                 dS ) z0Display the welcome banner in Claude Code style.Nr   r  r  Tr  
quiet_moder<  r  r'  r   toolsr  r  r  r   r  r   r   )MINIMUM_CONTEXT_LENGTHu'   [yellow]⚠️  Context length is only rW   u?    tokens — this is likely too low for agent use with tools.[/]z[dim]   Hermes needs at least zB tokens. Tool schemas + system prompt use a large fixed prefix.[/]r   rO   11434ollamaz*[dim]   Ollama fix: OLLAMA_CONTEXT_LENGTH=z 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[/])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  r  rS  r   r  r  r  r  r  r  r  rG  _show_statusr  r  r   r   r  r  r'  r  r   r}  rD    _show_tool_availability_warningsagent.model_metadatarV  r  r   hermes_cli.model_switchrZ  )
r  ctx_lenr  use_compactrU  r   rV  r   rZ  r  s
             r2   show_bannerzHermesCLI.show_banner  sk   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?&	 	 	 	 :>>6773>>11333 	@????? 	w!777!!!G'Q G G G    N1G  N  N  N  N   tZ44:H(""h(..2B2B&B&B##iAWiii    8####e    ##x  
 	GFFFFFT7B//52
%%j11 	!!!9   \   H   	r3   )quietsession_metarb  c                   |pi                      d          }|sdS t          j                            t	          |                    }	 t          j                    }n# t          $ r d}Y nw xY w|rBt          j                            |          t          j                            |          k    rdS t          j                            |          sPd| d|pd }|rt          |t          j                   n&|                     dt          |           d           dS 	 t          j        |           nd# t          $ rW}d	| d
| }|rt          |t          j                   n&|                     dt          |           d           Y d}~dS d}~ww xY w|t          j        d<   d| }|rt          |t          j                   dS |                     dt          |           d           dS )u!  Relaunch a resumed session in the directory it was started from.

        Idempotent and safe to call from every resume path. When the stored
        ``cwd`` differs from the current process directory, we both
        ``os.chdir()`` (so the process and any ``os.getcwd()`` fallback agree)
        and retarget ``TERMINAL_CWD`` (so the terminal tool, code-exec tool,
        and relative-path resolution all land in the same place — the local
        terminal backend snapshots cwd on first use, which happens after this).

        No-ops when: the session recorded no cwd (gateway/remote/older
        sessions), the directory no longer exists, or we're already there.
        A missing directory degrades to a single dim warning rather than a
        crash — repos get moved and deleted.
        r   Nu)   ⚠ Session's working directory is gone: u    — staying in rU   rA  z[dim]z[/dim]u0   ⚠ Could not enter session's working directory : r<  u   ↻ Working directory: )rD   r   r   r   rY   r  r  realpathr`  r  r/  r1  r  r  chdirr}  )r  rc  rb  recordedr  msgr   s          r2   _restore_session_cwdzHermesCLI._restore_session_cwd8  s:    !&B++E22 	F7%%c(mm44	ikkGG 	 	 	GGG	 	rw''11RW5E5Eg5N5NNNFw}}X&& 	hhhhX_XfcfhhC Bc
+++++##$@GCLL$@$@$@AAAF	HX 	 	 	TXTTQRTTC Bc
+++++##$@GCLL$@$@$@AAAFFFFF	 &.
>"222 	>#CJ'''''' < < < <=====s+   	A A,+A,#D8 8
FAFFc                 d   ddl m}  |            }t          j        d          j        }t          |ddd|          }t                      5  |                    |           ddd           n# 1 swxY w Y   |                                	                    d	          
                                S )
zHRender the resume panel at the current terminal width for resize replay.r   r  r  Tr  F)rr  r  r  r  r  Nr   )r  r  r  r  r  r  r  r  r$  rZ   r  )r  panelr  r  r  r  s         r2   "_render_resume_history_panel_linesz,HermesCLI._render_resume_history_panel_lineso  s    hjj(22:$
 
 
 %&& 	! 	!MM%   	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!||~~$$T**55777s   A..A25A2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_rc  rZ  TF)	hermes_cli.clipboardro  ro   r  r	   r5  r  r  r  )r  ro  img_dirtsimg_paths        r2   _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 ur3   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-rU   N)rE   rU  r  r  )r  rv  r%  r  s       r2   _resolve_checkpoint_refz!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          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.r   ry  z]52;c;r  Nr&  r^  r{  )base64	b64encodeencodedecoder  rS  r^  r2  r{  r/  r0  )r  ra   payloadseqr`  r&  s         r2   _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

r3   rC  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&  r^  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  r  rS  r^  r|  r2  r{  r/  r0  r   r   r   r  rF  r  r  )r  rC  r5  r`  r&  s        r2   _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%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.i   r  u   👁️  analyzing r3  zKB)...)	image_urluser_promptr  analysisrO   z6[The user attached an image. Here's what it contains:
zA]
[If you need a closer look, use vision_analyze with image_url: 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 retryr  zWhat do you see in this image?)r4  tools.vision_toolsr  r   r3  st_sizerF  r  r8  r  r  rY   r   loadsrD   r  r   r   r   )r  ra   r  r  rD  r  analysis_promptenriched_partsrt  size_kbresult_jsonr   descriptionr   	user_textr\  s                   r2   _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   )r   us     r2   r   z>HermesCLI._show_tool_availability_warnings.<locals>.<listcomp>!  s"    KKKQ>9JKqKKKr3   u:   [yellow]⚠️  Some tools disabled (missing API keys):[/]r  rU  Nr  z, +z moreu      [dim]• r8  z[/] [dim italic](r  r  z*[dim]   Run 'hermes setup' to configure[/])r  r  r  r   rU  r   )r  r  r  unavailableapi_key_missingrj  	tools_strs          r2   r\  z*HermesCLI._show_tool_availability_warnings  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                 J   t           j                            d          dk    rd}n.t          | j        d          }|rt          |          nd}| 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.r  r   ztools deferredTrR  r    toolsr  rB  r  N   r  u   [green bold]●[/]u   [red bold]●[/]r  r-  r  r  r  ui_labelr  )r  r  cyanrO   ri  z [dim u   ]·[/] [z]toolsets: r  r  u   ]·[/] [dim]provider: u   ]·[/] [dim]auth: r   [r  r6  u   ]·[/] [bold )r   r}  rD   r  r  rU  r'  r  r(  r  r  r  r   r   r   r  r  )r  tool_statusrU  
tool_countr  api_indicatorr  r#  separator_coloraccent_colorlabel_colortoolsets_infoprovider_infos                r2   r[  zHermesCLI._show_status/  sx    :>>6773>>*KK($:O\`aaaE',3U!J'///K 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=. .@K. ..+. .	
 	
 	
 	
 	
s   2AD DD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.titlerO   
started_at)
updated_atlast_updated_atlast_activity_atr   Nr  r   r   r  r'  r  r  FzHermes CLI StatuszSession ID: zPath: zTitle: zModel: r3  r4  z	Created: z%Y-%m-%d %H:%MzLast Activity: zTokens: rW   zAgent Running: YesNor   )r  markup)r  get_sessionr  r   rD   r   r  r	   fromtimestamprC   r  r  rp   r  r(  r  r  r   )r  rc  r  
created_atr  r  fieldrL   r   total_tokensr   r'  rA  r,  s                 r2   _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'  )rw  r  r   r  )r  r  r   r'  s       r2   _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     r2   _command_availablezHermesCLI._command_available  s$    G##//111tr3   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          |	           d           t#          |	
                                          D ]O\  }}
t                                          dt                       d|ddt          |
d                               Pt%                      }|rt          dt           dt           dt          |           d           t#          |
                                          D ]\  }}
t          |
                    dg                     }|
                    d          pd| d}t                                          dt                       d|ddt          |           d| d 	           | j                            d!i           }|rt          dt           d"t           dt          |           d#           t#          |
                                          D ]v\  }}|                    d|                    d$d                    }t                                          dt                       dd%|z   ddt          |                      wt          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 CommandsrO   7   Nr   +rN   |^
  u   ── u    ──z
    [bold r  z<15z[/] [dim]-[/] u   
  ⚡ zSkill Commandsr3  z installed):z<22r  u   
  ▣ zSkill Bundlesrf  zLoad z skillsz [dim](z skills)[/]quick_commandszQuick Commandsz configured):r   r  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  r  r  r   r   rU  rF  _BOLDr  r  r  r  r  r  r  rP  sortedr\  rD   r   r  _is_termux_environmentrb  )r  r  r  headerinner_widthcategorycommandscmddescskill_commandsrT  _bundles_nowskill_countr  r8  qcmds                   r2   	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
 011 	]u]]D]]C<O<O]]]^^^#N$8$8$:$:;;  	T##ffffffPTUbPcHdHdff    )** 	ZuZZ4ZZ3|;L;LZZZ[[[#L$6$6$8$899  	T!$((8R"8"899xx..N2N+2N2N2N##F F FH F Ft}}F F-8F F F   
 )92>> 	^u^^D^^C<O<O^^^___$^%9%9%;%;<<  
dxxtxx/C/CDD##```#*```QXY]Q^Q^``    	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.TrR  z(;_;) No tools availableNz(^_^)/ Available ToolsN   r  rN   r  rd  r  c                     | d         d         S )Nfunctionr8  r   )r  s    r2   r  z&HermesCLI.show_tools.<locals>.<lambda>  s    *f0E r3   r  r  r8  r  r  rO   r   r   . r    [r  z    * z<20z - 	  Total: u    tools  ヽ(^o^)ノ)r  r  r  rU  r  r  rD   r  r  r  rd  )
r  rU  r  r  padr  toolr8  toolsetr  s
             r2   
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:::r3   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  rN   r  rd  r  r  r  z(*)   r  z<18r  z>2z
 tools] - z  (*) = currently enabledz.  Tip: Use 'all' or '*' to enable all toolsetsz0  Example: python cli.py --toolsets web,terminalN)r  r  rU  r  rd  r  r  )
r  all_toolsetsr  r  r  r8  rT  r  r  markers
             r2   show_toolsetszHermesCLI.show_toolsets  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r3   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	}d
dlm	}  || j
                  rd}	nVt          | j
        t                    r:t          | j
                  dk    r"| j
        dd          d| j
        dd          }	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d0            t          d1| j                    t                       t          d2           t          d3| j                            d4                      t          d5| d|            t                       dS )6z4Display current configuration with kawaii ASCII art.r;  r   r<  r=  60r   r   z(loaded)z(not found)r   )is_token_providerzMicrosoft Entra IDr  Nr  r  zNot set!z(^_^) Configurationr%  r  rN   r  rd  r  z  -- Model --z  Model:     z  Base URL:  z  API Key:   z  -- Terminal --z  Environment:  sshrF  znot setrH  rJ  22z  SSH Target:   @r  z  Working Dir:  z  Timeout:      r<   z  -- Agent --z  Max Turns:  z  Toolsets:   r  ri  z  Verbose:    z  -- Session --z  Started:     z%Y-%m-%d %H:%M:%Sz  Config File: )r   r   r  r   r   r{  r|  r   agent.azure_identity_adapterr  r(  r   rY   rU  r  r'  r   r  r  r   r  r  r  )r  terminal_envterminal_cwdterminal_timeoutr  r  r  config_statusr  api_key_displayr  r  r  rE  rG  rI  s                   r2   show_configzHermesCLI.show_config%  s    y99y==9%7>>'-7"8nn36GG""$$ 	.*KK-K&1&8&8&:&:M

 	CBBBBBT\** 	)2OOc** 	)s4</@/@2/E/E!%bqb!1IIdl2336GIIOO(O%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==>>>r3   r  c           	          | j         sg S 	 ddlm}  || j         d| j        dd|dg          S # t          $ r g cY S w xY w)zCReturn recent CLI sessions for in-chat browsing/resume affordances.r   )query_session_listingr  FTr  )sourcecurrent_session_idinclude_all_sourcesinclude_unnamedr  exclude_sources)r  hermes_cli.session_listingr  r  r   )r  r  r  s      r2   _list_recent_sessionszHermesCLI._list_recent_sessions_  s     	I	HHHHHH(( #'?$) $!'     	 	 	III	s   ". ==history)rC  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ddd 
           t          dd dd dd dd dd 
           t	          |d          D ]\  }}|                    d          pd}|                    d          pddd         } ||                    d                     }	t          d|d
d|dd|dd|	dd|d!          
           t                       t          d"           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  r  z<3rd  Titlez<32Previewz<40zLast Activez<13IDu	   ───u`   ────────────────────────────────r  u'   ─────────────uH   ────────────────────────r  )r<  r  u   —r  rO   N&   last_activeidzU  Use /resume <number>, /resume <session id>, or /resume <session title> to continue.z  Example: /resume 2T)r	  hermes_cli.mainr	  rO  rI  rD   )
r  rC  r  r  r	  r  sessionr  r  r
	  s
             r2   _show_recent_sessionszHermesCLI._show_recent_sessionsr  s   
 --E-:: 	5222222Ywxxxx3444aaaaaaayaaa}aaa[_aabbb_	__J____j__S]__```%ha888 	j 	jLCKK((1EE{{9--3SbS9G(.])C)CDDKhChhhUhhhhhh{hhhY`aeYfhhiiiirsss1222tr3   c           	      6   | j         s'|                     d          st          d           dS d}d}dt          t	          | dd                    d	t
          d
t          ffd}fd}t                       t          d           t          d           t          d           | j         D ]O}|                    dd          }|dk    rdz  %|dvr* |             |dz  }|                    d          }|dnt          |          }|dk    rPt          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|
 |            Q |             t                       dS )#zDisplay conversation history.r	  rB  z"(._.) No conversation history yet.Ni  r   r  FrJ  r   c                     sdS |                      d          }|sdS 	 ddlm} d |j        t          |                                        d           dS # t
          t          t          f$ r Y dS w xY w)NrO   	timestampr   r   r  r  r  )rD   r	   r  rC   r  r  r  r9  )rJ  rs  r	   show_tss      r2   
_ts_suffixz*HermesCLI.show_history.<locals>._ts_suffix  s      r[))B r------S3X3E"II>>GGPPSSSS3   rrs   9A A54A5c                  r    sd S dk    rdnd} t          d           t          d d|  d           dd S )	Nr  rJ  messagesz

  [Tools]z    ( tool z hidden)r   )rO  )r  hidden_tool_messagess    r2   flush_tool_summaryz2HermesCLI.show_history.<locals>.flush_tool_summary  s`    '  4 9 999zD}---Q';QQ4QQQRRR#$   r3   z4+--------------------------------------------------+z3|            (^_^) Conversation History           |roler  r  r  >   user	assistantr   rO   r	  z	
  [You #r  rP  r  z
  [Hermes #r   callcallsz(requested r	  r4  z(no text response))	r  r	  rO  r  r  r   rY   rD   rU  )r  preview_limitvisible_indexr	  r	  ri  r	  r   content_textr   r  r_   r  r  r	  r	  s                 @@r2   show_historyzHermesCLI.show_history  s   ( 	--Y-?? I"#GHHHF wt%6>>??	 	 	 	 	 	 	 		% 	% 	% 	% 	% 	/000YZZZ/000, $	9 $	9C7769--Dv~~$)$000   QMggi((G!(22c'llLv~~"#Q#Q#Q

3#Q#QRRR"m<7m#lBSBSVcBcBcikmm   P}PPzz#PPQQQ..4"J 
&~~6"%l"3"3m"C"C  __
!+qvvgA
AA$AAA.7g7v778888r3   
event_typec           	          	 ddl m}  ||| j        r| j        j        ndt	          | dd          pd|dk    rdnd	           dS # t
          $ r Y dS w xY w)
u   Fire a session-boundary plugin hook (on_session_finalize or on_session_reset).

        Non-blocking — errors are caught and logged.  Safe to call from any
        lifecycle point (shutdown, /new, /reset).
        r   r\  NrG  r  on_session_resetnew_sessionsession_boundaryrF  )r  r]  r   r  r  r   )r  r"	  r_  s      r2   _notify_session_boundaryz"HermesCLI._notify_session_boundary  s    		FFFFFFL48JH4:00D z488AE(26H(H(H}}N`	       	 	 	DD	s   AA 
AAr  c                     | j         r|sdS t          | dd          rdS 	 ddlm} | j                             | |            dz            S # t
          $ r! t                              d|d	
           Y dS w xY w)a  Drop a just-ended session row when it never gained content.

        Starting the CLI and immediately quitting (or rotating with /new,
        /clear) used to leave an empty untitled row behind that clutters
        ``/resume`` and ``hermes sessions list``. Delegates the
        check-and-delete to ``SessionDB.delete_session_if_empty``, which
        only removes rows with no messages, no title, and no child
        sessions. Ported from google-gemini/gemini-cli#27770.
        Fr  Nr   r	  r  r  z Could not prune empty session %sTr  )r  r  r   ro   delete_session_if_emptyr   r   r   )r  r  _ghhs      r2   _discard_session_if_emptyz#HermesCLI._discard_session_if_empty  s      	z 	5
 4/66 	5		@@@@@@#;;*)< <     	 	 	LL2J     55		s   ,A 'A87A8c                 >   | j         r<| j        r5| j                             | j                   |                     d           n| j         r|                     d           | j        }| j        r||rz| j         r1	 | j                             | j                   n# t          $ r Y nw xY w	 | j                            |d           n# t          $ r Y nw xY w| 	                    |           t          j                    | _        | j                            d          }t          j                    j        dd         }| d| | _        g | _        d| _        d| _        t'          | j                   | 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        rI	 d| j         _        | j                            | j        t:          j                            dd          | j         | j!        | j"        d           d| j         _        n# t          $ r Y nw xY w|r| j        rd	dl#m$} 	 |%                    |          }n-# tL          $ r }	tO          d|	            d}d}Y d}	~	nd}	~	ww xY w|rd	 | j        (                    | j        |           d| _        |}nL# tL          $ r}	tO          d|	 d           d}Y d}	~	n(d}	~	wt          $ r d}Y nw xY w|tO          d           d}	 tS          | j         dd          }
|
 |
*                    | j        |pddd           n# t          $ r Y nw xY w|                     d           |s'|rtW          d|            dS tW          d           dS dS )zDStart a fresh session with a new session ID and cleared agent state.r^  r%	  r  Nrd  rc  F_last_flushed_db_idxr   r  )	TodoStore_invalidate_system_promptHERMES_SESSION_SOURCEr  )r,  r  )r  r  r'  model_configTr  z  Title rejected: r  u    — session started untitled.u<     Title is empty after cleanup — session started untitled._memory_managerrO   )parent_session_idr  rC  r$	  z(^_^)v New session started: z(^_^)v New session started!),r   r  commit_memory_sessionr'	  r  r  _flush_messages_to_session_dbr   end_sessionr+	  r	   r5  r  r  r  r  r  r  r  r  reset_session_staterS  r-	  tools.todo_toolr.	  r  r/	  _session_db_createdcreate_sessionr   r}  rD   r'  r  r  r  r  sanitize_titler  rF  set_session_titler  on_session_switchr  )r  silentr  old_session_idr<  r=  r.	  r  	sanitizedr   _mms              r2   r%	  zHermesCLI.new_session  s3   : 	A$3 	AJ,,T-FGGG))*?@@@@Z 	A))*?@@@ 	; 	; z J<<1    !   D ,,^]KKKK    **>:::%\^^*33ODDZ\\%bqb)
*99Z99$&!" 111: D	>$(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 %T- %666666%$-$<$<U$C$C		% % % % 8Q 8 8999$(	 $% ! %) ,>>tPYZZZ26D/$-EE) ) ) )#$J$J$J$JKKK$(EEEEEE( ) ) )$(EEE)* ^___ $
dj*;TBB?))*8*>B",	 *       ))*<=== 	5 5<U<<=====344444		5 	5s   8B 
B%$B%)C 
CC+H 
HHA+J9 9
KKK/ /
L9LL)M	 	
M?M--M?>M?8O 
OOc                 t   | j         }|sdS d| _         t          |t                    sdS |                                }|                                sdS t          |          }|dk     s|t          |          k    r$t          d| d           t          d           dS |                     d|            dS )	a  Resolve a bare numeric reply that follows a bare ``/resume`` prompt.

        After ``/resume`` (no args) prints the recent-sessions list it arms
        ``self._pending_resume_sessions``. The next submitted input is given
        one chance to be a bare session number (``3``); if so we resume that
        session here. Anything else (another command, free text, blank) simply
        disarms the prompt and is handled normally by the caller.

        Returns True if the input was consumed as a resume selection (caller
        must not treat it as chat); False otherwise. The pending state is
        always one-shot: it is cleared on the first submitted input regardless
        of outcome. See #34584.
        FNr  z  Resume index z is out of range.z:  Use /resume with no arguments to see available sessions.Tz/resume )	r  r   rY   r   r  rE   rU  rF  _handle_resume_command)r  ra   r  r  r  s        r2   !_consume_pending_resume_selectionz+HermesCLI._consume_pending_resume_selection  s     / 	5 )-%$$$ 	5::<< !! 	5H199G,,>e>>>???PQQQ4##$6u$6$6777tr3   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 re  hermes_conversation_z.jsonrx  r   r   )r'  r  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	   r5  r  ro   r  r   r   r   dumpr'  r  r  	isoformat)r  r	  	saved_dirr   r   r   s         r2   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  rB  r	  r	  z%(._.) No user message found to retry.r   rO   z(^_^)b Retrying: "r:   r  rf  )r  r  rH  rU  rD   )r  last_user_idxrM  last_messages       r2   
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r3   r  nprefillc                    | j         st          d           dS |dk     rd}g }t          t          | j                   dz
  dd          D ]P}| j         |                             d          dk    r*|                    |           t          |          |k    r nQ|st          d           dS |d         }t          |          }t          | j                   |z
  }| j         |                             dd	          }|                     |          }	| j         d|         | _         d
}
| j        B| j        r:	 | j        	                    | j        t          |d                    }|rt          |dz
  t          |          dz
            }||         d         }| j                            | j        |          }|                    dd
          }
|                     |                    d          pi                     d                    }|r|}	n_# t          $ r%}t                              d|           Y d}~n5d}~wt           $ r%}t                              d|           Y d}~nd}~ww xY w| j        t%          | j        d          r+	 | j                                         n# t           $ r Y nw xY wt%          | j        d          r0	 t          | j                   | j        _        n# t           $ r Y nw xY w	 t+          | j        dd          }|%| j        r|                    | j        d	dd           n# t           $ r Y nw xY w|dk    rdnd}|
p|}t          d| d| d| d|	dd          t          |	          dk    rdnd	 d 
           t          | j                   }t          d!| d"           |r|	r|                     |	           dS dS dS )#u  Back up N user turns: truncate history, soft-delete on disk, prefill.

        Walks backwards N user messages and discards everything from the
        Nth-from-last user message onward (its assistant response, tool
        calls, etc.). ``n`` defaults to 1 (the last exchange); ``/undo 3``
        backs up three user turns. If ``n`` exceeds the number of user
        turns, it backs up to the oldest one.

        Beyond the in-memory ``conversation_history`` slice, this also:
          • soft-deletes the truncated rows in SessionDB (``active=0``) so
            they're hidden from re-prompts and search but kept for audit;
          • notifies memory providers via ``on_session_switch(rewound=True)``;
          • mirrors /branch's agent surgery (system-prompt invalidation +
            flush-index reset);
          • when ``prefill`` is set and an input buffer is available,
            pre-fills the composer with the backed-up message text so it
            can be edited and resubmitted.

        ``prefill=False`` is used by callers that drive the undo
        programmatically (e.g. checkpoint rollback) and don't want to
        touch the user's input buffer.
        z(._.) No messages to undo.Nr  rB  r	  r	  z$(._.) No user message found to undo.r   rO   r   rS   r	  r	  rewound_counttarget_messagezundo: soft-delete skipped: %szundo: soft-delete failed: %sr/	  r-	  r2	  FT)r3	  r  rewoundturnturnsz(^_^)b Undid rd  r3  z message(s)). Backed up to: "r:   r  rf  r  z! message(s) remaining in history.)r  r  rH  rU  rD   r  _undo_content_to_textr  r  list_recent_user_messagesr  r  rewind_to_messager  r   r   r   r   rS  r/	  r-	  r  r=	  _prefill_input_buffer)r  rR	  rS	  user_indicesrM  cut_idxturns_undoneremoved_countremoved_msgremoved_textrewound_rowsrecents
target_idx	target_idr   db_textr   rA	  	turn_word	msg_countr  s                        r2   	undo_lastzHermesCLI.undo_last  s   . ( 	.///Fq55A s445592rBB 	 	A(+//776AA##A&&&|$$))E 	8999F r"<((D566@/8<<YKK11+>> %)$=hwh$G! 'DO'@*DDO3|R+@+@ E    /!$\A%5s7||a7G!H!HJ '
 3D 9I!-?? F $*::oq#A#AL #88$455;@@KK G  /'. A A A <a@@@@@@@@ @ @ @;Q????????@
 :!tz#>?? J88::::    Dtz#9:: 69$:S6T6TDJ33    D
dj*;TBB?t?))*,# $	 *        +a//FFW	 1M	^L ^ ^9 ^ ^	 ^ ^+CRC0^;>|;L;Lr;Q;Q%%WY^ ^ ^	
 	
 	
 122	?9???@@@  	5| 	5&&|44444	5 	5 	5 	5s[   8CH 
I.H<<I.	I))I.J( (
J54J5K- -
K:9K:>=L< <
M	M	c                     t          | t                    r| S t          | t                    r+d | D             }d                    d |D                       S dS )zAFlatten message content (str or content-part list) to plain text.c                     g | ]F}t          |t                    r/|                    d           dk    0|                    dd          GS r   r   r   rD   r   s     r2   r   z3HermesCLI._undo_content_to_text.<locals>.<listcomp>q  sY       a&& ,-55==F+B+B fb!!+B+B+Br3   r   c              3      K   | ]}||V  	d S r   r   r  s     r2   r   z2HermesCLI._undo_content_to_text.<locals>.<genexpr>v  '      3313Q333333r3   rO   r   r   s     r2   rZ	  zHermesCLI._undo_content_to_textk  ss     gs## 	Ngt$$ 	4    E
 9933333333rr3   c                 $   t          | dd          }|dS 	 |j        }||_        t          |d          rt	          |          |_        |                                 dS # t          $ r&}t          	                    d|           Y d}~dS d}~ww xY w)z=Place ``text`` in the active prompt_toolkit buffer, editable.r  Nr!  zundo: prefill buffer failed: %s)
r  r   ra   rS  rU  r!  rL  r   r   r   )r  ra   rC  r  r   s        r2   r]	  zHermesCLI._prefill_input_buffery  s    dFD));F	?$CCHs-.. 0&)$ii#NN 	? 	? 	?LL:A>>>>>>>>>	?s   AA 
B)B

Br   r  r  default_indexc                   	
 ddl }ddlm	 dg
	
fd} |j                     |j                    u }| j        r|rddlm} | j        }d| _        | j        	                                 	  ||           || _        | j        	                                 n/# || _        | j        	                                 w xY w |             
d         S )zbRun curses_single_select via run_in_terminal so prompt_toolkit handles terminal ownership cleanly.r   N)curses_single_selectc                  *                d<   d S )N)rr	  r   r   )rt	  rr	  r  r   r  s   r2   _pickz+HermesCLI._run_curses_picker.<locals>._pick  s"    ,,UEWWWF1IIIr3   r0  F)
r:  rV  rt	  current_threadmain_threadr  r=  r0  r!  rL  )r  r  r  rr	  r:  rv	  in_main_threadr0  was_visiblert	  r   s    ```     @@r2   _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?r  c                 (   ddl }dgfd} |j                     |j                    u }| j        r|s|                                  dS | j        r|rddlm} | j        }d| _        | j                                         	  ||           n,# t          $ r 	  |             n# t          $ r Y nw xY wY nw xY w|| _        | j                                         n/# || _        | j                                         w xY w |             d         S )uo  Prompt for free-text input safely inside or outside prompt_toolkit.

        Mirrors the thread-aware guard in ``_run_curses_picker``: ``run_in_terminal``
        returns a coroutine that must be awaited by the prompt_toolkit event loop,
        which only exists on the main thread.  Slash commands are dispatched from
        the ``process_loop`` daemon thread (see issue #23185), so calling
        ``run_in_terminal`` from there orphans the coroutine — ``_ask`` never runs,
        and user keystrokes leak into the composer instead.  Fall back to a direct
        ``input()`` when we're off the main thread.
        r   Nc                      	 t                                                     pd d<   d S # t          t          f$ r Y d S w xY wNr   )r  r   KeyboardInterruptEOFError)r  r   s   r2   _askz*HermesCLI._prompt_text_input.<locals>._ask  sU    !+..4466>$q			%x0   s   &+ A A rw	  F)
r:  rx	  ry	  r  rM  r=  r0  r!  rL  r   )r  r  r:  r	  rz	  r0  r{	  r   s    `     @r2   _prompt_text_inputzHermesCLI._prompt_text_input  s    		 	 	 	 	 	 21337Ly7L7N7NN 9 	^ 	49 	 	BBBBBB2K',D$I  """'%%%%   DFFFF    D ,7(	$$&&&& ,7(	$$&&&&DFFFaysN   B C 
B9
B&%B9&
B30B92B33B96C 8B99C "C?r   r  detailchoicesr$  c                    ddl ddlsdS t           dd          s                     d          S 	  j        j        n# t          $ r dY nw xY w j                     j                    u dt          dz  f fd}s
 |            S t          j                    d fd}d fd}dt          ffd	} ||          s
 |            S                                 }		 	 	                     d          }
 ||           |
 j         ||           S S # t          j        $ rZ  j                                        z
  }|dk    rY n:                                }||	z
  dk    r|}	                                  Y nw xY w	  j         ||           n#  j         ||           w w xY wdS )u  Prompt through the prompt_toolkit composer instead of raw input().

        This is for CLI slash-command confirmations.  The old raw input() path
        fought prompt_toolkit's active stdin ownership: in some terminals the
        prompt appeared above the TUI, choices were redrawn later, and Enter
        could be interpreted as EOF/exit.  A first-class modal state keeps the
        choices visible and lets the normal Enter key binding submit the typed
        or highlighted choice.

        **Platform note (Windows — issue #33961):**
        Earlier code bypassed the modal on ``sys.platform == "win32"`` and fell
        back to a raw ``input()`` prompt.  When the confirm was triggered from the
        ``process_loop`` daemon thread (the normal case) that ``input()`` ran off
        the main thread and deadlocked against prompt_toolkit's stdin ownership —
        the user saw a frozen cursor and Ctrl-C was swallowed (bare ``/reset``
        froze; ``/reset now`` worked only because it skips the prompt entirely).

        Native Windows now uses the same path as Linux/macOS: the modal is set up
        on ``self._app.loop`` via ``call_soon_threadsafe`` and answered by the
        normal prompt_toolkit key bindings (the same input channel that already
        handles ordinary typing on Windows).  The raw ``input()`` fallback is kept
        only for the genuinely safe cases: no running app (unit tests /
        non-interactive), no resolvable event loop, or a scheduling failure.
        r   Nr  Choice [1/2/3]: r   c                  ~    t           j        dk    r s                                 d S                     d          S )Nr  r	  )r/  rG  rM  r	  )rz	  r  s   r2   _stdin_fallbackz;HermesCLI._prompt_text_input_modal.<locals>._stdin_fallback  sC    
 |w&&~&  """t**+=>>>r3   c                                                        dd_                                         z   _                                         d S )Nr   )r  r	  r	  selectedresponse_queue)_capture_modal_input_snapshotr  r  r  rM  )_timer	  r	  r	  r  r$  r  s   r2   _setup_modalz8HermesCLI._prompt_text_input_modal.<locals>._setup_modal  sd    ..000 ""0) )D% ,1??+<+<w+FD(r3   c                  t    d  _         d _                                                                            d S r	  )r  r  _restore_modal_input_snapshotrM  r  s   r2   _teardown_modalz;HermesCLI._prompt_text_input_modal.<locals>._teardown_modal)  s=    (,D%+,D(..000r3   c                      s               dS  j                     d fd}	                     |           n# t          $ r Y dS w xY w                    d          S )NTr   c                  x    	                                                  d S #                                   w xY wr   )rG  )fnreadys   r2   _wrappedzNHermesCLI._prompt_text_input_modal.<locals>._run_on_app_loop.<locals>._wrapped5  s6     BDDDIIKKKKKEIIKKKKs   
# 9Fr  r  r  )r  rB  r   wait)r	  r	  r	  app_looprz	  r:  s   ` @r2   _run_on_app_loopz<HermesCLI._prompt_text_input_modal.<locals>._run_on_app_loop/  s     !1t#IO%%E             --h7777   uu::a:(((s   A 
AATr  r        @r  )r:  r+  r  r	  r  r>  r   rx	  ry	  rY   r|  r  r  r  rD   r  Emptyr  rM  )r  r  r	  r	  r$  r	  r	  r	  r	  _last_countdown_refreshr   r  r5  r	  r	  rz	  r	  r:  s   `````        @@@@@r2   _prompt_text_input_modalz"HermesCLI._prompt_text_input_modal  s   @ 	 	4 tVT** 	?**+=>>>	y~HH 	 	 	HHH	 21337Ly7L7N7NN	?t 	? 	? 	? 	? 	? 	? 	?  	%("2"?$$$
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
		 	 	 	 	 		)D 	) 	) 	) 	) 	) 	) 	) 	)$  -- 	%"?$$$"'//"3"3	2+++///::F$$_555! (4  1111 5 { + + + $ <u?P?P PI A~~//++C44;;25/((***++  (4  111 (4  1111 5tsG   A AA8F1 :"D0 01F!F1 #3FF1 FF1 1GrL   c                     | j         }|sd S |d                             |           d | _         d| _        |                                  d S Nr	  r   )r  r4  r  rM  )r  rL   r  s      r2   _submit_slash_confirm_responsez(HermesCLI._submit_slash_confirm_responseX  sY    ) 	F##E***$(!'($r3   r   c                     |d S |                                                                 }|sd S ddddddddddddddd}d |D             }|                    |          }||v r|S ||v r|S d S )Noncealwaysrp  )r   r	  approver  r  ok2r	  remember3rp  	nevermindnorR	  c                     h | ]
}|d          S r   r   r   choices     r2   	<setcomp>z<HermesCLI._normalize_slash_confirm_choice.<locals>.<setcomp>{  s    3336!9333r3   )r   r   rD   )r  r   r	  
choice_rawaliasesallowedr!  s          r2   _normalize_slash_confirm_choicez)HermesCLI._normalize_slash_confirm_choicea  s    
 ;4YY[[&&((
 	4 !
 
  437333[[,,
    tr3   c                 D   | j         }|sg S |                    d          pd}|                    d          pd}|                    d          pg }|                    dd          }d4d
t          dt          t                   dt          dt          dt          f
d}d5d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}	g }
|                                D ]!}|
                     ||d                     "t          |          D ]B\  }\  }}}||k    rdnd}|
                     || d|dz    d| d | dd!"                     C|
                    d#            |||
          }t          d$|d%z
            }g }|                                D ]!}|                     |||                     "g }t          |          D ]I\  }\  }}}||k    rdnd} || d|dz    d| d | |d!"          D ]}|                    ||f           Jt          j        d&          j        }d'}d'}t          d||z
            }t          d||z
  t          |          z
            }t          |d$          }t          |          |k    r!t          d|dz
            }|d|         d(gz   }g }|                    d)d*d+|z  z   d,z   f            ||d)d-||            |	|d)|           |D ]} ||d)d.||            |	|d)|           |D ]\  }}||k    rd/nd0} ||d)|||            |	|d)|            ||d)d1d#|           |                    d)d2d+|z  z   d3z   f           |S )6z0Render the /new-/clear-style confirmation panel.r  zConfirm actionr	  rO   r	  r	  r   8   V   
title_textcontent_lines	min_widthr  r   c           	         t          j        d          j        }t          t	          |           gd |D             z   |dz
  gz             }t          t          |dz   |dz
            |dz
  t          d|dz
                      }|dz   S )NrT   r  c                 ,    g | ]}t          |          S r   r  r%  s     r2   r   z\HermesCLI._get_slash_confirm_display_fragments.<locals>._panel_box_width.<locals>.<listcomp>      .S.S.STs4yy.S.S.Sr3   rg  r  r>   rd  r  r  r  r  rU  r  r	  r	  r	  r  	term_colslongestrC  s          r2   _panel_box_widthzHHermesCLI._get_slash_confirm_display_fragments.<locals>._panel_box_width      0;;CI3z??+.S.S].S.S.SSW`cdWdVeeffGGaKQ77QBPY\]P]H^H^__E19r3   ra   r  subsequent_indentc                 Z    t          j        | t          d|          dd|          }|pdgS Nr  F)r  replace_whitespacedrop_whitespacer	  rO   r  wrapr  ra   r  r	  wrappeds       r2   _wrap_panel_textzHHermesCLI._get_slash_confirm_display_fragments.<locals>._wrap_panel_text  =    m!Umm#( %"3  G ?rd"r3   border_stylecontent_style	box_widthNc                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S Nr   r  u   │ u    │
r  r  r8  r,  r	  r	  ra   r	  r  s         r2   _append_panel_linezJHermesCLI._get_slash_confirm_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2r3   c                 F    |                      |dd|z  z   dz   f           d S Nu   │rd  u   │
r  r,  r	  r	  s      r2   _append_blank_panel_linezPHermesCLI._get_slash_confirm_display_fragments.<locals>._append_blank_panel_line  -    LL,y(AG(KLMMMMMr3   H      ❯rd  r  r  z]     — rP  r	  u9   Type 1/2/3 or use ↑/↓ then Enter. ESC/Ctrl+C cancels.r  r  rT   r>   rd  u   … (detail truncated)class:approval-border   ╭r     ╮
class:approval-titleclass:approval-descclass:approval-selectedclass:approval-choiceclass:approval-cmdr     ╯
)r	  r	  r  )r  rD   rY   r   rE   r  r(  rI  r  r  r  r  r,  rU  r  )r  r  r  r	  r	  r	  r	  r	  r	  r	  r  r  r  _valuerA  r  r  r	  inner_text_widthdetail_wrappedchoice_wrappedr	  	term_rowsreserved_belowchrome_fullr  max_detail_rowskeepr,  styles                                 r2   $_get_slash_confirm_display_fragmentsz.HermesCLI._get_slash_confirm_display_fragments  sO   ) 	I		'""6&68$$*))I&&,"99Z++	 	 	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 %%'' 	= 	=D  !1!1$!;!;<<<<*3G*<*< 	} 	}&C&&%!XooUU3F  !1!1V2\2\sQw2\2\%2\2\VZ2\2\^`tz!{!{!{||||XYYY$$UM::	q)a-00%%'' 	L 	LD!!"2"249I"J"JKKKK02*3G*<*< 	6 	6&C&&%!XooUU3F++v,V,Vq,V,VE,V,VPT,V,VXh  }C  D  D  D 6 6%%sGn55556 ,Y77=	9~566	a[!83~;N;N!NOOoq11~00q/A-..D+ETE26N5OON-u	8I/JW/TUVVV5"9;QSXZcddd  (?KKK% 	j 	jGu&=?TV]_hiiii  (?KKK* 	Z 	ZLC14--F]Eu&=ugyYYYY  (?KKK5"9;O  RM  OX  	Y  	Y  	Y-u	8I/JW/TUVVVr3   	providersry  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_currentNrD   )r   rM  r   s      r2   r   z/HermesCLI._open_model_picker.<locals>.<genexpr>  s7      VV$!Q!%%BUBUVAVVVVVVr3   r   r   )stager	  r	  ry  r	  
user_provscustom_provsr9   r  N)r	  nextrI  r  rM  )r  r	  ry  r	  r	  r 
  default_idxs          r2   _open_model_pickerzHermesCLI._open_model_picker  s~    **,,,VV)I*>*>VVVXYZZ"#* 0$($
 $
  	c*****r3   c                 V   t          |dd          sdS 	 ddlm}  ||j        |j        |j        p| j        pd|j        p| j        pd|j                  }n# t          $ r d}Y nw xY w|dS d	d
g}| 	                    d|j
        |d          }|                     ||          }|dk    S )zDAsk for explicit confirmation before applying costly model switches.r  FTr   )expensive_model_warningrO   )r   r   r(  
model_infoN)r	  zSwitch anywayz.Use this model for the current Hermes session.)rp  CancelzKeep the current model.z!!! Expensive Model Warning !!!r   )r  r	  r	  r$  r	  )r  hermes_cli.model_cost_guardr
  	new_modeltarget_providerr   r(  r
  r   r	  rJ  r	  )r  r   r
  r   r	  r   r	  s          r2   _confirm_expensive_model_switchz)HermesCLI._confirm_expensive_model_switch  s   vy%00 	4	KKKKKK-- /?DM?R<$,<"!,  GG  	 	 	GGG	?4 X;
 ++3?	 , 
 
 55c7CCs   AA A&%A&persist_globalc                     	 |j         r&|                     |          st          d           d S |                     ||           d S # t          $ r}t          d|            Y d }~d S d }~ww xY w)N  Model switch cancelled.     ✗ Model selection failed: )r  r
  rF  _apply_model_switch_resultr   )r  r   r
  r"  s       r2   &_confirm_and_apply_model_switch_resultz0HermesCLI._confirm_and_apply_model_switch_result  s    	<~ d&J&J6&R&R 3444++FNCCCCC 	< 	< 	<:S::;;;;;;;;;	<s   +A A 
A.A))A.c                 h    d | _         |                                  |                     d           d S )Nr9   r  )r  r	  rM  r  s    r2   _close_model_pickerzHermesCLI._close_model_picker  s9    #' **,,,c*****r3   rd  r  r	  scroll_offsetr	  r	  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	  r
  rR	  r	  r	  r
  r
  max_visiblevisibles	            r2   _compute_model_picker_viewportz(HermesCLI._compute_model_picker_viewport  s    " +y>'AL'PQQa4Km##$MM000$w.2MAs=!g+>>??g%%r3   c                    |j         st          d|j                    d S | j        v	 ddlm}  ||| j        t          | j        pg           t          | j        dd                      n2# t          $ r%}t                              d|           Y d }~nd }~ww xY w| j        }| j        | j        | j        t          | dd           t          | dd           | j        | j        | j        d	}|j        | _        |j        | _        |j        | _        |j        | _        |j        | _        |j        r|j        | _        |j        r|j        | _        |j        r|j        | _        | j        	 | j                            |j        |j        |j        |j        |j        
           na# t          $ rT}|                                D ]\  }}t1          | ||           t          d|j         d| d| d           Y d }~d S 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|
rD|
j        rt          d|
j        dd           t          d|
                                            tA          |j        pdd          rd|j        !                                v p
|j        dk    }|rt          d            |j"        rt          d!|j"                    |rBtG          d"|j                   |j$        rtG          d#|j                   t          d$           d S t          d%           d S )&N     ✗ r   #merge_preflight_compression_warning_config_context_lengthr   r	  config_context_length/preflight-compression switch warning failed: %sr  r  r'  r   r  r  r  r(  r   r  r	
  new_providerr(  r   r       ⚠ Model switch to 	 failed (); staying on rU   $[Note: model was just switched from  to  via /. Adjust your self-identification accordingly.]     ✓ Model switched:     Provider: resolve_display_context_lengthrO   r   r(  r
  r!
      Context: rW    tokens    Max output:     Capabilities: r  claudeanthropic_messages    Prompt caching: enabled       ⚠ model.defaultmodel.providerz#    Saved to config.yaml (--global).       (session only — add --global to persist))%r  rF  error_messager   hermes_cli.context_switch_guardr
  r   r  r  r   r   r   r'  r   r  r(  r   r  r	
  r

  r  r  switch_modelr  setattrprovider_label_pending_model_switch_noter
  r^  r0
  
max_outputformat_capabilitiesrv   r   warning_messagers  provider_changed)r  r   r
  r
  r"  	old_model_cli_snapshot_k_vrA
  mir0
  ctxcache_enableds                 r2   r
  z$HermesCLI._apply_model_switch_result,  s7   ~ 	3V133444F:!
U______33*!$";"ArBB*1$*>VX\*]*]	      U U UNPSTTTTTTTTU J	 Z"&"9!(/BD!I!I")$0Dd"K"K|	
 	
 %
."("8 "("(/> 	*!>DL? 	,"ODM? 	,"ODM:!
''$.!'!7"N#_#_ (        
 ,1133 * *FBD"b))))/V-= / / / /"+/ / /   =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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EsD   AA, ,
B6BB)8F" "
H ,A	G;;H $A0K 
K"!K"c                    | 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          	  	        }|                                  t!          | dd           r1t#          j        | j        ||fd                                           n|                     ||           d S |                                  d S d S )Nr	  r   r	  r   r	  models)provider_model_idsr  r'  provider_data
model_listr9   r  r  c              3   z   K   | ]5\  }}|                     d                                d           k    1|V  6dS )r  Nr	  )r   rM  r   rQ
  s      r2   r   z;HermesCLI._handle_model_picker_selection.<locals>.<genexpr>  s        *O  *O1cdchchiocpcp  uB  uF  uF  GM  uN  uN  dN  dN!  dN  dN  dN  dN  *O  *Or3   )r?
  rO   r	  r 
  		raw_inputr	  ry  current_base_urlcurrent_api_key	is_globalexplicit_provideruser_providerscustom_providersr  Tr  r/   r7  )r  rD   rU  r
  rw  rP
  r   rM  r
  rI  r^  r?
  r   r'  r   r(  r  r:  r;  r
  r<  )r  r
  r  r	  r	  r	  rR
  rP
  r  back_idx
cancel_idxr?
  chosen_modelr   rQ
  s                 @r2   _handle_model_picker_selectionz(HermesCLI._handle_model_picker_selection  s   ( 	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~%>%>
 
 
 ((***4.. X$#J$n5#   egggg??WWW$$&&&&&K s   B; ;
CCcmd_originalc                 $   ddl m}m}m} ddlm} |                    dd          }t          |          dk    r|d                                         nd} ||          \  }}	}
}} ||
|          }|r1	 ddl	m
}  |             t          d           n# t          $ r Y nw xY wdd	lm}m} 	  |                                | j        pd| j        pd| j        pd
          }n# t          $ r d}Y nw xY w||j        nd}||j        nd}|s|	s| j        pd}| j        r || j                  nd}	 |t-          d           ||          d         }n# t          $ r g }Y nw xY w|s\t          d           t          d           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        v	 ddlm}  ||| j        t=          | j        pg           tA          | j        dd                     n2# t          $ r%}tB          "                    d|           Y d}~nd}~ww xY w| #                    |          st          d           dS | j        }| j        | j        | j$        tA          | dd          tA          | dd          | j        | j        | j%        d}|j&        | _        |j'        | _        |j'        | _$        |j        | _(        |j        | _)        |j        r|j        | _        |j        r|j        | _        |j%        r|j%        | _%        | j        	 | j                            |j&        |j'        |j        |j        |j%                   na# t          $ rT}|*                                D ]\  }}tW          | ||           t          d|j&         d | d!| d"           Y d}~dS 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tA          | j        dd          nd*          }|rt          d+|d,d-           |rD|j0        rt          d.|j0        d,d-           t          d/|1                                            te          |j        pdd0          rd1|j&        3                                v p
|j%        d2k    }!|!rt          d3           |j4        rt          d4|j4                    |rBtk          d5|j&                   |j6        rtk          d6|j'                   t          d7           dS t          d8           dS )9u  Handle /model command — switch model.

        Supports:
          /model                              — show current model + usage hints
          /model <name>                       — switch model (persists by default)
          /model <name> --session             — switch for this session only
          /model <name> --global              — switch and persist (explicit)
          /model <name> --provider <provider> — switch provider + model
          /model --provider <provider>        — switch to provider, auto-detect model

        Persistence defaults to on (``model.persist_switch_by_default`` in
        config.yaml, default True). Use ``--session`` for a one-off switch.
        r   )r?
  parse_model_flagsresolve_persist_behavior)	get_labelNr  rO   )clear_provider_models_cachez+  Cleared model picker cache. Refreshing...)build_models_payloadload_picker_context)r	  ry  rV
  r  zinventory context unavailabler	  z#  No authenticated providers found.z>  /model <name>                        switch model (persists)zC  /model <name> --session              switch for this session onlyz6  /model --provider <slug>             switch providerz@  /model --refresh                     re-fetch live model lists)r	  r 
  rT
  r
  r
  r
  r 
  r"
  r
  r  r  r#
  r$
  r&
  r'
  r(
  rU   r)
  r*
  r+
  r,
  r-
  r.
  r/
  r1
  r2
  rW   r3
  r4
  r5
  r  r6
  r7
  r8
  r9
  r:
  r;
  z    Saved to config.yamlr<
  )7r^  r?
  rc
  rd
  hermes_cli.providersre
  r  rU  r   rw  rf
  rF  r   hermes_cli.inventoryrg
  rh
  with_overridesr   r'  r   rZ
  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
  r0
  rC
  rD
  rv   r   rE
  rs  rF
  )"r  ra
  r?
  rc
  rd
  re
  r   raw_argsmodel_inputrY
  is_global_flagforce_refresh
is_sessionr
  rf
  rg
  rh
  rL
  r	  r 
  model_displayprovider_displayr	  r   r
  r"  rG
  rH
  rI
  rJ
  rA
  rK
  r0
  rM
  s"                                     r2   _handle_model_switchzHermesCLI._handle_model_switch  s   	
 	
 	
 	
 	
 	
 	
 	
 	
 	

 	322222 ""4++'*5zzA~~58>>###2 h''	
 21.*MM
  	IIIIII++---EFFFF    	SRRRRRRR	%%''66!%!4""j.B!%!4" 7  CC
  	 	 	CCC	
 ,/?S''
/2s++D  	#4 	 J3)M;?=Wyy777i;&'FGGG0055kB		   			  =>>>XYYY]^^^PQQQZ[[[## %) $    F !!]0b**!]0b L.B$/%)

 

 

 ~ 	3V133444F:!
U______33*!$";"ArBB*1$*>VX\*]*]	      U U UNPSTTTTTTTTU 33F;; 	/000F
 J	 Z"&"9!(/BD!I!I")$0Dd"K"K|	
 	
 %
."("8 "("(/> 	*!>DL? 	,"ODM? 	,"ODM :!
''$.!'!7"N#_#_ (      	 	 	 ,1133 * *FBD"b))))/V-= / / / /"+/ / /   	=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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./////DEEEEEsh   6B 
B#"B#/5C% %C43C44"E E&%E&;AI> >
J-J((J-!8O 
P8$A	P33P8c                    ddl m} |                    dd          }t          |          dk    r|d                                         nd}|                    |          \  }}|r|D ]}t          d|            dS 	 ddlm}m	}	 n*# t          $ r}
t          d|
            Y d}
~
dS d}
~
ww xY w |            }|                    ||||	nd	          }|j        rd
nd}|j                                        D ]1}t          |                    d          rd| d| nd|            2|j        r|j        rt          d           dS dS dS )u  Handle /codex-runtime — toggle the codex app-server runtime opt-in.

        Usage:
            /codex-runtime                       — show current state
            /codex-runtime auto                  — Hermes default (chat_completions)
            /codex-runtime codex_app_server      — hand turns to codex subprocess
            /codex-runtime on / off              — synonyms for the above
        r   )codex_runtime_switchNr  rO   u   ❌ )r  save_configu   ❌ could not load config: )persist_callback   ✓   ✗openai_runtimer  rd  rP  z3    Tip: `/reset` starts a new session immediately.)r  ru
  r  rU  r   
parse_argsrF  r~  r  rv
  r   applyr  rJ  r  r  requires_new_session)r  ra
  crsr   rl
  	new_valuer  errr  rv
  r"  r!  r   r\  r  s                  r2   _handle_codex_runtimezHermesCLI._handle_codex_runtime  s    	;:::::""4++'*5zzA~~58>>###2NN844	6 	 & &s%%%%F	BBBBBBBBB 	 	 	7#77888FFFFF	 kmm-6-Bkk  
 
 !.3eN--// 	( 	(DDOO<L,M,M '((($(((&( ( ( (> 	Kf9 	KIJJJJJ	K 	K 	K 	Ks    B	 	
B0B++B0
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'  )	rJ  r  r
  r  r   rh  r  r8  r   r  ra   r
  r
  r  r  s         r2   #_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}  )
rJ  r  r  r
  r  r   rh  r  r8  r   r
  s         r2   #_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)r  r  r  r  s    r2   _output_consolezHermesCLI._output_console'   s(    4&& 	!== |r3   c                 D     |                                  j        |i | dS )z.Print through the active command-safe console.N)r
  r  )r  r/   r0   s      r2   r  zHermesCLI._console_print-   s,    $$d5f55555r3   c                    t          | t                    r|                     dd          g}|                     d          r|                    d| d                     |                     d          r|                    d| d                     d                    d |D                       S t          |           S )	zEAccept string or dict personality value; return system prompt string.r  rO   tonezTone: r	  zStyle: r   c              3      K   | ]}||V  	d S r   r   r   s     r2   r   z8HermesCLI._resolve_personality_prompt.<locals>.<genexpr>:   rp	  r3   )r   r   rD   r  r   rY   )rL   r   s     r2   _resolve_personality_promptz%HermesCLI._resolve_personality_prompt1   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r3   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_ENABLED    → rO   u       ✓ z<12z Enabledu       ○ z Not configured (r4  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  	platformsrD   r   get_home_channelr8  default_reset_policyr  at_houridle_minutesrp   r   )r  r
  r
  r   platform_statusrG  r8  r  pconfighomehome_strpolicyr   s                r2   _show_gateway_statuszHermesCLI._show_gateway_statusB   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                 =  no |                                                                 }|                                }ddlm} |                                d                             d          } ||          }|r|j        n|}|dvrd| _        |dv r|                    dd          }t          |          dk    r|d         nd                                                                 }	|	d	v rd
| _	        n3|	r1t          dt           dt          |	           dt                      d
S dS |dk    r|                                  n|dk    r|                                  n|dk    r|                     |           ni|dk    r|                                  nM|dk    r|                                  n1|dk    r5|                                  t          dt           dt                      n|dk    r|                     dd|          	 d
S |                     d
           t-                       | j        rK| j        j        }
|
                                 |
                    dd           |
                                 n| j                                         | j        rt=                      }t?          j                     j!        }| j"        s|dk     r"|#                    tI                                 ntK          | j&        d
          }tO          j(        dtO          j)                              }d}tU          | d          r-| j+        r&tU          | j+        d          r| j+        j,        j-        }t]          || j/        ||| j&        | j0        || j1                   t          d            	 dd!l2m3}  |            }	 dd"l4m5}  |            6                    d#d$          }n# tn          $ r d$}Y nw xY w|#                    d%| d&| d'           n# tn          $ r Y nw xY w| 8                                 tG          d            	 dd!l2m3}  |            }	 dd"l4m5}  |            6                    d#d$          }n# tn          $ r d$}Y nw xY w| 9                    d%| d&| d'           n1# tn          $ r Y n$w xY w|d(k    r| :                                 n|d)k    r|                    d*          }t          |          dk    r|d                                         }|rh| j;        r>	 dd+l<m=} |>                    |          }n+# t~          $ r}t          d|            d}Y d}~nd}~ww xY w|st          d,           nS| j;        @                    | j0                  ro	 | j;        A                    | j0        |          rt          d-|            nt          d.           n# t~          $ r}t          d|            Y d}~nd}~ww xY w| j;        B                    |          }|rt          d/| d0|d1                     n|| _C        t          d2| d3           npdd4l<mD} t          d |                        nNt          d5           n=| j;        rt          d6| j0                    | j;        @                    | j0                  }|r/|E                    d)          rt          d7|d)                     n| jC        rt          d8| jC                    nt          d9           ndd4l<mD} t          d |                        n||d:k    r| F                    |          sdS n]|d;k    ra| G                    |          \  }}|                                pd}|                     d;d<|          	 d
S |                     |=           n|d>k    r| H                    |           n|d?k    r| I                    |           n|d@k    r| J                    |           n|dAk    r| K                    |           n|dBk    r| L                    |           ne|dCk    r| M                    |           nH|dDk    r| N                    |           n+|dEk    rB| O                                }|r*tU          | dF          r| jP        Q                    |           n|dGk    r| R                    |           n|dHk    rd} |                                }!t          |!          dk    rI	 t          |!d                   } n*# t~          $ r tG          dI|!d         dJ           Y dS w xY w| dk     rd} | dk    rdKndL|  dM}"|                     dH|"|          	 d
S | T                    |            n|dNk    r| U                    |           n|dOk    r| V                                 n|dPk    r| W                    |           n|dQk    r| X                    |           n|dRk    r| Y                    |           n~|dSk    r| Z                    |           na|dTk    r| [                    |           nD|dUk    rW| \                    | ]                    |                    5  | ^                    |           ddd           n# 1 swxY w Y   n|dVk    r| _                    |           n|dWk    r| `                    |           n|dXk    r| a                                 n|dYk    r| b                                 nu|dZk    r2| jc         | _c        | jc        rd[nd\}#| 9                    d]|#            n=|d^k    r| d                    |           n |d_k    r| e                                 n|d`k    r| f                    |           n|dak    r| g                                 n|dbk    r| h                    |           n|dck    r| i                    |           n|ddk    r| j                    |           nt|dek    r| k                                 nX|dfk    r| l                                 n<|dgk    r| m                    |           n|dhk    r| n                    |           n|dik    r| o                    |           n|djk    r| p                    |           n|dkk    r| q                                rdS n|dlk    rddmlrms}$  |$d
n           n|dok    r| t                                 nt|dpk    r| u                    |           nW|dqk    r%ddrlvmw}%  |%            }&tG          ds|& dt           n,|duk    r| x                    |           n|dvk    rV| \                    | ]                    |                    5  | y                                 ddd           n# 1 swxY w Y   n|dwk    r| z                    |           n|dxk    r| {                    |           ny|dyk    r	 ddzl|m}}'m~}(m})m}*  |'            }+ |)            }, |(            }-d{ |+D             }.t          |+          t          |.          z
  }/|.sUtG          d|           tG          d}           tG          d~t                       d           |/rtG          d|/ d           ni }0	 ddlm}1  |1                                            D ]}2|2|0|2d         <   n# tn          $ r i }0Y nw xY wtG          dt          |.           d           t          |.          D ]W\  }3}4}5}6}7}8 |*|3|,|-|8          }#dddE                    |#d          }9|4rd|4 nd}:|0E                    |3          pi };g }<|;E                    d          r|<                    |;d          d           |;E                    d          r|<                    |;d          d           |;E                    d          r|<                    |;d          d           |<rdd                    |<           dnd}=|#dk    rdnd|# d}>|;E                    d          rd|;d          nd}?tG          d|9 d|3 |: |> |= |?            Y|/rtG          d|/ d           tG          d           n# tn          $ r}tG          d|            Y d}~nd}~ww xY w|dk    r|                     |           n|dk    r|                     |           nl|dk    r|                                  nP|dk    r|                                  n4|dk    r|                     |           n|dk    r|                     |           n|dk    r|                    dd          }t          |          dk    r|d                                         nd}@|@st          d           n| jP        Q                    |@           | j        r3t          d|@dd          t          |@          dk    rdnd            nHt          d|@dd          t          |@          dk    rdnd            n|dk    rS|                    dd          }t          |          dk    r|d                                         nd}@|@st          d           n| j        r| j+        tU          | j+        d          r	 | j+                            |@          }A|Ar3t          d|@dd          t          |@          dk    rdnd            nCt          d           n2# tn          $ r}Bt          d|B            Y d}B~Bnd}B~Bww xY w| jP        Q                    |@           t          d|@dd          t          |@          dk    rdnd            
n|dk    r|                     |           
n|dk    rxddlm}Cm}D |                    dd          }t          |          dk    r|d                                         nd}@|@st          d |C                        d
S t)          | j        t,                    r| j        E                    d          ni }E |D|E          }F|Fd         }Gt/          | dd          t/          | dd          t/          | d@d          t/          | dd          t/          | dd          t/          | dd          d| _        d| _        d| _1        |G| _/        d| _        d| _        d| _        d| _+        d
| _        |@| _        t          d|G d           	n|dk    r|                     |           	n|dk    r|                     |           n|dk    r|                     |           n|dk    r|                     |           n|                                d         }HtG                      }ItI                      }J| j        E                    di           }K|H                    d          |Kv rt|K|H                    d                   }L|LE                    dæ          dk    rSddl}M|LE                    dd          }N|Nr	 ddlm}O  |OtN          j                                                  }P|M                    |Nd
d
d
d|PȦ          }Q|Qj                                        p|Qj                                        }R|Rr5ddlm}S  |S|R          }R| 9                    t_          |R                     n| 9                    dʦ           n%# |Mj        $ r | 9                    d˦           Y ntn          $ r$}| 9                    d| d'           Y d}~nd}~ww xY w| 9                    d|H dΝ           n|LE                    dæ          dk    r|LE                    dd                                          }T|Trs|T                    d          r|Tnd|T }T|t          |H          d                                         }U|T d|U                                 }V|                     |V          S | 9                    d|H dѝ           n| 9                    d|H dҝ           n|H                    d          tg                      v rddlm}Wm}X  |W|H                    d                    }Y|Yr|t          |H          d                                         }U	  |X |Y|U                    }Q|Qrt          tm          |Q                     n!# tn          $ r$}t          d| t                      Y d}~nd}~ww xY wn|H|Jv r|t          |H          d                                         }Zto          |H|Z| j0        զ          }[|[r|[\  }\}]}^|J|H         }_tG          d|_d          dt          |]           dם           |^r8t=                      #                    dd                    |^           d'           tU          | dF          r| jP        Q                    |\           n	t=                      #                    d|H d'           n|H|Iv r|t          |H          d                                         }`ddlm}am}b  |b|`          \  }c}Z|cr |a|Hg|c|Z| j0        զ          }d|dr|d\  }\}]}^tG          dt          |]           dd                    |]                      |^r8t=                      #                    dd                    |^           d'           tU          | dF          r| jP        Q                    |\           n%t=                      #                    d|H d'           d
S |`}Ztw          |H|Z| j0        զ          }\|\rL|I|H         d         }etG          d|e            tU          | dF          r| jP        Q                    |\           nUt=                      #                    d|H d'           n.ddlm}f |                                d         ot{          |f          t{          |I          z  t{          |J          z  }gofd|gD             }ht          |h          dk    raofd|hD             }it          |i          dk    r|i}hn=t}          d |hD                       nnfd|hD             }jt          |j          dk    r|j}ht          |h          dk    r|hd         }k|kok    r@t          d| t                      t          t           t~           dt                      n|                                t          o          d         }l|k|lz   }m|                     |m          S t          |h          dk    rdt          t~           d| t                      t          t           dd                    t          |h                     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  >   rv  r  N>   r2  quitr  rO   >   -d--deleteTr  u   ✗ Unknown argument: z4. Use /exit --delete to also remove session history.FhelpprofilerU  r  r   redrawu   ✓ UI redrawnr  zdThis clears the screen and starts a new session.
The current conversation history will be discarded.)ra
  )r>	  r  rR  r<  r   r  rT  uI     ✨ (◕‿◕)✨ Fresh start! Screen cleared and conversation reset.
get_random_tipr  r-  r  [dim 
   ]✦ Tip: r  r	  r  )maxsplitr  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))format_session_db_unavailablez$  Usage: /title <your session title>z  Session ID: z	  Title: z  Title (pending): z2  No title set. Usage: /title <your session title>handoffnewzPThis starts a fresh session.
The current conversation history will be discarded.)r  rv  r  r'  zcodex-runtimepersonalityr  hatchretryr  promptundoz(._.) Invalid count u    — use /undo or /undo N.z;This removes the last user/assistant exchange from history.zThis removes the last z user turns from history.r  saver  suggestions	blueprintcuratorkanbanrf  learnmemoryr
  r  	statusbarr
  hiddenz  Status bar r~  r  footeryolor}   r   compressusagecreditsbillinginsightscopyr   r  version)_print_version_info)check_updatespasteimagereload)
reload_envz  Reloaded .env (z var(s) updated)z
reload-mcpzreload-skillsbundlesr/  plugins)_discover_all_plugins_get_disabled_set_get_enabled_set_plugin_statusc                 *    g | ]}|d          dk    |S )r  bundledr   )r   r   s     r2   r   z-HermesCLI.process_command.<locals>.<listcomp>!  s&    HHHaadi6G6G6G6G6Gr3   zNo user plugins installed.z0  Install one: hermes plugins install owner/repoz"  Or drop a plugin directory into z	/plugins/r  u8    bundled plugins available — see: hermes plugins list)get_plugin_managerr8  zUser plugins (z):r  rx
  ry
  )r   disabledu   ○z vr  hooksz hooksr  z	 commandsr3  r  r4  r   r  r  rr  r	  rd  z  (+u&    bundled — see: hermes plugins list)z6  Enable/disable: hermes plugins enable/disable <name>zPlugin system error: rollbackr  stopagentsjourney
backgroundr|  z  Usage: /queue <prompt>r0  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: goalmoa)	moa_usagenormalize_moa_configdefault_presetr  r   r(  r   r  )r  r   r'  r(  r   r  zmoa-virtual-providerzmoa://localr  z"  MoA one-shot queued with preset z2; previous model will be restored after this turn.subgoalr#  voicer  r  r   execr  )_sanitize_subprocess_envr  )shellr  ra   r$  env)redact_sensitive_textz"[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: ri  u   
⚡ Loading bundle: z skills)z [yellow]Skipped missing skills: z$[bold red]Failed to load bundle for )&build_stacked_skill_invocation_messagesplit_stacked_skill_commandsu   
⚡ Loading z stacked skills: z,[bold red]Failed to load stacked skills for u   
⚡ Loading skill: z#[bold red]Failed to load skill for )COMMANDSc                 >    g | ]}|                               |S r   rE  r   rc  
typed_bases     r2   r   z-HermesCLI.process_command.<locals>.<listcomp>"  s*    LLL1<<
3K3KL1LLLr3   c                      g | ]
}|k    |S r   r   r
  s     r2   r   z-HermesCLI.process_command.<locals>.<listcomp>"  s    CCC11
??Q???r3   c              3   4   K   | ]}t          |          V  d S r   r  rb  s     r2   r   z,HermesCLI.process_command.<locals>.<genexpr>"  s(      %>%>c!ff%>%>%>%>%>%>r3   c                 :    g | ]}t          |          k    |S r   r  )r   rc  min_lens     r2   r   z-HermesCLI.process_command.<locals>.<listcomp>"  s)    #L#L#L!#a&&G:K:KA:K:K:Kr3   z[1;31mUnknown command: z!Type /help for available commandszAmbiguous command: zDid you mean: r  )r   r   r  r
  r  rh  r8  r  rU  r  rF  r  r  r  r  _handle_profile_command_handle_tools_commandr  r  rS  _confirm_destructive_slashr%	  r  r  r&  r]  r_  r2  r  r  r  r  r  r  r  r  rG  r  r  r   r   r  rS  r   r  r  r  r'  r  r   hermes_cli.tipsr
  r  r  r  r   ra  r  r!	  r  r  r  r;	  r  r  r<	  get_session_by_titler  r
  rD   _handle_handoff_command_split_destructive_skiprC	  _handle_sessions_commandrs
  r
  _handle_personality_command_handle_pet_command_handle_hatch_commandrQ	  r  r4  _handle_prompt_compose_commandrE   rk	  _handle_branch_commandrM	  _handle_cron_command_handle_suggestions_command_handle_blueprint_command_handle_curator_command_handle_kanban_commandr  r  _handle_skills_command_handle_learn_command_handle_memory_commandr
  r  r!  _handle_timestamps_command_toggle_verbose_handle_footer_command_toggle_yolo_handle_reasoning_command_handle_fast_command_manual_compress_show_usage_show_credits_show_billing_show_insights_handle_copy_command_handle_debug_command_handle_update_commandr	  r
  _handle_paste_command_handle_image_commandr~  r
  _confirm_and_reload_mcp_reload_skills_handle_bundles_command_handle_browser_commandhermes_cli.plugins_cmdr
  r
  r
  r
  rp   r  r
  list_pluginsr  r  r   _handle_rollback_command_handle_snapshot_command_handle_stop_command_handle_agents_command_handle_journey_command_handle_background_commandr  r}  _handle_goal_commandhermes_cli.moa_configr
  r
  r   r   r   r  _pending_moa_restore_modelr  r(  r   r  _pending_moa_disable_after_turnr  _handle_subgoal_command_handle_skin_command_handle_voice_command_handle_busy_commandrP  r\  r  tools.environments.localr
  r}  r
  r  r0  r1  agent.redactr
  r  TimeoutExpiredr  r1  re  r
  r
  rY   r`  rO  r
  r
  rT  r
  rG  r  r  )pr  r  r  ra
  _resolve_cmd
_base_word_cmd_defr|  _restr(  r`  ccterm_wrU  r   r_  r
  _tipr  
_tip_colorr   	raw_titler  	new_titler   r  r
  r	  	_new_argsrc  r  	retry_msg_undo_n_undo_parts
_undo_descr  r
  r
  r  r
  r
  r
  r
  entriesr   r
  user_entriesbundled_countloadedr
  r   r8  r
  _descr  _dirr  glyphverrT  rz  r	  rA  rr  r  acceptedr"  r
  r
  moa_cfgr!  presetbase_cmdr  skill_bundlesr  r  r  exec_cmdr
  sanitized_envr   r&  r
  r  	user_argsaliased_commandr
  r
  plugin_handleruser_instructionbundle_resultri  loaded_namesmissingbundle_infor  r
  r
  
extra_keysstacked_result
skill_namer
  	all_knownmatchesexactshortest	full_namerm  full_cmdr  r
  sp                                                                                                                 @@r2   r1  zHermesCLI.process_command{   sB&    MMOO))++	}} 	HGGGGG__&&q)0055
<
++%-=HMM:	 222,0D)((( !&&tQ//E!$UaU1XXR>>@@FFHHE***/3,,   DT  D  D  D  D  ~B  D  D  E  E  Et5&  NN)##((****'!!&&|4444*$$    (""("" ##%%%333T334444'!!..F)	 /  
  tD)))!###
 y %i&  """1%%%		""$$$
 y 0 ]]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' H->>>>>>(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NNNNNN F%B%B%D%D F FGGGGBCCCC! @:::;;;*66tGG Rw{{733 R:(8::;;;;( RG$2EGGHHHHPQQQQFFFFFF>::<<>>????)##//== u%  77EELIqOO%%-E..F)	 /  
  t5))))(""''5555*$$)),7777'!!%%l3333/))&&|4444-'',,\::::%$$\2222'!!&&|4444'!!))I 3WT+;<< 3#''	222(""//====&  G&,,..K;!##!+a.11GG!   ]Q]]]^^^FF Q;;G a<< NMPgPPP 
 ..) /   	
 tNN7####(""''5555&  ""$$$$&  %%l3333-'',,\::::+%%**<8888)##((6666(""''5555(""##D$=$=l$K$KLL : :++L999: : : : : : : : : : : : : : :'!!&&|4444(""''5555+%%%%''''(""%%''''+%%+/+C'CD$!%!9GIIxE 7 7 78888,&&++L9999)##  """"(""''5555&  +%%**<8888&  %%l3333*$$!!,////'!!)##    )##|,,,,*$$----&  %%l3333'!!&&|4444(""**,, u)##;;;;;;d3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)##((6666)##>3            0/11**,,,,..  IH7HHH #Gs</@/@ @# $T6777LMMM_?R?T?T___```$ mkMkkklll $&F$IIIIII!3!3!5!5!B!B!D!D 2 2A01F1V9--2$ $ $ $!#$ @3|+<+<@@@AAACI,CWCW N N?gufdC .tWhC P P P,1u E E I I%QV W W07?n7nnnR%zz$//52!88G,, B KK4=(@(@(@AAA88G,, B KK4=(@(@(@AAA88J// H KK4
+;(F(F(FGGG<@!H!8diioo!8!8!8!8b&+y&8&8m5mmm;?88G;L;L T 7W 7 7 7RTL5LL4LLeLVLULLMMMM$ \Z]ZZZ[[[RSSS 3 3 31a11222222223*$$)),7777*$$)),7777&  %%''''(""'')))))##((6666,&&++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%
       
 !&&tQ//E*-e**q..eAhnn&&&bG *YY[[**+++t0:4;0M0MUdkooe,,,SUG--g66J 01F&-d4H$&O&O#D*d;; w55"4D99#D*d;;#D*d;;/ /D+ ',D#!DMDJ1DL)DM.DMDJ37D0'.D$sssstttt)##((6666&  %%l3333'!!&&|4444&  %%l3333 !((+H355N-//M![__-=rBBNs##~55%hooc&:&:;88F##v--%%%%#xx	266H oZ ZYYYYY,D,DRZ__EVEV,W,WM%/^^ (T%)2= &4 & &F &,]%8%8%:%:%Sfm>Q>Q>S>SF% Z N N N N N N)>)>v)F)F $ 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  ?.! ! ! ! 1>.Cw"/"9K8V1D 8 8--8 8 8    #++Vtyy?Q?QVVV   t%566 5+//444MM''LxLLL    ^++#CMMNN399;;        0L/KD/Q/Q,
,  %K%K!/J/( $& & &N
 & 5C2\79S->-> 9 9#yy669 9   # 'MM// Z499WCUCU Z Z Z   #4)9:: 9 /33C888#++X8XXX    4#' 4.    ]!/!9&!AJ>*>>???t%566 5+//444MM''([h([([([\\\\
 988888&__..q1
MMC,?,??#mBTBTT	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  9P 
$O/ .P /O>;P =O>>P 
P-,P-R: %$R
 	R: 
RR: RR: :
SS>U 
V$U==V8AW< <
X#XX#e+ +#ffk77k;>k;
x++x/2x/:B.AD )0} AD })&AD (}))F0AD D
AED%AD=D=AEMAN9 N9
AO OAOOAO [>CA_ _A`_(	A`_1A``A`f3Ag
 g

Ag8gAg3g3Ag8portsystemc                 "    t          | |          S )a5  Try to launch a Chromium-family browser with remote debugging enabled.

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

        Returns True if a launch command was executed (doesn't guarantee success).
        )rt   )ro  rp  s     r2   _try_launch_chrome_debugz"HermesCLI._try_launch_chrome_debug#  s     'tV444r3   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: %sNr  rO   _goal_managergoalsr  r  )r  default_max_turns)hermes_cli.goalsrt  r~  r  r   r-  r   r  rD   rE   ru  )
r  rt  r  r"  sidr  r!  	goals_cfgr  mgrs
             r2   _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                     	 | j                                         sP| j                                         }|r| j                            |           | j                                         NdS dS # t
          $ r Y dS w xY w)ax  Move stray messages from ``_interrupt_queue`` into ``_pending_input``.

        While the agent is running, user input is routed into
        ``_interrupt_queue`` (see the architecture comment near
        ``_route_user_input_when_busy``). The explicit-interrupt path at the
        top of ``process_loop`` only drains that queue when
        ``busy_input_mode == "interrupt"`` AND a ``pending_message`` was
        acknowledged. If the agent's turn finishes naturally (no interrupt),
        any messages typed during the turn stay stuck in ``_interrupt_queue``
        forever. Subsequent ``Enter`` presses re-route to the same blocked
        queue and the CLI appears to hang.

        Called once at the end of every turn from ``process_loop``'s ``finally``
        block. Catches and swallows ``Exception`` because the drain must never
        break the main loop. (#20271)
        N)r  empty
get_nowaitr  r4  r   )r  strays     r2   '_drain_interrupt_queue_to_pending_inputz1HermesCLI._drain_interrupt_queue_to_pending_inputH#  s    "	+1133 3-88:: 3'++E222 +1133 3 3 3 3 3  	 	 	DD	s   A'A- -
A;:A;c                    |                                  }||                                sdS 	 t          | dd          }||                                swd}	 t	          |j                  D ]H}t          |t                    r
|r|d         }t          |t                    rt          |          rFd} n# t          $ r d}Y nw xY w|rdS n# t          $ r Y nw xY wt          | dd          re	 |                    d           n,# t          $ r}t          j        d	|           Y d}~nd}~ww xY wt          d
t           dt                       dS 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|                                sdS 	 ddlm}  |            }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.

        Interrupt handling: if the turn was user-cancelled (Ctrl+C), we
        AUTO-PAUSE the goal instead of judging + re-queuing. Otherwise
        Ctrl+C feels like it did nothing — the judge runs on whatever
        partial output landed, almost always says "continue", and the
        loop keeps going. Auto-pause keeps the goal recoverable via
        ``/goal resume`` once the user has sorted out what they want.
        The empty-response skip mirrors the gateway guard at
        ``_handle_message`` in ``gateway/run.py``.
        Nr  Fr   Tr  zuser-interrupted (Ctrl+C)rB  z"goal pause-on-interrupt failed: %sr  u_   ⏸ Goal paused — turn was interrupted. Use /goal resume to continue, or /goal clear to stop.rO   r	  r	  r   c                     g | ]D}t          |t                    r-|                    d           dv .|                    dd          ES )r   >   ra   output_textra   rO   rn	  r   s     r2   r   z=HermesCLI._maybe_continue_goal_after_turn.<locals>.<listcomp>#  sZ     ! ! ! !)!T22! 89uuV}}H_7_7_ EE&"--7_7_7_r3   r   c              3      K   | ]}||V  	d S r   r   r  s     r2   r   z<HermesCLI._maybe_continue_goal_after_turn.<locals>.<genexpr>#  s'      1H1Ha1H!1H1H1H1H1H1Hr3   )gather_background_processes)user_initiatedbackground_processesrJ  should_continuecontinuation_promptz$goal continuation enqueue failed: %s)r|  	is_activer  r~  r   r|  r   r&  rY   rJ  r   pauser-  r   rF  r  r  r  r  rD   r   r   rx  r  evaluate_after_turnr  r4  )r  r{  r  has_real_messager  r"  last_responsehistri  r   r   
_gather_bg	_bg_procsdecisionr
  s                  r2   _maybe_continue_goal_after_turnz)HermesCLI._maybe_continue_goal_after_turna#  s:   ( $$&&;cmmoo;F	d$4d;;G"7==??"#( , "&gm!4!4   &eU33 - -$)!HE%eS11 %6OPU6V6V %$+/(  , , , (,$$$, $ F 	 	 	D	 41599 		I		!<	==== I I IBCHHHHHHHHIOT O OHLO O   F 	,2D~~  776??k11!ggi44G!'400 	;! !%,! ! !
 )-		1H1HU1H1H1H(H(H(+GMr(:(:E 2  	 	 	MMM	 ""$$ 	F	RRRRRR"
II 	 	 	III	 **!* + 
 

 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   )C AB6 5C 6CC CC 
CC/D 
D/D**D/BG5 5HHH/ /H>=H>1K 
K7K22K7c                    g d}	 |                     | j                  }n# t          $ r d}Y nw xY w||dz   t          |          z           | _        | j        r/|                                 | 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 )u  Cycle tool progress mode: off → new → all → verbose → off.

        Tool-progress display (full args / results / think blocks at the
        ``verbose`` step) is INDEPENDENT of global DEBUG logging.  Cycling
        through here does not change ``self.verbose`` or the agent's
        ``verbose_logging`` / ``quiet_mode`` — those remain under the
        explicit ``-v``/``--verbose`` flag and the ``/verbose-logging``
        toggle.  See PR #6a1aa420e for the history that decoupled them.
        )r   r
  ri  r  r  r  r   ColorszTool progress: OFFu*    — silent mode, just the final response.zTool progress: NEWu'    — show each new tool (skip repeats).zTool progress: ALLu    — show every tool call.zTool progress: VERBOSEu*    — full args, results, and think blocks.rO   N)r  r  r  rU  r   r  reasoning_callbackhermes_cli.colorsr  DIMRESETYELLOWGREENBOLDrF  rD   )r  cycler  _Colorslabelss        r2   r  zHermesCLI._toggle_verbose#  sZ    100	++d566CC 	 	 	CCC	"'qCJJ(>"?: 	D,0,L,L,N,NDJ) -1,CDJ) 	877777knnW]nnnnnnnnnm``w}```!,  G  G  GW]  G  G  G	
 
 	

42B7788888s   ! 00r?	  new_session_idc                     |r|r||k    rdS 	 ddl m}m}m} n# t          $ r Y dS w xY w ||          r ||            ||           dS dS )u  Move YOLO bypass state from an old session key to a new one.

        Called whenever ``self.session_id`` is reassigned mid-run — ``/branch``
        forks into a new session, and auto-compression rotates the agent's
        session id into a fresh continuation session. Without this transfer
        the user's ``/yolo ON`` toggle would silently revert on the very next
        turn (the same UX failure mode that motivated this entire fix), since
        ``_session_yolo`` is keyed by session id.

        Mirrors ``tui_gateway/server.py`` (~line 1297-1305) which performs the
        same transfer for the TUI's session-rename path. No-op when YOLO
        wasn't enabled or when the ids match.
        Nr   disable_session_yoloenable_session_yolois_session_yolo_enabled)tools.approvalr  r  r  r   )r  r?	  r  r  r  r  s         r2   _transfer_session_yoloz HermesCLI._transfer_session_yolo$  s      	^ 	~7W7WF	          
  	 	 	FF	"">22 	1///  00000	1 	1s   
 
''c                 |    	 ddl m}m} n# t          $ r Y dS w xY w|rdS t	          | dd          pd} ||          S )a  Whether YOLO bypass is currently enabled for this CLI session.

        Reads from ``tools.approval._session_yolo`` (the same set that
        ``enable_session_yolo`` / ``disable_session_yolo`` write to) so the
        status bar reflects the actual bypass state instead of a stale env
        var. Also honors the process-start ``--yolo`` flag, which freezes
        ``HERMES_YOLO_MODE`` into ``_YOLO_MODE_FROZEN`` before tool imports
        happen.
        r   )_YOLO_MODE_FROZENr  FTr  Nr   )r  r  r  r   r  )r  r  r  session_keys       r2   rR  z!HermesCLI._is_session_yolo_active"$  s    	          	 	 	55	 	4
 dL$77D9&&{333s    
c                    ddl m} ddlm}m}m} | j        pd} ||          r4 ||           t          d|j         |j	         d|j
         d           dS  ||           t          d|j         |j         d	|j
         d
           dS )u  Toggle YOLO mode — skip all dangerous command approval prompts.

        Per-session toggle that mirrors the gateway and TUI ``/yolo`` handlers
        (see ``gateway/run.py:_handle_yolo_command`` and
        ``tui_gateway/server.py`` key=="yolo"). We deliberately do NOT mutate
        ``HERMES_YOLO_MODE`` here — that env var is read once at module import
        time into ``tools.approval._YOLO_MODE_FROZEN`` to keep prompt-injected
        skills from flipping the bypass mid-session, so setting it after CLI
        startup is a silent no-op. Routing through ``enable_session_yolo`` /
        ``disable_session_yolo`` gives the same auditable, per-session bypass
        the other surfaces have. ``run_conversation`` binds
        ``self.session_id`` as the active approval session key via
        ``set_current_session_key`` so the bypass takes effect on the very
        next dangerous command in this run.
        r   r  r  r   u     ⚠ YOLO mode OFFu.    — dangerous commands will require approval.u     ⚡ YOLO mode ONu2    — all commands auto-approved. Use with caution.N)r  r  r  r  r  r  r  rF  r  REDr  r  )r  r  r  r  r  r  s         r2   r  zHermesCLI._toggle_yolo<$  s1     	877777	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 o2"";// 	  ---A7< A A A A A A    
  ,,,E7< E E E'- E E E    r3   c                 l    |sdS t          | dd          |z   | _        |                     d           dS )zCCallback for intermediate reasoning display during tool-call loops.Nr  rO   Fr  )r  r  r  )r  r  s     r2   r  zHermesCLI._on_reasoningd$  sG     	F&-d4Lb&Q&QTb&b#%%E%22222r3   rO   c                    | 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dlm}m}m}m	}m
} d}|rU|                                                    dd	          }t          |          d	k    r|d	                                         } ||          \  }}	}
 ||          \  }}}|pd}|
rt          d
           |	sdS |	r~ddlm} t          | j        dd          pd}t          | j        dd          pd} || j         ||          } || j         |||pd|          }|d         D ]}t          d|            dS t          | j                   }|                     d          5  	 ddlm} ddlm} t'          | j                   }g }|}|r |||          \  }}|sd}|}t          | j        dd          pd}t          | j        dd          pd} ||||          }|r+t          dt          |           d| d|dd| d	           n4|rt          d| d|dd| d           nt          d| d|dd           | j                            |d||pdd          \  }}|r|r |||          }|| _         t          | j        d d          rM| j        j        | j        k    r8| j        j        | _        d| _        | j                            | j         d            || j         ||          } ||| j         ||          }|d!         rd"nd#}t          d$| d%|d&                     t          d'|d(                     |d)         rt          d'|d)                     n)# t0          $ 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 )+uu  Manually trigger context compression on the current conversation.

        Two modes:

        * ``/compress [<focus>]`` — compress the *whole* history. An
          optional focus topic 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.
        * ``/compress here [N]`` — boundary-aware compression. Summarize
          everything *except* the most recent ``N`` exchanges (default
          2), which are preserved verbatim. Inspired by Claude Code's
          Rewind "Summarize up to here" action (v2.1.139, May 2026,
          https://code.claude.com/docs/en/whats-new/2026-w20). Lets the
          user pick the compression boundary instead of leaving it to
          the automatic token-budget heuristic.
        rg  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   )extract_compress_flagsparse_partial_compress_argsrejoin_compressed_head_and_tail"split_history_for_partial_compresssummarize_compress_previewrO   r  zt(._.) --aggressive is not supported; use '/compress here [N]' to keep only recent exchanges, or /undo to drop turns.)estimate_request_tokens_rough_cached_system_promptrU  )r  rU  r,  u	   🗜️  zCompressing context...)summarize_manual_compressionFu-   🗜️  Summarizing up to here: compressing  of z messages (~rW   z tokens), keeping last z exchange(s) verbatim...u   🗜️  Compressing z tokens), focus: "z"...z tokens)...T)approx_tokensfocus_topicr9  r  noopu   🗜️u   ✅r  rd  headlinez     
token_linerG  u     ❌ Compression failed: )r  rU  r  r   compression_enabledhermes_cli.partial_compressr  r  r  r  r  r   r  r]  r  r  r  !agent.manual_compression_feedbackr  r   _compress_contextr  r  r5	  r   )r  ra
  r  r  r  r  r  rl
  _partsr  
aggressivepartial	keep_lastr  r  _sys_prompt_toolsr  reportr  original_countr  original_historyr  r  
compressedrc  
new_tokenssummaryiconr   s                                  r2   r  zHermesCLI._manual_compressk$  sr   $ ( 	C0I,J,JQ,N,NYZZZFz 	BCCCFz- 	<===F	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
  	-!''))//a88F6{{Q!!9??,, )?(>x(H(H%':*E*Eh*O*O'K!'R 	
  K L L L  	JJJJJJ!$*.ErJJPbKTZ$77?4F99))  M
 0/)#t F w * *($(())))FT677 899 c	8 c	8b8NNNNNNZZZZZZ#'(A#B#B   ' 	0!C!C()" "JD$   0 #(/ &dj2I2NNTRT Wd;;Ct = =$"- ! ! !
  l N#d)) N N+N N9FTN N*3N N N O O O O ! l 9. 9 9mi 9 9&19 9 9 : : : : j.jjmjjjjkkk !%
 < <"/ + 3t != ! !
A  St S!@!@T!R!RJ,6) DJd;;	^
-@@&*j&;DO*.D' J<<T=VX\]]]::-"-   

 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8Ec	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8 c	8s=   -O#/G=N-,O#-
O7O	O#OO##O'*O'c           	      T	   | j         s%|                                 st          d           dS | j         }|j        }|dk    r%|                                 s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}|j	        }|j
        }	|j        }
|j        }|j        dk    r|j        nd}|j        }|rt          d	||z  d	z            nd}|j        }t#          | j                  }t'          t)          j                    | j        z
                                            }t          d
           t          dd            t          d|j                    t          d|d           t          d|d           |rt          d|d           t          d|d           t          d|	d           t          d|
d           t          d|d           t          d|d           t          dd            t          d|dd|dd|dd           t          d|            t          d|            t          |d d          pt          | d d          }t          |d!d          pt          | d!d          }t          |d"d          pt          | d"d          }dd#lm}m} d}|rt8          j                            d$%          5 }	 |                    ||||&                               d'(          }n## t8          j        j!        tD          f$ r d}Y nw xY wddd           n# 1 swxY w Y   d)  ||          D             }|r"t                       |D ]}t          |           |                                  | j#        rhtI          j%                    &                    tH          j'                   d*D ]3}tI          j%        |          &                    tH          j(                   4dS tI          j%                    &                    tH          j)                   dS )+u  Rate limits + session token usage (when a live agent exists) + Nous credits.

        The Nous credits block is agent-independent (a portal fetch), so it runs even
        with no live agent — important for the TUI, where /usage runs in a slash-worker
        subprocess that resumes the session WITHOUT building an agent (self.agent is None),
        which would otherwise early-return before any credits showed.
        r  Nr   z,(._.) No API calls made yet in this session.)format_rate_limit_displayr  r  session_reasoning_tokensrT   u     📊 Session Token Usager  r  z  Model:                     z  Input tokens:              z>10,z  Output tokens:             u     ↳ Reasoning (subset):      z  Prompt tokens (total):     z  Completion tokens:         z  Total tokens:              z  API calls:                 z  Session duration:          z>10z  Current context:  rW   z / r3  r;   z%)z  Messages:         z  Compressions:     r   r   r(  )fetch_account_usagerender_account_usage_linesr  )max_workers)r   r(  g      $@r  c                     g | ]}d | S )r  r   r%  s     r2   r   z)HermesCLI._show_usage.<locals>.<listcomp>t%  s    ^^^d^^^r3   )openair  httpxhttpcorer4  hpackgrpcmodal)*r   _print_nous_credits_blockr  r  get_rate_limit_statehas_dataagent.rate_limit_trackerr  r  r  r  r  r  r  r  r  r  rU  r  rJ   r	   r5  r  r  r'  agent.account_usager  r  
concurrentfuturesThreadPoolExecutorsubmitr   TimeoutErrorr   r  r-  	getLoggersetLevelDEBUGWARNINGINFO)r  r   r	  rl_stater  input_tokensoutput_tokensreasoning_tokensr
  
completiontotalr  last_promptr_  pctr  rj	  r  r   r   r(  r  r  account_snapshot_poolaccount_linesr  noisys                               r2   r   zHermesCLI._show_usage$%  s    z 	1133 HFGGGF
'A::1133 FDEEEF --// 	) 	JJJJJJGGG++H55666GGG u&<a@@EA'>BBGa"5*DaHHMA,4
*-
7A7TWX7X7Xj33^_+9@Gc#g-3555a!3122	)8<>>D<N+N*]*]*_*_``*+++:   ;ek;;<<<AlAAABBBBmBBBCCC 	MK4DKKKLLL;f;;;<<<?j???@@@:e:::;;;:e:::;;;;g;;;<<<:   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 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 	&&(((< 	7((777t C C!%((11'/BBBBC C ((66666s6   N1-NN1N"N1!N""N11N58N5c                 x    ddl m}  |            }|sdS t                       |D ]}t          d|            dS )u  Print the Nous credits magnitudes + monthly-grant gauge when a Nous account
        is logged in. Returns True if it printed anything.

        Delegates to the shared ``agent.account_usage.nous_credits_lines`` helper —
        the single source for the /usage credits block across CLI, gateway, and TUI.
        It's agent-independent (a portal fetch gated on "a Nous account is logged in",
        NOT the inference-provider string), so /usage shows the block even in the TUI
        slash-worker subprocess that resumes WITHOUT a live agent. Fail-open and
        wall-clock-bounded inside the helper; also honors HERMES_DEV_CREDITS_FIXTURE
        for offline testing — same behavior as every other surface.
        r   )nous_credits_linesFr  T)r  r  r  )r  r  r,  r  s       r2   r  z#HermesCLI._print_nous_credits_block%  se     	;:::::""$$ 	5 	 	D+t++tr3   c                    ddl m}  |            }|j        s>t                       t	          dt          d                      t          d           dS t                       t          d           t          dd	            |j        D ]<}|                                                    d
          r*t          d|            =t          dd	            |j	        rt          d|j	                    |j
        sdS t          | dd          s6t                       t          d|j
                    t          d           dS g d}|                     dd|j
         |          }|                     ||          }|dk    rld}	 ddl}|                    |j
                  }n# t           $ r d}Y nw xY w|st          d|j
                    t                       t          d           dS |dk    r\	 |                     |j
                   t          d|j
                    dS # t           $ r t          d|j
                    Y dS w xY wt          d           dS )u  `/credits` — focused Nous credit balance + top-up handoff.

        Interactive CLI: balance block + identity line + a 3-button panel
        (Open top-up / Copy link / Cancel). Non-interactive contexts — the TUI
        slash-worker subprocess and any place without a live prompt_toolkit app
        (``self._app is None``) — render a text variant (balance + tappable
        top-up URL), because the modal would try to read the RPC stdin and crash
        the worker. The terminal never confirms or polls payment (billing phase
        2a). Fail-open: a portal hiccup or logged-out account degrades to a clear
        message, never a crash.
        r   )build_credits_view     💳 Not logged into Nous Portal.z/  Run `hermes portal` to log in, then /credits.Nu     💳 Nous creditsr  {   ─────────────────────────────────────────u   📈r  z
  Top up: uR     Complete your top-up in the browser — credits will appear in /credits shortly.))r   zOpen top-up in browserzlaunch the portal billing page)r
  z	Copy linkz%copy the top-up URL to your clipboardrp  r
  z
do nothingu   💳 Add credits?zTop-up page:
r  r	  r	  r   Fz  Open this URL to top up: r
  u     📋 Copied: z  Top-up URL: #     🟡 Cancelled. No credits added.)r  r  	logged_inr  rF  r  balance_linesrh  r  identity_line	topup_urlr  r	  r	  
webbrowserr   r   r  )	r  r  viewr  r	  r   r	  openedr	  s	            r2   r!  zHermesCLI._show_credits%  s    	;:::::!!##~ 	GGGBb!?@@BBCCCCDDDF#$$$:   & 	 	D{{}}''// +t++:    	-+t)++,,,~ 	F tVT** 	GGG/t~//000fgggF
 
 

 ++%4DN44 , 
 

 55c7CCVF!!!!#88    FDDNDDEEEGGGfgggggv9++DN;;;88899999 9 9 97t~778888889 788888s$   F+ +F:9F:<1H/ /!II/billingc                 <   ddl m}  |            }|j        sot                       |j        r*d|j         }t          dt          |                      n.t          dt          d                      t          d           dS |                     |           dS )u  `/billing` — terminal billing for Nous (one interactive modal).

        ZERO sub-commands: any argument is ignored. Bare ``/billing`` always
        opens the Overview (Screen 1), whose numbered menu is the *only* way to
        reach the Buy / Auto-reload / Monthly-limit sub-screens. (Per the unified
        UX spec §0.4 — ``/billing buy`` etc. are gone; we don't error on a stray
        arg, we just open the menu.)

        Interactive CLI uses the prompt_toolkit modal; non-interactive contexts
        (TUI slash-worker / no live app) render text + the portal deep-link, never
        prompting (the URL is the affordance), same discipline as ``_show_credits``.
        All money is Decimal end-to-end; the terminal never collects card details.
        r   build_billing_statezCouldn't load billing: r  r   z/  Run `hermes portal` to log in, then /billing.N)agent.billing_viewr  r  r  rr  rF  r  _billing_overview)r  r  r  r  _msgs        r2   r"  zHermesCLI._show_billing%  s     	;:::::##%% 	GGG{ I>>>,"T((,,----F"%C"D"DFFGGGGHHHF 	u%%%%%r3   rB  c                |    t          |dd          }|sdS |rt          d|            t          d|            dS )zCPrint a portal deep-link line (the funnel for portal-only actions).
portal_urlNr  z  Manage on portal: )r  r  )r  r  rC  urls       r2   _billing_portal_hintzHermesCLI._billing_portal_hint&  sY    e\400 	F 	!-v--   *S**+++++r3   c                 `   ddl m} t                       t          dt	          d                      t          dd            |j        }|t|j        m ||j                  } ||j                  }|j        rdnd	}| 	                    |j        |j                  \  }}t          d| d
| d| d| d| d           t          d ||j
                              |j        }	|	H|	j        r2t          d ||	j                   d ||	j                              nt          d           |j        rM|j        pd	                                }
d|j         |
rd|
 nd	 }t          dt%          |                      t          dd            |j        s6t          dt%          d                      |                     |           dS |j        s8t          dt%          d                      |                     |d           dS |j        4t          dt%          d                      |                     |           t/          | dd          s|                     |           dS g d}|                     dd	|          }|                     ||          }|dk    r|                     |           dS |dk    r|                     |           dS |d k    r|                     |           dS |d!k    r|                     |           dS t          d"           dS )#uB   Screen 1 — overview: balance, spend bar, role-gated action menu.r   format_moneyr  zUsage creditsr  r  N (default ceiling)rO   r  z usedr  rd  rF  z  Balance: u     Auto-reload: on — below     → reload to z  Auto-reload: offzOrg: rH  +Billing actions require an org admin/owner.,Terminal billing is turned off for this org.z,Enable it on the portal to buy credits here.rB  uJ   No saved card for terminal charges yet — set one up on the portal first.r  ))buyzBuy creditsz!purchase a one-time credit top-up)r   zAdjust auto-reloadzconfigure automatic top-ups)r  zAdjust monthly limitz&show the monthly spend cap (read-only))portalzManage on portalz%open the billing page in your browserr  u   💳 Choose an actionr  r  r   r  r       🟡 Cancelled.)r  r  r  rF  r  monthly_cap	limit_usdspent_this_month_usdis_default_ceiling_billing_spend_barbalance_usdauto_reloadr   threshold_usdreload_to_usdorg_namer	  r  r  is_adminr  cli_billing_enabledcardr  r	  r	  _billing_buy_flow_billing_auto_reload_flow_billing_limit_screen_billing_open_portal)r  r  r  capspentr  ceilingrD  r  arr	  	_org_liner	  r   r	  s                  r2   r  zHermesCLI._billing_overview&  s   333333/"_--//000:   ?s}8 L!9::E L//E.1.DL**"G..(#- HC FuFF%FFgFF#FFFFFGGG=LL):;;==>>>>z ,F<<@P3Q3Q F F%1\"2B%C%CF F   
 *+++> 	*J$"++--DOO0Mt2OOI(I(())):    ~ 	LIJJLLMMM%%e,,,F( 	MJKKMMNNN%%e4b%cccF
 :gRdeegg   %%e,,, tVT** 	%%e,,,F
 
 
 ++)" , 
 
 55c7CCU??""5)))))v**511111w&&u-----x%%e,,,,,%&&&&&r3   )r  r  c                   ddl m} 	 | |t          |                    n
 |d          }| |t          |                    n
 |d          }n&# t          $ r  |d           |d          }}Y nw xY w|dk    rd}nt	          ||z  dz            }t          dt          d|                    }t	          t          |dz  |z                      }t          dt          ||                    }d|z  d||z
  z  z   }	|	|fS )uV  Render a 10-cell `█`/`░` spend bar + integer percent from spent/limit.

        Returns ``(bar, pct)`` where ``bar`` is like ``[████░░░░░░]`` and ``pct``
        is the spent/limit percentage clamped to 0..100. Box-drawing glyphs are
        not SGR codes, so this is leak-safe even without ``_b()``/``_d()``.
        r   DecimalNrV   rT   r  r  )decimalr9  rY   r   rE   r  r  r  )
r  r3  r  r  r9  r<   lr  r  rD  s
             r2   r%  zHermesCLI._billing_spend_bars&  s6    	$#####	.','8E

###ggcllA','8E

###ggcllAA 	. 	. 	.73<<qAAA	.66CCq1um$$C!Sc]]##U39u,--..QE6**++v~%56>":;Cxs   A
A  A65A6c                     t          |dd           }|st          d           d S d}	 dd l}|                    |          }n# t          $ r d}Y nw xY w|st          d|            t          d           d S )Nr  z  No portal URL available.Fr   z  Open this URL: z*  Complete billing changes in the browser.)r  r  r	  r   r   )r  r  r  r  r	  s        r2   r1  zHermesCLI._billing_open_portal&  s    e\400 	.///F	__S))FF 	 	 	FFF	 	-+c++,,,:;;;;;s   A AAc                 6   |j         sDt                       t          dt          d                      |                     |           dS |j        sFt                       t          dt          d                      |                     |d           dS dS )zGGuard charge/auto-reload entry points; print + return False if blocked.r  r  Fr  zEnable it on the portal first.rB  T)r+  r  rF  r  r  r,  )r  r  s     r2   _billing_require_adminz HermesCLI._billing_require_admin&  s    ~ 	GGGQb!NOOQQRRR%%e,,,5( 	GGGRb!OPPRRSSS%%e4T%UUU5tr3   c                 p   ddl mm} |                     |          sdS t	          | dd          sd                    fd|j        D                       }t                       t          dt          d                      t          d	|            t          d
           | 
                    |           dS g }|j        D ]0}|                    t          |           |          df           1|                    d           |                    d           |j        }|r
d|j         nd}|                     d||          }|                     ||          }	|	r|	dk    rt          d           dS ddlm}
 |	dk    rj|                     d          }|t          d           dS  ||pd|j        |j                  }|j        st          d|j                    dS |j        }n-	  |
|	          }n # t2          $ r t          d           Y dS w xY w|                     ||           dS )u@   Screen 2 (preset select) → Screen 3 (confirm + charge + poll).r   r  validate_charge_amountNr  r  c              3   .   K   | ]} |          V  d S r   r   )r   r   r  s     r2   r   z.HermesCLI._billing_buy_flow.<locals>.<genexpr>&  s+      NNAQNNNNNNr3   r  zBuy usage creditsz  Presets: z9  Run this in the interactive CLI to complete a purchase.zone-time credit purchase)customu   Custom amount…zenter your own amountr  z	Payment: zNo saved card on fileu   💳 Buy usage creditsr  rp  r  r8  rC  z  Amount (USD): rO   min_usdmax_usd     🔴 u     🔴 Invalid selection.)r  r  rA  r>  r  r   charge_presetsr  rF  r  r  r  rY   r-  maskedr	  r	  r:  r9  r	  rE  rF  r	  rr  amountr   _billing_confirm_and_charge)r  r  rA  presetspreset_choicesr   r-  r	  r   r	  r9  enteredro  rJ  r  s                 @r2   r.  zHermesCLI._billing_buy_flow&  s   KKKKKKKK**511 	F tVT** 	iiNNNN9MNNNNNGGGG7b!45577888)))***MNNN%%e,,,F% 	Y 	YA!!3q66<<??<V"WXXXXUVVV@AAAz.2O*T[***8O++*6> , 
 
 55c>JJ 	8++7888F######X--.@AAG;<<<&&2u}em  A 4 )))***XFF    1222 	((77777s   4H   HHc                    ddl m}m} |j        }t	                       t          dt          d                      t	          dd            t	          d ||                      |rt	          d|j                    t	          dd            d	}t          dt          |                      d
d ||           ddfdg}t          | dd          st	          d           dS | 
                    d ||           d|r|j        nd|          }|                     ||          }	|	d
k    rt	          d           dS ddlm}
m}m}  |            }	  |||          }nE# |$ r |                     |           Y dS |
$ r!}|                     ||           Y d}~dS d}~ww xY w|                    d          }|st	          d           dS t          dt          d                      |                     |||           dS )uF   Screen 3 — confirm total + consent, charge, then poll to settlement.r   )r  new_idempotency_keyr  zConfirm purchaser  r  r  z  Payment: z;By confirming, you allow Nous Research to charge your card.payzPay z nowzsubmit the charge)rp  zGo backzdo not charger  Nz3  Run in the interactive CLI to confirm a purchase.u	   💳 Pay r  zno saved cardr  r  )BillingErrorBillingScopeRequiredpost_charge)
amount_usdidempotency_keychargeIdu6     🔴 No charge id returned; please check the portal.u-   Charge submitted — confirming settlement…)r  r  rP  r-  r  rF  r  rI  r  r  r	  r	  hermes_cli.nous_billingrR  rS  rT  _billing_handle_scope_required_billing_render_charge_errorrD   _billing_poll_charge)r  r  rJ  r  rP  r-  _consentconfirm_choicesr   r	  rR  rS  rT  r  r   r"  	charge_ids                    r2   rK  z%HermesCLI._billing_confirm_and_charge&  s   HHHHHHHHz2"/0022333:   0,,v..00111 	/---...:   I 	 	#R\\##$$$ 5<<//5557JK2
 tVT** 	GHHHF++5ll622555#'<DKK_# , 
 

 55c?KKU??7888F	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 "!##	 [FCHHHFF# 	 	 	//666FF 	 	 	--eS999FFFFF	 JJz**	 	JKKKFJRGHHJJKKK!!%F;;;;;s   E* *F,F,F''F,c                 F   ddl }ddlm} ddlm}m}m} |                                 dz   }	d}
|                                 |	k     r6	  ||          }n^# |$ r6}|j        pd}|                    t          |d                     Y d}~\d}~w|$ r}t          d	|            Y d}~dS d}~ww xY w|                    d
          }|dk    rQ|                    d          }ddlm} |r | ||                    n
 ||          }t          d| d           dS |dk    r+|                     ||                    d                     dS |                    |
           |                                 |	k     6t          d           |                     |           dS )zGPoll loop: 2s interval, 5-min cap, cancellable. settled = ledger truth.r   Nr  )rR  BillingRateLimitedget_charge_statusr   r  r  r  u#     🔴 Could not check the charge: r  settled	amountUsd)parse_moneyu     ✅ z in credits added.r  rC  us     🟡 Still processing after 5 minutes — this is a timeout, not a failure. Check /billing or the portal shortly.)r+  r  r  rX  rR  r`  ra  retry_afterr,  r  r  rD   rd  _billing_render_charge_failedr  )r  r  r^  rJ  r	  r  rR  r`  ra  r  intervalr  r"  r	  	state_stramtrd  showns                     r2   r[  zHermesCLI._billing_poll_charge'  s<   333333	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 ::<<#%jjllX%%	**955%   +!CbMM***   ACAABBB 

8,,II%%jj--:::::::=W[[%5%5666<<PVCWCW8u888999H$$225&**X:N:NOOOKK!!!1 jjllX%%6 	 ? 	@ 	@ 	@!!%(((((s$   A B/,B

B/B**B/c                 
   |pd                                 }|dk    rt          d           nA|dk    rt          d           n+|dk    rt          d           nt          d|pd	 d
           |                     |           dS )zCBranch the poll `failed` reasons to the right copy + portal funnel.rO   authentication_requiredu`     🔴 Your bank requires verification (3DS). Complete it on the portal to finish this purchase.payment_method_expiredu6     🔴 Your card has expired. Update it on the portal.card_declinedu>     🔴 Your card was declined. Try another card on the portal.u%     🔴 The charge didn't go through (processing_errorz).N)r   r  r  )r  r  rC  s      r2   rf  z'HermesCLI._billing_render_charge_failedH'  s    ,B%%''... 4 5 5 5 5///JKKKK&&RSSSSZ&:VDVZZZ[[[!!%(((((r3   c                 ~   ddl m} t          |dd          }t          |dd          pt          |dd          }|dk    rt          d           n|dk    rt          d	           n|d
k    rLt          |di           pi                     d          }|t          d| d           nt          d           not          ||          rMt          |dd          }|r$dt          dt          |dz                       dnd}t          d| d           nt          d|            |rt          d|            dS dS )z6Render a typed BillingError at submit time (pre-poll).r   )r`  rr  Nr  no_payment_methoduz     💳 No saved card for terminal charges yet. Set one up on the portal (one-time credit buys don't save a reusable card).cli_billing_disabledu]     🔴 Terminal billing is turned off for this org — an admin must enable it on the portal.monthly_cap_exceededr  remainingUsdu&     🔴 Monthly spend cap reached — $z headroom left.u!     🔴 Monthly spend cap reached.re  z (try again in ~r  r:   z min)rO   u!     🟡 Too many charges right nowz. This isn't a payment failure.rG  z
  Portal: )rX  r`  r  r  rD   r   r  r  )	r  r  r"  r`  coder  r  r	  minss	            r2   rZ  z&HermesCLI._billing_render_charge_errorV'  s   >>>>>>sGT**S,55[VZ9[9[
&&& N O O O O+++qrrrr+++ i44:??OOI$YyYYYZZZZ9::::/00 	#3t44DIMUEc!U4"9-=-=&>&>EEEESUD[d[[[\\\\/C//""" 	-+z++,,,,,	- 	-r3   c                    t                       t          d           d}t          dt          |                      t          | dd          st          d           dS ddg}|                     d	d
|          }|                     ||          }|dk    rt          d           dS 	 ddlm}  |d          }n*# t          $ r}t          d|            Y d}~dS d}~ww xY w|rdt          d           ddl	m
}	  |	            }
|
j        r|
j        rt          d           dS t          d           |                     |
           dS t          d           dS )u;   403 insufficient_scope → lazy step-up re-auth (plan D-A).uC     💳 Terminal billing needs an extra permission (billing:manage).zCAn org admin/owner must tick "Allow terminal billing" during login.r  r  Nz?  Run `hermes portal` and approve terminal billing, then retry.)r  zRe-authorize nowz'open the portal to grant billing access)r	  zNot nowrp  u#   💳 Grant terminal billing access?z+Opens the portal device-authorization page.r  r  r   r   )step_up_nous_billing_scopeT)open_browseru      🔴 Re-authorization failed: u!     ✅ Billing permission granted.r  z%  Run /billing buy again to continue.u     🟡 Permission granted, but terminal billing is still turned off for this org. Enable it in the portal, then run /billing again.uE     🟡 Terminal billing was not granted (an admin must tick the box).)r  rF  r  r  r	  r	  hermes_cli.authrx  r   r  r  r  r,  r  )r  r  
_scope_msgr]  r   r	  rx  grantedr"  r  freshs              r2   rY  z(HermesCLI._billing_handle_scope_requiredp'  s   STTT 	 	%R
^^%%&&&tVT** 	STTTFR'
 ++7@# , 
 

 55c?KKU??%&&&F	BBBBBB00dCCCGG 	 	 	:S::;;;FFFFF	  	[5666
 ?>>>>>''))E 15#< 1=>>>>> \ ] ] ]))%00000YZZZZZs   +B> >
C%C  C%c           	      >	   ddl m}m} |                     |          sdS |j        }|j        }t          |o|j                  }t                       t          dt          d                      t          dd            t          dt          d                      |rt          d	|j                    n&t          d
           |                     |           dS |r1t          d ||j                   d ||j                              t!          | dd          s&t          d           |                     |           dS |rg d}|                     dd ||j                   d ||j                   |          }|                     ||          }	|	dk    r|                     |           dS |	dk    rt          d           dS |r ||j                  nd}
d}||
rd|
 dndz  }|                     |          }|t          d           dS |pd                                s
|r|j        }nH ||pd|j        |j                  }|j        r|j        t          d|j                    dS |j        }|r ||j                  nd}d}||rd| dndz  }|                     |          }|t          d           dS |pd                                s
|r|j        }nH ||pd|j        |j                  }|j        r|j        t          d|j                    dS |j        }||||k    rt          d           dS t                       d|j         d  ||           d!}t          dt          |                      d"d#g}|                     d$d% ||           d ||           |          }|                     ||          }|d&k    rt          d           dS dd'lm}m}m} 	  |d(t?          |          t?          |          )           nE# |$ r |                      |           Y dS |$ r!}| !                    ||           Y d}~dS d}~ww xY wt          d* ||           d ||           d+           dS ),u7  Screen 4 — auto-reload config: threshold + reload-to → PATCH.

        Prefills the current values from ``state.auto_reload``. Validates both
        amounts (2dp, within bounds, ``reload_to > threshold``). When auto-reload
        is already on, offers a "Turn off" path (PATCH ``enabled:false``).
        r   r@  Nr  zAuto-reloadr  r  z8Automatically buy more credits when your balance is low.z  Card on file: u3     No saved card — set one up on the portal first.z  Currently: below r  r  z6  Run in the interactive CLI to configure auto-reload.))editzEdit thresholdsz change when / how much to reload)r   zTurn offzdisable auto-reloadr  u   💳 Auto-reloadu   On — below r  r   r  r   z   When balance falls below (USD)r  z]: re  rO   rD  rG  z  Reload balance to (USD)u;     🔴 Reload-to amount must be greater than the threshold.z5By confirming, you authorize Nous Research to charge z whenever your balance reaches z*. Turn off any time here or on the portal.)agreezAgree and turn onzenable auto-reloadr  u   💳 Turn on auto-reload?zBelow r  rR  rS  patch_auto_top_upTr   r^   top_up_amountu     ✅ Auto-reload on: below rU   )"r  r  rA  r>  r-  r'  r  r   r  rF  r  r  rI  r  r(  r)  r  r	  r	  _billing_auto_reload_disabler	  r   rE  rF  r	  rJ  rr  rX  rR  rS  r  rC   rY  rZ  )r  r  r  rA  r-  r5  currently_ontop_choicesr   r  cur_thr
thr_promptthreshold_rawthreshold_amttvcur_rel
rel_prompt
reload_raw
reload_amtrv_ar_consentr]  r	  rR  rS  r  r"  s                              r2   r/  z#HermesCLI._billing_auto_reload_flow'  s    	LKKKKKKK**511 	FzB-2:..-"]++--...:   URRSSUUVVV 	2T[223333GHHH%%e,,,F 	>ll23C&D&D > >)\"*:;;> >  
 tVT** 	JKKK%%e,,,F  	  K
 //(BLL1A$B$B B B!-b.>!?!?B B $ 0  C 66sKHHCe||11%888f}})*** 5AJ,,r/000d7
7<'7''''<
//
;; %&&&F#**,, 		& 		&,MM''#U]EM  B 5 BI-***+++IM 5AJ,,r/000d0
7<'7''''<
,,Z88
%&&&F b'')) 		#l 		#)JJ'' b%-  B 5 BI-***+++J!6*:U:UOPPPF8DK 8 8-9\--H-H8 8 8 	
 	&R__&&'''@.
 ++-bLL77bbU_H`H`bb# , 
 

 55c?KKW%&&&F	
 	
 	
 	
 	
 	
 	
 	
 	
 	
		m(<(<ER\L]L]     $ 	 	 	//666FF 	 	 	--eS999FFFFF	 	 7\\--H-H 7 7'<
337 7 7 	8 	8 	8 	8 	8s   (P0 0Q2Q2Q--Q2c                 l   ddl m}m}m} |j        }|r|j        t          |j                  nd}|r|j        t          |j                  nd}	  |d||           nE# |$ r |                     |           Y dS |$ r!}| 	                    ||           Y d}~dS d}~ww xY wt          d           dS )zTurn off auto-reload (PATCH ``enabled:false``).

        The endpoint requires ``threshold``/``topUpAmount`` in the body even when
        disabling, so we echo back the current values (falling back to 0).
        r   r  Nr9   Fr  u     ✅ Auto-reload turned off.)rX  rR  rS  r  r'  r(  rC   r)  rY  rZ  r  )	r  r  rR  rS  r  r5  thrrelr"  s	            r2   r  z&HermesCLI._billing_auto_reload_disable1(  s*   	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 )+U0@0LeB$%%%RU)+U0@0LeB$%%%RU	es#NNNNN# 	 	 	//666FF 	 	 	--eS999FFFFF	 	-.....s   A   B"=B"BB"c                    ddl m} t                       t          dt	          d                      t          dd            |j        }||j         t          dt          d                      nC ||j                  } ||j                  }|j	        rd	nd
}t          d| d| d|            d}t          dt          |                      | 
                    |           dS )uA   Screen 5 — monthly spend limit (read-only; cap is portal-only).r   r  r  zMonthly spend limitr  r  Nz/No monthly cap visible (managed on the portal).r  rO   r  z used this monthuK   The monthly limit is set on the portal — the terminal shows it read-only.)r  r  r  rF  r  r!  r"  r  r#  r$  r  )r  r  r  r2  r3  r  r4  _limit_notes           r2   r0  zHermesCLI._billing_limit_screenJ(  s+   3333335"23355666:   ;#-/PMNNPPQQQQ L!9::E L//E.1.DL**"GBuBB%BBBBCCC 	 	&R__&&'''!!%(((((r3   	/insightsc                 n   |                                 }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  }nm||         dk    r'|dz   t          |          k     r||dz            }|dz  }n:||                                         rt          ||                   }|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)rI   r  z  Error generating insights: )r  rU  rE   r  r  r  r  r  agent.insightsr  generateformat_terminalcloser   )r  r  r   rI   r  rM  r  r  dbr   r  r   s               r2   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!!## 58}}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.F 
F4F//F4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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   Nr	  get_config_pathr   r   r  u;   🔄 MCP server config changed — reloading connections...Tr/  )yamlr+  r  _last_config_checkr~  r  r   r3  r4  r  _config_mtimer   	safe_loadr   rD   _config_mcp_serversr  r:  r;  _reload_mcpr<  )r  _yamlCONFIG_WATCH_INTERVALr5  _get_config_pathcfg_pathr8  r   new_cfgnew_mcp_reload_threads              r2   _check_config_mcp_changesz#HermesCLI._check_config_mcp_changes(  s    	 #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
 
 
 	sH   A2 2
B ?B C )CC CC CC 
C'&C'>   -y--yesr5  cmd_textc                 N   |sdS |                                                                 }|sdS |d                             d          r
|dd         }d}g }|D ]5}|                                | j        v rd} |                    |           6d                    |          |fS )	a  Split inline-skip tokens out of a destructive slash command.

        Returns ``(remainder, skip)`` where ``remainder`` is the original
        text with the command word and any recognized skip tokens removed,
        and ``skip`` is True iff at least one skip token was found.

        Examples:
            "/reset now"            -> ("", True)
            "/reset --yes My title" -> ("My title", True)
            "/new My title"         -> ("My title", False)
            "/clear"                -> ("", False)
        )rO   Fr   r  r  NFTrd  )r   r  r  r   _DESTRUCTIVE_SKIP_TOKENSr  r   )r  r  tokensskipkepttoks         r2   r
  z!HermesCLI._split_destructive_skip(  s      	9!!'')) 	9!9$$ 	 ABBZF 	 	Cyy{{c:::KKxx~~t##r3   c                    |r|                      |          \  }}|rdS 	 t                      }t          |t                    r|                    d          nd}d}t          |t                    r#t          |                    dd                    }n# t          $ r d}Y nw xY w|sdS g d}	|                     d| d||		          }
|
t          d
| d           dS | 	                    |
|	          }|t          d|
 d| d           dS |dk    rt          d
| d           dS |dk    r>t          dd          rt          d           t          d           nt          d           |S )ud  Prompt the user to confirm a destructive session slash command.

        Used by ``/clear``, ``/new``/``/reset``, and ``/undo`` before they
        discard conversation state.  Three-option prompt:

          1. Approve Once — proceed this time only
          2. Always Approve — proceed and persist
             ``approvals.destructive_slash_confirm: false`` so future
             destructive commands run without confirmation
          3. Cancel — abort

        Gated by ``approvals.destructive_slash_confirm`` (default on).  If the
        gate is off the function returns ``"once"`` immediately without
        prompting.

        Inline-skip: if ``cmd_original`` contains ``now``, ``--yes``, or
        ``-y`` as an argument (e.g. ``/reset now``, ``/new --yes My title``),
        the modal is bypassed and ``"once"`` is returned immediately. This is
        an escape hatch for non-interactive use and for the degraded path where
        the modal can't be marshaled onto the app loop (native Windows itself now
        drives the modal normally — see #33961). Callers are responsible
        for stripping the skip tokens from any remaining argument parsing
        (see :meth:`_split_destructive_skip`).

        Returns ``"once"``, ``"always"``, or ``None`` (cancelled).  Callers
        proceed with the destructive action when the result is non-None.
        r	  	approvalsNTdestructive_slash_confirm))r	  Approve Oncezproceed this time only)r	  Always Approvez+proceed and silence this prompt permanently)rp  r
  zkeep current conversationu	   ⚠️  /u     — destroys conversation stater  u   🟡 /z cancelled (no input).   🟡 Unrecognized choice 'z'. /z cancelled.rp  z# cancelled. Conversation unchanged.r	  z#approvals.destructive_slash_confirmFuJ   🔒 Future /clear, /new, /reset, and /undo will run without confirmation.zL   Re-enable via `approvals.destructive_slash_confirm: true` in config.yaml.u5   ⚠️  Couldn't persist opt-out — proceeding once.)r
  r  r   r   rD   r  r   r	  r  r	  rs  )r  r  r	  ra
  rc  _skipr!  r  confirm_requiredr	  r   r	  s               r2   r  z$HermesCLI._confirm_destructive_slash(  s   F  	33LAAHAu v	$!##C0:30E0EO,,,4I#)T** Z#'	6QSW(X(X#Y#Y  	$ 	$ 	$#	$   	6

 
 

 ++GgGGG , 
 

 ;:7:::;;;455c7CC>LsLLLLLMMM4XG7GGGHHH4X !FNN ObcccdeeeeMNNNs   A4B B$#B$c                    	 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 g d}| 	                    dd|          }|t          d	           dS |                     ||          }|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.
        r  NTmcp_reload_confirm))r	  r  z
reload now)r	  r  z.reload now and silence this prompt permanently)rp  r
  zleave MCP tools unchangedu9   ⚠️  /reload-mcp — Prompt cache invalidation warningzReloading MCP servers rebuilds the tool set for this session and
invalidates the provider prompt cache. The next message will
re-send full input tokens (can be expensive on long-context or
high-reasoning models).r  u&   🟡 /reload-mcp cancelled (no input).r  z'. /reload-mcp cancelled.rp  u0   🟡 /reload-mcp cancelled. MCP tools unchanged.r	  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  r   r   rD   r  r   r  r  r  r	  r  r	  rs  )r  ra
  r!  r  r  r	  r   r	  s           r2   r)  z!HermesCLI._confirm_and_reload_mcp;)  s   	$!##C0:30E0EO,,,4I#)T** S#'	6JD(Q(Q#R#R  	$ 	$ 	$#	$   	##D$=$=l$K$KLL # #  """# # # # # # # # # # # # # # #F
 
 

 ++M*
  , 	
 	
 ;:;;;F55c7CC>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 G""G&)G&c                 j   	 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        qddl m} d}| j        }|rDd|vr@d|vr<t          |          }t          |          D ]}||vr|                    |           |} || j        |d           ||| _        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   )rD  discover_mcp_tools_servers_lockNu   🔄 Reloading MCP servers...u     ♻️  Reconnected: r  u     ➕ Added: u     ➖ Removed: z  No MCP servers connected.u     🔧 z tool(s) available from z
 server(s))refresh_agent_mcp_toolsri  r  T)enabled_overriderS  zAdded servers: zRemoved servers: zReconnected servers: z MCP tool(s) now availablezNo MCP tools availabler  rO   r	  z,[IMPORTANT: MCP servers have been reloaded. zD. The tool list for this conversation has been updated accordingly.]r	  r   u     ✅ Agent updated — z tool(s) availableu     ❌ MCP reload failed: )rM  rD  r  r  r  rG  rd  r  r  r   r  rU  r   r  r  r   r  r  _persist_sessionr   rU  )r  rD  r  r  r  old_servers	new_toolsconnected_serversaddedremovedreconnectedr  r  etrK  _namechange_partstool_summarychange_detailr   s                       r2   r  zHermesCLI._reload_mcp~)  s/   `	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%BBBBBB $( * .%r//cmm!"XXF!'(9!:!: 1 1 .."MM%000'-$''J%5#    $/,<D)
 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'+I4N  %M N 
MN M6N 
N2N--N2c                 l   	 ddl m}m} | j        st	          d            |            } |            a|                    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_skillsrR  u   🔄 Reloading skills...r  r  r  z  No new skills detected.u     📚 z skill(s) availableNrj  r   c                 x    |                      dd          }|                      dd          }|rd| d| nd| S )Nr8  rO   r  z    - re  r	  )rj  nmr  s      r2   	_fmt_linez+HermesCLI._reload_skills.<locals>._fmt_line	*  sO    XXfb))xxr2204G,,,d,,,-2--Gr3   u     ➕ Added Skills:r  u     ➖ Removed Skills:z[USER INITIATED SKILLS RELOAD:rO   zAdded Skills:zRemoved Skills:z,Use skills_list to see the updated catalog.]r   u     ❌ Skills reload failed: )rO  r  rR  r  r  rN  rD   r   rY   r  r   _pending_skills_reload_noter   )r  r  rR  r   r  r  r  r  rj  sectionsr   s              r2   r*  zHermesCLI._reload_skills)  s   ?	6NNNNNNNN( 20111"]__F 1022O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 
H3H..H3	tool_namec                     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    …N)r  r  r  r  agent.displayr  rF  )r  r  r  r  s       r2   _on_tool_gen_startzHermesCLI._on_tool_gen_start8*  s     4-u55 	,   &+D#!!###000000y%8889999999:::::r3   function_namer  function_argsc                    |dk    r|pd}|pd}|                     d          }|                     d          }	|r|	rd| d|	 d| nd	| }
	 |                     d
           n# t          $ r Y nw xY wt          dt           d|
 t
                      	 |                     |           nV# t          $ rI |                                r2t          dt           |                                 t
                      Y nw xY w|                                  dS |dk    r)|pd}|rd| dnd| _	        |                                  dS |dk    rd| _
        nA|dk    r|                     d          rd
| _        n|r|                    d          rd
| _
        |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}  |||||                     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}  |t4          |          sud
| _        t          dt            |             t
                       |t8          d$z  |           d
t4                              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#tA          |          |k    r|d|d*z
           d+z   }| d,| | _	        tC          j"                    | _        | j                            |g           #                    ||ni            |                                  dS dS dS )-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).

        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moa.reference	referencerO   	moa_index	moa_countz
Reference r  r	  u   Reference — Tr  r  u   ┊ ◇ Nzmoa.aggregatingu   ◆ aggregating (r4  u   ◆ aggregatingztool.startedFztool.completedis_errorr}   r9   >   ri  r
  r  r  r   r
  )get_cute_tool_messager   )r   _long_tool_hint_firedri  r(  )TOOL_PROGRESS_FLAGis_seen	mark_seentool_progress_hint_clir   r6  r-  rc  r  )get_tool_preview_max_lenr  r  rd  )$rD   r  r   rF  r  r  r  r   rM  r  r  r  r  r  r  r   r  r  r  r  r  agent.onboardingr  r  r  r  r  r  r   
setdefaultr  r  rU  r+  r  r  )r  r"	  r  r  r  r0   rA  ra   r  r  r  aggr  r  storedstored_argsr  r  r  r  r  r  r  r  r  _pls                             r2   _on_tool_progresszHermesCLI._on_tool_progressL*  s   ( ((!0[E=bD**[))CJJ{++E?Bjuj;#;;;;E;;;RjchRjRjF--D-9999   555v5t55666=,,T2222 = = =::<< =;;tzz||;T;;<<<= F***%2C?B!Y!;S!;!;!;!;HYDF ''"'D+++

:0F0F+#'D   	'J11+>> 	'"&D)))$'D!  +!8<U!U!U!::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^d^h^hiq^r^rsssD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!.!:   	 	 	 	sJ   A& &
A32A3B. .AD D:J 
JJB4M 
M M tool_call_idc                     	 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 %sTr  )r  r  r  r   r   r   )r  r  r  r  r  r  s         r2   _on_tool_startzHermesCLI._on_tool_start*  s    	^AAAAAA22=-PPH#=E,\::: $# 	^ 	^ 	^LL>X\L]]]]]]	^s   $ 'AAfunction_resultc                    |dk    r	 t          |t                    rt          j        |          n|pi }n# t          $ r i }Y nw xY wt          |t
                    r|                    d          dk    rj|                    d          dk    rQ|                    d          pd}|dk    rdn| d	d
f\  }}	 t          d| d| d           n# t          $ r Y nw xY w| 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.delegate_taskr  
dispatchedr  r
  r  r  )r-  zit finishesz taskszthey finishu   [2m↩ Background u    running — I'll resume when z. Keep chatting.[0mNr   )render_edit_diff_with_delta)r  r  print_fnzEdit diff preview failed for %sTr  )r   rY   r   r  r   r   rD   rF  r  r  r  r  r   r   )r  r  r  r  r  ry  rR	  r  r  r  r  s              r2   _on_tool_completezHermesCLI._on_tool_complete*  s   
 O++8B?TW8X8XuO444_n_trt   &$'' FJJx,@,@L,P,PU[U_U_`fUgUgkwUwUwJJw'',189Q44\\\S`Da
dyyy\`yyyzzzz    D/33L$GG	ZAAAAAA''+!        	Z 	Z 	ZLL:MTXLYYYYYY	Zs3   -6 AA9C 
CC<D 'EE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          }t          |t                    r|ni }n# t          $ r Y nw xY w j        F	  |             _        n5# t          $ r(  j	        5  d _
        ddd           n# 1 swxY w Y    w xY w|                    d          }|                    d          }	t          |t"          t$          f          rt          |t&                    s|nd j        _        t          |	t"          t$          f          rt          |	t&                    s|	n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| d }nt	                      rd!| d"}n| d"}t5          d#t6           d$t8           d%t:           d&| d't8           
            fd(}t=          j        |d)                                           dS )*z*Start capturing audio from the microphone.r  FNr   )create_audio_recordercheck_voice_requirementsaudio_availabledetailsrO   z'Termux:API Android app is not installedzTermux:API command package detected, but the Android app is missing.
Install/update the Termux:API Android app, then retry /voice on.
Fallback: pkg install python-numpy portaudio && python -m pip install sounddevicezVoice mode requires either Termux:API microphone access or Python audio libraries.
Option 1: pkg install termux-api and install the Termux:API Android app
Option 2: pkg install python-numpy portaudio && python -m pip install 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: uv pip install faster-whisper  (free, local; `pip install faster-whisper` also works if pip is on PATH)
Option 2: Set GROQ_API_KEY (free tier)
Option 3: Set VOICE_TOOLS_OPENAI_KEY (paid)Tr  r
  silence_thresholdsilence_durationr  g      @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  rF  r  r  rS  r  rL  _voice_stop_and_transcriber  s   r2   _on_silencez5HermesCLI._voice_start_recording.<locals>._on_silenceL+  s   !  ,                       GGGGGHHHtV$$ ' '	$$&&&++-----s   	,00	play_beepip  r  	frequencyr  )on_silence_stopsupports_silence_autostopzauto-stops on silence | z to stop & exit continuouszTermux:API capture | z to stopr   u   ● Recording...rd  (r4  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  rS  r  rL  r+  r,  )still_recordingr  s    r2   _refresh_levelz8HermesCLI._voice_start_recording.<locals>._refresh_leveln+  s    !% < <&*&;O< < < < < < < < < < < < < < <& E4(( +TY +I((***
4   !s   ""r/  ) r  tools.voice_moder  r  r  rD   r@  r/  
executabler  r  r~  r  r   r   r   r  rE   rC   r  _silence_threshold_silence_duration_voice_beeps_enabledr  r<  r8  rF  r  r  r  r:  r;  )r  r  r  reqsr	  	voice_cfgr  _cfg
_threshold	_durationr  r  _label_recording_hintr  s   `              r2   _voice_start_recordingz HermesCLI._voice_start_recording*  sr   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;==$$W--D *4 6 6>BII 	 	 	D	 ''<'<'>'>$$   % 2 2,1D)2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 ]]#677
MM"455	$Z#u>>lzR\^bGcGclJJil 	/ $IU|<<iZPY[_E`E`iIIfi 	.	. 	. 	. 	. 	. $$&& 	666666	Cq11111   	 &&{&CCCC 	 	 	! . .(-%. . . . . . . . . . . . . . .	 --//4')DdKK 	2[[[[OO#%% 	2FfFFFOO!'111OTWTTdTTTTTOTTdTTUUU	! 	! 	! 	! 	! 	t<<<BBDDDDDs   	C:'C::C>C><E 
EEE- -F>FFF	FF	F$I8 8
JJ	J% %K6K
>K
K	KK	K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}d}	  j        b	  j         5  d _        ddd           n# 1 swxY w Y   t	           d          r  j        r j                                         	 |rVt          j        	                    |          r7|r!t          t           d| t                      n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                                         	 |rVt          j        	                    |          r7|r!t          t           d| t                      n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}nm|
                    d          rt          t           dt                      n9|
                    dd          }t          dt           d| t                      d}n<# t          $ r/}t          dt           d| t                      |du}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                                         	 |rVt          j        	                    |          r7|r!t          t           d| t                      n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                                         	 |rVt          j        	                    |          r7|r!t          t           d| t                      n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  zRecording preserved at: _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(  rS  r  rL  r   rF  r  r  )r   r  s    r2   _restart_recordingz@HermesCLI._voice_stop_and_transcribe.<locals>._restart_recording+  s    O33555"400 3TY 3 I00222223 3 3 3$ O O O4 M MA Mt M MNNNNNNNNNOs   AA 
B A==Br/  r  i  r  r  zNo speech detected.zTranscribing...r  sttr'  )transcribe_recording)r'  r  
transcriptrO   rr  Unknown errorr   zTranscription failed: zVoice processing error: )"r  r  r  r  rS  r  rL  r   r   isfilerF  r  r  unlinkr   r  r*  r  r:  r;  r<  r
  r   r  r  r~  r  rD   r0  r   r  r  r  r4  )r  	submittedtranscription_failedwav_pathr.  r  	stt_modelr  
stt_configr0  r   r1  rr  r   s   `             r2   r  z$HermesCLI._voice_stop_and_transcribey+  s"   
  	* 	*( 	* 	* 	* 	* 	* 	* 	* 	* %*D!%)D"		* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	$[	Q#+f ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& ,x 8 8 ,+ ,4 Q Q Q4 Q QRRRR	(+++     *(/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_ +0022H ((** ::::::I155555    D 4::D::;;;J ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& ,x 8 8 ,+ ,4 Q Q Q4 Q QRRRR	(+++     *(/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A 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)$$ ,L")E)E)K)K)M)M ,#L17799
%++---4(( +TY +I((***#''
333 		I&& ,4::D::;;;;

7O<<FTFFFFFGGG'+$ 	8 	8 	8@@@q@$@@AAA#+4#7      	8 ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& ,x 8 8 ,+ ,4 Q Q Q4 Q QRRRR	(+++     *(/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= ! / /).&/ / / / / / / / / / / / / / /tV$$ ' '	$$&&& ,x 8 8 ,+ ,4 Q Q Q4 Q QRRRR	(+++     *(/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sW  	99= =U# A//A36A3+AD 
DD5-U# #G7 6U# 7
HU# H$U# 0III AK 
K&%K&
AU# 9P U# 
P"U# !P""E U# "\  #
V-%V\  V\  &V::V>V>6AY 
YY a \a \  a #\ $3a A^10a 1
^>;a =^>>Aa A	a c                     | j         r|sdS | j                                         t          j        | j        |fd                                           dS )zISchedule TTS and mark it pending before continuous recording can restart.NTr\
  )r  r   r  r:  r;  _voice_speak_responser<  r  s     r2   _voice_speak_response_asyncz%HermesCLI._voice_speak_response_async+  sa     	d 	F""$$$-	
 	
 	
 %'''''r3   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]*?```rd  z\[([^\]]+)\]\([^)]+\)r  zhttps?://\S+rO   z\*\*(.+?)\*\*z	\*(.+?)\*z`(.+?)`z^#+\s*r   z^\s*[-*]\s+z---+r  r  hermes_voiceT)r  tts_r  z.mp3)ra   output_pathrU   r  z.oggzVoice TTS playback failed: %szTTS playback failed: ) r  r   r  tools.tts_toolr>  r  r?  rU  r   r   r  r   rG  r   makedirsr   r   tempfile
gettempdirr+  r  r3  getsizer4  rsplitr  r   r   r   rF  r  r  )r  ra   r>  r?  tts_textmp3_pathogg_pathr   s           r2   r;  z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                     	 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  r
  beep_enabledT)r~  r  rD   r   r   r  r   )r  r  r"  s      r2   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          }t%          |t&                    r|n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}
|                                 }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 rd  Tr  r
  auto_ttsFz (TTS enabled)rO   zVoice mode enabledz to start/stop recordingz#/voice tts  to toggle speech outputz!/voice off  to disable voice mode)r  rF  r  r  r  r  rO  r  r  r  r  r/  r  r   r  r~  r  rD   r   r   r  r   r8  )r  r  rO  	env_checkr   r!  r  r  
_raw_voicevoice_config
tts_status_ptt_displays               r2   _enable_voice_modez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$**733J)3J)E)EM::2L
E22 +% + +&*DO+ + + + + + + + + + + + + + + 	 	 	D	 *.@%%b

 3355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CsI   GGG"AI ;II II II 
I('I(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   )r.  r   )recs    r2   _bg_shutdownz3HermesCLI._disable_voice_mode.<locals>._bg_shutdowny,  s:    LLNNNNN    DDs    
&&Tr/  r   stop_playbackr   zVoice mode disabled.)r  r  r  rp  r  r  r  r:  r;  r<  r  r^  r   r   rG  rF  r  r  )r  recorderr\  r^  s       r2   _disable_voice_modezHermesCLI._disable_voice_modek,  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   r
  r   )check_tts_requirementszEWarning: No TTS provider available. Install edge-tts or set API keys.z
Voice TTS rU   )	r  rF  r  r  r  r  rC  rb  r  )r  r  rb  s      r2   _toggle_voice_ttszHermesCLI._toggle_voice_tts,  s    	tEEtEEFFFF 	2 	2"&/1DO	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2"o=:? 	n======))++ n4llfjllmmm755f55t5566666s   A		AAc                    ddl m}  |            }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            t          d|                                             t          dt           dt                      |d         	                    d          D ]}t          d|            dS )zShow current voice mode status.r   )r  r   zVoice Mode Statusz  Mode:      r  r  z  TTS:       z  Recording: YESr	  z  Record key: r  zRequirements:r	  rP  N)
r  r  rF  r  r  r  r  r  r8  r  )r  r  r!  r  s       r2   _show_voice_statuszHermesCLI._show_voice_status,  s/   ======''))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
 	A!=!=!?!?AABBB1u11411222O))$// 	# 	#DM4MM""""	# 	#r3   r  rA  outcomec                    t                               di                               dd          sdS d                    |                                          }t	          |          dk    r|dd         dz   }d                    |                                          }t	          |          dk    r|dd         dz   }t          d	t           | d| d
| d| t           
           dS )a  Print a one-line scrollback summary of a resolved modal prompt.

        Modal panels (approval / clarify) live in the prompt_toolkit layout and
        vanish on the next repaint, so the question and the decision leave no
        trace in the terminal scrollback. When display.persist_prompts is on
        (default), emit a dim single line after the prompt resolves so the
        decision survives in chat history.
        r1  r"  TNrd  r   w   r  r   re  r
  )r  rD   r   r  rU  rF  r  r  )r  r  rA  r	  rg  s        r2   _persist_prompt_summaryz!HermesCLI._persist_prompt_summary,  s     ~~i,,001BDII 	F&,,..))v;;DSD\E)F((7==??++w<<#dsdme+GGTG4GG%GG6GGGGGHHHHHr3   c                 L   ddl }t                              di                               dd          }t          j                    }| }||s|ng d|d| _        |                                |z   | _        || _        | 	                                 |                                }	 	 |                    d	          }d| _        | 
                    d
d|t          |                     |S # t          j        $ rZ | j        |                                z
  }	|	dk    rY n:|                                }
|
|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   Nr2  r$  r   )questionr	  r	  r	  Tr  r  r  Clarifyr  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  rD   r|  r  r  r  r  r  rP  rj  rY   r	  rF  r  r  )r  rl  r	  r	  r$  r	  is_open_endedr	  r   r  r5  s              r2   _clarify_callbackzHermesCLI._clarify_callback,  s    	..B//33IsCC# !&3;ww,	
 
 "'!2!2W!<!.
 	 #(//"3"3	&&'++A+66)*&,,S)Xs6{{SSS; & & & 2U__5F5FF	>>Eoo''00C77.1+OO%%%&	&  #!&!"[T[[G[[UY[[\\\F	
 	
s   'AC+ +1E3EEc                 :   ddl }d}t          j                    }|                                  d|i| _        |                                |z   | _        |                                  	 	 |                    d          }d| _        d| _        | 	                                 |                                  |r t          dt           d	t                      nt          dt           d
t                      |S # t          j        $ r; | j        |                                z
  }|dk    rY n|                                  Y nw xY wd| _        d| _        | 	                                 |                                  t          dt           dt                      dS )a%  
        Prompt for sudo password through the prompt_toolkit UI.
        
        Called from the agent thread when a sudo command is encountered.
        Uses the same clarify-style mechanism: sets UI state, waits on a
        queue for the user's response via the Enter key binding.
        r   Nr+  r	  Tr  r  r   u,     ✓ Password received (cached for session)u     ⏭ Skippedu)     ⏱ Timeout — continuing without sudorO   )r+  r|  r  r	  r  r  r  rP  rD   r	  rF  r  r  r	  )r  r	  r$  r	  r   r  s         r2   r9  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_permanentr  rr  c                &   ddl }| j        5  t          t                              di                               dd                    }t          j                    }|||                     ||          d|d| _        |	                                |z   | _
        |                                  |	                                }	 	 |                    d	
          }d| _        d| _
        |                                  ddddd}	|                     dd||	                    |t          |                               |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  r$  r:   rq  )r  r  r	  r	  r	  Tr  r  zallowed oncezallowed for sessionzadded to allowlistdeniedr	  r	  r	  deny   ⚠Approvalr  r   u!     ⏱ Timeout — denying commandrv  )r+  r  rE   r  rD   r|  r  _approval_choicesr  r  r  rP  rj  rY   r	  rF  r  r  )r  r  r  rr  r	  r$  r	  r	  r   _outcome_labelsr  r5  s               r2   r:  zHermesCLI._approval_callback/-  s    	  3	 3	*..b99==iLLMMG"[]]N #*11'?1[["0$ $D  ',oo&7&7'&AD# OO&+oo&7&7#**+///::F+/D(./D+OO%%% .#8"6 (	' 'O 00z7'++FCKK@@   "K3	 3	 3	 3	 3	 3	 3	 3	L { * * * $ 7%//:K:K KI A~~//++C44;;25/)))*#*4 $(D &'D#OOFFFFFGGGg3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	 3	s>   B7HA9E

1F3;H=3F30H2F33AHH
H
c                j    |rg dng d}t          |          dk    r|                    d           |S )z7Return approval choices for a dangerous command prompt.ru  )r	  r	  rv  F   r
  )rU  r  )r  r  rr  r	  s       r2   ry  zHermesCLI._approval_choicesu-  sG    ;Jk7777PkPkPkw<<"NN6"""r3   actionr/   r  c                 t    |                      d| d| d          }ddddd	                    |d          S )
aB  Adapt the generic approval UI for the computer_use tool.

        The computer_use handler expects verdicts of the form
        `approve_once` | `approve_session` | `always_approve` | `deny`.
        The CLI's built-in approval UI returns `once` | `session` | `always`
        | `deny`. Translate between the two.
        zcomputer_use: zAllow computer_use to perform `z`?)r  r  approve_onceapprove_sessionalways_approverv  ru  )r:  rD   )r  r}  r/   r  verdicts        r2   r=  z)HermesCLI._computer_use_approval_callback|-  se     )).W..D&DDD * 
 

 #(&	
 

 #gv

	r3   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   r	  r
  T	show_fullc                     g | ]
}|d k    |S )r
  r   r	  s     r2   r   z8HermesCLI._handle_approval_selection.<locals>.<listcomp>-  s"    QQQ6&@P@P@P@P@Pr3   r  r	  )r  rD   r   r   rU  r  rM  r4  )r  r  r	  r	  chosens        r2   _handle_approval_selectionz$HermesCLI._handle_approval_selection-  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+++#r3   c                 	   | j         }|sg S dCdt          dt          t                   dt          dt          dt          f
d}dDd
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}|}ddddd d!} ||d"          }|                     ||d"                     t          |          D ]H\  }}||	k    rd#nd$}|                     || |                    ||           d"d$%                     I |||          }t          d&|d'z
            } |||          }|
s.d(|v r*t          |          d)k    r|dd*          |d+|          z   }g }t          |          D ]~\  }}|                    ||          }|d,k     rt          |d-z             }n|d,k    rd.}nd/}||	k    rd#| d0}nd$| d0} || | |d1%          D ]}|	                    ||f           t          j        d2          j        }d3}d*}d4}t          d||z
            }|t          |          z   t          |          z   }||k    }|r|n|} t          d-|| z
  t          |          z
            }!t          |          |!k    r2|!d-k    rt          d-|!d-z
            nd-}"|d|"          |d5|          z   }| t          |          z   t          |          z   }#|rdnd-}$||#z
  |$z
  }%t          dt          |%d6                    }%|r |||          ng }&|%d-k     s|&sg }&n4t          |&          |%k    r!t          d-|%d-z
            }"|&d|"         d7gz   }&g }'|'	                    d8d9d:|z  z   d;z   f            ||'d8d<||           |s ||'d8|           |D ]} ||'d8d=||           |s ||'d8|           |D ]\  }}||	k    rd>nd?}( ||'d8|(||           |&r#|s ||'d8|           |&D ]} ||'d8d@||           |'	                    d8dAd:|z  z   dBz   f           |'S )Ea  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.
        .   rI  r	  r	  r	  r  r   c           	         t          j        d          j        }t          t	          |           gd |D             z   |dz
  gz             }t          t          |dz   |dz
            |dz
  t          d|dz
                      }|dz   S )Nr	  c                 ,    g | ]}t          |          S r   r  r%  s     r2   r   zWHermesCLI._get_approval_display_fragments.<locals>._panel_box_width.<locals>.<listcomp>-  r	  r3   rg  r  r>   rd  r	  r	  s          r2   r	  zCHermesCLI._get_approval_display_fragments.<locals>._panel_box_width-  r	  r3   rO   ra   r  r	  c                 Z    t          j        | t          d|          dd|          }|pdgS r	  r	  r	  s       r2   r	  zCHermesCLI._get_approval_display_fragments.<locals>._wrap_panel_text-  r	  r3   r	  r	  r	  Nc                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S r	  r	  r	  s         r2   r	  zEHermesCLI._get_approval_display_fragments.<locals>._append_panel_line-  r	  r3   c                 F    |                      |dd|z  z   dz   f           d S r	  r	  r	  s      r2   r	  zKHermesCLI._get_approval_display_fragments.<locals>._append_blank_panel_line-  r	  r3   r  r  r	  r	  r   r  Fu   ⚠️  Dangerous Commandz
Allow oncezAllow for this sessionzAdd to permanent allowlistDenyzShow full command)r	  r	  r	  rv  r
  r:      ❯ r  r	  r  r  r
  rg  r  u   … (choose Show full command)	   r  rV   rd  r  rP  r	  r  rd  u=   … (command truncated — use /logs or /debug for full text)rS   u   … (description truncated)r	  r	  r  r	  r	  r	  r	  r	  r	  r  r	  r  rI  r  )r  rY   r   rE   rD   r(  rI  r  rU  r  r  r  r,  r  ))r  r  r	  r	  r	  r	  r  r  r	  r	  r  r  cmd_displaychoice_labelsr  rM  r	  r\  r	  r	  cmd_wrappedr	  rA  
num_prefixr	  r	  r	  chrome_tightr	  r  mandatory_fulluse_compact_chromechrome_rowsmax_cmd_rowsr	  mandatory_no_descdesc_sep_costavailable_for_descdesc_wrappedr,  r	  s)                                            r2   _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	+ /2'
 
 )(b99--k2>>???"7++ 	 	IAv H}}VV$F  !1!1>=,,VV<<>>"&" " "     %$UM::	q)a-00 '&{4DEE 	Vw..3{3C3Ca3G3G%bqb/,<,<0 - - K 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,/?/?O 0 0 K (#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r3   var_namer
  c                 &    t          | |||          S r   r  )r  r  r
  metadatas       r2   r;  z"HermesCLI._secret_capture_callbackW.  s     xBBBr3   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  )ra   r!  )r  r  r  r   ra   r!  r  r   )r  r  s     r2   r	  z'HermesCLI._capture_modal_input_snapshotZ.  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  ra   rO   r!  r   )
r  r  r  r   rD   ra   r  rU  r!  r   )r  r  r  s      r2   r	  z'HermesCLI._restore_modal_input_snapshoth.  s    -%)" 	wtVT:: 	F	)*C||FB//CH"%hll3Da&H&H#ch--"X"XC 	 	 	DD	s   A"B	 	
BBc                 6   | j         r9	 | j         d                             d           n# t          $ r Y nw xY wd| _         | j        r@	 | j        d                             d           n# t          $ r Y nw xY wd| _        d| _        | j        rT	 | j        d                             d           n# t          $ r Y nw xY wd| _        d| _        |                                  | j        r/	 | 	                                 dS # t          $ r d| _        Y dS w xY wdS )um  Drain and clear every input-blocking overlay left by an interrupted agent.

        approval/clarify/sudo/secret prompts each block a worker thread on a
        ``response_queue.get()``.  When the agent is interrupted the worker
        thread is torn down, but the overlay's state dict stays set — leaving
        the CLI input gated (``read_only`` condition + keypress filter) with no
        thread servicing the prompt.  The result is a frozen terminal until the
        prompt's own timeout expires.  Push a terminal value onto each queue so
        any still-blocked thread unblocks cleanly, then nil the state out and
        restore the user's pre-modal draft (#14026).

        Safe default per prompt: approval -> "deny", clarify/sudo/secret ->
        cancel (None / empty).  Each step is wrapped so a dead queue can't
        prevent clearing the others.
        r	  rv  Nz7The user cancelled. Use your best judgement to proceed.FrO   r   )
r  r4  r   r  r  r  r  r	  r  _cancel_secret_capturer  s    r2   $_clear_active_overlays_for_interruptz.HermesCLI._clear_active_overlays_for_interruptu.  s      	($%56::6BBBB   #'D  	+#$4599M       "&D%*D" 	1 !1266r::::   #D"#D..000 	**++----- * * *%)""""*	* 	*sB    * 
77	 A* *
A76A7 B1 1
B>=B>+D DDc                     | j         sd S | j         d                             |           d | _         d| _        |                                  d S r	  )r  r4  r  rP  )r  rL   s     r2   _submit_secret_responsez!HermesCLI._submit_secret_response.  sW    ! 	F+,00777! ! 	r3   c                 0    |                      d           d S r  )r  r  s    r2   r  z HermesCLI._cancel_secret_capture.  s    $$R(((((r3   c                     t          | dd           r2	 | j        j                                         d S # t          $ r Y d S w xY wd S )Nr  )r  r  r   r  r   r  s    r2   _clear_secret_input_bufferz$HermesCLI._clear_secret_input_buffer.  sd    4&& 		(..00000   	 	s   3 
A Ac                 '   GHIJK t           j                   d _                                         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/          t0                    rnd}	d |D             }
 ||	|
          \  }}|r/t          dt           dt3          |           dt                      t5          d |D                       rSd                    d |
D                       }t          dt           dt3          |           d| t                      |n-                     t/          t0                    rnd|          n# t(          $ rL}t+          j        d|                                t/          t0                    rnd|          Y d}~n5d}~ww xY w                     t/          t0                    rnd|          t/          t0                    rCdv r>	 d	dlm} d	dl m!}  | j         j"        pd j#        pd j        rtI           j        dd          nd          } |tK          j&                    |          }|j'        s|j(        r|j)        r<t          dt           d t3          |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/          t0                    rd	d'l-m.}  |           j/        0                    d(d)           tc                      2                    d*tg                       d+d, d-           te          d./           	 dI 4                                 d _5        d}dGdKd}dJd} j6        ra	 d	d0l7m8}m9}m:}m;}m<}  |            } ||          d1k    r |              |             d.}n"# tz          t|          f$ r Y nt(          $ r Y nw xY w|rwt          j@                    Kt          jB                    }d2t0          fG fd3}t          jC        |K| jD        fd4|id.5          }|E                                 d6t0          fKfd7JdH jF        rt/          t0                    rd8HHI Jfd9}t          jG                     _H        d: _I        t          jC        |d.;          } | E                                 d}!| J                                rt           d<          r	  jL                            d=>          }!|!r jM        s jN        r/	  jO        P                    |!           n# t(          $ r Y nw xY wd}!te          d?           ||Q                                  j        R                    |!            S                                 	 t          d@z  }"t          |"dAdBC          5 }#|#V                    t          jW        dD           dEt1          |!          ddF         dGt3           j        jX                   dH j        jY         d$           t           j        jX                  D ]&\  }$}%|#V                    dI|$ dJ|%jY         d$           '	 ddd           n# 1 swxY w Y   n# t(          $ r Y nw xY wnVn@# t~          j[        $ r  \                    dKL           Y nw xY w|                     d=           | J                                |!t          dM          D ]A}&|                     dN>           | J                                s ntI           dOd          r nB| J                                r t                              dP| j_                   n|                     dQ>            jH        5t          d:t          jG                     jH        z
             _I        d _H        t          jG                     _a        	 d	dRlbmc}'  |'             n# t(          $ r Y nw xY w d                                 |r/K-KP                    d           ||                    dS>           t          jf        g                                 t          jh        dK           IrI                    dT j/                  n j/         _/         j        rhtI           j        dUd          rR j        ji         ji        k    r= j                     ji         j        ji                    j        ji         _i        d _k        IrI                    dVd          nd}(|(rIrI                    dW          sI                    dX          sw	 d	dYllmm})  j        rtI           j        dZd          nd}* |) jn         ji        |( j/        |* j         j         j"         j#         jo        d[\           n# t(          $ r Y nw xY wIrtI                    dW          sI                    dX          rJ|(sHI                    d]d^          }+d_|+ }( jp        r&d _p        t          d$t           d`t                      d},t          IoI                    da                    }-|- _        |-r!I                    db          p|!},|(r|,r|(dcz   }(n`|!r^|!},	 | J                                s6 j        r/tI           j        ddd          r j        r                                 n# t(          $ r Y nw xY wIrI                    ded          nd}.tI           dfd          }/ js        rWIrT|/sQI                    dg          }0|0r9 t                                }dh}1|diz
  t3          |1          z
  }2t           dj|1 dkt          |2dlz
  d	          z   dmt           }3t           dndk|diz
  z   dot           }4|0                                u                                }5t3          |5          dpk    rWtI           dqd          sFd$                    |5ddp                   }6|6d$t           drt3          |5          dpz
   dst           z  }6n|0                                }6t          d$|3 d$t           |6 t           d$|4            |(r|.s	 d	dtlvmw}7  |7            }8|8x                    dudv          }9t          |8z                    dwdx                    }:t          |8z                    dydz                    };n0# t(          $ r# dv}9t          dx          }:t          dz          };Y nw xY wIo)I                    dW          pI                    dX          }< j{        o	 j|        o|< }=|rAGr?|<s= t                                }t          d$t           d{dk|diz
  z   d|t                      ns|=rnptc                      }>|>2                    t          t          |( j        }          d*|: d~|9 d-d|:|;t          j        d t                                                      j        r=t          jf        V                    d           t          jf        g                                 IrI                    d          sI                    da          skI                    dd	          }?|?tI           j        dd          k    r;tI           j        dd          }@t          d$t           d|? d|@ dt                       j6        r|(r|s                     |(           |,rt           d          r|,g}A jL                                        s`	  jL                                        }B|Br|A0                    |B           n# t~          j[        $ r Y nw xY w jL                                        `d$                    |A          }Ct3          |A          }D|CddM         t3          |C          dMk    rdndz   }E|Ddlk    rte          d|D d|E d           nte          d|E d            jO        P                    |C           IrI                    d          nd}F|Fr_t           d          rO|FddF         t3          |F          dFk    rdndz   }Ete          d|E d            jO        P                    |F           |(K'	 K                    d           n# t(          $ r Y nw xY w||Q                                 |+|J                                r|                    d>           S S S # t(          $ r}te          d_|            Y d}~K'	 K                    d           n# t(          $ r Y nw xY w||Q                                 |,|J                                r|                    d>           dS dS dS d}~ww xY w# K'	 K                    d           n# t(          $ r Y nw xY w||Q                                 |+|J                                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
        FN	signaturezInitializing agent...r'  runtimerequest_overridesmodel_overrideruntime_overrider  r   )build_native_content_partsdecide_image_input_moder  rO   z5image_routing decision failed, defaulting to text: %sra   nativec                 ,    g | ]}t          |          S r   r  r   s     r2   r   z"HermesCLI.chat.<locals>.<listcomp>.  s    %=%=%=c!ff%=%=%=r3   r  u   ⚠ skipped z unreadable image path(s)c              3   H   K   | ]}|                     d           dk    V  dS r   r  Nr	  r   s     r2   r   z!HermesCLI.chat.<locals>.<genexpr>/  s1      HHA155==K7HHHHHHr3   r  c              3   >   K   | ]}t          |          j        V  d S r   )r   r8  r   s     r2   r   z!HermesCLI.chat.<locals>.<genexpr>	/  s*      .T.TtAww|.T.T.T.T.T.Tr3   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_surrogatesr	  r  r  r  r  r  Tr2  )_load_tts_config_get_provider_import_elevenlabs_import_sounddevicestream_tts_to_speaker
elevenlabssentencec                    sd                     t          j        dd                    }d}j        r+| t	          j                                        d           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.Tr  r  u    ⚕ Hermes r  rd  r  r   r  r  r  r   r   N)r  r  r  r  r	   r5  r  ru  r  rF  r  r  r  r  rZ   )r  rx  rA  r  _streaming_box_openedr  s       r2   display_callbackz(HermesCLI.chat.<locals>.display_callbackp/  s     1 `04- 66wt|WVX7Y7YZZ ./ R',$Qhlnn.E.Eg.N.N$Q$Q$QE 1uy'J'J5'Q'QQ ^W ^ ^E ^53taxQRCSCS;S ^ ^X\ ^ ^___{?HOO,=,=??@@@@@r3   r  )r  r/   r0   r7  deltac                 :                         |            d S d S r   )r4  )r  
text_queues    r2   stream_callbackz'HermesCLI.chat.<locals>.stream_callback/  s)    !-"u----- .-r3   ui   [Voice input — respond concisely and conversationally, 2-3 sentences max. No code blocks or markdown.] c                     t          j                   t          j                   	 t	          j                   n# t          $ r Y nw xY w	 ddlm} m	}  |j
        pd          }n# t          $ r d } d }Y nw xY wrz   n}t          dd           }|rt          ||          }d _        t          dd           }|rt          ||          }d _        t          dd           }d _        |d }	 j                            |j        d d         j
        rnd |          t          d	d
          rUt          dd           pi }|                                D ]\  }}	|	t)          ||	           d _        d _        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            n# t          $ r Y nw xY w|!| !	  | |           d S # t          $ r Y d S w xY wd S d S #                                  	 t          d            t          d            t	          d            n# t          $ r Y nw xY w|| 	  | |           w # t          $ r Y w w xY ww w xY w)Nr   )reset_current_session_keyset_current_session_keyr   rB
  r  _pending_moa_configrB  )user_messager  r  ri  persist_user_message
moa_configr8  Fr7  zrun_conversation raised: %sTr  _summarize_api_errorc                 0    t          |           d d         S )Nr   r  )r   s    r2   r  z3HermesCLI.chat.<locals>.run_agent.<locals>.<lambda>/  s    UXYZU[U[\`]`\`Ua r3   Error: )final_responser	  	api_callsrl  r  rr  )r  r9  r  r:  r  r;  r   r  r  r  r  r  rL  rB
  r  r  r   run_conversationr  r  r@
  r7  r8  r-  rr  r  )r  r  _approval_session_tokenagent_message_msn_srn_moa_cfg_restore_keyr	  r"  _summary_voice_prefixrJ  r   r  r  s               r2   r  z!HermesCLI.chat.<locals>.run_agent/  sN    +4+GHHH%d&=>>>/0MNNNN    D
3        /F.E49/ /++ ! 3 3 304-.2+++3 <I U 7 7g t%A4HH ;$<]D$Q$QM6:D3 t%BDII <$<]D$Q$QM7;D4"4)>EE+/(##H2!!Z88%2-1-Fss-K(7 $8E-OWW4#+ 9  F t%FNN E#*41Mt#T#T#ZXZ,4NN,<,< < <LD&%1 'dF ; ; ;%)
:>7?D<  
 
 
M"?tTTTTbwtz3IKaKabbcfggH*>H*>*>$&%&%*"&!) FFFFFF
  ..00024888-d3333D9999$    /:?X?d!556MNNNNN( ! ! ! DD! ;:?d?d ..00024888-d3333D9999$    /:?X?d!556MNNNN( ! ! ! D! ;?ds   A   
AAA, ,A=<A=:BF I+ 
G.!AG)$I+ )G..I+ -H4 4
I I	I 
I$#I$+K"-J/.K"/
J<9K";J<<K"KK"
KK"KK"r9   r/  r  ru  r  u*   
⚡ New message detected, interrupting...interrupt_debug.logr  r   r   %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	  r  r  r  r  )maybe_auto_title_emit_auxiliary_failure)r'  r   r   r(  r  )failure_callbackmain_runtimerr  r2  r  z+Continuous voice mode stopped due to error.rm  interrupt_messagez.

---
_[Interrupted - processing new message]__interrupt_requestedresponse_previewedr  last_reasoningr  r  r  r  r  r  r  r  rS   r  z  ... (u(    more lines — /reasoning full to show)r  r  r  r  r  r  r  r  r  r  z bold]left)r  rg  )r  title_alignr	  r	  r  paddingr  r{  rl  r  r,  r   u   ⚠ Iteration budget reached (r  u    ) — response may be incompleter  r  u   
⚡ Sending z messages after interrupt: 're  u   
⚡ Sending after interrupt: 'pending_steeru/   
⏩ Delivering leftover /steer as next turn: 'r  )r  r;  r  _ensure_runtime_credentials_resolve_turn_agent_configr  r   rF  r  r  _init_agentrD   agent.image_routingr  r  r~  r  r   r   r'  r   r-  r   r   rY   rU  r~  r   r  r   agent.context_referencesr  r]  r  r   r(  r  r   r  rx  blocked
referencesinjected_tokensrP  rJ  r  r  r  r  r  r  r  r  r  r  rC  r  r  r  r  r  r>  r  r|  r  r:  r  r;  r   r<  r  r+  r  r  is_aliverS  r  r  r  r  r4  rG  r  r  r   r   r{  r  _active_childrenr  rI  r	  rM  rH  r   identr  r  rO  r  r  r/  r0  r2  r,  r  r  r  agent.title_generatorr  r  r  r  r  clear_interruptr  r  r  r  r  r7  rX  r  r  r  r  r  r  r  rich_boxHORIZONTALSr{  r<  r~  r  
put_nowait)Lr  rJ  r  
turn_router  r  r  	_img_mode_img_exc_text_for_parts_img_str_pathsr  _skipped
_img_namesr  r  _ctx_len_ctx_resultrx  r   r  use_streaming_tts
tts_thread
stop_event_load_tts_cfg	_get_provr  r  r  _tts_cfgr  r  agent_threadinterrupt_msg_dbgr;  _ci_ch
_wait_tickr  responser  _title_failure_cberror_detailpending_message_interrupted_this_turnr  _reasoning_already_shownr}   r  r  r_topr_botr,  display_reasoningr  r9  rA  _resp_color
_resp_textis_error_responsealready_streamed_chat_console
_api_calls	_max_iter	all_partsr  combinedrR	  r  _leftover_steerr  r  r   r  r  sL   ``                                                                     @@@@@r2   chatzHermesCLI.chat.  st   * 	$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 
e! e! e! e! e! e! e! e! e!X '+ikkD#$'D!$+9TJJJL    !M'')) 1+4!344 0+,<(,(=(A(A#(A(N(N( #"  $2 )d6L )!)$($7$;$;M$J$J$J$J'0 !) !) !)$(D!)04 (!"OPPP)5 * 0 0 0 J00??? !EEGGG	%'36K'K%)$g%F%F%F !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 $- % % % $%!G#"H !; < < < ((d(;;;;;< !%%c***c '')) 1+p ( #())  J %%c%222'0022  t^U;; ((** NN# %*	   !!"!--- &2(+Ct?V1V(W(W%*.' +/)++D'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_<<++DOTZ=RSSS"&*"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%)&*NVZZ5N5N%O%O" +AD'% "(**-@"A"A"R] ^ ^'*]]H  #0(11335 J5 $DJ0FNN5
 
22444    D MS!],@%!H!H!HX] (/t5QSX'Y'Y$" Tv T6N T"JJ'788	 T2244A+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wt=Mu/U/U,0IIeCRCj,A,A))-~$-~-~s5zzB-~-~x|-~-~~)),5OO,=,=)RRR$R0AR4RR5RRSSS " 2 "	HFFFFFF+O--E!../?NNE"=eooN_aj>k>k"l"lK!<U__]\e=f=f!g!gJJ  H H H(E"=i"H"HK!<Y!G!GJJJH
 %+$^

80D0D0]

S\H]H]!#'#7#mD<S#m\mXm $ )> GX 2244AGGGUa!e_GGGGHHHH%  $/MMM!''7tGcddd?+??U???$*%0($0 &"88::	) 	) 	) 	 	 	 $ #
  &&&
  """  fjj55 fjj>W>W #ZZQ77
5Er!J!JJJ '
4Db I II<T < <&< <)2< <59< <    ;8 ;4E ;00:::  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	(EE	C>I 
J)AJ$$J)5DP >P 
P/P**P/:0AJ +=T) (AJ )U:AJ <	UAJ UDAJ ,_? Z' &_? '
Z41_? 3Z44_? 9AJ :A_? _- *B*_!_- !_%%_- (_%)_- ,_? -
_:7_? 9_::_? =AJ ?%`'$AJ &`''DAJ e AJ 
e%"AJ $e%%EAJ  A%l& %AJ &
l30AJ 2l33CAJ A
q AJ 
qAJ qFAJ -A,y AJ *zAJ zH!AJ B)0AC CAJ CAC,C)AJ C+AC,C,D'AJ HAH,H,
AH9H8AH9J
ALJALJAL J$AJ: J:
AKKAKLALLAL LAN	LAL4L3AN	L4
AML>AN	M AMMAAN	c                 \   	 t           j        }||                                sdS n# t          $ r Y dS w xY w	 |                    d           |                                 dS # t          $ r Y nw xY w	 t          j        t          j        dk    rdnd           dS # t          $ r Y dS w xY w)u   Clear screen + scrollback so nothing is stranded above the exit summary.

        Called from ``_print_exit_summary`` after ``app.run()`` has returned and
        prompt_toolkit has torn down its renderer + restored terminal modes —
        so a direct write to the real stdout fd is safe (the StdoutProxy /
        patch_stdout layer is gone by now).

        Sequence: ``ESC[3J`` (erase scrollback) + ``ESC[2J`` (erase visible
        screen) + ``ESC[H`` (cursor home). Modern terminals on Linux, macOS and
        Windows (Terminal / conhost with VT processing, which prompt_toolkit
        already enables) all honor these. Best-effort: skip silently when
        stdout isn't a real console, and fall back to the platform ``clear`` /
        ``cls`` command if the escape write fails.
        Nz[3J[2J[Hrs  r  r  )	r/  r0  rz  r   r{  r2  r   rp  r8  )r  r}  s     r2   _clear_terminal_on_exitz!HermesCLI._clear_terminal_on_exitl1  s    	ZF~V]]__~  	 	 	FF		LL/000LLNNNF 	 	 	D		Irw$eeG<<<<< 	 	 	DD	s/   "' 
55)A$ $
A10A15&B 
B+*B+c                     t          | dd          }|rt          |d          sdS t          |dd          }t          |t                    st          | dd          }t          |t                    r|sdS t          | dd          }t          |t                    s|}	 |                    ||           t          |dd          r|j        | _        dS dS # t          t          f$ r&}t          	                    d|           Y d}~dS d}~ww xY w)a  Best-effort SQLite/JSON flush before the CLI marks a session closed.

        ``run_conversation()`` normally persists at turn boundaries, but a
        terminal close/SIGHUP/SIGTERM can unwind the prompt_toolkit app while
        the agent thread still holds the current turn only in memory.  Flush the
        agent's live ``_session_messages`` before ``end_session()`` so resume,
        session_search, and state.db do not lose the interrupted turn.
        r   Nr  rI  r  r  z5Could not persist active CLI session before close: %s)
r  rS  r   r   r  r  r   r	  r   r   )r  r   r	  r  r   s        r2   $_persist_active_session_before_closez.HermesCLI._persist_active_session_before_close1  sO    gt,, 	GE+=>> 	F5"5t<<(D)) 	Ct%;TBBH(D)) 	 	F&t-CTJJ.55 	,#+ 	U""8-ABBBulD11 3"'"23 3,- 	U 	U 	ULLPRSTTTTTTTTT	Us   3C D'DD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
           	 ddlm}  |            }n# t          $ r d}Y nw xY w|dv rdnd| }t          d| j         |            |
rt          d|
 d|            t                       t          d| j                    |
rt          d|
            t          d|	            t          d| d| d| d           d	S 	 ddlm}  |d          }n# t          $ r d}Y nw xY wt          |           d	S )z:Print session resume info on exit, similar to Claude Code.r   c                 D    g | ]}|                     d           dk    |S )r	  r	  r	  r   r=   s     r2   r   z1HermesCLI._print_exit_summary.<locals>.<listcomp>1  s-    ]]]1QUU6]]V\E\E\QE\E\E\r3   c                 n    g | ]2}|                     d           dk    s|                     d          0|3S )r	  r  r   r	  r4  s     r2   r   z1HermesCLI._print_exit_summary.<locals>.<listcomp>1  sB    uuuAaeeFmmW]F]F]abafafgsatatF]aF]F]F]r3   r/  r:   r?   r  r<   NzResume this session with:get_active_profile_namer   )r   rC  rO   z -p z  hermes --resume z  hermes -c "rf  zSession:        zTitle:          zDuration:       zMessages:       r3  z user, z tool calls))get_active_goodbyeu   Goodbye! ⚕)r/  r  rU  r  r	   r5  r  divmodrE   r  r  get_session_titler  r   hermes_cli.profilesr7  r  r8  )r  rj	  	user_msgsr   r  rG   rm  rF   r8   duration_strsession_titler7  _active_profileprofile_flagr8  goodbyes                   r2   _print_exit_summaryzHermesCLI._print_exit_summary1  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 -...,GGGGGG"9"9";"; , , ,"+, &)>>>D\?D\D\  FtFFFGGG HF}FFFFGGG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,,^<< ) ) )()'NNNNNs6   
D* *
D76D7
E E*)E*H! !H0/H0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  rd  r6  >   rC  r   )r  r  rB  rO   )r	  >$r  u   ›   »u   →c              3       K   | ]}|v V  	d S r   r   )r   rk  r  s     r2   r   z4HermesCLI._get_tui_prompt_symbols.<locals>.<genexpr>2  s'      552rY555555r3   )r  rD  r   rZ   r;  r7  r  r~  )	r  rD  symbolr7  r
  r  r   arrow_charsr  s	           @r2   _get_tui_prompt_symbolsz!HermesCLI._get_tui_prompt_symbols1  s_   	GGGGGG--f55FF 	 	 	FFF	 "F**,,s2	CCCCCC--//G333#..f.. 	 	 	D	==?? 	"!>  !&.E"IIB	@555555555 	49++--333 v~s    $$A 
A*)A*c                 z    d}t          | dd          }|dS |j        }t          |d          dz  dz  }||         S )z;Return a visual audio level indicator based on current RMS.u    ▁▂▃▄▅▆▇r  NrO   i@  r'  )r  current_rmsr  )r  _LEVEL_BARSr[  rmsr  s        r2   _audio_level_barzHermesCLI._audio_level_bar2  sN    .d-t44;2o C"d*5!!r3   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 t          | dd          r |dd          S | j        r |dd          S | j        r |dd          S | j        r |d|                                           S | j        r |dd          S | j        r |dd          S d|fgS )zFReturn the prompt_toolkit fragments for the current interactive state.r  rO   r	  r  r  c                     r7|}|r+| d|                                                                  }| |dz   fgS |r| | d| d fgS | | d fgS )Nrd  )r   rZ   )r	  r  r  ra   r  state_suffixs       r2   _state_fragmentz<HermesCLI._get_tui_prompt_fragments.<locals>._state_fragment'2  s     - >"44U[[]]44;;==Ds
+,, C4 @ @% @ @, @ @ABBt44l44566r3   zclass:voice-recordingu   ●zclass:voice-processingu   ◉zclass:sudo-promptu   🔐u   🔑zclass:prompt-workingrw  r  Nclass:clarify-selectedu   ✎r  u   ⚕zclass:voice-promptu   🎤zclass:promptr  )rK  r  rb  rY   r  rP  r  r  r  r  r  r  r  r  r  r  r  )r  rI  rT  rD  r  rS  s       @@r2   _get_tui_prompt_fragmentsz#HermesCLI._get_tui_prompt_fragments"2  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4/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@@@())r3   c                 d    d                     d |                                 D                       S )z6Return the visible prompt text for width calculations.rO   c              3       K   | ]	\  }}|V  
d S r   r   rb  s      r2   r   z1HermesCLI._get_tui_prompt_text.<locals>.<genexpr>L2  s&      LL4tLLLLLLr3   )r   rV  r  s    r2   _get_tui_prompt_textzHermesCLI._get_tui_prompt_textJ2  s/    wwLL4+I+I+K+KLLLLLLr3   c                 V   t          t          | di           pi           }	 ddlm} |                     |                       n# t
          $ r Y nw xY w	 t                      r2dt          dt          fdfd|                                D             }n# t
          $ r Y nw xY w|S )ap  Layer the active skin's prompt_toolkit colors over the base TUI style.

        Also rewrites any hex-color tokens in the resulting style strings
        to their light-mode equivalents (via _LIGHT_MODE_REMAP) when the
        terminal is detected as light.  This makes the chrome readable
        on cream Terminal.app backgrounds without per-skin overrides.
        _tui_style_baser   )"get_prompt_toolkit_style_overridesro  r   c                     | s| S |                                  }t          d |D                       }|r| S d                    d |D                       S )Nc              3   @   K   | ]}|                     d           V  dS )zbg:NrE  r  s     r2   r   zHHermesCLI._build_tui_style_dict.<locals>._remap_value.<locals>.<genexpr>n2  s.      )N)N!!,,u*=*=)N)N)N)N)N)Nr3   rd  c              3   b   K   | ]*}|                     d           rt          |          n|V  +dS )r  N)r  rX  r  s     r2   r   zHHermesCLI._build_tui_style_dict.<locals>._remap_value.<locals>.<genexpr>r2  sV       $ $ ;<,,s:K:KR3A666QR$ $ $ $ $ $r3   )r  r~  r   )ro  r  has_explicit_bgs      r2   _remap_valuez5HermesCLI._build_tui_style_dict.<locals>._remap_valuej2  sw     ! WWYYF&))N)Nv)N)N)N&N&NO& ! 88 $ $!'$ $ $   r3   c                 2    i | ]\  }}| |pd           S r  r   )r   r  ro  ra  s      r2   r  z3HermesCLI._build_tui_style_dict.<locals>.<dictcomp>v2  s-    VVV41aaag2!6!6VVVr3   )	r   r  r  r\  r  r   r  rY   r  )r  
style_dictr\  ra  s      @r2   _build_tui_style_dictzHermesCLI._build_tui_style_dictN2  s    '$(92>>D"EE
	QQQQQQ@@BBCCCC 	 	 	D		!## WC C     WVVV:CSCSCUCUVVV
 	 	 	D	s$   #A 
AAA B 
B&%B&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  Nr[  Fr9   r  T)r  PTStyle	from_dictrd  r  r	  rM  r  s    r2   _apply_tui_skin_stylezHermesCLI._apply_tui_skin_style{2  sl    tVT** 	'$@QSW2X2X 	5!+D,F,F,H,HII	c***tr3   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    r2   _get_extra_tui_widgetsz HermesCLI._get_extra_tui_widgets2  s	     	r3   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  r  
input_areas      r2   _register_extra_tui_keybindingsz)HermesCLI._register_extra_tui_keybindings2  s      r3   )slash_confirm_widgetmodel_picker_widgetspinner_widgetc          
          d t          d          ||||||||g	|                                 t          | dd          |	|
|||||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   ri  s     r2   r   z8HermesCLI._build_tui_layout_children.<locals>.<listcomp>2  s,     
 
 
& !' & "!!r3   r   height_pet_widgetN)r   rj  r  )r  sudo_widgetsecret_widgetapproval_widgetrn  clarify_widgetro  rp  spacer
status_barinput_rule_top	image_barrl  input_rule_botvoice_status_barcompletions_menus                   r2   _build_tui_layout_childrenz$HermesCLI._build_tui_layout_children2  s    2
 
a   $# ,,.. mT22      !" !#$ !%
 
 
 	
r3   c                 ?                          d          sdS 	 t                       n# t          $ r Y nw xY w	 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}  |             n# t          $ r Y nw xY w	 t'          j        dd          }|                                dvr                     d| d           n# t          $ r Y nw xY w	 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"}  |tG          d            fd!"           n# t          $ r Y nw xY w j$        rO j%        sHd#&                     j$                  }                     d$tO                       d%|            d _%                                          d& _(        tS          j*                     _+        tS          j*                     _,        d& _-        d& _.        d	 _/        d	d'l0m1}   |            _2        d	dlm}  |            }|3                                r|4                                j5        nd( _6         j        7                    d)          pi  _8        d( _9        d _:        d& _;        d	 _<        d _=        d	 _>        d _?        d _@        d	 _A        t          jC                     _D        d _E        d	 _F        d& _G        d _H        d _I        d	 _J        g  _K        d	 _L        t          jC                     _M        d& _N        d& _O        d _P        d& _Q        d& _R        d& _S        t          jT                     _U         jU        V                                 t&          jW        7                    d*          d+k    r X                                 t&          jW        7                    d*          d+k    r Y                                 t                      }d	d,l[m\} |]                    |j^        d-          d.             } fd/}t          ||           |]                    d0d1          d2             }t                      r|]                    d3          d4             }t           fd5          }|]                    d6|7          |]                    d0d8|7          fd9                        }|]                    d:d-          d;             }|]                    d<t           fd=          7           fd>            } |]                    d?t           fd@          7           fdA            }! fdB}"t          dC          D ]U}#|#d	k    rdDn|#dz
  }$ |]                    t          |#          t           fdE          7           |"|$                     V|]                    d<t           fdF          7           fdG            }%|]                    d?t           fdH          7           fdI            }&|]                    d<t           fdJ          7           fdK            }'|]                    d?t           fdL          7           fdM            }(|]                    d<t           fdN          7           fdO            })|]                    d?t           fdP          7           fdQ            }*|]                    d0t           fdR          dS           fdT            }+ fdU},t          dC          D ]U}#|#d	k    rdDn|#dz
  }$ |]                    t          |#          t           fdV          7           |,|$                     V fdW}-t          dC          D ]U}#|#d	k    rdDn|#dz
  }$ |]                    t          |#          t           fdX          7           |-|$                     Vt           fdY          }.|]                    d<|.7          dZ             }/|]                    d?|.7          d[             }0|]                    d\           fd]            }1|]                    d^           fd_            }2|]                    d`           fda            }3|]                    db           fdc            }4t           fdd          }5|]                    d0|5dS           fde            }6|]                    df          dg             }7dh}8	 d	dilmd}9 d	djlemf}:mg};  |; |9                      }8 |:|8          }<t          |8t                    ru|8i                                                                j                    dkd          d	         i                                dlv r!|<dmk    rt          l                    dn|8           n# t          $ r dm}<Y nw xY w m                    |8           |]                    |<          fdo            }=d	d,l[m\}> |]                    |>jn        d-           fdp            }?|]                    dq           fdr            }@|]                    d0ds           fdt            }A fdu}Bd	dvlomp}C d	dwlqmr}D t          dx jt        dy z          }Et          t          dd{d|          |Bd}ddt          fd~          t          t           jx                             |D|E          dt           |C            |E          
  
        djz        _{         fd}F|Fj|        _}        d	gd	gd	gd&gd& _~         fd}Gjz        xj        |Gz  c_        j        j                            t          t	                      t          fd          7                      G d dt
                    }Hfd}Ij        j                             |H|I                     fd}Jfd}Kfd}Lfd}Mt          t          |L          |Md          }Nt          t           j                   j        t          j                   _        t          t          |J          |K          }Od2dt          dt          t                   dt          dt          dt          f
dd3dt          dt          dt          dt          t                   fddt          dt          dt          dt          ddf
ddt          dt          ddfdfd}Pt          t          t          |P          d          t          fd          7          }Qfd}Rt          t          t          |R          d          t          fd          7          }Sfd}Tt          t          t          |T          d          t          fd          7          }Ufd}Vt          t          t          |V          d          t          fd          7          }Wfd}Xt          t          t          |X          d          t          fd          7          }Yfd}Zt          t          t          |Z          d          t          fd          7          }[t          dfdd          }\t          dfdd          }] fd}^t          t          |^          t          fd                    }_fd}`t          t          t          |`          d          t          fd          7          }at          t          t          fd          dd&          t          fd          7          }b                     |           t#          dd          }ct%          t'                               |S|U|W|Y|Q|[|N|O|b|\|_|]|a|c                              }di 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ddddddddd _        t-          j                                                   }et3                      rt5          t6          j                  nd}ft;          d4|d||ed&d&d|fd|fini tG          t<          7                    di           7                    dd	                    ddt>          
dt>          ini tA                      _        	 d	dlm}g d	dlm tK          |gd d&          sfd}h|h|g_        d|g_        n# t          $ r Y nw xY wtO                       j         fd}i|i_         fd}jt          j        |jd          }k|k                                  fd}lt          j        |ld          }m|m                                 tW          j        tZ                      fd}n	 d	dl}o|o                    |oj        |n           ta          |od          r|o                    |oj        |n           t6          j        dk    rd	 }p|o                    |oj        |p           n# t          $ r Y nw xY wd
 }q	 t'          j        d	           nE# tj          $ r7 t          d           t[                                                         Y dS w xY wt6          j        dk    r	 d	dlta          d          rs                                }r	 |r                    d	j                   |r                    d	           |r                                 n# |r                                 w xY wn]# tj          tx          tz          f$ r@ d	dld	dl G fddj                  }s                     |s                       Y nw xY w	 t                      5  	 d	dl}t|t                                }u|u                    |q           n# t          $ r Y nt          $ r Y nw xY wt                                                                                          ddd           n# 1 swxY w Y   n# t          t          t          f$ r Y ntz          tj          f$ r}vt          |vtj                    rtK          |vdd          nd}wt          |v          }x|wt          j        k    rnB|wt          j        t          j        hv sd|xv s
d|xv sd|xv rt          d|v d           n Y d}v~vnd}v~vww xY wd _.                                          	 t          t           dt           d           n# t          $ r Y nw xY w j        r>tK           dd&          r+	  j                                         n# t          $ r Y nw xY wta           d          r9 jP        r2	  jP                                         n# t          $ r Y nw xY wd _P        	 d	dlm}y  |y             n# t          $ r Y nw xY wt          d           t          d           t          d                                             ta           d          r݉ j        rՉ j        r	  j                             j        j        d           n;# t          t          f$ r&}zt                              d|z           Y d}z~znd}z~zww xY wtK           dd&          s\	                       j        j                   n;# t          t          f$ r&}zt                              d|z           Y d}z~znd}z~zww xY wtK           dd&          r	 d	d lm}{  |{            d!z  }| j        j        }} j                            |}||"          r7t          d#t           d$t          |}           d%t                      n6t          d#t           d&t          |}           d't                      n;# t          t          f$ r&}zt                              d(|z           Y d}z~znd}z~zww xY w j        rytK           dd&          rf	 d	d)l0m}~  |~d* j        j        d&dtK           j        d+d          tK           j        d,d          pdd-.           n# t          $ r Y nw xY wt[                                                                                           n# d _.                                          	 t          t           dt           d           n# t          $ r Y nw xY w j        r>tK           dd&          r+	  j                                         n# t          $ r Y nw xY wta           d          r9 jP        r2	  jP                                         n# t          $ r Y nw xY wd _P        	 d	dlm}y  |y             n# t          $ r Y nw xY wt          d           t          d           t          d                                             ta           d          r݉ j        rՉ j        r	  j                             j        j        d           n;# t          t          f$ r&}zt                              d|z           Y d}z~znd}z~zww xY wtK           dd&          s\	                       j        j                   n;# t          t          f$ r&}zt                              d|z           Y d}z~znd}z~zww xY wtK           dd&          r	 d	d lm}{  |{            d!z  }| j        j        }} j                            |}||"          r7t          d#t           d$t          |}           d%t                      n6t          d#t           d&t          |}           d't                      n;# t          t          f$ r&}zt                              d(|z           Y d}z~znd}z~zww xY w j        rytK           dd&          rf	 d	d)l0m}~  |~d* j        j        d&dtK           j        d+d          tK           j        d,d          pdd-.           n# t          $ r Y nw xY wt[                                                                                           w xY wtK           d/d          rd	d0lm}  | j        d&1           dS dS (5  z=Run the interactive CLI loop with persistent input at bottom.r  Nr  r   r  rO   T)endr2  r   r  welcomezAWelcome to Hermes Agent! Type your message or /help for commands.r  r  r  r  r  )prewarm_picker_cache_asyncrz  r  >   r   r   r  r  uF   [bold red]⚠  Secret redaction is DISABLED[/] (HERMES_REDACT_SECRETS=z). API keys and tokens may appear verbatim in chat output, session JSONs, and logs. Set [cyan]security.redact_secrets: true[/] in config.yaml to re-enable.)OPENCLAW_RESIDUE_FLAGdetect_openclaw_residuer  r  openclaw_residue_hint_clir-  r  r  r
  r
  r
  )maybe_run_curatorinfc                 6                         d|  d          S )Nu   [dim #6b7684]💾 r  )r  )ri  r  s    r2   r  zHermesCLI.run.<locals>.<lambda>?3  s%    t':':1111( ( r3   )idle_for_seconds
on_summaryr  r  z]Activated skills:[/] Fr
  r9   r  r  r   r  )eagerc                     dS )a  Consume parser-level ignored terminal sequences before self-insert.

            install_ignored_terminal_sequences() in hermes_cli.pt_input_extras
            registers focus reports (CSI I / CSI O) as Keys.Ignore at the
            VT100 parser level. Without this no-op binding the default
            self-insert path would still fire and the bytes would land in
            the buffer.
            Nr   events    r2    handle_ignored_terminal_sequencez7HermesCLI.run.<locals>.handle_ignored_terminal_sequence3  s	     4r3   c           	         j         rS| j        j        j        }j         d                             |           d_         | j                                         dS j        r_| j        j        j        }                    |           | j        j                                         | j                                         dS j	        r/
                                 | j                                         dS j        r| j        j        j                                        }j                            d          pg }|r                    ||          nd}|Fj                            dd          }d|cxk    rt          |          k     rn n||         d         }                    |pd           | j        j                                         | j                                         dS j        r	 ddlm}                      |dd          	           n=# t*          $ r0}t-          d
|                                             Y d}~nd}~ww xY w| 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                                        }t5          j                  }|s|rQ                    ||          r|                    |          s,d_        | j        j        r| j                                          | j        j                            d           | j                                         dS !                    ||          rP                    |           | j        j                            d           | j                                         dS tE          j                  }	j        #                                 | j                                         |	r||	fn|}
j$        r|rtK          |          sj&        }|dk    r|	s|sd}nd}	 j'        <tQ          j'        d          r't5          j'        )                    |                    }n;# t*          $ r.}t-          dtT           d| dtV                      d}Y d}~nd}~ww xY w|rE|dd         t          |          dk    rdndz   }t-          dtX           d| dtV                      nd}|dk    r{j-                            |
           |r|n*dt          |	           dt          |	          dk    rdnd d}t-          d|dd          t          |          dk    rdnd            n|dk    rj.                            |
           	 t^          dz  }ta          |d d!"          5 }|1                    te          j3        d#           d$ti          |
          dd%         d&j$         d'           ddd           n# 1 swxY w Y   n# t*          $ r Y nw xY w	 dd(l5m6}m7}m8}m9}  |tt          |          stt-          dtT            |j&                   tV                       |t^          d)z  |           dtt          ;                    d*i           ;                    d+i           |<   n*# t*          $ r Y nw xY wj-                            |
           | j        j                            d           dS dS ),a  Handle Enter key - submit input.
            
            Routes to the correct queue based on active UI state:
            - Sudo password prompt: password goes to sudo response queue
            - Approval selection: selected choice goes to approval response queue
            - Clarify freetext mode: answer goes to the clarify response queue
            - Clarify choice mode: selected choice goes to the clarify response queue
            - Agent running: goes to _interrupt_queue (chat() monitors this)
            - Agent idle: goes to _pending_input (process_loop monitors this)
            Commands (starting with /) always go to _pending_input so they're
            handled as commands, not sent as interrupt text to the agent.
            r	  Nr	  r	  r   rp  )rd
  F)r
  r
  T)r
  r6  r}  r|  r  zSteer failed (u   ) — queued for next turn.r  r  rO   u   ⏩ Steered: 're  r   imager  r<   z
 attached]r0  r  r  r  r   r   r  z ENTER: queued interrupt msg=r:   z, agent_running=r   )BUSY_INPUT_FLAGbusy_input_hint_clir  r  r   r6  r-  )<r  rC  r   ra   r4  rL  r  r  r  r  r  r  r   rD   r	  rU  r	  r  r^  rd
  r`
  r   rF  r
  r  r  r  r  r
  r1  r  rA  r2  r
  r   r  r  rJ  r  r   rS  r}  r  r  r  r  r  r   r   r{  r+  r  rY   r  r  r  r  r  r  r  )r  ra   r	  r	  r	  rd
  _excr  r
  r  r  _effective_moderW  r"  r  r  r;  r  r  r  r  r  s                        r2   handle_enterz#HermesCLI.run.<locals>.handle_enter3  s	     y/4 !1266t<<<#' 	$$&&& ! y/4,,T222	(..000	$$&&& # //111	$$&&& ( y/4::<<377	BBHbPT^==dGLLLZ^>#8<<ZKKHH3333s7||33333!(!21!533F4FhGGG	(..000	$$&&& ' 
/ QPPPPP77'?'?u'M'M 8     ! / / /CTCCDDD,,......../ 	(..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 dGz dG ;;DZ;XX //55 -,0) 9/ -!INN,,,I,22T2JJJ I((***F ;;DZ;XX 
((...I,22T2JJJ I((***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'!B!B!B 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FIdG dGs{   8&H 
I)&IIAW 
X$XX9]8 A], ]8 ,]00]8 3]04]8 8
^^	B` 
`('`(r  r  c                 :    | j                             d           dS )uj  Alt+Enter inserts a newline for multi-line input.

            Works on mac/Linux/WSL. On Windows Terminal this keystroke is
            intercepted at the terminal layer (toggles fullscreen) and never
            reaches here — Windows users get newline via Ctrl+Enter instead
            (bound below as c-j, since WT delivers Ctrl+Enter as LF).
            r   Nr   insert_textr  s    r2   handle_alt_enterz'HermesCLI.run.<locals>.handle_alt_entero4  s!      ,,T22222r3   r  c                 :    | j                             d           dS )u  Ctrl+Enter inserts a newline on Windows, WSL, SSH, and WT.

                Windows Terminal (incl. WSL/SSH sessions through it) delivers
                Ctrl+Enter as LF (c-j), distinct from plain Enter (c-m). This
                binding makes Ctrl+Enter the equivalent of Alt+Enter on those
                terminals, giving an Enter-involving newline keystroke
                without requiring terminal settings changes. Ctrl+J (the raw
                LF keystroke) also triggers this by virtue of being the same
                key code — a harmless side effect since Ctrl+J has no
                conflicting Hermes binding. See issue #22379.
                r   Nr  r  s    r2   handle_ctrl_enter_newlinez0HermesCLI.run.<locals>.handle_ctrl_enter_newline{4  s!     $0066666r3   c                  D     j          o j         o j         o j         S r   )r  r  r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s0    ++|D4H0H|QUQaMa|jnj|f| r3   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.  r   )r  cli_refs    r2   handle_open_in_editorz,HermesCLI.run.<locals>.handle_open_in_editor4  s"     ))%*>?????r3   tabc                 T   | j         }|j        rQ|j        j        }|(|                    d           |j        o|j        j        }|dS |                    |           dS |j        r-|j        j        r!|                    |j        j                   dS |                                 dS )u  Tab: accept completion, auto-suggestion, or start completions.

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

            After accepting a provider like 'anthropic:', the completion menu
            closes and complete_while_typing doesn't fire (no keystroke).
            This binding re-triggers completions so stage-2 models appear
            immediately.
            Nr   )	r   complete_statecurrent_completiongo_to_completionapply_completion
suggestionra   r  start_completion)r  r  r  s      r2   
handle_tabz!HermesCLI.run.<locals>.handle_tab4  s     &C! ' /B
%((+++!$!3!]8J8]J%F$$Z00000 'CN$7 ' 344444 $$&&&&&r3   r  c                  <    t           j                  o j         S r   r  r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    tD4G/H/H/gQUQgMg r3   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  rC  rL  r  r  s    r2   
clarify_upz!HermesCLI.run.<locals>.clarify_up4  sY     " '25a9LZ9X[\9\2]2]#J/	$$&&&&&' 'r3   downc                  <    t           j                  o j         S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    d6I1J1J1iSWSiOi r3   c                     j         rlj                             d          pg }t          |          }t          |j         d         dz             j         d<   | j                                         dS dS )z'Move selection down in clarify choices.r	  r	  r  N)r  rD   rU  r  rC  rL  )r  r	  max_idxr  s      r2   clarify_downz#HermesCLI.run.<locals>.clarify_down4  s     " '-11)<<Bg,,25gt?RS]?^ab?b2c2c#J/	$$&&&&&	' 'r3   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 )Nr	  r	  FT)r  r  rD   rU  r4  rC  rL  )r  r	  r  r  s     r2   r  zDHermesCLI.run.<locals>._make_clarify_number_handler.<locals>.handler4  s    & /t/E /"155i@@FBGS\\))+,<=AA'#,OOO.2+16.	,,.....G,,15.	,,...../ / / / -,r3   r   r  r  r  s   ` r2   _make_clarify_number_handlerz3HermesCLI.run.<locals>._make_clarify_number_handler4  s)    / / / / / / Nr3   rS   r  c                  <    t           j                  o j         S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    tD<O7P7P7oY]YoUo r3   c                  ,    t           j                  S r   r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    tD4H/I/I r3   c                     j         rAt          dj         d         dz
            j         d<   | j                                         d S d S Nr   r	  r  )r  r  rC  rL  r  s    r2   approval_upz"HermesCLI.run.<locals>.approval_up4  sW    # '36q$:Nz:Z]^:^3_3_$Z0	$$&&&&&' 'r3   c                  ,    t           j                  S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    d6J1K1K r3   c                     j         r^t          j         d                   dz
  }t          |j         d         dz             j         d<   | j                                         d S d S )Nr	  r  r	  )r  rU  r  rC  rL  r  r  r  s     r2   approval_downz$HermesCLI.run.<locals>.approval_down4  sr    # 'd29=>>B36w@TU_@`cd@d3e3e$Z0	$$&&&&&' 'r3   c                  ,    t           j                  S r   r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    tD4M/N/N r3   c                     j         rOt          dj                             dd          dz
            j         d<   | j                                         d S d S r  )r  r  rD   rC  rL  r  s    r2   slash_confirm_upz'HermesCLI.run.<locals>.slash_confirm_up4  sd    ( '8;At?X?\?\]gij?k?kno?o8p8p)*5	$$&&&&&' 'r3   c                  ,    t           j                  S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>4  s    d6O1P1P r3   c                    j         r{t          j                             d          pg           dz
  }t          |j                             dd          dz             j         d<   | j                                         d S d S )Nr	  r  r	  r   )r  rU  rD   r  rC  rL  r  s     r2   slash_confirm_downz)HermesCLI.run.<locals>.slash_confirm_down4  s    ( 'd7;;IFFL"MMPQQ8;GTE^EbEbcmopEqEqtuEu8v8v)*5	$$&&&&&' 'r3   c                  ,    t           j                  S r   r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda> 5  s    tD4L/M/M r3   c                     j         rOt          dj                             dd          dz
            j         d<   | j                                         d S d S r  )r  r  rD   rC  rL  r  s    r2   model_picker_upz&HermesCLI.run.<locals>.model_picker_up 5  sd    ' '7:1d>V>Z>Z[egh>i>ilm>m7n7n(4	$$&&&&&' 'r3   c                  ,    t           j                  S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>5  s    d6N1O1O r3   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   r	  rR
  r  r	  r   )r  rD   rU  r  rC  rL  )r  r  r  r  s      r2   model_picker_downz(HermesCLI.run.<locals>.model_picker_down5  s    ,E yy!!Z//eii44:;;eii55;<<q@ #GUYYz1-E-E-I J JE*I  """""r3   c                  ,    t           j                  S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>5  s    48P3Q3Q r3   )r  r  c                                                       | j        j                                         | j                                         dS )zESC closes the /model picker.N)r
  rC  r   r  rL  r  s    r2   model_picker_escapez*HermesCLI.run.<locals>.model_picker_escape5  sH     $$&&&I$**,,,I  """""r3   c                       fd}|S )Nc                     j         rWt          j         d                   k     r;j         d<                                    | j                                         d S d S d S )Nr	  r	  )r  rU  r  rC  rL  )r  r  r  s    r2   r  zEHermesCLI.run.<locals>._make_approval_number_handler.<locals>.handler5  sq    ' +C#d6J96U2V2V,V,V7:D(433555I((*****+ +,V,Vr3   r   r  s   ` r2   _make_approval_number_handlerz4HermesCLI.run.<locals>._make_approval_number_handler5  s)    + + + + + +
 Nr3   c                  ,    t           j                  S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>%5  s    tD<P7Q7Q r3   c                       fd}|S )Nc                 B   j         rt          j                             d          pg           k     rij         d                  d         }                    |           | j        j                                         | j                                         d S d S d S )Nr	  r   )r  rU  rD   r	  rC  r   r  rL  )r  r	  r  r  s     r2   r  zJHermesCLI.run.<locals>._make_slash_confirm_number_handler.<locals>.handler)5  s    , +s4;T;X;XYb;c;c;igi7j7j1j1j!6yA#FqIF77???I,22444I((*****	+ +1j1jr3   r   r  s   ` r2   "_make_slash_confirm_number_handlerz9HermesCLI.run.<locals>._make_slash_confirm_number_handler(5  s)    + + + + + + Nr3   c                  ,    t           j                  S r   r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>35  s    tD<U7V7V r3   c                  d     j          o' j         o j         o j         o j         o j         S r   )r  r  r  r  r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>:5  sw    ++  @D4H0H  @QUQjMj  @sw  tD  pD  @  MQ  M_  I_  @  hl  h@  d@ r3   c                 P    | j         j                            | j                   dS )zAUp arrow: browse history when on first line, else move cursor up.r  N)rC  r   auto_upargr  s    r2   
history_upz!HermesCLI.run.<locals>.history_up=5  s(     I$,,59,=====r3   c                 P    | j         j                            | j                   dS )zDDown arrow: browse history when on last line, else move cursor down.r  N)rC  r   	auto_downr  r  s    r2   history_downz#HermesCLI.run.<locals>.history_downB5  s(     I$..UY.?????r3   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)rS  r  s    r2   handle_ctrl_lz$HermesCLI.run.<locals>.handle_ctrl_lG5  s     ##%%%%%r3   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        rN                    d           | j        j                                         | j                                         dS j        rM                                 | j        j                                         | j                                         dS t)          j        pj        pj        pj                  }|rK                                 | j        j                                         | j                                         |rj        rj        sdS j        rwj        rp|j        z
  dk     r1t;          d	           d_        | j                                         dS |_        t;          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   Recording cancelled.r/  rp  r  u   
⚡ Force exiting...u=   
⚡ Interrupting agent... (press Ctrl+C again to force exit))$r+  r  r  r  r  rF  r  r  r:  r;  rp  r<  rC  rL  r  r	  r   r  r  r
  r  r  r  r  r  r  r  r   r  r  r  r2  r  ra   r  r  )r  r5  _should_cancel_voice_recorder_ref_overlay_clearedr  r  s        r2   handle_ctrl_cz$HermesCLI.run.<locals>.handle_ctrl_cR5  sd    )++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==>>> (/  %'''	$$&&& ( 33H===	(..000	$$&&& ' ((***	(..000	$$&&&  $  '%''' &	      '99;;;	(..000	$$&&&   )<  " !tz !//#552333(,D%INN$$$F),&VWWW
$$&&&&& ). !$2G !	(..000%++---	$$&&&&&$(!	     s   &AAAzc-qc                 P   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        rN                    d           | j        j                                         | j                                         dS j        rM                                 | j        j                                         | j                                         dS t'          j        pj        pj        pj                  }|rK                                 | j        j                                         | j                                         |rj        rj        sdS j        r1j        r*t7          d           j                                         dS | j        j        j        sj        rR| j        j                                         j                                         | j                                         dS d_         | j        !                                 dS )	a  Alternative interrupt/exit shortcut (Ctrl+Q).

            Behaves like Ctrl+C: cancels active prompts, interrupts the
            running agent, or clears the input buffer. Does not support
            the double-press 'force exit' feature of Ctrl+C.
            FNTr   r  r/  rp  u   
⚡ Interrupting agent...)"r  r  r  r  rF  r  r  r:  r;  rp  r<  rC  rL  r  r	  r   r  r  r
  r  r  r  r  r  r  r  r   r  r  ra   r  r  r  r2  )r  r  r  r  r  r  s       r2   handle_ctrl_qz$HermesCLI.run.<locals>.handle_ctrl_q5  s
    $)  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==>>> (/  %'''	$$&&& ( 33H===	(..000	$$&&& ' ((***	(..000	$$&&&
  $  '%''' &	      '99;;;	(..000	$$&&& )<  " 	!tz 	!3444
$$&&&&&). !$2G !	(..000%++---	$$&&&&&$(!	     s   &?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)rC  r   ra   deleter  r  r2  )r  r  r  s     r2   handle_ctrl_dz$HermesCLI.run.<locals>.handle_ctrl_d5  sZ     )*Cx !

& !$(!	     r3   c                  H    t           j        p j        p j                  S r   )r  r  r  r  r  s   r2   r  zHermesCLI.run.<locals>.<lambda>	6  s"    D+\t/?\4C\]] r3   c                    j         rM                                 | j        j                                         | j                                         dS j        rBj        d                             d           d_        | j                                         dS j        rN	                    d           | j        j                                         | j                                         dS dS )z'ESC cancels active secret/sudo prompts.Nr	  rO   rp  )
r  r  rC  r   r  rL  r  r4  r  r	  r  s    r2   handle_escape_modalz*HermesCLI.run.<locals>.handle_escape_modal6  s     ! ++---	(..000	$$&&&  !1266r:::#' 	$$&&&( 33H===	(..000	$$&&&	 r3   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).r  r   z-Suspend (Ctrl+Z) is not supported on Windows.Nr   rw	  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{  r~  killSIGTSTP)_sigri  s   r2   _suspendz6HermesCLI.run.<locals>.handle_ctrl_z.<locals>._suspend+6  s7    CJJLL)))4<(((((r3   )r/  rG  rF  r  r  rC  rL  signalr=  r0  r  r  r7  )r  r0  r  r.  r  r  ri  s        @@r2   handle_ctrl_zz$HermesCLI.run.<locals>.handle_ctrl_z6  s     |w&&VTVVPTVVWWW	$$&&&!!!!BBBBBB>>>>>>(**77nUUJ\z\\*\\\C) ) ) ) ) ) OH%%%%%r3   zctrl+br  )-normalize_voice_record_key_for_prompt_toolkitvoice_record_key_from_configr  >   winsuperwindowszc-bzvoice.record_key %r uses a TUI-only modifier (super/win); CLI fell back to Ctrl+B. Use ctrl+<key> or alt+<key> for cross-runtime parity.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        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    r2   _start_recordingzDHermesCLI.run.<locals>.handle_voice_record.<locals>._start_recording6  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  rC  rL  r:  r;  r  r<  r  r  r  r  r  r  r   is_setr  r^  rG  r   )r  r^  r  r  s      r2   handle_voice_recordz*HermesCLI.run.<locals>.handle_voice_recordW6  sV    & ' /'( 6 605G-6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 	$$&&& "=   %''''' ) F) W-@ GD[ _f_{ 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
)C4 4
D DDD#&D#c                 .   t          j                    }t          | j        pd          }| j        pd}|                    dd                              dd          }t          |          }t          |          \  }}|r                    d           t          |          r-	                                r| j
                                         |rddlm}  ||          }|                    d          }| j        }j                            d	d
          }j                            dd          }	|dk    o||k    }
|	dk    ot          |          |	k    }|
s|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           t6                              dd         |dz   t          |          |           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.
            rO   r  r   r   z1mouse reports leaked into bracketed paste payloadrB  r   r  paste_collapse_thresholdr  paste_collapse_char_threshold  r  r  pastesTr  paste_rc  %H%M%S.txtr   r   z-Collapsed paste #%d: %d lines, %d chars -> %sr  re      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_counterrU  r   rn  r  r  r  r  ru  rC  rL  r  r  r  r   r   rD   ra   r   r  r   r  r	   r5  r  
write_textr   rT  r!  r  r   r/  rG  )r  _paste_handler_start_paste_raw_sizer  _had_mouse_reportsr  
line_countr  r^   char_threshold	lines_hit	chars_hit	paste_dir
paste_fileplaceholderr\  _paste_handler_elapsed_ms_paste_counter_paste_just_collapsedr  s                    r2   handle_pastez#HermesCLI.run.<locals>.handle_paste6  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
* KOO,FJJ	!%1PRV!W!W%MEjI.E	*Q.U3{3C3C~3U	 1 1CHNN4D4D4O4OPS4T4T 1"1%%%*%%% ,x 7IOOD4O@@@!*-qnQ6G-q-q(,..JaJabjJkJk-q-q-q!qJ))+)HHHKK OQ_`aQbdnqrdrtw  yD  uE  uE  GQ  R  R  R"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0r3   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ru  rC  rL  r  s    r2   handle_ctrl_vz$HermesCLI.run.<locals>.handle_ctrl_v6  s=     //11 '	$$&&&&&' 'r3   ro  c                 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    r2   handle_alt_vz#HermesCLI.run.<locals>.handle_alt_v6  s:     //11 	$$&&&&& r3   c                  ,                                      S r   )rV  r  s   r2   
get_promptz!HermesCLI.run.<locals>.get_prompt6  s    44666r3   )AutoSuggestFromHistory)ThreadedCompleterc                      t                      S r   )rR  r   r3   r2   r  zHermesCLI.run.<locals>.<lambda>7  s    ,>,@,@ r3   c                      t                      S r   r[  r   r3   r2   r  zHermesCLI.run.<locals>.<lambda>7  s    +<+>+> r3   )skill_commands_providercommand_filterskill_bundles_providerr  )r  r  	preferredzclass:input-areac                  ,    t           j                  S r   )r  r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>7  s    W-E(F(F r3   )history_suggest	completer)
rt  r
  r	  	multiline
wrap_lines	read_onlyr	  r4  complete_while_typingauto_suggestz.mdc                  >   	 ddl m}  j        j        }	  |             j                                        j        }n)# t          $ r t          j	        d          j        }Y nw xY wt          |j                                        |          S # t          $ r Y dS w xY w)Nr   r  r  r  )r=  r  r)  documentr&  r  r  r   r  r  r  r,  rY  )r  docr  rl  r  s      r2   _input_heightz$HermesCLI.run.<locals>._input_height"7  s    >>>>>> '0R'.wyy'7'@'@'B'B'J$$  R R R'-'?'I'I'Q$$$R1I--//$  
    qqs1   B &= B #A# B "A##*B 
BBc                 L   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    }j	        
                    d
d          }j	        
                    dd          }	|dk    o||k    }
|	dk    ot          |          |	k    }|
s|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           t$                              dd         |dz   t          |          |           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 bufferrB  Tr   r   NFr  rg  !paste_collapse_threshold_fallbackr  r  r  r  r  r  r  rc  r  r  r   r   z8Collapsed paste #%d: %d lines, %d chars -> %s (fallback)r  re  r  r  )r  ra   r  r  r  r!  rU  r  r'  r   rD   r  r   r  r	   r5  r  r  r   rT  )r  ra   r  cursorchars_addedr  newlines_addedis_paster^   r  r  r  r  r  r  r   _prev_newline_count_prev_text_lenr  s                 r2   _on_text_changedz'HermesCLI.run.<locals>._on_text_changed<7  s%    :#(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(KQOOI![__-LdSSN!AA*	*AI&*Js4yyN/JI 	4Y 	4H 	4T__S=Q=Q 	4q!!!Q&!!!(83	t<<<&)m.2C)m)mhlnnF]F]^fFgFg)m)m)mm
%%dW%===VXfghXikuxyky{~  @D  |E  |E  GQ  R  R  R+/%a(lN1,=llall_illl&)#(mm###	4 	4 	4 	4 	4 	4r3   c                  T    t           j                  pt           j                  S r   )r  r  r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>z7  s"    D!455Tg>S9T9T r3   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     r2   r  z5HermesCLI.run.<locals>._PlaceholderProcessor.__init__7  s    !)r3   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;  ra   linenorK  r   rN  )r  tira   s      r2   apply_transformationzAHermesCLI.run.<locals>._PlaceholderProcessor.apply_transformation7  sg    {' fBINN>>++D f-I\^bHcGd8deeee%====r3   N)r  r  r  r  r  rQ  r   r3   r2   _PlaceholderProcessorrI  7  s8        QQ* * *> > > > >r3   rR  c                  r   j         r                                } d|  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dS j	        r$
                                }j        pd	}| d
| S j        rdS j        r                                } d|  dS dS )Nzrecording... z to stop, Ctrl+C to cancelztranscribing...u6   type password (hidden), Enter to submit · ESC to skipu4   type secret (hidden), Enter to submit · ESC to skiprO   u%   type 1/2/3, or use ↑/↓ then Enterz%type your answer here and press Enterr  rd  u9   msg=interrupt · /queue · /bg · /steer · Ctrl+C cancelztype or z
 to record)r  r8  r  r  r  r  r  r  r  r  r  r  r  r  )r&  framer  r  s      r2   _get_placeholderz'HermesCLI.run.<locals>._get_placeholder7  s*   ' J 88::IvIIII( )((" POO$ NMM& r+ ?>>( ?>>% r' +6688 0K4K**&***% SRR" 5 88::4&44442r3   c                  F   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
        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))rW  u      secret hidden · Enter to skip)rW  u%     ↑/↓ to select, Enter to confirm)rW  u4     type 1/2/3, or ↑/↓ to select, Enter to confirmrO   )rW  z"  type your answer and press EnterrW  r  u2    command in progress · input temporarily disabled)r  r  rE   r  r+  r  r  r  r  r  r  r  r  r  r  r  r  )r  	countdownrT  r  s      r2   get_hint_textz$HermesCLI.run.<locals>.get_hint_text7  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'FIYIY'Y#Z#Z[[	Z.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  Ir3   c                       j         s# j        s j        s j        s j        s j        rdS                                  S )Nr  )r  r  r  r  r  r  r  r(  s   r2   get_hint_heightz&HermesCLI.run.<locals>.get_hint_height7  sl    " g&; w?V ZaZv   {B  {Q   U\  Um q //111r3   c                  >                                     } | sg S d| fgS )NrW  )r  )r  r  s    r2   get_spinner_textz'HermesCLI.run.<locals>.get_spinner_text7  s/    "7799L 	!<011r3   c                  ,                                      S r   )r  r(  s   r2   get_spinner_heightz)HermesCLI.run.<locals>.get_spinner_height7  s    11333r3   )r   rt  r6  )r   rt  align)r   rt  r  rI  r  r	  r	  r  r   c           	         t          j        d          j        }t          t	          |           gd |D             z   |dz
  gz             }t          t          |dz   |dz
            |dz
  t          d|dz
                      }|dz   S )zBChoose a stable panel width wide enough for the title and content.r	  c                 ,    g | ]}t          |          S r   r  r%  s     r2   r   z;HermesCLI.run.<locals>._panel_box_width.<locals>.<listcomp>
8  s    )N)N)N#d)))N)N)Nr3   rg  r  r>   rd  r	  )r  r	  r	  r  r	  r	  rC  s          r2   r	  z'HermesCLI.run.<locals>._panel_box_width8  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r3   ra   r  r	  c                 Z    t          j        | t          d|          dd|          }|pdgS )Nr  F)r  break_long_wordsbreak_on_hyphensr	  rO   r	  r	  s       r2   r	  z'HermesCLI.run.<locals>._wrap_panel_text8  s=    m!Umm!&!&"3  G ?rd"r3   r	  r	  r	  c                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S r	  r	  r	  s         r2   r	  z)HermesCLI.run.<locals>._append_panel_line8  r	  r3   c                 F    |                      |dd|z  z   dz   f           d S r	  r	  r	  s      r2   r	  z/HermesCLI.run.<locals>._append_blank_panel_line8  r	  r3   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
            }|dz   t          |          z   t          |          z   }||k    }|r|n|}t          d||z
  t          |          z
  t          |          z
            }t          |d          }|t          |          z   t          |          z   |k    }|rd} %||          }|dk    rg }n4t          |          |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.
            rl  r	  r	  r   r:   r  r  rV   rd  r  r  r  rP  r	  rS   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  rd  r  Nu   … (question truncated)class:clarify-border   ╭─ )class:clarify-titleri  rk  r  r  r	  zclass:clarify-questionclass:clarify-choicerU  zclass:clarify-active-otherr  r	  )r  rD   rI  rY   r  r(  rU  r  r  r  r  r,  r  )'r  rl  r	  r	  r  rM  r	  r  r\  	other_numother_num_prefixother_labelr	  r	  r	  r	  	other_idxother_label_mandother_wrappedr	  r	  r  r	  r  r  r  r  max_question_rowschoices_overflowquestion_wrappedr	  r,  r	  other_styler	  r	  r	  r	  r  s'                                     r2   _get_clarify_displayz+HermesCLI.run.<locals>._get_clarify_display!8  s    *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 )1_s>/B/BBSEWEWWN!/)!;*<M,,+K #Ay;'>^ATAT'TWZ[hWiWi'i j j #$5r : :  +S-@-@@3}CUCUUYbb &$%!//:JKK A%%#%  %&&):::
 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Lr3   )r6  c                       j         d uS r   )r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>8  s    W%;4%G r3   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-borderrl  class:sudo-titler}  rd  r  r   r  r	  class:sudo-textr  r	  )r  r  r  rU  )	r  r  bodyr	  r,  r	  r	  r	  r  s	        r2   _get_sudo_displayz(HermesCLI.run.<locals>._get_sudo_display8  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Lr3   c                       j         d uS r   )r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>8  s    W%8%D r3   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  r
  z2Enter secret below (hidden), ESC or Ctrl+C to skipr  r|  r~  r}  rd  r  r   r  r	  r  r  r	  )r  rD   insertrY   r  r  rU  )r  r  r
  r  	help_textr  r	  r	  r,  r	  r	  r	  r  s            r2   _get_secret_displayz*HermesCLI.run.<locals>._get_secret_display8  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Lr3   c                       j         d uS r   )r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s    W%:$%F r3   c                  ,                                      S r   )r  r(  s   r2   _get_approval_displayz,HermesCLI.run.<locals>._get_approval_display$9  s    ::<<<r3   c                       j         d uS r   )r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>,9  s    W%<D%H r3   c                  ,                                      S r   )r	  r(  s   r2   _get_slash_confirm_displayz1HermesCLI.run.<locals>._get_slash_confirm_display/9  s    ??AAAr3   c                       j         d uS r   )r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>79  s    W%A%M r3   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 Providerr	  total_modelsrO
  r8  r3  z modelr  r<   rO   r4  r	  u     ← currentr
  z	Current: ry  r  z on r	  rQ
  rR
  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  rd  r	  r   r  r	  _scroll_offsetrj  rm  rk  rd  r  r  r	  zclass:clarify-hintrU  rn  r  r  r	  r  r	  )r  rD   r   r   rU  r  r  r=  r  r&  r  r  r   r  r  r,  ru  r
  rH  )r  r	  r  r	  
_providersr   r  rA  hintrQ
  rR
  r	  r	  r	  r  r	  r
  r
  r,  r  r	  r	  r\  r	  r	  r	  r	  r	  r  s                           r2   _get_model_picker_displayz0HermesCLI.run.<locals>._get_model_picker_display;9  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   r2   r  zHermesCLI.run.<locals>.<lambda>~9  s    W%@%L r3   r  c                  .                          d          S )Nr  r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s    799%@@ r3   zclass:input-rule)charrt  r	  c                  .                          d          S )Nr  r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s    799(CC r3   c                  \    j         sg S t          j         j                  } dd|  dfgS )Nzclass:image-badgerd  )r  r  r  )badgesr  s    r2   _get_image_barz%HermesCLI.run.<locals>._get_image_bar9  sF    + 	4(& F )-f---899r3   c                  ,    t           j                  S r   )r  r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s    T'*B%C%C r3   c                  ,                                      S r   )rD  r(  s   r2   _get_voice_statusz(HermesCLI.run.<locals>._get_voice_status9  s    66888r3   rs  c                       j         S r   )r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s
    W%8 r3   c                  ,                                      S r   )rh  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s    W5V5V5X5X r3   c                  6     j         ot           dd           S )Nr"  F)r!  r  r(  s   r2   r  zHermesCLI.run.<locals>.<lambda>9  s'    3 W)NPUVVV r3   )rl  r  )r  r
  )rv  rw  rx  rn  ry  ro  rp  rz  r{  r|  r}  rl  r~  r  r  z
input-arear  z#888888 italicr
  zprompt-workingr  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status-bar-yolozbg:#1a1a2e #FF4444 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#AAAAAA italicz#87CEEBz#FF4444 boldz#FFA500 italiczbg:#1a1a2e #87CEEB)zapproval-cmdzapproval-choicezapproval-selectedzvoice-promptzvoice-recordingzvoice-processingzvoice-statuszvoice-status-recording)layoutkey_bindingsr	  full_screenmouse_supportr&  r1  cli_refresh_interval)refresh_intervalerase_when_doner@  )_output_screen_diff_hermes_osd_patchedc                     	 |,t          |d          r|j        |j        k     r|j        |_        n# t          $ r Y nw xY w | |||||||||	|
||          S )uh  Wraps pt's _output_screen_diff to suppress the
                    reserve-vertical-space scroll (renderer.py L232-242).

                    Strategy: ONLY when previous_screen is non-None and
                    its current height is genuinely smaller than the new
                    screen's height, inflate it to match.  This prevents
                    the bottom-cursor-move at L242 without changing any
                    other code path's behavior.

                    Critical: do NOT replace a None previous_screen with
                    a fresh Screen() — that would skip the proper
                    reset_attributes()+erase_down() at L178-185 which
                    fires when previous_screen is None (first-paint /
                    width-change).  Without that reset, ANSI styles
                    leak between renders.
                    Nrt  )rS  rt  r   )rC  r&  screencurrent_poscolor_depthprevious_screen
last_styleis_doner  attrs_for_style_stringstyle_string_has_stylesizeprevious_width	_orig_osds                r2   _patched_output_screen_diffz2HermesCLI.run.<locals>._patched_output_screen_diff`:  s    ,*67?T\;];]6.5EE9? 6$    %9VV[+'Wk.0Fn	  s   .2 
??c                  4                                     d S r   )r|  )_original_on_resizerC  r  s   r2   _resize_clear_ghostsz+HermesCLI.run.<locals>._resize_clear_ghosts:  s     **30CDDDDDr3   c                       j         sk j        st          j        d           # j        r+                     d           t          j        d           nt          j        d            j         id S d S )Nru  r  r  )r  r  r+  r,  r  rM  r  s   r2   spinner_loopz#HermesCLI.run.<locals>.spinner_loop:  s    ' $y JsOOO( 	$$$#$666JsOOOO JsOOO ' $ $ $ $ $r3   r/  c            
      f   j         s	 	 j                            d          } n|# t          j        $ rj j        s`                                 	 ddlm} |	                                D ]\  }}j        
                    |            n# t          $ r Y nw xY wY w xY w| sd_        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} t-          d|j                    n't-          d|j                    d| d|rd| ndz   } |s3j        r,t          | t                    r                    |           r|st          | t                    rt3          |           rt-          d|             	                     |           s"d_         j        r                                 n # t:          $ r t-          d           Y yw xY wt=          dd           }	|	r
d _        |	} ntA          j!        d          }
t          | t                    r"tE          |
#                    |                     ng }|r$                    |           } tK                       &                    |            |r<tO          |          }t-          dtP           d| d|dk    rdnd dtR                      d_        d_*        d_+        ,                                 	 -                    | |pd            d_        d_.        d_/        j0        1                                 d_2        d_+        3                                 ,                                 j4        r5                                 6                                 	 7                                 n,# t          $ r}tq          j9        d|           Y d }~nd }~ww xY wj:        r<j;        r5j<        s.fd }t{          j>        |d!          ?                                 	 ddlm} |	                                D ]\  }}j        
                    |            ny# t          $ r Y nlw xY w# d_        d_.        d_/        j0        1                                 d_2        d_+        3                                 ,                                 j4        r5                                 6                                 	 7                                 n,# t          $ r}tq          j9        d|           Y d }~nd }~ww xY wj:        r<j;        r5j<        s.fd }t{          j>        |d!          ?                                 	 ddlm} |	                                D ]\  }}j        
                    |            w # t          $ r Y w w xY wxY wn2# t          $ r%}t          A                    d"|           Y d }~nd }~ww xY wj         d S d S )#Nru  r  r   r  Fz)mouse reports leaked into submitted inputrB  r   rm  r  r  r  u     📎 Auto-attached image: u     📄 Detected file: z[User attached file: r   rO   u	   
⚙️  Tz 
[dim]Command interrupted.[/dim]r  r  r  u   📎 r  r  r<   z	 attachedr  r9   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:   r  r2  r,  )r  r   r	  r+  r,  r(  rL  r   rF  r  r  )r   rC  r  s    r2   r.  z?HermesCLI.run.<locals>.process_loop.<locals>._restart_recordingI;  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)Br  r  rD   r|  r	  r  r  r  r  drain_notificationsr4  r   r"  r   r&  rY   r  r  r  r  r  r8  rF  r  rD	  rJ  r1  rA  r2  r	  r  r  r   r  r   finditerr  r  r  rU  r  r  r  r  rL  r-  r  r  r   r  r  r  r  rW  r  r  r-  r   r  r  r  r:  r;  r<  r   r   )r}  r  _evt_synthsubmit_imagesr  
_file_drop
_drop_path
_remainder_seed_paste_ref_re
paste_refsrR	  	_goal_excr.  r   rC  r  s                   r2   process_loopz#HermesCLI.run.<locals>.process_loop:  s   ' u\t\!%)%8%<%<S%<%I%I

 ; ! ! !#2 	% ::<<<% S S S S S S4D4X4X4Z4Z !D !DLD&$($7$;$;F$C$C$C$C!D#, % % % $% ! & !  @ED< %'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 ' '! 9! 'z377! !BB:NN	! !% %*Z*E*E %JcdnJoJo % 9Z 9 9:::%#'#7#7
#C#C /48 1#&> !/$'HHJJJ0 % % % $$GHHH$H% !(.CT J J  %7;D4).JJ$ %'J/^$_$_MMWXbdgMhMh!pm&<&<Z&H&H!I!I!InpJ! O%)%B%B:%N%N
GGG44Z@@@ % `.. ^T ^ ^ ^ ^A2 ^ ^X\ ^ ^___ +/D'+0D(*/D'NN$$$C!		*]5Jd	KKK.3+-/*03-/55777572.3+00222(((  6 E BBDDD DDFFF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O0@0T0T0V0V @ @f $ 3 7 7 ? ? ? ?@( ! ! ! D! /4+-/*03-/55777572.3+00222(((  6 E BBDDD DDFFF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O0@0T0T0V0V @ @f $ 3 7 7 ? ? ? ?@( ! ! ! D! ! \ \ \NN#WYZ[[[[[[[[\i ' u\ u\ u\ u\ u\sF  ( Y5 *B!:BB!
BB!BB!Y5  B!!Y5 'EY5 .8Y5 '7I Y5 I<8Y5 ;I<< Y5 C.Y5 T &BY5 :Q Y5 
Q8Q3.Y5 3Q88AY5 ?:S; 9Y5 ;
T	Y5 T		Y5 BY1!V65Y16
W WY1WAY1&:Y! Y1!
Y.+Y1-Y..Y11Y5 5
Z$?ZZ$c                 p   	 t                               d|            n# t          $ r Y nw xY w	 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	 d
dlm}  |            }|/t          |dd          }||                    |j                   dS 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.

            Guarded ``logger.debug``: CPython's ``logging`` module is not
            reentrant-safe.  ``Logger.isEnabledFor`` caches level results
            in ``Logger._cache``; under shutdown races the cache can be
            cleared (``_clear_cache``) or mid-mutation when the signal
            fires, raising ``KeyError: <level_int>`` (e.g. ``KeyError: 10``
            for DEBUG) inside the handler.  That KeyError then escapes
            before ``raise KeyboardInterrupt()`` can fire, which bypasses
            prompt_toolkit's normal interrupt unwind and surfaces as the
            EIO cascade from issue #13710.  Wrap the log in a bare
            ``try/except`` so the handler can never raise through it.
            z0Received signal %s, triggering graceful shutdownr   Nr  Freceived signal HERMES_SIGTERM_GRACE1.5      ?r   rN  r>  )r   r   r   r  r   r  rC   r   r   r9  r  r+  r,  "prompt_toolkit.application.currentr/  rB  r2  r	  )signumrT  _gracer/  r  _loopr  s         r2   _signal_handlerz&HermesCLI.run.<locals>._signal_handlerh;  s   :OQWXXXX   
4$// +GDBRTY4Z4Z +J(()DF)D)DEEE%!&ry1G'O'O!P!P%z2 % % %!$%zz
6***    	NNNNNN&((##D&$77E(2249===   #%%%sS    
,,?C 0"B C B)&C (B))C 
CC?D 
D'&D'SIGHUPr  c                     d S r   r   )r  rT  s     r2   _sigint_absorbz%HermesCLI.run.<locals>._sigint_absorb;  s	     Fr3   c                 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)
rD   r   r@  rY   KeyErrorr  r  r  EIOdefault_exception_handler)r>  contextr"  s      r2   _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3r3   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 setupdarwinKqueueSelectorc                       e Zd Z fdZdS )-HermesCLI.run.<locals>._SelectEventLoopPolicyc                 R                                                                   S r   )SelectorEventLoopSelectSelector)r  
_aio_probe
_selectorss    r2   new_event_loopz<HermesCLI.run.<locals>._SelectEventLoopPolicy.new_event_loop<  s#    );;J<U<U<W<WXXXr3   N)r  r  r  r  )r  r  s   r2   _SelectEventLoopPolicyr  <  s;        Y Y Y Y Y Y Y Yr3   r  r  r  zBad file descriptorzInvalid argumentz
Error: stdin is not usable (z).
This can happen with certain Python installations (e.g. uv-managed cPython on macOS)
where kqueue cannot register fd 0.
Try reinstalling Python via pyenv or Homebrew, then re-run: hermes setupu%   Shutting down… (finalizing session)r  r  r  )cleanup_temp_recordingsr  	cli_closez!Could not close session in DB: %sr  z!Could not prune empty session: %sr	  r  r  r  u   ✓ Session z deletedu   ✗ Session z not found for deletionz$Could not delete session on exit: %sr\  re  r'  rG  r.  )r  rl  rm  r'  rG  rC  r  )relaunch)preserve_inheritedr  r  r   )rF  r  r   r  r  r,  r  ra  rP  r  _preload_resumed_session_display_resumed_historyr  r  r7  r  r  r^  r  r   r   r   r  r  r  r  r  r  r   r~  r  r  r
  agent.curatorr  rC   r  r  r   r  r  r|  r  r  r  r  r  r  r  r
  _cli_refr   r3  r4  r  rD   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   rG  r}  r@  rI  r%   r  r  rq  Ignorer  r  r!   rH  rY   r  r<  r  r   r   r   r  r   r   r=  r  prompt_toolkit.auto_suggestr*  prompt_toolkit.completionr+  r  r  r$   r"   r   r  r  r)  tempfile_suffixwindowrt  r'  on_text_changedcontrolinput_processorsr  r    r   r   r   r   r'  r)  r   RIGHTru  r   rE   r   rm  r#   r   r   r  r[  rf  rg  rd  r  r  r/  r0  r   r  _STEADY_CURSORr  r  prompt_toolkit.rendererr  r  r  r  r  
_on_resizer;  r<  rC  rD  rY  r  SIGTERMrS  r  rG  SIGINTfstatr  rB  	selectorsr  
EVENT_READ
unregisterr  r  r  r4  DefaultEventLoopPolicyset_event_loop_policyr   r?  set_exception_handlerr@  r  r0  r  r	  r	  BrokenPipeErrorr  r  EINVALEBADFr4  r  r  r   r  r.  r  r  r  r  r  r1  r  r6	  r  r   r+	  r   ro   delete_sessionrF  r  r]  rt  hermes_cli.relaunchr  r  )r  _term_linesr  _welcome_skin_welcome_text_welcome_colorr  _redact_rawr  r  r  r  r  _resid_color_get_cfg_path_residr
  rF  rG  r  skills_labelr
  r  	_cfg_pathr  _IgnoreKeysr  r  r  r  _editor_filterr  r  r  r  r  _num_idxr  r  r  r  r  r  r  r  r  _normal_inputr  r  r  r  r  r  _modal_prompt_activer  r  _raw_keyr  r  r   
_voice_keyr  r  r!  r$  r&  r)  r*  r+  
_completerr=  rF  rR  rU  rY  r[  r]  r_  rp  rz  ry  ry  r  rv  r  rw  r  rx  r  rn  r  ro  r|  r~  r  r}  r  r  r{  r  r  r	  _cpr_disabled_output_pt_rendererr  r  r  spinner_threadr  process_threadr  _signalr  r  _kqr  r9  r  
_stdin_err_errnor  r  r   r*	  _sessions_dir_sidr_  r  r  r	  r	  r  r  r	  r  r   rD  rE  r  r	  rC  r  rl  s   `                                                                                                                               @@@@@@@@@@@@@@@r2   r  zHermesCLI.run2  s-   ))%00 	F
	     	 	 	D		 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	JJJJJJ&&(((( 	 	 	D		)$;VDDK  ""*DDD##$.9$ $ $    	 	 	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  """:>>6773>>((***:>>6773>>((*** ]];;;;;;	"$	/	/		 		 
0	/		C	G C	G C	G C	G C	GJ 	!\222	'	"	"	3 	3 
#	"	3 ()) 	7VVE]]7 7 ]7$ #||||
 
 
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'N'N'N'NOO	P	P	' 	' 	' 	' 
Q	P	'
 
y)P)P)P)PQQ	R	R	' 	' 	' 	' 
S	R	' 
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	 	 	 	 	 "II 	C 	CD		11taxDXBFF3t99Y/V/V/V/V%W%WFXXY{Y{  }A  ZB  ZB  C  C  C  C " @  @  @  @
 
 
]	+	+	> 	> 
,	+	> 
}	-	-	@ 	@ 
.	-	@ 
	& 	& 	& 	& 
	& 
V	! V	! V	! V	! V	! 
V	!B 
@	! @	! @	! @	! @	! 
@	!D 
	! 	! 	! 	! 
	!   )]]]] 
  
 
!5T	B	B	 	 	 	 
C	B	$ 
	& 	& 
	&2 $	555555        43KKMMBBHFFxPPJ8S))
NN$$**,,223::1=CCEEIddd%'', 	    	 	 	JJJ	 	''111	
		9	' 9	' 9	' 9	' 
	9	't 	-,,,,,	#4	0	0?	 ?	 ?	 ?	 ?	 ?	 
1	0?	B 
	' 	' 	' 	' 
	' 
#			 	 	 	 
		" 	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 ('
33"&0 6 6 8 8$  !
 
 

2 -2
)	 	 	 	 	 	" $1
   c!&$)!3	4 3	4 3	4 3	4 3	4 3	4 3	4 3	4 3	4j 	))-==))
 	+22 !## TTTT   	
 	
 	
	> 	> 	> 	> 	>I 	> 	> 	>	 	 	 	 	: 	+223H3HIY3Z3Z[[[
0	 0	 0	 0	 0	d	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x	 x	 x	 x	 x	 x	 x	 x	 x	t .$%9::   GGGGHH
 
 
	 	 	 	 	 	 	 	" +$%677   DDDDEE
 
 
	 	 	 	 	 	 	 	8 -$%899   FFFFGG
 
 
	= 	= 	= 	= 	= /$%:;;   HHHHII
 
 
	B 	B 	B 	B 	B  4$%?@@   MMMMNN 
  
  
<	 <	 <	 <	 <	 <	 <	 <	 <	| 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 !   W W W W 
 
 

* 	,,RJ,GGG
 +bJJJ// +"/$3)=#1(;#1!)#1')#1%5%5 0   
 
.6 
 "6 
 +6 
 b6 
 .6 
 $6 
 .6 
  !:6 
 26 
 86 
 86 
  7!6 
" "#<#6 
$ 8%6 
( ))6 
, >-6 
. 3/6 
0 )*>16 
 6 
2 12F36 
4 ./C56 
6 67K76 
: i;6 
< ^=6 
> ?6 
@ iA6 
B C6 
D #$4E6 
F  G6 
J >K6 
L 9M6 
N .O6 
P Q6 
T yU6 
V nW6 
X ^Y6 
 6 
Z -(!/%- 00&?k6 
 6 
 6 
n !$"<"<">">?? &''&sz222 	  

 
 4H3S.//Y[
 #:>>)R#@#@#D#DE[]^#_#_`` !1
 
 
2 .<-G.))R3
 
6 	,C000	*,	::::::PPPPPP<)>FF &8" " " " "H 4O0370 	 	 	D	
 	-...!n	E 	E 	E 	E 	E 	E 	E .	$ 	$ 	$ 	$ 	$  #)dKKKv	\ v	\ v	\ v	\ v	\ v	\r #)dKKK 	%%%D	& D	& D	& D	& D	&L$	$$$$NN7?O<<<w)) @w~???( |w&&   w~~>>> 	 	 	D			4 		4 		4
	HQKKKK 	 	 	[  
 NNN$$&&&FF	 <8##K....:'788 $$3355C$Q
(=>>>q)))				Z2 K K K,,,,....Y Y Y Y Y Y Y YZ-N Y Y Y 001G1G1I1IJJJJJKF	+  	**** !1133E//0LMMMM#   D    D -...$$&&&			#              $ +_= 	 	 	D'" 	 	 	 <FjRY;Z;ZdWZ$777`dFz??D""5<555&$..(D00%--_Z _ _ _    )	, !%D!!!JJDJJRVWWWWW    z gd,<eDD J((****    D t.// ,D4H ,(113333    D'+$DDDDDD''))))    't,,,!$''''---
 55777 t]++ P0@ PTZ PI$001FTTTT!#45 I I ILL!DaHHHHHHHHI t%>FF MM66tz7LMMMM%'89 M M M%H!LLLLLLLLM 4!:EBB 
P	PLLLLLL(,(;#z4+::4m:\\ i#$X$X$X74==$X$XRV$X$XYYYY#$g$g$g74==$g$gae$g$ghhh%'89 P P P%KQOOOOOOOOP z gd,<eDD NNNNNN L(#':#8"'$(%dj'4@@!(Z!F!F!O%)     !   DNNN$$&&&((****w !%D!!!JJDJJRVWWWWW    z gd,<eDD J((****    D t.// ,D4H ,(113333    D'+$DDDDDD''))))    't,,,!$''''---
 55777 t]++ P0@ PTZ PI$001FTTTT!#45 I I ILL!DaHHHHHHHHI t%>FF MM66tz7LMMMM%'89 M M M%H!LLLLLLLLM 4!:EBB 
P	PLLLLLL(,(;#z4+::4m:\\ i#$X$X$X74==$X$XRV$X$XYYYY#$g$g$g74==$g$gae$g$ghhh%'89 P P P%KQOOOOOOOOP z gd,<eDD NNNNNN L(#':#8"'$(%dj'4@@!(Z!F!F!O%)     !   DNNN$$&&&((**** 4,d33 	G444444HT+FFFFFF	G 	Gs  8 
AA	6B   
BB(<D% %D65D6E' '
E43E48AF= =
G
	G
)I2 8H I2 HI2 H'I2 I!  I2 !
I.+I2 -I..I2 2
I?>I?K J+ *K +J:7K 9J::K 
K'&K'+#L 
LL5B6n, ,n;:n;M&3AN N
AN'N&AN'QA=AS S
ASSASS'AS< S<>AT>T=AT>U*AW U?0AW V/AW WAWWAW WAAX8X7AX8X<A[& YA[Y-AY;Y:A[Y;AZZA[Z	AZZA[ZAZZ:A[[A[& [A[[A[& [!A[["A[& [%An  [&A^,\ An  \A^,\BA^'^"An  ^'A^,^,An  _$A_0 _0
A_=_<A_=`A`5 `5
AaaAaaAa9 a9
AbbAbbAb# b#
Ab0b/Ab0d&Ae eAe:eAe5e5Ae:fAf1 f1Ag)gAg$g$Ag)h B+Aj, j,Ak$j>AkkAk$lAAm m
Am$m#Am$n A~n=$Ao"o!A~o"
Ao/o,A~o.Ao/o/A~pAp'p&A~p'
Ap4p1A~p3Ap4p4A~qAq+q*A~q+
Aq8q5A~q7Aq8q8
A~rArrA~r
Ar"rA~r!Ar"r"A*A~t&At4t3A~t4Au,uAu'u"A~u'Au,u,A~vAv#v"A~v#Awv5AwwA~wAwwA~w2B+AzzA~zA{z0A{{A~{A{{A~{4AA}	}A~}	
A}}A~}A}};A~)NNNNNNNFNFFFru  r  )rI  )ri  )rt  rS   )F)r  r   )r  )FN)r  Tr	  r  )rd  rd  r  r  )r  )r  )NNN)r  r  r  r  rY   r
   rE   r   r  r  rF  rt  rC   rM  rP  rS  rW  rR  rh  rc  r|  r  staticmethodr  r  r  r  r   r   r  r  classmethodr  r&  rb  r  r  r  r  r  r  r+  r,  r  r  r  r  r   r  r'  r)  r-  r0  r4  r8  objectr=  rD  r]  rh  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r.  r%  r3  r@  rI  rP  ra  r   rj  rm  ru  ry  r  r  r  r\  r[  r  r  r  r  r  r  r  r	  r	  r!	  r'	  r+	  r%	  rD	  rM	  rQ	  rk	  rZ	  r]	  r|	  r	  r	  r	  r	  r	  r
  r
  r
  r
  r
  r
  r`
  rs
  r
  r
  r
  r
  r  r
  r
  r1  rr  r|  r  r  r  r  rR  r  r  r  r   r  r!  r"  r  r  r%  r1  r>  r.  rK  r[  rf  rZ  rY  r/  r  r0  r#  r  	frozensetr  r
  r  r)  r  r*  r  r  r  r  r(  r  r<  r;  r   rX  r`  rc  rf  rj  ro  r9  r:  ry  r=  r  r  r;  r	  r	  r  r  r  r  r-  r/  r1  rB  rK  rP  rV  rY  rd  rh  rj  rm  r  r  r   r3   r2   ru  ru  L  s         ""&! %"N* N*N* s)N* 	N*
 N* N* N* $N* N* N* N* N* N* N* N* N*`E   S T VZ    8	. 	. 	. 	.# # # # # # #0   $   2" " " "4 OT   t X\    *Q2 Q2 Q2 Q2f(= (=% (=4 (= (= (= (=T+@ +@ +@Y] +@ +@ +@ +@Z	'hsm 	' 	' 	' 	' 	' & & & & & \&J Jx} JS JRU J J J J
 #% #%(5/ #%TY #%ae #%ru #% #% #% \#%J 
6Xe_ 
6 
6RU 
6 
6 
6 \
6h$sCx. h h h hT # # # # # \# 0 0 0 0 0 0 [06 = =sCx = = = = \= Xc] d     ) )Xc] )c ) ) ) \).E Es E8C= ETW E E E EE E(3- E3 E E E E HSM S    c    8 7* 7* 7* 7*r8 8 85 84 8 8 8 8
4 4 4 4 3    <S T       @!C ! ! ! !   && & & &% % % %R R R R R.
<& 
<T 
< 
< 
< 
<a a# a a a a&BU BUHSM BUS BU BU BU BUHxP xP xPtes et e e e eN        (   &C D      !7c !7d !7 !7 !7 !7F 9> /5 /5 /5 /5$ /5 /5 /5 /5b"( "( "( "( "( "(H3S4Z 3C 3 3 3 3&Zc Zd Z Z Z Z"%C "%D "% "% "% "%H1 1 1 1$P P P Pd]c ]d ] ] ] ]~0? 0? 0? 0?d& & & & 'C 'C ' ' ' '*2 2 2 2 2
 /C / / / ^/* *D * * * *X3 3 3 3j   . . . .   *  2S S Sj IN 3> 3> 3> 3> 3>RV 3> 3> 3> 3>n849 8 8 8 8"T    (3 T cDj    "3 4    "s t    B [_ @= @= @=3 @= @=SW @=cf @= @= @= @=D  ,*
 *
 *
X3M 3M 3Mj/ / / / /     
:G :G :Gx( ( (V  @8 8 8t 3 T#s(^8L    & 6?R   s s TX    <Q Q Qf3 4    "HSM d    :s5 s5 s5 s5n$c $d $ $ $ $P!0 !0 !0F  :y5 y53 y5T y5 y5 y5 y5v #    \?# ?$ ? ? ? ?  DI c Z]`dZd    <5c 5cDj 5 5 5 5z z z z z 	z
 eCcM*+z z 
tz z z zxC$J 4     4Z  eCcM*+  
t	       DN N N`+ +D + +X[ +  EI + + + +         @<T <VZ < < < <+ + + +
   & &&& & 	&
 & & & 
sCx& & & \&6vF vF$ vF vF vF vFpD' D'T D'd D' D' D' D'LoF oF oF oF oFb&K# &K$ &K &K &K &KP
 
 
 
Z^ 
 
 
 
   Z^    0  6 6 6 	c 	 	 	 \	 7 7 7rW
s W
t W
 W
 W
 W
t 5s 5C 5D 5 5 5 \5  F   2|O |O |O |O@#9 #9 #9J1S 1# 1RV 1 1 1 184 4 4 4 44# # #P3C 3 3 3 3u8 u8S u8 u8 u8 u8r_7 _7 _7P4    ,N9 N9 N9h& &S & & & &< <> , , ,S ,$ , , , ,T' T' T'l @B       0< < < t    78 78 78r8< 8< 8<t*) *) *)X) ) )- - -40[ 0[ 0[dM8 M8 M8^/ / /2) ) ),"7 "7c "7 "7 "7 "7H3 3 3 3~  )y)?)?)?@@$x} $sDyAQ $ $ $ [$D '+	U UU U sm	U
 
#U U U UnA AC A A A A AFf3 f3 f3PL6 L6 L6 L6d;C ;D ; ; ; ;( C  UX pt    B	^3 	^s 	^SW 	^ 	^ 	^ 	^Zc Z# ZVZ Zmp Z Z Z ZF|E |E |E|iQ iQ iQV	 	 	 	 	 	2'# 2' 2' 2' 2'j	d 	 	 	 	:D :D :Dx7 7 7@7 7 7"# # #&IC I IS ISV I[_ I I I I&;
 ;
 ;
z. . . . .b 7;D D D# DC D/3D?BD D D DL JN    $ RVWZR[    c  PS X[    *   4j j jXC C Cc CUY C C C C. . . .   +* +* +* +*ZS T    ) ) ) )   t
+ t
+D t
+HSM t
+ t
+ t
+ t
+l     DU U U<A A AF%sCx % % % %N
"# 
" 
" 
" 
"&* &* &*PMc M M M M+tCH~ + + + +Zt           * " .
 .
 .
$ 
%.
 .
 .
 .
`P'G P'G P'G P'G P'Gr3   ru  first_responsec           
          ddl }|j                            d          pd                                sdS ddlm ddlm}m} 	                                }	 
                    |          }	 |                                 n:# t          $ r Y n.w xY w# 	 |                                 w # t          $ r Y w w xY wxY w|dS |j        pdg}|j        r|                    |j                   d                    d |D                                                       }|sdS |j        p|}	d	t$          d
t$          f fd}
dfd}dt$          d
dffd} |||
|||	|pdd            dS )u  Drive a kanban goal_mode worker through the Ralph-style goal loop.

    Called from the quiet single-query path AFTER the worker's first turn,
    only when ``HERMES_KANBAN_GOAL_MODE`` is set (dispatcher-spawned
    goal_mode card). Wires the worker's ``run_conversation`` and the kanban
    DB into ``goals.run_kanban_goal_loop``. All errors are swallowed by the
    caller — a broken goal loop must never wedge a worker, the dispatcher's
    claim TTL / crash detection is the backstop.
    r   NHERMES_KANBAN_TASKrO   	kanban_db)run_kanban_goal_loopDEFAULT_MAX_TURNSr  c              3      K   | ]}||V  	d S r   r   r   s     r2   r   z*_run_kanban_goal_loop_q.<locals>.<genexpr><  s'      77!Q7A777777r3   r
  r   c                 \   j                             | j                  }t          j         dd           r&j         j        j        k    rj         j        _        t          |t                    r|                    dd          nt          |          }|rt          |           |pdS )Nr  r  r  r  rO   )
r   r  r  r  r  r   r   rD   rY   r  )r
  r   respr  s      r2   	_run_turnz*_run_kanban_goal_loop_q.<locals>._run_turn<  s    ++!$!9 , 
 
 CI|T22	2	$66 Y1CN3=fd3K3K\vzz*B///QTU[Q\Q\ 	$KKKzrr3   
str | Nonec                                                      } 	                     |           }||j        nd 	 	 |                                  S # t          $ r Y S w xY w# 	 |                                  w # t          $ r Y w w xY wxY wr   )connectget_taskr  r  r   )rc  r  _kbri  s     r2   _task_statusz-_run_kanban_goal_loop_q.<locals>._task_status<  s    KKMM	Q((A }188$6				   				   s@    A A
AAB A54B5
B?BBBrC  c                                                     }	                     ||            	 |                                 d S # t          $ r Y d S w xY w# 	 |                                 w # t          $ r Y w w xY wxY w)NrB  )rB  
block_taskr  r   )rC  rc  rD  ri  s     r2   _blockz'_run_kanban_goal_loop_q.<locals>._block<  s    KKMM	NN1gfN555					   				   s@   A A 
AAA>A.-A>.
A;8A>:A;;A>c                 8    t                               d|           S )Nz%s)r   rT  )r=   s    r2   r  z)_run_kanban_goal_loop_q.<locals>.<lambda><  s    fkk$** r3   )ri  	goal_textrun_turntask_status_fnblock_fnr  r4  r  )r   r@  )r   r}  rD   r   r  r8  rx  r9  r:  rB  rC  r  r   r  r  r  r   goal_max_turnsrY   )r  r4  _os	_run_loop
_DEF_TURNSconnr-  
goal_partsrJ  r  r?  rE  rH  rD  ri  s   `            @@r2   _run_kanban_goal_loop_qrT  <  sF    {344:AACCG ++++++cccccccc ;;==D||D'**	JJLLLL 	 	 	D		JJLLLL 	 	 	D	|*"#Jy %$)$$$77z77777==??I #1zI# #       	 	 	 	 	 	 	s t        I#%+**	 	 	 	 	 	sB   B 4B	 	
BBC B0/C 0
B=:C <B==C qr
  r  r'  r   r(  r   r  r  rb  r  
list_toolslist_toolsetsgatewayrv  r  rx  r%  rw  r  rx  c                   F 	 ddl m}  |             n# t          $ r Y nw xY wdt          j        d<   |r8ddl}ddlm} t          d           |	                     |                       dS |s|s|p|pt                              dd	          }d}|rt                      }|rt          |           t                              d
d          }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)          |                     mnWd} 	 ddlm}!  |!dt                    } n# t          $ r d} Y nw xY w| | }n$ddlm}" t=           |"t          d                    }t?          |          }#tA          ||||||	|
|||||          F|#rtC          |#Fj"                  \  }$}%}&|&rYd#                    |&          }'|%r0tH          %                    d|'d#                    |%                     ntM          d|'           |$rDd#                    d Fj'        |$fD                       (                                F_'        |%F_)        |r/d|d          d|d          d |d!          d"}(Fj'        pd#|(z   F_'        |r<F*                                 F+                                 tY          j-        d           |r<F*                                 F.                                 tY          j-        d           t!          j        t^                     Ffd$})	 ddl0}*|*0                    |*j1        |)           |*0                    |*j2        |)           tg          |*d%          r|*0                    |*j4        |)           n# t          $ r Y nw xY w| s|rF5                    dtm          |          &          stY          j-        d'           	 to          | |          \  } }+g },t          j                            d(d#          (                                }-|-rE	 dd)l8m9}. dd*l:m;}/ |.<                                }0	 |.=                    |0|-          }1	 |0>                                 n:# t          $ r Y n.w xY w# 	 |0>                                 w # t          $ r Y w w xY wxY w|1t          |1d+d#          nd#}2|2rs |/|2          \  }3}4|3rLd, |+D             }5|3D ]=}6|6|5vr7|5@                    |6           |+                    t          |6                     >|4r|,                    |4           n2# t          $ r%}7tH          B                    d-|7           Y d}7~7nd}7~7ww xY w|rd.F_C        FD                                rm| }8|+s|,r6d/}9d}:	 dd0l:mE}: dd1l:mF}; dd2lGmH}<  |;FjI        pd#(                                FjJ        pd#(                                 |<                      }9n# t          $ r d/}9Y nw xY w|9d3k    r|:	  |:t'          | t(                    r| nd#d4 |+D             t-          |,          pd5          \  }=}>t          d6 |=D                       r|=}8n|+rFL                    | |+d	7          }8nD# t          $ r |+rFL                    | |+d	7          }8Y nw xY w|+rFL                    | |+d	7          }8FM                    |8          }?|?d8         FjN        k    rdF_O        FP                    |?d9         |?d:         |?                    d;          <          rdFjO        _Q        dFjO        _R        dFjO        _S        dFjO        _T        	 FjO        U                    |8FjV        =          }@nX# t          $ rK t          Fd>?           t          d@Fj"         tX          jY        A           tY          j-        dB           Y nw xY wt          FjO        dCd          r&FjO        j"        Fj"        k    rFjO        j"        F_"        t'          |@t                    r|@                    dDd#          nt)          |@          }A|Asyt'          |@t                    rd|@                    dE          rO|@                    dF          s|@                    dG          r%t          dH|@dE          tX          jY        A           n|Art          |A           t          j                            dI          dk    rD	 t          F|A           n2# t          $ r%}BtH          B                    dJ|B           Y d}B~Bnd}B~Bww xY wt          d@Fj"         tX          jY        A           d}Ct'          |@t                    ri|@                    dF          rTd'}Ct          j                            d(          r3|@                    dK          dLv r	 ddMl\m]}D |D}Cn# t          $ r d'}CY nw xY wtY          j-        |C           tY          j-        d'           nh| p|+rdNnd#}E|ErFj^                            dO|E            F_                                 F`                    | |+pdP           Fa                                 t          F           n# t          F           w xY wdS F	                                 dS )Qa  
    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   )configure_windows_stdior   HERMES_INTERACTIVEN)start_gatewayz0Starting Hermes Gateway (messaging platforms)...r  Fworktree_syncT)r  r   r<  c                 6    g | ]}|                                 S r   r@  r  s     r2   r   zmain.<locals>.<listcomp>s=  s     DDD1QWWYYDDDr3   rW   c                 6    g | ]}|                                 S r   r@  )r   xs     r2   r   zmain.<locals>.<listcomp>y=  s     )J)J)J!'')))J)J)Jr3   )coding_selectionr  )rG  r   )_get_platform_tools)r'  r  r   r(  r   r  r  r  rv  r%  rw  rx  r
  r  zoUnknown skill(s) requested, skipping: %s. Continuing with: %s. List available skills with `hermes skills list`.zUnknown skill(s): r  c              3      K   | ]}||V  	d S r   r   r   s     r2   r   zmain.<locals>.<genexpr>=  s;       , ,t,, , , , , ,r3   z?

[System note: You are working in an isolated git worktree at z. Your branch is `r  z`. Changes here do not affect the main working tree or other agents. Remember to commit and push your changes, and create a PR if appropriate. The original repo is at r  z.]rO   c                 f   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
          j                            d          r	 dd l}t          |d	          r1|                    |j        d
            |                    d           n# t          $ r Y nw xY w	 dd l}|                                 n# t          $ r Y nw xY wt(          j        t(          j        fD ]'}	 |                                 # t          $ r Y $w xY wt          j        d           t3                      )Nz'Received signal %s in single-query moder   r  r  r  r  r   r6  SIGALRMc                  *    t          j        d          S r	  )r   r3  )rc  s    r2   r  z1main.<locals>._signal_handler_q.<locals>.<lambda>>  s    ! r3   r  )r   r   r  r  rC   r   r   r9  r  r+  r,  r   r}  rD   r  rS  re  alarmr-  r.  r/  r0  r1  r2  r3  r	  )r  rT  _agentr  _sig_modr4  r5  r  s          r2   _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	 :>>.// 	))))8Y// & OOH$46L6LMMMNN1%%%   %%%%   J
3  MMOOOO    DHQKKK!!!sl   +B! 
"A- ,B! -B B! BB! !
B.-B.AD 
D$#D$(E 
EE,F
FFr  r  r  r6  r7  )extract_image_refsr  c                 ,    h | ]}t          |          S r   r  r   s     r2   r	  zmain.<locals>.<setcomp>=>      $I$I$ISVV$I$I$Ir3   z&kanban image-ref extraction failed: %sr   ra   )r  )r  r  r  c                 ,    g | ]}t          |          S r   r  r   s     r2   r   zmain.<locals>.<listcomp>i>  rm  r3   )
image_urlsc              3   H   K   | ]}|                     d           dk    V  dS r  r	  r   s     r2   r   zmain.<locals>.<genexpr>l>  s1      &T&TquuV}}'C&T&T&T&T&T&Tr3   r  r  r'  r  r  r  r=  ra  rB  z
session_id: rA     r  r  rr  r  r  r  HERMES_KANBAN_GOAL_MODEzkanban goal loop failed: %sfailure_reason)
rate_limitr
  )KANBAN_RATE_LIMIT_EXIT_CODEz[image attached]z[bold blue]Query:[/] r  )chermes_cli.stdiorZ  r   r   r}  r4  gateway.runr\  r  r  r  rD   r  r=  r  r  rC  rD  r  r   rY   r  r   r&  r(  r  agent.coding_contextra  hermes_cli.tools_configrb  r  rl  ru  rY  r  r   r   r   r  r  r   r  ra  r  r/  r2  r  rY  r  r  r  rS  r  rF  r  r  r  r8  r  rk  rB  rC  r  r  rq  r   r   r  r  r  r  r~  r  r   r'  r~  r  r  r  r   r  rS  suppress_status_outputstream_delta_callbacktool_gen_callbackr  r  r	  ro  r1  r   rT  hermes_cli.kanban_dbru  r  rP  r-  rB  rv  )Gr  rU  r
  r  rf  r'  r   r(  r   r  r  rb  r  rV  rW  rX  rv  r  rx  r%  rw  r  rx  rZ  r4  r\  use_worktreewt_info_repo
_sync_basetoolsets_listr  _codingra  rb  parsed_skillsskills_promptloaded_skillsmissing_skillsmissing_displaywt_noterj  r)  single_query_imagessingle_query_image_urls_kanban_task_idrD  _extract_refs_conn_task_body	_kb_paths_kb_urls_seen_pr  effective_queryr  _build_partsr  r  r  r
  r  r   r  r  
_exit_code_RL_CODE_query_labelr  sG                                                                         @r2   rC  rC  <  s   ~<<<<<<!!!!   
 (+BJ#$  ------@AAAMMOO$$$  m   I1I
z5(I(I 	"$$E .&u--- $>>J%
;;;G #* -4V_
>* 17;;;; #	&  JQE M K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
 	======&&jIIIGG 	 	 	GGG	#MM DCCCCC"#6#6z5#I#IJJM*622M '!  C  17TN8
 8
 8
4}n  	I"ii77O  	IG $IIm,,    !!Go!G!GHHH 	1 & , ,"%"3]!C, , , ! !egg  $1C   @@v@ @29(2C@ @ (/{';	@ @ @ 	 !.4"?    OL!!!"/" /" /" /" /"`    w~'8999w(9:::7H%% 	>NN7>+<===     [ [((tE{{(CC 	HQKKKW	()>ue)L)L&E& 24# jnn-A2FFLLNNO QQ;;;;;;WWWWWWKKMME! #UO D D!!KKMMMM( ! ! ! D!!!KKMMMM( ! ! ! D!:?:KGE62666QSE 
E.;mE.B.B+	8$ I$I$I5H$I$I$IE&/ I I#%U??$)IIbMMM$7$>$>tBxx$H$H$H# E3::8DDD  Q Q QLL!I4PPPPPPPPQ  n* */&2244 Q-+0O* 5.E 5 %+	'+/      TSSSSSEEEEEE(?(?!$!3 : : < <!$b 7 7 9 9 +) )II
  ) / / /(.III/ %00\5M&3?<-7s-C-C$KEE$I$I5H$I$I$I/34K/L/L/TPT4" 4" 4" 0
 $'&T&TV&T&T&T#T#T !*6<OO (; %*:=:\:\,13FQV ;] ;* ;* $- & & &#6 !&696X6X(-/BU 7Y 7& 7&O&
 1 .1.P.P % 3). /Q / /O
 "%!?!?!P!PJ!+.#2SSS$(	'1'':)3I)>*4..9L*M*M '   V-
 04	,;?	8 ;?	76:	3*%(Y%?%?-<585M &@ & &FF  1 * * *9#FZ[[[[!"C3>"C"C#*UUUUHSMMMMM* $CI|TBBB #	 4 F F-0Y-ACNGQRXZ^G_G_#p6::.>#C#C#Cehioepep !), *64 8 8, !'

7 3 3, "(H!5!5	, :@I9N9N	, ""=F7O"="=CJOOOOO% ,!(OOO :>>*CDDKKW 7X F F F F#, W W W &-JI V V V V V V V VW ?s~??cjQQQQ &'
%fd33 3

88L8L 3)*J!z~~.BCC 	3

 0I I!:I; I;!3%& %& %& %& %& %& 2:JJ'0 !3 !3 !312JJJ!3,,,   %[?R)Z););XZ NK%%&Ll&L&LMMM --///':'BdCCC'')))"3''''"3'''' GGIIIIIs   
!!%G> >HH,A%Q 
QQ A
m + W= U #T8 7W= 8
UW= UW= U/
UU/
U,)U/+U,,U//BW= <m =
X,X'"m 'X,,-m AZ4 3m 4[ m [m A7] m $].+m -]..B2m !!a m Abm bD(m g m 
hg<7m <hB
m j m j$!m #j$$Bm m__main__r  r   r  r/  )r>   )r  )r  r  )r\  )NNNNNNNNNNNFFFFFNFFFFFF(?  r  hermes_bootstrapModuleNotFoundErrorr-  r   r  r/  r   r   concurrent.futuresr  r|  rC  r  rE  r+  r  r  collectionsr   urllib.parser   r   
contextlibr   pathlibr   r	   typingr
   r   r   r   r  r  r   r}  r  hermes_cli.fallback_configr    hermes_cli.cli_agent_setup_mixinr   hermes_cli.cli_commands_mixinr   prompt_toolkit.historyr   prompt_toolkit.stylesr   rf  prompt_toolkit.patch_stdoutr   r=  r   prompt_toolkit.layoutr   r   r   r   r   r    prompt_toolkit.layout.processorsr   r   r   r    prompt_toolkit.filtersr!   prompt_toolkit.layout.dimensionr"   prompt_toolkit.layout.menusr#   prompt_toolkit.widgetsr$   prompt_toolkit.key_bindingr%   prompt_toolkitr&   r)  prompt_toolkit.formatted_textr'   r*  prompt_toolkit.cursor_shapesr(   BLOCKr  r>  r  hermes_cli.pt_input_extrasr)   r*   r+   r   r:  r|  r-   r5   rJ   rb   rd   rh   rk   hermes_cli.bannerrm   rn   r  r   ro   rp   hermes_cli.browser_connectrq   rr   rs   rt   hermes_cli.env_loaderru   rp  rv   rw   r   r{  r|  _project_envr   rY   r   r   r   r   r   r   r   r   r  r  hermes_loggingr  r~  r  r  r  r  r  rD   _tplrE   r  _ftlr  r  importlib.utilutilr  r  r  r  richr  r  rich.consoler  rich.markupr  r  
rich.panelr  	rich.textr  r  r  r  r  r  r  r  r  r  r  r  r  r  hermes_cli.callbacksr  r  r  r  r  r  rJ  rG  r  __annotations__rP  r  r  r  r#  rC   r=  rY  rQ  rR  ro  rr  rv  rK  r  r  r  r  r&  r  r  r  r  r   r  r#  r,  r=  r1  rZ  r  r  r  r]  r^  r  r  r  r3  r  rj  r  r  r  rX  r  r  r  r}  rz  r0  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r"  r-  rF  rL  rO  r  r[  r  rb  rn  r|  r  r   r  r  r  r  r  r  r  r  r  r|  r  r  r  r  r  r  r  r  r  r%  r  HERMES_AGENT_LOGOHERMES_CADUCEUSrG  rJ  rN  r]  rP  rR  rT  rY  r\  r`  re  rl  r~  rs  ru  rT  rC  fireFirer   r3   r2   <module>r     se    	 	 	 	
 	D	  				  



  				                  * * * * * * * * % % % % % %             , , , , , , , , , , , ,		8	$	$ !
>   9 9 9 9 9 9 ? ? ? ? ? ? : : : : : : / . . . . . 2 2 2 2 2 2 4 4 4 4 4 4 2 2 2 2 2 2 q q q q q q q q q q q q q q q q 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	         
 &&(((!#;=_=_ 	 	 	D	     , , ,1 1 1    0. . .2 2 25 5 5 R Q Q Q Q Q Q Q` 
 B A A A A A A A            5 4 4 4 4 4 7 7 7 7 7 7 7 7  tH~~$v-  | F F F FE E E E E EP     F# F# F F F Fc d4S>.B    :4S> c    &
td{ 
 
 
 
C C$J    kc3h k k k k\ _

	,,,,,,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		666666>>)R((,,-CTJJDTT$ZZ(((( 	 	 	D	",	####333333$ $ $ $ $ $ $ $L &&q*>*>*@*@AAAA 	 	 	D	 !                       ) ) ) ) ) )       ' ' ' ' ' '% % %2 2 22 2 2 3 2 2 2 2 2 N N N N N N N N. . .. . .. . .' ' ' ' ' '% % % 3 2 2 2 2 25 5 58 8 83 3 39 9 9< < <  AD ,c#*o E E E $ 
   # # # #,
 ,
 ,
 ,
\> >%$, >$ > > > >B 59 MS MS MST MS MS MS MS`JcDj JT J J J J 	  d
  	
 
   $ 9M ! ! !# !QU ! ! ! !H AK E E E# Et E E E E & & & &) ) ) )b .2 (4S>* 1 1 1 (3-    :    *t 4 D    H=c H=e H= H= H= H=Ve es ed ehtTWY\T\~F^ e e e eP #  T    > c C     *; ;c ;# ; ; ; ; ;|<@ <@DcN <@d <@ <@ <@ <@~3C 3C 3C 3ClE E E E0l( l(c l(# l(t l( l( l( l(^B? B? B? B? B? B?` 0  27 I I IC I$ I3 I I I IF "& 4$; % % %2:,--BJ.//	(y{{ : : : : : :Ft F F F FR<D < < < <R % % 4S>   (3 3     ON4E4K4K4M4MNNN 8 8 8 8,     	
y cj//11  	 	 	D	
! ! ! ! ! ! ! !H .*ID
A
A
A # #    # #    S    +s +y + + + +     < %/BJ0% % !
Ac Ac A A A A"0s 0 0 0 0$# ## #S # # # #L  ! "  %89993    > >t >t > > > >    / / /" " " "+ + + + + +* * * *Bf# f f f fR C        F S $    0 I       A @ @ @ @ @B B BS B B B B(3 (5c? ( ( ( (V:s :td{ : : : :@E# E- E E E EP T$Z PS \_bf\f ru    B#c #d # # # #
     4PG PG PG PGr "*.// bj!233 BJ899 "
#<== 
  RZ 344 
 #d # # # #L   &       0, , ,^(#S (#U39=M (# (# (# (#V3 3     ,C ,C ,C9uS#X&,C,C ,C
 ,C 	,C ,C ,C ,C^ t d
 eTWY]^bYcTcNd    B <==, , , , , , , ,^F j$.s . . . .l%C %D % % % %,     $D $ $ $ $" " "" " "4    " " "s    3c?U38_#Dt#K PTUXPY    0& &C &D & & & &^QyG QyG QyG QyG QyG"$4 QyG QyG QyGprW Wc Wd W W W Wv 04"!$/} }}
} } 	}
 $s)OeCHo-} } } } } } d^} } } } }  !}" #}$ %}& '}( )}* +}, -}. /} } } }@ zKKKDIdOOOOO s   
 D 	D"!D"&+E EE=I III- -I54I59J JJAK   K('K(,AL1 1L98L9=:M8 8N ?N 	<X XX