
    ,j*	             /       `   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: ddl;m<Z<m=Z=m>Z>m?Z? ddl@mAZA ddlBmCZC ddlDmEZE ddlFmGZG ddlHmIZI ddlJmKZL ddlMmNZO 	 ddlPmQZQ eQjR        ZSn# eTeUf$ r dZSY nw xY w	 ddlVmWZWmXZXmYZY  eY              eW              eX             [Y[W[Xn# eZ$ r Y nw xY wddl[Z[ddl\Z\d Z]d Z^d Z_d  Z`d! Zad" Zbd# Zcdd$ldmeZemfZf d%Zgdd&lhmiZimjZj dd'lkmlZlmmZmmnZnmoZo dd(lpmqZq dd)lrmsZs  ei            Zt eeu          jv        d*z  Zw eqetew+           d,Zxd-eyd.eyfd/Zzd0ed.eyfd1Z{d0ed.eyfd2Z|d3eyd.eeeyef                  fd4Z}d5eeyef         d.eyfd6Z~d7eyd.edz  fd8Zd9eyd.eydz  fd:Zd.eeyef         fd;Z e            Z	 dd<lmZ  ed=>           n# eZ$ r Y nw xY w	 dd?lmZ  e             n# eZ$ r Y nw xY w	 dd@lmZ  ee           n# eZ$ r Y nw xY w	 ddAlmZ e                    dBi                               dCd          Z eer ee          nd           n# eZ$ r Y nw xY w	 ddlZddlmZ  G dD dE          Zej                            d e                       n# eZ$ r Y nw xY wddFlmZ ddGlmZ ddHlmZ ddIlmZ ddJlmZ dK ZdL ZdM ZddNldmZ ddOlmZmZ dP ZdQ ZdR ZdSeyd.dfdTZdU ZddVlmZ dW ZdX ZdY ZdZ Zd[ Zd\a e            Zeeydz           ed]<   dZd\ad\add^Zdd_Zd`dadbefdcZdSeydz  d.efddZd=dedfdSeydz  dgeydheyd.dfdiZdjdkdheyd.dfdlZdedkdheyd.dfdmZĐddnZŐddoZdae eeyeyf                  edp<   dqe ey         d.e ey         fdrZd.e ey         fdsZdtedued.efdvZʐddweyd.e eeyeyf                  fdxZːddzeyd{ed.efd|Z̐dd}eeyeyf         d.dfd~Z͐ddZΐddZϐddweyded.dfdZdweyd.dfdZdZdZdZdZd\ddeyded.eyfdZdaedz  ed<    ej        d          Z ej        d          Z eۦ            Zdeyd.edz  fdZd.eydz  fdZd.efdZdddddddddddddZeeyeyf         ed<   deyd.eyfdZd e                                D             ZddZ e             	 ej                                        r#ej                                        r
 e             n# eZ$ r Y nw xY w G d d          Z eddd`          ZdZd.eyfdZd-eyd.efdZd-eyd.eyfdZ ej        d          Zd-eyd.eyfdZd.efdZdd-eydeyfdZd`ad\ad\ada et                    ad.efdZdded.dfdZddZed             ZddZd-eyd.dfdZddZd-eyfdZdeyfdZ  eh d          ZddlhmZ ddeyd.eyfdZd9eyd.eeyeyf         fdZdeyd.edz  fdĄZdeyd.dfdǄZddȐe	e         dededz  d.eyfd˄Z
deyd.efd̈́Zd-eyd.eyf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-eyd.eeyef         fdلZd-eyd.eyfdڄZddeydz  deydz  d.eeye	e         f         fd݄Z ej        dަ          Z G d߄ d          ZdZdZd.eyfdZd-eyd.efdZda da!d.efdZ"d.efdZ#d Z$d Z%d.efdZ&d Z'd.efdZ(deye	ey         z  eeydf         z  dz  d.e	ey         fdZ)deyde*d.efdZ+ G d de)e+          Z,d=ddeyd.dfdZ-	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddeydeydeydeydeye	ey         z  eeydf         z  deydeydeydeydede e         ded ededededeydedededed	ed
ef.dZ.e"dk    rddl/Z/ e/j0        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)	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/ubuntu/.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,   r3   )r-   r.   _estimate_usage_costs      r0   r3   r3   c   s*    OOOOOO0000r1   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-   r.   r6   minuteshoursremaining_mindayss          r0   format_duration_compactrH   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>>>>r1   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)rK   K
   z.2fd   r?   r9   .0,)rC   rB   absstrrstrip)
r-   r.   rJ   	abs_valuesignunits	thresholdsuffixscaledtexts
             r0   format_token_count_compactr`   x   s   4;QVZZ%;%;<<EE

I55zz!))33DBE" + +	6	!!*F{{ #  d{{{{3''..s33*D*&***** " <<r1   c                      ddl m}  || i |S )Nr   )is_table_divider)agent.markdown_tablesrb   )r-   r.   _is_table_dividers      r0   rb   rb      s*    KKKKKKd-f---r1   c                      ddl m}  || i |S )Nr   )looks_like_table_row)rc   rf   )r-   r.   _looks_like_table_rows      r0   rf   rf      s*    SSSSSS  $1&111r1   c                      ddl m}  || i |S )Nr   )realign_markdown_tables)rc   ri   )r-   r.   _realign_markdown_tabless      r0   ri   ri      s*    YYYYYY##T4V444r1   )_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_matchesz.env)hermes_homeproject_env)REASONING_SCRATCHPADthinkthinking	reasoningthoughtr_   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*rM   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)r_   cleanedtagtc_tags       r0   _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 ==??r1   contentc                     | dS t          | t                    r| S t          | t                    r+d | D             }d                    d |D                       S t          |           S )NrM   c                     g | ]S}t          |t                    r<|                    d           dk    0t          |                    dd                    TS typer_   rM   )
isinstancedictrB   rW   .0parts     r0   
<listcomp>z._assistant_content_as_text.<locals>.<listcomp>  sc     
 
 
$%%
 +/((6*:*:f*D*D $$%%*D*D*Dr1   
c              3      K   | ]}||V  	d S N r   ps     r0   	<genexpr>z-_assistant_content_as_text.<locals>.<genexpr>  s'      //qQ///////r1   r   rW   listjoinr   partss     r0   _assistant_content_as_textr   
  s    r'3 '4   0
 

 
 

 yy//E//////w<<r1   c                 :    t          t          |                     S r   )r   r   )r   s    r0   _assistant_copy_textr     s     !;G!D!DEEEr1   	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        r0   _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_FILErM   prefill_messages_fileagent)osgetenvr   rW   rB   r   r   )r   env_path	top_level	agent_cfgs       r0   _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2r1   effortc                     ddl m}  ||           }| r1|                                 r|t                              d|            |S )zHParse a reasoning effort level into an OpenRouter reasoning config dict.r   )parse_reasoning_effortNz5Unknown reasoning_effort '%s', using default (medium))hermes_constantsr   r   r   r   )r   r   results      r0   _parse_reasoning_configr   Q  s\    777777##F++F X&,,.. XV^NPVWWWMr1   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.rM   >   offnonenormaldefaultstandardN>   onfastpriorityr   z#Unknown service_tier '%s', ignoring)rW   r   lowerr   r   )r   rJ   s     r0   _parse_service_tier_configr   Z  sl    	rNN  ""((**E EMMMt***z
NN8#>>>4r1   c                  F   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idd0d1ddddd2ddddd2d3d4ddddd5d6i id7}d}|                                r 	 t          |d8d9:          5 }d;d<l	m
}  |t          j        |          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@          }
dA|v r;t          |
t                    r|
                    dA          |dA         |d@         dA<   n2# t"          $ r%}t$                              dB|           Y d=}~nd=}~ww xY w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dgdhdidjdkdldmdndodp	}t          j                            dq          dk    }|                                D ]\  }}||v r|dIk    r&|rt          ||                   t          j        |<   5|s|t          j        vrb||         }t          |t0          t          f          r"t3          j        |          t          j        |<   t          |          t          j        |<   |                    dri           }dsdti}|                                D ]+\  }}||v r"t          ||                   t          j        |<   ,|                    dui           }dvdwdxdyd2dzd{d|d}d2d~dddd2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   rM   auto)r   base_urlproviderlocalrS   r8   ,  z*nikolaik/python-nodejs:python3.11-nodejs20z3docker://nikolaik/python-nodejs:python3.11-nodejs20F)env_typecwdtimeoutlifetime_secondsdocker_imagedocker_forward_envsingularity_imagemodal_imagedaytona_imagedocker_volumesdocker_mount_cwd_to_workspacex   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fullrQ         	interruptr   )compactresume_displayresume_exchangesresume_max_user_charsresume_max_assistant_charsresume_max_assistant_linesresume_skip_tool_onlyshow_reasoning	streamingbusy_input_modepersistent_outputpersistent_output_max_linespersist_promptsskinr   2   )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backendr   )rS   r   r   r   TERMINAL_ENVTERMINAL_CWDTERMINAL_TIMEOUTr   TERMINAL_LIFETIME_SECONDSr   TERMINAL_DOCKER_IMAGEr   TERMINAL_DOCKER_FORWARD_ENVr   TERMINAL_SINGULARITY_IMAGEr   TERMINAL_MODAL_IMAGEr   TERMINAL_DAYTONA_IMAGEssh_hostTERMINAL_SSH_HOSTssh_userTERMINAL_SSH_USERssh_portTERMINAL_SSH_PORTssh_keyTERMINAL_SSH_KEYcontainer_cpuTERMINAL_CONTAINER_CPUcontainer_memoryTERMINAL_CONTAINER_MEMORYcontainer_diskTERMINAL_CONTAINER_DISKcontainer_persistentTERMINAL_CONTAINER_PERSISTENTTERMINAL_DOCKER_VOLUMESTERMINAL_DOCKER_ENV&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE TERMINAL_DOCKER_RUN_AS_HOST_USER(TERMINAL_DOCKER_PERSIST_ACROSS_PROCESSESTERMINAL_DOCKER_ORPHAN_REAPERTERMINAL_SANDBOX_DIRTERMINAL_PERSISTENT_SHELLSUDO_PASSWORD)	r   
docker_envr   docker_run_as_host_userdocker_persist_across_processesdocker_orphan_reapersandbox_dirpersistent_shellsudo_password_HERMES_GATEWAYr*  r   BROWSER_INACTIVITY_TIMEOUTr/  AUXILIARY_VISION_PROVIDERAUXILIARY_VISION_MODELAUXILIARY_VISION_BASE_URLAUXILIARY_VISION_API_KEYAUXILIARY_WEB_EXTRACT_PROVIDERAUXILIARY_WEB_EXTRACT_MODELAUXILIARY_WEB_EXTRACT_BASE_URLAUXILIARY_WEB_EXTRACT_API_KEYAUXILIARY_APPROVAL_PROVIDERAUXILIARY_APPROVAL_MODELAUXILIARY_APPROVAL_BASE_URLAUXILIARY_APPROVAL_API_KEY)r$  r%  approvalr   r   r#  securityredact_secretsHERMES_REDACT_SECRETS)r   r   __file__parentr   environrB   r   r   hermes_cli.configr2  yaml	safe_loadr   rW   r   updater   r   r   r3  getcwdpopitemsr   r   dumpsr   r   )"user_config_pathproject_config_pathignore_user_configconfig_pathdefaults_file_has_terminal_configr   r2  file_configkeyagent_file_configr   r3  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"                                     r0   load_cli_configr  d  s@
   $ $m3x../2CC (CDDK    *); *&)
 
 
   #H"$!VGI -2
 
 #&$).'= 	
 
 
 

 %' "F`lq_ n h {  U \ x {  c H 
 
4 $ "%(*-*+%)#*!%+.  $%
 
* s
  
 
 #	  #	 
 
 !
 
 B
Sn nHh !&  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 ll:r22O
 O##&5i&@
# -'++J@@G##!#&5e&<U##			U	#	#'8	8	8E4(((N~ 	% 	7	
 	/ 	; 	9 	- 	1 	' 	' 	' 	%  	1!" 	7#$ 	3%& 	 ?'( 4+)Q#E+U ?-7(=  LH *..!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=   &J3 8&D*J3 *D..J3 1D.2F J3 3
K"=KK")setup_loggingclimode)print_config_warnings)init_skin_from_config)set_tool_preview_max_lenr,  tool_preview_lengthc                       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    r0   <lambda>zG_AsyncHttpxDelNeuter.find_spec.<locals>._patched_exec.<locals>.<lambda>  s    4 r1   )getattr__del__r   )modulecls
_orig_execs     r0   _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         @r0   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   r1   r0   r  r    s9        	 	 	 	 	 	 	 	r1   r  )box)Console)escape)Panel)Textc                      ddl m}  || i |S )Nr   )AIAgent)	run_agentr  )r-   r.   _AIAgents      r0   r  r  '  s)    ------8T$V$$$r1   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-   r.   r  _get_tool_definitionss       r0   r  r  -  sK    ======IIIIII  $1&111r1   c                      ddl m}  || i |S )Nr   )get_toolset_for_tool)r  r  )r-   r.   _get_toolset_for_tools      r0   r  r  5  s*    IIIIII  $1&111r1   )build_welcome_banner)SlashCommandCompleterSlashCommandAutoSuggestc                      ddl m}  || i |S )Nr   )get_all_toolsets)toolsetsr  )r-   r.   _get_all_toolsetss      r0   r  r  ?  *    >>>>>>d-f---r1   c                      ddl m}  || i |S )Nr   )get_toolset_info)r  r  )r-   r.   _get_toolset_infos      r0   r  r  E  r  r1   c                      ddl m}  || i |S )Nr   validate_toolset)r  r  )r-   r.   _validate_toolsets      r0   r  r  K  r  r1   
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     r0   _sync_process_session_idr  Q  s+    >>>>>>:&&&&&r1   c                      ddl m}  || i |S )Nr   )get_job)cronr  )r-   r.   _get_jobs      r0   r  r  X  s)    ((((((8T$V$$$r1   prompt_for_secretc                      ddl m}  || i |S )Nr   )cleanup_all_environments)tools.terminal_toolr  )r-   r.   r  s      r0   _cleanup_all_terminalsr  a  s*    <<<<<<##T4V444r1   c                      ddl m}  || i |S )Nr   )set_sudo_password_callback)r  r  )r-   r.   _set_sudo_password_callbacks      r0   r  r  g  s*    ]]]]]]&&7777r1   c                      ddl m}  || i |S )Nr   set_approval_callback)r  r  )r-   r.   _set_approval_callbacks      r0   r  r  m  s*    SSSSSS!!426222r1   c                      ddl m}  || i |S )Nr   )set_secret_capture_callback)tools.skills_toolr  )r-   r.   _set_secret_capture_callbacks      r0   r  r  s  s*    ]]]]]]''8888r1   c                      ddl m}  || i |S )Nr   )_emergency_cleanup_all_sessions)tools.browser_toolr  )r-   r.   r  s      r0   _cleanup_all_browsersr  y  s*    BBBBBB**D;F;;;r1   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   r1   r0   _mark_tui_input_modes_activer    s     #r1   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_HOOKSrM   >   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   rr  rB   r   hermes_cli.pluginsr  r   r   r   r  r  debugagent.shell_hooksr  rs  r  )_accept_hooksr  r  r  r  s        r0   _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Tnotify_session_finalizer  c                    t           rdS da t                       	 t                       n# t          $ r Y nw xY w	 t	                       n# t          $ r Y nw xY w	 ddlm}  |             n# t          $ r Y nw xY w	 ddlm	}  |             n# t          $ r Y nw xY w| r6t          rt          j        nd}t          |          rt          |dd           	 t          rwt          t          d	          rdt          t          d
d          }t!          |t"                    rt                              |           dS t                                           dS dS dS # t          $ r Y dS w xY w)z"Run resource cleanup exactly once.NTr   )shutdown_mcp_servers)shutdown_cached_clientsr  shutdownr  platformreasonshutdown_memory_provider_session_messages)_cleanup_done#_reset_terminal_input_modes_on_exitr  r   r  tools.mcp_toolr  BaseExceptionagent.auxiliary_clientr  _active_agent_refr  %_should_emit_cleanup_session_finalize_notify_session_finalizehasattrr  r   r   r   )r  r  r  cleanup_session_id_session_msgss        r0   _run_cleanupr-    s     M ()))          777777   
BBBBBB!!!!     =NX.99TX01CDD 	$-!   
 	=):<V!W!W 	= $$57JDQQM-.. =!::=IIIII!::<<<<<	= 	= 	= 	=    sZ   * 
77A
 

AAA, ,
A98A9=B 
BBA!E :E 
E'&E'c                 .    t           sdS | dS | t           vS )NTF)r  )r  s    r0   r(  r(    s&    7 tuIIIr1   r  )r  r  r  r  c                 T    	 ddl m}  |d| ||           d S # t          $ r Y d S w xY w)Nr   invoke_hookon_session_finalizer  )r  r1  r   )r  r  r  _invoke_hooks       r0   r)  r)    sl    	BBBBBB!!		
 	
 	
 	
 	
 	
        
''keyboard_interruptr  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   r0  on_session_end_current_task_idrM   _current_turn_id_current_api_request_idFTr"  r  r  )	r  task_idturn_idapi_request_id	completedinterruptedr"  r  r  )r  r  replacer   r  r  r1  )r  r  r   r  r3  s        r0   _emit_interrupted_session_endrD    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  r  r  r  )r  r  r)  add)r  r  r   r  s       r0   %_notify_single_query_session_finalizerG  =  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)rG  r-  _release_active_sessionr  s    r0   _finalize_single_queryrK  M  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  sysstdoutisattywrite_TERMINAL_INPUT_MODE_RESET_SEQflushr   r   )streamttys     r0   r#  r#  V  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])/(.*)$)rO  r  r   matchgroupupperrC  chr)r   _rer;   driverests        r0   _normalize_git_bash_pathre    s     
|w		'++A Aggajj!''!**t++--@@DLLc"gg$>$>@@@		8!<<A Aggajj!''!**t++--@@DLLc"gg$>$>@@@Hr1   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)gitz	rev-parsez--show-toplevelT   )capture_outputr_   r   )
subprocessrun
returncodere  rP  r   r   )rj  r   s     r0   _git_repo_rootrm    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   rn  s     r0   _path_is_within_rootrq    sB    t   uur4  	repo_rootc           	      $   ddl }| pt                      } | s t          d           t          d           dS t          j                    j        dd         }d| }d| }t          |           dz  }|                    d	d	
           ||z  }t          |           dz  }d}	 |                                r|	                                nd}	||	
                                v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	 |                    dddt%          |          d|dgd	d	d|           }|j        dk    r,t          d|j                                         d           dS n+# t          $ r}t          d| d           Y d}~dS d}~ww xY wt          |           dz  }|                                r	 t          |                                           }|                                }|	                                
                                D ]}|                                }|r|                    d          r/t          |           |z  }||z  }	 |                    d          }|                    d          }n2# t0          t2          f$ r t                              d |           Y w xY wt5          ||          st                              d!|           t5          ||          st                              d"|           |                                rM|j                            d	d	
           t=          j        t%          |          t%          |                     _|                                 r|                                s|j                            d	d	
           	 tC          j"        t%          |          t%          |                     # t0          tF          f$ r}tH          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t%          |          || d(}t          d)|            t          d*|            |S )+zCreate an isolated git worktree for this CLI session.

    Returns a dict with worktree metadata on success, None on failure.
    The dict contains: path, branch, repo_root.
    r   Nu?   [31m✗ --worktree requires being inside a git repository.[0mz5  cd into your project repo first, then run hermes -w   hermes-zhermes/
.worktreesTparentsexist_okz
.gitignorez.worktrees/rM   ar   r   r   zCould not update .gitignore: %srg  worktreerF  z-bHEAD   ri  r_   r   r   u$   [31m✗ Failed to create worktree: [0mz.worktreeinclude#F)strictz+Skipping invalid .worktreeinclude entry: %sz5Skipping .worktreeinclude entry outside repo root: %sz9Skipping .worktreeinclude entry that escapes worktree: %srY  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)r   branchrr  u   [32m✓ Worktree created:[0m z
  Branch: )(rj  rm  printuuiduuid4hexr   mkdirr   	read_text
splitlinesr   endswithrR  r   r   r  rk  rW   rl  stderrr   resolve
startswithOSErrorr  rq  r   is_filerq  shutilcopy2is_dirr   symlinkNotImplementedErrorrO  r  infocopytree)rr  rj  short_idwt_namebranch_nameworktrees_dirwt_path	gitignore_ignore_entryexistingr   r   r   include_filerepo_root_resolvedwt_path_resolvedlineentrysrcdstsrc_resolveddst_resolved_sym_err	_copy_errr  s                            r0   _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::::::::;
Js7||T;OdBI   
 
 !!ZFM<O<O<Q<QZZZ[[[4 "    BBBBCCCttttt
 	??%77L ?J>	J!%i!8!8!:!:&00$..00;;== 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 G D 

;'
;
;<<<	
${
$
$%%%Ks   $AE 6AE;E EE EE 
FE==FA#G, ,
H6HH?B!T' !,LT' ,L=:T' <L==DT'  /Q1/T' 1T!+T.2S! T!
T+TTTTT' T!!T' '
U1UUrQ   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)rg  zfor-each-refz--format=%(refname)zrefs/remotesTr~  F)rg  logz	--oneliner|  z--notz	--remotes)rj  rk  rl  rP  r   boolr   )r  r   rj  remote_refsr   s        r0   _worktree_has_unpushed_commitsr  E  s      nnJJJdG % 
 
 !Q&&4!'')) 	5EEEdG   
 
 !!4FM''))***   tts"   'B B 
'B 3%B 
B'&B'r  c                    | 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|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  rr  rQ   r   u2   
[33m⚠ Worktree has unpushed commits, keeping: r  z4  To clean up manually: git worktree remove --force rg  r{  r  --forceT   r~  zFailed to remove worktree: %s-DzFailed to delete branch %s: %su   [32m✓ Worktree cleaned up: )
rW  rj  r   r   r  r  rk  r   r   r  )r  rj  r  r  rr  has_unpushedr   s          r0   _cleanup_worktreer  d  s    ##D 6lG(^F[!I==!! 1'2FFFL WwWWWXXXNWNNOOO9J'9=dBI 	 	
 	
 	
 	
  9 9 94a888888889BHdF+dBI 	 	
 	
 	
 	
  B B B5vqAAAAAAAAB 	
>g
>
>
>?????s0   
B* *
C4CCC< <
D,D''D,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  rm   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)rs  r  r   rm   get_metaprune_empty_ghost_sessionsset_metar   r  r   r  &finalize_orphaned_compression_sessionsrB   maybe_auto_prune_and_vacuumrC   r  )

session_db_load_full_config_get_hermes_home_hermes_home_maintpruned
_prune_exc	finalized_finalize_exccfgexcs
             r0   _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)
rs  r  rB   tools.checkpoint_managerr  rC   r  r   r   r  )r  r  r  r  s       r0    _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 ]t}|                                r|j                            d          s2	 |	                                j
        }	|	|k    rSn# t          $ r Y `w xY w|	|k    }
|
st          t          |          d          r	 |                    g d	d
d
dt          |                    }|j                                        }|                    dddt          |          dgd
d
d|            |r|                    ddd|gd
d
d|            t"                              d|j        |
           =# t          $ r,}t"                              d|j        |           Y d}~nd}~ww xY wt	          |            dS )u~  Remove stale worktrees and orphaned branches on startup.

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

    Also prunes orphaned ``hermes/*`` and ``pr-*`` local branches that
    have no corresponding worktree.
    r   Nrv    r  ru  rh  r  rg  r  z--show-currentTr~  rg  r{  r  r  r  r  r  rQ   z$Pruned stale worktree: %s (force=%s)zFailed to prune worktree %s: %s)rj  timer   r   _prune_orphaned_branchesiterdirr  namer  statst_mtimer   r  rW   rk  rP  r   r   r  )rr  r  rj  r  r  nowsoft_cutoffhard_cutoffr  mtimeforcebranch_resultr  r   s                 r0   _prune_stale_worktreesr    s~    KKKOOl2M!!  +++
$)++C-.K*T12K&&(( &K &K||~~ 	UZ%:%:9%E%E 		JJLL)E{"" # 	 	 	H	 $ 	-c%jj!DDD 	K&NN333#$s5zz +  M #)//11FNN
Hc%jj)D#$	      HdF3#'dBI     LL?USSSS 	K 	K 	KLL:EJJJJJJJJJ	K Y'''''s+   )C


CCB/F33
G)=!G$$G)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)rg  r  z--format=%(refname:short)TrQ   r~  c                 ^    g | ]*}|                                 |                                 +S r   r   )r   bs     r0   r   z,_prune_orphaned_branches.<locals>.<listcomp>9  s2    ZZZaPQPWPWPYPYZ		ZZZr1   r   )rg  r{  r   z--porcelainzbranch refs/heads/rZ  r  rh  mainc                 p    g | ]2}|v|                     d           s|                     d          0|3S )zhermes/hermes-zpr-r  )r   r  active_branchess     r0   r   z,_prune_orphaned_branches.<locals>.<listcomp>W  sW       O##\\*++ $/0||E/B/B $ 	
###r1   r   )rg  r  r  r}  z%Failed to prune orphaned branches: %szPruned %d orphaned branches)rj  rk  rl  rP  r   splitr   setr  rF  rangelenr   r  )rr  rj  r   all_branches	wt_resultr  head_resultcurrentorphanedibatchr   r  s               @r0   r  r  )  s(    	:::dBI   
 
 !!FZZ6=+>+>+@+@+F+Ft+L+LZZZ    55O	NN666dBI # 
 
	 $**400 	U 	UD344 U##DJJ/CQ$G$G$K$Q$Q$S$STTT	U    	 nn///dA9 % 
 
 $**,, 	)(((        H   1c(mmR(( E E1r6"	ENN'''%/#$	       	E 	E 	ELL@!DDDDDDDD	E LL.H>>>>>sT   'A' 6A' '
A54A5BD 
D%$D%)AE6 6
FFG;;
H*H%%H*z[1;38;2;255;215;0mz[1mr      bold	hex_colorr  c          	          t          |           } 	 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).
    rZ  r     rh  r  z1;rM   [z38;2;;r;   z[38;2;184;134;11m)_maybe_remap_for_light_moderC   r  
IndexError_ACCENT_ANSI_DEFAULT)r  r  r   gr  prefixs         r0   _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 )NrM   r  r  c              3       K   | ]	}|d z  V  
dS )r[  Nr   r   cs     r0   r   z&_luminance_from_hex.<locals>.<genexpr>  s&      %%aAE%%%%%%r1      c              3      K   | ]}|d v V  	dS )0123456789abcdefABCDEFNr   r  s     r0   r   z&_luminance_from_hex.<locals>.<genexpr>  s(      GGa#;;GGGGGGr1   r   r[  r	     gz6?g,C?g]m{?g     o@)r   lstripr  r   allrC   r  )r  r:   r   r  r  s        r0   _luminance_from_hexr    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   rr  rB   r   vs     r0   r   z*_query_osc11_background.<locals>.<genexpr>  0      
R
R2:>>!
R
R
R
R
R
Rr1   SSH_CONNECTION
SSH_CLIENTSSH_TTYr   z]11;?\皙?r1   @   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 )Nr	  r     rZ  r   )rC   r  )r>   r#  bitss      r0   normz%_query_osc11_background.<locals>.norm  s?    Ar

Aq66A:D59@AG!t)q11q@r1   rZ  r[  r  r  02X)rO  stdinrQ  rP  anytermiosrV  fileno	tcgetattrr   	setcbreak	tcsetattr	TCSAFLUSHrR  rT  selectr  	monotonicr   readr  r   searchbytesrC   r_  )r3  rV  fdoldr9  deadlinebufr   r8  chunkr;   r/  r  r  s                 r0   _query_osc11_backgroundrC    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_LIGHTrM   THERMES_TUI_THEMElightdarkHERMES_TUI_BACKGROUNDr   	COLORFGBGr  r  >   r  r  r   r	  TERM_PROGRAM)r  r   rr  rB   r   r   _TRUE_REr^  	_FALSE_REr  r  isdigitrC   rC  _LIGHT_DEFAULT_TERM_PROGRAMSr   )r   varr#  themebg_hintbg_lumcfgbglastbgbg_colorlumtps               r0   _detect_light_moder[    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)r  r`  s     r0   r  r  Z  sg       I0055 OOE'''&u--r1   c                 >    i | ]\  }}|                                 |S r   )r`  )r   kr#  s      r0   
<dictcomp>rg  i  s&    NNNDAq17799aNNNr1   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_installedFrM   c                 b     | ||          }	 t          |          S # t          $ r |cY S w xY wr   )r  r   )r  r  fallbackrJ   _orig_get_colors       r0   _wrapped_get_colorz9_install_skin_light_mode_hook.<locals>._wrapped_get_colorw  sM    c844	.u555 	 	 	LLL	s    ..TrM   )hermes_cli.skin_engineri  r   r  	get_colorrj  )ri  rn  rm  s     @r0   _install_skin_light_mode_hookrr  l  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]  Fr  skin_keyfallback_hexr  c                >    || _         || _        || _        d | _        d S r   )	_skin_key_fallback_hex_bold_cached)r  ru  rv  r  s       r0   __init__z_SkinAwareAnsi.__init__  s#    !)
#'r1   r|   c                    | j         y	 ddlm} t           |                                | j        | j                  | j                  | _         n0# t          $ r# t          | j        | j                  | _         Y nw xY w| j         S )Nr   get_active_skinr  )	r{  rp  r  r  rq  rx  ry  rz  r   )r  r  s     r0   __str__z_SkinAwareAnsi.__str__  s    <QBBBBBB+#O%%//@RSS       Q Q Q+D,>TZPPPQ|s   AA *A>=A>otherc                 &    t          |           |z   S r   rW   r  r  s     r0   __add__z_SkinAwareAnsi.__add__  s    4yy5  r1   c                 &    |t          |           z   S r   r  r  s     r0   __radd__z_SkinAwareAnsi.__radd__  s    s4yy  r1   Nc                     d| _         dS )z1Clear cache so the next access re-reads the skin.N)r{  r  s    r0   resetz_SkinAwareAnsi.reset  s    r1   )r]  r|   N)r  r  r  r  rW   r  r|  r  r  r  r  r   r1   r0   rt  rt    s         (UZ ( ( ( (C (d ( ( ( (
 
 
 
 
!S !S ! ! ! !!c !c ! ! ! !     r1   rt  response_borderr]  z[2;3mc                  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^  )rp  r  rq  r   r~  s    r0   _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.
    rM   )	_RichText	from_ansir_   s    r0   _rich_text_from_ansir    s     tzr***r1   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.rM   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   )r_   r  s     r0   _strip_markdown_syntaxr    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r1   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    r0   _protectz=_preserve_windows_dot_segments_for_markdown.<locals>._protect  s!    v('5;;q>>BBBr1   )r   MatchrW   !_WINDOWS_PATH_WITH_DOT_SEGMENT_REr   )r_   r  s     r0   +_preserve_windows_dot_segments_for_markdownr    sZ     DC C# C C C C -004@@@r1   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  get_terminal_sizecolumnsr   maxr  _STREAM_PAD)colss    r0   _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   rM   )rich.markdownr  r  r  r  r   r  rW   r   r   r  ri   r  r  r  r  )r_   r  r  r  panel_widthnormalized_moder  s          r0   _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)NrQ   r  )r  rC   	TypeErrorr  )rJ   s    r0   _coerce_output_history_limitr  B  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     r0   _configure_output_historyr  I  s3     #7mm <Y G G#<===OOOr1   c                  8    t                                            d S r   )r  clearr   r1   r0   _clear_output_historyr  Q  s    r1   c               #   8   K   t           } da 	 d V  | a d S # | a w xY w)NT)_OUTPUT_HISTORY_SUPPRESSED)	old_values    r0   _suspend_output_historyr  U  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    r0   _record_output_history_entryr  `  s9    " &? C] 5!!!!!r1   c                     t           rt          st          rd S t          |                               dd                              d          }|sd S |                                D ]}t          |           d S )NrM   r   )r  r  r  rW   rC  rX   r  r  )r_   
normalizedr  s      r0   _record_output_historyr  f  s    " &? C] T""4,,33D99J %%'' + +$T****+ +r1   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     r0   r   z)_replay_output_history.<locals>.<genexpr>  s(      !>!>#d))!>!>!>!>!>!>r1   r   F)r  r  r  tuplecallabler   r   rW   r  extend	_pt_print_PT_ANSIr   )rendered_linesr  liness      r0   _replay_output_historyr  p  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   r0   r  z,_cprint.<locals>._schedule.<locals>.<lambda>  s    9Xd^^+D+D r1   )asyncioinspectisawaitableiscoroutineensure_futurer   )_aio_inspectcoror  r_   s      r0   	_schedulez_cprint.<locals>._schedule  s    		""""&&&&"?#D#D#D#DEEDX%9%9$%?%?8CWCWX\C]C]""4(((((    	 	 	DD	s   AA   
A.-A.)r  prompt_toolkit.applicationr  r  r   r  r  r  r  loopr  get_running_loopRuntimeError
is_runningcall_soon_threadsafe)r_   r  appr  _asynciocurrent_loopr  r  s   `      @r0   _cprintr    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).
    rM   r  r   r_   )r   r_   )rW   r   r   r   	enumerater   rB   )messager  r   r  r   mergedr_   s          r0   _prepend_note_to_messager    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Nr1   >
   .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  
candidatesrn  s      r0   _termux_example_image_pathr	  *	  s     	-..	J  < <7== 	<7<<j(;;;;;	<7<<*JAAAr1   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
    rM   )rM   rM   r      "'rZ  \r[  Nr9  \ )rW   r   r  rC  )r   quoteposchtoken	remainders         r0   _split_path_inputr  8	  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)r1   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.
    rM   Nr  r  rZ  r  r  r9  file://filentz//r  r\  r  :r[  r   z/mnt/r6  )rW   r   r  r  rC  r   schemer   r   netlocr   r  r   
expandvarsr   r  isalphar   r   r   r   rw  r  r   r  r  )r  r  expandedparsedr  r   base_dirresolveds           r0   _resolve_attachment_pathr$  c	  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../r  r  rZ  r  r[  >   r\  r  r   z"/z"~z'/z'~z"./z"../z'./z'../r  r  rM   )r   is_imager  r9  c                 $    g | ]\  }}|d k    |S )r9  r   )r   idxr  s      r0   r   z%_detect_file_drop.<locals>.<listcomp>	  s!    OOO73R3YY3YYYr1   )r   rW   r   r  r  r  r$  r]   r   _IMAGE_EXTENSIONSr  r  reversedrX   )r%  strippedstarts_like_pathdirect_pathfirst_tokenr  	drop_pathspace_positionsr  	candidater#  s              r0   _detect_file_dropr4  	  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  r1   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.
    rM   r  r  limitr|   c                 h    t          |           |k    r| n| d t          d|dz
                     dz   S )NrZ  r  ...)r  r  )r  r9  s     r0   _truncz/_format_image_attachment_badges.<locals>._trunc	  s:    4yyE))ttt4Gc!UQY6G6G4G/H5/PPr1   4   rZ  u   [📎 r   r  ]z images attached]r      z] [+r9  c              3   *   K   | ]}d |z    dV  dS )u   [📎 Image #r>  Nr   )r   r  bases     r0   r   z2_format_image_attachment_badges.<locals>.<genexpr>
  sF         	$q###     r1   )	r  r  r  rW   rC   r  r  r   r  )r5  r6  r7  r<  firstextrarA  s         @r0   _format_image_attachment_badgesrD  	  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?++,,     r1   pasted_textc                 ,    |                                   S )z@Auto-attach clipboard images only for image-only paste gestures.r  )rE  s    r0   ,_should_auto_attach_clipboard_image_on_pasterG  
  s      """"r1   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~rM   [201~z^[[200~z^[[201~z(^|[\s\n>:\]\)])\[200~r  z\[201~(?=$|[\s\n<\[\(\):;.,!?])z(^|[\s\n>:\]\)])00~z01~(?=$|[\s\n<\[\(\):;.,!?]))rC  r   r   r  s    r0   &_strip_leaked_bracketed_paste_wrappersrJ  
  s       	["%%	b	!	!	B			B			 	 6+UD99D64b$??D6(%66D612t<<DKr1   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 )NrI  FrM   _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BracketedPaster  rR  r  r  r:  r   r   r  _input_parsersend)self_parserr   end_mark	end_indexpaste_content	remainingbp_startr  r  r  _BP_TIMEOUT_S_PtKeyPress_PtKeys_patched_vt100_feeds             r0   rc  zA_apply_bracketed_paste_timeout_patch.<locals>._patched_vt100_feedE
  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 6r1   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.keysrM  (prompt_toolkit.key_binding.key_processorrN  r  rW   Vt100ParserfeedrO  r   r  r   )
_vt100_modr  r`  ra  rb  rc  s     @@@@r0   $_apply_bracketed_paste_timeout_patchrl  +
  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.
    rY  Tc              3   T   K   | ]#}t           j                            |          V  $d S r   r!  r"  s     r0   r   z/_preserve_ctrl_enter_newline.<locals>.<genexpr>
  r$  r1   r%  
WT_SESSIONGHOSTTY_RESOURCES_DIRGHOSTTY_BIN_DIRTERMrM   zxterm-ghosttyrL  ghostty	microsoftWSL_DISTRO_NAME)z/proc/versionz/proc/sys/kernel/osreleaser   r   ignore)r   errorsNF)
rO  r  r2  r   rr  rB   r   r   r;  r  )r   r   s     r0   _preserve_ctrl_enter_newlinerx  
  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.
    enterrY  c-jN)rF  rO  r  rx  )kbhandlers     r0   _bind_prompt_submit_keysr~  
  se     BFF7OOG
|w'C'E'Eug r1   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   )r  s    r0   #_disable_prompt_toolkit_cpr_warningr  
  s9    26///   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.
    Fr
  z^[r~   r  rO   r;   rM   r   )_DSR_CPR_ESC_REr   _SGR_MOUSE_ESC_REsubn_DSR_CPR_VISIBLE_RE_SGR_MOUSE_VISIBLE_RE_SGR_MOUSE_BARE_RE)r_   has_eschas_visiblehas_bare_mousehad_mouse_reportscounts         r0   *_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-:"""r1   c                 *    t          |           \  }}|S )z2Compatibility wrapper returning only cleaned text.)r  )r_   r   r8  s      r0    _strip_leaked_terminal_responsesr    s    ;DAAJGQNr1   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.rM   r(  r   r  [User attached image: r>  NzImage file not found: zNot a supported image file: )r   rW   r4  rB   r  r  r$  r  r]   r   r+  r  rF  )
r  r  r  imagesdroppedexplicit_pathdedupedr(  imgr  s
             r0   _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r1   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)r  force_terminalcolor_system	highlight)ior  _bufferr  _inner)r  r  s     r0   r|  zChatConsole.__init__;  sI    xzz$	
 
 
r1   c                    | j                             d           | j                                          t          j        d          j        | j        _         | j        j        |i | | j         	                                }t                              d|          }|                    d                              d          D ]}t          |           d S )Nr   r  rM   r   )r  seektruncater  r  r  r  r7  r  getvalue_OSC_ESCAPE_REr   rX   r  r  )r  r-   r.   outputr  s        r0   r  zChatConsole.printE  s    !"4X>>F4*6***&&((  ##B//MM$''--d33 	 	DDMMMM	 	r1   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      r0   statuszChatConsole.statusS  s       




r1   N)r  r  r  r  r|  r  r   r  r   r1   r0   r  r  2  sW         
 
 
   
 
 ^
 
 
r1   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~  Nr  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   ╝[/]
)rp  r  r   r  rq  get_brandingr   rr  rB   
hermes_clir  r  rl   minr  r  r  ljust)r  _skin	skin_nameborder_colortitle_color	dim_colorline1	tiny_liner  _release_date_versionversion_linerM  innerbarcontent_widthline2s                    r0   _build_compact_bannerr  {  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s    ""c                     | r|                      d          sdS |                                 d         }d|dd         vS )a  Return True if *text* looks like a slash command, not a file path.

    Slash commands are ``/help``, ``/model gpt-4``, ``/q``, etc.
    File paths like ``/Users/ironin/file.md:45-46 can you fix this?``
    also start with ``/`` but contain additional ``/`` characters in
    the first whitespace-delimited word.  This helper distinguishes
    the two so that pasted paths are sent to the agent instead of
    triggering "Unknown command".
    r\  Fr   rZ  N)r  r  )r_   
first_words     r0   _looks_like_slash_commandr    sJ      ts++ uaJ jn$$r1   c                  >    t           ddlm}   |             a t           S )Nr   scan_skill_commands)_skill_commandsagent.skill_commandsr  r  s    r0   _ensure_skill_commandsr    s.    <<<<<<--//r1   c                      t                      S r   )r  r   r1   r0   get_skill_commandsr    s    !###r1   c                      ddl m}  || i |S )Nr   )build_skill_invocation_message)r  r  r-   r.   _impls      r0   r  r    )    LLLLLL5$!&!!!r1   c                      ddl m}  || i |S )Nr   )build_preloaded_skills_prompt)r  r  r  s      r0   r  r    s)    KKKKKK5$!&!!!r1   c                  >    t           ddlm}   |             a t           S )Nr   get_skill_bundles)_skill_bundlesagent.skill_bundlesr  )r  s    r0   r  r    s+    BBBBBBr1   c                      ddl m}  || i |S )Nr   )build_bundle_invocation_message)r  r  r  s      r0   r  r    r  r1   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  r  r  keysr   r  s    r0   _get_plugin_cmd_handler_namesr    se    ::::::&&((--//000   uus   .1 AAskills.c                    | sg S t          | t                    r| g}n9t          | t          t          f          rd | D             }nt          |           g}g }t	                      }|D ]_}|                    d          D ]G}|                                }|r||v r|                    |           |                    |           H`|S )zJNormalize a CLI skills flag into a deduplicated list of skill identifiers.c                 0    g | ]}|t          |          S r   r  r   items     r0   r   z*_parse_skills_argument.<locals>.<listcomp>  s#    GGGDd6Fc$ii6F6F6Fr1   rU   )	r   rW   r   r  r  r  r   rF  r  )r  
raw_valuesr!  r(  r   r   r  s          r0   _parse_skills_argumentr    s     	&# #X

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

&kk]
FUUD & &IIcNN 	& 	&DJ t!3!3HHZ   MM*%%%%	& Mr1   key_pathrJ   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   Trw  r   )atomic_roundtrip_yaml_updatei  zFailed to save config: %sNF)r   r   rp  rq  r   r  utilsr  r   chmodr  r  r   r   error)r  rJ   r{  r|  r~  r  r   s          r0   save_config_valuer    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                      e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 dd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	ddddededefdZ
ddZddeddfdZddZddZdddeddfdZdd Zdd"eddfd#Zd$ee         defd%Zed&edefd'            Zd d$ee         d)edefd*Zed!d+ee         d,ed-edefd.            Zed/ee         d0edefd1            Zdeeef         fd2Zed3edefd4            Zed3ed5edefd6            Zed"d8eeef         defd9            Z d#d)ee         defd:Z!ed#d)ee         defd;            Z"d#d<ed)ee         defd=Z#d#d)ee         defd>Z$d#d)ee         defd?Z%defd@Z&defdAZ'dBe(ddfdCZ)d#d)ee         fdDZ*d#d)ee         defdEZ+dF Z,dGedefdHZ-d3eddfdIZ.ddJZ/ddKZ0dLeddfdMZ1dN Z2dOeddfdPZ3ddQdReddfdSZ4dTedefdUZ5d3edz  defdVZ6dTeddfdWZ7d3eddfdXZ8ddYZ9ddZZ:d3eddfd[Z;dd\Z<dd]Z=d^edefd_Z>defd`Z?e@daefdb            ZAd#defdcZBdddZCddeZDdf ZEdg ZFddhdieGdjeddfdkZHdeIe         fdlZJdefdmZKdnedeIdedz  fdoZLd3eddfdpZMdqeddfdrZNdsdtd3edueIdvedefdwZOdx ZPdy ZQdz ZRdefd{ZSd|edefd}ZTd~ ZUd ZVd ZWd ZXd dedeIeGeef                  fdZYdd(ddqededefdZZd Z[deddfdZ\dee         defdZ]d$dZ^d3edefdZ_d Z`d Zad%dedefdZbedefd            Zcd3eddfdZdd&dedeIe         dededz  fdZedededz  fdZfdddededeIeeeef                  dededz  f
dZgdedz  ddfdZhdedz  deIeeeef                  dedz  fdZid Zjd'deIdededdfdZkdefdZldeddfdZmddZne	 	 	 d(dedededededededeeef         fd            ZodeddfdZpd!deddfdZqdefdZrdeddfdZsd!d3ededefdZtd!d3ededefdZud Zvd ZwedefdÄ            ZxdĄ Zyd^edefdńZzedededefdȄ            Z{dɄ Z|ddʄZ}d˄ Z~dededdfd΄ZdefdτZdЄ ZdOefdфZd)defdӄZdԄ ZdefdՄZdք Zd*d^efd؄ZddلZ eh dڣ          Zedee         deeef         fd܄            Z	 d#d^ededee         dee         fd݄Zd)deddfdބZd߄ ZddZdeddfdZd+dedededeGfdZdededeGfdZdededeGdefdZd Zd Zd3eddfdZd3efdZdefdZd Zd Zd Zd Zdededededdf
dZd ZdefdZdsdd^edededefdZdsdd^ededeIe         fdZded eGdedefdZddZd Zd#dededeGfdZddZdd	Zdeddfd
ZddZddZd#dueIdee         fdZd Zd Zdeeef         fdZdefdZd ZdefdZdeGeef         fdZdefdZdeIfdZddZdddddeIfdZd ZdS (,  	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                 j  $ t                      | _        t          | _        ||n t          d                             dd          | _        t          d                             dd          }|du rdnt          |          | _        t          d                             dd	          | _        t          d                             d
d          | _	        t          d                             dd          | _
        t          t          d                             dd          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 }	 t/          |                    dd                    }n# t0          t2          f$ r d}Y nw xY w	 t/          |                    dd                    }n# t0          t2          f$ r d}Y nw xY wt5          d|          | _        t5          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|| _&        tN          j(                            d%          }|r4	 t/          |          | _)        nn# t2          t0          f$ r
 d| _)        Y nTw xY wt+          |t,                    r4|                    d&          }t+          |t.                    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tO          j/        d,          pd-| _0        d| _1        | j0        | _2        d.| _3        d| _4        g | _5        |p5t          d#                             d'd!          ptO          j/        d/d!          pd| _6        | j6        rEto          | j6        d0          r0|p'tO          j/        d1          ptO          j/        d2          | _8        n/|p'tO          j/        d2          ptO          j/        d1          | _8        ||| _9        nt          d3                             d4          rt          d3         d4         | _9        nt                              d4          rt          d4         | _9        nbtO          j/        d5          rG	 t/          tO          j/        d5d!                    | _9        n%# t0          t2          f$ r
 d6| _9        Y nw xY wd6| _9        || _:        t          d3                             d7          pg | _;        |rd|vr{d8|vrwty          t                              d9          pi =                                          $$fd:|D             }|r,| >                    d;d<?                    |           d=           t                              d>i           }t+          |t                    rd?|i}|
p|                    d?d          | _@        |                    d@dA          | _A        |                    dBdC          | _B        |                    dDdE          | _C        || _D        |p"tN          j(                            dF          dGk    | _E        tO          j/        dHd!          p t          d3                             dId!          | _F        t          d3                             dJi           | _G        t          t          t                              | _J        t          t          d3                             dKd!                    | _L        t          t          d3                             dLd!                    | _N        t                              dMi           pi }|                    dN          | _O        |                    dO          | _P        |                    dP          | _Q        |                    dQ          | _R        |                    dRd          | _S        |                    dS          | _T        t                              dTi           pi }|                    dU          }d| _U        |dVvr?	 t          |          }d"|cxk    rdWk    r
n n|| _U        n# t0          t2          f$ r Y nw xY wt          t                    | _X        d| _Y        d| _Z        d| _[        d| _\        d| _]        g | _^        t          j`                    | _a        d| _b        d| _c        d"| _d        d| _e        d| _f        	 d dXlgmh}   |             | _f        n2# t          $ r%}!t          k                    dY|!           Y d}!~!nd}!~!ww xY wt          | jf                   t                       d| _n        |	r|	| _o        d| _b        nF| ja        p                    dZ          }"t          jr                    js        dd[         }#|" d\|# | _o        t          d]z  | _u        d"| _v        d| _]        d| _w        t          jy                    | _z        t          jy                    | _{        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!| _        g | _        d | _        g | _        d| _        d| _        t          j                    | _        d| _        d| _        d| _        d| _        d| _        d| _        t          j                    | _        | j        <                                 d| _        d| _        t          j                    | _        d| _        d| _        i | _        d | _        dS )^a  
        Initialize the Hermes CLI.

        Args:
            model: Model to use (default: from env or claude-sonnet)
            toolsets: List of toolsets to enable (default: all)
            provider: Inference provider ("auto", "openrouter", "nous", "openai-codex", "zai", "kimi-coding", "minimax", "minimax-cn")
            api_key: API key (default: from environment)
            base_url: API base URL (default: OpenRouter)
            max_turns: Maximum tool-calling iterations shared with subagents (default: 90)
            verbose: Enable verbose logging
            compact: Use compact display mode
            resume: Session ID to resume (restores conversation history from SQLite)
            pass_session_id: Include the session ID in the agent's system prompt
        Nr,  r  Ftool_progressr  r   r  r  bell_on_completer  r  Tr  r  r  r  r  queuesteerr  
timestampsfinal_response_markdownr   >   r   r   r  inline_diffsuser_message_previewfirst_linesr[  
last_linesrZ  r   rM   r7   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     r0   r   z&HermesCLI.__init__.<locals>.<listcomp>  s2    ]]]Q2B12E2E]!S\J\J\qJ\J\J\r1   z%[bold red]Warning: Unknown toolsets: , [/]r  r   max_snapshotsr  r  r  max_file_size_mbrQ   HERMES_IGNORE_RULESr   HERMES_EPHEMERAL_SYSTEM_PROMPTr
  r  r  r  provider_routingsortonlyrv  orderrequire_parametersdata_collection
openroutermin_coding_score>   NrM         ?	SessionDBuM   Failed to initialize SessionDB — session will NOT be indexed for search: %s%Y%m%d_%H%M%Sr  r8  z.hermes_history)r  console
CLI_CONFIGr   rB   r  rW   tool_progress_moder  r  r  r  r   r   r  r  r	  streaming_enabledshow_timestampsr	  _inline_diffs_enabledr   r   rC   r  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   rr  r  hermes_cli.runtime_providerr  _model_is_default_explicit_api_key_explicit_base_urlr   requested_provider_provider_sourcer   api_modeacp_commandacp_argsr   rt   r#  r  enabled_toolsetsr  r  r  _console_printr   checkpoints_enabledcheckpoint_max_snapshotscheckpoint_max_total_size_mbcheckpoint_max_file_size_mbr  r  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_scorerA   r   _fallback_model_active_agent_route_signaturer   _tool_callbacks_installed_tirith_security_checked_appconversation_historyr   r  session_start_resumed_prompt_start_time_prompt_duration_last_turn_finished_at_session_dbhermes_stater/  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_deadline	threading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_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_background_tasks_background_task_counter)%r  r"  r  r   r#  r   r  r	  r  r   r  r  r  _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%                                       @r0   r|  zHermesCLI.__init__K  se   > 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!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;#	o......(y{{D 	o 	o 	oNNjlmnnnnnnnn	o 	't'7888
 	)*** .2  	>$DO DMM .77HHM)"1"-J!.====DO *,=='*	
 $#kmm %
 ',#!
 (-$
 48!""!&!"%)"#"#'n..$(!'($#'  )-% $( ! !"$'*(**," %!,.+-*/'%)" %>++ # %!&!&(00  """ $(  490%.^%5%5"&*#(-% ?A()%%%sr   (#L L"!L"&#M
 
M M Q0 0R
R<'\$ $\?>\?0&k k+*k+-n 
n2n--n2r  r  surfacer  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r  z
[bold red]r   F)r  hermes_cli.active_sessionsr  r  r   r   r   r   r  rO  r  rL  atexitregisterrI  )r  r  r  r  leaser  r  s          r0   _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  r  s     r0   rI  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          r7| j        r2|| j        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  r  r:  r*  r^  rj  
invalidate)r  r  r  s      r0   _invalidatezHermesCLI._invalidate
  s    " 43U;; 	Fn4   	#TY 	#C$:O4OT`3`3`$'D!I  """""	# 	# 	# 	#3`3`r1   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  r  r   r  r  s     r0   
_paint_nowzHermesCLI._paint_now"  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  r  r   r  s     r0   _force_full_redrawzHermesCLI._force_full_redraw4  s     dFD)) 	F))#...   	NN 	 	 	DD	s   A 
AA)rebuild_scrollbackr  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_gotorT  r  )r  r  r  r  outs        r0   r  z&HermesCLI._clear_prompt_toolkit_screenM  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| _         	 |j                            d           n# t          $ r Y nw xY w	 |                                 n# t          $ r Y nw xY w |             dS )a  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``).

        Instead we just reset prompt_toolkit's renderer cache so the next
        incremental redraw starts from a clean slate, then let
        ``original_on_resize`` recalculate layout for the new size.

        We also flag ``_status_bar_suppressed_after_resize`` so the dynamic
        status bar and input separator rules stay hidden until the next user
        input.  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).  Clearing the suppression on the
        next prompt restores the bar cleanly.
        TFr  N)r  r  r  r   r  )r  r  original_on_resizes      r0   _recover_after_resizezHermesCLI._recover_after_resizeb  s    , 480	Le<<<< 	 	 	D		NN 	 	 	D	s   % 
22A 
AAQ?delayc                     	 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  r  )r  lockr  r  	timer_refs   r0   _run_recoveryzPHermesCLI._schedule_resize_recovery.<locals>._timer_fired.<locals>._run_recovery  s     > >"4)A4HHPYYY"> > > > > > > > 7;38=5	> > > > > > > > > > > > > > >
 ..s4FGGGGGs   A A  AA)r  r   r  )r  r  r  r  r  r  r  s   `  r0   _timer_firedz9HermesCLI._schedule_resize_recovery.<locals>._timer_fired  s    H H H H H H H H H 8DD       DDD #11-@@@$   s    $$A 
AATc                                  S r   r   )r  timers   r0   r  z5HermesCLI._schedule_resize_recovery.<locals>.<lambda>  s    ||E7J7J r1   F)r  r|  r}  r  cancelr   r  Timerdaemonr  startr  )r  r  r  r  	old_timerr  r  r  s   ```  @@@r0   _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     r0   _status_bar_context_stylez#HermesCLI._status_bar_context_style  sG    ))2.."))2**&&r1   r  c                 &    | dk    rdS | dk    rdS dS )z=Return a style class reflecting context compression pressure.rQ   r  rh  r  r  r   r  s    r0   _compression_count_stylez"HermesCLI._compression_count_style  s(     B;;))A::**%%r1   rQ   r7  c                     t          dt          d|pd                    }t          |dz  |z            }dd|z  dt          d||z
            z  z    dS )Nr   rR   [u   █u   ░r>  )r  r  round)r  r  r7  safe_percentfilleds        r0   _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Ir1   prompt_start_timeprompt_durationlivec                    | |dk    rdS | t          j                     | z
  n|}t          d|          }t          |dz            }|dz  }t          |dz            }|dz  }t          |dz            }t          |dz            }|dk    r| d| d	| d
}	nD|dk    r|r| d	| d| dn| d	| d
}	n(|dk    r|r| d| dn| d
}	nt          |           d}	|rdnd}
|
 d|	 S )uE  Format per-prompt elapsed time for the status bar.

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

        Emoji prefix: ⏱ when turn is live, ⏲ when frozen or fresh start.
        Uses width-1 (no variation selector) glyphs so the status bar stays
        aligned in monospace terminals.
        Nr7   u   ⏲ 0siQ r  r8   r   zd r=   r;   m r:   u   ⏱u   ⏲r9  )r  r  rC   )r  r  r  elapsedrG   r^  rE   rD   r6   time_stremojis              r0   _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$$($$$r1   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``.
        NrM   r7   u   ✓ )r  r  rH   )r  r  idles      r0   _format_idle_sincezHermesCLI._format_idle_since  sI      	(023	&66775-d33555r1   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#}	 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|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\  r  z.gguf      r;  r7   
model_namemodel_shortdurationprompt_elapsedrb  rc  )r  
idle_sincerd  )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_processesr  r  process_registryr  context_compressorlast_prompt_tokenscompression_countrR   )r  r"  r  r  r  r  r   r  r`  total_secondsrH   r  r  r   tools.process_registryr   count_runningr  r  )r  r   r  r  elapsed_secondssnapshotbg_tasksr   
compressorr  r  s              r0   _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 ()+,5
 
 
@	t%8$??H D69(mm23 	 	 	D	
	??????6F6T6T6V6VH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*+s$   	%F/ /
F<;F< G 
G+*G+r_   c                 l    	 ddl m}  || pd          S # t          $ r t          | pd          cY S w xY w)aV  Return terminal cell width for status-bar text.

        len() is not enough for prompt_toolkit layout decisions because some
        glyphs can render wider than one Python codepoint. Keeping the status
        bar within the real display width prevents it from wrapping onto a
        second line and leaving behind duplicate rows.
        r   
get_cwidthrM   )prompt_toolkit.utilsr.  r   r  )r_   r.  s     r0   _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   rM   r-  Nr;  )r/  r.  r   r0  r  r  r   rX   )
r  r_   r1  r.  ellipsisellipsis_widthr  r7  r  ch_widths
             r0   _trim_status_bar_textzHermesCLI._trim_status_bar_textj  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  r9  r  get_sizer  r   r  r  )r   r9  s     r0   _get_tui_terminal_widthz!HermesCLI._get_tui_terminal_width  sl    	=::::::799#,,..66 	= 	= 	=+G44<<<<	=s   +. #AAc                 :    ||                                  }|dk     S )zBHide low-value chrome on narrow/mobile terminals to preserve rows.Nr*  )r;  r  r7  s     r0   _use_minimal_tui_chromez!HermesCLI._use_minimal_tui_chrome  s"    =0022Erzr1   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  rC   r7  s    r0   _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   rD  rZ  r@  )r  r  r>  )r  rB  r7  s      r0   _tui_input_rule_heightz HermesCLI._tui_input_rule_height  so    ,,,GXGGHHH4>FF 	1u100u0==Dqq1Dr1   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.rk  Fr   r@  rZ  )r  r>  r=  s     r0   _agent_spacer_heightzHermesCLI._agent_spacer_height  s<    t-u55 	100u0==Dqq1Dr1   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@  rQ   NrZ  )_render_spinner_textr>  r;  mathr0  r  ceil)r  r7  spinner_linerK  
text_widths        r0   _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qr1   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  rM   r  r   r8   02dr;   r:   z5.1f    (r  )r  r  r:  rC   )r  txtt0r  _m_selapsed_strs          r0   rJ  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r1   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    r0   _voice_record_key_labelz!HermesCLI._voice_record_key_label  s    * t>EEQQr1   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_statusr[  N)hermes_cli.voicer_  rZ  r   )r  r]  r_  s      r0   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 rc  u
    ● REC  z	 to stop )class:voice-statusu	    ◉ STT )rd  u    ◉ Transcribing... rd  u    🎤 r9  z	 | TTS onrM   z | Continuousu    🎤 Voice modeu     —  z to record )r;  r>  r\  r  r  r  r  )r  r7  r  labelttsconts         r0   _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'^'^'^_``r1   c                 l   	 |                                  }||                                 }|d         }|| dnd}|d         }|                                 }|dk     r+d|d          d	| }|r|d
z  }|                     ||          S |dk     rd|d          |g}|                    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          }|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     ⚙    ⚠ YOLOr  r  r\  ctx --r  r      │ r"  Hermes)r+  r;  _is_session_yolo_activer6  rB   r  r   rk   r`   r   r  r"  )r  r7  r(  percentpercent_labelduration_labelyolo_activer_   r   r  bg_countbg_proc_count	ctx_totalctx_usedcontext_labelr  r  s                    r0   _build_status_bar_textz HermesCLI._build_status_bar_text  s   :	U4466H}446601G-4-@wMMMMdM%j1N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^,,, -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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L	 
C7L	 FL	 	'L32L3c           	      

     j         rt           dd           rg S 	                                  }                                 }|d         }                                 }|dk     rSdd|d         fdd|fg}|r*|                    d           |                    d	           |                    d
           n|d         }|| dnd}|dk     rg|                    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           |	                    dd|fg           |r*|                    d           |                    d	           |                    d
           nD|d         r2t          |d                   }t          |d                   }| d| }n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           |	                    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  rl  r  )zclass:status-bar-yolorq  )r  r9  r  rj  rk  rm  r  r   r  r  rn  ro  rp  r  r  r\  rr  )r  rs  )r  r9  r  r  c              3   H   K   | ]\  }}                     |          V  d S r   )r0  )r   r8  r_   r  s      r0   r   z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>  s5      XXwq$d<<TBBXXXXXXr1   rM   c              3       K   | ]	\  }}|V  
d S r   r   r   r8  r_   s      r0   r   z6HermesCLI._get_status_bar_fragments.<locals>.<genexpr>  s&      $?$?gaT$?$?$?$?$?$?r1   r  r9  )r  r  r+  r;  ru  r  rB   r  r  r  rk   r`   r  sumr   r6  r   r  )r  r(  r7  rx  ry  fragsrv  rw  r  rz  r{  r|  r}  r~  	bar_styler  r  total_width
plain_texttrimmeds   `                   r0   _get_status_bar_fragmentsz#HermesCLI._get_status_bar_fragmentsW  s   ' 	749NPT+U+U 	Im	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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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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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   R:S S %TT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.rM   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\  rZ  z' for OpenAI Codex.[/]zgpt-5.3-codex)get_codex_model_idsN)access_token)r"  r   hermes_cli.model_normalizer  r  rC  rL  r   hermes_cli.modelsr  r  r#  rH  r  r  r  hermes_cli.codex_modelsr  )r  r  current_modelchangedr  r  normalized_modelr  r  	canonicalresolved_moder  r  slugfallback_modelr  	availables                    r0   _normalize_model_for_providerz'HermesCLI._normalize_model_for_provider  sJ   )r0022	       
 !(===#?#?O`#a#a # #(8M(I(I1 ++ F  F  FVf  F  Fn  F  F  F   "2DJ$4M"G 	 	 	D	 	))````````66}dl[[[	 #m!;!;1 ++nnn^gnnn   "+DJ$-M"G 6 6}dl [ [ [ DM11$1DM"G   N ???bbbbbbbb778I=YY	 #m!;!;1 ++ Pm  P  Pgp  P  P  yJ  P  P  P   "+DJ$-M"G 7 78I= Y Y DM11$1DM"G   N..N - &&sA..q1D) ##;m ; ;"; ; ;   DJ MG ! 	,N	GGGGGG//15!G4  	  2%.q\N    ..+
sJ   AA1 1
A>=A>A6C? ?
DDA-F 
FF6*H! !
H.-H.c                 ~    |s|                      d           |pd| _        d| _        |                                  dS )z@Called by agent when thinking starts/stops. Updates TUI spinner.Tr  rM   r7   N)_flush_reasoning_previewr  r  r  r  r_   s     r0   _on_thinkingzHermesCLI._on_thinking0  sM     	6)))555!ZR #r1   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.
        r_   rM   Nlevelr  _pending_credit_notices)r  r*  r  r  r   )r  noticer_   r  s       r0   
_on_noticezHermesCLI._on_notice8  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)r  warnsuccessr  rR  )r  r  _DIMrB   r  _RSTr   )r  pendingr  r_   colors        r0   _flush_credit_noticeszHermesCLI._flush_credit_noticesL  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     r0   _on_notice_clearzHermesCLI._on_notice_clear_  s	    
 	r1   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  r4  _stream_reasoning_deltar	  _on_reasoningr  s    r0   _current_reasoning_callbackz%HermesCLI._current_reasoning_callbackh  sB     	04#9 	0//< 	& 3 	&%%tr1   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   r9  c              3   f   K   | ],}|                                 |                                 V  -d S r   r  r  s     r0   r   z4HermesCLI._emit_reasoning_preview.<locals>.<genexpr>  s<      __RVR\R\R^R^_tzz||______r1   r@  rR  z[thinking] rh  z
  ... ( more lines))r   r  r  r  r   r  r  r   r  rC  r   r  r  textwrapfillr	  r  r  r  )r  r  preview_text
term_widthr  
wrap_width
paragraphsraw_paragraphs	paragraphr  r  previews               r0   _emit_reasoning_previewz!HermesCLI._emit_reasoning_previewp  s   %++-- 	F	133;JJ 	 	 	JJJ	 Z#f++59::

+|/C/CFD/Q/QRR' 	L 	LIhh__	8L8L8N8N_____G L!!(-z"J"J"JKKKyy,, 	F< 	>>>,>>>???F''))u::>>iibqb	**G?3u::>????GG"G5T55g5t5566666s   3 AAr  r  c          	      
   t          | dd          }|sdS 	 t          j                    j        }n# t          $ r d}Y nw xY wt          d|t          d          z
  dz
            }d}|r|}d}n^|                    d          }t          d	|d
z            }|dk    r||k    si|                    d          sT|                    d          s?|                    d          s*|                    d          s|                    d          r|d|dz            }||dz   d         }nt          |          |k    rt          d|dz            }t          t          |          t          ||d
z  z   |dz                       }	d}
dD ]'}t          |
|                    |||	                    }
(|
dk    r|d|
dz            }||
dz   d         }|r|
                                n|| _        |r|                     |           dS dS )zFlush buffered reasoning text at natural boundaries.

        Some providers stream reasoning in tiny word or punctuation chunks.
        Buffer them here so the preview path does not print one `[thinking]`
        line per token.
        r<  rM   Nr  (   r  r  r   r	  r  r  r  z.
z!
z?
z:
rZ  r  r[  rt  )r9  	rS   !?rU   r  r  )r  r  r  r  r   r  r  rfindr  r  r  r<  r  )r  r  rA  r  target_width
flush_text
line_breakmin_newline_flushsearch_start
search_endcutboundarys               r0   r  z"HermesCLI._flush_reasoning_preview  sf    d4b99 	F	133;JJ 	 	 	JJJ	2zC,@,@@1DEE
 	)JCC4J #B(9 : :R///<<'' 0<<&& 0 <<&& 0 <<&&	 0
 <<&& 0 !!1:>!12
*q.**+S\))"2|q'899 S3||q?P/QS_bcSc+d+dee
 I R RHc399X|Z#P#PQQCC"99!$YsQwYJcAgii.C6@&Icjjlllc# 	5((44444	5 	5s   0 ??r%  c                 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.r5  Fz [dim]%H:%Mr   rM   r   rZ  [bold    ]●[/] [bold]r7  r[  r8  r   Nc              3   <   K   | ]}d t          |           dV  dS z[bold]r   N_escaper  s     r0   r   zCHermesCLI._format_submitted_user_message_preview.<locals>.<genexpr>  s4      NNT8gdmm888NNNNNNr1   r  r  z[dim]... (+z more )[/]c              3   <   K   | ]}d t          |           dV  dS r  r  r  s     r0   r   zCHermesCLI._format_submitted_user_message_preview.<locals>.<genexpr>  s4      JJT8gdmm888JJJJJJr1   )r  r   r  rh  r  r  r  r  rC   r  r  r  r  r   )r  r%  	ts_suffixr  r  r  headremaining_after_head
tail_counttailhidden_middle_countpreview_linesnouns                r0   &_format_submitted_user_message_previewz0HermesCLI._format_submitted_user_message_preview  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'''r1   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 #rM   ,\[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)NrZ  r   r   z8Paste file gone or unreadable, returning placeholder: %sr   )r   r_  r  r  IOErrorr   r   )r^  r   s     r0   _expand_refz7HermesCLI._expand_paste_references.<locals>._expand_ref  s~    A''D&~~w~777W% & & &Y[_```{{1~~%%%&s   : AA>=A>)r   rW   r   compiler   )r  r_   paste_ref_rer  s       r0   _expand_paste_referencesz"HermesCLI._expand_paste_references  s`    $$$ 	(8(D(D:2z"QRR		& 		& 		& T222r1   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   rM   r   r  r  N)r  r  r  rW   r  r  )r  r%  r_   s      r0   _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Yr1   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      ┌─   ─rZ  r      ┐_reasoning_bufrM   r  )_reasoning_shown_this_turnr  r  rA  r  r  r  r  r  r   r  )r  r_   rM  r_labelr_fillr  s         r0   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 )(r1   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   rM      └r  r[     ┘_deferred_contentN)	r  r  r  r  r   rA  r  r  _emit_stream_text)r  rA  rM  deferreds       r0   _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 1r1   c                 0   |*|                                   |                                  dS |sdS d| _        d}d}t          | dd          |z   | _        t          | d          sd| _        t          | dd	          s|D ]0}d
}	 | j                            ||          }|dk    rn| j        d|         }|d
k    rt          | dd          }nh|                    d          }	|	dk    r*t          | dd          o|	                                dk    }n#||	dz   d         	                                dk    }|r]|r/| 
                    |           |                    d          | _        d| _        | j        |t          |          z   d         | _        n|dz   }t          | dd	          r n2t          | dd	          s| j        }
|D ]V}t          dt          |                    D ]6}| j                            |d|                   r| j        d|          }
 n7W|
rP| 
                    |
           |
                    d          | _        | j        t          |
          d         | _        dS t          | dd	          r|D ]}| j                            |          }|dk    rtd	| _        | j        r&| j        d|         }|r|                     |           | j        |t          |          z   d         }d| _        |r|                     |            dS t%          d |D                       }t          | j                  |k    rA| j        r%| j        d|          }|                     |           | j        | d         | _        dS dS )a  Line-buffered streaming callback for real-time token rendering.

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

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

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

+KD(
 4.66 	"  *//44"99/4D, * @ $ 4TcT :  @ 88??? 0s3xxAE+-D(  2**5111FF $ ::k:::::K4'((;66& A%)%9-K<-%HN00@@@'+';[LMM'J$F9	 	r1   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  rM   r   Tr   r~  response_label
   ⚕ Hermesbanner_textr\  rZ  r  r	  rh  r  z[38;2;r  r;   r9  r  r[     ╭─r     ╮_stream_text_ansiprinted_liner|   c                 d    t          rt            |  t           n
t           |             d S r   )r  r  r  )r&  _tcs    r0   	_emit_onez.HermesCLI._emit_stream_text.<locals>._emit_one  sB    h{=C==t===[JhZfJhJhiiiiir1   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  ri   r  r  )rA  joinedblocklnr)  r  s       r0   _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$''  	" r1   r   r  )$r  r  r  r
  r;  r  rp  r  r  rq  r   rC   r%  r  r  r5  r   r  rh  rA  r  r0  r  _ACCENTr  r  r9  rW   r  r>  rf   rb   r=  r  r	  r  )r  r_   r  r  re  	_text_hex_r_g_brM  r  r.  r  r)  r(  s   `            @@r0   r  zHermesCLI._emit_stream_text  s    	F
  	741H%#P#P 	%,T3F%K%Kd%RD"F 	!!### & 	T;;t$$D &*D#&BBBBBB'))**+;\JJ!OOM9EE		 & & &$%			&
,1Q3,,1Q3,,1Q3,,)Eb)E)E2)E)E)E)E)E&&
+ , , ,)+&&&,# 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  rM   r%  r>  r=  Nr   r      ╰r  r[     ╯)r  r  r  r  r
  r9  rf   rb   r=  r  r   r>  r	  r  ri   r  r  r  r  r  r;  rA  r/  )r  r(  r+  r,  r-  r  rM  s          r0   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==>>>>>	? 	?r1   c                     d| _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        g | _        d| _        dS )z3Reset streaming state before each agent invocation.rM   FTN)r9  r:  r;  r%  r  r  r  r  r   r<  r  r=  r>  r  s    r0   r  zHermesCLI._reset_stream_stateW  sp    $"'!#!#( (,%%*" &(#!#!# %r1   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  r8  	cmd_lowers      r0   _slow_command_statuszHermesCLI._slow_command_statusg  s    MMOO))++	 011 	)(( 011 	'&& 122 	)(( 122 	)((	** 	211%%--(((I9I,I,I((
++ 	,++&&r1   c                     t          t          j                    dz            t          t                    z  }t          |         S )z9Return the current spinner frame for slow slash commands.rQ   )rC   r  r:  r  _COMMAND_SPINNER_FRAMES)r  	frame_idxs     r0   _command_spinner_framez HermesCLI._command_spinner_frame|  s5    ((2-..5L1M1MM	&y11r1   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.Tr7   r  u   ⏳ NFrM   )r  r  r  r  )r  r  s     r0   _busy_commandzHermesCLI._busy_command  s       !%%c***	////"""EEE$)D!#%D #..... %*D!#%D #....s   A$ $&B
c                 F   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           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.r_   rM   Tcursor_position)validate_and_handlez Failed to open external editor: )r  r  r  r  r  rw  r  rz  rt  r  r*  _skip_paste_collapser_   r  rF  open_in_editorr   )r  bufferr  target_bufferexisting_textexpanded_textr  s          r0   _open_external_editorzHermesCLI._open_external_editor  s   dFD)) 	t``Z^``aaa5  	tdd^bddeee5 	t1 	T5I 	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%((U(CCC4 	 	 	tHHSH$HHIII55555	s   BE+ +
F 5 FF 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     r0   _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_failuresrm  tirith_enabledrR  ui   ⚠ tirith security scanner enabled but not available — command scanning will use pattern matching only)r  r]  tools.tirith_securityrY  rZ  r   rB   r  r  r  r   )r  rY  rZ  tirith_pathsecurity_cfgr\  s         r0   _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)r  rT  N)hermes_cli.security_advisoriesrb  rc  r  rO  r  r   )r  rb  rc  hitsbanners        r0   _show_security_advisoriesz#HermesCLI._show_security_advisories  s    	        &%''D#^D))F ; f3:T::::::; ;  	 	 	 DD	s   ;A 
AAc           	      X   | j                                          d}t          | d          r-| j        r&t          | j        d          r| j        j        j        }t          j                    j        }| j	        p|dk     }|r6| 
                    t                                 |                                  nft          | j        d          }t          j        dt          j                              }t%          | j         | j        ||| j        | j        |           t          j                            d	          d
k    r|                                  ddlm} |r||k     r| 
                                 | 
                    d|dd           | 
                    d|dd           t5          | dd          pd}d|v sd|                                v r| 
                    d| d           n/d|v r| 
                    d           n| 
                    d           ddlm} t5          | dd          pd}	 ||	          rS| 
                                 | 
                    d           | 
                    d           | 
                    d           | 
                                 dS ) z0Display the welcome banner in Claude Code style.Nr   r!  r  TrK  
quiet_moder6  r1  r"  r   toolsrK  r  r  r  r   r   )MINIMUM_CONTEXT_LENGTHu'   [yellow]⚠️  Context length is only rU   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   rM   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[/])r1  r  r*  r   r!  r  r  r  r  r  rL  r  _show_statusr  rK  r   r   rw  r  r"  r  rr  rB    _show_tool_availability_warningsagent.model_metadatarm  r  r   hermes_cli.model_switchrq  )
r  ctx_lenr  use_compactrl  r   rm  r   rq  r  s
             r0   show_bannerzHermesCLI.show_banner  sf   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   	r1   )quietsession_metary  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 rS   r  z[dim]z[/dim]u0   ⚠ Could not enter session's working directory : r6  u   ↻ Working directory: )rB   r   r   r   rW   rw  r  realpathr  r  rO  r  rL  r  chdirrr  )r  rz  ry  recordedr   msgr   s          r0   _restore_session_cwdzHermesCLI._restore_session_cwdC  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)r  r  r  r  r7  Nr   )r  r  r  r  r  r  r  r  r  rX   r  )r  panelr  rA  r7  r1  s         r0   "_render_resume_history_panel_linesz,HermesCLI._render_resume_history_panel_linesz  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  rZ  r0  clip_r8  r  TF)	hermes_cli.clipboardr  rm   r  r   r  rh  r  r  )r  r  img_dirtsimg_paths        r0   _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 ur1   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.rZ  r   hashz#  Invalid checkpoint number. Use 1-rS   N)rC   r  r  r  )r  r  r  r*  s       r0   _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   rN  z]52;c;r^  Nr  r  rR  )base64	b64encodeencodedecoder  r*  r  rT  rR  rO  rP  )r  r_   payloadseqr  r  s         r0   _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

r1   r  c                   t          j                    }|| j        z
  dk     rdS || _        t          | dd          }|rt          |dd          nd}	 |r?t	          |d          r/|                    t                     |                                 n|r?t	          |d          r/|                    t                     |                                 nBt          j
                            t                     t          j
                                         n# t          $ r Y dS w xY wt                              d|           | j        s(d| _        t          d	t            d
t"                      dS dS )z@Best-effort reset when leaked mouse reports indicate mode drift.r   Nr^  r  r  rR  z-Recovered terminal input modes after leak: %sTrR  ziRecovered terminal input modes after leaked mouse reports. If this repeats, run /new or restart this tab.)r  r:  r@  r  r*  r  rS  rT  rR  rO  rP  r   r   r   rA  r  r  r  )r  r  r  r  r  s        r0   _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   rR  u   👁️  analyzing r  zKB)...)	image_urluser_promptr  analysisrM   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?)r  tools.vision_toolsr  r   r  st_sizer  r  r  r  rk  rW   r   loadsrB   r  r   r   r   )r  r_   r  r  r  r  analysis_promptenriched_partsr  size_kbresult_jsonr   descriptionr   	user_textr  s                   r0   _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     r0   r   z>HermesCLI._show_tool_availability_warnings.<locals>.<listcomp>,  s"    KKKQ>9JKqKKKr1   u:   [yellow]⚠️  Some tools disabled (missing API keys):[/]r  rl  Nr[  z, +z moreu      [dim]• r  z[/] [dim italic](r  r  z*[dim]   Run 'hermes setup' to configure[/])r  r  rL  r   r  r   )r  r  r  unavailableapi_key_missingr  	tools_strs          r0   rs  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 deferredTri  r    toolsr\  r  r}  N   r;  u   [green bold]●[/]u   [red bold]●[/]r~  r  r_  r  r^  ui_labelr`  )r_  r^  cyanrM   r  z [dim u   ]·[/] [z]toolsets: r  r   u   ]·[/] [dim]provider: u   ]·[/] [dim]auth: rR   [r>  r  u   ]·[/] [bold )r   rr  rB   r  rK  r  r"  r  r#  rp  r  rq  r   r   r   rG  rL  )r  tool_statusrl  
tool_countr  api_indicatorr  r  separator_coloraccent_colorlabel_colortoolsets_infoprovider_infos                r0   rr  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.titlerM   
started_at)
updated_atlast_updated_atlast_activity_atr   Nr  r   r   r  r"  z	(unknown)rk  FzHermes CLI StatuszSession ID: zPath: zTitle: zModel: r  r  z	Created: z%Y-%m-%d %H:%MzLast Activity: zTokens: rU   zAgent Running: YesNor   )r  markup)re  get_sessionr  r   rB   r   r`  r   fromtimestamprA   r  r  rn   r  r  rh  rL  r   )r  rz  r  
created_atr  r  fieldrJ   r   total_tokensr   r"  r  r  s                 r0   _show_session_statuszHermesCLI._show_session_statusf  s    	""#/;;DOLLRPR " " "!" !!'**0b7799'
!%%l33
 	00%3E*4E4EFF

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


0  
J 	 	E $$U++E %3E%LLAA
    gt,,u&<a@@EA4T22?igt,,;'$(8%@@AA
  ,4?,,,(**,,	
  	,LL*5**+++*e**x***?
++,<==??Ej112BCCEE'|'''=z;eet==
 	 	 	 	DIIe,,eLLLLLs0   !- <<!B) )B=<B=!D
DDc                     	 ddl m} n# t          $ r Y dS w xY wt          | dd           }t          |dd           pt          | dd           } ||          S )Nr   )model_supports_fast_modeFr   r"  )r  r  r   r  )r  r  r   r"  s       r0   _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     r0   _command_availablezHermesCLI._command_available  s$    G##//111tr1   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 CommandsrM   7   Nr   +rL   |^
  u   ── u    ──z
    [bold r>  z<15z[/] [dim]-[/] u   
  ⚡ zSkill Commandsr  z installed):z<22r  u   
  ▣ zSkill Bundlesr  zLoad z skillsz [dim](z skills)[/]quick_commandszQuick Commandsz configured):r   r\  z0Tip: Just type your message to chat with Hermes!rR  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  rp  r  r   r   r  r  _BOLDr  ry  r  r  r  r  r  r  sortedr  rB   r   r  _is_termux_environmentr	  )r  r  r  headerinner_widthcategorycommandscmddescskill_commandsr  _bundles_nowskill_countr  r  qcmds                   r0   	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.Tri  z(;_;) No tools availableNz(^_^)/ Available ToolsN   r  rL   r  r9  r[  c                     | d         d         S )Nfunctionr  r   )r  s    r0   r  z&HermesCLI.show_tools.<locals>.<lambda>  s    *f0E r1   r  r  r  r  r  rM   r   r   . rZ  z  [r>  z    * z<20z - z	  Total: u    tools  ヽ(^o^)ノ)r  rK  r  r  r  r  rB   r  rU  r  r  )
r  rl  r  r7  padr  toolr  toolsetr  s
             r0   
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:::r1   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  rL   r  r9  r[  r  r  z(*)z   rR  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  r  r  r  r  rK  )
r  all_toolsetsr  r7  r  r  r  r  r  markers
             r0   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r1   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.r5  r   r6  r7  60r   r   z(loaded)z(not found)r   )is_token_providerzMicrosoft Entra IDr  Nrt  r;  zNot set!z(^_^) Configurationr   r  rL   r  r9  r[  z  -- Model --z  Model:     z  Base URL:  z  API Key:   z  -- Terminal --z  Environment:  sshr?  znot setrA  rC  22z  SSH Target:   @r  z  Working Dir:  z  Timeout:      r:   z  -- Agent --z  Max Turns:  z  Toolsets:   r  r  z  Verbose:    z  -- Session --z  Started:     z%Y-%m-%d %H:%M:%Sz  Config File: )r   r   rw  r   r   rp  rq  r   agent.azure_identity_adapterr  r#  r   rW   r  r  r"  r   r  rK  r   r	  r`  rh  )r  terminal_envterminal_cwdterminal_timeoutr{  r|  r~  config_statusr  api_key_displayr  r7  r  r>  r@  rB  s                   r0   show_configzHermesCLI.show_config0  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==>>>r1   r9  c                       j         sg S 	  j                             ddg|          }n# t          $ r g cY S w xY w fd|D             S )zCReturn recent CLI sessions for in-chat browsing/resume affordances.r  r  )sourceexclude_sourcesr9  c                 P    g | ]"}|                     d           j        k     |#S )id)rB   r  )r   r:   r  s     r0   r   z3HermesCLI._list_recent_sessions.<locals>.<listcomp>v  s/    FFFaquuT{{do'E'E'E'E'Er1   )re  list_sessions_richr   )r  r9  r  s   `  r0   _list_recent_sessionszHermesCLI._list_recent_sessionsj  s     	I	'::!' ;  HH
  	 	 	III	FFFF8FFFFs   + ::history)r  r9  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.
        r9  Fr   )_relative_timer  uV   (._.) No messages in the current chat yet — here are recent sessions you can resume:z  Recent sessions:rR  r  z<3r9  Titlez<32Previewz<40zLast Activez<13IDu	   ───u`   ────────────────────────────────r  u'   ─────────────uH   ────────────────────────rZ  )r  r  u   —r  rM   N&   last_activer  zU  Use /resume <number>, /resume <session id>, or /resume <session title> to continue.z  Example: /resume 2T)r  hermes_cli.mainr  r  r  rB   )
r  r  r9  r  r  r*  sessionr  r  r  s
             r0   _show_recent_sessionszHermesCLI._show_recent_sessionsx  s   
 --E-:: 	5222222Yjkkkk&'''T3TTTGTTT)TTT-TTTdTTUUUR9RRzRRJRRRRjRRSSS%ha888 	] 	]LCKK((1EE{{9--3SbS9G(.])C)CDDK[s[[[[[[G[[[+[[[GTXM[[\\\\efff$%%%tr1   c                    | j         s'|                     d          st          d           dS d}d}dfd}t                       t          d           t          d	           t          d           | j         D ]9}|                    d
d          }|dk    rdz  %|dvr* |             |dz  }|                    d          }|dnt	          |          }|dk    rEt          d| d           t          d|d|          t          |          |k    rdnd            t          d| d           |                    d          pg }|r"|d|         }	t          |          |k    rdnd}
n+|r%t          |          }|dk    rdnd}d| d| d}	d}
nd}	d}
t          d|	 |
            ; |             t                       dS )zDisplay conversation history.r  r6  z"(._.) No conversation history yet.Ni  r   c                  r    sd S dk    rdnd} t          d           t          d d|  d           dd S )	NrZ  r  messagesz

  [Tools]z    ( tool z hidden)r   )r  )r  hidden_tool_messagess    r0   flush_tool_summaryz2HermesCLI.show_history.<locals>.flush_tool_summary  s`    '  4 9 999zD-   D.DDdDDDEEE#$   r1   z4+--------------------------------------------------+z3|            (^_^) Conversation History           |roler  r  rZ  >   user	assistantr   rM   r'  z	
  [You #r>  r  r;  z
  [Hermes #r   callcallsz(requested r#  r  z(no text response))r_  r  r  rB   rW   r  )r  preview_limitvisible_indexr%  r  r&  r   content_textr   r  r]   r  r  r$  s                @r0   show_historyzHermesCLI.show_history  sz   ( 	--Y-?? <:;;;F 	% 	% 	% 	% 	% 	"###LMMM"###, $	, $	,C7769--Dv~~$)$000   QMggi((G!(22c'llLv~~3=333444m<7m#lBSBSVcBcBcikmm   2-222333..4"J 
&~~6"%l"3"3m"C"C  __
!+qvvgA
AA$AAA.**&**++++r1   
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   r0  Nr  r  on_session_resetnew_sessionsession_boundaryr  )r  r1  r   r  r  r   )r  r/  r3  s      r0   _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	  )re  r  r   rm   delete_session_if_emptyr   r   r  )r  r  _ghhs      r0   _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        rD|rB	 | 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        t8          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-# tJ          $ r }	tM          d|	            d}d}Y d}	~	nd}	~	ww xY w|rd	 | j        '                    | j        |           d| _        |}nL# tJ          $ r}	tM          d|	 d           d}Y d}	~	n(d}	~	wt          $ r d}Y nw xY w|tM          d           d}	 tQ          | j         dd          }
|
 |
)                    | j        |pddd           n# t          $ r Y nw xY w|                     d           |s'|rtU          d|            dS tU          d           dS dS )zDStart a fresh session with a new session ID and cleared agent state.r2  r2  r0  Nr  r8  F_last_flushed_db_idxr   _todo_store)	TodoStore_invalidate_system_promptHERMES_SESSION_SOURCEr  )r'  rR  )r  r  r"  model_configTr.  z  Title rejected: rR  u    — session started untitled.u<     Title is empty after cleanup — session started untitled._memory_managerrM   )parent_session_idr  r  r1  z(^_^)v New session started: z(^_^)v New session started!)+r   r_  commit_memory_sessionr4  r  re  end_sessionr   r8  r   r  r`  rh  r  r  r  rg  ra  r  reset_session_stater*  r:  tools.todo_toolr<  r;  r=  _session_db_createdcreate_sessionr   rr  rB   r"  r  rR  rf  r/  sanitize_titler  r  set_session_titler  on_session_switchr  )r  silentr  old_session_idr  r  r<  r/  	sanitizedr   _mms              r0   r2  zHermesCLI.new_session  s   : 	A$3 	AJ,,T-FGGG))*?@@@@Z 	A))*?@@@ 	; 	; ,,^]KKKK    **>:::%\^^*33ODDZ\\%bqb)
*99Z99$&!" 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   1B 
BB3G 
GGA+J 
JJ!J7 7
K!KK!')L 
ML55MM8N 
N$#N$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.
        FNrZ  z  Resume index z is out of range.z:  Use /resume with no arguments to see available sessions.Tz/resume )	r  r   rW   r   rO  rC   r  r  _handle_resume_command)r  r_   r  r-  rU  s        r0   !_consume_pending_resume_selectionz+HermesCLI._consume_pending_resume_selectionr  s     / 	5 )-%$$$ 	5::<< !! 	5H199G,,>e>>>???PQQQ4##$6u$6$6777tr1   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.Nr0  r  savedTrw  z&(x_x) Failed to create save directory r|  hermes_conversation_z.jsonrM  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   r  rh  rm   r  r   r   r   dumpr"  r  r`  	isoformat)r  	timestamp	saved_dirr   r   r   s         r0   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.NrZ  r  r&  r'  z%(._.) No user message found to retry.r   rM   z(^_^)b Retrying: "r8   r;  r  )r_  r  r  r  rB   )r  last_user_idxr  last_messages       r0   
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r1   rZ  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.NrZ  r  r&  r'  z$(._.) No user message found to undo.r   rM   r   rQ   r  r  rewound_counttarget_messagezundo: soft-delete skipped: %szundo: soft-delete failed: %sr=  r:  r@  FT)rA  r  rewoundturnturnsz(^_^)b Undid r9  r  z message(s)). Backed up to: "r8   r;  r  rR  z! message(s) remaining in history.)r_  r  r  r  rB   r  _undo_content_to_textre  r  list_recent_user_messagesr  r  rewind_to_messager  r   r  r   r   r*  r=  r:  r  rJ  _prefill_input_buffer)r  r`  ra  user_indicesr  cut_idxturns_undoneremoved_countremoved_msgremoved_textrewound_rowsrecents
target_idx	target_idr   db_textr   rN  	turn_word	msg_countr^  s                        r0   	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   rB   r   s     r0   r   z3HermesCLI._undo_content_to_text.<locals>.<listcomp>[  sY       a&& ,-55==F+B+B fb!!+B+B+Br1   r   c              3      K   | ]}||V  	d S r   r   r  s     r0   r   z2HermesCLI._undo_content_to_text.<locals>.<genexpr>`  '      3313Q333333r1   rM   r   r   s     r0   rh  zHermesCLI._undo_content_to_textU  ss     gs## 	Ngt$$ 	4    E
 9933333333rr1   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^  NrF  zundo: prefill buffer failed: %s)
r  rE  r_   r*  r  rF  r  r   r   r  )r  r_   r  rA  r   s        r0   rk  zHermesCLI._prefill_input_bufferc  s    dFD));F	?$CCHs-.. 0&)$ii#NN 	? 	? 	?LL:A>>>>>>>>>	?s   AA 
B)B

Br   r  ry  default_indexc                   	
 ddl }ddlm	 dg
	
fd} |j                     |j                    u }| j        r|rddlm} | j        }d| _        | j        	                                 	  ||           || _        | j        	                                 n/# || _        | j        	                                 w xY w |             
d         S )zbRun curses_single_select via run_in_terminal so prompt_toolkit handles terminal ownership cleanly.r   N)curses_single_selectc                  *                d<   d S )N)r  r   r   )r  r  ry  r   r  s   r0   _pickz+HermesCLI._run_curses_picker.<locals>._pickx  s"    ,,UEWWWF1IIIr1   r  F)
r|  hermes_cli.curses_uir  current_threadmain_threadr^  r  r  r  r  )r  r  ry  r  r|  r  in_main_threadr  was_visibler  r   s    ```     @@r0   _run_curses_pickerzHermesCLI._run_curses_pickerq  s:   ======	X 	X 	X 	X 	X 	X 	X 	X 	X 21337Ly7L7N7NN9 	 	BBBBBB2K',D$I  """'&&&+6(	$$&&&& ,7(	$$&&&&EGGGays   1B "B?prompt_textc                    ddl }dgfd} |j                     |j                    u }| 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   )re  r   KeyboardInterruptEOFError)r  r   s   r0   _askz*HermesCLI._prompt_text_input.<locals>._ask  sU    !+..4466>$q			%x0   s   &+ A A r  F)	r|  r  r  r^  r  r  r  r  r   )r  r  r|  r  r  r  r  r   s    `     @r0   _prompt_text_inputzHermesCLI._prompt_text_input  sc    		 	 	 	 	 	 21337Ly7L7N7NN9 	 	BBBBBB2K',D$I  """'%%%%   DFFFF    D ,7(	$$&&&& ,7(	$$&&&&DFFFaysN   %A1 0B> 1
B<
BB
BBBBB> BB> >"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 )NrY  r  )rO  r  r  r  )r  r  s   r0   _stdin_fallbackz;HermesCLI._prompt_text_input_modal.<locals>._stdin_fallback  sC    
 |w&&~&  """t**+=>>>r1   c                                                        dd_                                         z   _                                         d S )Nr   )r  r  r  selectedresponse_queue)_capture_modal_input_snapshotr  r:  r  r  )_timer  r  r  r  r   r  s   r0   _setup_modalz8HermesCLI._prompt_text_input_modal.<locals>._setup_modal  sd    ..000 ""0) )D% ,1??+<+<w+FD(r1   c                  t    d  _         d _                                                                            d S r  )r  r  _restore_modal_input_snapshotr  r  s   r0   _teardown_modalz;HermesCLI._prompt_text_input_modal.<locals>._teardown_modal  s=    (,D%+,D(..000r1   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   )r  )fnreadys   r0   _wrappedzNHermesCLI._prompt_text_input_modal.<locals>._run_on_app_loop.<locals>._wrapped  s6     BDDDIIKKKKKEIIKKKKs   
# 9Frh  r  r  )r  r  r   wait)r  r  r  app_loopr  r|  s   ` @r0   _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TrZ  r        @r  )r|  r  r  r  r^  r  r   r  r  rW   r  rl  r  r:  rB   r  Emptyr  r  )r  r  r  r  r   r  r  r  r  _last_countdown_refreshr   r^  r  r  r  r  r  r|  s   `````        @@@@@r0   _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rJ   c                     | j         }|sd S |d                             |           d | _         d| _        |                                  d S Nr  r   )r  putr  r  )r  rJ   states      r0   _submit_slash_confirm_responsez(HermesCLI._submit_slash_confirm_response7  sY    ) 	F##E***$(!'($r1   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alwaysr  )r   r  approver  yok2r  remember3r  	nevermindnor`  c                     h | ]
}|d          S r   r   r   choices     r0   	<setcomp>z<HermesCLI._normalize_slash_confirm_choice.<locals>.<setcomp>Z  s    3336!9333r1   )r   r   rB   )r  r   r  
choice_rawaliasesallowedr  s          r0   _normalize_slash_confirm_choicez)HermesCLI._normalize_slash_confirm_choice@  s    
 ;4YY[[&&((
 	4 !
 
  437333[[,,
    tr1   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  rM   r  r  r   8   V   
title_textcontent_lines	min_widthr1  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rR   r  c                 ,    g | ]}t          |          S r   r  r  s     r0   r   z\HermesCLI._get_slash_confirm_display_fragments.<locals>._panel_box_width.<locals>.<listcomp>o      .S.S.STs4yy.S.S.Sr1   r  r[  r<   r  r  r  r  r  r  r  r  r  r  r1  	term_colslongestr  s          r0   _panel_box_widthzHHermesCLI._get_slash_confirm_display_fragments.<locals>._panel_box_widthm      0;;CI3z??+.S.S].S.S.SSW`cdWdVeeffGGaKQ77QBPY\]P]H^H^__E19r1   r_   r7  subsequent_indentc                 Z    t          j        | t          d|          dd|          }|pdgS Nrt  F)r7  replace_whitespacedrop_whitespacer  rM   r  wrapr  r_   r7  r  wrappeds       r0   _wrap_panel_textzHHermesCLI._get_slash_confirm_display_fragments.<locals>._wrap_panel_texts  =    m!Umm#( %"3  G ?rd"r1   border_stylecontent_style	box_widthNc                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S Nr   r[  u   │ u    │
r  r  r  r  r  r  r_   r  r  s         r0   _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2r1   c                 F    |                      |dd|z  z   dz   f           d S Nu   │r9  u   │
r  r  r  r  s      r0   _append_blank_panel_linezPHermesCLI._get_slash_confirm_display_fragments.<locals>._append_blank_panel_line  -    LL,y(AG(KLMMMMMr1   H      ❯r9  r  rZ  z]     — r  r  u9   Type 1/2/3 or use ↑/↓ then Enter. ESC/Ctrl+C cancels.rt  r[  rR   r<   r  u   … (detail truncated)class:approval-border   ╭r     ╮
class:approval-titleclass:approval-descclass:approval-selectedclass:approval-choiceclass:approval-cmdr5     ╯
)r  r  ro  )r  rB   rW   r   rC   r  r  r  r  r  r  r  r  r  r  )r  r  r  r  r  r  r  r  r  r  r  r  r*  _valuere  r  r  r  inner_text_widthdetail_wrappedchoice_wrappedr  	term_rowsreserved_belowchrome_fullr  max_detail_rowskeepr  styles                                 r0   $_get_slash_confirm_display_fragmentsz.HermesCLI._get_slash_confirm_display_fragmentsb  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r1   	providersr  current_providerc                     |                                   t          d t          |          D             d          }d||||||d| _        |                     d           dS )z/Open prompt_toolkit-native /model picker modal.c              3   J   K   | ]\  }}|                     d           |V  dS )
is_currentNrB   )r   r  r   s      r0   r   z/HermesCLI._open_model_picker.<locals>.<genexpr>  s7      VV$!Q!%%BUBUVAVVVVVVr1   r   r   )stager	  r  r  r	  
user_provscustom_provsr7   rB  N)r  nextr  r  r  )r  r	  r  r	  r	  r	  default_idxs          r0   _open_model_pickerzHermesCLI._open_model_picker  s~    **,,,VV)I*>*>VVVXYZZ"#* 0$($
 $
  	c*****r1   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_warningrM   )r   r   r#  
model_infoN)r  zSwitch anywayz.Use this model for the current Hermes session.)r  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  r  r  )r  r   r	  r   r  r   r  s          r0   _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	  r  _apply_model_switch_resultr   )r  r   r	  r  s       r0   &_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 )Nr7   rB  )r  r  r  r  s    r0   _close_model_pickerzHermesCLI._close_model_picker  s9    #' **,,,c*****r1   r  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   rZ  )r  r  )	r  r'	  r`  r	  r	  r(	  r)	  max_visiblevisibles	            r0   _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%%r1   c                 R   |j         st          d|j                    d S | j        }|j        | _        |j        | _        |j        | _        |j        | _	        |j
        | _        |j        r|j        | _        |j
        r|j
        | _
        |j        r|j        | _        | j        d	 | j                            |j        |j        |j        |j
        |j                   n*# t          $ r}t          d| d           Y d }~nd }~ww xY wd| d|j         d|j        p|j         d| _        |j        p|j        }t          d	|j                    t          d
|            |j        }	 ddlm}  ||j        |j        |j
        p| j
        pd|j        p| j        pd|| j        rt+          | j        dd           nd           }|rt          d|dd           n# t          $ r Y nw xY w|r||j        rt          d|j        dd           |                                r$t          d|                                            t          d|                                            t5          |j
        pdd          rd|j                                        v p
|j        dk    }	|	rt          d           |j        rt          d|j                    |rBt;          d|j                   |j        rt;          d|j                   t          d           d S t          d           d S )N     ✗ r	  new_providerr#  r   rH       ⚠ Agent swap failed ("); change applied to next session.$[Note: model was just switched from  to  via /. Adjust your self-identification accordingly.]     ✓ Model switched:     Provider: r   resolve_display_context_lengthrM   _config_context_lengthr   r#  r	  config_context_length    Context: rU    tokens    Max output: 
    Cost:     Capabilities: r  claudeanthropic_messages    Prompt caching: enabled       ⚠ model.defaultmodel.provider#    Saved to config.yaml (--global).       (session only — add --global to persist))r  r  error_messager"  r	  r	  r   rF  r#  rD  r   rE  rH  r   switch_modelr   provider_label_pending_model_switch_noter	  ru  r;	  r  
max_outputhas_cost_dataformat_costformat_capabilitiesrt   r   warning_messager  provider_changed)
r  r   r	  	old_modelr  rN	  mir;	  ctxcache_enableds
             r0   r#	  z$HermesCLI._apply_model_switch_result  s	   ~ 	3V133444FJ	%
."("8 "("(/> 	*!>DL? 	,"ODM? 	,"ODM:!	]
''$.!'!7"N#_#_ (      ] ] ][C[[[\\\\\\\\]=9 = =&BR = =(BF,B= = = 	'  .H&2H;)9;;<<<111222
 	NNNNNN00 &?DM?R<$,<"]a]g&qgdj:RTX&Y&Y&Ymq  C  866666777 	 	 	D	 	E} EC2=CCCCDDD!! 97R^^%5%577888C)?)?)A)ACCDDD #6?#8b/JJsx[a[k[q[q[s[sOs 7"66 	  	31222! 	97v577888 	Fov/?@@@& L!"2F4JKKK9:::::DEEEEEs+   %8C 
D(D  D)A0G 
G'&G'c                    | 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_listr7   rB  rZ  c              3   z   K   | ]5\  }}|                     d                                d           k    1|V  6dS )r  Nr	  )r   r  r   r]	  s      r0   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r1   )rM	  rM   r	  r	  		raw_inputr	  r  current_base_urlcurrent_api_key	is_globalexplicit_provideruser_providerscustom_providersr^  Tr  r-   r  )r  rB   r  r&	  r  r\	  r   r  r	  r  ru  rM	  r   r"  r   r#  r  r|  Threadr$	  r  )r  r	  r  r  r	  r	  r^	  r\	  r  back_idx
cancel_idxrM	  chosen_modelr   r]	  s                 @r0   _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                 f
   ddl 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          d         }n# t          $ r g }Y nw xY w|sMt          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 |                     |          st          d           dS | j        }|j        | _        |j        | _        |j        | _        |j        | _        |j        | _        |j        r|j        | _        |j        r|j        | _        |j         r|j         | _         | j!        d	 | j!                            |j        |j        |j        |j        |j                    n*# t          $ r}t          d| d           Y d}~nd}~ww xY wd| d|j         d|j"        p|j         d| _#        |j"        p|j        }t          d|j                    t          d |            |j$        }dd!l m%}  ||j        |j        |j        p| j        pd|j        p| j        pd|| j!        rtM          | j!        d"d          nd#          }|rt          d$|d%d&           |r||j'        rt          d'|j'        d%d&           |(                                r$t          d(|)                                            t          d)|*                                            tW          |j        pdd*          rd+|j        ,                                v p
|j         d,k    }|rt          d-           |j-        rt          d.|j-                    |	rBt]          d/|j                   |j/        rt]          d0|j                   t          d1           dS t          d2           dS )3u  Handle /model command — switch model for this session.

        Supports:
          /model                              — show current model + usage hints
          /model <name>                       — switch for this session only
          /model <name> --global              — switch and persist to config.yaml
          /model <name> --provider <provider> — switch provider + model
          /model --provider <provider>        — switch to provider, auto-detect model
        r   )rM	  parse_model_flags)	get_labelNrZ  rM   )clear_provider_models_cachez+  Cleared model picker cache. Refreshing...)build_models_payloadload_picker_context)r	  r  rb	  r  zinventory context unavailabler   )
max_modelsr	  z#  No authenticated providers found.z3  /model <name>                        switch modelz6  /model --provider <slug>             switch providerz@  /model --refresh                     re-fetch live model lists)r	  r	  r`	  r/	  r!	  r0	  r2	  r3	  r4	  r5	  r6	  r7	  r8	  r9	  r:	  r<	  r=	  r?	  rU   r@	  rA	  rB	  rC	  r  rD	  rE	  rF	  rG	  rH	  rI	  rJ	  rK	  )0ru  rM	  rp	  hermes_cli.providersrq	  r  r  r   r  rr	  r  r   hermes_cli.inventoryrs	  rt	  with_overridesr   r"  r   rf	  rg	  r  r	  r#  r  rL	  r	  r	  r	  rF  rD  rE  rH  r   rN	  rO	  r	  r;	  r  rP	  rQ	  rR	  rS	  rt   r   rT	  r  rU	  )r  rn	  rM	  rp	  rq	  r   raw_argsmodel_inputre	  r	  force_refreshrr	  rs	  rt	  rX	  r	  r	  model_displayprovider_displayr	  r   rV	  r  rN	  rW	  r;	  rY	  s                              r0   _handle_model_switchzHermesCLI._handle_model_switch  s    	LKKKKKKK222222 ""4++'*5zzA~~58>>###2 IZHYZbHcHcE&
  	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DDD[Q		   			  =>>>MNNNPQQQZ[[[## %) $    F !!]0b**!]0b L.B$/%)

 

 

 ~ 	3V133444F33F;; 	/000F
 J	%
."("8 "("(/> 	*!>DL? 	,"ODM? 	,"ODM :!	]
''$.!'!7"N#_#_ (      ] ] ][C[[[\\\\\\\\]=9 = =&BR = =(BF,B= = = 	'  .H&2H;)9;;<<<111222
 JJJJJJ,,"_;;N8dl8bY]Yc"m'$*6NPT"U"U"Uim
 
 
  	42C2222333 	E} EC2=CCCCDDD!! 97R^^%5%577888C)?)?)A)ACCDDD #6?#8b/JJsx[a[k[q[q[s[sOs 7"66 	  	31222 ! 	97v577888  	Fov/?@@@& L!"2F4JKKK9:::::DEEEEEsN   'B 
BB 5C C%$C%%$E
 
EE8K: :
L!LL!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_switchNrZ  rM   u   ❌ )r  save_configu   ❌ could not load config: )persist_callback   ✓   ✗openai_runtimerR  r9  r  z3    Tip: `/reset` starts a new session immediately.)r  r	  r  r  r   
parse_argsr  rs  r  r	  r   applyr  r  r  r  requires_new_session)r  rn	  crsr   ry	  	new_valuerw  errr  r	  r  r  r   r  r  s                  r0   _handle_codex_runtimezHermesCLI._handle_codex_runtimec  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_commandNrZ  r\  r"  )	r  r  r	  r  r   r  r  r  r   r  r_   r	  r	  rA  r  s         r0   #_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).
        Frk  r   r	  NrZ  r\  r  )
r  r  r  r	  r  r   r  r  r  r   r	  s         r0   #_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  r1  r  s    r0   _output_consolezHermesCLI._output_console  s(    4&& 	!== |r1   c                 D     |                                  j        |i | dS )z.Print through the active command-safe console.N)r	  r  )r  r-   r.   s      r0   rL  zHermesCLI._console_print  s,    $$d5f55555r1   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
  rM   tonezTone: r		  zStyle: r   c              3      K   | ]}||V  	d S r   r   r   s     r0   r   z8HermesCLI._resolve_personality_prompt.<locals>.<genexpr>  r~  r1   )r   r   rB   r  r   rW   )rJ   r   s     r0   _resolve_personality_promptz%HermesCLI._resolve_personality_prompt  s     eT"" 	4YY334Eyy   85eFm55777yy!! :7uW~7799999333333335zzr1   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    → rM   u       ✓ z<12z Enabledu       ○ z Not configured (r  z  Session Reset Policy:z
    Mode: z    Daily reset at: z:00z    Idle timeout: z minutesz  To start the gateway:z    python cli.py --gatewayz  Configuration file: z/config.yamlz   Error loading gateway config: z  To configure the gateway:z!    1. Set environment variables:z$       TELEGRAM_BOT_TOKEN=your_tokenz#       DISCORD_BOT_TOKEN=your_tokenz     2. Or configure settings in N)gateway.configr	  r	  r  TELEGRAMDISCORDSLACKWHATSAPPry  	platformsrB   r   get_home_channelr  default_reset_policyr  at_houridle_minutesrn   r   )r  r	  r	  r   platform_statusr  r  r  pconfighomehome_strpolicyr   s                r0   _show_gateway_statuszHermesCLI._show_gateway_status  s   @@@@@@@@"###OPPP"###-	((**F7888/""" !#E "B <!#C	O .=-B-B-D-D L L)/4 *..x88 Lw L!228<<D6:B2ty222HATAAAxAABBBBJTJJJJJJKKKKGGG+,,,/"""0F,v{,,---<<<<===Dv':DDDEEEGGG+,,,/000GGGN+>+@+@NNNOOOGGGGG 	 	 	8Q88999GGG/000566689997888X5H5J5JXXXYYYGGGGGGGGG	s   F8H 
J+B	J&&J+c                 6  ab |                                                                 }|                                }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|                                  n1|dk    r|                                  n|dk    r|                     |           n|dk    r|                                  n|dk    r|                                  n|dk    r5|                                  t          dt           dt                      n|dk    r|                     dd|          	 d
S |                     d
           t-                       | j        rK| j        j        }
|
                                 |
                    dd           |
                                 n| j                                         | j        r|t=                      }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        |           t          d            	 dd!l1m2}  |            }	 dd"l3m4}  |            5                    d#d$          }n# tl          $ r d$}Y nw xY w|#                    d%| d&| d'           na# tl          $ r Y nTw xY w| 7                                 tG          d            	 dd!l1m2}  |            }	 dd"l3m4}  |            5                    d#d$          }n# tl          $ r d$}Y nw xY w| 8                    d%| d&| d'           n# tl          $ r Y nw xY w|d(k    r| 9                                 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,           n| j:        ?                    | j0                  ro	 | j:        @                    | j0        |          rt          d-|            nt          d.           n# t|          $ r}t          d|            Y d}~nbd}~ww xY w| j:        A                    |          }|rt          d/| d0|d1                     n!|| _B        t          d2| d3           ndd4l;mC} t          d |                        nt          d5           n| j:        rt          d6| j0                    | j:        ?                    | j0                  }|r/|D                    d)          rt          d7|d)                     nd| jB        rt          d8| jB                    nDt          d9           n3dd4l;mC} t          d |                        n|d:k    r| E                    |          sdS n|d;k    ra| F                    |          \  }}|                                pd}|                     d;d<|          	 d
S |                     |=           n|d>k    r| G                    |           nn|d?k    r| H                    |           nQ|d@k    r| I                    |           n4|dAk    r| J                    |           n|dBk    r| K                    |           n|dCk    r| L                    |           n|dDk    rB| M                                }|r*tU          | dE          r| jN        O                    |           n|dFk    rd} |                                }!t          |!          dk    rI	 t          |!d                   } n*# t|          $ r tG          dG|!d         dH           Y dS w xY w| dk     rd} | dk    rdIndJ|  dK}"|                     dF|"|          	 d
S | Q                    |            n|dLk    r| R                    |           n|dMk    r| S                                 n|dNk    r| T                    |           n|dOk    r| U                    |           nj|dPk    r| V                    |           nM|dQk    r| W                    |           n0|dRk    r| X                    |           n|dSk    rW| Y                    | Z                    |                    5  | [                    |           ddd           n# 1 swxY w Y   n|dTk    r| \                    |           n|dUk    r| ]                                 n}|dVk    r| ^                                 na|dWk    r2| j_         | __        | j_        rdXndY}#| 8                    dZ|#            n)|d[k    r| `                                 n|d\k    r| a                    |           n|d]k    r| b                                 n|d^k    r| c                    |           n|d_k    r| d                    |           n|d`k    r| e                    |           n}|dak    r| f                                 na|dbk    r| g                                 nE|dck    r| h                    |           n(|ddk    r| i                    |           n|dek    r| j                                 n|dfk    r| k                                rdS n|dgk    rddhllmm}$  |$d
i           n|djk    r| n                                 n|dkk    r| o                    |           n~|dlk    r%ddmlpmq}%  |%            }&tG          dn|& do           nS|dpk    r| r                    |           n6|dqk    rV| Y                    | Z                    |                    5  | s                                 ddd           n# 1 swxY w Y   n|drk    r| t                    |           n|dsk    r| u                    |           n|dtk    r	 ddulvmw}'mx}(my})mz}*  |'            }+ |)            }, |(            }-dv |+D             }.t          |+          t          |.          z
  }/|.sTtG          dw           tG          dx           tG          dyt                       dz           |/rtG          d{|/ d|           ni }0	 dd}l|m}}1  |1            ~                                D ]}2|2|0|2d~         <   n# tl          $ r i }0Y nw xY wtG          dt          |.           d           t          |.          D ]W\  }3}4}5}6}7}8 |*|3|,|-|8          }#dddD                    |#d          }9|4rd|4 nd}:|0D                    |3          pi };g }<|;D                    d          r|<                    |;d          d           |;D                    d          r|<                    |;d          d           |;D                    d          r|<                    |;d          d           |<rdd                    |<           dnd}=|#dk    rdnd|# d}>|;D                    d          rd|;d          nd}?tG          d|9 d|3 |: |> |= |?            Y|/rtG          d|/ d           tG          d           
n# tl          $ r}tG          d|            Y d}~
nd}~ww xY w|dk    r|                     |           
n|dk    r|                     |           
n|dk    r|                                  
ny|dk    r|                                  
n]|dk    r|                     |           
n@|dk    r|                    dd          }t          |          dk    r|d                                         nd}@|@st          d           	n| jN        O                    |@           | j        r3t          d|@dd          t          |@          dk    rdnd            	nt          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            nt          d           nx# tl          $ r}Bt          d|B            Y d}B~BnVd}B~Bww xY w| jN        O                    |@           t          d|@dd          t          |@          dk    rdnd            n|dk    r|                     |           n|dk    r|                     |           n|dk    r|                     |           n|dk    r|                     |           n|dk    r|                     |           np|                                d         }Ct                      }Dt                      }E| j        D                    di           }F|C                    d          |Fv r4|F|C                    d                   }G|GD                    d          dk    rddl}H|GD                    dd          }I|Ir	 |H                    |Id
d
d
d          }J|Jj                                        p|Jj                                        }K|Kr$| 8                    t+          |K                     n| 8                    d           n*# |Hj        $ r | 8                    d           Y ntl          $ r$}| 8                    d| d'           Y d}~nd}~ww xY w| 8                    d|C d           n|GD                    d          dk    r|GD                    dd                                          }L|Lrs|L                    d          r|Lnd|L }L|t          |C          d                                         }M|L d|M                                 }N|                     |N          S | 8                    d|C d           n| 8                    d|C d           n|C                    d          t3                      v rddl|m}Om}P  |O|C                    d                    }Q|Qr|t          |C          d                                         }M	  |P |Q|M                    }J|Jrt          t9          |J                     n&# tl          $ r$}t          d| t                      Y d}~nd}~ww xY wn|C|Ev r|t          |C          d                                         }Rt;          |C|R| j0                  }S|Sr|S\  }T}U}V|E|C         }WtG          d|Wd~          dt          |U           d           |Vr8t=                      #                    dd                    |V           d'           tU          | dE          r| jN        O                    |T           nt=                      #                    d|C d'           n|C|Dv r|t          |C          d                                         }Rt=          |C|R| j0                  }T|TrL|D|C         d~         }XtG          d|X            tU          | dE          r| jN        O                    |T           nTt=                      #                    d|C d'           n-ddlm}Y |                                d         btA          |Y          tA          |D          z  tA          |E          z  }ZbfdǄ|ZD             }[t          |[          dk    rabfdȄ|[D             }\t          |\          dk    r|\}[n=tC          dɄ |[D                       aafdʄ|[D             }]t          |]          dk    r|]}[t          |[          dk    r|[d         }^|^bk    r@t          d| t                      t          t           tD           dt                      n|                                t          b          d         }_|^|_z   }`|                     |`          S t          |[          dk    rct          tD           d| t                      t          t           dd                    t          |[                     dt                      n?t          d| t                      t          t           tD           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\  >   r   r  N>   exitquitrZ  rM   >   -d--deleteTrR  u   ✗ Unknown argument: z4. Use /exit --delete to also remove session history.Fhelpprofilerl  r  r   redrawu   ✓ UI redrawnr  zdThis clears the screen and starts a new session.
The current conversation history will be discarded.)rn	  )rK  r  ri  r6  r   r!  rk  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  r   r  r"  zcodex-runtimegquotapersonalityretryrm  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kanbanr  memoryr	  r  	statusbarr,	  hiddenz  Status bar r	  footeryolorz   r   compressusagecreditsinsightscopyr  rv  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     r0   r   z-HermesCLI.process_command.<locals>.<listcomp>W  s&    HHHaadi6G6G6G6G6Gr1   zNo user plugins installed.z0  Install one: hermes plugins install owner/repoz"  Or drop a plugin directory into z	/plugins/rS  u8    bundled plugins available — see: hermes plugins list)get_plugin_managerr  zUser plugins (z):r  r	  r	  )r   disabledu   ○z vr  hooksz hooksr  z	 commandsr  r  r  r   r  r>  r  r  r9  z  (+u&    bundled — see: hermes plugins list)z6  Enable/disable: hermes plugins enable/disable <name>zPlugin system error: rollbackr(  stopagents
backgroundr  z  Usage: /queue <prompt>  Queued for the next turn: r;  z
  Queued: r  z  Usage: /steer <prompt>u9     ⏩ Steer queued — arrives after the next tool call: z!  Steer rejected (empty payload).z  Steer failed: z)  No agent running; queued as next turn: goalsubgoalr  voicebusyr  r   execr8  r}  )shellri  r_   r   z"[dim]Command returned no output[/]z*[bold red]Quick command timed out (30s)[/]z[bold red]Quick command error: z[bold red]Quick command 'z' has no command defined[/]aliasr  z' has no target defined[/]z6' has unsupported type (supported: 'exec', 'alias')[/])get_plugin_command_handlerresolve_plugin_command_resultz[1;31mPlugin command error: r>  u   
⚡ Loading bundle: z skills)z [yellow]Skipped missing skills: z$[bold red]Failed to load bundle for u   
⚡ Loading skill: z#[bold red]Failed to load skill for )COMMANDSc                 >    g | ]}|                               |S r   r  r   r  
typed_bases     r0   r   z-HermesCLI.process_command.<locals>.<listcomp>  s*    LLL1<<
3K3KL1LLLr1   c                      g | ]
}|k    |S r   r   r	  s     r0   r   z-HermesCLI.process_command.<locals>.<listcomp>"  s    CCC11
??Q???r1   c              3   4   K   | ]}t          |          V  d S r   r  r  s     r0   r   z,HermesCLI.process_command.<locals>.<genexpr>(  s(      %>%>c!ff%>%>%>%>%>%>r1   c                 :    g | ]}t          |          k    |S r   r  )r   r  min_lens     r0   r   z-HermesCLI.process_command.<locals>.<listcomp>)  s)    #L#L#L!#a&&G:K:KA:K:K:Kr1   z[1;31mUnknown command: z!Type /help for available commandszAmbiguous command: zDid you mean: r  )r   r   r  r	  r  r  r  r  r  rq  r  r  r  r  r  _handle_profile_command_handle_tools_commandr  r  r  _confirm_destructive_slashr2  r  r^  r  r  r  rT  r1  r  r  r  r  r  r  r  r  r  rK  r   r   rw  r*  r   r!  r  r  r"  r  hermes_cli.tipsr	  rp  r  rq  r   rx  rL  r.  re  rf  r/  rH  r  r  rI  get_session_by_titlerg  r	  rB   _handle_handoff_command_split_destructive_skiprP  _handle_sessions_commandr~	  r	  _handle_gquota_command_handle_personality_commandr_  rm  r  rC   ry  _handle_branch_commandr[  _handle_cron_command_handle_suggestions_command_handle_blueprint_command_handle_curator_command_handle_kanban_commandrC  r<  _handle_skills_command_handle_memory_commandr	  r  r  _toggle_verbose_handle_footer_command_toggle_yolo_handle_reasoning_command_handle_fast_command_manual_compress_show_usage_show_credits_show_insights_handle_copy_command_handle_debug_command_handle_update_commandr  r	  _handle_paste_command_handle_image_commandrs  r	  _confirm_and_reload_mcp_reload_skills_handle_bundles_command_handle_browser_commandhermes_cli.plugins_cmdr	  r	  r	  r	  rn   r  r	  list_pluginsr  r  r   _handle_rollback_command_handle_snapshot_command_handle_stop_command_handle_agents_command_handle_background_commandrk  r  _handle_goal_command_handle_subgoal_command_handle_skin_command_handle_voice_command_handle_busy_commandr  r  r   rj  rk  rP  r  r  TimeoutExpiredr  process_commandr  r	  r	  rW   r  r  r	  r  r  r/  )cr  r8  r;  rn	  _resolve_cmd
_base_word_cmd_defr  _restr  r  ccterm_wrl  r   rv  r	  _tipr  
_tip_colorr   	raw_titler/  	new_titler   r  r	  r  	_new_argsr8  r  	retry_msg_undo_n_undo_parts
_undo_descr  r	  r	  r  r	  r	  r	  r	  entriesr   r	  user_entriesbundled_countloadedr	  r   r  r	  _descr  _dirr  glyphverr  r.  r  re  r  r  acceptedr  base_cmdr  skill_bundlesr  r  rj  exec_cmdr   r  r  	user_argsaliased_commandr	  r	  plugin_handleruser_instructionbundle_resultr  loaded_namesmissingbundle_info
skill_namer	  	all_knownmatchesexactshortest	full_namer  full_cmdr
  r 
  sc                                                                                                    @@r0   r6
  zHermesCLI.process_command  s"    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 / ]]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(""''5555-'',,\::::'!!))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: : : : : : : : : : : : : : :(""''5555+%%%%''''(""%%''''+%%+/+C'CD$!%!9GIIxE 7 7 78888)##  """"(""''5555&  +%%**<8888&  %%l3333*$$!!,////'!!)##    *$$----&  %%l3333'!!&&(((((""**,, 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&  %%''''(""'')))),&&++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)##((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 &0^^ (T%)2 &4 & &F &,]%8%8%:%:%Sfm>Q>Q>S>SF% Z $ 3 34H4P4P Q Q Q Q $ 3 34X Y Y Y)8 ^ ^ ^ //0\]]]]]( Z Z Z //0XRS0X0X0XYYYYYYYYZ ++,m,m,m,mnnnnXXf%%00!XXh3399;;F n+1+<+<S+A+A!S|6||$0X$@$F$F$H$H	-3*A*Ai*A*A*G*G*I*I#33ODDD++,l,l,l,lmmmm''  )EH  )E  )E  )E  F  F  F  F%%)F)H)HHH        "<!;HOOC<P<P!Q!Q! 	N ,S]]^^ < B B D DIN!>!>*N955" " " 1#CKK000$ N N N L1 Ld L LMMMMMMMMN	N ]**#/H#?#E#E#G#G  ?.! ! ! ! 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    ^++#/H#?#E#E#G#G 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  3P $O) (P )O85P 7O88P 
P'&P'R4 $R R4 RR4 RR4 4
SS8U 
U<U77U<2AW6 6
X XXd+ +#eej77j;>j;2vvv"B-AB 0{  AB {AB {F/AB B
AB(BAB#B#AB(J"AL L
AL)LAL$L$AL)SBAU UAVU2	AVU;AVVAV\3A] ]
A^]A]=]=A^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).
        )rr   )ra
  rb
  s     r0   _try_launch_chrome_debugz"HermesCLI._try_launch_chrome_debugD  s     'tV444r1   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  rM   _goal_managergoalsr  r  )r  default_max_turns)hermes_cli.goalsrf
  rs  r  r   loggingr  r  rB   rC   rg
  )
r  rf
  r  r  sidr  r  	goals_cfgr  mgrs
             r0   _get_goal_managerzHermesCLI._get_goal_managerT  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                    |                                  }||                                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          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``.
        Nrm  Fr   Tro  zuser-interrupted (Ctrl+C)r6  z"goal pause-on-interrupt failed: %srR  u_   ⏸ Goal paused — turn was interrupted. Use /goal resume to continue, or /goal clear to stop.rM   r&  r(  r   c                     g | ]D}t          |t                    r-|                    d           dv .|                    dd          ES )r   >   r_   output_textr_   rM   r|  r   s     r0   r   z=HermesCLI._maybe_continue_goal_after_turn.<locals>.<listcomp>  sZ     ! ! ! !)!T22! 89uuV}}H_7_7_ EE&"--7_7_7_r1   r   c              3      K   | ]}||V  	d S r   r   r  s     r0   r   z<HermesCLI._maybe_continue_goal_after_turn.<locals>.<genexpr>  s'      1H1Ha1H!1H1H1H1H1H1Hr1   )user_initiatedr  should_continuecontinuation_promptz$goal continuation enqueue failed: %s)ro
  	is_activer  emptyr   r  r   r  rW   r  r   pauserk
  r  r  r  r  r_  r,  rB   r   r   evaluate_after_turnrm  r  )r  rn
  r  has_real_messager  r  last_responsehistr  r   r   decisionprompts                r0   _maybe_continue_goal_after_turnz)HermesCLI._maybe_continue_goal_after_turnw  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**=*NNll9%%+ 	 JJJ<<)** 	O\\"788F OO'++F33333  O O OM"H#NNNNNNNNNO	O 	OO Osy   )C AB6 5C 6CC CC 
CC/D 
D/D**D/BG5 5HHJ( (
K2KK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	  r  r	  r[  rZ  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.rM   N)rU  r3  r  r  r   r  reasoning_callbackhermes_cli.colorsr
  DIMRESETYELLOWGREENBOLDr  rB   )r  cycler*  _Colorslabelss        r0   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rL  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  rL  r
  r
  r
  r
  s         r0   _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       r0   ru  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  r  r
  REDr
  r
  )r  r
  r
  r
  r
  r
  s         r0   r
  zHermesCLI._toggle_yoloH  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    r1   c                 l    |sdS t          | dd          |z   | _        |                     d           dS )zCCallback for intermediate reasoning display during tool-call loops.Nr<  rM   Fr  )r  r<  r  )r  r  s     r0   r  zHermesCLI._on_reasoningp  sG     	F&-d4Lb&Q&QTb&b#%%E%22222r1   rM   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} d}|rU|	                                
                    dd	          }t          |          d	k    r|d	         	                                } ||          \  }}}	|	pd}	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)# t,          $ r}t          d'|            Y d}~nd}~ww xY wddd           dS # 1 swxY w Y   dS )(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.
        r  zE(._.) Not enough conversation to compress (need at least 4 messages).N.(._.) No active agent -- send a message first.z((._.) Compression is disabled in config.r   )parse_partial_compress_argsrejoin_compressed_head_and_tail"split_history_for_partial_compressrM   rZ  zCompressing context...)estimate_request_tokens_rough)summarize_manual_compressionF_cached_system_promptrl  )r
  rl  u-   🗜️  Summarizing up to here: compressing z of z messages (~rU   z tokens), keeping last z exchange(s) verbatim...u   🗜️  Compressing z tokens), focus: "z"...z tokens)...T)approx_tokensfocus_topicr  r  noopu   🗜️u   ✅rR  r9  headlinez     
token_liner  u     ❌ Compression failed: )r_  r  r  r   compression_enabledhermes_cli.partial_compressr
  r
  r
  r   r  rC  rt  r
  !agent.manual_compression_feedbackr
  r   r  _compress_contextr  rg  _flush_messages_to_session_dbr   )r  rn	  r
  r
  r
  ry	  _partspartial	keep_lastr
  original_countr
  r
  original_historyr  r  _sys_prompt_toolsr
  
compressedr8  
new_tokenssummaryiconr   s                            r0   r
  zHermesCLI._manual_compressw  sF   $ ( 	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??,,*E*Eh*O*O'K!'R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=   L;G=LL;
L+L&!L;&L++L;;L?L?c           
         | 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}t          |d	d          pd}t          |d
d          pd}	|j	        }
|j
        }|j        }|j        }|j        }|j        }|rt          d||z  dz            nd}|j        }t#          | j                  }t'          |j        t+          ||||          t          |dd          t          |dd                    }t-          t/          j                    | j        z
                                            }t          d           t          dd            t          d|j                    t          d|d           t          d|d           t          d|d           t          d|d           |	rt          d|	d           t          d|
d           t          d|d           t          d|d           t          d|d           t          d|d           t          d |j        d           t          d!|j        d           |j        8|j        d"k    rd#nd$}t          d%| d&t=          |j                  d'           n2|j        d(k    rt          d%d(d           nt          d%d)d           t          dd            t          d*|d+d,|d+d-|d.d/           t          d0|            t          d1|            |j        d2k    rt          d3|j                    t          |dd          pt          | dd          }t          |dd          pt          | dd          }t          |d4d          pt          | d4d          }dd5lm }m!} d}|rtD          j#        $                    d67          5 }	 |%                    ||||8          &                    d9:          }n## tD          j#        j'        tP          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)        rhtU          j+                    ,                    tT          j-                   d<D ]3}tU          j+        |          ,                    tT          j.                   4dS tU          j+                    ,                    tT          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  r  r  session_reasoning_tokensrR   )input_tokensoutput_tokenscache_read_tokenscache_write_tokensr   r   )r   r   u     📊 Session Token UsagerR  r  z  Model:                     z  Input tokens:              z>10,z  Cache read tokens:         z  Cache write tokens:        z  Output tokens:             u     ↳ Reasoning (subset):      z  Prompt tokens (total):     z  Completion tokens:         z  Total tokens:              z  API calls:                 z  Session duration:          z>10z  Cost status:              z  Cost source:              	estimatedr'  rM   z  Total cost:              $z>10.4fincludedzn/az  Current context:  rU   z / r  r9   z%)z  Messages:         z  Compressions:     r  z(  Note:             Pricing unknown for r#  )fetch_account_usagerender_account_usage_linesrZ  )max_workers)r   r#  g      $@r  c                     g | ]}d | S )rR  r   r  s     r0   r   z)HermesCLI._show_usage.<locals>.<listcomp>w   s    ^^^d^^^r1   )openair  httpxhttpcorer  hpackgrpcmodal)0r   _print_nous_credits_blockr  r  get_rate_limit_statehas_dataagent.rate_limit_trackerr
  r  r  r  r  r!  r"  r  r  r#  r  r_  r3   r"  r+   rH   r   r  r`  r$  r  r  
amount_usdrA   agent.account_usager
  r
  
concurrentfuturesThreadPoolExecutorsubmitr   TimeoutErrorr   r	  rk
  	getLoggersetLevelDEBUGWARNINGINFO) r  r   r*  rl_stater
  r
  r
  r
  r
  reasoning_tokensr
  
completiontotalr*  last_promptrv  pctr  rx  cost_resultr  r  r   r   r#  r
  r
  account_snapshot_poolaccount_linesr  noisys                                    r0   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#E+FJJOa$U,H!LLQPQ"5*DaHHMA,4
*-
 3+9@Gc#g-3555a!3122	)K)+"3#5	   UJ55UJ55

 

 

 *8<>>D<N+N*]*]*_*_``*+++:   ;ek;;<<<AlAAABBBF.?FFFGGGG.@GGGHHHBmBBBCCC 	MK4DKKKLLL;f;;;<<<?j???@@@:e:::;;;:e:::;;;;g;;;<<<E[-?EEEFFFE[-?EEEFFF!-'.+==SS2F___{?U9V9V___````:--@
@@@AAAA;;;;<<<:   O[OOOwOOOCOOOOPPP0Y001113\33444**JU[JJKKK 5*d33VwtZQU7V7V5*d33VwtZQU7V7V%D11SWT9d5S5SWWWWWWWW 	,#6616EE ,,',||+X!)7 (4 ( ( fTf** %$ #*7C , , ,'+$$$,, , , , , , , , , , , , , , , _^1K1KL\1]1]^^^ 	GGG%  d 	&&(((< 	7((777t C C!%((11'/BBBBC C ((66666s6   S:-S
S:S+(S:*S++S::S>S>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_linesFrR  T)r
  r
  r  )r  r
  r  r  s       r0   r
  z#HermesCLI._print_nous_credits_block   se     	;:::::""$$ 	5 	 	D+t++tr1   c                    ddl m}  |            }|j        s>t                       t          dt           dt
                      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_viewu     💳 zNot logged into Nous Portal.z/  Run `hermes portal` to log in, then /credits.Nu     💳 Nous creditsrR  u{   ─────────────────────────────────────────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)r  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: u#     🟡 Cancelled. No credits added.)r
  r
  	logged_inr  r  r  balance_linesr  r  identity_line	topup_urlr  r  r  
webbrowserr   r   r  )	r  r
  viewr  r  r   r  openedr
  s	            r0   r
  zHermesCLI._show_credits   s    	;:::::!!##~ 	GGGDDDDdDDEEE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	/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}  NrZ  z--daysz  Invalid --days value: r[  z--sourcer   r.  )InsightsEngine)rG   r  z  Error generating insights: )r  r  rC   r  r  rO  rf  r/  agent.insightsr
  generateformat_terminalcloser   )r  r8  r   rG   r  r  r/  r
  dbr   reportr   s               r0   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           |
                                rt!          d           dS dS )ax  Detect mcp_servers changes in config.yaml and auto-reload MCP connections.

        Called from process_loop every CONFIG_WATCH_INTERVAL seconds.
        Compares config.yaml mtime + mcp_servers section against the last
        known state.  When a change is detected, triggers _reload_mcp() and
        informs the user so they know the tool list has been refreshed.
        r   Nr  get_config_pathr   r   r  u;   🔄 MCP server config changed — reloading connections...Tr  r  r}  r  uL     ⚠️  MCP reload timed out (30s). Some servers may not have reconnected.)rt  r  r:  _last_config_checkrs  r  r   r  r  r  _config_mtimer   ru  r   rB   _config_mcp_serversr  r|  ri	  _reload_mcpr  r   is_alive)r  _yamlCONFIG_WATCH_INTERVALr  _get_config_pathcfg_pathr  r   new_cfgnew_mcp_reload_threads              r0   _check_config_mcp_changesz#HermesCLI._check_config_mcp_changes!  sC    	 #n((+@@@F"%IIIIII##%%   	F	MMOO,EE 	 	 	FF	 D&&&F #	h111 3Q//!,,23 3 3 3 3 3 3 3 3 3 3 3 3 3 3 	 	 	FF	 ++m,,2d...F#*  	KLLL")#D
 
 
 	B'''""$$ 	b`aaaaa	b 	bsH   A2 2
B ?B C )CC CC CC 
C'&C'>   -y--yesr  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)
        )rM   Fr   r\  rZ  NFTr9  )r   r  r  r   _DESTRUCTIVE_SKIP_TOKENSr  r   )r  r  tokensskipkepttoks         r0   r
  z!HermesCLI._split_destructive_skipX!  s      	9!!'')) 	9!9$$ 	 ABBZF 	 	Cyy{{c:::KKxx~~t##r1   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)r  r	  zkeep current conversationu	   ⚠️  /u     — destroys conversation stater
  u   🟡 /z cancelled (no input).   🟡 Unrecognized choice 'z'. /z cancelled.r  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   rB   r  r   r  r  r  r  )r  r8  r  rn	  r8  _skipr  r  confirm_requiredr  r   r  s               r0   r
  z$HermesCLI._confirm_destructive_slashw!  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)r  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.r  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   rB   r  r   rC  r<  r  r  r  r  r  )r  rn	  r  r  r   r  r   r  s           r0   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                 t   	 ddl m}m}m}m} |5  t          |                                          }ddd           n# 1 swxY w Y   | j        st          d            |              |            }|5  t          |                                          }ddd           n# 1 swxY w Y   ||z
  }||z
  }	||z  }
|
r2t          dd	                    t          |
                                |r2t          dd	                    t          |                                |	r2t          dd	                    t          |	                                |st          d	           n0t          d
t          |           dt          |           d           | j        vt          t          | j        d          r| j        j        ndd          | j        _        | j        j        rd | j        j        D             nt                      | j        _        g }|r8|                    dd	                    t          |                                |	r8|                    dd	                    t          |	                                |
r8|                    dd	                    t          |
                                |rt          |           dnd}|rd	                    |          dz   nd}| j                            dd| | dd           | j        7	 | j                            | j        | j                   n# t*          $ r Y nw xY wt          dt          | j        r| j        j        ng            d           dS # t*          $ r}t          d|            Y d}~dS d}~ww xY w)zReload MCP servers: disconnect all, re-read config.yaml, reconnect.

        After reconnecting, refreshes the agent's tool list so the model
        sees the updated tools on the next turn.
        r   )r  discover_mcp_tools_servers_lockNu   🔄 Reloading MCP servers...u     ♻️  Reconnected: r  u     ➕ Added: u     ➖ Removed: z  No MCP servers connected.u     🔧 z tool(s) available from z
 server(s)rK  Tri  c                 *    h | ]}|d          d         S )r  r  r   )r   r  s     r0   r  z(HermesCLI._reload_mcp.<locals>.<setcomp>A"  s/     / / /15D$V,/ / /r1   zAdded servers: zRemoved servers: zReconnected servers: z MCP tool(s) now availablezNo MCP tools availabler  rM   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: )r$  r  r$  r%  r&  r  r  r  r  r   r  r  r   r  r*  rK  rl  valid_tool_namesr  r_  _persist_sessionr   )r  r  r$  r%  r&  old_servers	new_toolsconnected_serversaddedremovedreconnectedchange_partstool_summarychange_detailr   s                  r0   r  zHermesCLI._reload_mcp"  s   M	3````````````  3 3!(--//223 3 3 3 3 3 3 3 3 3 3 3 3 3 3 ( 75666 ! """ +*,,I  9 9$'$8$8!9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 &3E!$55G+k9K RP		&:M:M0N0NPPQQQ B@diiu&>&>@@AAA FD		&//(B(BDDEEE$ l34444jIjjL]H^H^jjjkkk z%#7tz+=>>&ITZ%@%@DH#$ $ $
  Z%/1 / /9=9I/ / / /+.55 
+ L R##$Pdiiu6N6N$P$PQQQ V##$T		&//8R8R$T$TUUU ^##$\DIIf[FYFY<Z<Z$\$\]]]LUsc)nnHHHH[sL>JRDIIl33d::PRM%,, l-  lYe  l  l  l. .    z%J//11    !   D lSTZ1W1A1AUW-X-Xlllmmmmm 	3 	3 	31a11222222222	3s   N ">N AN A/N 5"B#N #B''N *B'+I9N %%M 
N 
MN M6N 
N7N22N7c                 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_skillsr  u   🔄 Reloading skills...r.  r/  r
  z  No new skills detected.u     📚 z skill(s) availableNr  r|   c                 x    |                      dd          }|                      dd          }|rd| d| nd| S )Nr  rM   r  z    - r|  r	  )r  nmr  s      r0   	_fmt_linez+HermesCLI._reload_skills.<locals>._fmt_line"  sO    XXfb))xxr2204G,,,d,,,-2--Gr1   u     ➕ Added Skills:rR  u     ➖ Removed Skills:z[USER INITIATED SKILLS RELOAD:rM   zAdded Skills:zRemoved Skills:z,Use skills_list to see the updated catalog.]r   u     ❌ Skills reload failed: )r  r5  r  r  r  r  rB   r   rW   r  r   _pending_skills_reload_noter   )r  r5  r  r   r.  r/  r
  r8  r  sectionsr   s              r0   r&
  zHermesCLI._reload_skillsf"  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>  r  )r  r;  r>  r   s       r0   _on_tool_gen_startzHermesCLI._on_tool_gen_start"  s     4-u55 	,   &+D#!!###000000y%8889999999:::::r1   function_namer  function_argsc                 ~   |dk    rd| _         |r| j        dv r|                    dd          }|                    dd          }| j                            |          }|r|                    d          ni }	|
|s| j        |= | j        d	k    r!|| j        k    r|                                  dS || _        	 dd
lm}
  |
||	||                    d                    }t          d|            n# t          $ r Y nw xY w	 t          | dd          s| j        dk    r|dk    rddlm}m}m}m}  |t"          |          sud| _        t          dt&            |             t(                       |t*          dz  |           dt"                              di                               di           |<   n# t          $ r Y nw xY w|                                  dS |dk    rdS |r|                    d          sddlm}  ||          }|p|}ddlm}  |            }|dk    r#t5          |          |k    r|d|dz
           dz   }| d| | _        t9          j                    | _         | j                            |g                               ||ni            |                                  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tool.completedr7   >   r  r	  r  is_errorFr   Nr	  )get_cute_tool_messager   )r   rR  _long_tool_hint_firedr  g      >@)TOOL_PROGRESS_FLAGis_seen	mark_seentool_progress_hint_cliTr   r1  r(  ztool.startedr8  r=  )get_tool_preview_max_lenr  r;  r9  )r  r3  rB   r  rx  r  r  r@  rF  r  r   r  agent.onboardingrH  rI  rJ  rK  r2  rG  r  r  r   
setdefaultr  r>  rL  r  r  r  r:  r  )r  r/  rB  r  rC  r.   r  rE  storedstored_argsrF  r  rH  rI  rJ  rK  r>  r   re  rL  _pls                        r0   _on_tool_progresszHermesCLI._on_tool_progress"  s    )))$'D! +!8N!J!J!::j#66!::j%88044]CC/5=fjjmmm2%f%/>*e33Ic8c8c$$&&&F-:*CCCCCC00X^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!.!:   	 	 	 	s%   ;:C6 6
DDB4F< <
G	G	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@  rU  r?  r   r   r  )r  rS  rB  rC  rU  r(  s         r0   _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                     | j                             |d          }	 ddlm}  |||||t                     dS # t
          $ r! t                              d|d           Y dS w xY w)zFRender file edits with inline diff after write-capable tools complete.Nr   )render_edit_diff_with_delta)rC  r(  print_fnzEdit diff preview failed for %sTr	  )r?  rx  r@  rY  r  r   r   r  )r  rS  rB  rC  rW  r(  rY  s          r0   _on_tool_completezHermesCLI._on_tool_complete)#  s    /33L$GG	ZAAAAAA''+!        	Z 	Z 	ZLL:MTXLYYYYYY	Zs   : 'A%$A%c                     t           dd          rdS ddlm}m}  |            }|d         sct	                      r8|                    dd          }d	|v rt          d
          t          d          t          dt          j         d          |                    d|                    d                    st          d           j	        5   j
        r	 ddd           dS d _
        ddd           n# 1 swxY w Y   i }	 ddlm}  |                                d          }t          |t                    r|ni }n# t          $ r Y nw xY w j         |             _        |                    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.rp  FNr   )create_audio_recordercheck_voice_requirementsaudio_availabledetailsrM   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  r  r  r  r*  r^  r  _voice_stop_and_transcriber  s   r0   _on_silencez5HermesCLI._voice_start_recording.<locals>._on_silence#  s   !  ,                       GGGGGHHHtV$$ ' '	$$&&&++-----s   	,00	play_beepip  rZ  	frequencyr  )on_silence_stopsupports_silence_autostopzauto-stops on silence | z to stop & exit continuouszTermux:API capture | z to stopr   u   ● Recording...r9  (r  c                      	 j         5  j        } d d d            n# 1 swxY w Y   | sd S t          d          r j        rj                                         t          j        d           o)NTr^  333333?)r  r  r*  r^  r  r  sleep)still_recordingr  s    r0   _refresh_levelz8HermesCLI._voice_start_recording.<locals>._refresh_level#  s    !% < <&*&;O< < < < < < < < < < < < < < <& E4(( +TY +I((***
4   !s   ""r  ) r  tools.voice_moder]  r^  r  rB   r  rO  
executabler  r  rs  r  r   r   r   r  rC   rA   r  _silence_threshold_silence_duration_voice_beeps_enabledri  r  r\  r  r/  r  r  r|  ri	  )r  r]  r^  reqsr`  	voice_cfgr  _cfg
_threshold	_durationrg  ri  _label_recording_hintrs  s   `              r0   _voice_start_recordingz HermesCLI._voice_start_recording=#  s   4// 	FTTTTTTTT''))%& 	%'' ((9b11<GG&l  
 #h  
 S!$S S S   xx-)@)@AA 	>    	) 	)$ 	) 	) 	) 	) 	) 	) 	) 	) %)D!	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 		555555;==$$W--D *4 6 6>BII 	 	 	D	 '#8#8#:#:D  ]]#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Dsl   	C:'C::C>C><E 
EE-I 
III. .J ?JJ J	J J	J 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   rZ  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  r*  r^  r  r   r  r  r  )r   r  s    r0   _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  rh  i  r[  rj  zNo speech detected.zTranscribing...r  sttr"  )transcribe_recording)r"  r  
transcriptrM   r  Unknown errorr   zTranscription failed: zVoice processing error: )"r  r  r  r  r*  r^  r  r   r   isfiler  r  r  unlinkr   r  r  r  r|  ri	  r  r	  rx  rt  ri  rs  r  rB   r  r   r  r  rm  r  )r  	submittedtranscription_failedwav_pathr  ri  	stt_modelr  
stt_configr  r   r  r  r   s   `             r0   rf  z$HermesCLI._voice_stop_and_transcribe#  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.NTrh	  )r  r  r  r|  ri	  _voice_speak_responser  r  s     r0   _voice_speak_response_asyncz%HermesCLI._voice_speak_response_async$  sa     	d 	F""$$$-	
 	
 	
 %'''''r1   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]*?```r9  z\[([^\]]+)\]\([^)]+\)r  zhttps?://\S+rM   z\*\*(.+?)\*\*z	\*(.+?)\*z`(.+?)`z^#+\s*r   z^\s*[-*]\s+z---+r  r  hermes_voiceT)ry  tts_r0  z.mp3)r_   output_pathrS   rZ  z.oggzVoice TTS playback failed: %szTTS playback failed: ) r  r  r  tools.tts_toolr  rt  r  r  r   r   r  r   r  r   makedirsr   r   tempfile
gettempdirr  rh  r  getsizer  rsplitr  r   r   r   r  r  r  )r  r_   r  r  tts_textmp3_pathogg_pathr   s           r0   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)rs  r  rB   r   r   r  r   )r  r  rz  s      r0   rx  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:warningsrR  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 r9  Tr  r	  auto_ttsFz (TTS enabled)rM   zVoice mode enabledz to start/stop recordingz#/voice tts  to toggle speech outputz!/voice off  to disable voice mode)r  r  r  r  rt  r^  r  r/  r  r  r  rO  ru  r   r  rs  r  rB   r   r   r  r   r\  )r  r^  r  	env_checkr   ry  r  r  
_raw_voicevoice_config
tts_status_ptt_displays               r0   _enable_voice_modezHermesCLI._enable_voice_modei$  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    r0   _bg_shutdownz3HermesCLI._disable_voice_mode.<locals>._bg_shutdown$  s:    LLNNNNN    DDs    
&&Tr  r   stop_playbackr   zVoice mode disabled.)r  r  r  r  r  r  r  r|  ri	  r  rt  r  r   r  r  r  r  r  )r  recorderr  r  s       r0   _disable_voice_modezHermesCLI._disable_voice_mode$  s    	+ 	+$ .)= .$++---(-%+H$D#DO%*D"	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ !)    
 L>>>DDFFF#'D 	666666MOOOO 	 	 	D	  """5T55t5566666s$   AA!!A%(A%#B4 4
C Cc                 n   | j         s t          t           dt                      dS | j        5  | j         | _        ddd           n# 1 swxY w Y   | j        rdnd}| j        r.ddlm}  |            st          t           dt                      t          t           d| d	t                      dS )
z!Toggle TTS output for voice mode.z"Enable voice mode first: /voice onNr   r	  r   )check_tts_requirementszEWarning: No TTS provider available. Install edge-tts or set API keys.z
Voice TTS rS   )	r  r  r  r  r  r  r  r  r/  )r  r  r  s      r0   _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`  r  N)
rt  r^  r  r  r  r  r  r  r\  r  )r  r^  ry  r  s       r0   _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""""	# 	#r1   r
  re  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.
        r,  r  TNr9  r   w   r?  r   r|  r	  )r2  rB   r   r  r  r  r  r  )r  r
  re  r  r  s        r0   _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Hr1   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   Nr-  r   r   )questionr  r  r  TrZ  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  r2  rB   r  rl  rt  r:  rv  ru  r  r  rW   r  r  r  r  )r  r  r  r  r   r  is_open_endedr  r   r^  r  s              r0   _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  TrZ  r  r   u,     ✓ Password received (cached for session)u     ⏭ Skippedu)     ⏱ Timeout — continuing without sudorM   )r  r  rl  r  rw  r:  rx  r  rB   r  r  r  r  r  )r  r  r   r  r   r^  s         r0   rP  z!HermesCLI._sudo_password_callback9%  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  r  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   r8   r  )r8  r  r  r  r  TrZ  r  zallowed oncezallowed for sessionzadded to allowlistdeniedr  r  r  deny   ⚠Approvalr-  r   u!     ⏱ Timeout — denying commandr  )r  r~  rC   r2  rB   r  rl  _approval_choicesrz  r:  r{  r  r  rW   r  r  r  r  )r  r8  r  r  r  r   r  r  r   _outcome_labelsr^  r  s               r0   rQ  zHermesCLI._approval_callbacki%  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.r  )r  r  r  F   r
  )r  r  )r  r8  r  r  s       r0   r  zHermesCLI._approval_choices%  sG    ;Jk7777PkPkPkw<<"NN6"""r1   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`?)r8  r  approve_onceapprove_sessionalways_approver  r  )rQ  rB   )r  r  r-   r
  verdicts        r0   rT  z)HermesCLI._computer_use_approval_callback%  se     )).W..D&DDD * 
 

 #(&	
 

 #gv

	r1   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     r0   r   z8HermesCLI._handle_approval_selection.<locals>.<listcomp>%  s"    QQQ6&@P@P@P@P@Pr1   rZ  r  )rz  rB   r   r   r  r  r  r  )r  r  r  r  chosens        r0   _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+++#r1   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.
        .   rm  r  r  r  r1  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     r0   r   zWHermesCLI._get_approval_display_fragments.<locals>._panel_box_width.<locals>.<listcomp>%  r  r1   r  r[  r<   r  r  r  s          r0   r  zCHermesCLI._get_approval_display_fragments.<locals>._panel_box_width%  r  r1   rM   r_   r7  r  c                 Z    t          j        | t          d|          dd|          }|pdgS r  r  r  s       r0   r  zCHermesCLI._get_approval_display_fragments.<locals>._wrap_panel_text%  r  r1   r  r  r  Nc                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S r  r  r  s         r0   r  zEHermesCLI._get_approval_display_fragments.<locals>._append_panel_line&  r  r1   c                 F    |                      |dd|z  z   dz   f           d S r  r  r  s      r0   r  zKHermesCLI._get_approval_display_fragments.<locals>._append_blank_panel_line	&  r  r1   r8  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  r  r
  r8      ❯ rR  r  rt  r[  r
  r  r  u   … (choose Show full command)	   rZ  rT   r9  r  r  r  rh  r  u=   … (command truncated — use /logs or /debug for full text)rQ   u   … (description truncated)r  r  r  r  r  r  r  r  r  r5  r  r  rm  ro  )rz  rW   r   rC   rB   r  r  r  r  r  r  r  r  r  ))r  r  r  r  r  r  r8  r  r  r  r  r  cmd_displaychoice_labelsr  r  r  r  r  r	  cmd_wrappedr	  re  
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)                                            r0   _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r1   var_namer
  c                 &    t          | |||          S r   r  )r  r  r
  metadatas       r0   rR  z"HermesCLI._secret_capture_callback&  s     xBBBr1   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^  )r_   rF  )ry  r  r^  rE  r_   rF  r  r   )r  rA  s     r0   r  z'HermesCLI._capture_modal_input_snapshot&  s    %1vt9T9T1F	.)*C#&#6* *D& IIKKKKK 	. 	. 	.)-D&&&&	.s   4A A'&A'c                 4   | j         }d| _         |rt          | dd          sdS 	 | j        j        }|                    dd          |_        t          |                    dd          t          |j                            |_        dS # t          $ r Y dS w xY w)zERestore any draft text that was present before a modal prompt opened.Nr^  r_   rM   rF  r   )
ry  r  r^  rE  rB   r_   r  r  rF  r   )r  r(  rA  s      r0   r  z'HermesCLI._restore_modal_input_snapshot&  s    -%)" 	wtVT:: 	F	)*C||FB//CH"%hll3Da&H&H#ch--"X"XC 	 	 	DD	s   A"B	 	
BBc                     | j         sd S | j         d                             |           d | _         d| _        |                                  d S r  )r  r  r  r  )r  rJ   s     r0   _submit_secret_responsez!HermesCLI._submit_secret_response&  sW    ! 	F+,00777! ! 	r1   c                 0    |                      d           d S )NrM   )r  r  s    r0   _cancel_secret_capturez HermesCLI._cancel_secret_capture&  s    $$R(((((r1   c                     t          | dd           r2	 | j        j                                         d S # t          $ r Y d S w xY wd S )Nr^  )r  r^  rE  r  r   r  s    r0   _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                                rt           d<          r	  jL                            d=>          }!|!r? jM        s jN        rTte          d?           ||O                                  j        P                    |!           	 t          d@z  }"t          |"dAdBC          5 }#|#S                    t          jT        dD           dEt1          |!          ddF         dGt3           j        jU                   dH j        jV         d$           t           j        jU                  D ]&\  }$}%|#S                    dI|$ dJ|%jV         d$           '	 ddd           n# 1 swxY w Y   n# t(          $ r Y nw xY wnVn@# t~          jX        $ r  Y                    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                     _^        	 d	dRl_m`}'  |'             n# t(          $ r Y nw xY w a                                 |r/K-Kb                    d           ||                    dS>           t          jd        e                                 t          jf        dK           IrI                    dT j/                  n j/         _/         j        rhtI           j        dUd          rR j        jg         jg        k    r= h                     jg         j        jg                    j        jg         _g        d _i        IrI                    dVd          nd}(|(rIrI                    dW          sI                    dX          sw	 d	dYljmk})  j        rtI           j        dZd          nd}* |) jl         jg        |( j/        |* j         j         j"         j#         jm        d[\           n# t(          $ r Y nw xY wIrtI                    dW          sI                    dX          rJ|(sHI                    d]d^          }+d_|+ }( jn        r&d _n        t          d$t           d`t                      d},t          IoI                    da                    }-|- _        |-r I                    db          p|!},|(r|,r|(dcz   }(IrI                    ddd          nd}.tI           ded          }/ jp        rFIrC|/s@I                    df          }0|0r( q                                }dg}1|dhz
  t3          |1          z
  }2t           di|1 djt          |2dkz
  d	          z   dlt           }3t           dmdj|dhz
  z   dnt           }4|0                                r                                }5t3          |5          dok    rFd$                    |5ddo                   }6|6d$t           dpt3          |5          doz
   dqt           z  }6n|0                                }6t          d$|3 d$t           |6 t           d$|4            |(r|.s	 d	drlsmt}7  |7            }8|8u                    dsdt          }9t          |8w                    dudv                    }:t          |8w                    dwdx                    };n0# t(          $ r# dt}9t          dv          }:t          dx          };Y nw xY wIo)I                    dW          pI                    dX          }< jx        o	 jy        o|< }=|rAGr?|<s= q                                }t          d$t           dydj|dhz
  z   dzt                      nr|=rnotc                      }>|>2                    t          t          |( j}        {          d*|: d||9 d-d}|:|;t          j        d~ q                                                      j        r=t          jd        S                    d           t          jd        e                                 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~          jX        $ r Y nw xY w jL                                        `d$                    |A          }Ct3          |A          }D|CddM         t3          |C          dMk    rdndz   }E|Ddkk    rte          d|D d|E d           nte          d|E d            j        b                    |C           IrI                    d          nd}F|Fr_t           d          rO|FddF         t3          |F          dFk    rdndz   }Ete          d|E d            j        b                    |F           |(K'	 K                    d           n# t(          $ r Y nw xY w||O                                 |+|J                                r|                    d>           S S S # t(          $ r}te          d_|            Y d}~K'	 K                    d           n# t(          $ r Y nw xY w||O                                 |,|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||O                                 |+|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  rM   z5image_routing decision failed, defaulting to text: %sr_   nativec                 ,    g | ]}t          |          S r   r  r   s     r0   r   z"HermesCLI.chat.<locals>.<listcomp>'  s    %=%=%=c!ff%=%=%=r1   rR  u   ⚠ skipped z unreadable image path(s)c              3   H   K   | ]}|                     d           dk    V  dS r   r  Nr	  r   s     r0   r   z!HermesCLI.chat.<locals>.<genexpr>'  s1      HHA155==K7HHHHHHr1   r  c              3   >   K   | ]}t          |          j        V  d S r   )r   r  r   s     r0   r   z!HermesCLI.chat.<locals>.<genexpr>'  s*      .T.TtAww|.T.T.T.T.T.Tr1   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)rT  )_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.Tr7  r  u    ⚕ Hermes r  r9  r[  r   r#  r  rZ  r   r$  N)rA  r  r1  r5  r   r  rh  r  r0  r  r/  r  r  r  rX   )r  rM  re  r  _streaming_box_openedr  s       r0   display_callbackz(HermesCLI.chat.<locals>.display_callback}'  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,=,=??@@@@@r1   r  )r  r-   r.   r  deltac                 :                         |            d S d S r   )r  )r   
text_queues    r0   stream_callbackz'HermesCLI.chat.<locals>.stream_callback'  s)    !-"u----- .-r1   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 _        	 j                            |j        d d         j
        r	nd           
nZ# t          $ rM}t%          j        d|d	
            t          j        dd           |          }d| g ddd	|d
Y d }~nd }~ww xY w                                 	 t          d            t          d            t	          d            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   rO	  r9  r  )user_messager_  r#  r>  persist_user_messagezrun_conversation raised: %sTr	  _summarize_api_errorc                 0    t          |           d d         S )Nr   r  )r   s    r0   r  z3HermesCLI.chat.<locals>.run_agent.<locals>.<lambda>'  s    UXYZU[U[\`]`\`Ua r1   Error: F)final_responser"  	api_callsrA  failedr  )r  rP  r  rQ  r  rR  r   r
  r%  r&  r  r  r  rO	  r9  r   run_conversationr_  rk
  r  r  )r%  r&  _approval_session_tokenagent_message_msn_srnr  _summary_voice_prefixr  r   r  r#  s           r0   r  z!HermesCLI.chat.<locals>.run_agent'  s    +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)!!Z88%2-1-Fss-K(7 $8E-OWW4 9  FF ! 
 
 
M"?tTTTTbwtz3IKaKabbcfggH*>H*>*>$&%&%*"&!) FFFFFF
  ..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=5D G( 
E+AE&!G( &E++G( -F1 1
F>=F>G 
G! G!(I>-H,+I,
H96I8H99III
IIIIr7   r  rn  r)  r  u*   
⚡ New message detected, interrupting...interrupt_debug.logrz  r   r   %H:%M:%Sz interrupt fired: msg=r8   z, children=z, parent._interrupt=z  child[z]._interrupt=rp  rB  r   皙?rp  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#  rH  )failure_callbackmain_runtimer  r  r+  z+Continuous voice mode stopped due to error.rB  interrupt_messagez.

---
_[Interrupted - processing new message]_response_previewedr  last_reasoningr  r[  r  r  rZ  r  r  r  rQ   z  ... (r  r~  r   r!  r  ra  r"  r\  r5  r6  r  z bold]left)rZ  r  )r  title_alignr  r		  r  paddingr7  r  rA  r-  r'  r   u   ⚠ Iteration budget reached (r\  u    ) — response may be incompleterm  r;  u   
⚡ Sending z messages after interrupt: 'r  u   
⚡ Sending after interrupt: 'pending_steeru/   
⏩ Delivering leftover /steer as next turn: 'rh  )r  rR  ro  _ensure_runtime_credentials_resolve_turn_agent_configr[  r   r  r  r  _init_agentrB   agent.image_routingr  r  rs  r  r   r   r"  r   rk
  r  r   rW   r  r2  r   r  r   agent.context_referencesr  rt  r  r   r#  r  r   rw  r   blocked
referencesinjected_tokensr  r  r  r  r_  r  r  r  r  r  r  r  r  r  r  r  r  r  rU  r  r  rl  r|  r  ri	  r  r  r  r  rb  rc  r  r*  rn  rt  ru  r  r  r   r   rR  rh  _active_children_interrupt_requestedr  r  r  r  r   identr  rd  r&  r9  r  r  rO  rP  rT  rq  r  r
  rg  agent.title_generatorr:  re  rH  r  r  r  rA  r  rp  r  r  r  rq  r:  r;  r/  r  r  r	  rich_boxHORIZONTALSr  r  rx
  
get_nowaitrm  
put_nowait)Lr  r  r  
turn_router  r  r  	_img_mode_img_exc_text_for_parts_img_str_pathsr
  _skipped
_img_namesr  r  _ctx_len_ctx_resultrM  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_tickr9  responser:  _title_failure_cberror_detailpending_message_interrupted_this_turnr?  _reasoning_already_shownrz   r  r  r_topr_botr  display_reasoningr  r  re  _resp_color
_resp_textis_error_responsealready_streamed_chat_console
_api_calls	_max_iter	all_partsrC  combinedr`  r  _leftover_steerr  r5  r   r#  r"  sL   ``                                                                     @@@@@r0   chatzHermesCLI.chat&  s   * 	$D$ABBB ',# //11 	444W==
k"d&HHHDJ :t88$88999%g.'	2(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r	+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 
X! X! X! X! X! X! X! X! X!~ '+ikkD#$'D!$+9TJJJL    !M'')) $+4!344 #+<(,(=(A(A#(A(N(N( "  $2 )d6L ) (!"OPPP)5 * 0 0 0 J00???	%'36K'K%)$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 $- % % % $%!-". !; < < < ((d(;;;;;< !%%c***I '')) $+V ( #())  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] ^ ^'*]]HLR!],@%!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,0IIeCRCj,A,A))-b$-b-bs5zzB-b-b\`-b-bb)),5OO,=,=)RRR$R0AR4RR5RRSSS " 2 "	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%   %**=*=*?*?%**** &%sG  AD 
E	(EE	C>I 
J)AJ$$J)5DP >P 
P/P**P/:0AG +=T) (AG )U:AG <	UAG UDAG ,^= AG ?^= ^+ (B*^^+ ^##^+ &^#'^+ *^= +
^85^= 7^88^= ;AG =%_%"AG $_%%DAG d AG 
d# AG "d##EAG >A%k$ #AG $
k1.AG 0k11IAG 9A,v& %AG &*wAG wH AG 40A@% @$AG @%A@7@4AG @6A@7@7D'AG E!AE7E7
AFFAFG
AI"GAIG(AI% G/AH H
AHHAHIAI"I"AI% I%AKI)AI?I>AKI?
AJJ	AKJAJJAAK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[Hr  r  r  )	rO  rP  rQ  r   rR  rT  r   rb
  r  )r  rU  s     r0   _clear_terminal_on_exitz!HermesCLI._clear_terminal_on_exitC)  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                       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     r0   r   z1HermesCLI._print_exit_summary.<locals>.<listcomp>u)  s-    ]]]1QUU6]]V\E\E\QE\E\E\r1   c                 n    g | ]2}|                     d           dk    s|                     d          0|3S )r&  r  r   r	  r  s     r0   r   z1HermesCLI._print_exit_summary.<locals>.<listcomp>v)  sB    uuuAaeeFmmW]F]F]abafafgsatatF]aF]F]F]r1   r  r8   r=   r  r:   NzResume this session with:get_active_profile_namer   )r   customrM   z -p z  hermes --resume z  hermes -c "r  zSession:        zTitle:          zDuration:       zMessages:       r  z user, z tool calls))get_active_goodbyeu   Goodbye! ⚕)r  r  r  r_  r   r  r`  divmodrC   r$  re  get_session_titler  r   hermes_cli.profilesr  rp  r  )r  rx  	user_msgsr   r  rE   r  rD   r6   duration_strsession_titler  _active_profileprofile_flagr  goodbyes                   r0   _print_exit_summaryzHermesCLI._print_exit_summarye)  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  r9  r  >   r  r   )r  r  r  rM   )r  >r
  r  u   ›   »u   →c              3       K   | ]}|v V  	d S r   r   )r   r  r3  s     r0   r   z4HermesCLI._get_tui_prompt_symbols.<locals>.<genexpr>)  s'      552rY555555r1   )rp  r  r   rX   r  r  r  r2  )	r  r  symbolr  r	  r-  r   arrow_charsr3  s	           @r0   _get_tui_prompt_symbolsz!HermesCLI._get_tui_prompt_symbols)  s_   	GGGGGG--f55FF 	 	 	FFF	 "F**,,s2	CCCCCC--//G333#..f.. 	 	 	D	==?? 	"!>  !&.E"IIB	@555555555 	49++--333 v~s    $$A 
A*)A*c                 z    d}t          | dd          }|dS |j        }t          |d          dz  dz  }||         S )z;Return a visual audio level indicator based on current RMS.u    ▁▂▃▄▅▆▇r  NrM   i@  r  )r  current_rmsr  )r  _LEVEL_BARSr  rmsr  s        r0   _audio_level_barzHermesCLI._audio_level_bar)  sN    .d-t44;2o C"d*5!!r1   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@  rM   r		  r
  rC  c                     r7|}|r+| d|                                                                  }| |dz   fgS |r| | d| d fgS | | d fgS )Nr9  )r   rX   )r		  r
  rC  r_   r  state_suffixs       r0   _state_fragmentz<HermesCLI._get_tui_prompt_fragments.<locals>._state_fragment)  s     - >"44U[[]]44;;==Ds
+,, C4 @ @% @ @, @ @ABBt44l44566r1   zclass:voice-recordingu   ●zclass:voice-processingu   ◉zclass:sudo-promptu   🔐u   🔑zclass:prompt-workingr  r  Nclass:clarify-selectedu   ✎r  u   ⚕zclass:voice-promptu   🎤zclass:promptro  )r  r>  r;  rW   r  r  r  rw  r  rz  r  ru  rt  r  r@  rk  r  )r  r  r  r  r  r  s       @@r0   _get_tui_prompt_fragmentsz#HermesCLI._get_tui_prompt_fragments)  s   #;;==..T5Q5Q5S5S.TT	7 	73 	7c 	7# 	7 	7 	7 	7 	7 	7 	7   	H''))C"?#:E3GGG! 	D"?#;UCCC 	@"?#6??? 	@"?#6??? 	B"?#95AAA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@@@())r1   c                 d    d                     d |                                 D                       S )z6Return the visible prompt text for width calculations.rM   c              3       K   | ]	\  }}|V  
d S r   r   r  s      r0   r   z1HermesCLI._get_tui_prompt_text.<locals>.<genexpr>*  s&      LL4tLLLLLLr1   )r   r  r  s    r0   _get_tui_prompt_textzHermesCLI._get_tui_prompt_text*  s/    wwLL4+I+I+K+KLLLLLLr1   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_overridesr#  r|   c                     | s| S |                                  }t          d |D                       }|r| S d                    d |D                       S )Nc              3   @   K   | ]}|                     d           V  dS )zbg:Nr  r  s     r0   r   zHHermesCLI._build_tui_style_dict.<locals>._remap_value.<locals>.<genexpr>'*  s.      )N)N!!,,u*=*=)N)N)N)N)N)Nr1   r9  c              3   b   K   | ]*}|                     d           rt          |          n|V  +dS )r  N)r  r  r  s     r0   r   zHHermesCLI._build_tui_style_dict.<locals>._remap_value.<locals>.<genexpr>+*  sV       $ $ ;<,,s:K:KR3A666QR$ $ $ $ $ $r1   )r  r2  r   )r#  r  has_explicit_bgs      r0   _remap_valuez5HermesCLI._build_tui_style_dict.<locals>._remap_value#*  sw     ! WWYYF&))N)Nv)N)N)N&N&NO& ! 88 $ $!'$ $ $   r1   c                 2    i | ]\  }}| |pd           S ro  r   )r   rf  r#  r  s      r0   rg  z3HermesCLI._build_tui_style_dict.<locals>.<dictcomp>/*  s-    VVV41aaag2!6!6VVVr1   )	r   r  rp  r  rv  r   r[  rW   ry  )r  
style_dictr  r  s      @r0   _build_tui_style_dictzHermesCLI._build_tui_style_dict*  s    '$(92>>D"EE
	QQQQQQ@@BBCCCC 	 	 	D		!## 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  Fr7   rB  T)r  PTStyle	from_dictr  r^  r		  r  r  s    r0   _apply_tui_skin_stylezHermesCLI._apply_tui_skin_style4*  sl    tVT** 	'$@QSW2X2X 	5!+D,F,F,H,HII	c***tr1   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    r0   _get_extra_tui_widgetsz HermesCLI._get_extra_tui_widgets>*  s	     	r1   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      r0   _register_extra_tui_keybindingsz)HermesCLI._register_extra_tui_keybindingsG*  s      r1   )slash_confirm_widgetmodel_picker_widgetspinner_widgetc          
          d t          d          ||||||||g	|                                 |	|
|||||D             S )zAssemble the ordered list of children for the root ``HSplit``.

        Wrapper CLIs typically override ``_get_extra_tui_widgets`` instead of
        this method.  Override this only when you need full control over widget
        ordering.
        c                     g | ]}||S r   r   r  s     r0   r   z8HermesCLI._build_tui_layout_children.<locals>.<listcomp>o*  s,     
 
 
$ !% $ "!!r1   r   height)r   r  )r  sudo_widgetsecret_widgetapproval_widgetr  clarify_widgetr  r  spacer
status_barinput_rule_top	image_barr  input_rule_botvoice_status_barcompletions_menus                   r0   _build_tui_layout_childrenz$HermesCLI._build_tui_layout_childrenV*  s    2
 
a   $# ,,..       !!" !#
 
 
 	
r1   c                 b<   ~                       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 t          dw jr        dx y          }Dt          t          ddzd{          |Bd|ddt          fd}          t          t           jv                            |Ddt           |C            |D~          
  
        djx        _y         fd}E|Ejz        _{        d	gd	gd	gd&gd& _|         fd}Fjx        xj}        |Fz  c_}        j~        j                            t          t                      t          fd          7                      G d dt                    }Gfd}Hj~        j                             |G|H                     fd}Ifd}Jfd}Kfd}Lt	          t          |K          |Ld          }Mt	          t          |I          |J          }Nd*dt          dt          t                   dt          dt          dt          f
dd+dt          dt          dt          dt          t                   fddt          dt          dt          dt          ddf
ddt          dt          ddfdfd}Ot          t	          t          |O          d          t          fd          7          }Pfd}Qt          t	          t          |Q          d          t          fd          7          }Rfd}St          t	          t          |S          d          t          fd          7          }Tfd}Ut          t	          t          |U          d          t          fd          7          }Vfd}Wt          t	          t          |W          d          t          fd          7          }Xfd}Yt          t	          t          |Y          d          t          fd          7          }Z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          }`t          t	          t          fd          dd&          t          fd          7          }a                     |           t          dd          }bt          t                               |R|T|V|X|P|Z|M|N|a|[|^|\|`|b                              }ci 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                                                   }dt%          d,|c||dd&d&ddt&          
dt&          ini t)                      _        	 d	dlm}e d	dlm t3          |edd&          sfd}f|f|e_        d|e_        n# t          $ r Y nw xY wt7                       j         fd}g|g_         fd}ht          j        |hd          }i|i                                  fd}jt          j        |jd          }k|k                                 t?          j        tB                      fd }l	 d	dl}m|m                    |mj        |l           tI          |md          r|m                    |mj        |l           tL          j        dk    rd }n|m                    |mj        |n           n# t          $ r Y nw xY wd }o	 t'          j        d	           nE# tT          $ r7 t          d           tC                                                         Y dS w xY wtL          j        dk    r	 d	dltI          d          rs                                }p	 |p                    d	j                   |p                    d	           |p                                 n# |p                                 w xY wn]# tT          tb          td          f$ r@ d	dl~d	dl G ~fdd	~j                  }q~                     |q                       Y nw xY w	 tm                      5  	 d	dl}r|r                                }s|s                    |o           n# tr          $ r Y nt          $ r Y nw xY wtu                                                        ddd           n# 1 swxY w Y   n# tx          tz          t|          f$ r Y ntd          tT          f$ r}tt          |ttT                    rt3          |td
d          nd}ut          |t          }v|ut~          j        k    rnB|ut~          j        t~          j        hv sd|vv s
d|vv sd|vv rt          d|t d           n Y d}t~tnd}t~tww xY wd _.         j        r>t3           dd&          r+	  j                                         n# t          $ r Y nw xY wtI           d          r9 jP        r2	  jP                                         n# t          $ r Y nw xY wd _P        	 d	dlm}w  |w             n# t          $ r Y nw xY wt          d           t          d           t          d           tI           d          r݉ j        rՉ j        r	  j                             j        j        d           n;# t          tz          f$ r&}xt                              d|x           Y d}x~xnd}x~xww xY wt3           dd&          s\	                       j        j                   n;# t          tz          f$ r&}xt                              d|x           Y d}x~xnd}x~xww xY wt3           dd&          r	 d	dlm}y  |y            dz  }z j        j        }{ j                            |{|z          r7t          dt           dt          |{           dt                      n6t          dt           dt          |{           dt                      n;# t          tz          f$ r&}xt                              d |x           Y d}x~xnd}x~xww xY w j        ryt3           dd&          rf	 d	d!l0m}|  ||d" j        j        d&dt3           j        d#d          t3           j        d$d          pdd%&           n# t          $ r Y nw xY wtC                                                                                           n# d _.         j        r>t3           dd&          r+	  j                                         n# t          $ r Y nw xY wtI           d          r9 jP        r2	  jP                                         n# t          $ r Y nw xY wd _P        	 d	dlm}w  |w             n# t          $ r Y nw xY wt          d           t          d           t          d           tI           d          r݉ j        rՉ j        r	  j                             j        j        d           n;# t          tz          f$ r&}xt                              d|x           Y d}x~xnd}x~xww xY wt3           dd&          s\	                       j        j                   n;# t          tz          f$ r&}xt                              d|x           Y d}x~xnd}x~xww xY wt3           dd&          r	 d	dlm}y  |y            dz  }z j        j        }{ j                            |{|z          r7t          dt           dt          |{           dt                      n6t          dt           dt          |{           dt                      n;# t          tz          f$ r&}xt                              d |x           Y d}x~xnd}x~xww xY w j        ryt3           dd&          rf	 d	d!l0m}|  ||d" j        j        d&dt3           j        d#d          t3           j        d$d          pdd%&           n# t          $ r Y nw xY wtC                                                                                           w xY wt3           d'd          rd	d(lm}}  |} j        d&)           dS dS (-  z=Run the interactive CLI loop with persistent input at bottom.r  Nr[  r   rZ  rM   T)endrT  r   r~  welcomezAWelcome to Hermes Agent! Type your message or /help for commands.r"  r\  r  r>  r   )prewarm_picker_cache_asyncro  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_residuerI  rJ  openclaw_residue_hint_clir  r_  r   r	  r	  r	  )maybe_run_curatorinfc                 6                         d|  d          S )Nu   [dim #6b7684]💾 r   )rL  )r  r  s    r0   r  zHermesCLI.run.<locals>.<lambda>*  s%    t':':1111( ( r1   )idle_for_seconds
on_summaryr  r  z]Activated skills:[/] Fr	  r7   r  r  r   rL  )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    r0    handle_ignored_terminal_sequencez7HermesCLI.run.<locals>.handle_ignored_terminal_sequenceT+  s	     4r1   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	                                  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                                        }t1          j                  }|s|rQ                    ||
          r|                    |          s,d	_        | j        j        r| j                                         | j        j                            d	           | j                                         dS                     ||
          rP                    |           | j        j                            d	           | j                                         dS tA          j                  }j        !                                 | j                                         |r||fn|}	j"        r|rtG          |          sj$        }
|
dk    r|s|sd}
nd}	 j%        <tM          j%        d          r't1          j%        '                    |                    }n;# t&          $ r.}t)          dtP           d| dtR                      d}Y d}~nd}~ww xY w|rE|dd         t          |          dk    rdndz   }t)          dtT           d| dtR                      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,                            |	           	 tZ          dz  }t]          |dd           5 }|/                    ta          j1        d!           d"te          |	          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&l3m4}m5}m6}m7}  |tp          |          stt)          dtP            |j$                   tR                       |tZ          d'z  |           d	tp          9                    d(i           9                    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   r  r"	  FT)r	  )append_to_historyr  r  rR  zSteer failed (u   ) — queued for next turn.r  r;  rM   u   ⏩ Steered: 'r  r   imagerZ  r:   z
 attached]r	  r  r6  rz  r   r   r7  z ENTER: queued interrupt msg=r8   z, agent_running=r   )BUSY_INPUT_FLAGbusy_input_hint_clirI  rJ  r   r1  r(  ):rw  r  rE  r_   r  r  r  r  r  rz  r  r  r   rB   r  r  r  r  rm	  r   r  r&	  ru  rt  r  r  r	  r6
  rp  r  r	  r	  r   r  rk  r  r  r   r*  r  r  r  r/  rm  rn  r   r   rR  r  rh  rW   rM  r  r  rI  rJ  r2  rN  )r  r_   r  r  r  _excr  r	  r  r  _effective_moderN
  r  r  rf  r  r  r  rI  rJ  r  s                       r0   handle_enterz#HermesCLI.run.<locals>.handle_enter`+  s	     y/4 !1266t<<<#' 	$$&&& ! y/4,,T222	(..000	$$&&& # //111	$$&&& ( 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	$$&&& ' /779999  / / /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 
W9$W44W9']& A]]& ]]& !]"]& &
]32]37B`	 	
``r  rz  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rE  insert_textr  s    r0   handle_alt_enterz'HermesCLI.run.<locals>.handle_alt_enter!,  s!      ,,T22222r1   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    r0   handle_ctrl_enter_newlinez0HermesCLI.run.<locals>.handle_ctrl_enter_newline-,  s!     $0066666r1   c                  D     j          o j         o j         o j         S r   )rt  rz  rw  r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>A,  s0    ++|D4H0H|QUQaMa|jnj|f| r1   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)rN  rE  )r  cli_refs    r0   handle_open_in_editorz,HermesCLI.run.<locals>.handle_open_in_editorD,  s"     ))%*>?????r1   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   )	rE  complete_statecurrent_completiongo_to_completionapply_completion
suggestionr_   r  start_completion)r  rA  r
  s      r0   
handle_tabz!HermesCLI.run.<locals>.handle_tabJ,  s     &C! ' /B
%((+++!$!3!]8J8]J%F$$Z00000 'CN$7 ' 344444 $$&&&&&r1   upc                  <    t           j                  o j         S r   r  rt  ru  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>m,  s    tD4G/H/H/gQUQgMg r1   c                     j         rAt          dj         d         dz
            j         d<   | j                                         dS dS )z%Move selection up in clarify choices.r   r  rZ  N)rt  r  r  r  r  r  s    r0   
clarify_upz!HermesCLI.run.<locals>.clarify_upm,  sY     " '25a9LZ9X[\9\2]2]#J/	$$&&&&&' 'r1   downc                  <    t           j                  o j         S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>t,  s    d6I1J1J1iSWSiOi r1   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  rZ  N)rt  rB   r  r  r  r  )r  r  max_idxr  s      r0   clarify_downz#HermesCLI.run.<locals>.clarify_downt,  s     " '-11)<<Bg,,25gt?RS]?^ab?b2c2c#J/	$$&&&&&	' 'r1   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)rt  ru  rB   r  r  r  r  )r  r  r*  r  s     r0   r}  zDHermesCLI.run.<locals>._make_clarify_number_handler.<locals>.handler,  s    & /t/E /"155i@@FBGS\\))+,<=AA'#,OOO.2+16.	,,.....G,,15.	,,...../ / / / -,r1   r   r*  r}  r  s   ` r0   _make_clarify_number_handlerz3HermesCLI.run.<locals>._make_clarify_number_handler~,  s)    / / / / / / Nr1   rQ   r  c                  <    t           j                  o j         S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    tD<O7P7P7oY]YoUo r1   c                  ,    t           j                  S r   r  rz  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    tD4H/I/I r1   c                     j         rAt          dj         d         dz
            j         d<   | j                                         d S d S Nr   r  rZ  )rz  r  r  r  r   s    r0   approval_upz"HermesCLI.run.<locals>.approval_up,  sW    # '36q$:Nz:Z]^:^3_3_$Z0	$$&&&&&' 'r1   c                  ,    t           j                  S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    d6J1K1K r1   c                     j         r^t          j         d                   dz
  }t          |j         d         dz             j         d<   | j                                         d S d S )Nr  rZ  r  )rz  r  r  r  r  r  r  r  s     r0   approval_downz$HermesCLI.run.<locals>.approval_down,  sr    # 'd29=>>B36w@TU_@`cd@d3e3e$Z0	$$&&&&&' 'r1   c                  ,    t           j                  S r   r  r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    tD4M/N/N r1   c                     j         rOt          dj                             dd          dz
            j         d<   | j                                         d S d S r  )r  r  rB   r  r  r   s    r0   slash_confirm_upz'HermesCLI.run.<locals>.slash_confirm_up,  sd    ( '8;At?X?\?\]gij?k?kno?o8p8p)*5	$$&&&&&' 'r1   c                  ,    t           j                  S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    d6O1P1P r1   c                    j         r{t          j                             d          pg           dz
  }t          |j                             dd          dz             j         d<   | j                                         d S d S )Nr  rZ  r  r   )r  r  rB   r  r  r  r  s     r0   slash_confirm_downz)HermesCLI.run.<locals>.slash_confirm_down,  s    ( 'd7;;IFFL"MMPQQ8;GTE^EbEbcmopEqEqtuEu8v8v)*5	$$&&&&&' 'r1   c                  ,    t           j                  S r   r  r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    tD4L/M/M r1   c                     j         rOt          dj                             dd          dz
            j         d<   | j                                         d S d S r  )r  r  rB   r  r  r   s    r0   model_picker_upz&HermesCLI.run.<locals>.model_picker_up,  sd    ' '7:1d>V>Z>Z[egh>i>ilm>m7n7n(4	$$&&&&&' 'r1   c                  ,    t           j                  S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    d6N1O1O r1   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	  r^	  rZ  r  r   )r  rB   r  r  r  r  )r  r  r  r  s      r0   model_picker_downz(HermesCLI.run.<locals>.model_picker_down,  s    ,E yy!!Z//eii44:;;eii55;<<q@ #GUYYz1-E-E-I J JE*I  """""r1   c                  ,    t           j                  S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    48P3Q3Q r1   )r  r  c                                                       | j        j                                         | j                                         dS )zESC closes the /model picker.N)r&	  r  rE  r  r  r   s    r0   model_picker_escapez*HermesCLI.run.<locals>.model_picker_escape,  sH     $$&&&I$**,,,I  """""r1   c                       fd}|S )Nc                     j         rWt          j         d                   k     r;j         d<                                    | j                                         d S d S d S )Nr  r  )rz  r  r  r  r  )r  r*  r  s    r0   r}  zEHermesCLI.run.<locals>._make_approval_number_handler.<locals>.handler,  sq    ' +C#d6J96U2V2V,V,V7:D(433555I((*****+ +,V,Vr1   r   r	  s   ` r0   _make_approval_number_handlerz4HermesCLI.run.<locals>._make_approval_number_handler,  s)    + + + + + +
 Nr1   c                  ,    t           j                  S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    tD<P7Q7Q r1   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  r  rB   r  r  rE  r  r  )r  r  r*  r  s     r0   r}  zJHermesCLI.run.<locals>._make_slash_confirm_number_handler.<locals>.handler,  s    , +s4;T;X;XYb;c;c;igi7j7j1j1j!6yA#FqIF77???I,22444I((*****	+ +1j1jr1   r   r	  s   ` r0   "_make_slash_confirm_number_handlerz9HermesCLI.run.<locals>._make_slash_confirm_number_handler,  s)    + + + + + + Nr1   c                  ,    t           j                  S r   r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  s    tD<U7V7V r1   c                  d     j          o' j         o j         o j         o j         o j         S r   )rt  rz  r  rw  r  r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>,  sw    ++  @D4H0H  @QUQjMj  @sw  tD  pD  @  MQ  M_  I_  @  hl  h@  d@ r1   c                 P    | j         j                            | j                   dS )zAUp arrow: browse history when on first line, else move cursor up.r  N)r  rE  auto_upargr  s    r0   
history_upz!HermesCLI.run.<locals>.history_up,  s(     I$,,59,=====r1   c                 P    | j         j                            | j                   dS )zDDown arrow: browse history when on last line, else move cursor down.r  N)r  rE  	auto_downr1  r  s    r0   history_downz#HermesCLI.run.<locals>.history_down,  s(     I$..UY.?????r1   zc-lc                 0                                      dS )uZ  Ctrl+L: force a clean full-screen repaint.

            Recovers the UI after external terminal buffer drift — tmux /
            cmux tab switches, ``clear`` from a subshell, SSH window
            restores, etc. — that prompt_toolkit can't detect on its own.
            Matches the universal bash/zsh/fish/vim/htop convention.
            N)r  r   s    r0   handle_ctrl_lz$HermesCLI.run.<locals>.handle_ctrl_l,  s     ##%%%%%r1   zc-cc                    t          j                     }d}d}j        5  j        rj        rj        }d_        d_        d}ddd           n# 1 swxY w Y   |rgt          dt           dt                      t          j	        |j
        d                                           | j                                         dS j        rBj        d                             d           d_        | j                                         dS j        rM                                 | j        j                                         | j                                         dS j        rBj        d                             d	           d_        | j                                         dS j        rN                    d
           | j        j                                         | j                                         dS j        rM                                 | j        j                                         | j                                         dS j        rgj        d                             d           d_        d_        | j        j                                         | j                                         dS j        rwj        rp|j        z
  dk     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  r  rM   r  r  7The user cancelled. Use your best judgement to proceed.rP  u   
⚡ Force exiting...u=   
⚡ Interrupting agent... (press Ctrl+C again to force exit))%r  r  r  r  r  r  r  r  r|  ri	  r  r  r  r  rw  r  r  r  rE  r  rz  r  r  r  r&	  rt  ru  rk  r   rs  r  rp  r	  r  r_   r  r  )r  r  _should_cancel_voice_recorder_refr  r  s       r0   handle_ctrl_cz$HermesCLI.run.<locals>.handle_ctrl_c-  s    )++C
 $)  M$ 0 0+ 00G 0$+$;M/4G,05G-+/(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 $ =T==t==>>> (/  %'''	$$&&&   !1266r:::#' 	$$&&& ! ++---	(..000	$$&&& # $%56::6BBB'+$	$$&&& ( 33H===	(..000	$$&&& ' ((***	(..000	$$&&& " #$4599M   '+#).&	(..000	$$&&&" !tz !//#552333(,D%INN$$$F),&VWWW
$$&&&&& ). !$2G !	(..000%++---	$$&&&&&$(!	     s   &AAAzc-qc                    d}d}j         5  j        rj        rj        }d_        d_        d}ddd           n# 1 swxY w Y   |rgt	          dt
           dt                      t          j        |j	        d          
                                 | j                                         dS j        rBj        d                             d           d_        | j                                         dS j        rM                                 | j        j                                         | j                                         dS j        rBj        d                             d	           d_        | j                                         dS j        rN                    d
           | j        j                                         | j                                         dS j        rM                                 | j        j                                         | j                                         dS j        rgj        d                             d           d_        d_        | j        j                                         | j                                         dS j        r1j        r*t9          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   r9  r  r  rM   r  r  r:  u   
⚡ Interrupting agent...)#r  r  r  r  r  r  r  r|  ri	  r  r  r  r  rw  r  r  r  rE  r  rz  r  r  r  r&	  rt  ru  rk  r   r  r  r_   r  r  rp  r	  )r  r;  r<  r  r  s      r0   handle_ctrl_qz$HermesCLI.run.<locals>.handle_ctrl_qn-  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==>>> (/  %'''	$$&&&   !1266r:::#' 	$$&&& ! ++---	(..000	$$&&& # $%56::6BBB'+$	$$&&& ( 33H===	(..000	$$&&& ' ((***	(..000	$$&&& " #$4599M   '+#).&	(..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)r  rE  r_   deleter  rp  r	  )r  rA  r  s     r0   handle_ctrl_dz$HermesCLI.run.<locals>.handle_ctrl_d-  sZ     )*Cx !

& !$(!	     r1   c                  H    t           j        p j        p j                  S r   )r  r  rw  r  r  s   r0   r  zHermesCLI.run.<locals>.<lambda>-  s"    D+\t/?\4C\]] r1   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  rM   r  )
r  r  r  rE  r  r  rw  r  r  r  r   s    r0   handle_escape_modalz*HermesCLI.run.<locals>.handle_escape_modal-  s     ! ++---	(..000	$$&&&  !1266r:::#' 	$$&&&( 33H===	(..000	$$&&&	 r1   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).rY  r   z-Suspend (Ctrl+Z) is not supported on Windows.Nr   r  r~  r  r  z' has been suspended. Run `fg` to bring z back.c                      t          j        d                                           t          j        d j                   d S )NrZ  r   )r   rR  r  killSIGTSTP)_sigr  s   r0   _suspendz6HermesCLI.run.<locals>.handle_ctrl_z.<locals>._suspend-  s7    CJJLL)))4<(((((r1   )rO  r  r  r  r  r  r  signalr  r  rp  r  r  )r  r  r  r  rK  rJ  r  s        @@r0   handle_ctrl_zz$HermesCLI.run.<locals>.handle_ctrl_z-  s     |w&&VTVVPTVVWWW	$$&&&!!!!BBBBBB>>>>>>(**77nUUJ\z\\*\\\C) ) ) ) ) ) OH%%%%%r1   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    r0   _start_recordingzDHermesCLI.run.<locals>.handle_voice_record.<locals>._start_recordingQ.  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  r  r  r|  ri	  rf  r  rk  rt  rw  rz  r  r  r  is_setrt  r  r  r   )r  r  rU  r  s      r0   handle_voice_recordz*HermesCLI.run.<locals>.handle_voice_record .  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.
            rM   r  r   r  z1mouse reports leaked into bracketed paste payloadr6  r   r  paste_collapse_thresholdrh  paste_collapse_char_threshold  r\  rZ  pastesTrw  paste_r8  %H%M%S.txtr   r   z-Collapsed paste #%d: %d lines, %d chars -> %sr  r|      lines → r>  g     @@g     @@zSlow bracketed-paste handler: %.1fms to process %d bytes (%d lines) on %s. If the input becomes unresponsive after this, attach this log line to the bug report.N)"r  perf_counterr  r   rC  rJ  r  r  rG  r  r  r  r  r  r  rE  r   rB   r_   r   r  r   r  r   r  rh  
write_textr   r  rF  r  r   rO  r  )r  _paste_handler_start_paste_raw_sizerE  _had_mouse_reportsr  
line_countrA  r\   char_threshold	lines_hit	chars_hit	paste_dir
paste_fileplaceholderr  _paste_handler_elapsed_ms_paste_counter_paste_just_collapsedr  s                    r0   handle_pastez#HermesCLI.run.<locals>.handle_paste].  s   " $(#4#6#6 !%*"233O**K &--fd;;CCD$OOK@MMK.XYd.e.e+K+! o22:m2nnn;KHH 'TMmMmMoMo '	$$&&& 1::::::22;??(..t44
* 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0r1   zc-vc                 f                                     r| j                                         dS dS )a  Fallback image paste for terminals without bracketed paste.

            On Linux terminals (GNOME Terminal, Konsole, etc.), Ctrl+V
            sends raw byte 0x16 instead of triggering a paste.  This
            binding catches that and checks the clipboard for images.
            On terminals that DO intercept Ctrl+V for paste (macOS
            Terminal, iTerm2, VSCode, Windows Terminal), the bracketed
            paste handler fires instead and this binding never triggers.
            Nr  r  r  r   s    r0   handle_ctrl_vz$HermesCLI.run.<locals>.handle_ctrl_v.  s=     //11 '	$$&&&&&' 'r1   r#  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.
            Nrr  r   s    r0   handle_alt_vz#HermesCLI.run.<locals>.handle_alt_v.  s:     //11 	$$&&&&& r1   c                  ,                                      S r   )r  r  s   r0   
get_promptz!HermesCLI.run.<locals>.get_prompt.  s    44666r1   )AutoSuggestFromHistoryc                      t                      S r   )r  r   r1   r0   r  zHermesCLI.run.<locals>.<lambda>.  s    ,>,@,@ r1   c                      t                      S r   r  r   r1   r0   r  zHermesCLI.run.<locals>.<lambda>.  s    +<+>+> r1   )skill_commands_providercommand_filterskill_bundles_providerrt  )r  r  	preferredzclass:input-areac                  ,    t           j                  S r   )r  r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>.  s    W-E(F(F r1   )history_suggest	completer)
r  r
  r		  	multiline
wrap_lines	read_onlyr  r  complete_while_typingauto_suggestz.mdc                     	 ddl m}  ddlm} j        j        }t          d |	                                                    }	  |             j        	                                j
        |z
  }n,# t          $ r t          j        d          j
        |z
  }Y nw xY w|dk     rd}d}|j        D ]1} ||          }|dk    r|dz  }|t          d| |z             z  }2t          t          |d          d	          S # t          $ r Y dS w xY w)
Nr   r8  r-  r[  r  rQ   r  rZ  rt  )r  r9  r/  r.  rJ  documentr  r  r  r:  r  r   r  r  r  r  )
r9  r.  docprompt_widthavailable_widthvisual_linesr  
line_widthr  r  s
           r0   _input_heightz$HermesCLI.run.<locals>._input_height.  sl   >>>>>>;;;;;; '0"1jj1J1J1L1L&M&MNN`&-gii&6&?&?&A&A&IL&XOO  ` ` `&,&>x&H&H&PS_&_OOO`"R''&(O I R RD ",D!1!1J!Q$)$A*1O/P(Q(QQ3|Q//333   qqs7   AC> )A1 0C> 1&BC> BA#C> >
DDc                 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 bufferr6  Tr   r   NFrZ  r  !paste_collapse_threshold_fallbackrh  rZ  r[  r\  r\  rw  r]  r8  r^  r_  r   r   z8Collapsed paste #%d: %d lines, %d chars -> %s (fallback)r  r|  r`  r>  )rJ  r_   r  r  r  rF  r  r  rH  r   rB   r  r   r  r   r  rh  rb  r   r  )rA  r_   re  cursorchars_addedrf  newlines_addedis_paster\   rg  rh  ri  rj  rk  rn  ro  _prev_newline_count_prev_text_lenr  s                 r0   _on_text_changedz'HermesCLI.run.<locals>._on_text_changed/  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 	4r1   c                  T    t           j                  pt           j                  S r   )r  rw  r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>E/  s"    D!455Tg>S9T9T r1   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     r0   r|  z5HermesCLI.run.<locals>._PlaceholderProcessor.__init__L/  s    !)r1   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  r_   linenor  r   r  )r  tir_   s      r0   apply_transformationzAHermesCLI.run.<locals>._PlaceholderProcessor.apply_transformationO/  sg    {' fBINN>>++D f-I\^bHcGd8deeee%====r1   N)r  r  r  r  r|  r  r   r1   r0   _PlaceholderProcessorr  J/  s8        QQ* * *> > > > >r1   r  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 skiprM   u%   type 1/2/3, or use ↑/↓ then Enterz%type your answer here and press Enterr:  r9  u9   msg=interrupt · /queue · /bg · /steer · Ctrl+C cancelztype or z
 to record)r  r\  r  rw  r  rz  r  ru  rt  r  r@  r  rk  r  )r~  framer  r  s      r0   _get_placeholderz'HermesCLI.run.<locals>._get_placeholderW/  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2r1   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-countdownrS  zs))r  u      secret hidden · Enter to skip)r  u%     ↑/↓ to select, Enter to confirm)r  u4     type 1/2/3, or ↑/↓ to select, Enter to confirmrM   )r  z"  type your answer and press Enterr  rR  u2    command in progress · input temporarily disabled)rw  r  rC   rx  r  r:  r  r  rz  r{  r  r  rt  rv  ru  r  r@  )r^  	countdownr  r  s      r0   get_hint_textz$HermesCLI.run.<locals>.get_hint_texty/  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  Ir1   c                       j         s# j        s j        s j        s j        s j        rdS                                  S )NrZ  )rw  r  rz  r  rt  r  rH  rw  s   r0   get_hint_heightz&HermesCLI.run.<locals>.get_hint_height/  sl    " g&; w?V ZaZv   {B  {Q   U\  Um q //111r1   c                  >                                     } | sg S d| fgS )Nr  )rJ  )rM  r  s    r0   get_spinner_textz'HermesCLI.run.<locals>.get_spinner_text/  s/    "7799L 	!<011r1   c                  ,                                      S r   )rO  rw  s   r0   get_spinner_heightz)HermesCLI.run.<locals>.get_spinner_height/  s    11333r1   )r   r  r  )r   r  r  rm  r  r  r  r1  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     r0   r   z;HermesCLI.run.<locals>._panel_box_width.<locals>.<listcomp>/  s    )N)N)N#d)))N)N)Nr1   r  r[  r<   r  r  )r  r  r  r1  r  r  r  s          r0   r  z'HermesCLI.run.<locals>._panel_box_width/  s    0;;CI3u::,)N)N)N)N)NNR[^_R_Q``aaGGaKQ77QBPY\]P]H^H^__E19r1   r_   r7  r  c                 Z    t          j        | t          d|          dd|          }|pdgS )Nrt  F)r7  break_long_wordsbreak_on_hyphensr  rM   r  r  s       r0   r  z'HermesCLI.run.<locals>._wrap_panel_text/  s=    m!Umm!&!&"3  G ?rd"r1   r  r  r  c                     t          d|dz
            }|                     |df           |                     ||                    |          f           |                     |df           d S r  r  r  s         r0   r  z)HermesCLI.run.<locals>._append_panel_line/  r  r1   c                 F    |                      |dd|z  z   dz   f           d S r  r  r  s      r0   r  z/HermesCLI.run.<locals>._append_blank_panel_line/  r  r1   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.
            r  r  r  r   r8   r  rZ  rT   r9  r  r  rR  r  r  rQ   z. Other (type below)z. Other (type your answer)Hermes needs your inputrt  r[  z7Type your answer in the prompt below, then press Enter.r  rh  r  r  Nu   … (question truncated)class:clarify-border   ╭─ )class:clarify-titler  r  r  r  r  zclass:clarify-questionclass:clarify-choicer  zclass:clarify-active-otherr5  r  )rt  rB   r  rW   ru  r  r  r  r  r  r  r  r  )'r  r  r  r  r  r  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'                                     r0   _get_clarify_displayz+HermesCLI.run.<locals>._get_clarify_display/  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Lr1   )r  c                       j         d uS r   )rt  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>0  s    W%;4%G r1   c                     j         } | sg S d}d} ||g          }g }|                    d           |                    d|f           |                    dddt          d|t          |          z
  d	z
            z  z   d
z   f            |d|            |dd||            |d|           |                    ddd|z  z   dz   f           |S )Nu   🔐 Sudo Password Requiredz5Enter password below (hidden), or press Enter to skipclass:sudo-borderr  class:sudo-titler  r9  r  r   r  r  class:sudo-textr5  r  )rw  r  r  r  )	r  r  bodyr  r  r  r  r  r  s	        r0   _get_sudo_displayz(HermesCLI.run.<locals>._get_sudo_display0  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Lr1   c                       j         d uS r   )rw  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>0  s    W%8%D r1   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 skiprZ  r  r  r  r9  r  r   r  r  r  r5  r  )r  rB   insertrW   r  r  r  )r  r  r
  r  	help_textr  r  r  r  r  r  r  r  s            r0   _get_secret_displayz*HermesCLI.run.<locals>._get_secret_display0  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Lr1   c                       j         d uS r   )r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>0  s    W%:$%F r1   c                  ,                                      S r   )r  rw  s   r0   _get_approval_displayz,HermesCLI.run.<locals>._get_approval_display0  s    ::<<<r1   c                       j         d uS r   )rz  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>0  s    W%<D%H r1   c                  ,                                      S r   )r
	  rw  s   r0   _get_slash_confirm_displayz1HermesCLI.run.<locals>._get_slash_confirm_display0  s    ??AAAr1   c                       j         d uS r   )r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>0  s    W%A%M r1   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_modelsr[	  r  r  z modelrZ  r:   rM   r  r	  u     ← currentr	  z	Current: r  r  z on r	  r]	  r^	  u   ⚙ Model Picker — r  Provideru   ← BackzSelect a model (z available)z7No models listed for this provider. Use Back or Cancel.r  T   )r  r1  rt  r  r  r   r8  r  _scroll_offsetr  r  r  r9  r  r  r  zclass:clarify-hintr  r  r  rR  r  r5  r  )r  rB   r   r   r  r  r  r  r9  r  r:  rowsr   r  r  r  r  r-	  r  )r  r	  r  r  
_providersr   r  re  hintr]	  r^	  r  r	  r  r9  r	  r'	  r,	  r  r*  r  r		  r  r  r  r  r  r  r  s                           r0   _get_model_picker_displayz0HermesCLI.run.<locals>._get_model_picker_display0  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  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>?1  s    W%@%L r1   r  c                  .                          d          S )NrD  rF  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>G1  s    799%@@ r1   zclass:input-rule)charr  r		  c                  .                          d          S )NrE  r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>L1  s    799(CC r1   c                  \    j         sg S t          j         j                  } dd|  dfgS )Nzclass:image-badger9  )r  rD  r  )badgesr  s    r0   _get_image_barz%HermesCLI.run.<locals>._get_image_barS1  sF    + 	4(& F )-f---899r1   c                  ,    t           j                  S r   )r  r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>^1  s    T'*B%C%C r1   c                  ,                                      S r   )rh  rw  s   r0   _get_voice_statusz(HermesCLI.run.<locals>._get_voice_statusb1  s    66888r1   r  c                       j         S r   )r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>j1  s
    W%8 r1   c                  ,                                      S r   )r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>o1  s    W5V5V5X5X r1   c                  6     j         ot           dd           S )Nr  F)r  r  rw  s   r0   r  zHermesCLI.run.<locals>.<lambda>|1  s'    3 W)NPUVVV r1   )r  r  )
max_heightr'	  )r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  z
input-arearl  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-rulera  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_support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.
                    Nr  )r*  r  r   )r  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                r0   _patched_output_screen_diffz2HermesCLI.run.<locals>._patched_output_screen_diff2  s    ,*67?T\;];]6.5EE9? 6$    %9VV[+'Wk.0Fn	  s   .2 
??c                  4                                     d S r   )r  )_original_on_resizer  r  s   r0   _resize_clear_ghostsz+HermesCLI.run.<locals>._resize_clear_ghosts72  s     **30CDDDDDr1   c                       j         sk j        st          j        d           # j        r+                     d           t          j        d           nt          j        d            j         id S d S )Nr)  rB  r8  )rp  r^  r  rq  r  r  r  s   r0   spinner_loopz#HermesCLI.run.<locals>.spinner_loop<2  s    ' $y JsOOO( 	$$$#$666JsOOOO JsOOO ' $ $ $ $ $r1   r  c            
      "   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_        *                                 	 +                    | |pd            d_        d_,        d_-        j.        /                                 d_0        *                                 	 1                                 n,# t          $ r}te          j3        d|           Y d }~nd }~ww xY wj4        r<j5        r5j6        s.fd }to          j8        |d!          9                                 	 ddlm} |	                                D ]\  }}j        
                    |            n/# t          $ r Y n"w xY w# d_        d_,        d_-        j.        /                                 d_0        *                                 	 1                                 n,# t          $ r}te          j3        d|           Y d }~nd }~ww xY wj4        r<j5        r5j6        s.fd }to          j8        |d!          9                                 	 ddlm} |	                                D ]\  }}j        
                    |            w # t          $ r Y w w xY wxY wn2# t          $ r%}tt          ;                    d"|           Y d }~nd }~ww xY wj         d S d S )#Nr)  r  r   r  Fz)mouse reports leaked into submitted inputr6  r   r  r(  r  r>  u     📎 Auto-attached image: u     📄 Detected file: z[User attached file: r   rM   u	   
⚙️  Tz 
[dim]Command interrupted.[/dim]r  r  rR  u   📎 r  rZ  r:   z	 attachedr  r7   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)Nr8   r  g333333?r  )r  r  r  r  rq  r  r  r   r  r  r  )r   r  r  s    r0   r  z?HermesCLI.run.<locals>.process_loop.<locals>._restart_recording2  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)<rp  rm  rB   r  r  rk  r  r%  r   drain_notificationsr  r   r  r   r  rW   rJ  r  r  r4  r  r  r  r  rQ  r  r6
  r  r	  r  r  r  r   r  r   finditerr  r  r  r  r  r  r  r}  r  r  r  r  r  r
  rk
  r  r  r  r  r|  ri	  r  r   r   )r%  r   _evt_synthsubmit_imagesre  
_file_drop
_drop_path
_remainder_seed_paste_ref_re
paste_refsr`  	_goal_excr  r   r  r  s                   r0   process_loopz#HermesCLI.run.<locals>.process_loopP2  s    ' ]\\\!%)%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'NN$$$-!		*]5Jd	KKK.3+-/*03-/55777572(((Z @@BBBB( Z Z Z#M*MyYYYYYYYYZ  + 
]0F 
]tOd 
][ [ [ [ [ [ &,4FtTTTZZ\\\!OOOOOO0@0T0T0V0V @ @f $ 3 7 7 ? ? ? ?@( ! ! ! D!S /4+-/*03-/55777572(((Z @@BBBB( Z Z Z#M*MyYYYYYYYYZ  + 
]0F 
]tOd 
][ [ [ [ [ [ &,4FtTTTZZ\\\!OOOOOO0@0T0T0V0V @ @f $ 3 7 7 ? ? ? ?@( ! ! ! D! ! \ \ \NN#WYZ[[[[[[[[\y ' ]\ ]\ ]\ ]\ ]\sF  ( W *B!:BB!
BB!BB!W  B!!W 'EW .8W '7I W I<8W ;I<< W C W ?R4 A	W "O7 6W 7
P PW P  AW ':R# !W #
R1-W 0R11W 4A
W?TW
T=T83W8T==AW:V?>W?
W	WWWW 
XW==X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   Nrk  Freceived signal HERMES_SIGTERM_GRACE1.5      ?r   )r  r  )r   r  r   r  r   r  rA   r   r   r  r  r  rq  "prompt_toolkit.application.currentr  r  r	  r  )signumr  _gracer  r^  _loopr  s         r0   _signal_handlerz&HermesCLI.run.<locals>._signal_handler2  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'SIGHUPrY  c                     d S r   r   )r'  r  s     r0   _sigint_absorbz%HermesCLI.run.<locals>._sigint_absorbW3  s	     Fr1   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)
rB   r   r  rW   KeyErrorr  r  r1  EIOdefault_exception_handler)r  contextr  s      r0   _suppress_closed_loop_errorsz3HermesCLI.run.<locals>._suppress_closed_loop_errorsk3  s    ++k**C#|,, 1G3s881S1S#x(( -@CHH-L-L#w'' GC$,G,G59,T,T**733333r1   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    r0   new_event_loopz<HermesCLI.run.<locals>._SelectEventLoopPolicy.new_event_loop3  s#    );;J<U<U<W<WXXXr1   N)r  r  r  r@  )r>  r?  s   r0   _SelectEventLoopPolicyr:  3  s;        Y Y Y Y Y Y Y Yr1   rA  r1  r0  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 setuprk  r  )cleanup_temp_recordingsre  	cli_closez!Could not close session in DB: %srq  z!Could not prune empty session: %sr  r  r  rR  u   ✓ Session z deletedu   ✗ Session z not found for deletionz$Could not delete session on exit: %sr0  r:  r"  r  r  )r  rA  rB  r"  r  r  rr  )relaunch)preserve_inheritedr  ro  r   )r  r[  r   r  r  r  r  rx  rg  ra  _preload_resumed_session_display_resumed_historyrp  r  r  rq  rL  ru  r  r   r   r   rM  r  r  rI  rJ  r  r   rs  r  r
  r	  agent.curatorr  rA   r  r  r   r  rk  r  rl  rm  rn  ro  rp  rs  r  r	  _cli_refr   r  r  r  rB   r  r  rt  ru  rv  rw  rx  ry  rz  r{  r|  r}  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rr  rW  r`  r#   rg  rM  rF  Ignorer~  rx  r   r  rW   r  r`  rN  rO  r   r   r  r   r   ra  rW  prompt_toolkit.auto_suggestry  r  r  r"   r    r   ri  r  rJ  tempfile_suffixwindowr  rH  on_text_changedcontrolinput_processorsr  r   r   r   r   r   r   rC   r   r  r!   r   r   r  r  r  r  r  r   _STEADY_CURSORr  r^  prompt_toolkit.rendererr  r  r  r  rl  
_on_resizeri	  r  r  r  r-  rL  SIGTERMr*  r+  rO  r  SIGINTfstatr  r  	selectorsr8  
EVENT_READ
unregisterr
  r  r2  r  DefaultEventLoopPolicyset_event_loop_policyr   r  set_exception_handlerr  r  rk  r  r  BrokenPipeErrorr1  r3  EINVALEBADFr   r  r  rt  rB  r  r  r  re  rC  r  r  r8  r   rm   delete_sessionr  r  r  r  r1  rI  hermes_cli.relaunchrD  rr  )r  _term_linesr  _welcome_skin_welcome_text_welcome_colorr  _redact_rawr  r  rI  rJ  r  _resid_color_get_cfg_path_residr	  r=
  r>
  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_inputr2  r5  r7  r=  r?  rB  _modal_prompt_activerE  rM  _raw_keyr  rN  rO  
_voice_keyrW  rM  rp  rs  ru  rx  ry  
_completerr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r		  _pt_rendererr  r  r  spinner_threadr   process_threadr*  _signalr-  r6  _kqrA  r  r)  
_stdin_err_errno_msgrB  r   r7  _sessions_dir_sidr3  rD  r>  r  r  r
  r  r  rn  ro  r  r  r?  r  r  r  r  s   `                                                                                                                             @@@@@@@@@@@@@@@r0   rk  zHermesCLI.run*  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	/		}	G }	G }	G }	G }	G~ 	!\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 " @  @  @  @
 
 
]	+	+	> 	> 
,	+	> 
}	-	-	@ 	@ 
.	-	@ 
	& 	& 	& 	& 
	& 
^	! ^	! ^	! ^	! ^	! 
^	!R 
O	! O	! O	! O	! O	! 
O	!b 
	! 	! 	! 	! 
	!   )]]]] 
  
 
!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 "&0 6 6 8 8$  
 
 

& -2
)	 	 	 	 	 	4 $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 !$"<"<">">??  
 !!
 
" .<-G.))R#
 
& 	,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^	\ ^	\ ^	\ ^	\ ^	\ ^	\B #)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t	+  	**** !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
 z gd,<eDD J((****    D t.// ,D4H ,(113333    D'+$DDDDDD''))))    't,,,!$''''---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
 z gd,<eDD J((****    D t.// ,D4H ,(113333    D'+$DDDDDD''))))    't,,,!$''''---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;J)1AK K
AK(K'AK(NA=AP P
APPAPP#AP8 P8>AQ:Q9AQ:R*AT R;0AT  S+AT T ATTAT TAAU4U3AU4U8AX VAXV	-AV7V6AXV7AWWAXW	AWWAXWAWW&AXW6AX XAXXAX X	AXX
AX XAi* XA[X(Ai* X*A[X<BA[[
Ai* [A[[Ai* [9A\ \
A\ \A\ \=A] ]
A]$]#A]$]/A^ ^
A^^A^_%&A` `Aa`A`?`?AaaAa; a;Ab3bAb.b.Ab3c
B+Ae6 e6Af.fAf)f)Af.gAAh! h!
Ah.h-Ah.i*"Aw=jAj'j&Aw=j'
Aj4j1Aw=j3Aj4j4Aw=kAk+k*Aw=k+
Ak8k5Aw=k7Ak8k8
Aw=lAllAw=l
Al"lAw=l!Al"l"AAw=m9&An nAw=n Aon2AooAw=oAooAw=o/AppAw=pAqp!Aqp=Aw=qAqqAw=qB+At
t	Aw=t
AutAt=t8Aw=t=AuuAw=u AAv5v4Aw=v5
Awv?Aw=wAww;Aw=)NNNNNNNFNFFFrJ  r  )r  )r  rQ   )F)r  r   )FN)rZ  Tr  r  )r  r  r  ro  )r
  )NNN)r  r  r  r  rW   r	   rC   r   r  r|  r  rI  rA   r  r  r  r  r  r  r  staticmethodr  r  r  r  r
   r   r+  r0  classmethodr6  r  r;  r>  rA  rF  rH  rO  rJ  r\  objectra  rh  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r
  r  r  r  r  r<  r@  r   rC  rN  rW  r`  rg  rx  r   r  r   r  r  r  r  r  r  rs  rr  r  r  r  r  r  r  r  r  r  r.  r4  r8  r2  rQ  r[  r_  ry  rh  rk  r  r  r  r  r  r
	  r	  r	  r$	  r&	  r-	  r#	  rm	  r~	  r	  r	  r	  r	  rL  r	  r	  r6
  rd
  ro
  r
  r
  r
  ru  r
  r  r
  r
  r
  r
  r
  r  	frozensetr  r
  r
  r%
  r  r&
  rA  rR  rV  r[  r  rf  r  r  rx  r  r  r  r  r  r  rP  rQ  r  rT  r  r  rR  r  r  r  r  r  r}  r  r  r  r  r  r  r  r  r  r  r  rk  r   r1   r0   r  r  C  s         ""&! %"V* V*V* s)V* 	V*
 V* V* V* $V* V* V* V* V* V* V* V* V*pE   S T VZ    8	. 	. 	. 	.# # # # # # #0   $   2 OT   t X\    *   B+@ +@ +@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]$sCx. ] ] ] ]~ # # # # # \# 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    &R R R R R.
<& 
<T 
< 
< 
< 
<a a# a a a a&<U <UHSM <US <U <U <U <U|pP pP pPd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$J J J JX]c ]d ] ] ] ]~0? 0? 0? 0?d& & & & 'C 'C ' ' ' '*2 2 2 2 2
 /C / / / ^/ D    F. . . .   *  2R R Rh 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G G3 GT#s(^8L G G G G 6?R   s s TX    <A A AF3 4    "HSM d    :g5 g5 g5 g5V$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    <*c *cDj * * * *d 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& & & \&6RF RF$ RF RF RF RFhD' D'T D'd D' D' D' D'L|F |F |F |F |F|&K# &K$ &K &K &K &KP
 
 
 
Z^ 
 
 
 
   Z^    0  6 6 6 	c 	 	 	 \	 7 7 7r~s ~t ~ ~ ~ ~B 5s 5C 5D 5 5 5 \5  FrO rO rO rOl#9 #9 #9J1S 1# 1RV 1 1 1 184 4 4 4 44# # #P3C 3 3 3 3R8 R8S R8 R8 R8 R8ly7 y7 y7D4    ,N9 N9 N9`"7 "7c "7 "7 "7 "7H6b 6b 6b 6bz  )y)?)?)?@@$x} $sDyAQ $ $ $ [$D '+	U UU U sm	U
 
#U U U UnA AC A A A A AFS3 S3 S3jL6 L6 L6 L6d;C ;D ; ; ; ;(P PC P PUX Ppt P P P Pd	^3 	^s 	^SW 	^ 	^ 	^ 	^Zc Z# ZVZ Zmp Z Z Z Z(tE tE tEl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. . . .   S T    ) ) ) )   ~	+ ~	+D ~	+HSM ~	+ ~	+ ~	+ ~	+@     DA A AF%sCx % % % %N
"# 
" 
" 
" 
"&* &* &*PMc M M M M+tCH~ + + + +Zt           * " -
 -
 -
$ 
%-
 -
 -
 -
^V&G V&G V&G V&G V&Gr1   r  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_TASKrM   	kanban_db)run_kanban_goal_loopDEFAULT_MAX_TURNSr  c              3      K   | ]}||V  	d S r   r   r   s     r0   r   z*_run_kanban_goal_loop_q.<locals>.<genexpr>E4  s'      77!Q7A777777r1   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,  rM   )
r   r/  r_  r  r  r   r   rB   rW   r  )r
  r   respr  s      r0   	_run_turnz*_run_kanban_goal_loop_q.<locals>._run_turnK4  s    ++!$!9 , 
 
 CI|T22	2	$66 Y1CN3=fd3K3K\vzz*B///QTU[Q\Q\ 	$KKKzrr1   
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   )r  r  _kbr>  s     r0   _task_statusz-_run_kanban_goal_loop_q.<locals>._task_status[4  s    KKMM	Q((A }188$6				   				   s@    A A
AAB A54B5
B?BBBr  c                                                     }	                     ||            	 |                                 d S # t          $ r Y d S w xY w# 	 |                                 w # t          $ r Y w w xY wxY w)Nr6  )r  
block_taskr
  r   )r  r  r  r>  s     r0   _blockz'_run_kanban_goal_loop_q.<locals>._blockf4  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   r  )r;   s    r0   r  z)_run_kanban_goal_loop_q.<locals>.<lambda>x4  s    fkk$** r1   )r>  	goal_textrun_turntask_status_fnblock_fnr  r  r  )r|   r  )r   rr  rB   r   r  r  rj
  r  r  r  r  r
  r   r  r  r  r   goal_max_turnsrW   )r  r  _os	_run_loop
_DEF_TURNSconntask
goal_partsr  r  r  r  r  r  r>  s   `            @@r0   _run_kanban_goal_loop_qr  "4  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	  ry  r  
list_toolslist_toolsetsgatewayr   r{  rM  r  r  r}  r  c                 J  E 	 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}|rct                      }|rt          |           t                      }|r2|a|d
         t          j        d<   t!          j        t$          |           ndS nd}| p|} d}|rt'          |t(                    r d |                    d          D             }nt'          |t,          t.          f          rqg }|D ]l}t'          |t(                    r3|                    d |                    d          D                        J|                    t)          |                     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          ||||||	|
|||||          E|"rtC          |"Ej"                  \  }#}$}%|%r'd#                    |%          }&tI          d|&           |#rDd#                    d Ej%        |#fD                       &                                E_%        |$E_'        |r/d|d
          d|d          d|d          d}'Ej%        pd|'z   E_%        |r<E(                                 E)                                 tU          j+        d           |r<E(                                 E,                                 tU          j+        d           t!          j        tZ                     Efd }(	 ddl.})|).                    |)j/        |(           |).                    |)j0        |(           tc          |)d!          r|).                    |)j2        |(           n# t          $ r Y nw xY w| s|rE3                    dti          |          "          stU          j+        d#           	 tk          | |          \  } }*g }+t          j                            d$d          &                                },|,rE	 dd%l6m7}- dd&l8m9}. |-:                                }/	 |-;                    |/|,          }0	 |/<                                 n:# t          $ r Y n.w xY w# 	 |/<                                 w # t          $ r Y w w xY wxY w|0t{          |0d'd          nd}1|1rs |.|1          \  }2}3|2rLd( |*D             }4|2D ]=}5|5|4vr7|4>                    |5           |*                    t          |5                     >|3r|+                    |3           n2# t          $ r%}6t          A                    d)|6           Y d}6~6nd}6~6ww xY w|rd*E_B        EC                                rm| }7|*s|+r6d+}8d}9	 dd,l8mD}9 dd-l8mE}: dd.lFmG};  |:EjH        pd&                                EjI        pd&                                 |;                      }8n# t          $ r d+}8Y nw xY w|8d/k    r|9	  |9t'          | t(                    r| ndd0 |*D             t-          |+          pd1          \  }<}=t          d2 |<D                       r|<}7n|*rEK                    | |*d	3          }7nD# t          $ r |*rEK                    | |*d	3          }7Y nw xY w|*rEK                    | |*d	3          }7EL                    |7          }>|>d4         EjM        k    rdE_N        EO                    |>d5         |>d6         |>                    d7          8          rd9EjN        _P        d9EjN        _Q        dEjN        _R        dEjN        _S        	 EjN        T                    |7EjU        :          }?nX# t          $ rK t          Ed;<           t          d=Ej"         tT          jX        >           tU          j+        d?           Y nw xY wt{          EjN        d@d          r&EjN        j"        Ej"        k    rEjN        j"        E_"        t'          |?t                    r|?                    dAd          nt)          |?          }@|@syt'          |?t                    rd|?                    dB          rO|?                    dC          s|?                    dD          r%t          dE|?dB          tT          jX        >           n|@rt          |@           t          j                            dF          dk    rD	 t          E|@           n2# t          $ r%}At          A                    dG|A           Y d}A~And}A~Aww xY wt          d=Ej"         tT          jX        >           d}Bt'          |?t                    ri|?                    dC          rTd#}Bt          j                            d$          r3|?                    dH          dIv r	 ddJl[m\}C |C}Bn# t          $ r d#}BY nw xY wtU          j+        |B           tU          j+        d#           nh| p|*rdKnd}D|DrEj]                            dL|D            E^                                 E_                    | |*pdM           E`                                 t          E           n# t          E           w xY wdS E	                                 dS )Na  
    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{  Fr   r6  c                 6    g | ]}|                                 S r   r  r  s     r0   r   zmain.<locals>.<listcomp>4  s     DDD1QWWYYDDDr1   rU   c                 6    g | ]}|                                 S r   r  )r   xs     r0   r   zmain.<locals>.<listcomp>4  s     )J)J)J!'')))J)J)Jr1   )coding_selectionr  )r  r   )_get_platform_tools)r"  r  r   r#  r   r  r	  r  r   r  r  r  r	  r  zUnknown skill(s): r  c              3      K   | ]}||V  	d S r   r   r   s     r0   r   zmain.<locals>.<genexpr>"5  s;       , ,t,, , , , , ,r1   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 rr  z.]rM   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   r  SIGALRMc                  *    t          j        d          S r  )r   _exit)r8  s    r0   r  z1main.<locals>._signal_handler_q.<locals>.<lambda>o5  s    ! r1   r[  )r   r  r  r  rA   r   r   r  r  r  rq  r   rr  rB   rL  r*  r  alarmrk
  r  rO  rP  r  rT  r  r  )r'  r  _agentr(  _sig_mod_lg_streamr  s          r0   _signal_handler_qzmain.<locals>._signal_handler_qO5  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  rZ  r  r  )extract_image_refsr  c                 ,    h | ]}t          |          S r   r  r   s     r0   r  zmain.<locals>.<setcomp>5      $I$I$ISVV$I$I$Ir1   z&kanban image-ref extraction failed: %sr   r_   )r  )r  r  r  c                 ,    g | ]}t          |          S r   r  r   s     r0   r   zmain.<locals>.<listcomp>5  r  r1   )
image_urlsc              3   H   K   | ]}|                     d           dk    V  dS r  r	  r   s     r0   r   zmain.<locals>.<genexpr>5  s1      &T&TquuV}}'C&T&T&T&T&T&Tr1   r  r  r"  r  r  r  Tr  r5  r6  z
session_id: r     r  r,  r  r.  r
  r+  HERMES_KANBAN_GOAL_MODEzkanban goal loop failed: %sfailure_reason)
rate_limitbilling)KANBAN_RATE_LIMIT_EXIT_CODEz[image attached]z[bold blue]Query:[/] r  )bhermes_cli.stdior  r   r   rr  r  gateway.runr  r  rk  r2  rB   rm  r  r  rW  r  r  r  r   rW   r  r   r  r  r  agent.coding_contextr  hermes_cli.tools_configr  r  r  r  r  r  r   r  r
  r   r  rx  r  rO  r	  r  r-  rL  rU  rT  r*  r+  r  r  r  r  r  rH  r  r  r  r
  r  rF  r   r   r  r3  rE  r  r  rs  r  r   r"  r2  r  rF  r[  r   rG  rj  suppress_status_outputstream_delta_callbacktool_gen_callbackr/  r_  r  rD  r  r   r  hermes_cli.kanban_dbr  r1  rg  r}  r  rK  )Fr  r  r	  r  r  r"  r   r#  r   r  r	  ry  r  r  r  r  r   r{  rM  r  r  r}  r  r  r  r  use_worktreewt_info_repotoolsets_listr  _codingr  r  parsed_skillsskills_promptloaded_skillsmissing_skillsmissing_displaywt_noter  rw  single_query_imagessingle_query_image_urls_kanban_task_idr  _extract_refs_conn_task_body	_kb_paths_kb_urls_seen_pr  effective_queryrV  _build_partsr  r  r
  rZ  rU  r   rj  r  
_exit_code_RL_CODE_query_labelr  sF                                                                        @r0   r  r  |4  sJ   ~<<<<<<!!!!   
 (+BJ#$  ------@AAAMMOO$$$  m   I1I
z5(I(I 	"$$E .&u---%''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  	E"ii77OC/CCDDD 	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! !G0/G0A%P 
PPA
k9  V. =S9 S) (V. )
S63V. 5S66V. 9T ;TT 
TT TT  BV. -k9 .
W8Wk9 W-k9 AY% $k9 %Y41k9 3Y44k9  A7[8 7k9 8$\k9 \B2k9 !_4 3k9 4Aa	k9 a		D(k9 2f k9 
f2f-(k9 -f22B
k9 =i k9 ik9 iBk9 9l
__main__r  r   r~  )r<   )r  )r  )r  )NNNNNNNNNNNFFFFFNFFFFFF(1  r  hermes_bootstrapModuleNotFoundErrorrk
  r   r  rO  r   r   concurrent.futuresr
  r  r  r1  r  r  r  r  collectionsr   urllib.parser   r   
contextlibr   pathlibr   r   typingr	   r
   r   r   r
  r  r   rr  rt  hermes_cli.fallback_configr    hermes_cli.cli_agent_setup_mixinr   hermes_cli.cli_commands_mixinr   prompt_toolkit.historyr   prompt_toolkit.stylesr   r  prompt_toolkit.patch_stdoutr   r  r   prompt_toolkit.layoutr   r   r   r   r    prompt_toolkit.layout.processorsr   r   r   r   prompt_toolkit.filtersr   prompt_toolkit.layout.dimensionr    prompt_toolkit.layout.menusr!   prompt_toolkit.widgetsr"   prompt_toolkit.key_bindingr#   prompt_toolkitr$   r  prompt_toolkit.formatted_textr%   r  prompt_toolkit.cursor_shapesr&   BLOCKrQ  rU  AttributeErrorhermes_cli.pt_input_extrasr'   r(   r)   r   r|  r  r+   r3   rH   r`   rb   rf   ri   hermes_cli.bannerrk   rl   r>  r   rm   rn   hermes_cli.browser_connectro   rp   rq   rr   hermes_cli.env_loaderrs   r  rt   r   rp  rq  _project_envr   rW   r   r   r   r   r   r   r   r   r  r2  hermes_loggingr  rs  r  rp  r  r@  r  rB   _tplrC   r  importlib.utilutilr  r  r  r  richr  rQ  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  r"  r  r  __annotations__r'  r  r  r  r  r  r-  r(  r)  rD  rG  rK  r#  rW  re  rm  rq  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rM  rN  r  rP  rA   r  rC  r[  rb  r  ry  rd  rr  r1  rQ  rP  rt  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$  r4  r   rD  rG  rJ  rl  r  r  r  r  r  rS  rx  r~  r  r  r  r  r  r  HERMES_AGENT_LOGOHERMES_CADUCEUSr  r  r  r  r  r  r  r  r  r  r  r  r2  r  r  r  r  fireFirer   r1   r0   <module>r     s    	 	 	 	
 	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 d d d d d d d d d d d d d d o o o o o o o o o o o o , , , , , , 5 5 5 5 5 5 7 7 7 7 7 7 + + + + + + 2 2 2 2 2 2 < < < < < < : : : : : :888888 &NN^$   NNN	         
 &&(((!#;=_=_ 	 	 	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 ' ' ' ' ' '  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    &C D4K    C C$J    [c3h [ [ [ [|
 _

	,,,,,,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	",	####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 $ 
   # # # #,
 ,
 ,
 ,
\ 59 : : :T : : : :z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    } }s }htCH~.F } } } }@ #  T    >2@ 2@DcN 2@d 2@ 2@ 2@ 2@j3C 3C 3C 3ClE E E E0?( ?(c ?(# ?(t ?( ?( ?( ?(D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        N 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   &   (#S (#U39=M (# (# (# (#V3 3     t d
 eTWY]^bYcTcNd    B <==, , , , , , , ,^F j$.s . . . .l%C %D % % % %,     $D $ $ $ $" " "" " "4    " " "s    3c?U38_#Dt#K PTUXPY    0& &C &D & & & &^X_G X_G X_G X_G X_G"$4 X_G X_G X_G~~W Wc Wd W W W Wv 04"!$/k kk
k k 	k
 $s)OeCHo-k k k k k k d^k k k k k  !k" #k$ %k& 'k( )k* +k, -k. /k k k k\ zKKKDIdOOOOO s   
 D 	D D $+E EE;I III+ +I32I37J	 	JJAK K&%K&*:L% %L-,L-<V VV