
    ,jp                       U d Z 	 ddlZn# e$ r Y nw xY wddlZddlZddZdaded<   defdZ	ddd	de
fd
ZddZ e             de
fdZdee         de
fdZdedz  fdZddZde
fdZ e            r ed          ddlZddlZddlZddlZddlZddlZddlmZ ddlmZ ddlmZ  ddl!m"Z" ddl#m$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 dd l9m:Z: dd!l;m<Z< dd"l=m>Z> dd#l?m@Z@ dd$lAmBZB dd%lCmDZD dd&lEmFZF dd'lGmHZH dd(lImJZJ dd)lKmLZL dd*lMmNZN dd+lOmPZP dd,lQmRZR dd-lSmTZT dd.lUmVZV dd/lWmXZX dd0lYmZZZ dd1l[m\Z\ dd2l]m^Z^ dd3l_m`Z` dd4lambZb dd5lcmdZd dd6lemfZf dd7lgmhZh dd8limjZj d9eddfd:Zk eel          jm        jm        n                                Zoejp        q                    d eeo                     dd;Zr er             dd<lsmtZt dd=lumvZv  eveod>z  ?           d@Zw	 ddlxZy et            dAz  Zzez{                                r e|ezdBC          5 Z} eyj~        e}          pi Zddd           n# 1 swxY w Y   dDej        vr^e                    dEi           Z eee          r<e                    dF          Ze% ee                                          ej        dD<   e                    dGi           Z eee          re                    dH          rdIZw[[zn# e$ r Y nw xY w	 ddJlmZ  e edK ej        dLd         D             dM          dNv rdOndPQ           n# e$ r Y nw xY wewr	 ddRlmZ  edIS           n# e$ r Y nw xY wddlZddlZddlZddTlmZ ddUlmZmZ ddVlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ  ej        e          ZddWeeef         dz  de
fdXZdYedZededz  fd[Zd\ededz  fd]Zdefd^Zdefd_Zde
fd`ZddaZde
fdbZde
fdcZdefddZde
fdeZdfedee         fdgZddhedee         fdiZddjedkedle
fdmZdnedoefdpZdqedee         fdrZdsee         dee         fdtZ	 dduee         dvee         ddfdwZ edxdyh          Z	 dzedefd{Zd@d|dzed}e
deeeed~f         f         fdZdede
fdZdZdZ eh d          ZdefdZdede
fdZ̐ddZ͐ddedz  dedz  fdZdede
deee         ef         fdZdedee         fdZdee         fdZӐddedefdZ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddee         de
dee         dee         dededee
         de
dee         dee         de
de
de
dee         de
fdZՐddZ֐ddZde
fdZd Zd Zd Zd Zd Zd Zd Zd Zdede
fdZddZd Zg dZeeeeef                  ed<   deeeeef                  fdZdedefdZdMdMdMddedededededdfdZdefdZddZdeddfdZ	 ddededededdf
dZdededdfdZdddÜdĄZddgZddededee         fdȄZdedefdɄZddʄZdd˄Z	 dd̄Zd̈́ ZdZdτ ZdefdЄZdeddfd҄ZddӄZddededefdՄZdedefdքZdedefd؄Zdل Zdڄ Zdۄ Zd܄ Z d݄ Zdބ Zd߄ Zd Zd Zd Zd Zd Zd Z	d Z
d Zd Zd ZdIdde
ddfdZd Zd ZdedefdZdZdedz  fdZdee
edz  edz  f         fdZddedededefdZdede
fdZddddjee         dedededej        f
d Zdeeef         dz  fdZddIdddededeed~f         de
dWeeef         dz  dej        fdZd@dded	e
de
fd
Zdede
fdZdedefdZdefdZdedede
de
fdZ dede
ddfdZ!dedee         fdZ"dee         fdZ#dedee         fdZ$dedee         fdZ%deddfdZ&dede
fdZ'dej(        fdZ)ddde*e         dz  dee         fdZ+ddZ,dd Z-d!edefd"Z.	 dd$eddfd%Z/e/Z0d& Z1d'ee         dedee         fd(Z2d'ee         ded)edee         fd*Z3	 dd)ed+ee         ddfd,Z4	 	 dd'ee         ded)ed-e
de
f
d.Z5d'ee         ded)ede
fd/Z6h d0Z7d1Z8d2Z9d'ee         dedee         fd3Z:d4ee         de
fd5Z;d'ee         dede
fd6Z<d'ee         dede
fd7Z=d'ee         ded8ed9edef
d:Z>de
fd;Z?d< Z@d'ee         dede
fd=ZAd'ee         deddfd>ZBd? ZCddAedee         fdBZDdefdCZEddDZFddEZGddFZHddGdHdjee         dWeeef         dz  dIeddfdJZIde
fdKZJdedz  fdLZKdMedee         fdNZLddOdMedPedz  deeeef                  fdQZMdReeeef                  dMedefdSZNdTdUdMedVedeeeef                  fdWZOdXedYede
fdZZPd[eeeef                  ddfd\ZQddd]djee         dWeeef         dz  dMedz  ddfd^ZRddMedz  ddfd_ZSdd`ZTdd@dadbee         dWeeef         dz  dAeddfdcZUdd@dadbee         dWeeef         dz  dAeddfddZVdbee         dWeeef         dz  dedz  fdeZWddWeeef         dz  de
fdfZXde
fdgZYddhdbee         dWeeef         dz  ddfdiZZdjee         dedz  fdkZ[ddlZ\ G dm dn          Z]ddoe
fdpZ^dq Z_defdrZ`dd@dtduedve
fdwZaddxZbddyZcdz Zdd{ Zed| Zfdoe
fd}Zgdedefd~Zhd ZiddZjdefdZkdedede
fdZld Zmd ZnddZod Zpd Zq eh d          Zr eh d          Zsdedz  fdZtde
fdZuh dZvdddhfddhfddhfdZwde
fdZxde
fdZyde
fdZzddZ{ddZ|de
fdZ}de
fdZ~d Zd Zd Zd Zd Zd Zd Zd Zd Zd Zedk    r e             dS dS (  u	  
Hermes CLI - Main entry point.

Usage:
    hermes                     # Interactive chat (default)
    hermes chat                # Interactive chat
    hermes gateway             # Run gateway in foreground
    hermes gateway start       # Start gateway as service
    hermes gateway stop        # Stop gateway service
    hermes gateway status      # Show gateway status
    hermes gateway install     # Install gateway service
    hermes gateway uninstall   # Uninstall gateway service
    hermes setup               # Interactive setup wizard
    hermes logout              # Clear stored authentication
    hermes status              # Show status of all components
    hermes cron                # Manage cron jobs
    hermes cron list           # List cron jobs
    hermes cron status         # Check if cron scheduler is running
    hermes doctor              # Check configuration and dependencies
    hermes honcho setup                    # Configure Honcho AI memory integration
    hermes honcho status                   # Show Honcho config and connection status
    hermes honcho sessions                 # List directory → session name mappings
    hermes honcho map <name>               # Map current directory to a session name
    hermes honcho peer                     # Show peer names and dialectic settings
    hermes honcho peer --user NAME         # Set user peer name
    hermes honcho peer --ai NAME           # Set AI peer name
    hermes honcho peer --reasoning LEVEL   # Set dialectic reasoning level
    hermes honcho mode                     # Show current memory mode
    hermes honcho mode [hybrid|honcho|local]  # Set memory mode
    hermes honcho tokens                   # Show token budget settings
    hermes honcho tokens --context N       # Set session.context() token cap
    hermes honcho tokens --dialectic N     # Set dialectic result char cap
    hermes honcho identity                 # Show AI peer identity representation
    hermes honcho identity <file>          # Seed AI peer identity from a file (SOUL.md etc.)
    hermes honcho migrate                  # Step-by-step migration guide: OpenClaw native → Hermes + Honcho
    hermes version             Show version
    hermes update              Update to latest version
    hermes uninstall           Uninstall Hermes Agent
    hermes acp                 Run as an ACP server for editor integration
    hermes sessions browse     Interactive session picker with search

    hermes claw migrate --dry-run  # Preview migration without changes
    Nreturnc                     	 ddl } |                      d           dS # t          $ r Y nw xY wddl}ddl}	 |                                }|dk    r2|                    dd          }|                    dd	ddd           dS |d
k    r.|                    dd          }|                    d	           dS dS # t          $ r Y dS w xY w)ud  Set the process title to 'hermes' so tools like 'ps', 'top', and
    'htop' show the app name instead of 'python3.xx'.

    Purely cosmetic — non-fatal on any platform.

    Strategy (try in order):
      1. ``setproctitle`` (opt-in dep — installed via ``hermes tools`` or
         ``pip install setproctitle``, or bundled in a future release).
      2. ctypes ``prctl(PR_SET_NAME)`` (Linux only, 15-char limit).
      3. ctypes ``pthread_setname_np`` (macOS only, kernel thread name —
         changes lldb/top but not ``ps aux``).
      4. No-op on Windows (the .exe name is already ``hermes.exe``).
    r   NhermesLinuxz	libc.so.6T)	use_errno   s   hermesDarwinz
libc.dylib)	setproctitleImportErrorctypesplatformsystemCDLLprctlpthread_setname_np	Exception)r
   r   r   r   libcs        4/home/ubuntu/.hermes/hermes-agent/hermes_cli/main.py_set_process_titler   D   s   !!(+++    MMMOOO
""W;;{d;;;DJJr9aA.....x;;|t;<<D##I.....      s$    
**A
B8 2B8 8
CCzlist | None_EARLY_INTERFACE_CACHEc                  (   t           t           d         S d} 	 t          j                            d          }|r!t          j                            |d          }n>t          j                            t          j                            d          dd          }t          j                            |          rddl}t          |d	          5 }|
                    |          pi }ddd           n# 1 swxY w Y   |                    d
i           }t          |t                    rV|                    d          }t          |t                    r,|                                                                dk    rd} n# t           $ r d} Y nw xY w| ga | S )zReturn the configured default interface ("cli"/"tui") via a minimal
    YAML read. Best-effort: any error falls back to "cli" (legacy behavior).Nr   cliHERMES_HOMEconfig.yaml~.hermesutf-8encodingdisplay	interfacetui)r   osenvirongetpathjoin
expanduserexistsyamlopen	safe_load
isinstancedictstrstriplowerr   )valuehomecfg_path_yaml_iface_frawdispifaces           r   _config_default_interface_earlyr:   t   s    )%a((Ez~~m,, 	Ww||D-88HHw||BG$6$6s$;$;YVVH7>>(## 		"&&&&h111 6R!++B//526 6 6 6 6 6 6 6 6 6 6 6 6 6 6779b))D$%% "--eS)) "ekkmm.A.A.C.Cu.L.L!E   #WLs7   B4E= C0$E= 0C44E= 7C48BE= =FFargvzlist[str] | Nonec                     | t           j        dd         } d| v rdS t          j                            d          dk    sd| v rdS t                      d	k    S )
zEarliest TUI decision, usable before argparse/config imports.

    Precedence: explicit ``--cli`` wins (forces classic REPL), then
    ``--tui``/``HERMES_TUI=1``, then ``display.interface`` in config.
    N   z--cliF
HERMES_TUI1z--tuiTr"   )sysr;   r#   r$   r%   r:   r;   s    r   _wants_tui_earlyrB      s]     |x|$u	z~~l##s**goot*,,55    c                      t           j                            d          dk    rd S t                      sd S 	 t          j        d          sd S t          j        dd           d S # t          $ r Y d S w xY w)NHERMES_TUI_NO_EARLY_DISABLEr?   r=   sM   [?1003l[?1002l[?1001l[?1000l[?9l[?1006l[?1005l[?1015l[?1016l[?2029l)r#   r$   r%   rB   isattywriteOSError rC   r   _suppress_mouse_residue_earlyrJ      s    	z~~344;;  y|| 	F 	G	
 	
 	
 	
 	

    s   A$ A$ $
A21A2c                      t           j                            dd          } t          t           j                            d          pd| v p|                     d                    S )z3Tiny Termux check for pre-import startup shortcuts.PREFIX TERMUX_VERSIONcom.termux/files/usr/data/data/com.termux/)r#   r$   r%   bool
startswithprefixs    r   #_is_termux_startup_environment_fastrU      s_    Z^^Hb))F

'(( 	7!V+	7566  rC   c                     | dgdgdgfv S )N	--versionz-VversionrI   rA   s    r   _is_termux_fast_version_argvrY      s    [MD6I;777rC   c                  D   t           j        D ]} | st          j                    } t          j                            | dd          }	 t          |d          5 }|D ]}|                                }|                    d          s,|                    d          \  }}}|	                    dd          d	                                                             d
          }|pdc cddd           c S 	 ddd           n# 1 swxY w Y   # t          $ r Y w xY wdS )zARead OpenAI SDK version without importing ``importlib.metadata``.openaiz_version.pyr   r   __version__=#r=   r   z"'N)r@   r&   r#   getcwdr'   r+   r0   rR   	partitionsplitrH   )baseversion_filehandlelinestripped_key_sepr2   s           r   _read_openai_version_fastri      s      	9;;Dw||D(MBB
	lW555 )" ) )D#zz||H#..}== ! (0(:(:3(?(?%D$!KKQ//288::@@GGE =D(() ) ) ) ) ) ) ) ) ))) ) ) ) ) ) ) ) ) ) ) ) ) ) )  	 	 	H	4s=   DBD&D6DD	D	D	
D
DDc                     ddl m} m} t          j                            t          j                            t          j                            t                    t          j	                            }t          d| d|  d           t          d|            t          dt          j                                        d                     t                      }t          |rd| nd	           d S )
Nr   )__release_date__r\   zHermes Agent v ()	Project: Python: OpenAI SDK: OpenAI SDK: Not installed)
hermes_clirk   r\   r#   r&   abspathr'   dirname__file__pardirprintr@   rX   ra   ri   )rk   r\   project_rootopenai_versions       r   _print_fast_version_inforz      s    888888887??27<<0I0I29#U#UVVL	
=;
=
=*:
=
=
=>>>	
$l
$
$%%%	
-S[&&((+
-
-....00N	^
\
)
)
)
)A\]]]]]rC   c                      t           j                            d          dk    rdS t                      sdS t	          t
          j        dd                   sdS t                       dS )zDHandle ``hermes --version`` before config/logging imports on Termux.HERMES_TERMUX_DISABLE_FAST_CLIr?   Fr=   NT)r#   r$   r%   rU   rY   r@   r;   rz   rI   rC   r   _try_termux_ultrafast_versionr}      sd    	z~~6773>>u.00 u'55 u4rC   )Path)Optional)add_accept_hooks_flag)build_cron_parser)build_gateway_parser)build_profile_parser)build_model_parser)build_setup_parser)build_postinstall_parser)build_whatsapp_parser)build_slack_parser)build_login_parser)build_logout_parser)build_auth_parser)build_status_parser)build_webhook_parser)build_hooks_parser)build_doctor_parser)build_security_parser)build_dump_parser)build_debug_parser)build_backup_parser)build_import_cmd_parser)build_config_parser)build_version_parser)build_update_parser)build_uninstall_parser)build_dashboard_parser)build_gui_parser)build_logs_parser)build_prompt_size_parser)build_memory_parser)build_acp_parser)build_tools_parser)build_insights_parser)build_skills_parser)build_pairing_parser)build_plugins_parser)build_mcp_parser)build_claw_parsercommand_namec                     t           j                                        s5t          d|  dt           j                   t          j        d           dS dS )a  Exit with a clear error if stdin is not a terminal.

    Interactive TUI commands (hermes tools, hermes setup, hermes model) use
    curses or input() prompts that spin at 100% CPU when stdin is a pipe.
    This guard prevents accidental non-interactive invocation.
    zError: 'hermes z' requires an interactive terminal.
It cannot be run through a pipe or non-interactive subprocess.
Run it directly in your terminal instead.filer=   N)r@   stdinrF   rw   stderrexit)r   s    r   _require_ttyr   1  sk     9 9l 9 9 9 		
 	
 	
 	
 	 rC   c                  8   t           j        dd         d} d}d}dt          dt          ffd}h d}dd	h}d}|t	                    k     r|         }|d
k    rn|dk    r ||          rn|dv r&|dz   t	                    k     r|dz            } d}|}n|                    d          r!|                    dd          d         } d}|}n~d|vr ||v r|dz   t	                    k     r|dz  }nGd|vr>||v r:|dz   t	                    k     r$|dz                                d          s|dz  }n|dz  }|t	                    k     | &|dk    r ddl}|                    d|           sd} d}d}t          j
                            dd          }	| !|	rt          |	          j        j        dk    rdS | r	 ddlm}
  |
            dz  }|                                r2|                                                                }|r
|dk    r|} d}n# t(          t*          f$ r Y nw xY w| 	 ddlm}  ||           }n# t0          t2          f$ r<}t5          d| t           j                   t          j        d           Y d}~n:d}~wt:          $ r*}t5          d| dt           j                   Y d}~dS d}~ww xY w|t          j
        d<   |dk    rA|A|dz   }t           j        d|         t           j        ||z   d         z   t           _        dS dS dS dS )z:Pre-parse --profile/-p and set HERMES_HOME before imports.r=   Nr   indexr   c                     	                      dd|           }                     d|dz   |            n# t          $ r Y dS w xY wdS )a"  True once argv reaches `hermes mcp add ... --args <command argv>`.

        ``mcp add --args`` is command-argv passthrough. Flags after that point
        belong to the child MCP command (for example Docker MCP Toolkit's
        ``--profile``), not to Hermes' own profile selector.
        mcpr   addr=   FT)r   
ValueError)r   	mcp_indexr;   s     r   _inside_mcp_add_argsz5_apply_profile_override.<locals>._inside_mcp_add_argsW  sa    	

5!U33IJJui!mU3333 	 	 	55	ts   15 
AA>   -m-r-s-t-z--model--resume--skills	--oneshot
--provider
--toolsets-c
--continue--z--args>   	--profile-p   z
--profile=r]   -z^[a-z0-9][a-z0-9_-]{0,63}$r   rM   profilesget_default_hermes_rootactive_profiledefault)resolve_profile_envError: r   z"Warning: profile override failed (z), using default)r@   r;   intrQ   lenrR   ra   rematchr#   r$   r%   r~   parentnamehermes_constantsr   r)   	read_textr0   UnicodeDecodeErrorrH   hermes_cli.profilesr   r   FileNotFoundErrorrw   r   r   r   )profile_nameconsumeprofile_indexr   value_flagsoptional_value_flagsiarg_rehermes_home_envr   active_pathr   r   hermes_homeexcstartr;   s                    @r   _apply_profile_overrider   P  s+   8ABB<DLGMC D      "  K !,/	A
c$ii--1g$;;(??33A66?%%%!a%#d))*;*;A;LGM>>,'' 	99S!,,Q/LGMc>>c[00QUSYY5F5FFAAsNN+++AD		!!QK**3// " FAAFA5 c$ii--@ GqLLyy6EE 	!LG M jnn]B77O  ',
::F 
	@@@@@@11336FFK!!##  ",,..4466  DI--#'LG"G, 	 	 	D	 	??????--l;;KK-. 	 	 	/C//
3333HQKKKKKKKK 	 	 	JSJJJZ    FFFFF	 %0
=!Q;;=4!A%Ex'#(57?3D3D*EECHHH'  " ;44s7   :AH H('H(.I   J?2JJ?J::J?get_hermes_home)load_hermes_dotenv.env)project_envFr   r   r   HERMES_REDACT_SECRETSsecurityredact_secretsnetwork
force_ipv4Tsetup_loggingc              #   D   K   | ]}|                     d           |V  dS r   NrR   .0r   s     r   	<genexpr>r     s3      LLSs8K8KLSLLLLLLrC   r=   rM   >   guidesktop	dashboardr   r   mode)apply_ipv4_preferenceforce)datetime)r\   rk   )_prompt_auth_credentials_choice_model_flow_openrouter_model_flow_nous_model_flow_openai_codex_model_flow_xai_oauth_model_flow_qwen_oauth_model_flow_minimax_oauth_model_flow_google_gemini_cli_model_flow_custom_model_flow_azure_foundry_model_flow_named_custom_model_flow_copilot_model_flow_copilot_acp_model_flow_kimi_model_flow_stepfun_model_flow_bedrock_api_key_model_flow_bedrock_model_flow_api_key_provider_model_flow_anthropicenvc                     | pt           j        }t          |                    dd                    }t	          |                    d          pd|v p|                    d                    S )z<Import-safe Termux check for cold-start-sensitive CLI paths.rL   rM   rN   rO   rP   )r#   r$   r/   r%   rQ   rR   )r  checkrT   s      r   _is_termux_startup_environmentr  4  so    2:E8R(())F		"## 	7!V+	7566  rC   
common_dirrefc                    	 | dz                       dd          }n# t          $ r Y dS w xY w|                                D ]}|r*|                    d          s|                    d          r/|                    dd	          }t          |          d
k    r:|d	                                         |k    r|d                                         c S dS )zLook up a ref in .git/packed-refs without spawning git.

    packed-refs lines look like ``<sha> <ref>`` with optional ``^<sha>``
    peel lines and ``#``-prefixed comments / ``# pack-refs with:`` header.
    zpacked-refsr   replacer   errorsNr^   ^ r=   r   r   )r   rH   
splitlinesrR   ra   r   r0   )r  r  textre   partss        r   _read_packed_refr%  ?  s    ]*55wy5YY   tt!! $ $ 	ts++ 	ts/C/C 	

3""u::??uQx~~//3668>>#####4s    
++	repo_rootc                 <   | dz  }	 |                                 r|                    dd                                          D ]r}|                    d          \  }}}|                                dk    r?|                                r+| |                                z                                  } ns|}|dz  }|                                rT	 |                    dd                                          }|r||z                                  }n# t          $ r Y nw xY w|dz  }	|	                    dd                                          }
|
                    d	          r|
	                    dd
          d
                                         }||fD ]L}||z  }|                                r1d| d|                    dd                                           c S Mt          ||          }|rd| d| S d| dS d|
 S # t          $ r Y dS w xY w)z9Return a cheap checkout fingerprint without spawning git..gitr   r  r  :gitdir	commondirHEADzref:r=   zgit:z:unresolvedz	git:HEAD:N)is_filer   r"  r`   r0   resolver)   rH   rR   ra   r%  )r&  git_dirre   key_r2   r  commondir_filerel	head_fileheadr  	candidateref_file
packed_shas                  r   _read_git_revision_fingerprintr9  R  s   & G'?? 	))79)MMXXZZ   $s 3 3Q99;;(**u{{}}*(5;;==8AACCGE 
 ;.  "" 	$..	.RRXXZZ ;")C-!8!8!:!:J   f$	""GI"FFLLNN??6"" 	+**S!$$Q'--//C &z2 i i	$s???$$ ih#hh(:(:GT](:(^(^(d(d(f(fhhhhhi)*c::J 10c00J000 +#****!4!!!   ttsJ   CH AD H 
D# H "D##CH 'H H H 
HHc                      t          t                    } | r| S t          dz  }	 |                                }dt           dt           d|j         d|j         S # t          $ r dt           dt           dcY S w xY w)z=Cheap invalidation key for Termux bundled-skill startup sync.skillszskills:r)  z:missing)r9  PROJECT_ROOTstatr\   rk   st_mtime_nsst_sizerH   )git_fp
skills_dirr=  s      r   "_termux_bundled_skills_fingerprintrB    s    +L99F (JB  [[['7[[$:J[[T\[[[ B B BAAA'7AAAAAABs   5A A:9A:c                  *    t                      dz  dz  S )Nr;  z.termux_bundled_sync_stampr   rI   rC   r   !_termux_bundled_skills_stamp_pathrD    s    x'*FFFrC   c                     t                      sdS t          j                            d          dk    rdS 	 t	                      } |                     d                                          t                      k    S # t          $ r Y dS w xY w)NTHERMES_TERMUX_FORCE_SKILLS_SYNCr?   r   r   )	r  r#   r$   r%   rD  r   r0   rB  rH   stamps    r   "_termux_bundled_skills_sync_neededrI    s    )++ t	z~~788C??t133006688<^<`<```   tts   AA= =
B
Bc                      t                      sd S 	 t                      } | j                            dd           |                     t                      dz   d           d S # t          $ r Y d S w xY w)NTparentsexist_ok
r   r   )r  rD  r   mkdir
write_textrB  rH   rG  s    r   "_mark_termux_bundled_skills_syncedrQ    s    )++ 1334$777;==DwWWWWW   s   AA$ $
A21A2c                      t                      rt                      sdS ddlm}   | d           t	                       dS )a  Sync bundled skills, but skip unchanged Termux checkouts cheaply.

    Hashing every bundled skill is safe but expensive on older Android
    storage. The git/ref stamp keeps post-update correctness: a changed
    checkout revision forces one real sync, then later starts skip it.
    Fr   sync_skillsTquiet)r  rI  tools.skills_syncrT  rQ  rS  s    r    _sync_bundled_skills_for_startuprX    s[     &'' 0R0T0T u------Kd&(((4rC   c                  h    t                      sdS t          j                            d          dk    S )NTHERMES_TERMUX_PREFETCH_UPDATESr?   )r  r#   r$   r%   rI   rC   r   $_termux_should_prefetch_update_checkr[    s/    )++ t:>>:;;sBBrC   c                 F   | sdS t          j                    | z
  }|dk     rdS |dk     rt          |dz             dS |dk     rt          |dz             dS |dk     rd	S |d
k     rt          |dz             dS t          j        |                               d          S )zBFormat a timestamp as relative time (e.g., '2h ago', 'yesterday').?<   just now  m agoQ h agoi  	yesterdayi:	 d agoz%Y-%m-%d)_timetimer   r  fromtimestampstrftime)tsdeltas     r   _relative_timerl    s     sJLL2Erzzzt||ebj//((((u}}edl##****v~~{v~~eem$$++++!"%%..z:::rC   c                     ddl m} m}m} ddlm} ddl m} |                    dd          } |            }|                    d          }t          |t                    r*|                    d          pd
                                }n,t          |t                    r|
                                }nd}|o||k    }	ddlm}
 h d	}|
                                D ]'}|j        d
k    r|                    |j                   (t#          d |D                       rdS  |             }|                                r	 |                    d                                          D ]}|
                                }|                    d          sd|vr0|                    d          \  }}}|
                                
                    d          }|
                                |v r|r dS n# t.          $ r Y nw xY w	 |
                                D ]4\  }}|j        d
k    r ||          }|                    d          r dS 5n# t.          $ r Y nw xY w |            dz  }|                                rq	 ddl} |j        |                                          }|                    d          }|r" ||          }|                    d          rdS n# t.          $ r Y nw xY wt          |t                    r|                    d          pd
                                }|                    d          pd
                                }|                    d
          pd
                                }|s|s|rdS |	rH	 ddlm}m}  |            }|r" ||          s|                    d          rdS n# t.          $ r Y nw xY wdS )z3Check if at least one inference provider is usable.r   )get_env_pathr   load_config)get_auth_status)DEFAULT_CONFIGmodelrM   r   )PROVIDER_REGISTRY>   OPENAI_API_KEYANTHROPIC_TOKENOPENAI_BASE_URLANTHROPIC_API_KEYOPENROUTER_API_KEYapi_keyc              3   >   K   | ]}t          j        |          V  d S N)r#   getenv)r   vs     r   r   z/_has_any_provider_configured.<locals>.<genexpr>  s*      
3
3A29Q<<
3
3
3
3
3
3rC   Tr   r   r^   r]   z'"	logged_inz	auth.jsonNactive_providerproviderbase_url)read_claude_code_credentialsis_claude_code_token_validrefreshTokenF)hermes_cli.configrn  r   ro  hermes_cli.authrp  rq  r%   r-   r.   r0   r/   rs  values	auth_typeupdateapi_key_env_varsanyr)   r   r"  rR   r`   r   itemsjsonloadsagent.anthropic_adapterr  r  )rn  r   ro  rp  rq  _DEFAULT_MODELcfg	model_cfg_model_name_has_hermes_configrs  provider_env_varspconfigenv_filere   r0  r1  valprovider_idstatus	auth_filer  authactivecfg_providercfg_base_urlcfg_api_keyr  r  credss                                 r   _has_any_provider_configuredr    s   LLLLLLLLLL////// 100000#''44N
+--C  I)T""  }}Y//52<<>>	Is	#	# oo''$F)F
 211111   %++-- ? ?	))$$W%=>>>

3
3!2
3
3
333 t |~~H 
	 **G*<<GGII    zz||??3'' 3d??"nnS11Qiikk''..99;;"333344   	 	 	D	$5$;$;$=$= 	 	 K I--$_[11Fzz+&& tt		      !!K/I 
	KKK4:i113344DXX/00F  (00::k**  4 	 	 	D	 )T"" !j117R>>@@!j117R>>@@ }}Y//52<<>> 	< 	; 	4
  	       
 1022E **5115:YY~5N5N t 	 	 	D	 5sW   ?B1G4 2G4 4
H HAI I 
IIAK! !
K.-K.4O 
OOsessionsc                      st          d           dS 	 ddldgd d  fd}                    |           d         S # t          $ r Y nw xY wt          d           t	                     D ]\  }}|                    d          pd	                                }|                    d
          pd	                                }|p	|p|d         }t          |          dk    r|dd         dz   }t          |                    d                    }|                    dd	          dd         }t          d|dz   dd|dd|dd|            	 	 t          dt                      d                                          }	|	r|	
                                dv rdS t          |	          dz
  }
d|
cxk    rt                     k     rn n |
         d         S t          dt                      d           n@# t          $ r t          d           Y n%t          t          f$ r t                       Y dS w xY w)a  Interactive curses-based session browser with live search filtering.

    Returns the selected session ID, or None if cancelled.
    Uses curses (not simple_term_menu) to avoid the ghost-duplication rendering
    bug in tmux/iTerm when arrow keys are used.
    No sessions found.Nr   c                    |                      d          pd                                }|                      d          pd                                }|                      dd          dd         }t          |                      d                    }| d         dd	         }d
}t          d||z
            }|r|d|         }	n|r|d|         }	n|}	|	d| d|dd|dd| S )z!Format a session row for display.titlerM   previewsourceN   last_activeid   -      <  <10<5r!  )r%   r0   rl  max)
smax_xr  r  r  r  sid
fixed_cols
name_widthr   s
             r   _format_rowz+_session_browse_picker.<locals>._format_rowS  s   UU7^^)r0022EuuY''-24466GUU8R((!,F(})=)=>>KD'#2#,C -JR!344J [j[) {
{+PZPPPPKPPPvPPP3PPPrC   c                    |                                 }||                     d          pd                                 v p||                     d          pd                                 v pT||                     dd                                           v p*||                     d          pd                                 v S )z?Check if a session matches the search query (case-insensitive).r  rM   r  r  r  )r1   r%   )r  queryqs      r   _matchz&_session_browse_picker.<locals>._matchi  s    AaeeGnn*11333 8y))/R668888dB--///8 x.B55777	rC   c           
      *                        d                                           r                                                                                      dj        d                               dj        d                               dj        d                               dj        dk    rdnj	        d           d}d}dt                    }	 |                                  |                                 \  }}|d
k     s|dk     rS	 |                     ddd           n# j        $ r Y nw xY w|                                  |                                  d S r:d d}j        }                                r|                    d          z  }n5d}j        }                                r|                    d          z  }	 |                     dd||dz
  |           n# j        $ r Y nw xY wd}t)          d||z
            }	ddd|	 dddddddd }
	                                 r                    d          nj        }|                     dd|
|dz
  |           n# j        $ r Y nw xY w|dz
  }t)          |d          }|s7	 d}|                     dd||dz
  j                   nB# j        $ r Y n5w xY w|t-          |          k    rt-          |          dz
  }t)          |d          }||k     r|}n|||z   k    r||z
  dz   }t/          t1          |t3          t-          |          ||z                                 D ]\  }}|dz   }||dz
  k    r n||         }||k    rdnd}| ||dz
            z   }j        }||k    r3j        }                                r|                    d          z  }	 |                     |d||dz
  |           # j        $ r Y w xY w|dz
  }|rPd|dz    dt-          |           d}t-          |          t-                    k     r|d t-                     d!z  }nd"t-                     d}	 |                     |d||dz
                                  r                    d          nj                   n# j        $ r Y nw xY w|                                  |                                 }|j        hv r|r|dz
  t-          |          z  }n|j        hv r|r|dz   t-          |          z  }n|j        d#d$hv r|r||         d%         d<   d S |d&k    rrdt                    }d}d}nd S |j        d'dhv r2r/d d         rfd(D             }nt                    }d}d}nL|t?          d)          k    rsd S d*|cxk    rd+k    r(n n%tA          |          z  fd,D             }d}d}.)-Nr   r=   r            rM   T   (   zTerminal too smallu     Browse sessions — filter: u   █uM     Browse sessions — ↑↓ navigate  Enter select  Type to filter  Esc quitr  r  z   zTitle / Previewr  r  Activer  Srcr  r!  IDz  No sessions match the filter.    → /	 sessionsz (filtered from rm   z  0/
      r        c                 ,    g | ]} |          |S rI   rI   r   r  r  search_texts     r   
<listcomp>zB_session_browse_picker.<locals>._curses_browse.<locals>.<listcomp>  s*    'V'V'Vavva?U?U'V'V'V'VrC   r      ~   c                 ,    g | ]} |          |S rI   rI   r  s     r   r  zB_session_browse_picker.<locals>._curses_browse.<locals>.<listcomp>  s*    NNNavva7M7MNNNNrC   )!curs_set
has_colorsstart_coloruse_default_colors	init_pairCOLOR_GREENCOLOR_YELLOW
COLOR_CYANCOLORSCOLOR_WHITElistcleargetmaxyxaddstrerrorrefreshgetchA_BOLD
color_pairaddnstrr  A_DIMr   	enumeraterangeminA_NORMALKEY_UPKEY_DOWN	KEY_ENTERKEY_BACKSPACEordchr)stdscrcursorscroll_offsetfilteredmax_yr  headerheader_attrr  r  
col_headerdim_attrvisible_rowsmsgdraw_ir   yr  arrowrowattrfooter_yfooterr0  r  r  r  cursesresult_holderr  s                           @r   _curses_browsez._session_browse_picker.<locals>._curses_browses  s   OOA  "" X""$$$))+++  F$6;;;  F$7<<<  F$5r:::  ):):AA@RTVWWWFMKH~~HM&%00u199

a,@AAAA!<   NN$$$LLNNNF  	<NkNNNF"(-K((** <#v'8'8';';;lF"(-K((** <#v'8'8';';;NN1aKHHHH|   D 1
 UZ%788
g#4gzgggghgggV[gggaegg
060A0A0C0CU))!,,,  NN1aUQYIIII|   D  %qy"<33   #!?q!S%!)V\JJJJ!<    X..!$X!2 ^^F--(.=<#???(.(=(A%.)H}|/KLL & & ! !	 #QJ	>>!E$QK+,;;E#kk!UQY&?&??%;;#)=D%0022 = $(9(9!(<(< <!"NN1aeaiFFFF%| ! ! ! D! !19 =G&1*GGs8}}GGGF8}}s8}}44"ES]]"E"E"EE<CMM<<<F	NN 	060A0A0C0CU))!,,,    |   D    llnn6=*** >"(1*H!=V_... >"(1*H!=V-r2666 B+3F+;D+Aa(FBYY" &(#'>>!"() V13:::" *&1#2#&6& 6'V'V'V'V'V8'V'V'VHH'+H~~H!"()CHH__[_F3%%%%#%%%%%3s88+KNNNNN8NNNHF$%M[M&sn   D7 7
EE#H   
HH:AJ 
JJ/#K 
K"!K")P
PPA
S 
SSz:
  Browse sessions  (enter number to resume, q to cancel)
r  rM   r  r  2   /   ...r  r  r  r  r=   z>3. <50r  Tz
  Select [1-]: >   r  r   quitz  Invalid selection. Enter 1-z or q to cancel.z/  Invalid input. Enter a number or q to cancel.)rw   r  wrapperr   r  r%   r0   r   rl  inputr1   r   r   KeyboardInterruptEOFError)r  r
  r   r  r  r  labelr  srcr  idxr  r  r  r	  s   `          @@@@r   _session_browse_pickerr  B  s     "###tG	Q 	Q 	Q,	 	 	\	& \	& \	& \	& \	& \	& \	& \	& \	&| 	~&&&Q    

HIII(## F F1w%2,,..55##)r0022++AdGu::??#2#J&E$QUU=%9%9::eeHb!!"1"%D1q5DDDuDDDKDDDsDDEEEE	;X;;;<<BBDDC #))++)>>>tc((Q,CC''''#h--'''''}T**Q#h--QQQRRRR 	E 	E 	ECDDDDD!8, 	 	 	GGG44	s6   2A 
AA"A
H .<H + H I	'I	I	r  c                    d}	 ddl m}  |            }|                    | d          }|r|d         d         nd	 |&	 |                                 S # t          $ r Y S w xY wS # t          $ r Y nw xY w	 |&	 |                                 n># t          $ r Y n2w xY wn-# |&	 |                                 w # t          $ r Y w w xY ww xY wdS )z7Look up the most recently-used session ID for a source.Nr   	SessionDBr=   )r  limitr  )hermes_stater  search_sessionscloser   )r  dbr  r  s       r   _resolve_last_sessionr"  3  sE   	B******Y[[%%V1%==$,6x{4  $6 >



        >



    2>



    
 4sk   8A&  A
A"!A"&
A30B  2A33B  :B 
BB C
$B98C
9
CC
CC
cmdbackendvia_sudoc                     	 t          j        | ddd          S # t           j        $ rC |rd| n|}t          d| d| dt          j                   t	          j        d	           Y d
S w xY w)zRun a container inspect probe, returning the CompletedProcess.

    Catches TimeoutExpired specifically for a human-readable message;
    all other exceptions propagate naturally.
    Tr   capture_outputr#  timeoutzsudo zError: timed out waiting for z to respond.
The z+ daemon may be unresponsive or starting up.r   r=   N)
subprocessrunTimeoutExpiredrw   r@   r   r   )r#  r$  r%  r  s       r   _probe_containerr-  G  s    	~c$T2NNNN$   %-:!!!!7HE H HH H H	
 	
 	
 	

 	s    AA,+A,container_infocli_argsc                 L   | d         }| d         }| d         }| d         }t          j        |          }|s3t          d| dt          j                   t          j        d           d	}t          |d
dd|g|          }|j        dk    rt          j        d          }|rt          |d|d
dd|g|d          }	|	j        dk    rjt          d| d| d| d| dt          j	        dd           d| dd
                    |           t          j                   t          j        d           nKt          d| d| dd
                    |           t          j                   t          j        d           t          j                                        }
|
rdgndg}g }dD ]?}t          j                            |          }|r|                    d | d!| g           @|r|d|gn|g}|d"gz   |z   d#|gz   |z   ||gz   |z   }t          j        |d         |           d	S )$a  Replace the current process with a command inside the managed container.

    Probes whether sudo is needed (rootful containers), then os.execvp
    into the container. On success the Python process is replaced entirely
    and the container's exit code becomes the process exit code (OS semantics).
    On failure, OSError propagates naturally.

    Args:
        container_info: dict with backend, container_name, exec_user, hermes_bin
        cli_args: the original CLI arguments (everything after 'hermes')
    r$  container_name	exec_user
hermes_binr   z. not found on PATH. Cannot route to container.r   r=   Ninspectz--formatokr   sudoz-nT)r%  zError: container 'z' not found via zL.

The container is likely running as root. Your user cannot see it
because z7 uses per-user namespaces. Grant passwordless
sudo for u    — the -n (non-interactive) flag is required
because a password prompt would hang or break piped commands.

On NixOS:

  security.sudo.extraRules = [{
    users = [ "USERz	your-userz"" ];
    commands = [{ command = "z<"; options = [ "NOPASSWD" ]; }];
  }];

Or run: sudo hermes r!  z<.
The container may be running under root. Try: sudo hermes z-it-i)TERM	COLORTERMLANGLC_ALL-er]   execz-u)shutilwhichrw   r@   r   r   r-  
returncoder#   r|  r'   r   rF   r$   r%   extendexecvp)r.  r/  r$  r1  r2  r3  runtime	sudo_pathprobeprobe2is_tty	tty_flags	env_flagsvarr  
cmd_prefixexec_cmds                    r   _exec_in_containerrN  Y  s'    Y'G#$45N{+I-Jl7##G MgMMM	
 	
 	
 	
 	
 I	)Z~> E 1L((	  	%D'9j$W  F
  A%%@ @ @ @ @  '@ @ !(	@ @ ')i&D&D@ @ 6=@ @ ,/88H+=+=@ @ !   $ b^ b bW b bMPXXV^M_M_b bZ   
 HQKKKYF!-vII6 5 5jnnS!! 	5dsNNSNN3444/8G)T7++wiJ(	
	 
	 		
 :
&	' 	  Ihqk8$$$$$rC   
name_or_idc                 8   	 ddl m}  |            }|                    |           }d}|r	|d         }n|                    |           }|r)	 |                    |          p|}n# t
          $ r Y nw xY w|                                 |S # t
          $ r Y nw xY wdS )aX  Resolve a session name (title) or ID to a session ID.

    - If it looks like a session ID (contains underscore + hex), try direct lookup first.
    - Otherwise, treat it as a title and use resolve_session_by_title (auto-latest).
    - Falls back to the other method if the first doesn't match.
    - If the resolved session is a compression root, follow the chain forward
      to the latest continuation. Users who remember the old root ID (e.g.
      from an exit summary printed before the bug fix, or from notes) get
      resumed at the live tip instead of a stale parent with no messages.
    r   r  Nr  )r  r  get_sessionresolve_session_by_titleget_compression_tipr   r   )rO  r  r!  sessionresolved_ids        r   _resolve_session_by_name_or_idrV    s    ******Y[[ ..,,%) 	B!$-KK 55jAAK 	 44[AAP[    	


   4s6   A	B
 A$ #B
 $
A1.B
 0A11B
 

BBr&   c                    | sd S 	 t          j        t          |                               d                    }t	          |                    d          pd                                          }|pd S # t          $ r Y d S w xY w)Nr   r   
session_idrM   )r  r  r~   r   r/   r%   r0   r   )r&   datar  s      r   _read_tui_active_session_filerZ    s     tz$t**...@@AA$((<((.B//5577{d   tts   A.A5 5
BBrX  active_session_filec                 &   t          |          p| pt          d          }|sdS d}	 ddlm}  |            }|                    |          }|s	 ||                                 dS dS |                    |          }t          |                    d          pd          }|dk    r	 ||                                 dS dS t          |                    d          pd          }t          |                    d          pd          }	t          |                    d	          pd          }
t          |                    d
          pd          }t          |                    d          pd          }||	z   |
z   |z   |z   }n)# t          $ r Y ||                                 dS dS w xY w	 ||                                 n# ||                                 w w xY wt                       t          d           t          d|            |rt          d| d           t                       t          d|            |rt          d|            t          d|            t          d| d| d|	 d|
|z    d| d           dS )z/Print a shell-visible epilogue after TUI exits.r"   r  Nr   r  message_countinput_tokensoutput_tokenscache_read_tokenscache_write_tokensreasoning_tokenszResume this session with:z  hermes --tui --resume z  hermes --tui -c ""zSession:        zTitle:          zMessages:       zTokens:         z (in z, out z, cache z, reasoning rm   )rZ  r"  r  r  rQ  r   get_session_titler   r%   r   rw   )rX  r[  targetr!  r  rT  r  r^  r_  r`  ra  rb  rc  total_tokenss                 r   _print_tui_exit_summaryrh    se   
 	&&9:: 	/	/ ... 
  	B******Y[[..(( 	* >HHJJJJJ >' $$V,,GKK88=A>>A  >HHJJJJJ > 7;;~66;!<<GKK88=A>>,? @ @ EAFF -A!B!B!GaHHw{{+=>>C!DD  !! 	 	    >HHJJJJJ > 	 >HHJJJ >HHJJJJ  
GGG	
%&&&	
-V
-
-... .,E,,,---	GGG	
%V
%
%&&& *((()))	
,]
,
,---		Y	Y 	Y*	Y 	Y2?	Y 	Y"%77	Y 	YEU	Y 	Y 	Y    s6   'F +?F CF G	 
F.G	 -F..G	 	G"ideallyInertpeerdirc                     | dz                                   r:| dz                                   s#| j        dz                                   r| j        S | S )u6  Return the npm workspace root for *dir*.

    In a workspace checkout the single ``package-lock.json`` and hoisted
    ``node_modules/`` live at the workspace root (the parent of the
    sub-package directory).  Heuristic: if *dir* has a ``package.json``
    but **no** ``package-lock.json``, and its **parent** has a
    ``package-lock.json``, the parent is the workspace root.
    Otherwise *dir* itself is the root (standalone project or
    prebuilt-bundle layout).

    Used by ``_tui_need_npm_install``, ``_make_tui_argv``, and
    ``_build_web_ui`` so that lockfile/node_modules resolution and
    ``npm install`` cwd stay consistent — a single helper prevents
    the checks from diverging if someone accidentally creates a
    sub-package lockfile (e.g. running ``npm install`` in the wrong
    directory).
    package.jsonpackage-lock.json)r-  r   )rk  s    r   _workspace_rootro  2  sd    & 
~	&&((**3355 Z--6688
 zJrC   include_child_workspacesrq  .c                N   t          |           }|| k    r| dfS 	 |                     |                                          }n# t          $ r |dfcY S w xY wd|g}|r| dz  }|                                rt          |                                          D ]i}|                                rS|dz                                  r<|                    d|                    |                                          g           j|	                    d           |t          |          fS )zJReturn Termux-only ``(cwd, npm_args)`` for installing deps for *dir* only.rI   --workspacepackagesrm  z--include-workspace-root=false)ro  relative_toas_posixr   is_dirsortediterdirr-  rB  appendtuple)rk  rq  ws_root	workspaceworkspace_argspackages_dirchilds          r   !_termux_workspace_install_contextr  M  sT    c""G#~~BwOOG,,5577		   { "/	 :N Z'   	 4 4 6 677  <<>> u~'=&F&F&H&H "))&(9(9'(B(B(K(K(M(MN   :;;;E.))))s   'A AArootc                 L   | dz  dz  }t          |           }|dz  }|                                r|                                sdS |dz  dz  dz  dz  }|                                sd	S |                                sdS |dz  d
z  }|                                sd	S 	 t          j        |                    d                                        d          pi }t          j        |                    d                                        d          pi }nV# t          t          t          j        f$ r7 |	                                j
        |	                                j
        k    cY S w xY wdt          dt          fd}|                                D ]\  }	}
|	st          |
t                    s|	|vr.|
                    d          s|
                    d          rM d	S t          ||	         t                    r! ||
           |||	                   k    r d	S dS )uQ  True when @hermes/ink is missing or node_modules is behind package-lock.json.

    Prebuilt bundle mode: when ``dist/entry.js`` exists and there is no
    ``package-lock.json`` (nix install layout only ships ``dist/`` +
    ``package.json``), skip reinstall entirely — the bundle is self-contained
    and there is nothing to install.

    With npm workspaces the single ``package-lock.json`` and the hoisted
    ``node_modules/`` live at the workspace root (the parent of the
    ``ui-tui/`` directory).  The lockfile / ink / marker checks use that
    workspace root; only the prebuilt-bundle sentinel stays relative to
    *root* (``ui-tui/dist/entry.js``).

    Compares ``package-lock.json`` against ``node_modules/.package-lock.json``
    (npm's hidden lockfile) by **content**, not mtime: git checkouts and npm
    rewrites can bump the root lockfile's timestamp even when installed deps
    already match, which used to trigger a spurious "Installing TUI
    dependencies" on every launch.

    For each entry in the root lock's ``packages`` map:
      - missing from hidden lock → reinstall (unless the entry is marked
        ``optional`` or ``peer``, which npm may intentionally skip per platform)
      - present but with differing fields (excluding npm-written runtime
        annotations like ``ideallyInert``) → reinstall

    Extra entries that exist only in the hidden lock are ignored — stale
    transitives left over from a removed dependency don't break runtime and
    we'd rather not force a reinstall for them. Falls back to mtime
    comparison if either lockfile is unparseable.
    distentry.jsrn  Fnode_modulesz@hermesinkrm  Tz.package-lock.jsonr   r   rt  pkgr   c                 >    d |                                  D             S )Nc                 ,    i | ]\  }}|t           v||S rI   )_NPM_LOCK_RUNTIME_KEYSr   kr}  s      r   
<dictcomp>z=_tui_need_npm_install.<locals>.comparable.<locals>.<dictcomp>  s)    PPPA9O0O0O10O0O0OrC   )r  )r  s    r   
comparablez)_tui_need_npm_install.<locals>.comparable  s    PPPPPPrC   optionalrj  )ro  r-  r  r  r   r%   rH   r   JSONDecodeErrorr=  st_mtimer.   r  r-   )r  entryr|  lockr  markerwanted	installedr  r   r  s              r   _tui_need_npm_installr  g  sa   B 6MJ&Ed##G((D}} t||~~ u
N
"Y
.
6
GC;;== t<<>> u~%(<<F>> t
=DNNGN<<==AA*MMSQSJv///AABBFFzRRXVX		')=> = = =yy{{#fkkmm&<<<<<=Q Q Q Q Q Q \\^^  	c 	#t$$ 	y  wwz"" cggfoo 44iot,, 	CJJdOE
 E
 2
 2
 445s    A:D AE.-E.)r  zpackages/hermes-ink/src)	rm  rn  ztsconfig.jsonztsconfig.build.jsonzbabel.compiler.config.cjszscripts/build.mjsz packages/hermes-ink/package.jsonzpackages/hermes-ink/index.jsz!packages/hermes-ink/text-input.js>   .cjs.mjs.js.ts.jsx.tsx.jsonc              #     K   t           D ]}| |z  }|                                r|V   t          D ]Z}| |z  }|                                s|                    d          D ](}|                                r|j        t          v r|V  )[dS )z?Yield source/config files that affect ``ui-tui/dist/entry.js``.*N)_TUI_BUILD_INPUT_FILESr-  _TUI_BUILD_INPUT_DIRSrw  rglobsuffix_TUI_BUILD_INPUT_SUFFIXES)r  r3  r&   rb   s       r   _iter_tui_build_inputsr    s      %  cz<<>> 	JJJ$  cz{{}} 	JJsOO 	 	D||~~ $+1J"J"J


		 rC   c                    t           j                            d          pd                                                                }|dv rdS | dz  dz  }	 |                                j        }n# t          $ r Y dS w xY wt          |           D ]5}	 |                                j        |k    r dS $# t          $ r Y  dS w xY wdS )a  True when ``dist/entry.js`` is missing or older than TUI inputs.

    The TUI bundle is self-contained. Rebuilding it on every launch adds a
    visible cold-start tax on slow Termux CPUs, while a simple mtime freshness
    check still rebuilds immediately after source updates, dependency updates,
    or local edits. Set ``HERMES_TUI_FORCE_BUILD=1`` to force the old behaviour.
    HERMES_TUI_FORCE_BUILDrM   >   r?   onyestrueTr  r  F)	r#   r$   r%   r0   r1   r=  r  rH   r  )r  r  r  output_mtimer&   s        r   _tui_need_rebuildr    s     Z^^455;BBDDJJLLE***t6MJ&Ezz||,   tt 't,,  	yy{{#l22tt 3 	 	 	444	5s$   A/ /
A=<A=B33
CCc            	         t          j        d          rt          j        d          rdS t          j                            d          rdS t
          dz  dz  dz  } |                                 sdS t          j                            d          p"t          t          j	                    d	z            }	 t          j        d
dd|  dgi t          j        d|iddddd          }n# t          t          j        f$ r Y dS w xY wt          j                            dd                              t          j                  }g }|j        pd                                }|r9|                    t          |                                          j                   |                    t          |          dz  dz  t          j	                    dz  dz  g           |D ]?}t          |          }|                                r||vr|                    d|           @t          j                            |          t          j        d<   dS )uz  Make sure `node` + `npm` are on PATH for the TUI.

    If either is missing and scripts/lib/node-bootstrap.sh is available, source
    it and call `ensure_node` (fnm/nvm/proto/brew/bundled cascade). After
    install, capture the resolved node binary path from the bash subprocess
    and prepend its directory to os.environ["PATH"] so shutil.which finds the
    new binaries in this Python process — regardless of which version manager
    was used (nvm, fnm, proto, brew, or the bundled fallback).

    Idempotent no-op when node+npm are already discoverable. Set
    ``HERMES_SKIP_NODE_BOOTSTRAP=1`` to disable auto-install.
    nodenpmNHERMES_SKIP_NODE_BOOTSTRAPscriptslibznode-bootstrap.shr   r   bashr   zsource "z+" >&2 && ensure_node >&2 && command -v nodeTr   r  F)r  r(  r#  r   r  r  PATHrM   binz.localr   )r?  r@  r#   r$   r%   r<  r-  r/   r~   r3   r*  r+  rH   SubprocessErrorra   pathsepstdoutr0   rz  r.  r   rB  rw  insertr'   )helperr   resultr$  extrasresolvedextrar  s           r   _ensure_tui_noder    s<    |F U 3 3 	z~~233 I%-0CCF>> *..//O3ty{{Y7N3O3OK N6NNN
 ;2::}k::
 
 
 Z/0    JNN62&&,,RZ88EF#**,,H 7d8nn,,..5666
MM4$$v-5ty{{X7MPU7UVWWW  JJ<<>> 	aunnLLA//BJvs   52C( (DDhermes_cli_dirc                 x    | t          t                    j        } | dz  dz  }|                                r|ndS )z3Find a pre-built TUI entry.js bundled in the wheel.Ntui_distr  )r~   ru   r   r-  )r  bundleds     r   _find_bundled_tuir  4  s>    h.z)J6Goo''177T1rC   tui_dirtui_devc                 2	   t                       dt          dt          fd}t          j                            d          }|r5|r3t          d| dt          j                   t          j        d           |s|rNt          |          }|d	z  d
z  
                                r% |d          }|dt          |d	z  d
z            g|fS t                      }|$ |d          }|dt          |          g|j        fS d}t                      }d}	|r|st          |           }	|o| o|	 }
|
sht          |           rX |d          }t          j                            d          st          d           t!          |           }|| k    rdnd}|rt#          | d          \  }}t%          j        |dg|ddddt          |          t$          j        t$          j        dddi t          j        ddi          }|j        d k    r|j        pd! d"|j        pd!                                 }d"                    |                                d#d                   }t          d$           |rt          |           t          j        d           d}|r	 |d          }| d%z  d&z  }t%          j        |d'd(gt          |          dddd)          }|j        d k    r|j        pd! |j        pd!                                 }d"                    |                                d#d                   }t          d*           |rt          |           t          j        d           | d+z  d,z  d-z  }|                                rt          |          d.g| fS |d/g| fS d}|r|p|	}|r |d          }t%          j        |d'd(gt          |           dddd)          }|j        d k    r|j        pd! |j        pd!                                 }d"                    |                                d#d                   }t          d0           |rt          |           t          j        d            |d          }|dt          | d	z  d
z            g| fS )1uL   TUI: --dev → tsx src; else node dist (HERMES_TUI_DIR prebuilt or esbuild).r  r   c                    | dk    rat           j                            d          }|r@t           j                            |          r!t          j        |t           j                  r|S t          j        |           }|s=| dk    r7	 ddl	m
}  |d          rt          j        d          }n# t          $ r Y nw xY w|s&t          |  d           t          j        d           |S )Nr  HERMES_NODEr   ensure_dependencyu.    not found — install Node.js to use the TUI.r=   )r#   r$   r%   r&   isfileaccessX_OKr?  r@  hermes_cli.dep_ensurer  r   rw   r@   r   )r  env_noder&   r  s       r   	_node_binz!_make_tui_argv.<locals>._node_bin@  s    &==z~~m44H  BGNN844  8RW9U9U  |C   	vCCCCCC$$V,, 0!<//D    	SHHHIIIHQKKKs   %B+ +
B87B8HERMES_TUI_DIRz1Error: --dev is incompatible with HERMES_TUI_DIR=z
The prebuilt TUI has no source code to hot-reload.
Unset HERMES_TUI_DIR (e.g. `unset HERMES_TUI_DIR`) to use --dev from a checkout.r   r=   r  r  r  z--expose-gcNFr  HERMES_QUIETu   Installing TUI dependencies…rI   )rs  ui-tuiTrp  install--silent	--no-fund
--no-audit--progress=falser   r  CIr?   )cwdr  r   r#  r   r  r  r   rM   rN  znpm install failed.rt  z
hermes-inkr+  build)r  r(  r#  r   r  zTUI dev prebuild failed.r  z.bintsxzsrc/entry.tsxr   zTUI build failed.)r  r/   r#   r$   r%   rw   r@   r   r   r~   r-  r  r   r  r  r  ro  r  r*  r+  PIPErA  r  r0   r'   r"  r)   )r  r  r  ext_dirpr  r  did_installtermux_startuptermux_need_rebuild$skip_install_for_fresh_termux_bundler  npm_cwdnpm_workspace_argsr  combinedr  ink_dirr  should_builds                       r   _make_tui_argvr  <  s   s s    & jnn-..G 7 ` ` ` ` 		
 	
 	
 	
 	  G 	NWAF
Z'0022 N y((mSVj1H-I-IJAMM $%%9V$$D-W6FF K355N 9g 9/88 	Bw;B/B+B ) 1-!'**- iz~~n-- 	42333!'** 5<w4F4FbbLe 	*K)-+ + +'G'  $ 	
   # G??)2:)tS))!
 
 
$ !! --2FF1D"FFLLNNHii 3 3 5 5cdd ;<<G'((( gHQKKK ' iJ&5%!G
 
 
 !! --2Dv}/BDDJJLLHii 3 3 5 5cdd ;<<G,--- gHQKKK&/%7::<< 	8HHo.77W~w&&
 L :"9&9 i%!G
 
 
 !! --2Dv}/BDDJJLLHii 3 3 5 5cdd ;<<G%&&& gHQKKK9VD-Wv%5
%B!C!CDgMMrC   toolsetsc                    	 ddl m}  ||           pg S # t          t          f$ r | sg cY S t	          | t
                    r| gn| }t	          |t          t          f          s|g}g }|D ]~}t	          |t
                    r3|                    d |	                    d          D                        J|
                    t          |                                                     d |D             cY S w xY w)zCNormalize argparse/Fire-style toolset input for the TUI subprocess.r   )_normalize_toolsetsc              3   >   K   | ]}|                                 V  d S r{  r0   r   parts     r   r   z*_normalize_tui_toolsets.<locals>.<genexpr>  s*      !K!K4$**,,!K!K!K!K!K!KrC   ,c                     g | ]}||S rI   rI   )r   items     r   r  z+_normalize_tui_toolsets.<locals>.<listcomp>  s    444t4444rC   )hermes_cli.oneshotr  AttributeErrorr   r-   r/   r  r{  rB  ra   rz  r0   )r  r  	raw_items
normalizedr  s        r   _normalize_tui_toolsetsr    s.   5::::::""8,,22K( 5 5 5 	III",Xs";";IXJJ	)dE]33 	$"I "
 	5 	5D$$$ 5!!!K!K4::c??!K!K!KKKKK!!#d))//"3"34444444444445s    C7CC76C7c                  f   d} | D ]}	 t          |dd          5 }|                                                                }ddd           n# 1 swxY w Y   n# t          t          f$ r Y gw xY w|dk    r dS |sw	 t          |          }n# t          $ r Y w xY w|dk    r|dk    r dS |c S dS )	u_  Return the container memory limit in bytes, or None if unconstrained.

    Node's V8 heap is NOT cgroup-aware: with a flat ``--max-old-space-size=8192``
    it happily grows the heap toward 8GB regardless of the container's real
    memory limit.  In a Docker/k8s container capped below ~9-10GB, the cgroup
    OOM-killer SIGKILLs Node before V8's own heap monitor ever fires — which
    runs no JS handler, writes no ``[tui-parent]`` breadcrumb, and the user
    sees only a bare gateway ``stdin EOF``.  Reading the real cgroup limit lets
    us size the heap cap below it so V8 GCs/exits gracefully instead of being
    reaped silently.

    Checks cgroup v2 (``/sys/fs/cgroup/memory.max``) then v1
    (``/sys/fs/cgroup/memory/memory.limit_in_bytes``).  A literal ``max`` (v2)
    or the v1 "unlimited" sentinel (a huge near-INT64 value) means no limit.
    )z/sys/fs/cgroup/memory.maxz+/sys/fs/cgroup/memory/memory.limit_in_bytesrr   r   Nr  r   l           )r+   readr0   rH   r   r   )
candidatesr&   fr7   r  s        r   _read_cgroup_memory_limitr    s@    J   	dC'222 'affhhnn&&' ' ' ' ' ' ' ' ' ' ' ' ' ' '$ 	 	 	H	%<<44 	 	HHEE 	 	 	H	A:: W444sF   A'AAA	AA	AA-,A-=B
BB    
default_mbc                     t                      }|s| S |dz  }t          |dz            }|| k    r| S |dk    rt          d|          n|S )u  Pick a V8 ``--max-old-space-size`` (MB) that fits the container.

    Returns ``default_mb`` (8192) when unconstrained or when the box is large
    enough that 8GB fits.  In a memory-limited container, returns ~75% of the
    cgroup limit so the heap + non-heap RSS stays under the cgroup ceiling,
    clamped to a sane floor (1536MB — below this V8 GC-thrashes and the TUI
    is barely usable).  Never exceeds ``default_mb``.
       g      ?i   i   )r  r   r  )r  r  limit_mbsizeds       r   _resolve_tui_heap_mbr	  )  sj     &''E %H 4  E
  ($3tUE9rC   resume_session_idrr  r  r;  verboserV  r  imageworktreecheckpointspass_session_id	max_turnsaccept_hooksc                 	   t           dz  }ddl}t          j                                        }	 ddlm}  ||           n,# t          $ r t          	                    dd           Y nw xY w|
                    d	d
          \  }}t          j        |           ||d<   t          j                            dt          t                               |d<   |                    dt          j                   |                    dt          j                               |                    d|rdnd           d}|
r	 ddlm}m}m}m}  |            }|r ||            |            }n7# t          $ r*}t/          d| t          j                   d}Y d}~nd}~ww xY w|st          j        d           |d         |d<   |d         |d<   |r
||d<   ||d<   |r
||d<   ||d<   t5          |          }|rd                    |          |d<   |rt9          |t:          t<          f          rag }|D ]A}|                    d t          |                               d          D                        B|rd                    |          |d <   n(t          |          !                                }|r||d <   |r||d!<   |	r|	|d"<   |rd#|d$<   |rd#|d%<   |t          |          |d&<   |rd'|d(<   n|rd)|d(<   |rd#|d*<   |                    d+d,                                           } tE          d- | D                       s$| #                    d.tI                                  d/                    |           |d+<   |%                    d0d           | r| |d0<   tM          ||          \  }!}"d}#	 	 tO          j(        |!t          |"          |1          }#n# tR          $ r d2}#Y nw xY w|#d3v rtU          | |           	 t          j+        |           n# tX          $ r Y nw xY w|r	  ||           n[# t          $ r Y nOw xY wnJ# 	 t          j+        |           n# tX          $ r Y nw xY w|r	  ||           w # t          $ r Y w w xY ww xY w|#d4k    r?dd5l-m.}$ t/                       t/          d6           t/                        |$d7gd89           t          j        |#           dS ):z%Replace current process with the TUI.r  r   N)apply_terminal_config_to_envr  z5Failed to apply terminal config bridge for TUI launchTexc_infozhermes-tui-active-session-r  )rT   r  HERMES_TUI_ACTIVE_SESSION_FILEHERMES_PYTHON_SRC_ROOTHERMES_PYTHON
HERMES_CWDNODE_ENVdevelopment
production)_cleanup_worktree_git_repo_root_prune_stale_worktrees_setup_worktreeu#   ✗ Failed to create TUI worktree: r   r=   r&   TERMINAL_CWDHERMES_MODELHERMES_INFERENCE_MODELHERMES_TUI_PROVIDERHERMES_INFERENCE_PROVIDERr  HERMES_TUI_TOOLSETSc              3   f   K   | ],}|                                 |                                 V  -d S r{  r  r  s     r   r   z_launch_tui.<locals>.<genexpr>  sK       ! !%)TZZ\\!JJLL! ! ! ! ! !rC   HERMES_TUI_SKILLSHERMES_TUI_QUERYHERMES_TUI_IMAGEr?   HERMES_TUI_CHECKPOINTSHERMES_TUI_PASS_SESSION_IDHERMES_TUI_MAX_TURNSr  HERMES_TUI_TOOL_PROGRESSoffHERMES_ACCEPT_HOOKSNODE_OPTIONSrM   c              3   @   K   | ]}|                     d           V  dS )--max-old-space-size=Nr   )r   ts     r   r   z_launch_tui.<locals>.<genexpr>  s/      FFq||344FFFFFFrC   r4  r!  HERMES_TUI_RESUME)r  r     >   r   r7  *   relaunchu   ⚕ Launching update...r  F)preserve_inherited)/r<  tempfiler#   r$   copyr  r  r   loggerdebugmkstempr   r%   r/   
setdefaultr@   
executabler_   r   r  r  r   r!  rw   r   r   r  r'   r-   r  r{  rB  ra   r0   r  rz  r	  popr  r*  callr  rh  unlinkrH   hermes_cli.relaunchr:  )%r
  r  rr  r  r  r;  r  rV  r  r  r  r  r  r  r  r  r<  r  r  active_session_fdr[  wt_infor  r  r   r!  repor   tui_toolsets	flattenedr  r2   _tokensr;   r  coder:  s%                                        r   _launch_tuirN  A  s   $ X%GOOO
*//

C]BBBBBB$$----- ] ] ]LW[\\\\\]-5-=-=+G .> . .** H,?C()$&JNN #l"3"3% %C ! NN?CN333NN<---NN:I}}\JJJG .	            ">##D -&&t,,,%o''GG 	 	 	===CJOOOOGGGGGG	  	HQKKK#FOL%foN .#N(-$% 4%-!"+3'(*844L <%(XXl%;%;!" 1ftUm,, 	1I     ! !-0YY__S-A-A! ! !      ?+.88I+>+>'(KK%%''E 1+0'( ("' ("' ,(+$% 0,/()&))nn"# 0*3&''	 0*/&' )%(!" ggnb))//11GFFgFFFFF IG/C/E/EGGHHH((7++C GG&&& 5#4 w00ID#D	?4SXX3???DD  	 	 	DDD	 8#$57JKKK	I)**** 	 	 	D	 	!!'****   			I)**** 	 	 	D	 	!!'****   	 rzz000000'((((6666HTNNNNNs   A &A*)A*;-E) )
F3 FF+$O P< OP< OP< 7P 
PPP+ +
P87P8<R>QR
Q RQ  R&Q21R2
Q?<R>Q??Rc                      t           j                            d          rdS 	 ddlm}   |             t           j        d<   dS # t
          $ r Y dS w xY w)uM  Pin the active kanban board into ``HERMES_KANBAN_BOARD`` for the chat session.

    Without this, in-process tools (``kanban_*``) and shelled-out CLI calls
    (``hermes kanban …``) resolve the board on different paths: the env-pin if
    set, otherwise the global ``<root>/kanban/current`` file. A concurrent
    ``hermes kanban boards switch`` from another session can flip the file
    mid-turn, so the same chat sees its tool calls hit board A while its shell
    calls hit board B (#20074). Pinning at chat boot mirrors what the
    dispatcher already does for spawned workers.
    HERMES_KANBAN_BOARDNr   get_current_board)r#   r$   r%   hermes_cli.kanban_dbrR  r   rQ  s    r   _pin_kanban_board_envrT    su     
z~~+,, ::::::,=,=,?,?
()))   s   A 
AAc                  N    	 ddl m}   | d           dS # t          $ r Y dS w xY w)u+  Seed ``~/.hermes/skills/`` with the bundled skill library on first launch.

    Called from any CLI entrypoint that the user might use as their first
    interaction with Hermes — chat, dashboard (the desktop GUI's backend),
    and gateway. The skills_sync module is manifest-based and idempotent:
    skipped skills cost ~milliseconds, so calling this repeatedly is fine.

    Failures are swallowed because skills are an enhancement, not a hard
    dependency. Hermes still functions without them; the user just sees an
    empty skills library.
    r   rS  TrU  N)rW  rT  r   rS  s    r   _sync_bundled_skills_quietlyrV    sT    111111$   s    
$$c                    t          | dd          rdS t          | dd          s#t          j                            d          dk    rdS 	 ddlm}  |                                d	i           pi                     d
d          }t          |t                    o)|                                	                                dk    S # t          $ r Y dS w xY w)u  Decide whether to launch the TUI for a chat/bare invocation.

    Precedence (highest first):
      1. ``--cli`` flag         → always classic REPL
      2. ``--tui`` flag / ``HERMES_TUI=1`` → always TUI
      3. ``display.interface`` config value ("cli" | "tui")
      4. default → classic REPL

    Explicit flags always win over config so muscle memory and scripts keep
    working regardless of the configured default.
    r   Fr"   r>   r?   Tr   ro  r    r!   )getattrr#   r$   r%   r  ro  r-   r/   r0   r1   r   )argsro  r9   s      r   _resolve_use_tuir[    s     tUE"" utUE"" bjnn\&B&Bc&I&It111111""9b117R<<[%PP%%%H%++--*=*=*?*?5*HH   uus   A8C 
CCc                    t          |           }t          | dd          }|rt          | dd          st          |t                    rPt	          |          }|r|| _        nt          d| d           t          d           t          j        d           ne|rdnd	}t          |
          }|s|dk    rt          d	
          }|r|| _        n-|rdnd}t          d| d           t          j        d           t          | dd          }|rt	          |          }|r|| _        	 ddl
m}m}	m}
m} ddlm}  |
 |                      }|rt          j                            dt'          |           d|	 d           |D ].}t          j                            d ||           d           /t          j                            d| d           t          j                            d           n# t(          $ r Y nw xY wt+                      st                       t          d           t                       t          d           t                       ddlm}m}  |            s |d           t          j        d           	 t3          d                                                                          }n# t8          t:          f$ r d}Y nw xY w|d v rt=          |            dS t                       t          d!           t          j        d           t?                      r"	 dd"l m!}  |             n# t(          $ r Y nw xY w	 tE                       n# t(          $ r Y nw xY wt          | d#d$          rd%tF          j$        d&<   t          | d'd$          rd%tF          j$        d(<   t          | d)d$          rd%tF          j$        d*<   t          | d+d          r| j%        tF          j$        d,<   tM                       |rtO          t          | dd          t          | d-d$          t          | d.d          t          | d/d          t          | d0d          t          | d1d          t          | d2d          t          | d3d$          t          | d4d          t          | d5d          t          | d6d$          t          | d7d$          t          | d8d$          t          | d9d          t          | d:d$          ;           dd<l(m)} i d.| j*        d/t          | d/d          d0| j+        d1t          | d1d          d2t          | d2d          d3t          | d3d$          d4| j,        d5t          | d5d          dt          | dd          d6t          | d6d$          d7t          | d7d$          d8t          | d8d$          d9t          | d9d          d)t          | d)d$          d't          | d'd$          d=t          | d=d$          }d> |-                                D             }	  |d@i | dS # t\          $ r1}t          d?|            t          j        d           Y d}~dS d}~ww xY w)AzRun interactive chat CLI.continue_lastNresumezNo session found matching ''.z5Use 'hermes sessions list' to see available sessions.r=   r"   r   r]  TUICLIzNo previous z session found to continue.r   )MIGRATION_GUIDE_URLRETIREMENT_DATEfind_retired_xai_refsformat_issuerX  u   [33m⚠ xAI retires z model(s) in your config on z:[0m
u     [33m⚠[0m rN  z  [2mMigration guide: z[0m
z,  [2mRun 'hermes doctor' for details.[0m

zLIt looks like Hermes isn't configured yet -- no API keys or providers found.z  Run:  hermes setup)is_interactive_stdin#print_noninteractive_setup_guidancez;No interactive TTY detected for the first-run setup prompt.zRun setup now? [Y/n] n>   rM   r  r  z4You can run 'hermes setup' at any time to configure.)prefetch_update_checkyoloFr?   HERMES_YOLO_MODEignore_user_configHERMES_IGNORE_USER_CONFIGignore_rulesHERMES_IGNORE_RULESr  HERMES_SESSION_SOURCEr  rr  r  r  r;  r  rV  r  r  r  r  r  r  r  )r  rr  r  r  r;  r  rV  r  r  r  r  r  r  r  maincompactc                     i | ]
\  }}|||S r{  rI   r  s      r   r  zcmd_chat.<locals>.<dictcomp>  s    ???tq!arC   r   rI   )/r[  rY  r-   r/   rV  r^  rw   r@   r   r"  hermes_cli.xai_retirementrb  rc  rd  re  r  ro  r   rG   r   r   r  hermes_cli.setuprf  rg  r  r0   r1   r  r  	cmd_setupr[  hermes_cli.bannerri  rX  r#   r$   r  rT  rN  r   rr  rr  r  r  r  r   )rZ  use_tuicontinue_valr  r  last_idkind
resume_valrb  rc  rd  re  _load_config_for_xai_check_retired_xai_refs_refrf  rg  replyri  cli_mainkwargses                         r   cmd_chatr  (  s?   t$$G 4$77L GD(D99 lC(( 	5lCCH &DLDDDEEEMNNN &0UU5F+6:::G >v/u=== % '2uuUFTFFFGGG x..J #1*== 	#"DK
	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	POOOOO112L2L2N2NOO 	UJA3/@+A+A A A%4A A A   * Q Q
  !Od9K9K!O!O!OPPPPJX:MXXXYYYJSTTT    ()) Z	
 	
 	
 	$%%%	
 	
 	
 	
 	
 	
 	
 	

 $#%% 	//M   HQKKK	12288::@@BBEE+, 	 	 	EEE	$$$dOOOFDEEE
 ,-- 	??????!!#### 	 	 	D	(****    tVU## -),
%& t)511 625
./
 t^U++ 0,/
() tXt$$ :.2k
*+ 
D(D))D)U33$..T:t44T:t444400D)T22$//$..$..T:u55mU;;#D*;UCCdK66 ~u==	
 	
 	
 	
& %$$$$$GD*d33 	DM 	'$$//	
 	74D11 	w.. 	 	w-- 	'$$// 	GD*e44 	wt]E:: 	74):EBB 	WT;55 	ne<< 	gd,@%HH  	74E22!F& @?v||~~???F6   mmmsa   *CG8 8
HH3K KK3M 
MMM$ $
M10M11X; ;
Y6&Y11Y6c                 D    t                       ddlm}  ||            dS )zGateway management commands.r   )gateway_commandN)rV  hermes_cli.gatewayr  )rZ  r  s     r   cmd_gatewayr    s6     """222222ODrC   c                     ddl m}  ||           }t          |t                    r|dk    rt	          |          dS dS )z1Local OpenAI-compatible proxy to OAuth providers.r   )	cmd_proxyN)hermes_cli.proxy.clir  r-   r   
SystemExit)rZ  
_cmd_proxyrcs      r   r  r    sY     =<<<<<	D		B"c rQwwnn wwrC   c           	         t          d           ddlm}m} t	                       t	          d           t	          d            |d          pd}|st	                       t	          d           t	                       t	          d	           t	          d
           t	          d           t	                       t	          d           t	          d           t	          d           t	                       	 t          d                                          }n'# t          t          f$ r t	          d           Y dS w xY w|dk    r |dd           d}t	          d           t	                       t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           t	          d           n< |dd            d }t	          d!           n|}|dk    rd"nd#}t	          d$|            t	                        |d%          pd	                                d&k    rt	          d'            |d(          pd}|rt	          d)|            	 t          d*                                          }n# t          t          f$ r d+}Y nw xY w|	                                d,v r}|dk    r"t          d-                                          }	n!t          d.                                          }	|	r2 |d(|	
                    d/d                     t	          d0|	            nt	                       |dk    r1t	          d1           t          d2                                          }	n!t          d.                                          }	|	r3 |d(|	
                    d/d                     t	          d3|	            nt	          d4           t          t                                                    j        d5         }
|
d6z  d7z  }|d8z  }|                                st	          d9|            dS |d:z                                  s"t	          d;           t!          j        d<          }|st	          d=           dS 	 t%          j        |d>d?d@dAgt)          |          t$          j        t$          j        dBdCdDE          }n # t          $ r t	          dF           Y dS w xY w|j        dk    rn|j        pd                                }|r/dG                    |                                dHd                   ndI}t	          dJ           t	          |           dS t	          dK           nt	          dL           t7                      dz  dMz  }|                    dBdBN           |dOz                                  rt	          dP           	 t          dQ                                          }n# t          t          f$ r d+}Y nw xY w|	                                d,v r=t!          j        |dBR           |                    dBdBN           t	          dS           nO |d%          pd	                                d&k    r |d%d&           t	          dT           t	          dU           dS t	                       t	          dV           |dk    rt	          dW           t	          dX           nt	          dY           t	                       t	          dZ           t	          dV           t	                       	 t%          j        d[t)          |          d\d]t)          |          gt)          |          ^           n# t          $ r Y nw xY wt	                       |dOz                                  r |d%d&           t	          d_           t	                       |dk    rZt	          d`           t	          da           t	          db           t	          dc           t	                       t	          dd           nht	          d`           t	          da           t	          de           t	          df           t	                       t	          dd           t	          dg           t	                       t	          dh           dS t	          di           dS )jzESet up WhatsApp: choose mode, configure, install bridge, pair via QR.whatsappr   )get_env_valuesave_env_valueu   ⚕ WhatsApp Setupz2==================================================WHATSAPP_MODErM   z&How will you use WhatsApp with Hermes?z&  1. Separate bot number (recommended)uF        People message the bot's number directly — cleanest experience.zH     Requires a second phone number with WhatsApp installed on a device.z   2. Personal number (self-chat)z/     You message yourself to talk to the agent.z3     Quick to set up, but the UX is less intuitive.z  Choose [1/2]: z
Setup cancelled.Nr?   botu     ✓ Mode: separate bot numberu     ┌─────────────────────────────────────────────────┐u9     │  Getting a second number for the bot:           │u9     │                                                 │u9     │  Easiest: Install WhatsApp Business (free app)  │u9     │  on your phone with a second number:            │u;     │    • Dual-SIM: use your 2nd SIM slot            │u<     │    • Google Voice: free US number (voice.google) │u;     │    • Prepaid SIM: $3-10, verify once            │u9     │  WhatsApp Business runs alongside your personal │u;     │  WhatsApp — no second phone needed.             │u     └─────────────────────────────────────────────────┘z	self-chatu'     ✓ Mode: personal number (self-chat)zseparate bot numberzpersonal number (self-chat)u   
✓ Mode: WHATSAPP_ENABLEDr  u   ✓ WhatsApp is already enabledWHATSAPP_ALLOWED_USERSu   ✓ Allowed users: z
  Update allowed users? [y/N] rh  >   r  r  z<  Phone numbers that can message the bot (comma-separated): z(  Your phone number (e.g. 15551234567): r!  u     ✓ Updated to: z+  Who should be allowed to message the bot?z4  Phone numbers (comma-separated, or * for anyone): u     ✓ Allowed users set: uF     ⚠ No allowlist — the agent will respond to ALL incoming messagesr=   r  zwhatsapp-bridgez	bridge.jsu    
✗ Bridge script not found at r  uM   
→ Installing WhatsApp bridge dependencies (this can take a few minutes)...r  u5     ✗ npm not found on PATH — install Node.js firstr  r  r  r  Tr   r  )r  r  r   r#  r   r  u   
  ✗ Install cancelledrN  r  z(no output)u     ✗ npm install failed:u     ✓ Dependencies installedu)   ✓ Bridge dependencies already installedrT  rK  z
creds.jsonu#   ✓ Existing WhatsApp session foundz8
  Re-pair? This will clear the existing session. [y/N] ignore_errorsu     ✓ Session clearedu'   
✓ WhatsApp is configured and paired!z(  Start the gateway with: hermes gatewayu   ──────────────────────────────────────────────────u0   📱 Open WhatsApp (or WhatsApp Business) on thez*   phone with the BOT's number, then scan:u,   📱 Open WhatsApp on your phone, then scan:u0      Settings → Linked Devices → Link a Devicer  z--pair-onlyz	--sessionr  u!   ✓ WhatsApp paired successfully!z  Next steps:z)    1. Start the gateway:  hermes gatewayz2    2. Send a message to the bot's WhatsApp numberz)    3. The agent will reply automaticallyu;     Tip: Agent responses are prefixed with '⚕ Hermes Agent'u)       2. Open WhatsApp → Message Yourselfu.       3. Type a message — the agent will replyz4  so you can tell them apart from your own messages.z1  Or install as a service: hermes gateway installuG   ⚠ Pairing may not have completed. Run 'hermes whatsapp' to try again.)r   r  r  r  rw   r  r0   r  r  r1   r  r~   ru   r.  rL  r)   r?  r@  r*  r+  r/   DEVNULLr  rA  r   r'   r"  r   rO  rmtree)rZ  r  r  current_modechoicewa_mode
mode_labelcurrent_usersresponsephonerx   
bridge_dirbridge_scriptr  r  errr  session_dirs                     r   cmd_whatsappr    s@
   ????????	GGG	
	(OOO !=117RL .+67776777VWWWV	
 	
 	
 	0111?@@@CDDD	-..4466FF+, 	 	 	&'''FF	 S==N?E222G3444GGG  p  q  q  qMNNNMNNNMNNNMNNNOPPPPQQQOPPPMNNNMNNNOPPP  p  q  q  q  qN?K888!G;<<<<%,%5%5!!;X 	 	)Z))*** 
GGG())/R6688FBB/000 "M":;;ArM \3M33444	?@@FFHHHH+, 	 	 	HHH	>>|++%R %''  HIIOOQQ 47sB9O9OPPP2522333e?@@@F egg E DEEKKMME 	\N3U]]35K5KLLL5e556666Z[[[ >>))++3A6L	),==J,M!! A-AABBB'//11 ;\	
 	
 	
 l5!! 	IJJJF	^il<NO
OO!)!    FF ! 	 	 	-...FF	 !!=&B--//C;>Qdii 0 0 6777MG-...'NNNF,----9::: "##j09<KdT222l"**,, 3444	K egg H +, 	 	 	HHH	>>|++M+T::::dT:::)**** 0117R>>@@FJJ16:::<===<===F 
GGG	*%@AAA:;;;;<===	GGG	
<===	*	GGGS''SEUEUVJ	
 	
 	
 	
 	
     
GGGl"**,, Y
 	)62221222e/"""=>>>FGGG=>>>GGGOPPPP/"""=>>>=>>>BCCCGGGOPPPHIIIABBBBBWXXXXXs\   6!D  D<;D<!K% %K;:K;1AT3 3UU=!Y Y54Y5&A_) )
_65_6c                 @    t          d           ddlm}  |            S )u"  Set up WhatsApp Business Cloud API (official Meta integration).

    Walks the user through the Meta-side credentials (Phone Number ID,
    Access Token, App Secret, optional App/WABA IDs) plus webhook
    configuration. Includes field-shape validators that catch the most
    common setup mistakes (e.g. pasting a phone number into the Phone
    Number ID field).

    Distinct from ``hermes whatsapp`` (the Baileys bridge wizard) — the
    two adapters are complementary, not alternatives. See
    ``hermes_cli/setup_whatsapp_cloud.py``.
    whatsapp-cloudr   )run_whatsapp_cloud_setup)r   hermes_cli.setup_whatsapp_cloudr  )rZ  r  s     r   cmd_whatsapp_cloudr  	  s4     !"""HHHHHH##%%%rC   c                 (    ddl m}  ||            dS )zInteractive setup wizard.r   )run_setup_wizardN)rv  r  )rZ  r  s     r   rw  rw  	  s+    111111TrC   c                 "   ddl m} ddlm}  |d           t	          d           t	                       dD ]} ||           t                      st	                       t          |            dS t	                       t	          d           dS )	zFOne-shot bootstrap for pip users: install non-Python deps + run setup.r   )stamp_install_methodr  pipu!   ⚕ Hermes post-install bootstrap)r  browserripgrepffmpegu   ✓ Post-install complete.N)r  r  r  r  rw   r  rw  )rZ  r  r  deps       r   cmd_postinstallr  	  s    666666777777	
-...	GGG7  #')) ,$*+++++rC   c                     t          d           t          | dd          r1	 ddlm}  |             t	          d           n# t
          $ r Y nw xY wt          |            dS )	uK   Select default model — starts with provider selection, then model picker.rr  r  Fr   )clear_provider_models_cachez  Cleared model picker cache.rZ  N)r   rY  hermes_cli.modelsr  rw   r   select_provider_and_model)rZ  r  s     r   	cmd_modelr  
  s    tY&& 	EEEEEE'')))12222 	 	 	D	4((((((s   A 
AAr  c                 f    	 ddl m}  ||           }|duo
|j        dk    S # t          $ r Y dS w xY w)a6  Return True when provider_id maps to a profile with auth_type='api_key'.

    Used as a catch-all in select_provider_and_model() so that new providers
    declared in plugins/model-providers/<name>/ automatically dispatch to _model_flow_api_key_provider
    without requiring an explicit elif branch here.
    r   )get_provider_profileNry  F)	providersr  r  r   )r  r  _ps      r   _is_profile_api_key_providerr  
  sa    222222!!+..~;",)";;   uus   " 
00c                   01234567 ddl m7m0m} ddlm4m}m} ddlm	}  |            }|
                    d          }t          |t                    r|
                    dd          }|pd}d	}|
                    d          5t          5t                    r5
                    d
          }|pt          j        d          pd3 4|          }dt          t          t          t          t          f         f         f047fd}	dt          dt          fd2 |	|          1dt          f1235fd}
 |
            }|d}|sI3dk    rC |3|
                    d          |          }||j        }nd3 d}t#          d| d           |sE	  7d          }n8# 0$ r0}3dk    r ||          }t#          d| d           d	}Y d	}~nd	}~ww xY w|dk    r |d          rd}ddlm}m}m}m} t          |          6|r|1v r1|         d         }n|r6
                    ||          nd}t#                       t#          d|            t#          d|            t#                       d |D             } |d  |D                       }|r ||          nd}g }d}|D ]}|d!         d"k    r\|d#         }|
                    d$d          }|r|d%          d&| d'n
|d%          d(}d)| }t/          |          o||k    }|d*         }nK|d+         } |
                    | 6
                    | |                     }| }t/          |          o| |k    }g }|r.|                    || d,|f           t3          |          d-z
  }|                    |||f           1                                D ]\  }}!|!d         }"|!d.         }#|#                    d/d                              d0d                              d1          }$|!
                    dd          }%|%rd2|% nd}&|" d3|$ d'|& }|r4||k    r.|                    || d,g f           t3          |          d-z
  }|                    ||g f           |                    dd4g f           t          |
                    d5          t:                    o!t/          |
                    d5                    }'|'r|                    d6d7g f           |                    d8d9g f           |                    d:d;g f           t=          d< |D             |=          }(|(||(         d         d:k    rt#          d>           d	S ||(         d         })||(         d?         }*|*rd}+||*v r|*                    |          }+6fd@|*D             },||(         d-                              d(d-          d         }-t=          |,|+dA|- dBC          }.|.t#          d>           d	S |*|.         }/n|)}/|/d8k    rtC                       d	S |/dk    rtE          ||           n|/dDk    rtG          ||| E           n|/dFk    rtI          ||           n|/dGk    rtK          ||| E           n|/dHk    rtM          ||           n|/dIk    rtO          ||| E           no|/dJk    rtQ          ||           nW|/dKk    rtS          ||           n?|/dLk    rtU          ||           n'|/dk    rtW          |           n|/,                    dM          s|/1v rJ |	 |                      
                    |/          }!|!t#          dN           d	S t[          ||!           n|/d6k    rt]          |           n|/dOk    rt_          ||           n|/dPk    rta          ||           ni|/dQk    rtc          ||           nR|/dRk    rte          ||           n;|/dSk    rtg          ||           n$|/dTv sti          |/          rtk          ||/|           |/dUvr%|/,                    dM          stm                       d	S d	S d	S )Va  Core provider selection + model picking logic.

    Shared by ``cmd_model`` (``hermes model``) and the setup wizard
    (``setup_model_provider`` in setup.py).  Handles the full flow:
    provider picker, credential prompting, model selection, and config
    persistence.
    r   )resolve_provider	AuthErrorformat_auth_error)get_compatible_custom_providersro  r  )resolve_provider_fullrr  r   rM   z	(not set)Nr  r&  autor   c                 4   ddl m} i i  |            }dt          dt          dt          dt          dt          dd ffd	}|                    d
          }t	          |t
                    r|D ]}t	          |t                    s ||                    dd          d|                    dd          p|                    dd          |                    dd          |                    dd          p+|                    dd          p|                    dd                     |                    d          }t	          |t                    r|                                D ]\  }}t	          |t                    s ||                    dd          p|||                    dd          p|                    dd          |                    dd          |                    dd          p+|                    dd          p|                    dd                     dt          t          t          f         dt          dt          dt          dt          f
d}i }	 |           D ]}
t	          |
t                    s|
                    d          pd	                                }|
                    d          pd	                                }|r|spd|
                                                    dd          z   }|
                    d          pd	                                }|r	  |           n# $ r |}Y nw xY w|||
                    dd          |
                    dd          |
                    dd          |
                    di           |
                    dd          |
                    dd          | ||||
                    dd                     ||||
                    dd                    d|	|<   |	S )Nr   )read_raw_configr   provider_keyrr  ry  r  r   c                    t          |pd                                          }t          |pd                                          }t          | pd                                          } t          |pd                                          }t          |pd                                          }g }| r>|                    |                                 f|                                 |ff           |r>|                    |                                f|                                |ff           d|v r|D ]}	                    ||           d|v r|D ]}
                    ||           d S d S )NrM   ${)r/   r0   rB  r1   rA  )r   r  rr  ry  r  templatebase_template
identitiesidentityraw_api_key_refsraw_base_url_refss            r   _record_rawzRselect_provider_and_model.<locals>._named_custom_provider_map.<locals>._record_rawT
  s    7=b))//11HB//5577Mtzr??((**D|1r2288::L$$**,,E
 J L!!DJJLL?TZZ\\54I"JKKK !!"((**,|/A/A/C/CU.KL   x * D DH$//(CCCC}$$ * J JH%00=IIII %$J JrC   custom_providersrM   default_modelurlapir  refsc                 j   t          |pd                                                                          }t          |pd                                                                          }t          |pd                                          }||f|f||f|ffD ]}|d         r|| v r
| |         c S dS )NrM   r   r/   r0   r1   )r  r   r  rr  name_lcpkey_lcr  s          r   _lookup_refzRselect_provider_and_model.<locals>._named_custom_provider_map.<locals>._lookup_ref
  s     $*"oo++--3355G,,"--3355;;==G$$**,,E% 
% 
	 * * A; *8t#3#3>)))2rC   custom:r!  r   key_envmodelsdiscover_modelsTapi_mode)r   r  ry  r  rr  r  r  r  r  api_key_refbase_url_ref)r  r  r/   r%   r-   r  r.   r  r{  r0   r1   r  )r  r  raw_cfgr  raw_list	raw_entryraw_providersraw_keyr  custom_provider_mapr  r   r  r0  r  r  r  r  r  r  s                  @@r   _named_custom_provider_mapz=select_provider_and_model.<locals>._named_custom_provider_mapE
  s   555555 .0.0!/##	J	J	J 	J 		J
 	J 	J 	J 	J 	J 	J 	J 	J< ;;122h%% 	%  	!)T22 MM&"--MM'2..T)--QS2T2TMM)R00MM*b11 0 }}UB//0 }}UB//     K00mT** 	&3&9&9&;&;  "!)T22 MM&"--8MM'2..T)--QS2T2TMM)R00MM*b11 0 }}UB//0 }}UB//   	ucz"		 	 		
 	 	 	 	& !44S99 	 	EeT** IIf%%+2244D		*--3::<<H x djjll223<<<C!IIn55;BBDDL ''$$\2222  ' ' '&CCC' $ 99Y33 99Y337B//))Hb11#(99->#E#E!IIj"55 ,*{$dL%))GR:P:P    !,%t\599Wb;Q;Q! !( ($$" #"s   4M  M
	M
r  c                     t          | pd                                                              d                                          S )NrM   r  )r/   r0   rstripr1   )r  s    r   _norm_base_urlz1select_provider_and_model.<locals>._norm_base_url
  s8    39"~~##%%,,S1177999rC   c                  
   dk    st          t                    sdS                      dd                    } | sdS                                 D ],\  }} |                    dd                    | k    r|c S -dS )NcustomrM   r  )r-   r.   r%   r  )current_baser0  provider_info_custom_provider_mapr  effective_providerr  s      r    _active_custom_key_from_base_urlzCselect_provider_and_model.<locals>._active_custom_key_from_base_url
  s    ))It1L1L)2%~immJ&C&CDD 	2"6"<"<">"> 	 	C~m//
B??@@LPP


 QrrC   r  zUnknown provider 'zb'. Check 'hermes model' for available providers, or run 'hermes doctor' to diagnose config issues.z	Warning: z) Falling back to auto provider detection.
openrouterrv  r  )CANONICAL_PROVIDERS_PROVIDER_LABELSgroup_providersprovider_group_for_slugr   nonez  Current model:    z  Active provider:  c                 (    i | ]}|j         |j        S rI   )slugtui_descr   r  s     r   r  z-select_provider_and_model.<locals>.<dictcomp>  s    GGGaqvqzGGGrC   c                     g | ]	}|j         
S rI   )r  r  s     r   r  z-select_provider_and_model.<locals>.<listcomp>  s    #H#H#HqAF#H#H#HrC   r|  groupgroup_iddescriptionr  u    ▸ (rm   u    ▸zgroup:membersr  u     ← currently activer=   r  https://http://r      — rl   z$Custom endpoint (enter URL manually)r  remove-customzRemove a saved custom providerz
aux-configzConfigure auxiliary models...cancelzLeave unchangedc                     g | ]\  }}}|	S rI   rI   r   r1  r  s      r   r  z-select_provider_and_model.<locals>.<listcomp>F  s    ***;1eQ***rC   r   
No change.r   c                 <    g | ]}                     ||          S rI   r%   )r   mprovider_labelss     r   r  z-select_provider_and_model.<locals>.<listcomp>W  s6     
 
 
*+O1%%
 
 
rC   zSelect z
 provider:r   r  nousr  zopenai-codexz	xai-oauthz
qwen-oauthzminimax-oauthzgoogle-gemini-clizcopilot-acpcopilotr  zyWarning: the selected saved custom provider is no longer available. It may have been removed from config.yaml. No change.	anthropiczkimi-codingstepfunbedrockzazure-foundry>   
minimax-cn
openai-apiopencode-goollama-cloudopencode-zenkimi-coding-cntencent-tokenhubgmixaizaiarceegemininvidiaxiaomialibabaminimaxdeepseekkilocodelmstudiohuggingface>   r  r  r
  )7r  r  r  r  r  r  ro  r  hermes_cli.providersr  r%   r-   r.   r#   r|  r/   r  rw   r  r  r  r  r  rQ   rz  r   r  r  r  r  _prompt_provider_choicer   ra   _aux_config_menur  r  r  r  r  r	  r
  r  r  r  rR   r  _remove_custom_providerr  r  r  r  r  r  r  _clear_stale_openai_base_url)8rZ  r  ro  r  r  configcurrent_modelconfig_providercompatible_custom_providersr  r  r  
active_defwarningr   r  r  r  r  active_labelcanonical_descsgrouped_rowsactive_groupordereddefault_idxr  gid
group_descr  r0  	is_activer  r  r  r   r  	short_urlsaved_model
model_hint_has_saved_custom_listprovider_idxselected_keyselected_membersmember_defaultmember_labelsgroup_label
member_idxselected_providerr  r  r  r  r  r  r  r  s8                                                   @@@@@@@@r   r  r   
  s            
         
 ;:::::[]]FJJw''M-&& 9%)))R88!0[M O

7##I)T"" 4#--
33 	K29%@AAKV  #B"A&"I"I}#4T#s(^0C+D }# }# }# }# }# }# }# }#~:C :C : : : : 65 	c 	 	 	 	 	 	 	 	 	 .-//F~ R(F22**JJ{##'
 


 !]FF%7    
 PgPPPQQQ 	%%f--FF 	 	 	!V++++C00T'TTTUUUFFFFFF		 --0A"B"B            +,,O Q&000+F3F;>DP**66:::&	GGG	
0
0
0111	
/
/
/000	GGG HG3FGGGO"?#H#H4G#H#H#HIIL 7=D**6222"L
 13GK 2 2v;'!!j/C33J<Fas7|88:8888sSZ|LaLaLaE 3..C\**Bsl/BI)nGGv;D#''o.A.A$.M.MNNECV7IG 	2NNCE!A!A!A7KLLLg,,*KKNNC01111288:: - -]V$ ,$$Z44<<YKKRRSVWW	#''44.9A*[***r
33933z33 	-cVmmNNCE!A!A!A2FGGGg,,*KKNNC+,,,,NNHDbIJJJ'

3E(F(FMM RV

%&&S S  P)I2NOOONNL"A2FGGGNNH/4555***'***  L w|4Q78CCl<(+L|,Q/
  )%%%-33F;;N
 
 
 
/?
 
 
 l+A.44VQ??B,"3K333
 
 


 ,F,Z8(L(( L((v}5555	f	$	$T:::::	n	,	, 7777	k	)	)fm$?????	l	*	*v}5555	o	-	-!&-dCCCCC	1	1	1%fm<<<<	m	+	+6666	i	'	'FM2222	h	&	&6""""$$Y//.O 44422;;==AAEEFWXX H   F 7777	o	-	-''''	k	)	)fm4444	m	+	+////	i	'	'FM2222	i	'	'FM2222	o	-	-!&-8888	  
 
* 
&&7	8	8+
, 	%V->NNN  !    **955	
 	%&&&&&   s   F G"&GGc                     ddl m} m}m}  |            }|                    di           }t          |t                    r<|                    d          pd                                                                }nd}|dk    s|sdS  | d          }|rB |dd           t          t          |          d	k    rd
|dd	          dnd
| d           dS dS )aQ  Remove OPENAI_BASE_URL from ~/.hermes/.env if the active provider is not 'custom'.

    After a provider switch, a leftover OPENAI_BASE_URL causes auxiliary
    clients (compression, vision, delegation) with provider:auto to route
    requests to the old custom endpoint instead of the newly selected
    provider.  See issue #5161.
    r   )r  r  ro  rr  r  rM   r  Nrv  r  z.Cleared stale OPENAI_BASE_URL from .env (was: z...)rm   )r  r  r  ro  r%   r-   r.   r0   r1   rw   r   )r  r  ro  r  r  r  	stale_urls          r   r2  r2    s)    MLLLLLLLLL
+--C$$I)T"" MM*--3::<<BBDD88/00I 
("---9~~"" RYss^QQQQN)NNN	
 	
 	
 	
 	

 
rC   ))visionVisionzimage/screenshot analysis)compressionCompressionzcontext summarization)web_extractzWeb extractzweb page summarization)approvalApprovalzsmart command approval)r   MCPzMCP tool reasoning)title_generationzTitle generationzsession titles)tts_audio_tagszTTS audio tagszGemini TTS tag insertion)
skills_hubz
Skills hubzskills search/install)triage_specifierzTriage specifierzkanban spec fleshing)kanban_decomposerzKanban decomposerztask decomposition)profile_describerzProfile describerzauto profile descriptions)curatorCuratorzskill-usage review pass
_AUX_TASKSc                      t          t                    } 	 ddlm}  |            D ],}|                     |d         |d         |d         f           -n# t
          $ r Y nw xY w| S )a  Return built-in + plugin-registered auxiliary tasks for picker/menu use.

    Built-in tasks come first (preserving order), followed by plugin tasks
    sorted by key. Used by ``_aux_config_menu``, ``_reset_aux_to_auto``, and
    display-name lookups so plugin-registered tasks (registered via
    :meth:`hermes_cli.plugins.PluginContext.register_auxiliary_task`) appear
    in the same surfaces as built-in ones without core knowing about them.
    r   )get_plugin_auxiliary_tasksr0  display_namer  )r  r`  hermes_cli.pluginsrb  rz  r   )tasksrb  r  s      r   _all_aux_tasksrf    s     EAAAAAA//11 	V 	VELL%,n(=u]?STUUUU	V    	 Ls   =A 
A! A!task_cfgc                 P   t          | t                    sdS t          |                     d          pd                                          }t          |                     d          pd                                          pd}t          |                     d          pd                                          }|rM|                    dd                              dd                              d          }d	| d
|rd| ndz   S |dk    rd|rd| ndz   S |r| d| S |S )z;Render the current aux config for display in the task menu.r  r  rM   r  rr  r  r  r  zcustom (rm       · )r-   r.   r/   r%   r0   r  r  )rg  r  r  rr  shorts        r   _format_aux_currentrk    sC   h%% v8<<
++1r2288::H8<<
++5v66<<>>H&HW%%+,,2244E G  R0088BGGNNsSS"%"""&EnUnnn2FF658b99 ('''''OrC   rr  r  ry  taskr  ry  c                <   ddl m}m}  |            }|                    di           }t	          |t
                    si }||d<   |                    | i           }	t	          |	t
                    si }	|	|| <   ||	d<   |pd|	d<   |pd|	d<   |pd|	d<    ||           d	S )
u  Persist an auxiliary task's provider/model to config.yaml.

    Only writes the four routing fields — timeout, download_timeout, and any
    other task-specific settings are preserved untouched. The main model
    config (``model.default``/``model.provider``) is never modified.
    r   ro  save_config	auxiliaryr  rM   rr  r  ry  N)r  ro  rp  rA  r-   r.   )
rm  r  rr  r  ry  ro  rp  r  auxr  s
             r   _save_aux_choicers    s     ;:::::::
+--C
..b
)
)Cc4   KNN4$$EeT"" D	 E*[bE'N BE*}"E)KrC   c                     ddl m} m}  |             }|                    di           }t	          |t
                    si }||d<   d}t                      D ]\  }}}|                    |i           }t	          |t
                    si }|||<   d}	|                    d          dvrd|d<   d}	d	D ]}
|                    |
          rd
||
<   d}	|	r|dz  } ||           |S )zReset every known aux task back to auto/empty. Returns number reset.

    Includes plugin-registered tasks (via ``_all_aux_tasks``) so a plugin
    that contributed an auxiliary task gets reset alongside built-ins.
    r   ro  rq  Fr  >   NrM   r  r  Trl  rM   r=   )r  ro  rp  rA  r-   r.   rf  r%   )ro  rp  r  rr  countrm  _name_descr  changedfields              r   _reset_aux_to_autorz  >  s4    ;:::::::
+--C
..b
)
)Cc4   KE,..  eUtR((%&& 	ECI99Z  (::: &E*G5 	 	Eyy !e 	QJEKLrC   c                     ddl m}  	  |             }t          |                    d          t                    r|                    di           ni }t                       t          d           t                       t          d           t          d           t          d           t          d	           t          d
           t                       t                      }t          d |D                       dz   }t          d |D                       dz   }g }|D ]\  }}}	t          |                    |          t                    r|                    |i           ni }
t          |
          }|	                    |           d|	z   dz   	                    |           | }|
                    ||f           |
                    d           |
                    d           t          d |D             d          }|dS ||         d         }|dk    rdS |dk    rCt                      }|rt          d| d           nt          d           t                       bt          |           r)u   Top-level auxiliary-model picker — choose a task to configure.

    Loops until the user picks "Back" so multiple tasks can be configured
    without returning to the main provider menu.
    r   rX  Trq  u(     Auxiliary models — side-task routingz@  Side tasks (vision, compression, web extraction, etc.) defaultu@     to your main chat model.  "auto" means "use my main model" —z>  Hermes only falls back to a lightweight backend (OpenRouter,z<  Nous Portal) if the main model is unavailable.  Override az@  task below if you want it pinned to a specific provider/model.c              3   <   K   | ]\  }}}t          |          V  d S r{  r   )r   r1  r   s      r   r   z#_aux_config_menu.<locals>.<genexpr>x  s.      ==ZQas4yy======rC   r   c              3   <   K   | ]\  }}}t          |          V  d S r{  r}  )r   r1  descs      r   r   z#_aux_config_menu.<locals>.<genexpr>y  s.      ==ZQ4s4yy======rC   r  (rm   )	__reset__zReset all to auto)__back__Backc                     g | ]\  }}|S rI   rI   r  s      r   r  z$_aux_config_menu.<locals>.<listcomp>  s    +++xq%U+++rC   r  Nr  r  zReset z auxiliary task(s) to auto.z-All auxiliary tasks were already set to auto.)r  ro  r-   r%   r.   rw   rf  r  rk  ljustrz  r/  rz  _aux_select_for_task)ro  r  rr  	all_tasksname_coldesc_colentriestask_keyr   r  rg  currentr  r  r0  rh  s                   r   r0  r0  `  s    .-----1"kmm*4SWW[5I5I4*P*PXcggk2&&&VX8999PQQQPQQQNOOOLMMMPQQQ #$$	==9=====A==9=====A)+$- 	. 	. HdD)3CGGH4E4Et)L)LT"%%%RT  *(33G::h''V#*s*:)A)A()K)KVWVV  NNHe,----9:::+,,,%++7+++
 
 
 ;Fcl1o*F+"$$A G=q===>>>>EFFFGGGS!!!c1"rC   c                     ddl m} ddlm}  |            }t	          |                    d          t                    r|                    di           ni }t	          |                               t                    r|                     i           ni }t          |                    d          pd                                          pd}t          |                    d          pd                                          }t          |                    d	          pd                                          }t           fd
t                      D                        }		  ||||          }
n+# t          $ r}t          d|            g }
Y d}~nd}~ww xY wg }|dk    r|sdnd}|                    dd| g f           |
D ]}|                    dd          }|                    d          p|}|                    dd          }|                    d          pg }|rd| dnd}||k    r|sdnd}|                    || | | t          |          f           |rdnd}|                    dd| g f           |                    ddg f           t                       t          d|	 dt          |                      t                       t!          d |D             d          }|dS ||         \  }}}|dk    rdS |dk    r(t#           dddd           t          |	 d            dS |dk    rt%           |           dS t'           |||           dS )!ui  Pick a provider + model for a single auxiliary task and persist it.

    Uses ``list_authenticated_providers()`` to only show providers the user
    has already configured. This avoids re-running OAuth/credential flows
    inside the aux picker — users set up new providers through the normal
    ``hermes model`` flow, then route aux tasks to them here.
    r   rX  )list_authenticated_providersrq  r  r  rr  rM   r  c              3   0   K   | ]\  }}}|k    |V  d S r{  rI   r   r0  r   r1  rm  s       r   r   z'_aux_select_for_task.<locals>.<genexpr>  -      RR,#tQcTkkkkkkRRrC   )current_providerr4  current_base_urlz*Could not detect authenticated providers: Nu     ← current__auto__zauto (recommended)r  r   total_modelsr  r	  z models
__custom__zCustom endpoint (direct URL)r  r  z  Configure u    — current: c                     g | ]\  }}}|	S rI   rI   r  s      r   r  z(_aux_select_for_task.<locals>.<listcomp>  s    "D"D"D[Qq5"D"D"DrC   r  r  rr  r  ry  z: reset to auto.)r  ro  hermes_cli.model_switchr  r-   r%   r.   r/   r0   nextrf  r   rw   rz  r  rk  r/  rs  _aux_flow_custom_endpoint_aux_flow_provider_model)rm  ro  r  r  rr  rg  r  r4  r  rc  r  r   r  auto_markerr  r  r   totalr  rD  r  custom_markerr  _labels   `                       r   r  r    s    .-----DDDDDD
+--C&01E1Et&L&L
T#''+r
"
"
"RTC$.swwt}}d$C$CKswwtR   H8<<
33=v>>DDFFP&W--344::<<M8<<
339r::@@BBRRRR.2B2BRRRTXYYL00-'-
 
 
		
    @3@@AAA						 13G ,v55>N5TV  NNJ B[ B BBGHHH 	L 	LuuVR  uuV}}$na((x&B/4<+U++++"
#'777@P7OOVX 	 	;z;6;;T&\\JKKKK (8?OORMNNL"P"P"PRTUVVVNNJ+,,,	GGG	
T
T
T5H5R5R
T
TUUU	GGG
!"D"DG"D"D"Da
P
P
PC
{"3<D&&zzb2rRRRR///000|!$111 T4?????s   %E4 4
F>FFprovider_slugcurated_modelsr4  c                     ddl m} ddlm} t	           fdt                      D                        }i }	  ||          pi }n# t          $ r i }Y nw xY wt          |          }|spt          d| d           t          d           	 t          d          
                                }	n&# t          t          f$ r t                       Y d	S w xY w|	pd
}
n" |||||          }
|
t          d           d	S t           ||
pd
d
d
           |
rt          | d| d|
            d	S t          | d| d           d	S )zHPrompt for a model under an already-authenticated provider, save to aux.r   )_prompt_model_selection)get_pricing_for_providerc              3   0   K   | ]\  }}}|k    |V  d S r{  rI   r  s       r   r   z+_aux_flow_provider_model.<locals>.<genexpr>  r  rC   zNo curated model list for .z;Enter a model slug manually (blank = use provider default):zModel: NrM   )r4  pricingconfirm_providerr  r  : ri  z (provider default model))r  r  r  r  r  rf  r   r  rw   r  r0   r  r  rs  )rm  r  r  r4  r  r  rc  r  
model_listr  selecteds   `          r   r  r    s    877777::::::RRRR.2B2BRRRTXYYL G**=99?R    n%%J
  ;=;;;<<<KLLL		""((**CC!8, 	 	 	GGGFF	 9"**'*	
 
 
 ,F}HNRQS     K>>>>H>>?????IIIIIJJJJJs#   A AA!B/ /CCc                     ddl m} t           fdt                      D                        }t	          |                    d          pd                                          }t	          |                    d          pd                                          }t                       t          d|            t          d           t                       	 |rd	| d
nd}t          |                                          }n&# t          t          f$ r t                       Y dS w xY w|p|}|st          d           dS 	 |rd| d
nd}t          |                                          }	n&# t          t          f$ r t                       Y dS w xY w|	p|}		  |d                                          }
n&# t          t          f$ r t                       Y dS w xY wt           d|	||
           |                    dd                              dd                              d          }t          | d| d|	rd|	 ndz              dS )zHPrompt for a direct OpenAI-compatible base_url + optional api_key/model.r   masked_secret_promptc              3   0   K   | ]\  }}}|k    |V  d S r{  rI   r  s       r   r   z,_aux_flow_custom_endpoint.<locals>.<genexpr>$  r  rC   r  rM   rr  z  Custom endpoint for zH  Provide an OpenAI-compatible base URL (e.g. http://localhost:11434/v1)z
Base URL [r  z
Base URL: NzNo URL provided. No change.zModel slug (optional) [zModel slug (optional): z0API key (optional, blank = use OPENAI_API_KEY): r  r  r  r  r  z
: custom (rm   ri  )hermes_cli.secret_promptr  r  rf  r/   r%   r0   rw   r  r  r  rs  r  r  )rm  rg  r  rc  r  r4  
url_promptr  model_promptrr  ry  rB  s   `           r   r  r     s   ======RRRR.2B2BRRRTXYYL8<<
339r::@@BBW--344::<<M	GGG	
1<
1
1222	
TUUU	GGG2BT.).... 	 J%%''x(    
!!C +,,,	 +8m8888* 	
 l##))++x(    "]E&&>
 

%'' 	 x(        J++33IrBBII#NNI	\
1
1Y
1
1
1u5T^E^^^RT
UVVVVVs6   +D D)(D)+E0 0FFF9 9GGzSelect provider:r  c          	         	 ddl m}  ||| |          }|dk    rt                       |S n# t          $ r Y nw xY wt          |           t	          | d          D ]*\  }}|dz
  |k    rdnd}t          d| d| d|            +t                       	 	 t          d	t          |            d
|dz    d                                          }|s|S t          |          dz
  }d|cxk    rt          |           k     rn n|S t          dt          |                       n@# t          $ r t          d           Y n%t          t          f$ r t                       Y dS w xY w)zShow provider selection menu with curses arrow-key navigation.

    Falls back to a numbered list when curses is unavailable (e.g. piped
    stdin, non-TTY environments).  Returns the selected index, or None
    if the user cancels.
    r   )_curses_prompt_choicer=   u   →r!  r  r  T
Choice [1-z] (): Please enter 1-Please enter a numberN)rv  r  rw   r   r  r  r   r0   r   r   r  r  )	choicesr   r  r  r  r   cr  r  s	            r   r/  r/  V  s   ::::::##E7G<<!88GGGJ      
%LLL'1%% & &1a%7**$6$$A$$$$%%%%	GGG	FS\\FFgkFFFGGMMOOC c((Q,CC&&&&#g,,&&&&&
2CLL223333 	+ 	+ 	+)*****!8, 	 	 	GGG44	s0   (, 
99;D# 0D# D# #E >E E zqwen3-coder-pluszqwen3-codercurrent_api_modec                 &   ddl m}  ||           }t          |pd                                                                          }|p|pd}g d}t                       t          d           t          |d          D ]\  }\  }}	}
g }||k    r|                    d           ||k    r|                    d           |rd	d
                    |           dnd}t          d| d|	 |            t          d|
            	 t          d                                                                          }n%# t          t          f$ r t          d            w xY w|s|pdS |dv rdS |dv rdS |dv rdS |dv rdS t          d| d           dS )zwPrompt for a custom provider API mode.

    Returns an explicit mode string, or None to keep auto-detect behavior.
    r   )_detect_api_mode_for_urlrM   ))rM   zAuto-detectzIUse Hermes URL heuristics; best for standard OpenAI-compatible endpoints.)chat_completionszChat Completionsz=Use /chat/completions for standard OpenAI-compatible servers.)codex_responseszResponses / Codexz:Use /responses for Codex-compatible tool-calling backends.)anthropic_messageszAnthropic Messagesz4Use /v1/messages for Anthropic-compatible endpoints.zSelect API compatibility mode:r=   detectedr  z [z / ]r  r  z     z.Choice [1-4, Enter to keep current/detected]: z
Cancelled.N>   auto-detectr?   r  detect>   2chatcompletionsr  r  >   3codex	responsesr  r  >   4messagesr  r  r  zInvalid API mode choice: z. Falling back to auto-detect.)hermes_cli.runtime_providerr  r/   r0   r1   rw   r  rz  r'   r  r  r  )r  r  r  detected_modenormalized_currentdefault_modemode_optionsr  r2   r  r  markersr  r7   s                 r   !_prompt_custom_api_mode_selectionr    s1   
 EDDDDD,,X66M-344::<<BBDD%<<"L  L. 
GGG	
*+++,5lA,F,F % %((eUKM!!NN:&&&L  NN9%%%07?,ejj)),,,,R)3))%)))***#k##$$$$<
 

%''%%'' 	 x(   n  $#t#
444t
>>>!!
<<<  
BBB##	
Ic
I
I
IJJJ4s   3D; ;"Ec                 l   ddl }|                     dd                              dd                              d          }|                    dd|          }|                    d          d         }d|v sd	|v rd
| d}n1d|                                v rd| d}n|                                }|S )zGenerate a display name from a custom endpoint URL.

    Returns a human-friendly label like "Local (localhost:11434)" or
    "RunPod (xyz.runpod.io)".  Used as the default when prompting the
    user for a display name during custom endpoint setup.
    r   Nr  rM   r  r  z/v1/?$	localhost	127.0.0.1zLocal (rm   runpodzRunPod ()r   r  r  subra   r1   
capitalize)r  r   cleanr   s       r   _auto_provider_namer    s     IIIZ,,44YCCJJ3OOEFF9b%((E;;sADdkT11    	TZZ\\	!	!!$!!!  KrC   c                    t          |                     dd          pd                                          }|r|S t          |                     dd          pd                                          }|r=t          |                     dd          pd                                          sd| dS t          |pd                                          S )zDReturn the value that should be persisted for a custom provider key.r  rM   r  ry  r  }r/   r%   r0   )r  resolved_api_keyr  r  s       r   %_custom_provider_api_key_config_valuer    s    m''r::@bAAGGIIK -##Ir228b99??AAG !s=,,Y;;ArBBHHJJ ! W    %2&&,,...rC   c                     t          |                     dd          pd                                          }|r|S t          |pd                                          S )zDReturn the value that should be persisted for a custom provider URL.r  rM   r  )r  resolved_base_urlr  s      r   &_custom_provider_base_url_config_valuer    s^    }((<<BCCIIKKL  &B''--///rC   c                    ddl m}m}  |            }|                    d          pg }	t	          |	t
                    sg }	|	D ]}
t	          |
t                    r|
                    dd                              d          |                     d          k    rd}|r |
                    d          |k    r||
d<   d	}|r=|r;|
                    d
i           }t	          |t                    si }d|i||<   ||
d
<   d	}|r!|
                    d          |k    r||
d<   d	}nd|
v r|
                    dd           d	}|r|	|d<    ||            dS |st          |           }|| d}
|r||
d<   |r||
d<   |r||
d<   |r|r	|d|ii|
d
<   |	
                    |
           |	|d<    ||           t          d| d           dS )u  Save a custom endpoint to custom_providers in config.yaml.

    Deduplicates by base_url — if the URL already exists, updates the
    model name, context_length, and api_mode but doesn't add a duplicate entry.
    Uses *name* when provided, otherwise auto-generates from the URL.
    r   ro  r  r  rM   r  Frr  Tr  context_lengthr  N)r   r  ry  u%     💾 Saved to custom providers as "z" (edit in config.yaml))r  ro  rp  r%   r-   r  r.   r  rC  r  rz  rw   )r  ry  rr  r  r   r  ro  rp  r  r  r  rx  
models_cfgs                r   _save_custom_providerr    s    ;:::::::
+--C*++1rIi&& 	   eT"" 	uyyR'@'@'G'G(
 (
__S!!(" (" G 7++u44!&g  "YYx44
!*d33 $!#J%5~$F
5!",h 99Z((H44(0E*%"Gu$$		*d+++ !*3&'C   FF  -"8,,x00E #"i g %$j F F #3^"DEhU'CK	
O$
O
O
OPPPPPrC   c                    ddl m}m}  |            }|                    d          pg }t	          |t
                    r|st          d           dS t          d           g }|D ]}t	          |t                    r|                    dd          }|                    d	d
          }|                    dd
                              dd
          	                    d          }	|
                    | d|	 d           |
                    t          |                     |
                    d           	 ddlm}
  |
dt          |          dd          }t                       |dk     rd}n# t          t          t           t"          j        f$ r t'          |d          D ]\  }}t          d| d|            t                       	 t)          dt+          |           d                                          }|rt/          |          dz
  nd}n# t0          t2          t4          f$ r d}Y nw xY wY nw xY w||t+          |          k    rt          d           dS |                    |          }||d<    ||           t	          |t                    r|                    dd          nt          |          }t          d| d           dS )z=Let the user remove a saved custom provider from config.yaml.r   ro  r  zNo custom providers configured.NzRemove a custom provider:
r   unnamedr  rM   r  r  r  rl   rm   Cancelcurses_radiolistzSelect provider to remove:r  r  cancel_returnsr=   r  r  r  r  r  u   ✅ Removed "z" from custom providers.)r  ro  rp  r%   r-   r  rw   r.   r  r  rz  r/   hermes_cli.curses_uir  r   NotImplementedErrorrH   r*  r  r  r  r   r0   r   r   r  r  rC  )r3  ro  rp  r  r  r  r  r   r  rB  r  r  r   r  r  removedremoved_names                    r   r1  r1  E  s.   ::::::::
+--C*++1rIi&& i /000	
'(((G ' 'eT"" 	'99VY//D))J++CJ33;;IrJJQQRUVVINNd22i2223333NN3u::&&&&NN8999999(MM	
 
 
 	77C,gz7QR   gq)) 	! 	!DAq-q--A--    	6S\\66677==??C"%/#c((Q,,4CC-x8 	 	 	CCC	 {cS^^++lmmC  G'CK*4Wd*C*CUFI&&&W  

@,
@
@
@AAAAAs8   :8E3 3AH:AHH:H41H:3H44H:9H:_PROVIDER_MODELSc                 z    | t           v rddlm} |t                      | <   |S t	          dt
          d|           )zADefer the model-catalog import until something actually reads it.r   r  zmodule z has no attribute )_LAZY_MODEL_EXPORTSr  r  globalsr  __name__)r   r  s     r   __getattr__r    sR    """666666*		$
I8IIII
J
JJrC   c                     |                      d          }t          |t                    rHt          |                     d          pd                                                                          S dS )Nagentreasoning_effortrM   )r%   r-   r.   r/   r0   r1   )r3  	agent_cfgs     r   _current_reasoning_effortr    sc    

7##I)T"" L9==!344:;;AACCIIKKK2rC   effortc                 r    |                      d          }t          |t                    si }|| d<   ||d<   d S )Nr  r  )r%   r-   r.   )r3  r   r  s      r   _set_reasoning_effortr    sD    

7##Ii&& $	#w$*I !!!rC   c           	         t          t                              d | D                                 dfdD             }|                    fdD                        |sdS fdd}d}d	k    rt	          |          }n6|v r|                              }nd
|v r|                    d
          }nd}	 ddlm} fd|D             }|                    |           |                    |            |d||d          }|dk     rdS t                       |t	          |          k     r||         S |t	          |          k    rd	S dS # t          t          t          t          j        f$ r Y nw xY wt          d           t          |d          D ]#\  }	}
t          d|	 d |
                      $t	          |          }t          d|dz    d|            t          d|dz    d|            t                       	 	 t!          d|dz    d                                          }|sdS t%          |          }d|cxk    r|k    rn n||dz
           S ||dz   k    rd	S ||dz   k    rdS t          d|dz               n2# t&          $ r t          d           Y nt(          t*          f$ r Y dS w xY w)zOPrompt for a reasoning effort. Returns effort, 'none', or None to keep current.c              3      K   | ]X}t          |                                          #t          |                                                                          V  Yd S r{  r  )r   r   s     r   r   z5_prompt_reasoning_effort_selection.<locals>.<genexpr>  sk       
 
,2VARARATAT
KK%%''
 
 
 
 
 
rC   )minimallowmediumhighxhighc                     g | ]}|v |	S rI   rI   )r   r   dedupeds     r   r  z6_prompt_reasoning_effort_selection.<locals>.<listcomp>  s#    III&v7H7Hv7H7H7HrC   c              3   $   K   | ]
}|v|V  d S r{  rI   )r   r   canonical_orders     r   r   z5_prompt_reasoning_effort_selection.<locals>.<genexpr>  s-      QQf63P3P63P3P3P3PQQrC   Nc                     | k    r|  dS | S )Nu     ← currently in userI   )r   current_efforts    r   r  z2_prompt_reasoning_effort_selection.<locals>._label  s"    ^##4444rC   zDisable reasoningzSkip (keep current)r  r  r   r  c                 &    g | ]} |          S rI   rI   )r   r   r  s     r   r  z6_prompt_reasoning_effort_selection.<locals>.<listcomp>  s!    888f66&>>888rC   zSelect reasoning effort:r  r  r=   r  r  r   Tr  z] (default: keep current): r  r  )r  r.   fromkeysrB  r   r   r  r  rz  rw   r   r  rH   r*  r  r  r  r0   r   r   r  r  )effortsr  r=  disable_label
skip_labelr>  r  r  r  r   r   rh  r  r  r  r  s    `           @@@r   "_prompt_reasoning_effort_selectionr    s    
 
6=
 
 
 	
 	
 G
 DOIIIIOIIIGNNQQQQQQQQQQ t    
 (M&J'll	7	"	"mmN33	W		mmH--9999998888888}%%%z"""& 	
 
 
 774W3<#g,,6t,gz7QR    

$%%%w** * *	6(1((v(())))GA	
'q1u
'
'
'
'(((	
$q1u
$
$

$
$%%%	GGG	JAJJJKKQQSSF tf++CC}}}}1}}}}}sQw''a!e||va!e||t+AE++,,,, 	+ 	+ 	+)*****!8, 	 	 	44	sO   AE (E ?E "E;:E;*J <)J &	J 1	J <J K-K Kexisting_keyc                 ,  	
 ddl m	 ddlm} ddlm | j        r| j        d         nd
dt          dt          f	
fd}|sht          d	| j
         d
           
sdS  |d          }|st          d           dS  |
|           t          d           t                       |dfS ddlm} 
r |
          nd}t          d| j
         d|dd          d|            
st                       |dfS 	 t          d                                                                          }n'# t           t"          f$ r t                       d}Y nw xY w|                    d          r\ |d          }|s!t          d           t                       |dfS  |
|           t          d           t                       |dfS |                    d          r& |
d           t          d| j
         d           dS t                       |dfS )u  Shared API-key entry point for ``hermes setup`` / ``hermes model``.

    Handles both first-time entry and the already-configured case.  When a key
    is already present, offers [K]eep / [R]eplace / [C]lear so the user can
    recover from a malformed paste without editing ``~/.hermes/.env`` by hand.

    Returns ``(resolved_key, abort)``.  ``abort=True`` means the caller should
    ``return`` immediately — the user cancelled entry, declined to replace, or
    cleared the key and is now unconfigured.
    r   )LMSTUDIO_NOAUTH_PLACEHOLDER)r  r  rM   allow_lmstudio_defaultr   c                     dk    r| r	 dd}n d}	  |                                           }n&# t          t          f$ r t                       Y dS w xY w|s
dk    r| rS |S )Nr,  z (Enter for no-auth default r  z (or Enter to cancel): rM   )r0   r  r  rw   )r  promptenteredr  r  r  r  s      r   _prompt_new_keyz(_prompt_api_key.<locals>._prompt_new_key  s    *$$)?$__=X___FF888F	**62288::GG!8, 	 	 	GGG22	  	/;*449O4..s   7 AAzNo z API key configured.)rM   TT)r  
Cancelled.zAPI key saved.F)format_secret_source_suffixr  z
 API key: Nr  u   ... ✓z,  [K]eep / [R]eplace / [C]lear (default K): r  r  z  No change.z  API key updated.r  z7  API key cleared.  Re-run `hermes setup` to configure z again.)r  r  r  r  r  r  r  rQ   r/   rw   r   hermes_cli.env_loaderr  r  r0   r1   r  r  rR   )r  r  r  r  r  new_keyr  source_suffixr  r  r  r  s     `      @@@r   _prompt_api_keyr#    s    <;;;;;000000======-4-EMg&q))2G4 C           6GL666777 	8!/>>> 	,8w(((~ BAAAAA<CK//888M	
Ow|
O
O|BQB'7
O
O
O
OPPP #U""EFFLLNNTTVVx(     	!/??? 	'.!!!GGG&&w((("###~ w###[gl[[[	
 	
 	
 x 
GGGs   =3D1 1!EEc                 b    | pd                                                                 }d|v rdS dS )z>Infer the current StepFun region from the configured endpoint.rM   zapi.stepfun.comchinainternational)r0   r1   )r  r  s     r   _infer_stepfun_regionr'  P  s8    .b''))//11JJ&&w?rC   regionc                 &    ddl m}m} | dk    r|n|S )Nr   )STEPFUN_STEP_PLAN_CN_BASE_URLSTEPFUN_STEP_PLAN_INTL_BASE_URLr%  )r  r*  r+  )r(  r*  r+  s      r   _stepfun_base_url_for_regionr,  X  sG            W 	&%,rC   c                    	 ddl m}mm ddlm}m	 dt          f 	fd}	 t                       t          d           t          d           t                        |            }|r* |            rdS  || 	           t          d
           dS t                       t          d           t                       ddl	m
} 	  |d                                          }n&# t          t          f$ r t                       Y dS w xY w|r || 	           t          d           dS t          d           dS # t          $ r/ t                       t          d           t                       t          d           t                       t          d           t          d           t          d           t          d           t                       t          d           t                       ddl	m
} 	  |d                                          }n'# t          t          f$ r t                       Y Y dS w xY w|r || 	           t          d           Y dS t          d           Y dS w xY w)zNRun the Claude OAuth setup-token flow. Returns True if credentials were saved.r   )run_oauth_setup_tokenr  r  )save_anthropic_oauth_token%use_anthropic_claude_code_credentialsr   c                     	              } n# t           $ r d } Y nw xY w| rk |           s"t          |                     d                    r>            t          d           ddlm} t          d |             d           dS d	S )
Nr  save_fnu%     ✓ Claude Code credentials linked.r   display_hermes_homez]    Hermes will use Claude's credential store directly instead of copying a setup-token into z/.env.TF)r   rQ   r%   rw   r   r5  )r  _dhh_fnr  r  r  r0  s     r   ._activate_claude_code_credentials_if_availablezQ_run_anthropic_oauth_flow.<locals>._activate_claude_code_credentials_if_availabley  s    	0022EE 	 	 	EEE	 
	&&u--
	15eii6O6O1P1P
	 21.IIII9:::GGGGGG Bpwpwpypy  B  B  B   4us   
 u<     Running 'claude setup-token' — follow the prompts below.z9  A browser window will open for you to authorize access.Tr2  u     ✓ OAuth credentials saved.z8  If the setup-token was displayed above, paste it here:r  z*  Paste setup-token (or Enter to cancel): Fu     ✓ Setup-token saved.u)     ⚠ Could not detect saved credentials.z/  The 'claude' CLI is required for OAuth login.z  To install and authenticate:zE    1. Install Claude Code:  npm install -g @anthropic-ai/claude-codez/    2. Run:                  claude setup-tokenz.    3. Follow the browser prompts to authorizez)    4. Re-run:               hermes modelz8  Or paste an existing setup-token now (sk-ant-oat-...):z$  Setup-token (or Enter to cancel): u2     Cancelled — install Claude Code and try again.)r  r.  r  r  r  r/  r0  rQ   rw   r  r  r0   r  r  r   )
r  r.  r/  r7  tokenr  manual_tokenr  r  r0  s
   `      @@@r   _run_anthropic_oauth_flowr:  m  s[            
       
D         $<LMMMIJJJ%%'' 	==?? t&&unEEEE23334 	HIIIAAAAAA	//< egg L "8, 	 	 	GGG55	  	&&|^LLLL,---49:::u   ?@@@.///UVVV?@@@>???9:::HIIIAAAAAA	(()OPPVVXXEE!8, 	 	 	GGG555	  	&&unEEEE,---44BCCCuu5ss   AD? :D? 1D? 
C( 'D? (DD? 
D!D? .D? ?C I9 HI9I=I9I!I9&I98I9c                 (    ddl m}  ||            dS )z(Authenticate Hermes CLI with a provider.r   )login_commandN)r  r<  )rZ  r<  s     r   	cmd_loginr=    s*    ------M$rC   c                 (    ddl m}  ||            dS )zClear provider authentication.r   )logout_commandN)r  r?  )rZ  r?  s     r   
cmd_logoutr@    s*    ......N4rC   c                 (    ddl m}  ||            dS )zManage pooled credentials.r   )auth_commandN)hermes_cli.auth_commandsrB  )rZ  rB  s     r   cmd_authrD    s*    555555LrC   c                 (    ddl m}  ||            dS )zShow status of all components.r   )show_statusN)hermes_cli.statusrF  )rZ  rF  s     r   
cmd_statusrH    s*    ------KrC   c                 (    ddl m}  ||            dS )zCron job management.r   )cron_commandN)hermes_cli.cronrJ  )rZ  rJ  s     r   cmd_cronrL    s*    ,,,,,,LrC   c                 (    ddl m}  ||            dS )z Webhook subscription management.r   )webhook_commandN)hermes_cli.webhookrN  )rZ  rN  s     r   cmd_webhookrP    s*    222222ODrC   c                     t          | dd          }|dv rt          dt          j                   dS |dk    rdd	lm}  ||           S t          d
| t          j                   dS )u   Slack integration helpers.

    Dispatches ``hermes slack <subcommand>``. Currently supports:
      manifest — print or write a Slack app manifest with every gateway
                 command registered as a first-class slash.
    slack_commandN>   NrM   zusage: hermes slack <subcommand>

subcommands:
  manifest   Generate a Slack app manifest with every gateway
             command registered as a native slash

Run `hermes slack manifest -h` for details.r   r=   manifestr   )slack_manifest_commandzUnknown slack subcommand: )rY  rw   r@   r   hermes_cli.slack_clirT  )rZ  r  rT  s      r   	cmd_slackrV    s     $
.
.C
j: 		
 		
 		
 		
 q
j??????%%d+++	
,s
,
,3:>>>>1rC   c                 $    ddl m}  ||           S )z"Multi-profile collaboration board.r   )kanban_command)hermes_cli.kanbanrX  )rZ  rX  s     r   
cmd_kanbanrZ    s$    000000>$rC   c                 (    ddl m}  ||            dS )z%Shell-hook inspection and management.r   )hooks_commandN)hermes_cli.hooksr\  )rZ  r\  s     r   	cmd_hooksr^    s*    ......M$rC   c                 (    ddl m}  ||            dS )z%Check configuration and dependencies.r   )
run_doctorN)hermes_cli.doctorr`  )rZ  r`  s     r   
cmd_doctorrb  #  *    ,,,,,,JtrC   c                     t          | dd          }|dv r4ddlm}  ||           }t          j        t          |pd                     t          d| t          j                   t          j        d           dS )	z$Dispatch `hermes security <subcmd>`.security_commandN)auditNr   )cmd_security_auditzunknown security subcommand: r   r   )rY  hermes_cli.security_auditrg  r@   r   r   rw   r   )rZ  r  rg  rM  s       r   cmd_securityri  *  s    
$*D
1
1C
o@@@@@@ "!$''TYQ   	
/#
/
/cjAAAAHQKKKKKrC   c                 (    ddl m}  ||            dS )z)Dump setup summary for support/debugging.r   )run_dumpN)hermes_cli.dumprk  )rZ  rk  s     r   cmd_dumprm  7  s%    ((((((HTNNNNNrC   c                 (    ddl m}  ||            dS )z!Debug tools (share report, etc.).r   )	run_debugN)hermes_cli.debugro  )rZ  ro  s     r   	cmd_debugrq  >  s%    ******IdOOOOOrC   c                 (    ddl m}  ||            dS )zConfiguration management.r   )config_commandN)r  rs  )rZ  rs  s     r   
cmd_configrt  E  s*    000000N4rC   c                 p    t          | dd          rddlm}  ||            dS ddlm}  ||            dS )z,Back up Hermes home directory to a zip file.quickFr   )run_quick_backup)
run_backupN)rY  hermes_cli.backuprw  rx  )rZ  rw  rx  s      r   
cmd_backuprz  L  sg    tWe$$ 666666000000
4rC   c                 (    ddl m}  ||            dS )z(Restore a Hermes backup from a zip file.r   )
run_importN)ry  r|  )rZ  r|  s     r   
cmd_importr}  X  rc  rC   check_updatesr  c           	         ddl m} t           |                       t          dt                      t          dt          j                                        d                     	 ddlm}m} 	 t          d |d                      n# |$ r t          d           Y nw xY wn# t          $ r t          d           Y nw xY w| sd S 	 dd	l m
} dd
lm}  |            }|r3|dk    r-|dk    rdnd}t          d| d| d |             d           d S |dk    rt          d           d S d S # t          $ r Y d S w xY w)Nr   )format_banner_version_labelrn   ro   )rX   PackageNotFoundErrorrp   r[   rq   )check_for_updatesrecommended_update_commandr=   commitcommitszUpdate available: r!  u    behind — run ''z
Up to date)rx  r  rw   r<  r@   rX   ra   importlib.metadatar  r   r  r  r  r   )r  r  _pkg_versionr  r  r  behindcommits_words           r   _print_version_infor  _  s   ======	
%
%
'
'(((	
$l
$
$%%% 

-S[&&((+
-
-...
+TTTTTTTT	/9h!7!799::::# 	/ 	/ 	/-.....	/ + + +)*****+  777777@@@@@@""$$ 	 fqjj'-{{88	L8V 8 8l 8 822448 8 8     q[[, [   sO   *B* 3B B* B&#B* %B&&B* *CCA	D2 D2 2
E ?E c                 &    t          d           dS )zShow version.Tr~  N)r  r  s    r   cmd_versionr    s    d++++++rC   c                 t   t          | dd          r1ddlm} t          t	          j         |                                 dS t          | dd          r3t          | dd          st          d           dd	lm}  ||            dS t          | dd          st          d
           ddlm	}  ||            dS )z9Uninstall Hermes Agent (or just the Chat GUI with --gui).gui_summaryFr   )gui_install_summaryNr   r  zuninstall --gui)run_gui_uninstall	uninstall)run_uninstall)
rY  hermes_cli.gui_uninstallr  rw   r  dumpsr   hermes_cli.uninstallr  r  )rZ  r  r  r  s       r   cmd_uninstallr    s     t]E** @@@@@@dj,,..//000 tUE"" tUE** 	,*+++::::::$
 4&& "[!!!222222M$rC   c                 &   d}t          j        |           D ]y\  }}}d |D             |dd<   t           j                            |          dk    r?	 t	          j        |           |dz  }n# t          $ r Y nw xY w|                                 z|S )a~  Remove all __pycache__ directories under *root*.

    Stale .pyc files can cause ImportError after code updates when Python
    loads a cached bytecode file that references names that no longer exist
    (or don't yet exist) in the updated source.  Clearing them forces Python
    to recompile from the .py source on next import.

    Returns the number of directories removed.
    r   c                     g | ]}|d v|	S )>   
.worktreesvenvr  r(  .venvrI   )r   ds     r   r  z)_clear_bytecode_cache.<locals>.<listcomp>  s.     
 
 
OOO OOOrC   N__pycache__r=   )r#   walkr&   basenamer?  r  rH   r  )r  r  dirpathdirnamesr1  s        r   _clear_bytecode_cacher    s     G "  1
 

 
 

 7G$$55g&&&1   NNNs   A,,
A98A9)zhermes_cli/main.pyzhermes_cli/config.pyzhermes_cli/__init__.pyzcli.pyzrun_agent.pyzmodel_tools.pyztoolsets.pyzhermes_constants.pyc                     	 t          j        | ddgz   |ddd          }|j                                        pdS # t           j        t
          f$ r Y dS w xY w)z=Return the current HEAD SHA, or None if it can't be resolved.	rev-parser,  Tr  r(  r#  r  N)r*  r+  r  r0   CalledProcessErrorrH   git_cmdr  r  s      r   _capture_head_shar    s{    
{F++
 
 
 }""$$,,)73   tts   8; AAc                    ddl }ddl}t          |           } |                    d          5 }t          D ]}| |z  }|                                st          |          |                    dd          dz   z  }	 |                    t          |          t          |          d	           y# |j	        $ r7}d
t          |          t          |          fcY d}~c cddd           S d}~wt          $ r-}d
t          |          d| fcY d}~c cddd           S d}~ww xY w	 ddd           n# 1 swxY w Y   dS )u  Compile each file in ``_UPDATE_CRITICAL_FILES`` to catch SyntaxErrors.

    These are the files imported on every ``hermes`` startup; if any of them
    has a syntax error (orphan merge-conflict markers, bad ref to a name
    that no longer exists, etc.) the CLI can't bootstrap at all. We validate
    them after a successful ``git pull`` so we can auto-roll-back instead of
    leaving the user with a bricked install.

    The compiled ``.pyc`` is written to a temp directory rather than the
    source tree's ``__pycache__/`` so we don't race with concurrent test
    workers that walk the same dir, and so we don't leave a stale pyc
    behind in production if the next interpreter run picks a different
    Python version. The pyc is discarded on function return either way —
    we only care about the compile-or-not signal.

    Returns ``(ok, failing_path, error_message)``. ``ok=True`` means every
    file parsed cleanly.
    r   Nzhermes-syntax-check-rS   r  __r  T)cfiledoraiseFzcould not read: )TNN)
py_compiler<  r~   TemporaryDirectory_UPDATE_CRITICAL_FILESr)   r  compiler/   PyCompileErrorrH   )r  r  r<  tmpdirrelpathr&   r  r   s           r   _validate_critical_files_syntaxr    s'   & OOO::D		$	$,B	$	C	C Bv- 	B 	BG'>D;;==   LLGOOC$>$>$DEEB""3t99CJJ"MMMM, 2 2 2c$iiS11111111B B B B B B B B  B B Bc$ii)AC)A)AAAAAAAAAB B B B B B B BB	BB B B B B B B B B B B B B B B  sZ   AD5<2B/.D5/
D%9C+D%D5+D%8D D%D5 D%%D55D9<D9     r@prompt_textr   r)  c                    ddl }ddl}ddlm}  |            }|dz  }|dz  }|                    d           | |t          |                                          d}	|                    d	          }
|
                    |	                    |	                     |

                    |           t          j                    |z   }t          j                    |k     r|                                rp	 |                                                                }|                    d           |                    d           |r|n|S # t           t"          f$ r Y nw xY wt          j        d
           t          j                    |k     |                    d           |                    d           t'          dt)          |           d|d           |S )aw  File-based IPC prompt for gateway mode.

    Writes a prompt marker file so the gateway can forward the question to the
    user, then polls for a response file.  Falls back to *default* on timeout.

    Used by ``hermes update --gateway`` so interactive prompts (stash restore,
    config migration) are forwarded to the messenger instead of being silently
    skipped.
    r   Nr   z.update_prompt.jsonz.update_responseT)
missing_ok)r  r   r  z.tmp      ?z  (no response after zs, using default: rm   )r  uuidr   r   rE  r/   uuid4with_suffixrP  r  r  rf  	monotonicr)   r   r0   rH   r   sleeprw   r   )r  r   r)  _json_uuidr   r3   prompt_pathresponse_pathpayloadtmpdeadlineanswers                r   _gateway_promptr    s    000000?D..K--M D))) %++--   G
 
!
!&
)
)CNN5;;w''(((KK   7*H
/

h
&
&!! 	&002288::$$$555""d"333!'4vvW4Z(   C /

h
&
& $'''D)))	
N#g,,
N
N'
N
N
NOOONs   2AE
 
EEweb_dirc                 *   | j         j        dk    r| j         j         n| j         }|dz  dz  }|dz  dz  }|                                s|dz  }|                                sdS |                                j        }t          dd	h          t          j        | d
          D ]x\  }}}fd|D             |dd<   |D ]\}|                    d          rEt          j	        
                    t          j	                            ||                    |k    r  dS ]ydD ];}	| |	z  }
|
                                r |
                                j        |k    r dS <|dz  }|                                r|                                j        |k    rdS dS )a  Return True if the web UI dist is missing or stale.

    Mirrors the staleness logic used by ``_tui_build_needed()`` for the TUI.
    The dashboard source lives under ``web/``, but the Vite build
    still outputs to ``hermes_cli/web_dist/`` (per vite.config.ts
    outDir: "../hermes_cli/web_dist"), NOT to ``web/dist/``, so Python
    packaging can continue serving the same static asset directory. Uses the
    Vite manifest as the sentinel because it is written last and therefore
    has the newest mtime of any build output.
    appsrr   web_distz.vitezmanifest.json
index.htmlTr  r  topdownc                     g | ]}|v|	S rI   rI   )r   r  skips     r   r  z(_web_ui_build_needed.<locals>.<listcomp>Y  s    <<<QatmmqmmmrC   N)r  r  r  r  z.cssz.htmlz.vue)rm  z	yarn.lockzpnpm-lock.yamlzvite.config.tszvite.config.jsrn  F)r   r   r)   r=  r  	frozensetr#   r  endswithr&   getmtimer'   )r  rx   dist_dirsentinel
dist_mtimer  r  	filenamesfnmetamp	root_lockr  s               @r   _web_ui_build_neededr  D  s    -4N,?6,I,I7>((w~Ll*Z7H'!O3H?? +l*?? t)Jnf-..D(*(F(F(F    $9<<<<(<<< 	  	 B{{RSS  7##BGLL"$=$=>>KK444	  	 	 t^99;; 	27799-
::4422I inn..7*DDt5rC          )idle_timeout_secondsindentr  r  r  c          
         g t          j                    t          j                    	 t	          j        | |t          j        t          j        dddd          n<# t          $ r/}t	          j	        | ddt          |                    cY d	}~S d	}~ww xY wdfd}t          j        |d          }|                                 d}	 	                     d          }n# t          j        $ r 5  t          j                    z
  }	d	d	d	           n# 1 swxY w Y   |	|k    rmd}                                 	                     d          }n=# t          j        $ r+                                                                  }Y nw xY wY nY nw xY w|                    d           d                              }
|rd| d}|
|z  }
|dk    rd}t	          j	        | ||
d          S )u  Run a subprocess that streams output, with an idle-output timeout.

    Issue #33788: ``npm run build`` (Vite) was invoked with
    ``capture_output=True`` and no timeout. On low-memory hosts (notably
    WSL2 with the default 4 GB cap) the build can stall or sit silent for
    minutes; users see a frozen terminal, assume the update is hung, and
    reboot — leaving the editable install in a half-state with the
    ``hermes`` launcher present but ``hermes_cli`` not importable.

    This helper fixes both halves: stdout is streamed (so the user sees
    progress), and if no bytes have appeared on stdout/stderr for
    ``idle_timeout_seconds``, the process is terminated and the call
    returns with a non-zero ``returncode``. The caller's existing
    stale-dist fallback (#23817) takes over from there.

    Returns a ``CompletedProcess`` with merged stdout (text), empty
    stderr, and an integer returncode. Never raises on idle timeout —
    propagation of failure is via the returncode.
    Tr   r  r=   )r  r  r   r#  r   r  bufsizer  rM   )r  r   Nr   c                     j         J j         D ]} 	 t           |                                  d           n# t          $ rs t	          t
          j         dd           pd}|                                                     |d                              |d          }t           | d           Y nw xY w5                      |            t          j
                    d d d            n# 1 swxY w Y   d S )NTflushr   asciir  r  )r  rw   r  UnicodeEncodeErrorrY  r@   encodedecoderz  rf  r  )re   encsafer  last_output_tsr  merged_chunksprocs      r   _readerz'_run_with_idle_timeout.<locals>._reader  sd   {&&&K 
	3 
	3D5000=====% 5 5 5cj*d;;Fw{{}}++C	+BBII#V_I``'''t444444	5
  3 3$$T***!&!2!23 3 3 3 3 3 3 3 3 3 3 3 3 3 3
	3 
	3s"   '=A:B:9B:?)C44C8	;C8	rf  daemonFr  r)  r  r   u$   
  ⚠ Build produced no output for u   s — terminated.
    Common causes: out-of-memory on a low-RAM host (WSL/container),
    a stuck Node process, or an antivirus scan stalling I/O.
r   |   r   N)rf  r  	threadingLockr*  Popenr  STDOUTrH   CompletedProcessr/   Threadr   waitr,  	terminatekillr'   )r#  r  r  r  r   r  reader_threadidle_killedr  idler  r   r  r  r  r  s      `        @@@@r   _run_with_idle_timeoutr  o  s   4  "M_&&N>DQ?$	
 	
 	
  Q Q Q*3Bs3xxPPPPPPPPPQ3 3 3 3 3 3 3 3 3 3 $GDAAAMK	1%%B( 	 	 	 : :((>9: : : : : : : : : : : : : : :***"   %1--BB!0 % % %IIKKKBBB%  +*		$ q!!!ww}%%H 	M4H M M M 	
 	C77B&sBxKKKKsw   0A   
B*$BBBC+ +F <DF D#	#F &D#	'F EF 7FF FF F c                     ddl } 	 t          d                              d          }n# t          $ r Y dS w xY w|                     d|| j                  sdS t          j        d          rdS dD ]G}t          |z  d	z  dz  }|	                                r!i t          j        d
t          |          ic S H	 t          j        g ddddd          }|j        dk    rN|j                                        }|r3t          |          	                                ri t          j        d
|iS n# t$          $ r Y nw xY wdS )u  Return extra env vars for native module builds on NixOS.

    On NixOS, python3 is typically not on the system PATH (it lives in
    the Nix store and only enters PATH inside a nix-shell or when
    explicitly installed as a system package).  node-gyp uses Python to
    compile native addons like ``node-pty`` and its ``find-python.js``
    does a bare ``PATH`` lookup — which fails on NixOS.

    Two-tier resolution:
    1. Fast path — the hermes venv's python3 (present in managed installs)
    2. Fallback — resolves the absolute python3 path via ``nix-shell``

    Returns an env dict suitable for ``subprocess.run(env=...)`` or
    ``None`` when we are not on NixOS or python3 is already on PATH.
    r   Nz/etc/os-releaser   r   z
^ID=nixos$python3)r  r  r  PYTHON)z	nix-shellr   r  z--runzwhich python3TFr   )r(  r#  r  r)  )r   r~   r   rH   searchMr?  r@  r<  r)   r#   r$   r/   r*  r+  rA  r  r0   r   )r   
os_release	venv_namevenv_pythonr  python3_paths         r   _nixos_build_envr    s     III+,,666HH

   tt99]J55 t |I t ' > >	"Y.6B 	>=bj=(C,<,<=====	>
DDDd%
 
 
 !!!=..00L >\ 2 2 9 9 ; ; >="*=h===    4s   #* 
88:A3D/ /
D<;D<rI   
extra_argsr(  r  r  r  r(  c          
         i t           j        |pi ddi}|dz  }|                                r/| dg|}t          j        ||||dddd	          }|j        d
k    r|S | dg|}	t          j        |	|||dddd	          S )u  Run a deterministic npm install that does not mutate ``package-lock.json``.

    Prefers ``npm ci`` (strict, lockfile-preserving) when a lockfile is present;
    falls back to ``npm install`` only if ``npm ci`` fails (e.g. lockfile out of
    sync on a WIP checkout).  Without this, ``npm install`` on npm ≥ 10 silently
    rewrites committed lockfiles (stripping ``"peer": true`` etc.), which leaves
    the working tree dirty and causes the next ``hermes update`` to stash the
    lockfile — repeatedly.
    r  r?   rn  ciTr   r  F)r  r  r(  r#  r   r  r  r   r  )r#   r$   r)   r*  r+  rA  )
r  r  r  r(  r  run_envlockfileci_cmd	ci_resultinstall_cmds
             r   _run_npm_install_deterministicr    s    ( 76	r6D#66G((H t)j)N)	
 	
 	
	 1$$ 	/J/K>%	 	 	 	rC   fatalr  c                   | dz                                   sdS t          |           sdS dt          ddfdt          j        d          }|s|r d            d	           | S  d
           d)fd}t          |           }|| k    rdnd}t                      rt          |           \  }}t          ||g |dR           }|j	        dk    r4 d|rdnd d|rdndz               ||           |r d           dS t          |ddg|           }|j	        dk    r(t          j        d           t          |ddg|           }|j	        dk    r|j        pd|j        pdz   }|                                }	|	r/d                    |	                                d d                   nd}
| j        j        d!k    r| j        j        n| j        }|d"z  d#z  }|d$z  }|                                 r d%           |
r d&|
            dS  d|rdnd d'|rdndz               ||           |r d           dS  d(           dS )*aW  Build the web UI frontend if npm is available.

    Args:
        web_dir: Path to the dashboard frontend source directory.
        fatal: If True, print error guidance and return False on failure
               instead of a soft warning (used by ``hermes web``).

    Returns True if the build succeeded or was skipped (no package.json).
    rm  Tr#  r   Nc                     	 t          |            d S # t          $ rZ t          t          j        dd           pd}t          |                     |d                              |d                     Y d S w xY w)Nr   r  r  r  )rw   r  rY  r@   r  r  r  )r#  r   s     r   _sayz_build_web_ui.<locals>._sayO  s    	^$KKKKK! 	^ 	^ 	^sz:t<<GH$++hy+99@@R[@\\]]]]]]	^s    A A76A7r  z3Web UI frontend not built and npm is not available.zBInstall Node.js, then run:  cd web && npm install && npm run buildu   → Building web UI...r  subprocess.CompletedProcessc                     | j         | j        fD ]d}|st          |t                    r)|                    dd                                          n|                                }|r |           edS )aR  Print captured npm output so users can see *why* a step failed.

        Windows users hitting `rm -rf` / `cp -r` errors (or any other
        sync-assets / Vite failure) would otherwise see only ``Web UI
        build failed`` with no hint of the underlying cause, because
        the npm calls run with ``capture_output=True``.
        r   r  r  N)r  r   r-   bytesr  r  )r  blobr#  r  s      r   _relayz_build_web_ui.<locals>._relay^  s     ]FM2 	 	D FPQUW\F]F]p4;;wy;99@@BBBcgcncncpcpD T


	 	rC   rI   )rs  webr  )r  r   r  u   ✗u   ⚠z Web UI npm install failedrM   z# (hermes web will not be available)zD  Run manually:  npm install --workspace web && npm run build -w webFr+  r  r  r  
  ir  rr   r  r  u<     ⚠ Web UI build failed — serving stale dist as fallbackz  Build error:
  z Web UI build failedu     ✓ Web UI built)r  r   r   N)r)   r  r/   r?  r@  ro  r  r  r  rA  r  rf  r  r   r  r0   r'   r"  r   r   )r  r  r  r$  r  r  r1r2build_outputstderr_previewstderr_tailrx   r  
dist_indexr  s                 @r   _build_web_uir-  :  s    n$,,.. t(( t^3 ^4 ^ ^ ^ ^ ,u

C  	WDFGGGDUVVVyD	!"""      g&&G 1870B0B""H^%'' Q&G&P&P##	'4'444
 
 
B
 
}F%*UFFFErr EG	
 	
 	
 	r


 	YDWXXXu 
 eW 57	C	C	CB	} 	A#S%$9wGGG	}
 	RBIO<%++--HV^fkk.";";"="=cdd"CDDD\^070Cv0M0Mw~,,SZSa,.;,

  	DOPPP 97+778884@%*U@@@Err EG	
 	
 	
 	r


 	YDWXXXuD	4rC   desktop_dirc                 6    | dz  dz                                   S )z;Return True when a local desktop renderer build is present.r  r  r)   )r.  s    r   _desktop_dist_existsr1    s    & </77999rC   rx   c                 6    t          j                    dt          ddf fd}ddlm}  dz  }g }|                                r(|                    d	                                          }|                    d
|          dD ]]} |z  }|                                rBt          |
                                         }                    |          s ||           ^ dz  dz  }t          j        |d          D ]\  }	}
 fd|	D             |	dd<   t          |
          D ]V}t                    |z  }t          |
                                         }                    |          s ||           W                                S )a  Return a SHA-256 hex digest of all source files that feed the desktop build.

    Covers ``apps/desktop/`` (excluding anything matched by .gitignore)
    plus the root ``package.json`` / ``package-lock.json`` (workspace config
    that determines dependency resolution for the desktop workspace).

    Parses the repo-root ``.gitignore`` via *pathspec* so we automatically
    skip ``node_modules/``, ``dist/``, ``*.pyc``, etc. without maintaining
    a hardcoded skip-list.
    r&   r   Nc                    t          |                                         }                    |                                                               d           	 t	          | d          5 t          fdd          D ]}                    |           	 d d d            n# 1 swxY w Y   n# t          t          f$ r Y nw xY w                    d           d S )N    rbc                  .                          d          S )Ni   )r  )r  s   r   <lambda>zC_compute_desktop_content_hash.<locals>._hash_file.<locals>.<lambda>  s    !&&-- rC   rC   )r/   ru  r  r  r+   iterrH   IOError)r&   r3  chunkr  hrx   s      @r   
_hash_filez1_compute_desktop_content_hash.<locals>._hash_file  s#   $""<0011			dD!! $Q!"7"7"7"7== $ $EHHUOOOO$$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ! 	 	 	D		s6   "B7 2,B+B7 +B//B7 2B/3B7 7C
Cr   )PathSpecz
.gitignorer   r   	gitignore)rm  rn  r  r   Tr  c           	          g | ]I}                     t          t                    |z                                                    G|JS rI   )
match_filer/   r~   ru  )r   r  r  rx   specs     r   r  z1_compute_desktop_content_hash.<locals>.<listcomp>  s\     
 
 
??3W(9'F'F|'T'T#U#UVV

 
 
rC   )hashlibsha256r~   pathspecr=  r-  r   r"  
from_linesr/   ru  r@  r#   r  rx  	hexdigest)rx   r<  r=  r>  linesr   r  r3  r.  r  r  r  fpr  r;  rA  s   `            @@@r   _compute_desktop_content_hashrI    s    	A
 
$ 
 
 
 
 
 
 
 "!!!!!|+IE C##W#55@@BB{E22D 6  499;; 	ammL1122C??3'' 
1 ')3K(*T(J(J(J  $9
 
 
 
 
 

 
 

 ## 	 	Bg#Bbnn\2233C??3'' 
2		 ;;==rC   c                  (    ddl m}   |             dz  S )zCReturn the path to the desktop build stamp file under $HERMES_HOME.r   r   zdesktop-build-stamp.json)r   r   r   s    r   _desktop_stamp_pathrK  	  s(    000000?999rC   source_modec                   |rt          |           sdS nt          |           dS t                      }|                                sdS 	 t	          j        |                    d                    }n## t          t          j        t          f$ r Y dS w xY w|
                    d          |k    rdS |
                    d          }|sdS t          |          }||k    S )a   Return True when the desktop build output is stale or missing.

    Compares the current content hash against the saved stamp. Also returns
    True if the expected build artifact doesn't exist (e.g. first run after
    ``hermes update`` that pulled new source but hasn't built yet).
    TNr   r   
sourceModecontentHash)r1  _desktop_packaged_executablerK  r-  r  r  r   rH   r  KeyErrorr%   rI  )r.  rx   rL  
stamp_file
stamp_data
saved_hashcurrent_hashs          r   _desktop_build_neededrV    s     #K00 	4	 (44<4$&&J tZ
 4 4g 4 F FGG

T)84   tt ~~l##{22t..J t0>>L:%%s   (A4 4BBc                   t                      }	 |j                            dd           t          |           }ddlm}m} || |j        |j                                                  d}|	                    t          j        |d          dz   d	
           dS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)z7Write the desktop build stamp after a successful build.TrK  r   r  timezone)rO  rN  builtAtr   )r  rN  r   r   z'Failed to write desktop build stamp: %sN)rK  r   rO  rI  r  rY  nowutc	isoformatrP  r  r  r   r>  r?  )rx   rL  rR  content_hashr  rY  rS  r   s           r   _write_desktop_build_stampr_  3  s   $&&JEt<<<4\BB////////'%#x|HL11;;==
 


 	djA>>>EPWXXXXX E E E>DDDDDDDDDEs   BB 
C(C		Cc                 B   | dz  }t           j        dk    r#t          |                    d                    }nFt           j        dk    r|dz  dz  |dz  dz  |dz  dz  g}n|d	z  d
z  |d	z  dz  |dz  d
z  |dz  dz  g}d |D             }|sdS t	          |d           S )z?Return the current platform's unpacked Electron app executable.releasedarwinz%mac*/Hermes.app/Contents/MacOS/Hermeswin32zwin-unpackedz
Hermes.exezwin-ia32-unpackedzwin-arm64-unpackedzlinux-unpackedr   Hermeszlinux-arm64-unpackedc                 :    g | ]}|                                 |S rI   r0  r  s     r   r  z0_desktop_packaged_executable.<locals>.<listcomp>X  s%    444a4444rC   Nc                 4    |                                  j        S r{  )r=  r  )r  s    r   r7  z._desktop_packaged_executable.<locals>.<lambda>[  s    qvvxx'8 rC   )r0  )r@   r   r  globr  )r.  release_dirr   existings       r   rP  rP  E  s    	)K
|x+**+RSSTT

		 	 .(<7--<..=


 **X5**X5008;008;	

 54:444H tx889999rC   c                     t          j                    } g }t          j                            d          pt          j                            d          }|r"|                    t          |                     t          j        dk    r|                    | dz  dz  dz             nt          j        dk    rkt          j                            d          }|r(|                    t          |          dz  d	z             |                    | d
z  dz  dz  d	z             nat          j                            d          }|r%|                    t          |          dz             |                    | dz  dz             t                      }g }|D ]D}|	                                }||vr*|
                    |           |                    |           E|S )u  Return the per-user Electron download cache directories for this OS.

    electron-builder's ``app-builder unpack-electron`` extracts the Electron
    distribution from a zip stored in this cache (NOT from node_modules), so a
    corrupt zip here — not a bad workspace install — is what poisons the build.
    Honors the ``electron_config_cache`` / ``ELECTRON_CACHE`` overrides that
    ``@electron/get`` respects, then falls back to the platform defaults.
    electron_config_cacheELECTRON_CACHErb  LibraryCacheselectronrc  LOCALAPPDATACacheAppDataLocalXDG_CACHE_HOMEz.cache)r~   r3   r#   r$   r%   rz  r@   r   setr(   r   )	r3   r   overridelocalxdgseenoutr  r  s	            r   _electron_download_cache_dirsr{  ^  s    9;;DJz~~566Z"*..IY:Z:ZH *$x..)))
|x$*X5
BCCCC		 	 
~.. 	Bd5kkJ6@AAA$*W4zAGKLLLLjnn-.. 	6d3ii*4555$/J6777eeDC  \\^^T>>HHRLLLJJrNNNJrC   c                    g }t                      D ]v}|                                st          |                    d                    D ]<}	 |                                 |                    |           -# t          $ r Y 9w xY ww| dz  }|                                rT|                    d          D ]>}	 t          j	        |d           |                    |           /# t          $ r Y ;w xY w|S )u   Clear the cached Electron download + half-written unpacked dir so the
    next ``pack`` re-downloads and re-stages from scratch.

    Root cause of the ``ENOENT … rename '…/linux-unpacked/electron' ->
    '…/linux-unpacked/Hermes'`` desktop build failure: a corrupt zip in the
    per-user Electron download cache (a partial download resumed into the same
    file leaves prepended/concatenated junk, or an interrupted write truncates
    it). electron-builder's ``app-builder unpack-electron`` extracts the
    distribution from that cached zip (NOT from node_modules); a bad zip yields
    a partial tree MISSING the 193 MB ``electron`` binary, so the final rename
    dies. Re-running repeats the same broken extraction forever.

    We deliberately do NOT try to detect corruption ourselves. stdlib
    ``zipfile`` silently tolerates the prepended/concatenated junk that is the
    most common corruption here — it reads from the end-of-central-directory
    backward, so ``testzip()`` returns clean on exactly the zips ``unzip -t``
    and ``@electron/get`` reject. Gating the purge on a self-rolled validator
    would therefore skip the real-world case and never self-heal. Instead, on a
    packaged-build failure we unconditionally remove the version's cached zips
    and the stale unpacked dir, then let the caller retry once: ``@electron/get``
    re-downloads with its own SHASUM verification (the real source of truth),
    and ``before-pack.cjs`` re-wipes the unpacked dir. If the failure was
    unrelated, a clean re-download is harmless and the retry fails the same way.

    Best-effort: never raises. Returns the paths removed so the caller can log
    them and decide whether a retry is worthwhile (empty list ⇒ nothing to
    clear, so no point retrying).
    zelectron-*.zipra  z
*-unpackedTr  )
r{  rw  rx  r  rE  rz  rH   rg  r?  r  )r.  r  	cache_dirzip_pathrh  unpackeds         r   _purge_electron_build_cacher    s=   : G244 
 
	!! 	y/?@@AA 	 	H!!!x((((    		 	)K #((66 	 	Hhd;;;;x((((    Ns$   )A77
BB9+C%%
C21C2c                    t           j        dk    rg S 	 ddl}n# t          $ r g cY S w xY w	 | dz                                  }n# t
          $ r g cY S w xY w|                                sg S t          j                    }g }	 |	                    ddg          }n# t          $ r g cY S w xY w|D ]}	 |j
        }n# t          $ r Y w xY w|                    d          }|                    d          }	|	r|||k    rP	 t          |	                                          }
n# t
          t          f$ r Y w xY w||
j        v r|                    |           g }|D ]N}	 |                                 |                    t#          |j                             ?# t          $ r Y Kw xY w|rV	 |                    |d          \  }}|D ]'}	 |                                 # t          $ r Y $w xY wn# t          $ r Y nw xY w|S )	u  Terminate any running desktop app executing from this build's ``release``
    dir so a rebuild can replace its (otherwise locked) executable.

    On Windows a running ``Hermes.exe`` keeps an exclusive lock on
    ``release/win-unpacked/Hermes.exe``. electron-builder's pack then can't
    delete the stale binary and dies with ``remove …\Hermes.exe: Access is
    denied`` / ``ERR_ELECTRON_BUILDER_CANNOT_EXECUTE`` (before-pack hits the same
    EPERM cleaning the dir). The retry path repeats the failure because the lock
    is still held. POSIX lets you unlink a running binary, so this is a no-op
    off-Windows.

    Scope is deliberately narrow: only processes whose executable lives *inside*
    this desktop's ``release`` tree are stopped — a packaged install elsewhere or
    an unrelated "Hermes" process is never touched. Best-effort: never raises.
    Returns the PIDs we asked to stop.
    rc  r   Nra  pidexer  r  )r@   r   psutilr   r.  rH   rw  r#   getpidprocess_iterinfor%   r~   r   rL  rz  r  r   r  
wait_procsr  )r.  r  rh  mevictims	proc_iterr  r  r  r  exe_pathstoppedr1  alives                 r   %_stop_desktop_processes_locking_buildr    s   " |w	   			"Y.7799   			 		BG''77		   			 ! !	9DD 	 	 	H	hhuoohhuoo 	ckSBYY	Cyy((**HH$ 	 	 	H	(***NN4   G  	NNNN3tx==)))) 	 	 	H	 
	((!(<<HAu  IIKKKK    H
  	 	 	D	Ns    ((A AAB B)(B)1B99
CC?!D!!D54D5;F
F'&F'-G2 G! G2 !
G.+G2 -G..G2 2
G?>G?c           
         t           j        dk    rdS t          j                            d          st          j                            d          rdS t          |           }|dS |j        d         }t          |                              d          r|	                                sdS t          j        d          }|sdS 	 t          j        dd	t          |          gd
           t          j        |ddddt          |          gd
           dS # t          $ r}t          d| d           Y d}~dS d}~ww xY w)a  Make a locally-built (unsigned) macOS desktop app survive in-place self-update.

    An ad-hoc-signed .app has no stable Designated Requirement (no Team ID), so
    when the self-updater rebuilds the bundle in place with a fresh build (a new,
    different cdhash) Gatekeeper/LaunchServices treats the changed code as
    tampering and macOS reports "Hermes is damaged and can't be opened." The
    bundle also inherits the com.apple.quarantine flag from the downloaded
    installer process chain. Both make the relaunch fail.

    Clearing the quarantine xattrs and re-applying a clean deep ad-hoc signature
    (omitting the hardened-runtime flag, which is meaningless without a real
    Developer ID) lets the rebuilt app relaunch. No-op when a real signing
    identity is configured (CSC_LINK / APPLE_SIGNING_IDENTITY) so a properly
    signed/notarized build is never clobbered. Best-effort: never raises.
    rb  NCSC_LINKAPPLE_SIGNING_IDENTITYr   z.appcodesignxattrz-crFr  z--forcez--deepz--signr   z*  (warning: macOS relaunch fixup skipped: rm   )r@   r   r#   r$   r%   rP  rL  r/   r  rw  r?  r@  r*  r+  r   rw   )r.  r  appr  r   s        r   !_desktop_macos_relaunchable_fixupr    s[     |x	z~~j!! RZ^^4L%M%M 
&{
3
3C
{
+a.Cs88V$$ CJJLL |J''H CC1????)Xxc#hhOW\]]]]]] C C CA3AAABBBBBBBBBCs   AD 
D=D88D=packaged_executablec                    t           j        dk    rdS | j        dz  }|                                st	          d|            dS 	 |                                }n## t          $ r t	          d|            Y dS w xY wt          j        |j	                  st	          d|            dS |j
        dk    rt          j        |j	                  d	k    rdS t          j        d
          }|st	          d           dS t	          d           |ddt          |          g|ddt          |          gfD ]6}t          j        |d          j        dk    rt	          d|             dS 7dS )z=Configure Electron's Linux SUID sandbox helper when required.linuxTzchrome-sandboxu?   ✗ Hermes Desktop is missing Electron's Linux sandbox helper: Fu1   ✗ Cannot stat Electron's Linux sandbox helper: u;   ✗ Electron's Linux sandbox helper is not a regular file: r   i	  r6  uN   ✗ Hermes Desktop requires sudo to configure Electron's Linux sandbox helper.u@   → Configuring Electron Linux sandbox helper (sudo required)...chownz	root:rootchmod4755r  u9   ✗ Failed to configure Electron's Linux sandbox helper: )r@   r   r   r)   rw   lstatrH   r=  S_ISREGst_modest_uidS_IMODEr?  r@  r/   r*  r+  rA  )r  sandboxsandbox_lstatr6  commands        r   _desktop_linux_sandbox_fixupr  ,  s   
|wt!(+;;G>> YPWYYZZZu
   K'KKLLLuu <-.. UGUUVVVuq  T\-2G%H%HF%R%Rt<D ^___u	
LMMM7KW>wPVX[\cXdXd@ef  >'///:a??WgWWXXX55 @ 4s   A A;:A;rZ  c           	         t           dz  dz  }|dz                                  s&t          d|            t          j        d           	 ddlm}  |d	           n# t          $ r Y nw xY wt          j	        
                                }t          | d
d          rd|d<   t          | dd          rd|d<   t          | dd          rHt          t          | j                                                                                            |d<   t          | dd          rHt          t          | j                                                                                            |d<   t          | dd          }t          | dd          }t          | dd          }t%          |          }|s|sIt'          j        d          }|s2t          d           t          d           t          j        d           nd}|r:|rt+          |          sGt          d|dz              t          d           t          d           t          j        d           t           dz  d z  dz                                  sJt          d!           t          d"t            d#           t          d           t          j        d           t          d$|dz              nC|It          d%|d&z              t          d'           t          d(           t          j        d           nt          d)|            n|pt-          |t           |*          }	|	s|rd+nd,}
t          d-|
 d.           nt          d/           t/                      }t1          |t           d|0          }|j        dk    rBt          d1           t          d2t            d#           t          j        |j        pd           |rd+nd,}
t          d3|
 d4           |rd5nd6}|sJt5          |          }|r9t          d7d8                    t9          t          |                     d9           t;          j        |d:|g||d;          }|j        dk    rc|sat?          |          }|rPt          d<           |D ]}t          d=|            t5          |           t;          j        |d:|g||d;          }|j        dk    rd|sb|                     d>          sMt          d?           tC          |          }d@|d><   t5          |           t;          j        |d:|g||d;          }|j        dk    rt          dA           t          dB|            t          j"        dCk    rt          dD           t          dE           t          dF           t          dG           t          j        |j        pd           t%          |          }|stG          |           tI          t           |*           t          | dHd          r|rOt+          |          s)t          dI|dz              t          j        d           t          dJ|dz   dK           nN|9t          dL|d&z              t          dM           t          j        d           nt          dN| dK           dS |rEt          dO           t;          j        |dPdQd dRg||d;          }t          j        |j                   |8t          dS|d&z              t          dM           t          j        d           tK          |          st          j        d           t          dT|            t;          j        t          |          g||d;          }t          j        |j                   dS )Uz1Build and launch the native Electron desktop GUI.r  r   rm  z!Desktop GUI source not found at: r=   r   r   r   r   	fake_bootFr?   HERMES_DESKTOP_BOOT_FAKEignore_existingHERMES_DESKTOP_IGNORE_EXISTINGhermes_rootNHERMES_DESKTOP_HERMES_ROOTr  HERMES_DESKTOP_CWDr  
skip_buildforce_buildr  z@Desktop GUI requires Node.js/npm, but npm was not found on PATH.z&Install Node.js, then run:  hermes guiuC   ✗ --skip-build --source was passed but no desktop dist found at: r  z4  Pre-build first:  cd apps/desktop && npm run buildzG  Or drop --skip-build to install dependencies and build automatically.r  ro  uC   ✗ --skip-build --source requires existing workspace dependencies.z  Install first:  cd z
 && npm ciuI   → Skipping desktop source build (--skip-build --source); using dist at uF   ✗ --skip-build was passed but no packaged desktop app was found at: ra  z3  Pre-build first:  cd apps/desktop && npm run packz0  Or drop --skip-build to package automatically.u9   → Skipping desktop package build (--skip-build); using )rL  zsource buildzpackaged appu   ✓ Desktop z& is up to date (content stamp matches)u0   → Installing desktop workspace dependencies...)r(  r  u%   ✗ Desktop dependency install failedz  Run manually:  cd u   → Building desktop r  r  packu@     ⚠ Stopped running desktop app to free the build output (pid , rm   r+  )r  r  r  uQ     ⚠ Desktop build failed; cleared cached Electron download and retrying once...z    - ELECTRON_MIRRORu     ⚠ Desktop build still failing; the Electron download from GitHub looks blocked. Retrying once via a public mirror (npmmirror.com)... (set ELECTRON_MIRROR to use another mirror)z'https://npmmirror.com/mirrors/electron/u   ✗ Desktop GUI build failedz,  Run manually:  cd apps/desktop && npm run rc  z:  If this says "Access is denied" on Hermes.exe, close anyz*  running Hermes desktop window and retry.zC  If the log shows Electron download retries, rebuild via a mirror:zB    ELECTRON_MIRROR=<mirror-base-url> hermes desktop --force-build
build_onlyu/   ✗ --build-only --source produced no dist at: u"   ✓ Desktop source build ready at z (not launching; --build-only)u0   ✗ --build-only produced no launchable app at: z7  Expected an unpacked Electron app for the current OS.u    ✓ Desktop packaged app ready: u1   → Launching Hermes Desktop from source build...r>  r   r  uH   ✗ Desktop package build completed but no launchable app was found at: u'   → Launching packaged Hermes Desktop: )&r<  r)   rw   r@   r   hermes_loggingr   r   r#   r$   r=  rY  r/   r~   r  r(   r.  r  rP  r?  r@  r1  rV  r  r  rA  r  r'   mapr*  r+  r  r%   r.   r   r  r_  r  )rZ  r.  _setup_logging_guir  rL  r  r  r  r  build_neededbuild_label	nixos_envinstall_resultbuild_scriptr  build_resultpurgedr  
mirror_envlaunch_results                       r   cmd_guir  R  s   ')3K.(0022 ?+??@@@FFFFFF&&&&&    *//

Ct[%(( .*-&'t&.. 403,-t]D)) _,/T5E0F0F0Q0Q0S0S0[0[0]0],^,^()tUD!! O$'TX(A(A(C(C(K(K(M(M$N$N !$%00K|U33J$u55K6{CC * l5!! 	TUUU:;;;HQKKK nN 	e'44 r\gjp\prrsssLMMM_``` >1J>OWWYY [\\\FlFFFGGG_```t^ilr^rttuuuu (t[fir[rttuuuGHHHDEEEHQKKKKcNaccdddd # 
&;;'
 '
 '
  R	N,7K..^KTTTTUUUUDEEE(**I;C^cirsssN(A--=>>>E\EEEFFF27a888,7K..^K:+:::;;;&1=77vL ~ @LL ~|]a]f]fgjknpwgxgx]y]y|||}}}%>3|*D+[^fklllL&!++K+ 5[AA umnnn# , ,lqll++++ :+FFF#->3|2LR]cfns#t#t#tL&!++K+PaHbHb+  W X X X "#YY
0Y
,-5kBBB)~sE<.Hk_iqvwww&!++4555S\SSTTT<7**XYYYFGGG[\\\Z[[[05A666">{"K"K ? 2+>>> '|MMMM t\5))  
	j'44 ^V\H\^^___k{V7Kkkkllll (^[S\E\^^___KLLLHQKKKKh5Hhhhiii +ABBB"VT:s'KQ\bemrsss)***"rYdgpYprrsssGHHH'(;<< 	
I4G
I
IJJJNC(;$<$<#=;TW_deeeMH]%&&&&&s   A 
A,+A,exclude_pidsr  c                    
 g d}t          j                    }g }	 t          j        dk    rt	          j        g dddddd          }|j        d	k    s|j        g S d|j                            d          D ]}|	                                }|
                    d          r|t          d          d
         C|
                    d          ry|t          d          d
         }t          fd|D                       rGt          |          |k    r4	 |                    t          |                     # t          $ r Y w xY wnt	          j        g dddd          }|j        d	k    rt!          |dd                              d          D ]}|	                                }|rd|v r|                    d
d          }t          |          dk    rG	 t          |d	                   }	n# t          $ r Y jw xY w|d         
t          
fd|D                       r|	|k    r|                    |	           n$# t"          t          j        t&          f$ r g cY S w xY w r fd|D             }|S )uq  Return PIDs of ``hermes dashboard`` processes other than ourselves.

    ``hermes dashboard`` is a long-lived server process commonly started and
    forgotten.  When ``hermes update`` replaces files on disk, the running
    process keeps the old Python backend in memory while the JS bundle on
    disk is updated, causing a silent frontend/backend mismatch (e.g. new
    auth headers the old backend doesn't recognise → every API call 401s).

    The dashboard has no service manager (systemd / launchd), no PID file,
    and we can't know the original launch args — so the only sane action
    after an update is to kill the stale process and let the user restart
    it.  This helper is just the detection step; see
    ``_kill_stale_dashboard_processes`` for the kill.

    *exclude_pids* is an optional set of PIDs that must never be returned.
    This is used by the Hermes Desktop Electron app to protect its own
    backend child process: when the desktop spawns ``hermes dashboard`` as
    a backend and triggers an auto-update, the update must not kill the
    dashboard that the desktop itself manages.  The desktop sets the
    environment variable ``HERMES_DESKTOP_CHILD_PID`` on the spawned
    backend process; ``_kill_stale_dashboard_processes`` reads it and
    passes it here.  (#37532)

    Returns an empty list on any scan error (missing ps/wmic, timeout, etc.).
    )zhermes dashboardzhermes_cli.main dashboardzhermes_cli/main.py dashboardrc  )wmicprocessr%   zProcessId,CommandLinez/FORMAT:LISTTr  r   ignore)r(  r#  r)  r   r  r   NrM   rN  zCommandLine=z
ProcessId=c              3       K   | ]}|v V  	d S r{  rI   )r   r  current_cmds     r   r   z-_find_stale_dashboard_pids.<locals>.<genexpr>N  s(      ??A,??????rC   )psz-Az-ozpid=,command=r'  r  grepr=   r   c              3       K   | ]}|v V  	d S r{  rI   )r   r  r  s     r   r   z-_find_stale_dashboard_pids.<locals>.<genexpr>o  s'      ::A1<::::::rC   c                     g | ]}|v|	S rI   rI   )r   r  r  s     r   r  z._find_stale_dashboard_pids.<locals>.<listcomp>u  s#    MMMq7L7L!7L7L7LrC   )r#   r  r@   r   r*  r+  rA  r  ra   r0   rR   r   r  r   rz  r   rY  r   r,  rH   )r  patternsself_piddashboard_pidsr  re   pid_strrf   r$  r  r  r  s   `         @@r   _find_stale_dashboard_pidsr    s   :  H
 y{{H "N?<7""  ^SSS#   F  A%%)>	K++D11 ! !zz||??>22 !"&s>':':'<'<"=KK__\22 	!"3|#4#4#6#67G????h?????!LLH44!*11#g,,????) ! ! ! D!!*  ^333#	  F  A%%#FHb99??EE 3 3D#zz||H# !v'9'9 $NN433E5zzQ !!%(mm% ! ! ! !#AhG::::::::: 3sh&--c222z8'B   			  NMMMM^MMMsc   A I B9I "D<;I <
E	I E		BI G54I 5
H?I HAI I&%I&c                     	 ddl m}  n# t          $ r Y dS w xY w	 |                                 sdS |                                 }n# t          $ r Y dS w xY w|                    d          rdS 	 |                                 }n# t          $ r d}Y nw xY wt          d|dz            }t                       t          d           t          d	| d
           t          d           t          d           t          d           dS )a  Print a short heads-up about the skill curator after `hermes update`.

    Only fires when the curator is enabled AND has no recorded run yet, which
    is exactly the window where the gateway ticker used to fire Curator
    against a fresh skill library immediately after an update. We defer the
    first real pass by one ``interval_hours``; this notice tells the user how
    to preview or disable before then. Silent on steady state.
    r   r^  Nlast_run_at   r=      u   ℹ Skill curatorzC  Background skill maintenance is enabled. First pass is deferred ~zwd after installation; only agent-created skills are in scope and nothing is ever auto-deleted (archive is recoverable).z,  Preview now:  hermes curator run --dry-runz$  Pause it:     hermes curator pausezV  Docs:         https://hermes-agent.nousresearch.com/docs/user-guide/features/curator)	r  r^  r   
is_enabled
load_stater%   get_interval_hoursr  rw   )r^  statehoursdayss       r   _print_curator_first_run_noticer  y  s}   !!!!!!!   !!## 	F""$$   yy **,,   q%2+D	GGG	
		L	L 	L 	L  
 

8999	
0111	`    s4   	 
A A 
AA/B BBc                     	 ddl m}  n# t          $ r Y dS w xY w	 |                                 }n# t          $ r Y dS w xY w|                    d          }|sdS |                    d          |k    rdS |                    d          pd}|sdS d|vr.	 ||d<   |                     |           n# t          $ r Y nw xY wdS t          |          }t                       t          d	|            |                                D ]}t          d
|            t          d           	 ||d<   |                     |           dS # t          $ r Y dS w xY w)u  Print the most recent curator run summary, exactly once.

    The curator runs in the background (gateway tick + CLI session start),
    so users learn about skill consolidations only by stumbling into a
    rename. ``hermes update`` is a high-attention surface — surface the
    most recent run's rename map here, once.

    Show-once: state stamps ``last_run_summary_shown_at`` after printing.
    Subsequent ``hermes update`` invocations skip the block until a newer
    curator run lands. Silent when the curator has never run, when the
    most recent summary has already been shown, or when the summary has
    no rename information to display (no archives).
    r   r  Nr  last_run_summary_shown_atlast_run_summaryrM   rN  u   ℹ Skill curator — last run r  zP  (This message shows once per curator run. View anytime: hermes curator status))	r  r^  r   r  r%   
save_state_format_time_agorw   r"  )r^  r  r  summarywhenre   s         r    _print_curator_recent_run_noticer    s   !!!!!!!   ""$$    ))M**K yy,--<<ii*++1rG  7	1<E-.u%%%% 	 	 	D	 K((D	GGG	
2D
2
2333""$$  k4kk		/  -8)*5!!!!!   s<   	 
0 
>>B0 0
B=<B=*E 
EEiso_tsc                    	 ddl m }m}  |j        |                     dd                    }|j        |                    |j                  } |j        |j                  |z
  }t          |                                          }|dk     rdS |d	k     r|dz   d
S |dk     r|d	z   dS |dz   dS # t          $ r Y dS w xY w)zGRender an ISO timestamp as `Xh ago` / `Xd ago` / `Xm ago`. Best effort.r   rX  Zz+00:00N)tzinfor^  r_  r`  ra  rb  rc  re  recently)
r  rY  fromisoformatr  r  r\  r[  r   total_secondsr   )r  r  rY  rj  rk  secss         r   r  r    s   ////////#X#FNN3$A$ABB98<00BX\**R/5&&(())"99:$;;bj''''%<<dl))))%-&&&&   zzs$   BB5 B5 B5 -B5 5
CC:the running backend no longer matches the updated frontendreasonc                    d}t           j                            d          }|r{t                      }|                    d          D ]S}|                                }|s	 |                    t          |                     =# t          t          f$ r Y Pw xY w|r|}t          |          }|sdS t                       t          dt          |           d|  d           g g t          j        dk    r|D ]}	 t          j        d	d
t#          |          dgddd          }|j        dk    r                    |           n7                    ||j        p|j        pd                                f           # t,          t          j        t0          f$ r.}                    |t#          |          f           Y d}~d}~ww xY wnddl}	ddl}
|D ]}	 t          j        ||	j                   # t:          $ r                     |           Y ?t<          t0          f$ r.}                    |t#          |          f           Y d}~xd}~ww xY w |
j                    dz   }fd|D             }|r} |
j                    |k     rj |
j         d           g }ddl!m"} |D ]8} ||          r|                    |           #                    |           9|}|r |
j                    |k     j|D ]}	 t          j        ||	j#                                       |           3# t:          $ r                     |           Y Tt<          t0          f$ r.}                    |t#          |          f           Y d}~d}~ww xY wD ]}t          d|            D ]\  }}t          d| d|            r t          d           t          d           dS dS )u  Kill running ``hermes dashboard`` processes.

    Called at the end of ``hermes update`` (default ``reason``) and also
    from ``hermes dashboard --stop`` (which overrides ``reason``).  The
    dashboard has no service manager, so after a code update the running
    process is guaranteed to be serving stale Python against a
    freshly-updated JS bundle.  Leaving it alive produces silent
    frontend/backend mismatches (new auth headers the old backend doesn't
    recognise → every API call 401s).

    POSIX: SIGTERM, wait up to ~3s for graceful exit, SIGKILL any survivors.
    Windows: ``taskkill /PID <pid> /F`` since there's no clean SIGTERM
    equivalent for background console apps.

    The dashboard isn't auto-restarted because we don't know the original
    launch args (--host, --port, --insecure, --tui, --no-open).  The user
    restarts it manually; a hint is printed.
    NHERMES_DESKTOP_CHILD_PIDr  r  u   ⟲ Stopping z dashboard process(es) (rm   rc  taskkillz/PIDz/FTr  r'  r   rM         @c                 8    g | ]}|v|d  D             v|S )c                     h | ]
}|d          S )r   rI   )r   r  s     r   	<setcomp>z=_kill_stale_dashboard_processes.<locals>.<listcomp>.<setcomp>L  s    <R<R<RaQqT<R<R<RrC   rI   )r   r  failedkilleds     r   r  z3_kill_stale_dashboard_processes.<locals>.<listcomp>K  sA     
 
 
q1<R<R6<R<R<R3R3RA3R3R3RrC   g?)_pid_existsu       ✓ stopped PID u       ✗ failed to stop PID r  z*  Restart the dashboard when you're ready:z"    hermes dashboard --port <port>)$r#   r$   r%   ru  ra   r0   r   r   r   	TypeErrorr  rw   r   r@   r   r*  r+  r/   rA  rz  r   r  r   r,  rH   signalrg  r  SIGTERMProcessLookupErrorPermissionErrorr  r  gateway.statusr  SIGKILL)r  excluderaw_pidparsedr  pidsr  r  r  _signalrf  r  pendingstill_pendingr  err_msgr  r  s                   @@r   _kill_stale_dashboard_processesr
    s   0  $Gjnn788G  55MM#&& 	 	D::<<D 

3t99%%%%	*    	G%7;;;D 	GGG	
F#d))
F
FV
F
F
FGGGF$&F
|w 	- 	-C-#S48#'	   $))MM#&&&&MM3)M&-)M2(T(T(V(V"WXXX%z'@'J - - -sCFFm,,,,,,,,-	- 	!     	- 	-C-W_----% # # #c"""""#W- - - -sCFFm,,,,,,,,- #5?$$s*
 
 
 
 

 
 
  	$/%/++h66EKM 322222 ' ';s## '!((----MM#&&&&#G  	$/%/++h66  	- 	-C-W_---c""""% # # #c"""""#W- - - -sCFFm,,,,,,,,-  , ,*S**++++ > >W<C<<7<<==== 4:;;;2333334 4sg   #"BBB?BFG$GGG88II)$II?/L//NN $N		Nc           	      N   ddl }ddl}ddlm} t	          |           }|dk    r:t          d| d           t          d| d           t          j        d	           d
| d}t          d           |                    d          }	 t          j
                            |d| d          } |||           t          d           ddl}|                    |d          5 }	t          j
                            |          }
|	                                D ]}t          j
                            t          j
                            ||j                            }|                    |
t          j        z             s||
k    rt'          d|j         d          |j        dz	  dz  }|                    |          rt'          d|j                   |	                    |           ddd           n# 1 swxY w Y   t          j
                            |d|           }t          j
                            |          s`t          j        |          D ]K}t          j
                            ||          }t          j
                            |          r
|dk    r|} nLh d}d}t          j        |          D ]}||v rt          j
                            ||          }t          j
                            t3          t4                    |          }t          j
                            |          rIt          j
                            |          rt9          j        |           t9          j        ||           nt9          j        ||           |d	z  }t          d| d           n=# t@          $ r0}t          d|            t          j        d	           Y d}~nd}~ww xY wt9          j        |d           n# t9          j        |d           w xY wtC          t4                    }|rt          d| d|d	k    rd nd!            t          d"           dd#l"m#}m$}  |              |            }t          j%        d$d%g}|stM          |          }|rvi t          j'        d&t3          t4          d'z            i}tQ          |          r,|)                    d(d           |)                    d)d           tU          |d%g|*           nr	 tW          j,        |d+gz   t4          dd,           n@# tV          j-        $ r. tW          j,        t          j%        d$d-d.d/gt4          d0           Y nw xY wtU          |           t]                       t_          t4          d1z             	 dd2l0m1} t          d3            |d4          }|d5         rAt          d6te          |d5                    d7d8                    |d5                               |3                    d9          rAt          d:te          |d9                    d;d8                    |d9                               |3                    d<          r&t          d=te          |d<                    d>           |3                    d?          r&t          d@te          |d?                    dA           |d5         s$|3                    d9          st          dB           n# t@          $ r Y nw xY w	 ddCl4m5}  |t4                    rt          dD           n2# t@          $ r%}tl          7                    dE|           Y d}~nd}~ww xY wt                       t          dF           	 tq                       n2# t@          $ r%}tl          7                    dG|           Y d}~nd}~ww xY w	 ts                       n2# t@          $ r%}tl          7                    dH|           Y d}~nd}~ww xY wtu                       dS )IzUpdate Hermes Agent by downloading a ZIP archive.

    Used on Windows when git file I/O is broken (antivirus, NTFS filter
    drivers causing 'Invalid argument' errors on file creation).
    r   N)urlretrieverr  u   ✗ --branch=z: is not supported on the Windows ZIP-fallback update path.z  This path runs when git file I/O is broken on the system. Either resolve the git-side breakage (typically an antivirus or NTFS filter holding files open) and rerun `hermes update --branch z/`, or update against main with `hermes update`.r=   z@https://github.com/NousResearch/hermes-agent/archive/refs/heads/z.zipu!   → Downloading latest version...zhermes-update-rS   zhermes-agent-u   → Extracting...r  zZip-slip detected: z escapes extraction directory   i   z)ZIP contains unsupported symlink member: __MACOSX>   r  r  r   r(  u   ✓ Updated z items from ZIPu   ✗ ZIP update failed: Tr       ✓ Cleared  stale __pycache__ directorr  ies#   → Updating Python dependencies...	ensure_uvupdate_managed_uvr   r  VIRTUAL_ENVr  
PYTHONPATH
PYTHONHOMEr  rW   r  r  r(  	ensurepip	--upgrade--default-pipr  r  r%  rS     → Syncing bundled skills...rU  copied  +  new: r  updated     ↑ 
 updated: user_modified  ~  user-modified (kept)cleaned     −  removed from manifest     ✓ Skills are up to dateseed_cache_from_checkout1     ✓ Model catalog cache refreshed from checkoutz/Model catalog seed during zip update failed: %s   ✓ Update complete!#Curator first-run notice failed: %s$Curator recent-run notice failed: %s);r<  zipfileurllib.requestr  _resolve_update_branchrw   r@   r   mkdtempr#   r&   r'   r=  ZipFilerealpathinfolistfilenamerR   sepr   external_attrS_ISLNK
extractallisdirlistdirr/   r<  r)   r?  r  copytreecopy2r   r  hermes_cli.managed_uvr  r  rB  _ensure_uv_for_termuxr$   _is_termux_envrC  3_install_python_dependencies_with_optional_fallbackr*  r+  r  _update_node_dependenciesr-  rW  rT  r   r%   hermes_cli.model_catalogr-  r>  r?  r  r  r
  ) rZ  r<  r2  r  branchzip_urltmp_dirr~  _statzftmp_dir_realmembermember_pathr   	extractedr  r6  preserveupdate_countr  r  dstr  r  r  r  uv_binpip_cmduv_envrT  r  r-  s                                    r   _update_via_ziprW  t  s	    OOONNN****** $D))FF   	
 	
 	
 	P P P P	
 	
 	
 	W6WWW  

-...&677G?37<<)E)E)E)EFFGX&&&!"""__Xs++ 	#r 7++G44L++--   g..rw||GV_/U/UVV#..|bf/DEE#|33$\fo\\\  
 ,2h>==&& $UFOUU   MM'"""/	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	#4 GLL*B&*B*BCC	w}}Y'' 	Z((  GLL!44	7==++ Z )IE <;;Jy)) 	 	Dx',,y$//C',,s<00$77Cw}}S!! '7>>#&& 'M#&&&S))))S#&&&ALL:\:::;;;;   +++,,, 	gT22222gT22222 $L11G 
aWaaSTZ_aa	
 	
 	
 

/000BBBBBBBB Y[[F~tU+G 0&w// EJBJJs<&3H/I/IJJ&!! 	+JJ|T***JJ|T***;VUOQWXXXXX	N;-' #	     , 	 	 	N{KQ      	 	<GDDD,&'''111111-...4(((( 	USVH-..SSdiix@P6Q6QSSTTT::i   	YVI.//YY499VIEV;W;WYY   ::o&& 	NLVO455LLLMMM::i   	KI3vi011IIIJJJh 	1

9(=(= 	1/000   
KEEEEEE##L11 	GEFFF K K KFJJJJJJJJK 
GGG	
 !!!?')))) ? ? ?:A>>>>>>>>?@(**** @ @ @;Q????????@#%%%%%s   
AN- #DG6*N- 6G::N- =G:>F.N- ,P -
O'7&O"P "O''P P!T5 5:U21U2*E"\ 
\\%] 
]3]..]3^# #
_-___% %
`/``r  c                 ^   t          j        | ddgz   |ddd          }|j                                        sd S t          j        | ddgz   |dd          }|j                                        r*t	          d           t          j        | d	gz   |d
           ddlm}m}  |j        |j                  	                    d          }t	          d           t          j        | dddd|gz   |d           t          j        | g dz   |ddd          j                                        }|S )Nr  z--porcelainTr  zls-filesz
--unmergedr  r(  r#  u?   → Clearing unmerged index entries from a previous conflict...resetr  r(  r   rX  z%hermes-update-autostash-%Y%m%d-%H%M%Su8   → Local changes detected — stashing before update...stashpushz--include-untrackedr   r  )r  --verifyz
refs/stash)
r*  r+  r  r0   rw   r  rY  r[  r\  ri  )r  r  r  unmergedr  rY  
stash_name	stash_refs           r   _stash_local_changes_if_neededrb  7  s   ^8]++  F =   t ~:|,,	  H  JOPPPw'*DIIII++++++++hl++44/ J 

DEEEN7F$94LL   
 9999   UUWW  rC   ra  c                    t          j        | g dz   |ddd          }|j                                        D ]I}|                    d          \  }}}|                                |k    r|                                c S Jd S )N)r\  r  z--format=%gd %HTr  r!  )r*  r+  r  r"  r`   r0   )r  r  ra  
stash_listre   selectorr1  r  s           r   _resolve_stash_selectorrf  e  s     6666  J !,,.. $ $"nnS11!V<<>>Y&&>>##### '4rC   stash_selectorc                     t          d           t          d           |rt          d|            d S t          d|  d           d S )NzS  Check `git status` first so you don't accidentally reapply the same change twice.z@  Find the saved entry with: git stash list --format='%gd %H %s'z!  Remove it with: git stash drop z  Look for commit z7, then drop its selector with: git stash drop stash@{N})rw   )ra  rg  s     r   _print_stash_cleanup_guidanceri  v  sy     
]   

LMMM 
B.BBCCCCCeeee	
 	
 	
 	
 	
rC   prompt_userc                 p   |rt                       t          d           t          d           t          d           t          d           | |dd          }n2t                                                                                      }|dvr2t          d           t          d           t          d	|            d
S t          d           t	          j        | dd|gz   |dd          }t	          j        | g dz   |dd          }t          |j                                                  }|j        dk    s|r@t          d           |j                                        r&t          |j                                                   |j	                                        r&t          |j	                                                   |j                                        }	|	r8t          d           |	
                                D ]}
t          d|
            t          d           t          d|            t	          j        | g dz   |d           t          d           t          d|            d
S t          | ||          }|.t          d           t          d           t          |           nt	          j        | dd|gz   |dd          }|j        dk    rt          d           |j                                        r&t          |j                                                   |j	                                        r&t          |j	                                                   t          d           t          ||           t          d           t          d            dS )!Nu/   ⚠ Local changes were stashed before updating.zL  Restoring them may reapply local customizations onto the updated codebase.z=  Review the result afterward if Hermes behaves unexpectedly.z Restore local changes now? [Y/n]r  >   rM   r  r  z Skipped restoring local changes.z.Your changes are still preserved in git stash.z'Restore manually with: git stash apply Fu   → Restoring local changes...r\  applyTrY  )diff--name-onlyz--diff-filter=Ur   uF   ✗ Update pulled new code, but restoring local changes hit conflicts.z
Conflicted files:u     • u8   
Your stashed changes are preserved — nothing is lost.z  Stash ref: )rZ  --hardr,  r[  z"Working tree reset to clean state.z1Restore your changes later with: git stash apply uR   ⚠ Local changes were restored, but Hermes couldn't find the stash entry to drop.zT  The stash was left in place. You can remove it manually after checking the result.dropuP   ⚠ Local changes were restored, but Hermes couldn't drop the saved stash entry.u?   ⚠ Local changes were restored on top of the updated codebase.zB  Review `git diff` / `git status` if Hermes behaves unexpectedly.)rw   r  r0   r1   r*  r+  rQ   r  rA  r   r"  rf  ri  )r  r  ra  rj  input_fnr  restorer_  has_conflictsconflicted_filesr  rg  rp  s                r   _restore_stashed_changesru    s"     ?@@@Z	
 	
 	
 	MNNN0111x BCHHHHww}},,..H+++4555BCCCGIGGHHH5	
*+++n7GY//	  G ~<<<<	  H ..0011MQ-VWWW>!! 	*'.&&(()))>!! 	*'.&&(())) $?0022 	$'(((%0022 $ $lqll####IJJJ)i))***
 	1111	
 	
 	
 	

 	2333M)MMNNN u,Wc9EEN`	
 	
 	
 	b	
 	
 	
 	&i0000~w77	
 
 
 ?ab   {  "" +dk''))***{  "" +dk''))***f   *)^DDD	
KLLL	
NOOO4rC   c                    t          | ||          }| t          d           t          |           dS t          j        | dd|gz   |dd          }|j        dk    r{t          d	           |j                                        rAt          d
|j                                                                        d                     t          ||           dS t          d           dS )u  Throw away a stash created before an update, without applying it.

    Used only on a NON-interactive update when the user has set
    ``updates.non_interactive_local_changes: discard`` — i.e. they've opted out
    of keeping local source edits on this machine. Drops the stash entry
    instead of re-applying it, so the working tree stays clean at the freshly
    pulled HEAD. Unlike ``git reset --hard`` + ``git clean -fd``, this only
    affects what was stashed (tracked changes + the untracked files we
    explicitly captured) — ignored paths like node_modules/venv/build outputs
    are never touched, since they were never stashed.

    Returns True if the stash was dropped, False on a git failure (in which
    case the stash is left in place for safety).
    Nut   ⚠ Configured to discard local changes on non-interactive update, but Hermes couldn't find the stash entry to drop.Fr\  rp  TrY  r   uX   ⚠ Configured to discard local changes, but Hermes couldn't drop the saved stash entry.r  uS   → Discarded local source changes (updates.non_interactive_local_changes=discard).)	rf  rw   ri  r*  r+  rA  r   r0   r"  )r  r  ra  rg  rp  s        r   _discard_stashed_changesrw    s   & -Wc9EEN@	
 	
 	
 	&i000u>7FN33	  D !%	
 	
 	
 ; 	><t{((**5577:<<===%i@@@u	
_```4rC   >   (git@github.com:NousResearch/hermes-agent,git@github.com:NousResearch/hermes-agent.git,https://github.com/NousResearch/hermes-agent0https://github.com/NousResearch/hermes-agent.gitr{  z.skip_upstream_promptc                     	 t          j        | g dz   |dd          }|j        dk    r|j                                        S n# t
          $ r Y nw xY wdS )z5Get the URL of the origin remote, or None if not set.)remoteget-urloriginTrY  r   N)r*  r+  rA  r  r0   r   r  s      r   _get_origin_urlr  /  s    
5555	
 
 
 !!=&&((( "   4s   A A 
AA
origin_urlc                    | sdS |                      d          }|                    d          r
|dd         }t          D ]?}|                     d          }|                    d          r
|dd         }||k    r dS @dS )zDCheck if the origin remote points to a fork (not the official repo).Fr  r(  NT)r  r  OFFICIAL_REPO_URLS)r  r  officialofficial_normalizeds       r   _is_forkr  ?  s     u""3''J6"" %_
&  &ooc22''// 	;"5crc":,,,55 -4rC   c                 v    	 t          j        | g dz   |dd          }|j        dk    S # t          $ r Y dS w xY w)z-Check if an 'upstream' remote already exists.)r}  r~  upstreamTrY  r   Fr*  r+  rA  r   r  s      r   _has_upstream_remoter  P  sg    	7777	
 
 
  A%%   uu   '* 
88c                     	 t          j        | dddt          gz   |dd          }|j        dk    S # t          $ r Y dS w xY w)zHAdd the official repo as the 'upstream' remote. Returns True on success.r}  r   r  TrY  r   F)r*  r+  OFFICIAL_REPO_URLrA  r   r  s      r   _add_upstream_remoter  ^  sj    	x
4EFF	
 
 
  A%%   uus   .1 
??rb   r5  c                     	 t          j        | dd| d| gz   |dd          }|j        dk    r&t          |j                                                  S n# t          $ r Y nw xY wdS )zDCount commits on `head` that are not on `base`. Returns -1 on error.rev-list--countz..TrY  r   r  )r*  r+  rA  r   r  r0   r   )r  r  rb   r5  r  s        r   _count_commits_betweenr  l  s    
z9.?.?.?.?@@	
 
 
 !!v}**,,--- "   2s   AA 
A$#A$c                  V    ddl m}   |             t          z                                  S )z2Check if user previously declined to add upstream.r   r   )r   r   SKIP_UPSTREAM_PROMPT_FILEr)   r   s    r   _should_skip_upstream_promptr  |  s4    000000O 99AACCCrC   c                  ~    	 ddl m}   |             t          z                                   dS # t          $ r Y dS w xY w)z3Create marker file to skip future upstream prompts.r   r   N)r   r   r  touchr   r   s    r   _mark_skip_upstream_promptr    sa    444444			6	6==?????   s   *. 
<<c                 v    	 t          j        | g dz   |dd          }|j        dk    S # t          $ r Y dS w xY w)znAttempt to push updated main to origin (sync fork).

    Returns True if push succeeded, False otherwise.
    )r]  r  rr  z--force-with-leaseTrY  r   Fr  r  s      r   _sync_fork_with_upstreamr    sg    
	FFFF	
 
 
  A%%   uur  c                     t          | |          }|st                      rdS t                       t          d           t          d           t                       	 t          d                                                                          }n'# t          t          f$ r t                       d}Y nw xY w|dv rBt          d           t          | |          rt          d           d	}n0t          d
           dS t          d           t                       dS t                       t          d           	 t          j        | g dz   |d	d	           n%# t          j        $ r t          d           Y dS w xY wt          | |dd          }t          | |dd          }|dk     s|dk     rt          d           dS |dk    rPt                       t          d| d           t          d           t          d           t          d           dS |dk    rt          d           dS t                       t          d| d           t          d           	 t          j        | g dz   |d	           n%# t          j        $ r t          d           Y dS w xY wt          d            t          d!           t          | |          rt          d"           dS t          d#           t          d$           dS )%a[  Check if fork is behind upstream and sync if safe.

    This implements the fork upstream sync logic:
    - If upstream remote doesn't exist, ask user if they want to add it
    - Compare origin/main with upstream/main
    - If origin/main is strictly behind upstream/main, pull from upstream
    - Try to sync fork back to origin if possible
    Nu=   ℹ Your fork is not tracking the official Hermes repository.zA  This means you may miss updates from NousResearch/hermes-agent.z/Add official repo as 'upstream' remote? [Y/n]: rh  >   rM   r  r  u   → Adding upstream remote...uF     ✓ Added upstream: https://github.com/NousResearch/hermes-agent.gitTu<     ✗ Failed to add upstream remote. Skipping upstream sync.zg  Skipped. Run 'git remote add upstream https://github.com/NousResearch/hermes-agent.git' to add later.u   → Fetching upstream...)fetchr  rr  --quiet)r  r(  r  u7     ✗ Failed to fetch upstream. Skipping upstream sync.zupstream/mainzorigin/mainr   u9     ✗ Could not compare branches. Skipping upstream sync.u   ℹ Your fork has z commit(s) not on upstream.z2  Skipping upstream sync to preserve your changes.z-  If you want to merge upstream changes, run:z    git pull upstream mainu&     ✓ Fork is up to date with upstreamu   → Fork is z commit(s) behind upstreamu   → Pulling from upstream...)pull	--ff-onlyr  rr  r  uO     ✗ Failed to pull from upstream. You may need to resolve conflicts manually.u     ✓ Updated from upstreamu   → Syncing fork...u     ✓ Fork synced with upstreamuL     ℹ Got updates from upstream but couldn't push to fork (no write access?)zF    Your local repo is updated, but your fork on GitHub may be behind.)r  r  rw   r  r0   r1   r  r  r  r  r*  r+  r  r  r  )r  r  has_upstreamr  origin_aheadupstream_aheads         r   _sync_with_upstream_if_neededr    s    (55L !')) 	F 	MNNNQRRR	GHHNNPPVVXX H +, 	 	 	GGGHHH	 '''1222#GS11 \    $TUUUy   '(((F
 
GGG	
$%%%	>>>>		
 	
 	
 	
 	
 (   GHHH
 *'3WWL+m_ N a>A--IJJJ aL<LLLMMMBCCC=>>>*+++ 6777 
GGG	
C
C
C
CDDD	
()))
????	
 	
 	
 	
 	

 (   ]	
 	
 	
 		 

'((( 

   -- X/00000Z	
 	
 	
 	VWWWWWs6   3B !B76B7=E E=<E=I< <JJc                     g } ddl m}  |            }|                     |           |dz  }|                                r@|                                D ]+}|                                r|                     |           ,| D ]@}	 |dz  }|                                r|                                 1# t          $ r Y =w xY wdS )u  Delete the update-check cache for ALL profiles so no banner
    reports a stale "commits behind" count after a successful update.

    The git repo is shared across profiles — when one profile runs
    ``hermes update``, every profile is now current.
    r   r   r   z.update_checkN)r   r   rz  rw  ry  r)   rE  r   )homesr   default_homeprofiles_rootr  r3   
cache_files          r   _invalidate_update_cacher    s    E888888**,,L	LL :-M $"**,, 	$ 	$E||~~ $U###  	/J  "" $!!### 	 	 	D	 s   -B44
C Callr  c                 4   	 ddl }t          dz                      d          5 }|                    |                              di           }ddd           n# 1 swxY w Y   n# t
          $ r g cY S w xY w|                    di           }t          |t                    sg S |                    | g           }g }|D ]Y}d|v rSd|v rO|                    dd	          d	                             dd	          d         }||v r|	                    |           Z|S )
zReturn optional extras referenced by a dependency group.

    ``group`` is usually ``all`` (desktop/server broad install) or
    ``termux-all`` (Termux-compatible broad install).
    r   Npyproject.tomlr5  projectzoptional-dependencies[r  r=   )
tomllibr<  r+   loadr%   r   r-   r.   ra   rz  )	r  r  rd   r  optional_depsr  
referencedr  r   s	            r   !_load_installable_optional_extrasr  .  s|   --33D99 	>Vll6**..y"==G	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	> 	>   			 KK 7<<MmT** 	UB''DJ ( (#::#**99S!$$Q'--c155a8D}$$!!$'''s4   !A% *AA% AA%  A!A% %A43A4c                      t           dz  S )Nz.update-incomplete)r<  rI   rC   r   _update_marker_pathr  R  s    ...rC   c                     	 t                                          dt          j                     dt	          j                     dd           dS # t          $ r&} t                              d|            Y d} ~ dS d} ~ ww xY w)z6Drop the interrupted-install breadcrumb. Never raises.zstarted=z
pid=rN  r   r   z,Could not write update-incomplete marker: %sN)	r  rP  rf  rg  r#   r  rH   r>  r?  r   s    r   _write_update_incomplete_markerr  V  s    J((:uz||::29;;:::W 	) 	
 	
 	
 	
 	
  J J JCSIIIIIIIIIJs   AA 
B A;;B c                      	 t                                                       dS # t          $ r Y dS t          $ r&} t                              d|            Y d} ~ dS d} ~ ww xY w)z8Remove the interrupted-install breadcrumb. Never raises.z,Could not clear update-incomplete marker: %sN)r  rE  r   rH   r>  r?  r  s    r   _clear_update_incomplete_markerr  `  s    J$$&&&&&    J J JCSIIIIIIIIIJs    $ 
A 	A AA c                  h	   t                                                      sdS t          dz                                  st	                       dS t          dz  } 	 t          j        | t
          j        t
          j        z  t
          j	        z            }t          j
        |t          j                     d                                           t          j        |           n# t          $ r[ 	 t          j                    |                                 j        z
  dk    r|                                  n# t(          $ r Y nw xY wY dS t(          $ r%}t*                              d|           Y d}~nd}~ww xY wd}t.          j        }	 	 t          j        d          }t          j        dd           n# t(          $ r d}Y nw xY wt.          j        t.          _        t9          d	           	 d
dlm} 	 t?          j         t.          j!        ddddgt          d           n2# tD          $ r%}t*                              d|           Y d}~nd}~ww xY w |            }|ri t
          j#        dtI          t          dz            i}tK          |          r,|&                    dd           |&                    dd           tO          |dg|tK          |          rdnd           n.tO          t.          j!        ddgtK                      rdnd           t	                       t9          d           n# tD          $ r}t*                              d|           t9          d           t9          d           t9          d t                      t9          d!t.          j!         d"           t9          d!t.          j!         d#           Y d}~nd}~ww xY w|t.          _        |;	 t          j        |d           t          j        |           n# t(          $ r Y nw xY w	 |                                  dS # t(          $ r Y dS w xY w# |t.          _        |;	 t          j        |d           t          j        |           n# t(          $ r Y nw xY w	 |                                  w # t(          $ r Y w w xY wxY w)$u  Finish a dependency install that a prior ``hermes update`` left half-done.

    Triggered on launch when ``.update-incomplete`` is present — meaning the
    code was pulled but the dep install was killed before it verified clean.
    Unconditionally bootstraps pip via ``ensurepip`` (a killed ``pip install``
    can wipe pip from the venv entirely, which blocks the venv from recovering
    on its own), then re-runs the editable ``.[all]`` install + core-dependency
    verification, then clears the marker.

    Never raises: a recovery failure must not block launch.  If it can't
    self-heal it prints the one-line manual command and leaves the marker so
    the next launch tries again.

    Concurrency: the marker lives next to the shared venv, so a gateway start
    plus a CLI launch (or two profiles starting at once) can both see it.  An
    ``O_EXCL`` lockfile ensures only one process runs the reinstall; the
    others skip and let the winner clear the marker.

    Output: everything — our status lines AND the streamed pip/uv install
    (which inherits fd 1) — is routed to stderr.  Launches whose stdout is a
    protocol stream (``hermes acp`` speaks JSON-RPC on stdout) must never get
    install noise on stdout.
    Nr  z.update-incomplete.lockrN  r`  z*Could not create install-recovery lock: %sr=   r   ug   ⚠ A previous `hermes update` was interrupted mid-install — finishing dependency installation now...r   )r  r   r  r  r  Tr[  z,ensurepip during install recovery failed: %sr  r  r  r  r  
termux-allr  r  r  r  uH   ✓ Dependency installation recovered — your install is healthy again.z'Interrupted-install recovery failed: %su3   ✗ Could not auto-recover the interrupted install.z  Recover manually with:    cd r  z -m ensurepip --upgradez -m pip install -e '.[all]')(r  r)   r<  r-  r  r#   r+   O_CREATO_EXCLO_WRONLYrG   r  r  r   FileExistsErrorrf  rg  r=  r  rE  rH   r>  r?  r@   r  dupdup2r   rw   rB  r  r*  r+  rB  r   r$   r/   rD  rC  rE  )	lock_pathfdr   saved_stdout_fdsaved_sys_stdoutr  rT  rV  s           r   !_recover_from_interrupted_installr  j  s{   0   '')) 
 ++4466 '))) 88IHWY
RY 6 DEE
	'''..00111
   	z||inn..77$>>  """ 	 	 	D	 H H H 	A3GGGGGGGGH
 OzE	# fQiiOGAqMMMM 	# 	# 	#"OOO	#Z
7	
 	
 	

*	F777777
R^T;_U$#'    
  R R RKSQQQQQQQQR Y[[F RBJRs<&;P7Q7QRR!&)) 3JJ|T222JJ|T222CUO*8*@*@K,,e     D^T51*8*:*:E,,   
 ,---\]]]] 	F 	F 	F LLBCHHHGHHH,---*L**+++@@@@AAADDDDEEEEEEEE	F &
&+++))))   	 	 	 	DD	 &
&+++))))   	 	 	 	D	s0  BC# #
E5.AD43E54
E>E5 EE5	E5E00E5)F2 1Q 2G>Q  G(Q *L/ 1+H L/ 
I'IL/ IC"L/ .Q /
O9B
OQ OQ )P	 	
PPP0 0
P>=P>R1)Q;:R1;
RR1RR1R! R1!
R.+R1-R..R1   )r  heartbeat_interval_secondsr  c                   t          j                    t          j                    d	fd}t          j        |d          }|                                 	 t          j        | t          d|           	                                 |
                    d           dS # 	                                 |
                    d           w xY w)
a3  Run dependency install command with periodic heartbeat output.

    Some resolvers/build backends (especially when compiling Rust/C extensions)
    can stay quiet for minutes. Emit a simple elapsed-time heartbeat so users
    know ``hermes update`` is still progressing even if pip/uv itself is silent.
    r   Nc                                                     sOt          t          j                    z
            } t	          d|  dd                                          Md S d S )Nu%     … still installing dependencies (uC   s elapsed) — compiling Rust/C extensions can take several minutesTr  )r   r   rf  rg  rw   )elapseddoner  r   s    r   
_heartbeatz/_run_install_with_heartbeat.<locals>._heartbeat  s    ))677 	%*,,.//GL L L L    ))677 	 	 	 	 	rC   Tr  )r  r  r  g?r  r  )r  Eventrf  rg  r  r   r*  r+  r<  ru  r'   )r#  r  r  r  r5  r  r   s     `  @@r   _run_install_with_heartbeatr    s     ?DJLLE        	
4888AGGIII			
 	
 	
 	
 	


	s 	


	ss   B& &,Cc                  "    t           j        dk    S )Nrc  r@   r   rI   rC   r   _is_windowsr    s    <7""rC   c                      t           dz  } |                                 sdS | t                      rdndz  }|                                r|ndS )zKReturn the venv Scripts directory if we're running inside the project venv.r  NScriptsr  )r<  rw  r  )venv_dirr  s     r   _venv_scripts_dirr    sS    f$H?? t{}}?))%@Gnn&&077D0rC   scripts_dirc                 6    t                      sg S | dz  | dz  gS )u  Entry-point shims that uv may try to rewrite during ``pip install -e .``.

    On Windows these are .exe launchers generated by setuptools/uv. On POSIX
    they're regular Python scripts which can be replaced atomically — no
    self-replacement hazard exists outside Windows.
    
hermes.exezhermes-gateway.exe)r  )r  s    r   _hermes_exe_shimsr     s0     == 	l"** rC   )exclude_pidr  c                N   t                      sg S 	 ddl}n# t          $ r g cY S w xY wt                      }t	          |           D ]}	 |                    t          |                                                                                     J# t          $ r7 |                    t          |                                                     Y w xY w|sg S |t          |          h}nt          j                    h}	 t          t          |                    }	 |                    |                                          }n# t          $ r g }Y nw xY w|D ]}	 |                                }	n# t          $ r Y $w xY w|	s+	 t          t%          |	                                                                                    }
n8# t          t&          f$ r$ t          |	                                          }
Y nw xY w|
|v r9	 |                    t          |j                             # t          $ r Y w xY wn# t          $ r Y nw xY wg }	 |                    g d          }n# t          $ r g cY S w xY w|D ]'}	 |j        }n# t          $ r Y w xY w|                    d          }|                    d          }|r|||v rO	 t          t%          |                                                                                    }n8# t          t&          f$ r$ t          |                                          }Y nw xY w||v rZ|                    d          pt%          |          j        }|                    t          |          t          |          f           )|S )um  Find other live processes whose .exe is one of our entry-point shims.

    Windows blocks DELETE/REPLACE on a running .exe — and even RENAME on the
    same .exe when another process opened it without ``FILE_SHARE_DELETE``.
    The Hermes Desktop Electron app spawns ``hermes.EXE`` as a backend child,
    so during ``hermes update`` the user-invoked process and the desktop's
    child both hold the same file. The quarantine rename then fails with
    ``[WinError 32]`` and uv inherits the lock.

    This helper enumerates processes whose ``exe`` matches one of the venv's
    shims (``hermes.exe`` / ``hermes-gateway.exe``) and returns ``(pid,
    process_name)`` pairs. The caller's own PID and its entire ancestor
    chain are excluded so the running ``hermes update`` invocation never
    reports itself — this matters on Windows where the setuptools .exe
    launcher (``hermes.exe``) is a separate process from the Python
    interpreter it loads (``python.exe``).

    Returns an empty list off-Windows, on missing psutil, or when no other
    instances exist. Never raises — process enumeration is best-effort.
    r   N)r  r  r   r  r  r   )r  r  r   ru  r  r   r/   r.  r1   rH   r   r#   r  r  r8  ProcessrL  r  r~   r   r  r  r  r%   r   rz  )r  r  r  
shim_pathsshimr  seed	ancestorsancestoranc_exeanc_normmatchesr  r  r  r  r  exe_normr   s                      r   #_detect_concurrent_hermes_instancesr  /  s1   . == 	   			 55J!+.. . .	.NN3t||~~..44667777 	. 	. 	.NN3t99??,,-----	. 	. "%k"2"2!3	}D&&''	t,,4466II 	 	 	III	! 	 	H",,..    0tG}}446677==??Z( 0 0 0w<<--//0:%% $$S%6%67777    H &	      &(G''(>(>(>??		   			  2 2	9DD 	 	 	H	hhuoohhuoo 	ckSL%8%8	(499,,..//5577HH$ 	( 	( 	(3xx~~''HHH	(z!!88F##5tCyy~DNNCHHc$ii0111Ns    &&	AB>CC H= 'E H= EH= EH= E10H= 1
E>;H= =E>>H= A GH= 2G;8H= :G;;H= 'H+*H= +
H85H= 7H88H= =
I
	I
I( (I76I7 J
JJA L2MMr  c                    |dz  }dg}| D ] \  }}|                     d| d|            !|                     d           |                     d| d           |                     d           |                     d           |                     d	           |                     d
           |                     d           | rwd                    d | D                       }|                     d           |                     d           |                     d| d           |                     d           |                     d           |                     d           d                    |          S )zCBuild a human-readable explanation + remediation hint for the user.r  u"   ✗ Another hermes.exe is running:    PID r  rM   z'  Updating now would fail to overwrite z becausez1  Windows blocks REPLACE on a running executable.z9  Close Hermes Desktop, exit any open `hermes` REPLs, andz;  stop the gateway (`hermes gateway stop`) before retrying.r!  c              3   &   K   | ]\  }}d | V  dS )z/PID NrI   )r   r  r1  s      r   r   z7_format_concurrent_instances_message.<locals>.<genexpr>  s,      @@fc1MCMM@@@@@@rC   z8  If you've already closed everything and these PIDs arez8  stale, terminate them directly, then retry the update:z      taskkill z /Fz9  Override with `hermes update --force` if you've alreadyz7  confirmed those processes will not write to the venv.rN  )rz  r'   )r  r  r  rG  r  r   pid_argss          r   $_format_concurrent_instances_messager    s    %D12E / /	T---t--....	LL	LLI4IIIJJJ	LLDEEE	LL	LLLMMM	LLNOOO	LL 88@@@@@@@OPPPOPPP4x444555R	LLLMMM	LLJKKK99UrC   r  )max_attemptsr  c          	      J   g }t                      s|S ddl}t          |                                dz            }g d}t          dt	          |t          |                              }t          |           D ](}|                                s|                    |j	        d| z             }d}	t          |          D ]m}
||
         dz  }|r|                    |           	 |                    |           |                    ||f           d}	 n# t          $ r}|}	Y d}~fd}~ww xY w|	t          ||          }|r(t!          d|j         d	           t!          d
           t!          d|j         d|	j        j         d           t!          d           *|S )uP  Pre-empt Windows file lock on the running ``hermes.exe``.

    Windows allows RENAMING a mapped/running executable (the kernel tracks the
    file by handle, not path), but blocks DELETE/REPLACE while it's loaded. uv
    needs to overwrite the entry-point shims during ``pip install -e .``;
    when ``hermes update`` runs, ``hermes.exe`` IS the live process, and uv
    fails with ``Access is denied. (os error 5)``.

    We rename live shims to ``hermes.exe.old.<unix-ms>`` first. uv then writes
    fresh shims at the original paths. The ``.old`` files are cleaned up on
    the next hermes invocation by ``_cleanup_quarantined_exes``.

    Rename can still fail when *another* process has opened the .exe without
    ``FILE_SHARE_DELETE`` — typically AV real-time scanners with transient
    handles (recovers in <1s), or the Hermes Desktop backend child process
    (won't recover until the user closes it). We mitigate:

    1. Retry up to ``max_attempts`` times with exponential backoff
       (100/250/500/1000 ms). Handles the AV-scanner case.
    2. If all retries fail, schedule the .exe for replacement on next
       reboot via ``MoveFileExW(MOVEFILE_DELAY_UNTIL_REBOOT)``. This still
       lets uv create a fresh shim at the original path (Windows will keep
       the old file's content under a new name until the reboot), so the
       update can complete; the user just needs to reboot to fully unload
       the stale image.
    3. Print a clear warning naming the most likely culprit (running
       Hermes Desktop / gateway / REPL) and pointing to ``--force``.

    Returns the list of (original, quarantined) pairs so the caller can roll
    back if the install itself fails before uv writes a replacement. Pairs
    where we used ``MOVEFILE_DELAY_UNTIL_REBOOT`` are NOT returned — they
    are already deferred and roll-back is meaningless.
    r   N  )r   d        r  r=   z.old.g     @@     ⚠ zD is locked by another process; scheduled replacement on next reboot.zb    The new shim was written at the same path, but a reboot is needed to fully unload the old one.u     ⚠ Could not quarantine rl   z&: another process is holding it open).zy    Close Hermes Desktop, exit other `hermes` REPLs, stop the gateway, or pause AV scanning, then re-run `hermes update`.)r  rg  r   r  r  r   r  r)   r  r  r  r  renamerz  rH   _schedule_replace_on_rebootrw   r   	__class__r  )r  r  movedrg  rH  
backoff_msattemptsr  rf  last_excattemptdelayr  	scheduleds                 r   _quarantine_running_hermes_exer    s.   H &(E== KKK		d"##E *))J1c,J8899H!+.. 2
 2
{{}} 	!!$+"?@@#'X 	 	Gw'&0E "

5!!!F###dF^,,,     0f==	 	/ / / /   @    	4$) 4 4x7I7R 4 4 4	
 	
 	
 	J	
 	
 	
 	

 Ls   '.D
D-!D((D-r  quarantine_targetc                 @   t                      sdS 	 ddl}ddlm} d}d}|j        j        j        }|j        |j        |j        g|_        |j	        |_
         |t          |           t          |          ||z            }t          |          S # t          $ r Y dS w xY w)u7  Schedule ``shim`` -> ``quarantine_target`` via PendingFileRenameOperations.

    Uses Win32 ``MoveFileExW`` with ``MOVEFILE_REPLACE_EXISTING |
    MOVEFILE_DELAY_UNTIL_REBOOT``. The OS persists the rename in
    ``HKLM\System\CurrentControlSet\Control\Session Manager\
    PendingFileRenameOperations`` and applies it before any user-mode code
    runs on next boot — at which point no process can hold the .exe.

    Returns ``True`` if the schedule call succeeded, ``False`` otherwise
    (non-Windows, ctypes failure, lack of privilege, etc.). Never raises.
    Fr   N)wintypesr=   r  )r  r   r  windllkernel32MoveFileExWLPCWSTRDWORDargtypesBOOLrestyper/   rQ   r   )r  r  r   r  MOVEFILE_REPLACE_EXISTINGMOVEFILE_DELAY_UNTIL_REBOOTr	  r5  s           r   r  r  %  s     == u######$'!&)#m,8 ( 0(2BHNS&m[II!""%(CC
 

 Bxx   uus   A<B 
BBr  c                     | D ]S\  }}	 |                                 s)|                                 r|                    |           D# t          $ r Y Pw xY wdS )zMRoll back ``_quarantine_running_hermes_exe`` if uv didn't write replacements.N)r)   r  rH   )r  originalquarantineds      r   _restore_quarantined_exesr  H  s    !&  +	??$$ -););)=)= -""8,,, 	 	 	D		 s   =A
AAr  r  c                    g }|t          |          }	 t          | |           dS # t          $ r |t          |            w xY w)uF  Run an editable install, quarantining the running ``hermes.exe`` first.

    Any ``pip install -e .`` (or ``--reinstall``) rewrites the entry-point
    shims, and on Windows the live ``hermes.exe`` is the running process —
    pip can neither delete nor overwrite it, so without quarantine the shim
    is left missing and ``hermes`` drops off PATH. This wraps
    :func:`_run_install_with_heartbeat` with the same rename-out-of-the-way /
    restore-on-failure dance that the primary install path uses, so EVERY
    install that touches the shims is protected — including the
    verification-repair reinstalls in
    :func:`_verify_core_dependencies_installed`, which previously called
    ``_run_install_with_heartbeat`` directly and bypassed quarantine.

    Off-Windows (``scripts_dir is None``) this is a thin pass-through.
    Nr  )r  r  BaseExceptionr  )r#  r  r  r  s       r   _run_quarantined_installr  R  sn    * &(E.{;;#CS111111    "%e,,,s	   ( Ac                     t                      sdS | t                      } | dS 	 |                     d          D ]'}	 |                                 # t          $ r Y $w xY wdS # t          $ r Y dS w xY w)a  Sweep ``hermes.exe.old.*`` left by prior updates.

    Called early on every hermes invocation. The .old files are unlocked once
    their owning process exited, so deletion succeeds the next run. Silent
    no-op when nothing's there or on file-locked / permission errors.
    Nz*.exe.old.*)r  r  rg  rE  rH   )r  stales     r   _cleanup_quarantined_exesr  t  s     == ')) %%m44 	 	E   	 	
    s4   A% AA% 
A A% A  A% %
A32A3c                  j   	 ddl m}  n3# t          $ r&}t                              d|           Y d}~dS d}~ww xY w	 |                                 }n3# t          $ r&}t                              d|           Y d}~dS d}~ww xY w|sdS t                       t          dt          |           d           	 |                     d	          }n*# t          $ r}t          d
|            Y d}~dS d}~ww xY wd |	                                D             }d |	                                D             }d |	                                D             }d |	                                D             }|r5t          dt          |           dd
                    |                      |r t          dt          |           d           |rld
                    d |D                       }|d         d                             dd          d         }	t          dt          |           d|	 d|            |ry|D ]V\  }
}|                    dd          d         }	t          |	          dk    r|	dd         dz   }	t          d|
 d|	            Wt          d           t          d            dS dS )!u  Refresh lazy-installed backends after a code update.

    When pyproject.toml's ``[all]`` extra was slimmed down (May 2026), most
    optional backends moved to ``tools/lazy_deps.py`` and only install on
    first use. ``hermes update`` runs ``uv pip install -e .[all]`` which
    leaves those packages untouched — so if we bump a pin in
    :data:`LAZY_DEPS` (CVE response, transitive bug fix), users who already
    activated the backend keep the stale version forever.

    This function asks lazy_deps which features the user has previously
    activated and reinstalls them under the current pins. Features the
    user never enabled stay quiet — no churn for cold backends.

    Never raises. A failure here must not block the rest of the update.
    r   )	lazy_depsz(Lazy refresh skipped (import failed): %sNz1Lazy refresh skipped (active_features failed): %su   → Refreshing z active lazy backend(s)...Fr  u(     ⚠ Lazy refresh failed unexpectedly: c                 $    g | ]\  }}|d k    |S )	refreshedrI   r   r  r  s      r   r  z1_refresh_active_lazy_features.<locals>.<listcomp>  s&    CCCtq!!{2B2B2B2B2BrC   c                 $    g | ]\  }}|d k    |S )r  rI   r!  s      r   r  z1_refresh_active_lazy_features.<locals>.<listcomp>  s!    ???TQYqrC   c                 F    g | ]\  }}|                     d           ||fS )zfailed:r   r!  s      r   r  z1_refresh_active_lazy_features.<locals>.<listcomp>  s1    LLLAALL4K4KLq!fLLLrC   c                 F    g | ]\  }}|                     d           ||fS )zskipped:r   r!  s      r   r  z1_refresh_active_lazy_features.<locals>.<listcomp>  s1    NNN$!QQ\\*5M5MN1vNNNrC   r#  z refreshed: r       ✓ z already currentc              3       K   | ]	\  }}|V  
d S r{  rI   )r   r  r1  s      r   r   z0_refresh_active_lazy_features.<locals>.<genexpr>  s&      001!000000rC   r=   r  r  u     · z
 skipped (r     r  r  z failed to refresh: z9  Backends keep their previously-installed version; rerunz6  `hermes update` once the upstream issue is resolved.)toolsr  r   r>  r?  active_featuresrw   r   refresh_active_featuresr  r'   ra   )r  r   r  resultsr   r  r  skippednamesr  featurer  s               r   _refresh_active_lazy_featuresr/    sF    #######   ?EEE**,,   H#NNN  	GGG	
CCKK
C
C
CDDD3353AA    	>>>???	 DCw}}CCCI??W]]__???GLLLLLFNN'--//NNNG KIs9~~II499Y3G3GIIJJJ 75s7||555666 B 		0000000A$$T1--b1@c'll@@f@@@@AAA H% 	B 	BOGV\\$**2.F6{{S  -@7@@@@AAAAIJJJFGGGGGH Hs?   	 
949A 
BA==B8C 
C6C11C6r  install_cmd_prefixc                    t                      rt                      nddt          t                   ddf fd}	  |ddd| dg           dS # t          j        $ r t          d	           Y nw xY w |g d
           g }g }t          |          D ]T}	  |ddd| dg           |                    |           +# t          j        $ r |                    |           Y Qw xY w|r%t          dd	                    |                      |r%t          dd	                    |                      t           |           dS )a   Install base deps plus as many optional extras as the environment supports.

    By default this targets ``.[all]``; Termux callers can pass
    ``group='termux-all'`` to use the curated Android-compatible profile.

    On Windows, pre-renames live ``hermes.exe`` / ``hermes-gateway.exe`` shims
    in the venv Scripts dir before each install attempt so uv can write fresh
    copies (Windows blocks REPLACE on a running .exe but allows RENAME). See
    ``_quarantine_running_hermes_exe`` for the rationale.
    NrZ  r   c                 2    t          | z              d S )Nr  )r  )rZ  r  r0  r  s    r   _installzE_install_python_dependencies_with_optional_fallback.<locals>._install  s0     %3K	
 	
 	
 	
 	
 	
rC   r  r=  z.[r  u`     ⚠ Optional extras failed, reinstalling base dependencies and retrying extras individually...)r  r=  r  r  u0     ✓ Reinstalled optional extras individually: r  u1     ⚠ Skipped optional extras that still failed: r  )r  r  r  r/   r*  r  rw   r  rz  r'   #_verify_core_dependencies_installed)r0  r  r  r3  failed_extrasinstalled_extrasr  r  s   ``     @r   rE  rE    s     *5@#%%%DK
tCy 
T 
 
 
 
 
 
 
 


)T====1222( 
 
 
n	
 	
 	
 	
 	


 H###$$$!M"$2??? ( (	(Hi}E}}}5666##E****, 	( 	( 	(  '''''	(  
\tyyIY?Z?Z\\	
 	
 	
  
Z		-@X@XZZ	
 	
 	
 ((:5QQQQQQs#   A A43A4'C$C*)C*c          
      2
   	 ddl }n# t          $ r Y dS w xY wt          dz  }|                                sdS 	 t	          |d          5 }|                    |          }ddd           n# 1 swxY w Y   |                    di                               dg           pg }n3# t          $ r&}t          	                    d|           Y d}~dS d}~ww xY wg }		 ddl
m}
 |D ]?}	  |
|          }|	                    |j        |j        f           0# t          $ r Y <w xY wn# t          $ r |D ]}|                    d	d
          d         }dD ]$}||v r|                    |d
          d         } n%|                                                    dd
          d                                         }|r|	                    |df           Y nw xY wg |	D ]l\  }}|                    |           	 |                                r                    |           H# t          $ r                     |           Y iw xY wsdS t%          |           dS dt&          t(                   ffd} |            }|sdS t+          dt-          |           dd                    |dd                    t-          |          dk    rdnd            t+          d           t1                      rt3                      nd}g d}	 t5          | |z   |           nG# t6          j        $ r5}t                              d|           t+          d           Y d}~dS d}~ww xY w |            }|st+          d           dS i |D ]}|                    d	d
          d                                         }|}dD ]$}||v r|                    |d
          d         } n%||                                                    dd
          d                                         <   fd|D             }t+          dd                    |                      	 t=          | ddg|z              n^# t6          j        $ rL}t                              d |           t+          d!d                    |           d"           Y d}~dS d}~ww xY w |            }|r(t+          d#d                    |           d"           dS t+          d           dS )$u  Check that every base dep from pyproject.toml is importable; if not, retry.

    Reads ``pyproject.toml`` directly (so we don't trust the venv's stale
    metadata), filters out deps gated by ``;`` environment markers that don't
    apply to this platform, and runs ``importlib.metadata.version()`` in the
    venv interpreter for each one. If anything is missing we reinstall the
    base group with ``--reinstall`` to force uv to re-resolve, then check
    again. We treat the final state as a warning rather than a hard failure
    so a single broken-on-PyPI dep can't block an otherwise-successful
    update — but the warning makes the partial install visible at the spot
    that caused it, instead of hours later in a downstream subprocess.
    r   Nr  r5  r  dependenciesz3dep verification: failed to read pyproject.toml: %s)Requirement;r=   )z==z>=z<=z~=>r  z!=r  r   c                     d} 	 t          j        t                    d| gddd          }n4# t          $ r'}t                              d|           g cY d }~S d }~ww xY wd |j                                        D             S )Nzimport importlib.metadata as md, sys
missing=[]
for name in sys.argv[1:]:
    try: md.version(name)
    except md.PackageNotFoundError: missing.append(name)
print('\n'.join(missing))
r   TF)r(  r#  r  r  z'dep verification: subprocess failed: %sc                 ^    g | ]*}|                                 |                                 +S rI   r  r   re   s     r   r  zN_verify_core_dependencies_installed.<locals>._missing_deps.<locals>.<listcomp>z  s-    TTTtzz||T

TTTrC   )r*  r+  r/   r   r>  r?  r  r"  )check_scriptr  r  
applicabler  r  s      r   _missing_depsz:_verify_core_dependencies_installed.<locals>._missing_depsf  s    + 	
	^[!!4C
C#  FF  	 	 	LLBAFFFIIIIII	 UT)A)A)C)CTTTTs   +1 
A"AA"A"u     ⚠ Verification: z( declared dep(s) missing after install: r  r  r  rM   u;     → Reinstalling base group with --reinstall to repair...)r  --reinstallr=  r  r  z+dep verification: repair install failed: %su@     ⚠ Repair install failed; check `hermes update` output above.u2     ✓ All declared core dependencies now installedc                 <    g | ]}                     ||          S rI   r  )r   rh  name_to_specs     r   r  z7_verify_core_dependencies_installed.<locals>.<listcomp>  s)    ;;;\a##;;;rC   u1     → Force-installing remaining missing dep(s): r  rB  r  z/dep verification: per-package repair failed: %su     ⚠ Could not install: zC. Run `hermes update --force` after closing other hermes processes.u"     ⚠ Still missing after repair: )r  r   r<  r-  r+   r  r%   r   r>  r?  packaging.requirementsr9  rz  r   r  ra   r0   evaluate_resolve_install_target_pythonr  r/   rw   r   r'   r  r  r  r*  r  r8  r  )r0  r  r  r  	pyprojectr  rY  raw_depsr  depsr9  rA  reqr5  opr   r  rA  missingr  repair_argsstill_missingbarespecsfinal_missingr@  rD  r  s    `                       @@@r   r4  r4    s   $    //I )T"" 	#a<<??D	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	#88Ir**..~rBBHb   JANNN /1D*666666 	 	D!k$''SXsz23333   		  	* 	* 	* 	* 	*D::c1%%a(D>  ::::b!,,Q/DE  ::<<%%c1--a06688D *T4L)))	* 	*	* J $ $f>d###	$   (!!$''' 	$ 	$ 	$d#####	$   11CSIIKU49 U U U U U U U U, mooG 		Gs7|| 	G 	G99WRaR[!!	G,/LL1,<,<55"	G 	G   

GHHH *5@#%%%DK777K ,#;	
 	
 	
 	
 	
 (   DaHHHPQQQ
 "MOOM BCCC
 L C Czz#q!!!$**,,: 	 	BTzzzz"a((+  ?CTZZ\\''Q//288::;;;;;;];;;E	NDIIe<L<LNN  
#)]!CU!CC	
 	
 	
 	
 	
 (   H!LLLP		-(@(@ P P P	
 	
 	
 	 "MOOM DP=1I1I P P P	
 	
 	
 	
 	

 	BCCCCCs    
B' A/#B' /A33B' 6A37/B' '
C1CC
D& (,DD& 
D"D& !D""D& &B+GG9)H##IIL$ $M(3*M##M(Q6 6SASSc                 L   |rYd|v rUt          |d                   }|t                      rdndz  }|t                      rdndz  }|                                r|S | rFt          | d                   }|                                rd|j                                        vr|S dS )	a  Figure out which Python interpreter the install just targeted.

    ``_install_python_dependencies_with_optional_fallback`` is called with
    either ``[uv, pip]`` (and a ``VIRTUAL_ENV`` env var pointing at the
    target venv) or ``[sys.executable, -m, pip]`` (the in-process Python).
    The verification step needs the *resulting* environment's Python so
    ``importlib.metadata`` queries the right site-packages.
    r  r  r  z
python.exepythonr   uvN)r~   r  r)   r   r1   )r0  r  	venv_rootr  r6  firsts         r   rG  rG    s      }##]+,,	KMMDyyuE{}}J||(K	 	  '*++<<>> 	d%**:*:*<*<<<L4rC   c                      t          |           S r{  )r  r  s    r   rD  rD    s    )#...rC   c                  "    t           j        dk    S )Nandroidr  rI   rC   r   _is_android_pythonr[    s    <9$$rC   r  c          	      >   ddl }ddl}ddlm}m} |                                5 }t          |          }|dz  }|j                            ||            |||          }	t          | ddt          |	          gz   |           ddd           dS # 1 swxY w Y   dS )a  Install psutil on Android by patching upstream platform detection.

    psutil's setup currently gates Linux sources behind
    ``sys.platform.startswith('linux')``. On Termux Python reports
    ``sys.platform == 'android'``, so setup aborts with
    "platform android is not supported" despite compiling fine when using the
    Linux source path.

    We patch only the extracted build tree used for this install attempt;
    nothing is persisted in the repository.

    Stopgap: remove this once https://github.com/giampaolo/psutil/pull/2762
    merges and ships in a release. The standalone installer script uses the
    same shared helper and should be removed together.
    r   N)
PSUTIL_URLprepare_patched_psutil_sdistzpsutil.tar.gzr  z--no-build-isolationr  )r<  r3  hermes_cli.psutil_androidr]  r^  r  r~   requestr  r  r/   )
r0  r  r<  urllibr]  r^  r  tmp_patharchivesrc_roots
             r   _install_psutil_android_compatre    s   ( OOORRRRRRRR		$	$	&	& 	
#99_,"":w777//BB#)-CS]]!SS	
 	
 	
 	
	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
s   A BBBrU  c                 
   ddl m}  |            }|r|S t                      sdS 	 t          d           t	          j        | ddgz   t          d           n# t          $ r Y nw xY w |            pt          j	        d          S )	aR  Best-effort uv bootstrap on Termux for faster update installs.

    The normal path (``ensure_uv()`` in managed_uv) installs the managed
    standalone uv into ``$HERMES_HOME/bin/uv``, but on Termux the official
    installer may not work (glibc vs bionic).  Fall back to ``pip install uv``
    which gets a Termux-compatible binary.
    r   )
resolve_uvNuL     → Termux detected: trying to install uv for faster dependency updates...r  rU  Fr  )
rB  rg  rD  rw   r*  r+  r<  r   r?  r@  )rU  rg  ri  s      r   rC  rC    s     100000z||H  t\]]]w)T!22ERRRRR    :<<-6<---s   0A 
A$#A$c                  B   t          j        d          } | sd S t          dz                                  sd S t	          d           g d}t                      }g |d}t          | t          t          |          d|          }|j        dk    rat	          d	           |j	        r|j	        pd

                                nd
}|r*t	          d|                                d                     d S g |dddd}t          | t          t          |          d|          }|j        dk    rt	          d           d S t	          d           |j	        r|j	        pd

                                nd
}|r,t	          d|                                d                     d S d S )Nr  rm  u$   → Updating Node.js dependencies...)r  r  r  z--workspaces=falseFr  r   u%     ⚠ npm install failed in repo rootrM   r  r  rs  r  r%  u:     ✓ repo root + ui-tui, web workspaces (desktop skipped)u"     ⚠ npm workspace install failed)r?  r@  r<  r)   rw   r  r  r{  rA  r   r0   r"  )r  r  r  	root_argsroot_resultr   ws_args	ws_results           r   rF  rF  &  s   
,u

C >)1133  

0111@@@J ""I 4*323I0##  K ""56667B7IQ+$*11333r 	42**,,R022333 K
JMJ8J]JEJG.>>  I q  JKKKKK23335>5EM)"(b//1112 	42**,,R02233333	4 	4rC   c                   6    e Zd ZdZd Zd Zd Zd Zd Zd Z	dS )	_UpdateOutputStreamu  Stream wrapper used during ``hermes update`` to survive terminal loss.

    Wraps the process's original stdout/stderr so that:

    * Every write is also mirrored to an append-only log file
      (``~/.hermes/logs/update.log``) that users can inspect after the
      terminal disconnects.
    * Writes to the original stream that fail with ``BrokenPipeError`` /
      ``OSError`` / ``ValueError`` (closed file) no longer cascade into
      process exit — the update keeps going, only the on-screen output
      stops.

    Combined with ``SIGHUP -> SIG_IGN`` installed by
    ``_install_hangup_protection``, this makes ``hermes update`` safe to
    run in a plain SSH session that might disconnect mid-install.
    c                 0    || _         || _        d| _        d S NF)	_original_log_original_broken)selfr  log_files      r   __init__z_UpdateOutputStream.__init__o  s    !	 %rC   c                    | j         ,	 | j                             |           n# t          $ r Y nw xY w| j        r-t	          |t
          t          f          rt          |          ndS 	 | j                            |          S # t          t          t          f$ r7 d| _        t	          |t
          t          f          rt          |          ndcY S w xY w)Nr   T)rr  rG   r   rs  r-   r/   r"  r   rq  BrokenPipeErrorrH   r   )rt  rY  s     r   rG   z_UpdateOutputStream.writet  s    9 	%%%%      	F *4#u > >E3t999AE	F>''---*5 	F 	F 	F %)D! *4#u > >E3t999AEEE		Fs   $ 
11)B ACCc                     | j         +	 | j                                          n# t          $ r Y nw xY w| j        rd S 	 | j                                         d S # t
          t          t          f$ r d| _        Y d S w xY w)NT)rr  r  r   rs  rq  rx  rH   r   rt  s    r   r  z_UpdateOutputStream.flush  s    9 	!!!!     	F	)N  """""*5 	) 	) 	)$(D!!!!	)s   # 
00A A:9A:c                 j    | j         rdS 	 | j                                        S # t          $ r Y dS w xY wrp  )rs  rq  rF   r   rz  s    r   rF   z_UpdateOutputStream.isatty  sM      	5	>((*** 	 	 	55	s   $ 
22c                 4    | j                                         S r{  )rq  filenorz  s    r   r}  z_UpdateOutputStream.fileno  s     ~$$&&&rC   c                 ,    t          | j        |          S r{  )rY  rq  )rt  r   s     r   r  z_UpdateOutputStream.__getattr__  s    t~t,,,rC   N)
r  
__module____qualname____doc__rv  rG   r  rF   r}  r  rI   rC   r   rn  rn  ]  s{         "& & &
F F F() ) )  ' ' '
- - - - -rC   rn  gateway_modec                    t           j        t           j        ddd}| r|S ddl}t	          |d          r9	 |                    |j        |j                   n# t          t          f$ r Y nw xY w	 ddl	m
}  |            dz  }|                    dd	           |d
z  }t          |ddd          }ddl}|                    d|j                                                            d           d           ||d<   t#          |d         |          t           _        t#          |d         |          t           _        d|d<   n# t$          $ r d|d<   Y nw xY w|S )u$  Protect ``cmd_update`` from SIGHUP and broken terminal pipes.

    Users commonly run ``hermes update`` in an SSH session or a terminal
    that may close mid-install.  Without protection, ``SIGHUP`` from the
    terminal kills the Python process during ``pip install`` and leaves
    the venv half-installed; the documented workaround ("use screen /
    tmux") shouldn't be required for something as routine as an update.

    Protections installed:

    1. ``SIGHUP`` is set to ``SIG_IGN``.  POSIX preserves ``SIG_IGN``
       across ``exec()``, so pip and git subprocesses also stop dying on
       hangup.
    2. ``sys.stdout`` / ``sys.stderr`` are wrapped to mirror output to
       ``~/.hermes/logs/update.log`` and to silently absorb
       ``BrokenPipeError`` when the terminal vanishes.

    ``SIGINT`` (Ctrl-C) and ``SIGTERM`` (systemd shutdown) are
    **intentionally left alone** — those are legitimate cancellation
    signals the user or OS sent on purpose.

    In gateway mode (``hermes update --gateway``) the update is already
    spawned detached from a terminal, so this function is a no-op.

    Returns a dict that ``cmd_update`` can pass to
    ``_finalize_update_output`` on exit.  Returning a dict rather than a
    tuple keeps the call site forward-compatible with future additions.
    NF)prev_stdoutprev_stderrru  r  r   SIGHUPr   logsTrK  z
update.logar=   r   )	bufferingr   z
=== hermes update started seconds)timespecz ===
ru  r  r  r  )r@   r  r   r  hasattrr  SIG_IGNr   rH   r  r   rO  r+   r  rG   r[  r]  rn  r   )r  r  r  _get_hermes_homelogs_dirlog_pathru  _dts           r   _install_hangup_protectionr    s   < zz	 E   w!! 	NN7>7?;;;;G$ 	 	 	 D	! 	JIIIII##%%.td333l*#WEEEH|!!++Y+??H H H	
 	
 	

 %j(})=xHH
(})=xHH
!k ! ! ! !j!
 Ls$    A A*)A*.CE EEc                    | sdS |                      d          rx	 |                      dt          j                  t          _        n# t          $ r Y nw xY w	 |                      dt          j                  t          _        n# t          $ r Y nw xY w|                      d          }|<	 |                                 |                                 dS # t          $ r Y dS w xY wdS )zWRestore stdio and close the update.log handle opened by ``_install_hangup_protection``.Nr  r  r  ru  )r%   r@   r  r   r   r  r   )r  ru  s     r   _finalize_update_outputr    s    yy 	=#*==CJJ 	 	 	D		=#*==CJJ 	 	 	D	yy$$H	NNNN 	 	 	DD		 s5   *A 
AA*B 
BB*(C 
C"!C"c                 P    t          | dd          pd                                pdS )a5  Normalize ``args.branch`` into a non-empty branch name.

    Centralizes the "default to main, accept --branch override, treat empty
    or whitespace-only values as the default" parsing so every consumer of
    ``--branch`` (check path, git-update path, ZIP-fallback path) agrees on
    the same answer.
    rH  Nrr  )rY  r0   r  s    r   r4  r4    s,     D(D))3V::<<FFrC   rr  )branch_explicitrH  r  c          	         ddl m}  |t                    }|dk    r1ddl m} t	           |                       t          j        d           |dk    rddl m} ddlm	} |r| d	k    rt	          d
|  d            |            }|$t	          d           t          j        d           n@|dk    rt	          d           n*t	          d           t	          d |             d           dS t          dz  }|
                                s#t	          d           t          j        d           dg}	t
          j        dk    rg d}	| d	k    rt	          d           t          j        |	dd| gz   t          dd          }
|
j        dk    r:t	          d           t          j        |	dd| gz   t          dd          }
d}d|  }nAd}d |  }n9t	          d           t          j        |	dd| gz   t          dd          }
d}d|  }|
j        dk    r|
j                                        }d!|v sd"|v rt	          d#           nSd$|v sd%|v rt	          d&           n;t	          d'           |r*t	          d(|                                d                     t          j        d           t          j        |	d)d*d+|gz   t          dd          }|j        dk    rDt	          d,|  d-|                    d.d          d          d/           t          j        d           t          j        |	d0d1| d2gz   t          ddd3          }t'          |j                                                  }|dk    rt	          d           dS |dk    rd4nd5}t	          d6| d7| d8| d/           ddl m} t	          d |             d           dS )9a  Implement ``hermes update --check``: fetch and report without installing.

    ``branch`` selects which branch the check compares against. Default is
    "main"; callers can pass another branch to ask "are there new commits
    on origin/<branch>?" without performing the update.

    ``branch_explicit`` is True iff the caller passed --branch on the CLI.
    PyPI installs can't honor non-default branches, so when this is True
    on a PyPI install we surface a one-line notice instead of silently
    dropping the flag.
    r   detect_install_methoddocker)format_docker_update_messager=   r  r  )check_via_pypirr  u?   ⚠ --branch is ignored for PyPI installs (would have checked 'z').Nu.   ✗ Could not reach PyPI to check for updates.u   ✓ Already up to date.u   ⚕ Update available on PyPI.z  Run 'z' to install.r(  u6   ✗ Not a git repository — cannot check for updates.gitrc  r  r   windows.appendAtomically=falseu   → Fetching from upstream...r  r  TrY  u   → Fetching from origin...r  Forigin/z	upstream/Could not resolve hostunable to access9   ✗ Network error — cannot reach the remote repository.Authentication failedcould not read UsernameD   ✗ Authentication failed — check your git credentials or SSH key.u   ✗ Failed to fetch.r  r  r^  r     ✗ Branch 'z' not found on r  r  r  zHEAD..r  r  r  r  u   ⚕ Update available: r!  z behind )r  r  r<  r  rw   r@   r   r  rx  r  r)   r   r*  r+  rA  r   r0   r"  ra   r   r  )rH  r  r  methodr  r  r  r  r/  r  fetch_resultupstream_existscompare_branchr   verify_result
rev_resultr  r  s                     r   _cmd_update_checkr    s    877777""<00F
 	CBBBBB**,,---@@@@@@444444 	av//_TZ___```!!>BCCCHQKKKKq[[+,,,,1222G6688GGGHHHV#G>> FGGGgG
|wAAA -...!~w
F33	
 
 
 "a''/000%>7Hf55 #	  L $O/v//NN"O111NN 	+,,,!~w&11	
 
 
  +6++!##$**,,#v--1Cv1M1MMNNNN$..2Kv2U2UXYYYY())) 536,,..q133444 N;
I~FF	  M 1$$VVVVN4H4Ha4P4PQR4SVVVWWW:888)DD  J "((**++F{{'(((((#)Q;;xxIWvWWWWnWWWXXX@@@@@@C2244CCCDDDDDrC   c            
      t   t           j        dk    rdS 	 t          j                    dk    rdS n# t          $ r Y dS w xY wt          d          } |                                 s|                                 sdS t          j        	                    d          pd}	 t          j        ddd	| d
t          j        	                    dd           ddddgddd          }n# t          t          j        f$ r Y dS w xY w|j        dk    rdS d}d}d}dD ]}t          |          |z  }|                                s*	 |                    d          }n# t"          $ r Y Nw xY wt%          d |                                D                       }	|	r	 |                    dd          5 }
|
                    d|z   dz   |z   dz              ddd           n# 1 swxY w Y   n,# t"          $ r}t-          d| d|            Y d}~d}~ww xY wt-          d |            d}|rt-          d!           dS dS )"aH  Ensure /usr/local/bin is on PATH for RHEL-family root non-login shells.

    Mirrors the post-symlink probe added to ``scripts/install.sh`` so that
    existing FHS-layout root installs on RHEL/CentOS/Rocky/Alma 8+ get
    repaired on ``hermes update`` without requiring a reinstall.  The
    installer's assumption that ``/usr/local/bin`` is on PATH for every
    standard shell breaks on those distros in non-login interactive shells
    (su, sudo -s, tmux panes, some web terminals): /etc/bashrc doesn't
    add /usr/local/bin and /root/.bash_profile doesn't either.  Symptom:
    ``hermes`` prints ``command not found`` even though the symlink lives
    at /usr/local/bin/hermes.

    Silent no-op on: non-Linux, non-root, non-FHS installs, and any system
    where ``bash -i -c 'command -v hermes'`` already resolves.  Idempotent.
    r  Nr   z/usr/local/bin/hermesHOMEz/rootr  r8  zHOME=zTERM=r9  dumbr  r   zcommand -v hermesTr  r'  z"export PATH="/usr/local/bin:$PATH"uK   # Hermes Agent — ensure /usr/local/bin is on PATH (RHEL non-login shells)F)z.bashrcz.bash_profiler  r  c              3   v   K   | ]4}d |v o+d|v o'|                                                     d           V  5dS )z/usr/local/binr  r^   N)lstriprR   r>  s     r   r   z)_ensure_fhs_path_guard.<locals>.<genexpr>  sj       
 
  $ 2$2KKMM,,S111
 
 
 
 
 
rC   r  r   r   rN  u     ⚠ Could not update r  u&     ✓ Added /usr/local/bin to PATH in z?    (reload your shell or run 'source ~/.bashrc' to pick it up))r@   r   r#   geteuidr  r~   
is_symlinkr)   r$   r%   r*  r+  r   r,  rA  r-  r   rH   r  r"  r+   rG   rw   )fhs_linkr3   rF  	path_linepath_comment	wrote_anyr6  r  ri  already_guardedr  r  s               r   _ensure_fhs_path_guardr    sM     |w:<<1F     +,,H   ):): 
 :>>&!!,WD8
vv6688#	  
 
 
 z89   14IX  I1  	4jj9${{}} 		}}I}66HH 	 	 	H	  
 
 !++--	
 
 
 
 
  		#00 GA|+d2Y>EFFFG G G G G G G G G G G G G G G 	 	 	6C66166777HHHH	 	<s<<===		 QOPPPPPQ Qsm   . 
<<AC C98C9<E
E E G#)"GG#G	G#G	G##
H-HHc           	      <   t          | dd          rt          d           t                       dS t          t          | dd                    }	 ddlm}  |            }nF# t
          $ r9}t          j        t                    	                    d|           i }Y d}~nd}~ww xY wt          |t                    r|                    d	i           ni }|                    d
d          }|                    dd          }|s|sdS 	 ddlm} n9# t
          $ r,}t          d| d           t                       Y d}~dS d}~ww xY wt          d           t          j                    }		  |t#          |                    }
nG# t
          $ r:}t          d|            t          d           t                       Y d}~dS d}~ww xY wt          j                    |	z
  }|
t          d           t                       dS 	 |
                                j        }n# t(          $ r d}Y nw xY w| d}dD ]}|dk     r n|dz  }|dd| }	 ddlm}m}  |            }	  |             d|
                    |           }n# t2          $ r t5          |
          }Y nw xY wn# t
          $ r t5          |
          }Y nw xY wt          d| d| d|dd           t          d |
            t          d!           t          d"           t                       dS )#u  Create a full zip backup of HERMES_HOME before running the update.

    Gated on ``updates.pre_update_backup`` in config (default false).  Off
    by default because the zip can add minutes to every update on large
    HERMES_HOME directories.  The ``--backup`` flag on ``hermes update``
    opts in for a single run; ``--no-backup`` forces it off when config
    has it enabled.  Never raises — a backup failure should not block the
    update itself.
    	no_backupFu,   ◆ Pre-update backup: skipped (--no-backup)Nbackupr   rX  z/Could not load config for pre-update backup: %supdatespre_update_backupbackup_keepr  )create_pre_update_backupu5   ⚠ Pre-update backup: could not load backup module (z); continuing update.u!   ◆ Creating pre-update backup...)keepu     ⚠ Backup failed: z  Continuing with update.uI     ⚠ Backup skipped (no files found or write failed); continuing update.z B)KBMBGBi   .1fr!  r   r5  r  z  Saved:    rl   r  zs)z  Restore:  hermes import z6  Disable:  omit --backup (backups are off by default)z?            set updates.pre_update_backup: false in config.yaml)rY  rw   rQ   r  ro  r   logging	getLoggerr  r?  r-   r.   r%   ry  r  rf  r  r   r=  r?  rH   r   r   r5  ru  r   r/   )rZ  force_backupro  r  r   updates_cfgenabledr  r  t0out_pathr  
size_bytessize_strunitr   r5  r3   display_paths                      r   _run_pre_update_backupr    s    t[%(( <===h6677L111111kmm   (##))=s	
 	
 	
 	 -7sD,A,AI#'')R(((rKoo1599G??=!,,D <  	>>>>>>>   ^C^^^	
 	
 	
 	 

-...			B++T;;;   +c++,,,)***	 o"$GYZZZ]]__,

   


    H" . .Ed
 ---t--	%IIIIIIII  	)1133RRh6J6J46P6PRRLL 	) 	) 	)x==LLL	) % % %8}}% 

D
D
D
D
DW
D
D
D
DEEE	
1x
1
1222	
CDDD	
LMMM	GGGGGs   A! !
B$+/BB$D 
E!D??E*F 
G/GGH H,+H,J% ""J J% J!J%  J!!J% %K Kc                 L   	 t          j        | ddgz   |dd          }|j        dk    rdS d |j                                        D             }|sdS t          j        | dd	g|z   |ddd
           t          dt          |           d           dS # t          $ r Y dS w xY w)av  Restore tracked ``package-lock.json`` files that npm dirtied locally.

    npm rewrites lockfiles non-deterministically at install/build time. On a
    managed install those diffs are never intentional, so we discard them so
    ``hermes update`` sees a clean tree instead of autostashing every run.
    Best-effort; only ever touches files named ``package-lock.json``.
    rm  rn  TrY  r   Nc                     g | ]=}|                                                     d           )|                                 >S )rn  )r0   r  r>  s     r   r  z+_discard_lockfile_churn.<locals>.<listcomp>f  sM     
 
 
zz||$$%899
JJLL
 
 
rC   checkoutr   Fr  u"   → Discarded npm lockfile churn (z	 file(s)))r*  r+  rA  r  r"  rw   r   r   )r  r&  rm  dirtys       r   _discard_lockfile_churnr  U  s   ~v}--	
 
 
 ?aF
 
..00
 
 

  	Fz40%00	
 	
 	
 	
 	H3u::HHHIIIII   s   (B %B A B 
B#"B#c           
         ddl m}m}m}m}  |            r |d           dS  |t
                    dk    r+t           |                       t          j        d           t          | dd          r>t          |           }t          |t          t          | d	d                    
           dS t          | dd          }t          |          }	 t          | |           t          |           dS # t          |           w xY w)zUpdate Hermes Agent to the latest version.

    Thin wrapper around ``_cmd_update_impl``: installs hangup protection,
    runs the update, then restores stdio on the way out (even on
    ``sys.exit`` or unhandled exceptions).
    r   )r  r  
is_managedmanaged_errorzupdate Hermes AgentNr  r=   r  FrH  )rH  r  gateway)r  )r  r  r  r  r  r<  rw   r@   r   rY  r4  r  rQ   r  _cmd_update_implr  )rZ  r  r  r  r  rH  r  _update_io_states           r   
cmd_updater  z  sc               z|| +,,, \**h66**,,---tWe$$  (-- x!>!>??	
 	
 	
 	
 	4E22L
 2|LLL2L9999 011111 01111s   C6 6Dc                    ddl m} ddlm} t	          d|            t	          d           ddlm}m}  |              |            }t          j	        t          j
        k    }dt          j	                            t          j                  v }|rt          j        d          nd}d	}	 |            r;|s2t	          d
           t	          d           t          j        d           |dddg}
nA|r|r|ddg}
n7|r#|ddddg}
|rd}	n)|
                    dd           nt          j        dddddg}
t	          dd                    |
                      i }|	ri t          j        dt          j	        i|d<   t+          j        |
fi |}|j        dk    r#t	          d           t          j        d           t	          d           dS )z*Update Hermes via pip (for PyPI installs).r   )r\   )is_uv_tool_installu   → Current version: u    → Checking PyPI for updates...r  pipxNFu=   ✗ Detected a uv-tool install but managed uv install failed.zN  Install uv manually: https://docs.astral.sh/uv/getting-started/installation/r=   toolupgradezhermes-agentr  r  r  Tr  z--systemr   u   → Running: r!  r  r  u   ✗ Update failedu;   ✓ Update complete! Restart hermes to use the new version.)rr   r\   r  r  rw   rB  r  r  r@   rT   base_prefixra   r#   r:  r?  r@  r   r  rB  r'   r$   r*  r+  rA  )rZ  r\   r  r  r  rU  in_venvpipx_managedr  export_virtualenvr#  
run_kwargsr  s                r   _cmd_update_pipr    s<   &&&&&&444444	
/+
/
/000	
,---BBBBBBBB 	BjCO+GSZ--bf555L#/96<TD  T 	QRRRbcccHQKKK69n5	 T$ T Y/	 T5)[.A 	& !% JJq*%%%%~tUI{NS	
)#((3--
)
)***J FErzE=#*EE
5^C..:..FA!"""	
GHHHHHrC   c                 RE   |rd4dnd}t          t          | dd                    }|p>|p<t          j                                        ot          j                                         }d}|r	 ddlm}  |            pi                     di           }t          |t                    r;t          |                    d	d
                                                    }|dk    }n4# t          $ r'}	t                              d|	           d}Y d}	~	nd}	~	ww xY wt!          d           t!                       t#                      rct          | dd          sRt%                      }
|
Bt'          |
          }|r1t!          t)          ||
                     t          j        d           t-          |            d}t.          dz  }|                                srt          j        dk    rd}n_ddlm}  |t.                    }|dk    rt7          |            dS t!          d           t!          d           t          j        d           t          j        dk    r3|                                rt9          j        g dt.          dd           dg}t          j        dk    rg d}t=          |t.                     t?          |t.                    }tA          |          }|r/t!          d           t!          d|            t!                       |rtC          |            dS 	 tE          |           }t!          d           t9          j        |dd |gz   t.          dd!          }|j#        dk    r|j$        %                                }d"|v sd#|v r>t!          d$           t!          |rd|&                                d          nd           nSd%|v sd&|v rt!          d'           n;t!          d(           |r*t!          d|&                                d                     t          j        d           t9          j        |g d)z   t.          ddd*          }|j        %                                }||k    r5|d+k    rd,nd-| d.}t!          d/| d0| d1           tO          |t.                    }t9          j        |d2|gz   t.          dd!          }|j#        dk    rt9          j        |d2d3|d4| gz   t.          dd!          }|j#        dk    r|tQ          |t.          |d|5           t!          d6| d7           |j$        %                                rAt!          d|j$        %                                &                                d                     t          j        d           ntO          |t.                    }|duo@| o=|p;t          j                                        ot          j                                        }t9          j        |d8d9| d:gz   t.          ddd*          }tS          |j        %                                          }|dk    rtU                       |r|d;k    rtW          |t.                     |tQ          |t.          |||5           ||d+hvr#t9          j        |d2|gz   t.          ddd*           t!          d<           dS t!          d=| d>           d}	 dd?l,m-}  |d@dA          }|rt!          dB|            n2# t          $ r%}	t                              dC|	           Y d}	~	nd}	~	ww xY wt!          dD           d} t]          |t.                    }!	 t9          j        |dEdFd |gz   t.          dd!          }"|"j#        dk    rt!          dG           t9          j        |dHdId4| gz   t.          dd!          }#|#j#        dk    r{t!          dJ| dK           |#j$        %                                r)t!          d|#j$        %                                            t!          dL|            t          j        d           t_          t.                    \  }$}%}&|$st!                       t!          dM           t!          d|%            |&r>t          |&          &                                ddN         D ]}'t!          dO|'            |!rt!                       t!          dP|!ddQ          dR           t9          j        |dHdI|!gz   t.          dd!          }(|(j#        dk    rt!          dS           t!          dT           nt!          dU           t!          dVt.           dW|!            |(j$        %                                rBt!          dX|(j$        %                                &                                d          dY           n5t!                       t!          dZ           t!          dVt.           d[           t          j        d           d} |W| s#t!          d\| dY           t!          d]           n|rta          |t.          |           nytQ          |t.          |||5           n_# |X| s#t!          d\| dY           t!          d]           w |rta          |t.          |           w tQ          |t.          |||5           w w xY wtU                       tc          t.                    })|)rt!          d^|) d_|)dk    rd`nda            |r|d;k    rtW          |t.                     te                       t!          db           ddcl3m4}*m5}+  |+              |*            },t          j6        dddg}-|,sto          |-          },de}.|,ri tp          j9        dft          t.          dgz            i}/tu          |/          r=|/;                    dhd           |/;                    did           dj}.t!          dk           tu          |/          r0ty                      r"t!          dl           t{          |,dg|/m           t}          |,dg|/|.n           nt          j6        dddg}-	 t9          j        |-dogz   t.          dd           n@# t8          j?        $ r. t9          j        t          j6        dddpdqdrgt.          ds           Y nw xY wtu                      rdj}.t!          dt           tu                      r,ty                      rt!          dl           t{          |-           t}          |-|.u           t                       t                       t                       t          t.          dvz             t.          dwz  dxz  }0t          |0          dupt          |0          }1|0dyz                                  rt          jG        dz          r|1r}t!          d{           t          j6        ddd|dxd}g}2t9          j        |2t.          ds          }3|3j#        dk    rt9          j        |2t.          ds          }3|3j#        dk    rt!          d~           t!                       t!          d           	 ddlHmI}4  |4t.                    rt!          d           n2# t          $ r%}5t                              d|5           Y d}5~5nd}5~5ww xY w	 ddlJ}6ddlK}7|6L                    |7           n# t          $ r Y nw xY w	 ddlMmN}8 t!                       t!          d            |8d          }|d         rAt!          dt          |d                    ddP                    |d                               |                    d          rAt!          dt          |d                    ddP                    |d                               |                    d          r&t!          dt          |d                    d           |                    d          r&t!          dt          |d                    d           |d         s$|                    d          st!          d           n2# t          $ r%}5t                              d|5           Y d}5~5nd}5~5ww xY w	 ddlQmR}9mS}:  |9            };|;rxt!                       t!          d           |;D ]W}<	  |:|<jT        d          }=|=r|=                    d          rd}>n|=rt          |=                    dg                     }?t          |=                    dg                     }@t          |=                    dg                     }Ag }B|?r|BU                    d|? d           |@r|BU                    d|@ d           |Ar|BU                    d|A d           |BrdP                    |B          nd}>nd}>t!          d|<jV         d|>            &# t          $ r&}Ct!          d|<jV         d|C dY           Y d}C~CQd}C~Cww xY wn# t          $ r Y nw xY w	 ddlWmX}D  |D            }E|Ert!          d|E d           n# t          $ r Y nw xY wt!                       t!          d           ddlmY}FmZ}Gm[}Hm\}I  |Fd          }J |G            }K |H            \  }L}Mt          |Jp|K          }N|N o|L|Mk     }O|Np|L|Mk     }P|Or|t!                       t!          d|L d|M d           	  |Idd           t!          d           n;# t          $ r,}Qt!          d|Q            t!          d           Y d}Q~Qn
d}Q~Qww xY w|Prt!                       d5d}R|Jr-t!          dt          |J           d            |R|Jdd           |Kr-t!          dt          |K           d            |R|Kdd           t!                       |rt!          d           d`}Sn|r5t          dd          %                                                                }Snt          j                                        rt          j                                        st!          d           d}SnG	 t          d          %                                                                }Sn# t          $ r d}SY nw xY w|Sdv rot!                       |p|p|Sdk     }T |I|Td          }U|Ud         s|Ud         rt!                       t!          d¦           |s|s|Sdk    r|Jrt!          dæ           n-t!                       t!          dĦ           nt!          dŦ           	 ddl,m`}V  |V|          }W|Wr0t!                       t!          d|Wd          d|Wd          dK           n2# t          $ r%}	t                              d|	           Y d}	~	nd}	~	ww xY wt!                       t!          d̦           	 t                       n2# t          $ r%}5t                              d|5           Y d}5~5nd}5~5ww xY w	 t                       n2# t          $ r%}5t                              d|5           Y d}5~5nd}5~5ww xY w	 t                       n2# t          $ r%}5t                              d|5           Y d}5~5nd}5~5ww xY w	 t          j        dk    rCt          jG        dѦ          r/ddldme}X t!                       t!          dӦ            |XdԦ           n2# t          $ r%}5t                              d|5           Y d}5~5nd}5~5ww xY w|r8t                      dz  }Y	 |Yg                    dצ           n# t          $ r Y nw xY w	 ddlimj}Zmk}[ml}\mm}]mn}^mo}_mp}`mq}amr}b ddls}c	 d6dt          dt          dt          dt           fdބ}d	 d7dt          dt          dt          dt          fd}e	 ddlKmv}f n# t          $ r d}fY nw xY wd}g	 ddlm}  |                                d          pi }h|h                    d          }gn# t          $ r Y nw xY w	 |gt          |g          nt          |f          }in&# t          t          f$ r t          |f          }iY nw xY wt          |id          dz   }ig }jt                      g }k |[            r	  |\             n# t          $ r Y nw xY wdddgfddgffD ]\  }l}m	 t9          j        |mg dz   dddQ          }|j        %                                &                                D ]D}'|'{                                }B|Bs|Bd         }n|n|                    d          s8|n}                    d          }ot9          j        |md|ogz   ddd          }p|pj        %                                dk    rd}q	 t9          j        |md|oddgz   ddd          }rtS          |rj        pd%                                pd          }qn$# t          t8          j~        t          f$ r d}qY nw xY wd}s|qdk    r0t!          d|o dtS          |i           d            |a|q|i          }s|srt9          j        |md|ogz   dddQ           t9          j        |md|ogz   ddd            |d|m|od٬          r|jU                    |o            |e|m|od߬          }tt          d|tdz             }u |d|m|o|u          r|jU                    |o           t!          d|o d           t9          j        |md|ogz   dddQ           t9          j        |md |ogz   ddd          }v|vj#        dk    r |d|m|od٬          r|jU                    |o           Vt!          d|o d           t9          j        |md|ogz   dddQ           t9          j        |md |ogz   ddd            |d|m|od٬          r,|jU                    |o           t!          d|o d           |ldk    rdnd}wt!          d|o d|w d|o d|w d	|o d
|w d|o            t!          d|o d|vj$        %                                            F# t          t8          j~        f$ r Y w xY w |Z            r	 ddlim}xm}ym}z  |z            }{|{                                rt9          j        dd |y            gddd          }p|pj#        dk    r~	  |x             |jU                     |y                       nU# t8          j?        $ rC}5t          |5dd          pd%                                }t!          d|            Y d}5~5nd}5~5ww xY wn## t          t8          j~        t          f$ r Y nw xY w |`            }| |]||d          fd |^||          D             }}|}                                D ]\  }~} |_|j        |~          s |a|~|i          }|s5	 tq          j        |~|cj                   n# t          t          f$ r Y nw xY w |bdd                               |~           |kU                    |j                   D ]P}~|~|}v r	 tq          j        |~|cj                                       |~           8# t          t          f$ r Y Mw xY w|jsrt!                       |jD ]}t!          d|            |kr(dP                    |k          }t!          d|            t                    t          |k          z
  }|r;t!          d| d           t!          d           |dk    rt!          d           |jss	 	 t          j        d            |`            } |]|d          }fd|D             }|rt!                       t!          dt          |           d           dd lm} |D ]0}~	  ||~d!           # t          t          t          f$ r Y -w xY wt          j        d"           n3# t          $ r&}t                              d#|           Y d}~nd}~ww xY wn3# t          $ r&}5t                              d$|5           Y d}5~5nd}5~5ww xY w	 dd%lim}m}mk}[  |[            r |            rt!                       t!          d&            |            D ]$\  }}}|rdnd}lt!          dO| d'|l d(           %t!                       t!          d)           t!          d*           t!          d+           t!                       t!          d,           t!                       t!          d-           n3# t          $ r&}5t                              d.|5           Y d}5~5nd}5~5ww xY wt#                       t!                       t!          d/           t!          d0           dS # t8          j?        $ r}5t          j        dk    rAt!          d1|5            t!          d2           t!                       tC          |            n-t!          d3|5            t          j        d           Y d}5~5dS Y d}5~5dS d}5~5ww xY w(8  uj   Body of ``cmd_update`` — kept separate so the wrapper can always
    restore stdio even on ``sys.exit``.rM   c                 "    t          | |          S r{  )r  )r  r   s     r   r7  z"_cmd_update_impl.<locals>.<lambda>  s    OFG$D$D rC   Nr  Fr   rX  r  non_interactive_local_changesr\  discardz8Could not read updates.non_interactive_local_changes: %su   ⚕ Updating Hermes Agent...r  r   r(  rc  Tr  r  u+   ✗ Not a git repository. Please reinstall:zD  curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bashr=   )r  r   r  r3  zwindows.appendAtomicallyfalser  r  r  u   ⚠ Updating from fork:r  u   → Fetching updates...r  r  rY  r  r  r  r  r  r  u(   ✗ Failed to fetch updates from origin.)r  z--abbrev-refr,  r  r,  zdetached HEADzbranch 'r  u     ⚠ Currently on u    — switching to z for update...r  z-Br  )rj  rq  r  z&' does not exist locally or on origin.r  zHEAD..origin/r  rr  u   ✓ Already up to date!u
   → Found z new commit(s))create_quick_snapshotz
pre-update)r  r  u     ✓ Pre-update snapshot: zPre-update snapshot failed: %su   → Pulling updates...r  r  uP     ⚠ Fast-forward not possible (history diverged), resetting to match remote...rZ  ro  u   ✗ Failed to reset to origin/r  z<  Try manually: git fetch origin && git reset --hard origin/u6   ✗ Pulled code has a syntax error in a critical file:r  r  u   → Rolling back to r  r  u6     ✓ Rollback complete — your install is unchanged.z5  Try ``hermes update`` again later once a fix lands.u-     ✗ Rollback failed. Recover manually with:r  z && git reset --hard z    (rm   u;     Could not capture pre-pull SHA — recover manually with:z- && git reflog && git reset --hard <prev-sha>u1     ℹ️  Local changes preserved in stash (ref: z(  Restore manually with: git stash applyr  r  r  r  r  r  r   r  r  r  r  r  r  uH     → Termux detected: using uv + curated termux-all optional profile...uY     → Termux/Android detected: prebuilding psutil with Linux source path compatibility...r  r  rW   r  r  r  r  uC     → Termux detected: using curated termux-all optional profile...r  r%  r  r   rm  r  u/   → Checking if desktop app needs rebuilding...hermes_cli.mainz--build-onlyuE     ⚠ Desktop build failed (non-fatal; run `hermes desktop` to retry)u   ✓ Code updated!r,  r.  z+Model catalog seed during update failed: %srS  r  rU  r  r   r!  r  r"  r#  r$  r%  r&  r'  r(  r)  r*  r+  z$Skills sync during update failed: %s)list_profilesseed_profile_skillsu-   → Syncing bundled skills to all profiles...skipped_opt_outzopted out (--no-skills)+z newu   ↑z updatedr   z user-modifiedz
up to datezsync failedr  z	: error ()sync_honcho_profiles_quietz
-> Honcho: synced z profile(s)u-   → Checking configuration for new options...)get_missing_env_varsget_missing_config_fieldscheck_config_versionmigrate_config)required_onlyu     ℹ Updating config format (vu    → vu   )…)interactiverV  u:     ✓ Config format updated (no new settings to configure)u'     ⚠️  Config format update failed: z*     Run 'hermes config migrate' to retry.c                    | sd S t          d| d           | d d         }|D ]}t          |t                    rX|                    |          p|r|                    |          pd}|                    d          pd                                }nt          |          }d}|rt          d| d|            t          d|            t          |           t          |          z
  }|d	k    rt          d
| d           d S d S )Nr  r)  r  r]  r  rM   u
         • r	  r   u         … and z more)rw   r-   r.   r%   r0   r/   r   )	r  r  r0  fallback_keyshownitr   r  r  s	            r   _print_itemsz&_cmd_update_impl.<locals>._print_itemsd"  s>    Fm5mmm$$$bqb	 3 3B!"d++ "!vvc{{\|/T|@T@T\Y\ "} 5 5 ;BBDD  #2ww! 3<4<<d<<====14112222E

SZZ/1997577788888 9rC   u
     ⚠️  z+ new required setting(s) need configurationzNew settingsr   u
     ℹ️  z new config option(s) availablezNew optionsr0  uG     ℹ --yes: auto-applying config migration (skipping API-key prompts).z2Would you like to configure new options now? [Y/n]rh  uB     ℹ Non-interactive session — applying safe config migrations.r  z-Would you like to configure them now? [Y/n]: >   rM   r  r  r  	env_addedconfig_addedu   ✓ Configuration updated!u:     ℹ API keys require manual entry: hermes config migratez8Skipped. Run 'hermes config migrate' later to configure.u!     ✓ Configuration is up to date)restore_cron_jobs_if_emptieduE     ⚠️  cron/jobs.json was emptied during this update — restored 	job_countz! job(s) from pre-update snapshot snapshot_idz'Cron jobs auto-restore check failed: %sr/  r0  r1  zFHS PATH guard check failed: %srb  
cua-driverinstall_cua_driveru+   → Refreshing cua-driver (Computer Use)...r  zcua-driver refresh failed: %sz.update_exit_code0)	is_macossupports_systemd_services_ensure_user_systemd_envfind_gateway_pidsfind_profile_gateway_processes'launch_detached_profile_gateway_restart_get_service_pids_graceful_restart_via_sigusr1_wait_for_gateway_exit      $@
scope_cmd_	svc_name_r)  r   c                 \   t          j                    t          |d          z   }	 	 t          j        | d|gz   ddd          }|j                                        dk    rdS n# t          t          j        f$ r Y nw xY wt          j                    |k    rdS t          j	        d           )az  Poll ``systemctl is-active`` until the unit reports active.

                systemd's Stopped -> Started transition after a graceful exit
                (or a hard restart) is not instantaneous; a one-shot check
                races that window and falsely reports the unit as down.
                Poll every 0.5s up to ``timeout`` seconds before giving up.
                r  T	is-activer  r'  r  F)
rf  r  r  r*  r+  r  r0   r   r,  r  )r	  r	  r)  r  _verifys        r   _wait_for_service_activez2_cmd_update_impl.<locals>._wait_for_service_active#  s     !?,,s7C/@/@@%
",.&+y)AA+/!%$%	# # # #>//11X==#'4 >-z/HI   ((H44$uK$$$%s   :A$ $A=<A=        r   c           
         	 t          j        | d|ddgz   ddd          }n# t          t           j        f$ r |cY S w xY w|j        pd                                }|r|dk    r|S d	}d
}|                                D ]`}dD ][\  }}	|                    |          rA	 |t          |dt          |                              |	z  z  }d}n# t          $ r Y nw xY w n\a|r|n|S )a  Read the unit's ``RestartUSec`` (RestartSec) in seconds.

                After a graceful exit-75, systemd waits ``RestartSec`` before
                respawning the unit.  Callers that poll for ``is-active``
                must use a timeout >= ``RestartSec`` + transition slack, or
                they'll give up *during* the cooldown window and wrongly
                conclude the unit didn't relaunch.
                showz--property=RestartUSec--valueTr  r'  rM   infinityr	  F))msgMbP?)usgư>)r        N@)r  g      ?N)r*  r+  r   r,  r  r0   ra   r  floatr   r   )
r	  r	  r   _showr7   r  matchedr  _suf_mults
             r   _service_restart_secz._cmd_update_impl.<locals>._service_restart_sec9#  s^   #&N""%4%	 (,! !  EE *:+DE # # #"NNN#|)r0022  #cZ//"NIIKK " "D( " "e  ==.. "% %tLs4yyjL/A)B)BU)J J*.#- % % % $%!E" !(4uuW4s   " ==-C


CC)%DEFAULT_GATEWAY_RESTART_DRAIN_TIMEOUTr$	  r  restart_drain_timeoutg      >@g      .@user	systemctlz--userr   )z
list-unitszhermes-gateway*z--plainz--no-legendz
--no-pagerr'  z.servicer	  r  r  r	  z--property=MainPIDr 	  u     → z: draining (up to zs)...)drain_timeoutzreset-failedr   r   r  r  r  u0    drained but didn't relaunch — forcing restartrestartz  died after restart, retrying...r%  z recovered on retryz--user u     ✗ zB failed to stay running after restart.
    Check logs: journalctl z-u z; --since '2 min ago'
    Recover manually:
      systemctl zreset-failed z
      systemctl zrestart u     ⚠ Failed to restart )launchd_restartget_launchd_labelget_launchd_plist_path	launchctlr  r   u     ⚠ Gateway restart failed: )r  all_profilesc                 2    i | ]}|j         v |j         |S rI   )r  )r   r  manual_pidss     r   r  z$_cmd_update_impl.<locals>.<dictcomp>$  s4     ! ! !8{** $***rC   r  g      @)r)  force_afteru     ✓ Restarted u,     ✓ Restarting manual gateway profile(s): u     → Stopped z manual gateway process(es)z(    Restart manually: hermes gateway runz;    (or: hermes -p <profile> gateway run  for each profile)r  c                     g | ]}|v |	S rI   rI   )r   r  killed_pidss     r   r  z$_cmd_update_impl.<locals>.<listcomp>$  s#    JJJ#sk7I7I#7I7I7IrC   u6    gateway process(es) ignored SIGTERM — force-killing)terminate_pidr         ?z&Post-restart survivor sweep failed: %sz(Gateway restart during update failed: %s)has_legacy_hermes_units_find_legacy_hermes_unitsr	  u+   ⚠ Legacy Hermes gateway unit(s) detected:  (z scope)z;  These pre-rename units (hermes.service) fight the currentz<  hermes-gateway.service for the bot token and cause SIGTERMz  flap loops. Remove them with:z!    hermes gateway migrate-legacyz)  (add `sudo` if any are in system scope)z*Legacy unit check during update failed: %sz-Tip: You can now select a provider and model:z7  hermes model              # Select provider and modelu   ⚠ Git update failed: u#   → Falling back to ZIP download...u   ✗ Update failed: rM   r{  )r	  )r	  )rQ   rY  r@   r   rF   r  r  ro  r%   r-   r.   r/   r1   r   r>  r?  rw   r  r  r  r  r   r  r<  r)   r   r  r  r*  r+  r  r  r  rW  r4  rA  r   r0   r"  rb  ru  r   r  r  ry  r  r  r  rw  r  r  rB  r  r  rB  rC  r#   r$   rD  rC  r[  re  rE  r  r  r/  rF  r-  rP  r1  r?  r@  rG  r-  	importlibr   reloadrW  rT  r   r'   r   r  r  r&   rz  r   plugins.memory.honcho.clir  r  r  r  r  r  r  r  r	  r  r  r  hermes_cli.tools_configr
	  r   rP  rH   r  r	  r	  r	  r	  r	  r	  r	  r	  r	  r  r  r%	  r+	  r  r   r  ru  ra   r  removesuffixr,  r   r1	  r2	  r3	  r   r  profiler  r  r  r  r   rf  r  r   r;	  r=	  r>	  r
  )rZ  r  gw_input_fn
assume_yes_non_interactive_updatediscard_local_changesro  _update_cfg_moder   r  
concurrentuse_zip_updater/  r  r  r  r  is_forkrH  r  r   r  current_branchr  auto_stash_refcheckout_resulttrack_resultprompt_for_restorecommit_countpre_update_snapshot_idr  update_succeededpre_pull_shapull_resultreset_result	syntax_okfailing_pathsyntax_errorre   rollback_resultr  r  r  rT  rU  install_grouprV  r.  has_desktop_app_desktop_build_cmdr  r-  r  rA	  _hcrT  r  r  r5	  r  r  r  r  r"  modifiedr$  per  syncedr  r  r  r  missing_envmissing_configcurrent_ver
latest_verhas_new_optionsversion_bump_onlyneeds_migration_mig_errr	  r  interactive_migrationr+  r	  cron_restorer
	  _exit_code_pathr	  r	  r	  r	  r	  r	  r	  r	  r	  r  r	  r*	  _DEFAULT_DRAIN
_cfg_drain
_cfg_agent_drain_budgetrestarted_servicesrelaunched_profilesscope	scope_cmdr  svc_namer  	_main_pidr&	  _graceful_ok_restart_sec_post_drain_timeoutr0	  _scope_flagr1	  r2	  r3	  
plist_pathservice_pidsprofile_processesr  r  drainedsvcr-  unmapped_count_service_pids_after
_surviving_stuck_terminate_pid
_sweep_excr=	  r>	  r   r&   is_sysr:	  r7	  s                                                                                                                                                 @@r   r  r    s.    		D	D	D	D 
 gdE51122J 	 	<	<	  "":sz'8'8':':; 
 " *
	*555555&;==.B33IrBBK+t,, ;KOO,KWUUVV\\^^(-(:% 	* 	* 	*LLSUXYYY$)!!!!!!	*
 

()))	GGG }} WT7E:: '))"<[IIJ ::{SSTTT 4    NV#G>> <7""!NN??????**<88F%%%?@@@V   HQKKK |w7>>#3#3   	
 	
 	
 	
 gG
|wAAA G\222 !,77Jz""G '(((:    e (--'(((!~w&11	
 
 
 "a''!(..00F'6115G65Q5QQRRRvE36,,..q13332FFFF'6115NRX5X5XZ    ABBB 97v00221577888HQKKK ;;;;
 
 
  ,,.. V## "V++  1111 
 WWWWWWXXX;G\RRN(n:v.. #	  O )Q..
  *~z49K69K9KLL$#'	       *a// &10#(*(-%0    WWWWXXX#*0022 RP<#6#<#<#>#>#I#I#K#KA#NPPQQQHQKKK;G\RRN $& OOM#)"2"2"4"4"L9J9J9L9L 	 z#;6#;#;YGG
 
 
 6=..00111$&&&  E6V++-g|DDD )( " 2(    ff%555z>::$#'    +,,,F7<777888 "&	@??????%:%:TU%V%V%V"% NL4JLLMMM 	@ 	@ 	@LL93????????	@ 	&'''  ),??`	$.6;&AA #	  K %** f    *~w2DF2D2DEE$#'	       *a//D6DDDEEE#*0022 B@<#6#<#<#>#>@@AAA_W]__   HQKKK 5T5 51I|\  NOOO)<))*** - !$L 1 1 < < > >rr B - -mTmm,,,, aGGGGcrc1BGGGHHH&0n7Hl"CC('+!	' ' 'O '1Q66VWWWUVVVVMNNNYYY<YYZZZ*17799 ]!"[/*@*F*F*H*H*S*S*U*UVW*X"["["[\\\GGGWXXX_L___```#) ( ]N]]]   EFFFF*  -$&    -$&$6!,   % ) ( ]N]]]   EFFFF*  -$&    -$&$6!,    % *4 	!"""
 (55 	eeeGWXLLSS^cee  
  	Av'')'<@@@ 	()))3444FFFFFFFF 	>4/ 	4*733F &	^N
NM3|f7L3M3MNNFf%% b

<...

<... ,`aaaf%% L*<*>*> Lqrrr.FKKKK?V=     ~tU3G{m+$#'	     0   ^T;_U$       ] ,[\\\ 8$6$8$8 8qrrr.w777?}]]]] 	()))%'''!###lU*+++ #V+i76{CC4OtSghsStSt.(0022 	_v|E7J7J 	_ 	_CDDD"%.$8I9Vd!e
 &>*<,V[\\\L&!++)~.@lZ_```&!++]^^^!"""	KIIIIII''55 KIJJJ 	K 	K 	KLLFJJJJJJJJ	K	****S!!!! 	 	 	D		D555555GGG1222 [t,,,Fh YWS!122WW$))F8DT:U:UWWXXXzz)$$ ]S	!233]]tyyPYIZ?[?[]]   zz/** RPS!899PPPQQQzz)$$ OMs6)#455MMMNNN(# 5FJJy,A,A 53444 	D 	D 	DLL?CCCCCCCC	D!	       
 )=??L ;EFFF% ; ;A;//dCCC 3'8!9!9 3%>FF 3%(x)<)<%=%=F&)!%%	2*>*>&?&?G'*155"+E+E'F'FH$&E% ? %-=-=-=-= > > >& F %-D7-D-D-D E E E' K %-I-I-I-I J J J9>%PTYYu%5%5%5LFF%2F51655V556666$ ; ; ;91699B999::::::::; 	 	 	D		LLLLLL//11F B@V@@@AAA 	 	 	D	 	=>>>	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 +*>>>2244"6"6"8"8Z{<n==<K*$< 	 *E[:-E b	7 GGGU+UUZUUU  D5====RSSSS D D DJJJKKKBCCCCCCCCD  R	7GGG9 9 9 9*  B^[!1!1^^^   [.&AAA CW3~#6#6WWWXXX^]EBBBGGG #]    ##Lc  UWWUWW  i&&(( #SZ->->-@-@ #Z[[[!#MNN H
   # # #"HHH# 333 !DJD(f2D)% ).5JRWXXX;' 87>+B 8GGG6777  XJ X(f2D2D+2DVWWWPQQQQ5666	IFFFFFF778NOOL J ,[ 9J J+7+FJ J J  
  	I 	I 	ILLBCHHHHHHHH	I 	$%%%	C+---- 	C 	C 	CLL>BBBBBBBB	C	D,.... 	D 	D 	DLL?CCCCCCCC	D
	?"$$$$ 	? 	? 	?LL:A>>>>>>>>	?	=|x''FL,F,F'FFFFFFCDDD""40000 	= 	= 	=LL8!<<<<<<<<	=&  	-//2EEO**3////   F	H
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 %$$$
 "&% % %% % 	% % % %@ "%15 15 1515 15 	15 15 15 15r&        & & &!%&J999999([]]..w77=2
'^^,CDD

   6 "- *%%%~.. 
 z* 6 6 6 %n 5 56  t44t;M!#%%K"$ )(** m,,....    D k845}-) g g$E9c!+%   ,0!%$&" " " %+M$7$7$9$9$D$D$F$F S" S"D$(JJLLE#( ) (#( !$D $(==#<#< ) ('+'8'8'D'DH$.N )[(,C C/3%)()	% % %E  %|1133x?? ( )*I.(2$-(.(0(<(1	'&%& 48)-,-)" )" )" -01C0J0J0L0L0QPQ,R,R		 * * 9 1$ . . .
 -.			. ,1L(1}} %$bX$b$b]I[I[$b$b$b!" !" !" 0M/L$-2?0" 0" 0"
  , I", !+$-0J$J37)-,.	!" !" !" !" !+$-(0C$C37)-,.	!" !" !" !" $<#;$-$,,0$" $" $" !-
 %7$=$=h$G$G$G$,
 0D/C$-$,,/0" 0" 0"
 7:$($04$77" 7" 3 $<#;$-$,,?$" $" $" !-
 %7$=$=h$G$G$G$,
 !&$gX$g$g$g!" !" !"( 'N )^X,F F/3%)(*	    '1n )Y,A A/3%)(*	' ' 'G  '1Q66 $<#;$-$,,0$" $" $" +!*
 %7$=$=h$G$G$G$G %*([([([([%& %& %& %/N(1^X4N(N7;-102	%& %& %& %& %/N(1Y4I(I7;-102	%& %& %& %& (@'?(1(004(& (& (& %*
 );(A(A((K(K(K(-.Tx.T.T.T(U(U(U(UCHF??iiXZ(--_X -_ -_JU-_ -_Zb-_ -_ @K-_ -_ Zb-_ -_ @K	-_ -_ U]	-_ -_)* )* )* )* !&$cx$c$c7>K_K_KaKa$c$c!" !" !" !"cS"h .z/HI    xzz           "8!7!9!9J!((** Q *(&2C2C2E2EF+/!%$%	! ! ! !+q00Q / 1 1 1 2 9 9:K:K:M:M N N N N#-#@ Q Q Q*1!Xr*B*B*Hb)O)O)Q)Q %&Ov&O&O P P P P P P P PQ *:+DkR   D -,..L++)  K! ! ! !::UUU! ! !
 /4466 !9 !9	T>>t|SQQ  87"/    W_5555.@     '&sEEEE$$$#**4<8888"  +++GC111OOC((((*O<   D " [ - 4 4C2S223333& R II&9::EPPPQQQ!$[!1!1C8K4L4L!L! V>VVVWWWDEEE%))Y   & k SC   &7&7&9&9#..!4!%  
 KJJJJJJ %GGGdVddd   ONNNNN% ! !!
 +N3d;;;;; 2OWM ! ! ! D! K$$$ S S SEzRRRRRRRRS  	H 	H 	HLLCQGGGGGGGG	H	J          )(** C/F/F/H/H CCDDD*C*C*E*E : :&D$(.:HHFE888%8889999STTTTUUU78889:::ABBB 	J 	J 	JLLEqIIIIIIII	J 	()))=>>>GHHHHH(   <7""/A//0007888GGGD!!!!+++,,,HQKKKKKKKKK "!!!!!sY  0A6C' '
D1DD"N5BH BH /'\ BH 
]!]<BH ])BH 0J<j ,ABH Ak""FBH 7!r BH :sBH sF"BH 9%z BH 
{){	BH 	{BH {0 /BH 0
{=:BH <{==BH E0AA2 A1BH A2
AB!A<ABBBH BAB!B!BH B%7AH3 CD AG?G=AH3 G?
AH/H	AH*H$AH3 H*AH/H/AH3 H2BH H3
AI H=BH H?AI I BH I%AI* I)BH I*
AI7I4BH I6AI7I7BBH LAL- L+BH L-
AM#L7!AMMBH MAM#M#DBH R3AR6 R5BH R6ASSBH SASSB#BH U)AAV- V,BH V-
AWV7AWWBH WAWW BH W=AX XBH X
AX;XAX6X1BH X6AX;X;BH X?AY YBH Y
AY=YAY8Y3BH Y8AY=Y=BH ZAZ ZBH Z
AZ?ZAZ:Z5BH Z:AZ?Z?BH [AA\ \BH \
A]\!A]\<BH ]A]]BH ]A]3 ]2BH ]3
A^ ]=BH ]?A^ ^ BH ^A BB _%A_, _+BB _,A_;_8BB _:A_;_;BB `:A`< `;BB `<
Aa	aBB aAa	a	BB a Aa. a-BB a. AbbBB bAbb3BB c
Ac cBB c
AccBB cAccBB c2CArgA	AhhArhAh0h-Arh/Ah0h0IArr BB rArrBB rArrBB r*AAv t'At, t+Av t,Au>t;9Au9u4Av u9Au>u>Av vBB vAv"vBB v!Av"v"A/BB xAx-x,BB x-Ayy BB yAyyABB z/Az?z>BB z?A{{BB {A{{B8BB ~A9BA @B@@BA @B@3@0BA @2B@3@3BA ABB A
BA=ABA8A3BB A8BA=A=BB B BH B
BB1BBB,B'BH B,BB1B1BH B5C&BF FBH F
BGF&BGGBH GBGGA BH HBJ&HA8BJ!J!BJ&c                 h   h d}h d}g }d}|t          |           k     r| |         }||v r|                    |           |dz  }g }|t          |           k     r}| |                             d          sb| |         |vrX|                    | |                    |dz  }|t          |           k     r%| |                             d          s
| |         |vX|r(|                    d                    |                     n|                    |           |dz  }|t          |           k     |S )a  Join unquoted multi-word session names after -c/--continue and -r/--resume.

    When a user types ``hermes -c Pokemon Agent Dev`` without quoting the
    session name, argparse sees three separate tokens.  This function merges
    them into a single argument so argparse receives
    ``['-c', 'Pokemon Agent Dev']`` instead.

    Tokens are collected after the flag until we hit another flag (``-*``)
    or a known top-level subcommand.
    >'   acpr   r   r  r  clawcrondumpr  r?  loginrr  setupr(  r  r3  doctorhonchoimportlogoutmemoryr;  r  r  r   r  pairingpluginsrF	  rX   webhookinsightsr   r  r  r   r  
completionr  >   r   r   r   r   r   r=   r   r!  )r   rz  rR   r'   )r;   _SUBCOMMANDS_SESSION_FLAGSr  r   r8  r$  s          r   _coalesce_session_name_argsr	  I%  sY   ( ( (LR <;;NF	A
c$ii--QN""MM%   FAECIIQ**3// G<//T!W%%%Q CIIQ**3// G<//  /chhuoo...MM%   FA% c$ii--& MrC   c                 .   ddl m}m}m}m}m}m}m}m}m	}	m
}
m} ddlm} t          | dd          }| |            } |            }t          d|            t          d|             |            }|D ]}|j        |k    s|dk    r|j        r|j        r,t          d	|j         |j        rd
|j         dndz              t          d|j        rdnd            t          d|j         d           |j        r(|j        p|j        }t          d| d|j                     nt                       dS |dk    r% |            } |            }|st          d           dS 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$ 
           |D ]}|j        |k    s|dk    r	|j        rd%nd&}|j        }|j        pd'dd(         }|j        rdnd}|j        r|j        p|j        nd'}|j        rd'}|j        r|j         d)|j        pd* }|dd+         }nd'}t          | |d,d|dd|dd|dd| 
           t                       dS |d-k    r| j        }	  ||           |dk    rt          d.           nt          d/|            dS dS # t6          t8          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|d2k    r| j        }t          | d3d4          }t          | d5d4          }t          | d6d4          }t          | d7d4          }	 t          | d8d          } |||||||t          | d9d          :          } t          d;| d<|             |s|rDt          | d8d          p	 |            }!|rt          d=|! d>           nt          d?|! d>           |s|r6	 dd@lm }"  |"|          rt          dA| d           n# tB          $ r Y nw xY w|s ||           }#|#r%|#"                    dB          rt          dC           nZ|#r6tG          |#"                    dDg                     }$t          |$ dE           n"t          dF$                    |                     |s ||          }%|%r<t          dG| dH|%            t          dI| dJ           t          dK| dL           nb ||          }&|&rUt          dM|&             |
            s9t          dN |             dO           t          dP           t          dQ           	 dRtK          | &                    tO          j(                                        z   }'n# t6          $ r tK          |           }'Y nw xY wt          dS           t          d&| dT           t          d&| dU           t          d&| dV           |s|r't          dW|' dX           t          dY|' dZ           n5t          d[| d\           t          d]           t          dY|' d^           t                       dS # t6          tR          t8          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|d_k    rm| j        }t          | d`d4          }(	  |||(a           dS # t6          t8          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|dbk    rddcl*m+}) tY          t          | ddd4                    }*tY          t          | ded4                    }+tY          t          | dfd4                    },t          | dgd          }-t          | dhd          }|*r1|+s/t          dit:          j-        j           t;          j        dk           |*r3|-s|r/t          dlt:          j-        j           t;          j        dk           |*s1|s/t          dmt:          j-        j           t;          j        dk           |-r1|+r/t          dnt:          j-        j           t;          j        dk           |rf|-sc|+s`	 |).                    |          dk    rddolm/}. tO           |.                      } n|)0                    |          } nI# tB          $ r<}/t          d0|/ t:          j-        j           t;          j        d1           Y d}/~/nd}/~/ww xY w| 1                                s3t          dp| dqt:          j-        j           t;          j        d1           |)2                    |           }0|0"                    d9          pd}1|1st          dr| ds           n,|0"                    dt          rdund}2t          |2 |1            t;          j        d           |-r	 |).                    |          dk    rddolm/}. tO           |.                      } n|)0                    |          } |)3                    | |-d4v           t          dw| dx           nI# tB          $ r<}/t          d0|/ t:          j-        j           t;          j        d1           Y d}/~/nd}/~/ww xY wt;          j        d           ddyl*m4}3 |*r<|35                    dz{          }4|4s#t          d|           t;          j        d           n|g}4d}5d}6|4D ]u}7|36                    |7|,}          }8|8j7        r%|5d1z  }5t          d~|8j         d|8j8                    E|6d1z  }6t          d|8j         d|8j9         t:          j-        j           v|*st;          j        |5d1k    rdnd1           t;          j        |5dk    rdnd1           dS |dk    r| j        }ddl m0}9m:}:m;};m<}<m=}=m>}>m}m?}?  |:|          s't          d| d           t;          j        d1            |9|          }  |;|           \  }}@ |<|           } |=|           }A |>|           \  }B}C}D |?|          }Et          d|            t          d|             |rt          d| |@rd
|@ dndz              t          d|rdnd            t          d|A            t          d| dz  @                                rdnd            t          d| dz  @                                rdnd            |Br>t          d|B d)|Cpd*            |Drt          d|D            t          d| d           |Er=t:          jA        dk    }F |            |Fr|E dn|Ez  }Gt          d|E d| d|G d           t                       dS |dk    r| j        }t          | dd4          }Ht          | dd          }Iddl m:}:  |:|          s't          d| d           t;          j        d1           |Ip|}E|Hr5 |	|E          rt          d|E d           dS t          d|E d           dS  ||E          }%|%r&t          d0|%            t;          j        d1            ||E|Ir|nd          }&|&r9t          d|&             |
            st          d |             dO           dS dS dS |dk    rddl mB}J 	  |J| jC        | jD                  }Kt          d| jC         d| jD                    t          d|K d           dS # t6          tR          t8          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|dk    rddl mE}L | j        }| jF        p| d}M	  |L||M          }Nt          d| d|N            dS # t6          t8          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|dk    rddl mG}O 	  |O| jH        t          | dd                    } | j        }t          d| d|              ||          }%|%s ||          }&|&rt          d|&            t                       dS # t6          tR          t8          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|dk    r#ddlI}PddlJmK}QmL}RmM}S 	 |PN                    d          5 }T |Q| jO        tO          |T          t          | dd                    }Ut          |U           t          | d`d4          so	 t          d          R                                S                                }Vn# t          t          f$ r d}VY nw xY w|Vdvrt          d           	 ddd           dS ddd           n# 1 swxY w Y    |R| jO        t          | dd          t          | dd4          t          | dd4                    }Ut          d|UjV        j         d|UjV        jW                    t          d|UjX                    |UjV        jY        rt          d|UjX         dŝ           |UjZ        rt          d|UjV        j         dǝ           t          d|UjV        j         dL           dS # |St6          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|dk    rddlJm[}Wm\}XmM}S ddl m0}9m.}Y | j        }	  |Y|          }Z |X |9|Z                    }[|['t          d|Z d̝           t;          j        d1           t          | dd4          }\t          | d`d4          st          d|Z d|[jO        pdЛ            t          d|[jW                    |\rt          dҦ           nt          dӦ           t          dԦ           	 t          dզ          R                                S                                }Vn# t          t          f$ r d}VY nw xY w|Vdvrt          d֦           dS  |W|Z|\צ          }Ut          d|UjV        j         d|UjV        jW                    |UjZ        rt          d|UjV        j         dǝ           dS dS # |St6          f$ r1}t          d0|            t;          j        d1           Y d}~dS d}~ww xY w|dk    rddlJm]}]mM}S 	  |]| j                  }^n?# |St6          f$ r0}t          d0|            t;          j        d1           Y d}~nd}~ww xY w|^st          d| j         dޝ           dS t          d|^"                    d                      t          d|^"                    dd*                      |^"                    d9          rt          d|^d9                     |^"                    d          rt          d|^d                     |^"                    d          rt          d|^d                     |^"                    d          rt          d|^d                     |^"                    d          rt          d|^d                     |^"                    d          rt          d|^d                     |^"                    d          pg }_|_rt          d           |_D ]}`|`"                    ddz          rdnd}2d&|`d          d
|2 d}a|`"                    d9          r|ad|`d9          z  }at          |a           |`"                    d          t          d|`d                     t                       dS dS )u;   Profile management — create, delete, list, switch, alias.r   )r  create_profiledelete_profiler  set_active_profileget_active_profile_namecheck_alias_collisioncreate_wrapper_scriptremove_wrapper_script_is_wrapper_dir_in_path_get_wrapper_dirr4  profile_actionNz
Active profile: zPath:           r   zModel:          rl   rm   rM   zGateway:        runningr  zSkills:         z
 installedzAlias:          u    → hermes -p r  zNo profiles found.z
 Profilez<16r!  Modelz<28Gatewayz<12AliasDistributionu-   ───────────────r  uQ   ───────────────────────────u!   ───────────u<   ────────────────────u    ◆r     —   @r]  r  z<15usez Switched to: default (~/.hermes)zSwitched to: r   r=   createcloneF	clone_allno_alias	no_skills
clone_fromr  )r   r	  r	  clone_configr	  r	  r  z

Profile 'z' created at zFull copy from r  z.Cloned config, .env, SOUL.md, and skills from )clone_honcho_for_profilezHoncho config cloned (peer: r  z`No bundled skills seeded (--no-skills). Delete .no-bundled-skills in the profile to opt back in.r  z bundled skills synced.u9   ⚠ Skills could not be seeded. Run `{} update` to retry.u   
⚠ Cannot create alias 'u   ' — z/  Choose a custom alias:  hermes profile alias z --name <custom>z$  Or access via flag:     hermes -p z chatzWrapper created: u   
⚠ z is not in your PATH.z3  Add to your shell config (~/.bashrc or ~/.zshrc):z(    export PATH="$HOME/.local/bin:$PATH"z~/z
Next steps:z0 setup              Configure API keys and modelz" chat               Start chattingz/ gateway start      Start the messaging gatewayz
  Edit z/.env for different API keysz  Edit z"/SOUL.md for different personalityu.   
  ⚠ This profile has no API keys yet. Run 'z setup' first,z8    or it will inherit keys from your shell environment.z!/SOUL.md to customize personalitydeleter  )r  describe)r   all_missingr  	overwriter#  r   z'profile describe: --all requires --autor   r   zJprofile describe: --all is mutually exclusive with a profile name / --textz<profile describe: profile name is required (or --all --auto)z:profile describe: --text is mutually exclusive with --autor   zError: profile 'z' not foundz(no description set for 'z')description_autoz[auto] )r  r	  zDescription updated for 'r_  )r]  T)missing_onlyz'All profiles already have descriptions.)r	  zDescribed '': zprofile describe r  r	  )get_profile_dirprofile_exists_read_config_model_check_gateway_running_count_skills_read_distribution_metar	  find_alias_for_profilezError: Profile 'z' does not exist.z

Profile: z	Path:    z	Model:   z	Gateway: z	Skills:  z	.env:    r   r)   znot configuredz	SOUL.md: zSOUL.mdzDistribution: zInstalled from: z  (run `hermes profile info z` for full manifest)rc  z.batz	Alias:   r?	  aliasremove
alias_name)r	  u   ✓ Removed alias 'r  z
No alias 'z' found to remove.)rf  u   ✓ Alias created: u   ⚠ r  )rename_profilez
Profile renamed: r  zPath: rN  export)export_profilez.tar.gzu   ✓ Exported 'z' to r	  )import_profileimport_name)r   u   ✓ Imported profile 'z' at z  Wrapper created: r  )plan_installinstall_distributionDistributionErrorhermes_dist_preview_rS   install_name)override_namez
Proceed with install? [y/N] >   r  r  zInstall cancelled.r  )r   r  create_aliasu   
✓ Installed 'z' vz  Profile path: zA  Next: copy .env.EXAMPLE to .env and fill in required keys:
    z/.env.EXAMPLEz^  Cron jobs were included but are NOT scheduled automatically.
  Review them with:  hermes -p z
 cron listz
  Use with:      hermes -p r  )update_distributionread_manifestr	  )r	  normalize_profile_namezt' is not a distribution (no distribution.yaml). Only profiles installed via `hermes profile install` can be updated.force_configz	
Update 'z' from: z(no source)z  Currently at version z6  --force-config set: config.yaml WILL be overwritten.zC  config.yaml will be preserved (pass --force-config to overwrite).zA  User data (memories, sessions, auth, .env) will NOT be touched.z
Proceed? [y/N] zUpdate cancelled.)r	  u   
✓ Updated 'u   ' → vz6  Cron files were refreshed.  Review with:  hermes -p r  )describe_distributionr	  z	Profile 'z/' is not a distribution (no distribution.yaml).
Distribution: r   zVersion:      rX   zDescription:  authorzAuthor:       licensezLicense:      hermes_requireszRequires:     Hermes r  zSource:       installed_atzInstalled:    env_requiresz
Environment variables:requiredr  r	  z      default: )^r   r  r	  r	  r  r	  r	  r	  r	  r	  r	  r	  r   r5  rY  rw   r   
is_defaultrr  r  gateway_runningskill_count
alias_pathr	  distribution_namedistribution_versionr   r   r   r@   r   rC	  r	  r   r%   r   formatr/   ru  r~   r3   r  rr   r   rQ   r   r	  r   r	  rw  read_profile_metawrite_profile_metar]  list_describable_profilesdescribe_profiler5  r  r  r	  r	  r	  r	  r	  r	  r)   r   r	  old_namenew_namer	  outputr	  rc  r<  hermes_cli.profile_distributionr	  r	  r	  r  r  _render_distribution_planr  r0   r1   r  r  rS  rX   
target_dirr	  has_cronr	  r	  r	  )brZ  r  r	  r	  r  r	  r	  r	  r	  r	  r	  r	  r5  actionr   dhhr   r  alias_displayr  r  r   rr  gwr	  r  r  r	  r	  r	  r	  r	  profile_dirsource_labelr	  r  r  	collisionwrapper_pathprofile_dir_displayr  _profiles_modall_flag	auto_flagoverwrite_flag
text_value_hhr   r  r  tag_pdtargetsok_count
fail_counttgtoutcomer	  r	  r	  r	  r	  r	  r	  r  r;  	dist_namedist_versiondist_sourcer	  
is_windowsr  r	  custom_namer	  new_dirr	  r	  result_pathr	  r<  r	  r	  r	  r  planr  r	  r	  r	  canonr  r	  r	  rY  env_reqserre   sb                                                                                                     r   cmd_profiler
  %  s                              544444T+T22F~..00!!##1<11222&&&''' =?? 	 	Av%%,)*C*C*C7 4174412C-
----E   VA4E'Tyy9VV   BBBBCCC< U$%L$:AFMS]SS16SSTTT =??((** 	&'''F 	.)@ . .'@ . .	@ . .-. .+. .	
 	
 	
 	,
 , ,
 , ,
 , ,, ,), ,	
 	
 	

  	Q 	QA Ff$$9)<)<)<  
 6DW%ss+E/>YB01GQ\+QV%E| " -OO0F0M#OOCRCyVOTOOOOOOBOOOUOOOOOPPPP	5 	t$$$y  9::::,d,,----- ;: -. 	 	 	-A--   HQKKKKKKKKK	 
8		 gu--D+u55	4U33D+u55	c	 |T::J(.%#"!##D->>  K @@@;@@AAA 		 	D,55R9P9P9R9R   ;L;;;<<<<XXXX  
  	 RRRRRR//55 FDTDDDEEE    D  ,,[99 fjj):;; S      Hb!9!9::FV<<<====SZZ      O11$77	 OOOOIOOPPP`$```   LLLLMMMM#8#8#>#>L# O@,@@AAA6688 O!"T+;+;+=+="T"T"TUUU! V   ""MNNN7&*S1H1H1U1U-V-V&V## 7 7 7&)+&6&6###7 "###MtMMMNNN?t???@@@LtLLLMMM X	 XS"5SSSTTTW 3WWWXXXXZdZZZ   QRRRV 3VVVWWWGGGGGO->? 	 	 	-A--   HQKKKKKKKKK	 
8		 dE5))	N4S))))))-. 	 	 	-A--   HQKKKKKKKKK	 
:		 	988888mU;;<<vu5566	gdK??@@T6400
t^T22 	I 	;#*MMMMHQKKK 	 	t 	\Z    HQKKK 	 	PWZWabbbbHQKKK 	) 	LZ    HQKKK  	
 	9 	 77==JJGGGGGG"&ssuu++KK"/"?"?"E"EK   oooCJ7777 %%'' ::::LLLL 22;??D88M**0bD &:$:::;;;;#'88,>#?#?GiiRndnn%%%HQKKK  	 77==JJGGGGGG"&ssuu++KK"/"?"?"E"EK00 *%* 1   
 :$:::;;;;   oooCJ7777 HQKKK 	877777 	333FFG ?@@@fG
 
	 
	C**3.*IIGz ARG$8RRW=PRRSSSSa
P(<PPPP      	0H(a--QQQ///hll*****	6		 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 ~d## 	<T<<<===HQKKK%od++,,[99x##K00{++/F/F{/S/S,	<++D11
"D""###'+''((( 	P%e%%X)M)9h)9)9)9)92NOOO:r8))y::;;;"&""###[[6%9$A$A$C$CYIY[[	
 	
 	
 	^[9%<$D$D$F$F\L\^^	
 	
 	
  	MD9DD|/BsDDEEE 8666777KKKKLLL 	N0J&&((:,]z,?,?,?,?S]^GLjLLLL'LLLMMM	7		 x//dL$77666666~d## 	<T<<<===HQKKK (D
 	L$$Z00 C9J999:::::A:AAABBBBB--j99I +	++,,,00;#@44D  L  L:L::;;;..00 LJ!1!1!3!3JJJKKKKKL LL L 
8		666666	$nT]DMBBGKKKDMKKLLL&7&&&'''''O->? 	 	 	-A--   HQKKKKKKKKK	 
8		666666 04 0 0 0	(.v66K;4;;k;;<<<<<-. 	 	 	-A--   HQKKKKKKKKK	 
8		666666	(.74#E#E  K #DC4CCkCCDDD .-d33I @44T:: @>>>???GGGGGO->? 	 	 	-A--   HQKKKKKKKKK	 
9			
 	
 	
 	
 	
 	
 	
 	
 	
 	
*	 ,,4J,KK s#|KII")$"E"E  
 *$///tUE22 $!&'G!H!H!N!N!P!P!V!V!X!X$&78 $ $ $!#$\112333                      " ('T>488dGU33$T7E::	  D Tdm&8TTT]=RTTUUU6T_66777}) :?: : :   } U6:m6HU U U   K$-2DKKKLLLLL!:. 	 	 	-A--   HQKKKKKKKKK	 
8			
 	
 	
 	
 	
 	
 	
 	
 	
 	

 	POOOOOOO $	**400E#mOOE$:$:;;G[u [ [ [   "4??L4.. S5SS'.2QMSSTTTAAABBB aRSSSS_```YZZZ "#677==??EEGGFF "34      FFF ---...F&&u<HHHDVDM$6VVt}?TVVWWW} @!%!3@ @ @     
 ":. 	 	 	-A--   HQKKKKKKKKK	 
6		\\\\\\\\	(():;;DD!:. 	 	 	-A--   HQKKKKKKKK	  	*D- * * *   F3&!1!1334449txx	37799:::88M"" 	:84#68899988H 	534>3344488I 	644	?4455588%&& 	EC$/@*ACCDDD88H 	534>3344488N## 	;94#799:::88N++1r 		=,--- = =$&FF:t$<$<Ljj*0BvJ00#00066-(( 87B}$5777Dd66)$$0;ByM;;<<<O 
	s  53J, ,K.=&K))K.BY $O= <Y =
P
Y 	P

D>Y 	6V  ?Y  VY VB9Y Z.&ZZ[ \!&\\6Ac 
d	2dd	A7i 
j2jjA| }-&}}!~$ $&5&!!&6A7AA/ A/AB7B&AB2B2AB7CAJ$ C&AAF1D73AE+E*AF1E+AFE>AF1F AFFAF1FAJ$ F%AJ$ F1AF5F5AJ$ F8AF5F9C)AJ$ J$AK!J0&AKKAK!LCAR O3AP PAR PAPPAR PAPPAR P5AAR RASR&ASSASS#AS4 S4AT0T &AT+T+AT0c                    ddl m} | j        }t          d|j         d|j                    |j        rt          d|j                    |j        rt          d|j                    |j        rt          d|j                    t          d| j	                    t          d	| j
                    | j        r=| j
        |z                                  }|rt          d
           nt          d           |j        rlt          d           |j        D ]T}|j        rdnd}t          j                            |j                  du}|s| j
                                        r| j
        dz  }|                                r	 |                                                                D ]k}|                                }	|	r|	                    d          r.|	                    dd          d                                         }
|
|j        k    rd} nln# t0          $ r Y nw xY w|rdn
|j        rdnd}d|j         d| d| d}	|j        r|	d|j         z  }	t          |	           V| j        rt          d           dS dS )zAPrint a human-readable summary of a pending distribution install.r   )MANIFEST_FILENAMEr	  z vr  z  Author:   z  Requires: Hermes z  Source:   z  Target:   uC     (profile exists — will overwrite distribution-owned files only)u    ⚠ Profile exists but is NOT a distribution.  Installing here will
    overwrite its SOUL.md, skills/, cron/, and mcp.json.
    Your memories, sessions, auth.json, and .env will be preserved,
    but any hand-edits to distribution-owned files will be lost.z
  Env vars:r	  r  Nr   r^   r]   r=   Tu   ✓ setzneeds settingr	  u       • rl   r  rm   r	  uj   
  ⚠ This distribution ships cron jobs.  They will NOT run automatically — review and enable manually.)r	  r
  rS  rw   r   rX   r  r	  r	  
provenancer	  ri  r-  r	  r	  r#   r$   r%   rw  r   r"  r0   rR   ra   rH   r	  )r
  r
  mfexisting_is_distributionr
  r
  alreadyenv_pathr7   re   r0  r  s               r   r	  r	  '  s   AAAAAA	B	
4RW
4
4

4
4555	~ %#2>##$$$	y *(RY(()))	 :8B$688999	
*
*
*+++	
*
*
*+++}  %)O6G$G#P#P#R#R # 	WXXXXS   
 o/ 	 	B ";**C jnnRW--T9G t5577 ?V3##%% 
#+#5#5#7#7#B#B#D#D & &C#&99;;D#' )4??3+?+? ) ("&**S!"4"4Q"7"="="?"?C"bg~~*. %  . #   ")ZYY2;0YTYF9bg9999999D~ 10000$KKKK} 
<	
 	
 	
 	
 	

 
s   BH
H%$H%c                     t                      } | st          d           dS t          t          |            d           | D ]}d}	 t          j        dk    rd| d}t
          j                            |          rwt          |d          5 }|	                                
                    d	d
                              dd                                          }ddd           n# 1 swxY w Y   n# t          t          f$ r Y nw xY w|rt          d| d|            t          d|            t          |           S )a:  Print ``hermes dashboard`` PIDs and return the count.

    Uses the same detection logic as ``_find_stale_dashboard_pids`` (the
    current process is excluded, but since ``hermes dashboard --status``
    runs in a short-lived CLI process that never matches the pattern,
    the exclusion is irrelevant here).
    &No hermes dashboard processes running.r   z& hermes dashboard process(es) running:rM   rc  z/proc/z/cmdliner5  r4      r   r  r  Nr  r  )r  rw   r   r@   r   r#   r&   r)   r+   r  r  r  r0   rH   r   )r  r  cmdlinecmdline_pathr  s        r   _report_dashboard_statusr%
  (  s    &''D 6777q	SYY
>
>
>??? $ $	|w&&55557>>,// lD11 QFFHH$WWd33#VGIV>>"UWW	                 $ 	 	 	D	 	$-S--G--...."S""####t99s8   AC5AC)C5)C-	-C50C-	1C55D	D	hostportc                     ddl }	 |                    | pd|fd          5  	 ddd           dS # 1 swxY w Y   dS # t          $ r Y dS w xY w)u   True when something is accepting TCP connections at host:port.

    Any listener counts — even a 401 response proves a dashboard is up.
    Used by the unified profile-launch routing to decide attach-vs-start.
    r   Nr  r<	  r  TF)socketcreate_connectionrH   )r&
  r'
  r)
  s      r   _dashboard_listeningr+
  9(  s     MMM%%t':{D&A3%OO 	 		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	   uus'   = 0= 4= 4= 
A
Ac                 :   t          | dd          r*t                      }t          j        |dk    rdnd           t          | dd          rit	                      }|s#t          d           t          j        d           t          d           t	                      }t          j        |rdnd           	 dd	lm}  |            }n# t          $ r d
}Y nw xY w|dvr7t          | dd          s%t          | dd          st          j                            d          dk    rd| j        pd d| j         d| }t          | j        | j                  rst          d| j         d           t          d| d|            | j        s+	 ddl}|                    |           n# t          $ r Y nw xY wt          j        d           t          d| d           t          j        dddd
dd t)          | j                  d!| j        d"|g}| j        r|                    d#           t          | d$d          r|                    d%           t          | d&d          r|                    d'           t          j                                        }	|	                    d(d           t          j        d)k    r=t3          j        ||	*          }
t          j        |
                                           n t          j        t          j        ||	           	 dd+lm}  |d,-           n# t          $ r Y nw xY w	 ddl}ddl }nq# tB          $ rd}t          d.           t          d/tD           d0t          j         d1           t          d2|            t          j        d           Y d}~nd}~ww xY wtG                       d3t          j        vr?t          | d&d          s.tI          tD          d4z  d56          st          j        d           nt          | d&d          rd3t          j        v rtK          t          j        d3                   ntD          d7z  d8z  }|d9z  &                                sDt          d:|            t          d;           t          d<           t          j        d           t          d=|            	 dd>l'm(}  |             n5# t          $ r(}t          d?| t          j)        @           Y d}~nd}~ww xY w	 ddAl*m+}  |tX          dBC           n,# t          $ r tX          -                    dDd5E           Y nw xY wddFl.m/}  || j        | j        | j         t          | d$d          t          | dd          pdG           dS )HzGStart the web UI server, or (with --stop/--status) manage running ones.r  Fr   stopr!
  zrequested via --stop)r  r=   )r	  r   )r   r  isolatedopen_profilerM   HERMES_DESKTOPr?   r  r  r)  z
/?profile=z*Machine dashboard already running on port r  z  Managing profile 'r	  Nz+Routing to the machine dashboard (profile 'zB' preselected). Use --isolated for a dedicated per-profile server.r   r  r   r   z--portz--hostz--open-profilez	--no-openinsecurez
--insecurer  z--skip-buildr   rc  r  r   r   r   z;Web UI dependencies not installed (need fastapi + uvicorn).zMRe-install the package into this interpreter so metadata updates apply:
  cd r&  zP -m pip install -e .
If `pip` is missing in this venv, use:  uv pip install -e .zImport error: HERMES_WEB_DISTr%  Tr  rr   r  r  u6   ✗ --skip-build was passed but no web dist found at: zG  Pre-build first:  npm install --workspace web && npm run build -w webz.  Or drop --skip-build to build automatically.u8   → Skipping web UI build (--skip-build); using dist at discover_pluginsu   ⚠ Plugin discovery failed: r   start_background_mcp_discoveryzdashboard-mcp-discoveryr>  thread_namez9Background MCP tool discovery failed at dashboard startupr  )start_server)r&
  r'
  open_browserallow_publicinitial_profile)0rY  r%
  r@   r   r  rw   r
  r   r	  r   r#   r$   r%   r&
  r'
  r+
  no_open
webbrowserr+   rB  r/   rz  r=  rC  r   r*  r  r   execvper  r   fastapiuvicornr   r<  rV  r-  r~   r)   rd  r4
  r   hermes_cli.mcp_startupr6
  r>  r?  hermes_cli.web_serverr9
  )rZ  ru  r  	remainingr	  _launch_profiler  r>
  reexec_argvr  r  r  r@
  rA
  r  
_dist_rootr4
  r   r6
  r9
  s                       r   cmd_dashboardrH
  H(  s    tXu%% )(**eqjja((( tVU## 
()++ 	:;;;HQKKK'/EFFFF /00	i&Q'''$??????1133 $ $ $#$ 	444j%00 	5nb11 	5 JNN+,,33Y	0[YY49YYYY	4955 		KtyKKKLLLBBBSBBCCC< %%%%OOC((((    DHQKKKP/ P P P	
 	
 	

 ND"3)c$)nndio
 < 	,{+++4U++ 	-|,,,4u-- 	/~...joot$$$ <7""#KS999DHTYY[[!!!!Js~{C888FFFFFF&&&&&    	 	 	KLLLJ J JJ J J	
 	
 	
 	"q""###	 !"""
**74u3U3U*\E1>>> 	HQKKK	|U	+	+ W !BJ.. -.///,z9 	
 \)1133 	W:WWXXX[\\\BCCCHQKKKUUUVVVF777777 F F F 	3c33#*EEEEEEEEE	F
IIIIII&&1	
 	
 	
 	
 	
  
 
 
G 	 	
 	
 	
 	
 	

 322222
 LYY%T:u55nb99?R     sy   7C CCF' '
F43F4L* *
L76L7;M 
N2AN--N2	S 
T$TTT) )&UUc                 (    ddl m}  ||            dS )z?Register a self-hosted dashboard OAuth client with Nous Portal.r   )cmd_dashboard_registerN)hermes_cli.dashboard_registerrJ
  rZ  _impls     r   rJ
  rJ
  )  s%    MMMMMM	E$KKKKKrC   c                     ddl m}m}m} t	          | dd          }|dk    rt           ||                     dS |dk    rt           ||                     dS t           ||                     dS )zPrint shell completion script.r   )generate_bashgenerate_zshgenerate_fishshellr  zshfishN)hermes_cli.completionrO
  rP
  rQ
  rY  rw   )rZ  parserrO
  rP
  rQ
  rR
  s         r   cmd_completionrW
  
)  s    PPPPPPPPPPD'6**E~~ll6""#####	&mmF##$$$$$mmF##$$$$$rC   c                 (    ddl m}  ||            dS )z?Show a byte/char breakdown of the system prompt + tool schemas.r   cmd_prompt_sizeN)hermes_cli.prompt_sizerZ
  rL
  s     r   rZ
  rZ
  )  s%    ??????	E$KKKKKrC   c                 8   ddl m}m} t          | dd          pd}|dk    r |             dS  ||t          | dd          t          | d	d
          t          | dd          t          | dd          t          | dd          t          | dd                     dS )z!View and filter Hermes log files.r   )tail_log	list_logslog_namer  r  NrG  r  followFlevelrT  since	component)	num_linesr`
  ra
  rT  rb
  rc
  )hermes_cli.logsr]
  r^
  rY  )rZ  r]
  r^
  r_
  s       r   cmd_logsrf
  )  s    33333333tZ11<WH6	H$,,tXu--dGT**i..dGT**$T22     rC   >7   prompt-sizer	  r   lspr   r  r  r	  r	  r	  helpr  sendr?  hooksr	  rr  proxyr	  slackr(  r  r3  r	  r	  kanbanr	  r	  portalr;  r  r  bundlesr^  r   r  migrater	  r	  rF	  secretsrX   r	  fallbackr	  r   r  r  r   r  r	  r  postinstallcomputer-user  >   r   r   r   r   r   r   r   r   r   r   r   r   r   c                  R   t           j        dd         } d}|t          |           k     r}| |         }|dk    r#|dz   t          |           k     r| |dz            S dS |                    d          r5d|v r|dz  }c|t          v r|dz   t          |           k     r|dz  }|dz  }|S dS )u  Return the first non-flag, non-flag-value token in ``sys.argv[1:]``.

    Used by ``main()`` to decide whether plugin discovery has to run at
    argparse-setup time. Handles common invocations like
    ``hermes -m gpt5 --provider openai chat "msg"`` by skipping the
    values attached to known top-level flags.

    Does NOT fully simulate argparse — unknown ``--foo=bar`` / ``--foo
    bar`` flags degrade gracefully (``bar`` may be wrongly classified as
    a positional, which at worst forces a one-time plugin discovery).
    r=   Nr   r   r   r]   r   )r@   r;   r   rR   _TOP_LEVEL_VALUE_FLAGS)r;   r   toks      r   _first_positional_argvry
  g)  s     8ABB<D	A
c$ii--1g$;;1us4yy  AE{"4>># 		czzQ,,,QT1B1BQFA
4rC   c                  @    t                      } | dS | t          v rdS dS )a  True when the CLI might be invoking a plugin-registered subcommand.

    Returning False lets ``main()`` skip plugin discovery entirely during
    argparse setup, saving ~500-650ms per invocation for users whose
    enabled plugins don't contribute any CLI command.
    NFT)ry
  _BUILTIN_SUBCOMMANDS)rW  s    r   _plugin_cli_discovery_neededr|
  )  s1     #$$E}u$$$u 4rC   >   Nrlr	  r  rJ  r+  tickr  
mcp_actionserve)r	  r  r   c                     t          t          | dd          p"t          j                            d          dk              S )Nr"   Fr>   r?   )rQ   rY  r#   r$   r%   r  s    r   _is_tui_chat_launchr
  )  s4    eU++Rrz~~l/K/Ks/RSSSrC   c                     | j         dk    rdS | j         dk    rt          | dd           dk    rdS | j         dk    rt          | dd           dv rdS d	S )
Nr	  Tr  r  r+  r	  rJ  >   r+  r~
  F)r  rY  r  s    r   "_command_has_dedicated_mcp_startupr
  )  sj    |ut|y  WT3Dd%K%Ku%T%Tt|v'$"E"E"X"Xt5rC   c                 6    t          |           rdS | j        dv S )NF>   Nr}
  r  )r
  r  r  s    r   _should_background_mcp_startupr
  )  s%    4   u<///rC   c                 f   t                               | j        d          \  }}| j        t          v s|rt	          | |d          |v sdS t          t	          | dd                    }	 ddlm}  |             n,# t          $ r t          
                    dd	           Y nw xY wd}t          |           rd}nit          |           rd}nWt          |           rH	 dd
lm}  |t          d           n,# t          $ r t                              dd	           Y nw xY wd}|r>	 ddlm}  |             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)zCDiscover plugins/MCP/hooks for commands that can run an agent turn.)NNNr  Fr   r3
  z&plugin discovery failed at CLI startupTr  r5
  zcli-mcp-discoveryr7
  z3Background MCP tool discovery failed at CLI startup)discover_mcp_toolsz(MCP tool discovery failed at CLI startuprX  )register_from_config)r  z-shell-hook registration failed at CLI startup)_AGENT_SUBCOMMANDSr%   r  _AGENT_COMMANDSrY  rQ   rd  r4
  r   r>  r8  r
  r
  r
  rB
  r6
  r?  tools.mcp_toolr
  r  ro  agent.shell_hooksr
  )
rZ  	_sub_attr_sub_set_accept_hooksr4
  _run_inline_mcp_discoveryr6
  r
  ro  r
  s
             r   _prepare_agent_startupr
  )  s   ,00|LLIx'' 	(!$	488HDD~u==>>M
777777 
 
 
4 	 	
 	
 	
 	
 	


 !%4   * %*!!	+D	1	1 * %*!!	'	-	- *	MMMMMM**/      	 	 	LLE      	
 %*!  
	 :99999     	 	 	LL:      	
	
111111::::::[[]]GGGGGG 
 
 
; 	 	
 	
 	
 	
 	
 	

sH   (A9 9&B"!B"C4 4&DD%D6 6&EE#!F &F0/F0c                 X    dD ]&\  }}t          | |          st          | ||           'd S )N)r  Nrr  Nr  Nr  N)r  Fr^  Nr]  Nr  F)r  setattr)rZ  r  r   s      r   _set_chat_arg_defaultsr
  )  sH    	 ) )g tT"" 	)D$((() )rC   c                     t                      sdS t          j                            d          dk    rdS t          j        dd         } d| v sd| v rdS t          |           rdS t          |           rt          d           d	S t                      }t          d
 | D                       }|s|dvrdS ddlm}  |            \  }}}|                    t                     |                    t!          |                     }t#          |dd          rt          d           d	S t#          |dd          rht%          |           ddlm} t	          j         ||j        t#          |dd          t#          |dd          t#          |dd                               |j        s|j        r|j        d|_        |j        dv rt5          |           t#          |dd           ot#          |dd           }	|	rPt7          |dd	           dt          j        d<   dt          j        d<   t#          |dd          rdt          j        d<   nt%          |           t          |           d	S dS )zHRun obvious Termux non-TUI chat/oneshot/version paths on a light parser.Fr|   r?   r=   N-h--helpr~  Tc              3   X   K   | ]%}|d k    p|dk    p|                     d          V  &dS )r   r   z
--oneshot=Nr   r   s     r   r   z._try_termux_fast_cli_launch.<locals>.<genexpr>"*  sU         	tIsk)IS^^L-I-I     rC      Nr  r   build_top_level_parserfuncrX   oneshotrun_oneshotrr  r  r  rr  r  r  r  r  r  rs  HERMES_DEFER_AGENT_STARTUPHERMES_FAST_STARTUP_BANNERr  r1  )r  r#   r$   r%   r@   r;   rB   rY   r  ry
  r  hermes_cli._parserr
  set_defaultsr  
parse_argsr	  rY  r
  r  r
  r   r
  r^  r]  r  r
  r
  )
r;   rW  has_oneshotr
  rV
  _subparserschat_parserrZ  r
  interactive_prompts
             r   _try_termux_fast_cli_launchr
  *  s   )++ u	z~~6773>>u8ABB<Dt||x4''u  u#D)) %0000t"$$E      K  566u999999'='='?'?$FK(+++8>>??DtY&& %0000ttY%% 
t$$$222222KdGT22 z488 z488	  	
 	
 	
 	 t) t|/C|~%%t$$$!(w!=!==bgdT[]aFbFbBb 		) D)T***7:BJ347:BJ34t^U33 847
01"4(((t5rC   c                  l   t                      sdS dt          j        dd         v sdt          j        dd         v rdS t          t          j        dd                   } | sdS t	                      }|dvrdS ddlm}  |            \  }}}|                    t          	           |	                    t          t          j        dd                             }t          |d
d          st          |dd          rdS t          |dd          dvrdS t          |          sdS t          |           dS )a  Launch obvious Termux TUI invocations before building every subparser.

    `hermes --tui` is the hot path on phones. The full parser setup imports
    command modules for model, fallback, migrate, kanban, bundles, plugins,
    etc. even though the TUI immediately execs Node. On Termux only, parse the
    lightweight top-level/chat parser and hand off to ``cmd_chat`` when the
    invocation is unambiguously the built-in TUI/chat path.
    Fr
  r=   Nr
  r
  r   r
  r
  rX   r
  r  T)r  r@   r;   rB   ry
  r
  r
  r
  r  r
  r	  rY  r[  )	wants_tuirW  r
  rV
  r
  r
  rZ  s          r   _try_termux_fast_tui_launchr
  V*  sW    *++ usx|x38ABB<77u !""..I u"$$EN""u999999'='='?'?$FK(+++8!""FFGGD tY&& '$	4*H*H utY%%^;;uD!! uTNNN4rC   c           
         t          | dd           }|dk    ruddlm}m}  |            }t	          |                    d          t                    si |d<   d|d         d<    ||           t          d           t          d	           d S |d
k    rddlm	}m
}  |            dz  t          | dd          }g }|dv r|                    d           |dv r|                    d           fd|D             }	|	st          d |             d           d S t          d           |	D ]=\  }
}|
z  }|                                j        }t          d|
 d| d|dd           >t          | dd          ss	 t          d                                                                          }n'# t"          t$          f$ r t          d           Y d S w xY w|dk    rt          d            d S |	D ]2\  }
}|
z                                   t          d!|
 d| d"           3t          d#           t          d$ |             d           d S dd%lm}  ||            d S )&Nmemory_commandr0  r   ro  r	  rM   r  u%   
  ✓ Memory provider: built-in onlyz  Saved to config.yaml
rZ  r  memoriesrf  r  >   r  r	  )z	MEMORY.mdzagent notes>   r  r-	  )zUSER.mdzuser profilec                 L    g | ] \  }}|z                                   ||f!S rI   r0  )r   r  r  mem_dirs      r   r  zcmd_memory.<locals>.<listcomp>*  sF     
 
 
!!T!7K7K7M7M
I
 
 
rC   u1   
  Nothing to reset — no memory files found in z/memories/
z:
  This will permanently erase the following memory files:u       ◆ rl   u   ) — r  z bytesr  Fz
  Type 'yes' to confirm: z
  Cancelled.
z  Cancelled.
u     ✓ Deleted rm   zE
  Memory reset complete. New sessions will start with a blank slate.z  Files were in: )r
  )rY  r  ro  rp  r-   r%   r.   rw   r   r   r5  rz  r=  r?  r  r0   r1   r  r  rE  hermes_cli.memory_setupr
  )rZ  r  ro  rp  r3  r   r5  rf  files_to_resetri  r  r  r&   sizer  r
  r
  s                   @r   
cmd_memoryr
  *  sR   
$($
/
/C
e||>>>>>>>>&**X..55 	"!F8')x$F6777()))))	IIIIIIII!/##j0x//&&&!!">???_$$!!"=>>>
 
 
 
%3
 
 
  	hEXEXEZEZhhh   FLMMM 	> 	>GAtQ;D99;;&D<Q<<$<<d<<<<====tUE** 	<==CCEEKKMM/0   ())) &''' 	1 	1GAtq[  """/1/////0000U	
 	
 	
 	E"5"5"7"7EEEFFFFF::::::ts   =3F1 1 GGc                 `   	 ddl m} g }t          | dd          r|                    d           t          | dd          r|                    d           t          | dd          r|                    d	           t          | d
d          r|                    d           t          | dd          r|                    d            ||           dS # t          $ rN t          dt          j                   t          dt          j                   t          j        d           Y dS w xY w)z%Launch Hermes Agent as an ACP server.r   rq  acp_versionFrW   r  z--checkr	  z--setupsetup_browserz--setup-browserrH	  --yeszACP dependencies not installed.r   z+Install them with:  pip install -e '.[acp]'r=   N)	acp_adapter.entryrr  rY  rz  r   rw   r@   r   r   )rZ  acp_mainacp_argvs      r   cmd_acpr
  *  sM   6666664.. 	)OOK(((4%(( 	'OOI&&&4%(( 	'OOI&&&4%00 	/OO-...4u-- 	%OOG$$$   /cjAAAA;#*MMMMs   CC AD-,D-c                     t          | dd           }|dv rddlm}  ||            d S |dk    r%ddlm} t	          j         ||                      d S t          d           ddlm}  ||            d S )	Ntools_action>   r  enabledisabler   )tools_disable_enable_commandz
post-setup)run_post_setup_commandr(  )tools_command)rY  rD	  r
  r
  r@   r   r   r
  )rZ  r	  r
  r
  r
  s        r   	cmd_toolsr
  *  s    T>400F...HHHHHH$$T*****	<		BBBBBB''--.....W999999drC   c                 L   	 ddl m} ddlm}  |            } ||          }|                    | j        | j                  }t          |                    |                     |	                                 d S # t          $ r}t          d|            Y d }~d S d }~ww xY w)Nr   r  )InsightsEngine)r  r  zError generating insights: )r  r  agent.insightsr
  generater  r  rw   format_terminalr   r   )rZ  r  r
  r!  enginereportr  s          r   cmd_insightsr
  *  s    
1******111111Y[[##diDDf$$V,,---





 1 1 1/A//0000000001s   A8A< <
B#BB#c                     t          | dd           dk    r"t          d           ddlm}  ||            d S ddlm}  ||            d S )Nskills_actionr3  zskills configr   )skills_command)rY  r   hermes_cli.skills_configr
  hermes_cli.skills_hub)rZ  skills_config_commandr
  s      r   
cmd_skillsr
  *  sx    t_d++x77_%%%TTTTTTd#####888888trC   c                 (    ddl m}  ||            d S )Nr   )pairing_command)hermes_cli.pairingr
  )rZ  r
  s     r   cmd_pairingr
  +  s*    222222ODrC   c                 (    ddl m}  ||            d S )Nr   )plugins_command)hermes_cli.plugins_cmdr
  )rZ  r
  s     r   cmd_pluginsr
  +  s*    666666ODrC   c                 (    ddl m}  ||            d S )Nr   )mcp_command)hermes_cli.mcp_configr
  )rZ  r
  s     r   cmd_mcpr
  +  s*    111111KrC   c                 (    ddl m}  ||            d S )Nr   )claw_command)hermes_cli.clawr
  )rZ  r
  s     r   cmd_clawr
  +  s*    ,,,,,,LrC   c                     =>?@AB t                       	 ddlm}   |              n# t          $ r Y nw xY w	 t	                       n# t          $ r Y nw xY w	 dt
          j        dd         vrt                       n# t          $ r Y nw xY wt                      rdS t                      rdS ddl
m}  |            \  @}}|                    t                     t          |t                     dd	lm} |                    d
dd          }|                    d          }|                    ddgd           |                    dd           |                    ddgd           |                    dd           |                    |           |                    ddd          AA                    d          }|                    d d!gd"          }dd#lm}	 |	                    |           Afd$}
A                    |
           dd%lm}m} |                    d&d'd(          }|                    d)          }|                    d*d+d,          }|                    d-d.d/0           |                    d1d.d20           |                    |           |                    |           t7          |t8          t:          3           	 dd4lm}  ||           n2# t          $ r%}t@          !                    d5|           Y d}~nd}~ww xY wtE          |tF          6           tI          |tJ          7           tM          |tN          8           |                    d9d:d;          }|                    tP                     tS          |tT          <           dd=l+m,}  ||           t[          |t\          >           t_          |t`          ?           tc          |td          @           tg          |th          A           tk          |tl          B           to          |tp          C           ddDl9m}  ||           ddEl:m;}  ||          }|                    tx                     t{          |t|          F           t          |t          G           t          |t          H           t          |t          I           t          |t          J           t          |t          K           |                    dLdMdN          }ddOlIm}  ||           t          |t          P           t          |t          Q           t          |t          R           t          |t          S           |                    dTdUdV          }ddWlRm}mS}  ||           |                    |           t          |t          X           t                      r	 ddYlWmX} ddZlYmZ}m[} t                      } |            D ]} |                    | d[         | d\         | ]                    d]d^          t          d_          j_        `          }! | da         |!           | ]                    db          |!                    | db                    |`                    | d[                     |              |            ja        b                                D ]} | d[         |v r|                    | d[         | d\         | ]                    d]d^          t          d_          j_        `          }! | da         |!           | ]                    db          |!                    | db                    nD# t          $ r7}"t          jd        t                    !                    dc|"           Y d}"~"nd}"~"ww xY w|                    dddedf          }#	 ddOlfm}$  |$|#           nD# t          $ r7}"t          jd        t                    !                    dg|"           Y d}"~"nd}"~"ww xY wt          |t          h           t          |t          i           |                    djdkdl          ??                    dm          }%|%                    dndo          }&|&                    dpd.dq0           |%                    drds           ?fdt}'?                    |'           t          |t          u           |                    dvdwdx          BB                    dy          }(|(                    ddz          })|)                    d{d|           |)                    d}t          d~d           |(                    dd          }*|*                    dd           |*                    d{d           |*                    dd           |(                    dd          }+|+                    dd           |+                    ddd.d0           |(                    dd          },|,                    dt          dd           |,                    d{d           |,                    ddd.d0           |(                    dd           |(                    ddd          }-|-                    dd.d0           |-                    d1d.d0           |(                    dd           |(                    dd          }.|.                    dd           |.                    ddd           |(                    dd          }/|/                    d{d|           |/                    d}t          dd           dt          dt          fd==Bfd}0B                    |0           t          |t                     t          |t                     t          |t                     t          |t                     t          |t                     t          |t                     t          |t                     |                    dd          }1|1                    dddg dd           |1                    @fd           t          |t          t                      t          |t                     t          |t                     t          |t                     ddlm}2  |2            }3|3r7t          |3t
          j        dd                    t          j        d           t          t
          j        dd                   }4ddl}5t          |dæ          r&t          |j                                                  nt                      >t!          >fdĄ|4D                       }6|6rd|_        t
          j        }7	 |5                                t
          _        @                    |4          }8|7t
          _        nh# t*          $ r>}9|7t
          _        |9j        dk    r d|_        @                    |4          }8Y d}9~9n$d}9~9ww xY wd|_        @                    |4          }8|8j        rt          |8           dS t1          |8           t3          |8dd          r\ddlm}: t          j         |:|8j        t3          |8dd          t3          |8dd          t3          |8dd          ̦                     |8j        s|8j        rJ|8j        Cd|8_        dD ](\  };}<t          |8|;          stA          |8|;|<           )t          |8           dS |8j        <dD ](\  };}<t          |8|;          stA          |8|;|<           )t          |8           dS t          |8dЦ          r|8                    |8           dS @                                 dS )z Main entry point for hermes CLI.r   )configure_windows_stdior  r=   Nr
  r
  )r  )cmd_fallbackrs
  z>Manage fallback providers (tried when the primary model fails)zManage the fallback provider chain.  Fallback providers are tried in order when the primary model fails with rate-limit, overload, or connection errors.  See: https://hermes-agent.nousresearch.com/docs/user-guide/features/fallback-providers)ri
  r  fallback_command)destr  lsz<Show the current fallback chain (default when no subcommand))aliasesri
  r   zOPick a provider + model (same picker as `hermes model`) and append to the chain)ri
  r	  rmz&Pick an entry to delete from the chainr  zRemove all fallback entriesrr
  z:Manage external secret sources (Bitwarden Secrets Manager)zPull API keys from an external secret manager at process startup instead of storing them in ~/.hermes/.env.  Currently supports Bitwarden Secrets Manager.  See: https://hermes-agent.nousresearch.com/docs/user-guide/secrets/bitwardensecrets_command	bitwardenbwz%Bitwarden Secrets Manager integration)secrets_clic                     t          | dd           }t          | dd           }|dv r||                     |           S                                  dS )Nr
  secrets_bw_command)r
  r
  r   )rY  r
  
print_help)rZ  r  bw_subsecrets_parsers      r   _dispatch_secretszmain.<locals>._dispatch_secrets+  s_    d-t443T::%%%&*<99T??"!!###qrC   )cmd_migratecmd_migrate_xairq
  z?Migrate configuration for retired models or deprecated settingszxDiagnose and (optionally) rewrite the active config.yaml to replace references to retired models or deprecated settings.migrate_typer"  z;Migrate xAI models scheduled for retirement on May 15, 2026zScan config.yaml for references to xAI models retiring on May 15, 2026 and, with --apply, rewrite them in-place to the official replacements per the xAI migration guide. The original config.yaml is backed up before any rewrite.z--apply
store_truez:Rewrite config.yaml in-place (default: dry-run, no writes))r	  ri
  z--no-backupz8Skip the timestamped backup of config.yaml when applying)r  r  )register_subparserzLSP CLI registration failed: %s)rw  )r  )r  r  z.Set up WhatsApp Business Cloud API integrationzConfigure the official Meta WhatsApp Business Cloud API adapter (Business account required, public webhook URL required). Distinct from `hermes whatsapp` which sets up the Baileys bridge for personal accounts.)rV  )register_send_subparser)r=  )r@  )rD  )rH  )rL  )rP  )
add_parser)build_parser)r^  )rb  )ri  )rm  )rq  )rz  r  z.Inspect / prune / clear ~/.hermes/checkpoints/u   Manage the filesystem checkpoint store — the shadow git repo hermes uses to snapshot working directories before write_file/patch/terminal calls. Lets you see how much space checkpoints occupy, force a prune, or wipe the base.)register_cli)r}  )rt  )r
  )r
  rp
  zDCreate, list, and manage skill bundles (aliases for multiple skills)zSkill bundles let you load several skills under one slash command. `/<bundle>` from the CLI or gateway loads every referenced skill at once.)r	  bundles_command)r
  )discover_plugin_cli_commands)r4
  get_plugin_managerr   ri
  r  rM   argparse)ri
  r  formatter_classsetup_fn
handler_fnzPlugin CLI discovery failed: %sr^  uB   Background skill maintenance (curator) — status, run, pause, pina  The curator is an auxiliary-model background task that periodically reviews agent-created skills, prunes stale ones, consolidates overlaps, and archives obsolete skills. Bundled and hub-installed skills are never touched. Archives are recoverable; auto-deletion never happens.zcurator CLI wiring failed: %s)r
  )r
  ru
  z4Manage the Computer Use (cua-driver) backend (macOS)a  Install or check the cua-driver binary used by the
`computer_use` toolset. macOS-only.

Use `hermes computer-use install` to fetch and run the
upstream cua-driver installer. This is equivalent to the
post-setup hook that `hermes tools` runs when you first
enable the Computer Use toolset, and is a stable target
for re-running the install if it didn't fire (e.g. when
toggling the toolset on a returning-user setup).computer_use_actionr  z/Install or repair the cua-driver binary (macOS)r  zRe-run the upstream installer even if cua-driver is already on PATH. The upstream install.sh always pulls the latest release, so this performs an in-place upgrade.r  z1Print whether cua-driver is installed and on PATHc           	      8   t          | dd           }|dk    r0ddlm}  |t          t          | dd                               d S |dk    rdd l}dd l} |j        d	          }|r}d
}	  |j        d	dgddd          j        	                                }n# t          $ r Y nw xY w|rt          d| d| d           nt          d|            t          d           d S t          d           t          d           d S                                  d S )Nr  r  r   r		  r  Fr	  r  r	  rM   rW   Tr  r'  zcua-driver: installed at rl   rm   z:  Refresh to latest: hermes computer-use install --upgradezcua-driver: not installedz"  Run: hermes computer-use install)rY  rD	  r
	  rQ   r?  r*  r@  r+  r  r0   r   rw   r
  )rZ  r	  r
	  r?  r*  r&   rX   computer_use_parsers          r   cmd_computer_usezmain.<locals>.cmd_computer_use,  s   4d;;YBBBBBBtGD)U,K,K'L'LMMMMFXMMM6<--D ,jn%{3'+$   UUWW G !   D >HdHHgHHHIIII<d<<===RSSS-...6777F&&(((((s   ,-B 
B'&B')r
  r  z<Manage session history (list, rename, export, prune, delete)z(View and manage the SQLite session storesessions_actionzList recent sessionsz--sourcez/Filter by source (cli, telegram, discord, etc.)z--limitr  zMax sessions to show)typer   ri
  r	  zExport sessions to a JSONL filer	  z)Output JSONL file path (use - for stdout)zFilter by sourcez--session-idzExport a specific sessionr	  zDelete a specific sessionrX  zSession ID to deleter
  z-yzSkip confirmationprunezDelete old sessionsz--older-thanZ   z/Delete sessions older than N days (default: 90)z$Only prune sessions from this sourceoptimizezAReclaim disk space: merge FTS5 segments + VACUUM (no data change)repairz>Repair a malformed state.db schema so hidden sessions reappearzRecover a state.db whose schema is malformed (e.g. 'table messages_fts already exists'), which makes Desktop/Dashboard show no sessions. A backup is made first; sessions and messages are preserved and the FTS search index is rebuilt if needed.z--check-onlyz@Only report whether the database opens cleanly; do not modify itz2Skip the timestamped backup copy (not recommended)statszShow session store statisticsr  zSet or change a session's titlezSession ID to renamer  r  zNew title for the session)nargsri
  browseuB   Interactive session picker — browse, search, and resume sessionsr  z#Max sessions to load (default: 500)r  r   c                     	 t          |                                                                           dv S # t          t          f$ r Y dS w xY w)z?Prompt for y/N confirmation, safe against non-TTY environments.>   r  r  F)r  r0   r1   r  r  r  s    r   _confirm_promptzmain.<locals>._confirm_promptk-  sX    	==&&((..00L@@+, 	 	 	55	s   47 AAc           
         dd l }| j        }|dk    rddlm}m}m} |}|                                st          d| d           d S  ||          }|t          d| d           d S t          d| d	|            t          | d
d          rd S t          d            ||t          | dd                     }|	                    d          r|	                    d          rt          d|d                     t          d|	                    d                      	 ddlm
}	  |	            j                            d                                          d         }
t          d|
 d           n# t          $ r t          d           Y new xY wt          d|	                    d                      |	                    d          rt          d|d                     t          d           d S 	 ddlm
}	  |	            }n*# t          $ r}t          d|            Y d }~d S d }~ww xY wt          | dd           }|rd ndg}|d k    r|                    | j        || j        !          }|st          d"           d S t%          d# |D                       }|r-t          d$d%d&d'd(d&d)d*d&d+            t          d,           n,t          d'd-d&d)d*d&d.d/d&d+            t          d0           |D ]}t'          |	                    d1                    }|r|	                    d2d3          d d4         n|	                    d2d3          d d5         }|rE|	                    d6          pd7d d8         }|d9         }t          |d%d&|d(d&|d*d&|            |d9         }t          |d-d&|d*d&|d         d/d&|            Րn|d:k    r| j        r
|                    | j                  }|st          d;| j         d<           d S |                    |          }|st          d;| j         d<           d S |                    |d=          d>z   }| j        d?k    r!t2          j                            |           nt9          | j        d@dAB          5 }|                    |           d d d            n# 1 swxY w Y   t          dC| j                    n|                    | j        D          }| j        d?k    r>|D ]9}t2          j                            |                    |d=          d>z              :nXt9          | j        d@dAB          5 }|D ]/}|                    |                    |d=          d>z              0	 d d d            n# 1 swxY w Y   t          dEt=          |           dF| j                    n|dGk    r|                    | j                  }|st          d;| j         d<           d S | j        s  +dH| dI          st          dJ           d S tA                      dKz  }|!                    ||L          rt          dM| dN           n-t          d;| j         d<           n|dOk    r| j"        }| j        rdP| j         dQnd3}| j        s# +dR| dS| dT          st          dJ           d S tA                      dKz  }|#                    || j        |U          }t          dV| dW           n|dXk    r|                    | j                  }|st          d;| j         d<           d S d&$                    | j%                  }	 |&                    ||          rt          d;| dY|            nt          d;| j         d<           n# tN          $ r}t          dZ|            Y d }~nd }~ww xY w|d[k    rt          | d\d]          pd]}t          | dd           }|rd ndg} |                    || |!          }|(                                 |st          d"           d S tS          |          }!|!st          dJ           d S t          d^|!            dd_l*m+}"  |"d`|!g           d S |dak    r|j,        }|                                r"tZ          j.        /                    |          dbz  ndc}#t          dd           	 |0                                }
n># t          $ r1}t          de|            |(                                 Y d }~d S d }~ww xY w|                                r"tZ          j.        /                    |          dbz  ndc}$|#|$z
  }%t          df|
 dg           t          dh|#didj|$didk|%didl           n|dmk    r|1                                }&|2                                }'t          dn|&            t          do|'            dpD ]4}(|1                    |(D          })|)dk    rt          dq|( dr|) ds           5|j,        }|                                r6tZ          j.        /                    |          dbz  }*t          dh|*didt           n,3                                 |(                                 d S )uNr   r  )DEFAULT_DB_PATH_db_opens_cleanlyrepair_state_db_schemazNo session database at z (nothing to repair).u   ✓ u$    opens cleanly — no repair needed.u   ✗ z does not open cleanly: 
check_onlyFu*   Repairing (a backup copy is made first)…r  )r  repairedbackup_pathz
  backup: z  strategy: strategyr  zSELECT COUNT(*) FROM sessionsu   ✓ Repaired — z sessions recovered.u   ✓ Repaired.u   ✗ Repair failed: r  z  A backup is preserved at: z3  Keep state.db and the backup; do not delete them.z(Error: Could not open session database: r  r  r  )r  exclude_sourcesr  r  c              3   @   K   | ]}|                     d           V  dS )r  Nr  )r   r  s     r   r   z-main.<locals>.cmd_sessions.<locals>.<genexpr>-  s,      >>QUU7^^>>>>>>rC   Titlez<32r!  Previewz<40zLast Activez<13r  uJ  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────r  r  z<6u  ───────────────────────────────────────────────────────────────────────────────────────────────r  r  rM   &   0   r  r	  r  r  r	  z	Session 'z' not found.)ensure_asciirN  r   wr   r   zExported 1 session to r]  z	Exported z sessions to r	  zDelete session 'z' and all its messages? [y/N] r  r  )sessions_dirzDeleted session 'r_  r  z from 'r  z%Delete all ended sessions older than z daysz? [y/N] )older_than_daysr  r0  zPruned z session(s).r  z' renamed to: r   r  r  r  zResuming session: r9  r   r  r  r	  u0   Optimizing session store (FTS merge + VACUUM)…zError: optimization failed: z
Optimized z FTS index(es).zDatabase size: r  z MB -> z MB (reclaimed z MB)r  zTotal sessions: zTotal messages: )r   telegramdiscordr  rm
  r  r  r  z MB)4r  r  r  r!  r"  r#  r)   rw   rY  r%   r  _connexecutefetchoner   list_sessions_richr  r  r  rl  rX  resolve_session_idexport_sessionr  r	  r@   r  rG   r+   
export_allr   r  r   delete_session
older_thanprune_sessionsr'   r  set_session_titler   r   r  rF  r:  db_pathr#   r&   getsizevacuumsession_countr^  r
  )-rZ  r  r	  r!  r"  r#  r?  r  r
  r  rh  r!  r  _source_excluder  
has_titlesr  r  r  r  r  resolved_session_idrY  re   r  r0  r  
source_msgru  r  r  _browse_excludeselected_idr:  	before_mbafter_mbsavedr  msgsr  r  size_mbr  sessions_parsers-                                              r   cmd_sessionszmain.<locals>.cmd_sessionsr-  sC   %
 X          &G>>## NNNNOOO&&w//F~JWJJJKKKBBB&BBCCCt\511 >???++GD+u$E$E E  F zz*%% M::m,, @>vm'<>>???=VZZ
%;%;==>>>+666666!	)117 hjj$A EaEEEFFFF  + + +/*****+ AFJJw,?,?AABBB::m,, RP9NPPQQQKLLLF	......BB 	 	 	@Q@@AAAFFFFF	
 $$//"044V,,{HDJ -  H  *+++>>X>>>>>J "QQQyQQQ}QQQ4QQRRRk""""NNNNNNUNNNNNOOOj!!! U U,QUU=-A-ABB "3AEE)R(("--y"--crc2 
  UUU7^^4ucrc:ED'CUNNNNNN{NNNNNOOOOD'CWSSS;SSSQx[SSScSSTTTTU x Q&(&;&;DO&L&L#* CdoCCCDDDF(()<== CdoCCCDDDF{{4e{<<tC;#%%J$$T****dk3AAA &Q& & & & & & & & & & & & & & &@4;@@AAAA===<<;#%%% T T
((QU)K)Kd)RSSSST dk3AAA OQ!) O OAGGEKKK$F$F$MNNNNOO O O O O O O O O O O O O O O Oc(mmOO$+OOPPPPx"$"7"7"H"H& ?$/???@@@8 &Z':ZZZ   ,'''F*,,z9L  !4< PP AA*=AAABBBB?$/???@@@@w?D59[H14;1111bJ8 &[D[[z[[[   ,'''F*,,z9L%% $T[| &  E /E///0000x"$"7"7"H"H& ?$/???@@@HHTZ((E%''(;UCC EP&9PPPPQQQQCdoCCCDDD % % %mmm$$$$$$$$% xD'3//63ET8T22F&,:dd6(O,,e -  H HHJJJ *+++0::K l### 4{44555444444Hj+.///Fz!!jG >>##((K88 
 DEEE IIKK   8Q88999


 >>##((K88 
 (E1q111222.)J . .J . .#-. . .   
 w$$&&E##%%D,U,,---+T++,,,J 4 4$$C$00q552s22a222333jG~~ :'//'22kB88888999 &&(((





s   'AE; ;FF>H 
H6H11H6-SSS.3V..V25V2A_ 
_._))_. d 
e&ee)r
  )r
  )r  )r  )r  )r
  )r
  r	  z2Print shell completion script (bash, zsh, or fish)rR
  r]  r  )r  rS
  rT
  zShell type (default: bash))r  r   r  ri
  c                 $    t          |           S r{  )rW
  )rZ  rV
  s    r   r7  zmain.<locals>.<lambda>.  s    ^D&5Q5Q rC   )rH
  rJ
  )r  )rf
  rY
  )get_container_exec_infor  c              3   J   K   | ]}|                     d           |v V  dS r   r   )r   r5  _known_cmdss     r   r   zmain.<locals>.<genexpr>.  sM        c9J9J	[     rC   TFr
  r
  rr  r  r  r
  r  )r
  r
  r
  r
  r  Nr
  )r
  r
  r
  r
  rU  r
  r
  r
  r
  )r   hermes_cli.stdior
  r   r  r@   r;   r  r
  r
  r
  r
  r
  r  r   r  hermes_cli.fallback_cmdr
  r  add_subparsersrr   r
  r	  hermes_cli.migrater  r  add_argumentr   r  r  agent.lsp.clir  r>  r?  r   rw  r   r  r   r  r  r   rV  hermes_cli.send_cmdr  r   r=  r   r@  r   rD  r   rH  r   rL  r   rP  hermes_cli.portal_clirY  r  rZ  r   r^  r   rb  r   ri  r   rm  r   rq  r   rz  hermes_cli.checkpointsr   r}  r   rt  r   r
  r   r
  hermes_cli.bundlesr
  r   r
  r|
  plugins.memoryr  rd  r4
  r  ru  r%   
__import__RawDescriptionHelpFormatterr   _cli_commandsr  r  r  r  hermes_cli.curatorr   r
  r   r
  r   r
  r   r/   rQ   r   r
  r   r
  r   r  r   r  r   r  r   r
  r   r
  r   rH
  rJ
  r   r  r   rf
  r   rZ
  r  rR  rN  r   r	  ior  r  keysr  r	  r   StringIOr
  r  rM  rX   r
  rY  r  r
  r
  r^  r]  r  r
  r
  r
  )Cr
  r
  
subparsersr
  r
  fallback_parserfallback_subparserssecrets_subparsers
secrets_bw_secrets_clir   r  r  migrate_parsermigrate_subparsersmigrate_xai_lsp_register_lsp_errwhatsapp_cloud_parserr  _add_portal_parser_build_kanban_parserkanban_parsercheckpoints_parser_register_checkpoints_clibundles_parser_bundles_registerr
  r  r4
  r  seen_plugin_commandscmd_infoplugin_parser_exccurator_parser_register_curator_clicomputer_use_subcomputer_use_installr  sessions_subparserssessions_listsessions_exportsessions_deletesessions_prunesessions_repairsessions_renamesessions_browserP  completion_parserrR  r.  _processed_argv_io_has_cmd_token_saved_stderrrZ  r   r
  r  r   r  rT  r  rV
  r
  rO  sC                                                                @@@@@@r   rr  rr  +  s    <<<<<<!!!!   !####   38ABB<''-///    #$$ "$$ 999999&<&<&>&>#FJ(+++
 zY7777
 544444 ++M`	 , 	 	O *88>P8QQ""K #   
 ""^ #    ""5 #   
 ""* #      l 333
  **IV	 + 	 	N (66<M6NN#..4 /  J 766666j)))     %6777
 @???????**NK	 +  N (66N6KK$//J;	 0 	 	K I    
 G    
 /222[111
 	RRRR
BEEEEEEj!!!! B B B 	6AAAAAAAAB zY7777
 ZIIII
 *<@@@@
 '11=8	 2 	 	 &&,>&???
 zY7777
 <;;;;;J'''
 zY7777
 
z::::
 j84444
 
z::::
 j84444
 ====
 GFFFFFz"""
 GFFFFF((44MJ/// zY7777
 
z:::: *<@@@@
 j84444
 zY7777
 
z::::
 $..=E /   QPPPPP0111
 J:>>>>
 
z::::
 ====
 
z::::
  **S(	 +  N VUUUUUUUn%%%_555
 ==== $%%  W	WCCCCCCOOOOOOOO#&55 88:: 
; 
; * 5 5V$!&) (]B ? ?$.z$:$:$V	 !6 ! ! %$]333<<--9!..H\4J.KKK$((&)9::::..00>EEGG L LF#';;; * 5 5V$!&) (]B ? ?$.z$:$:$V	 !6 ! ! %$]333<<--9!..H\4J.KKKL  	W 	W 	Wh''--.OQUVVVVVVVV	W  **QE	 + 
 
NQLLLLLLn---- Q Q Q(##))*I4PPPPPPPPQ 
z::::
 zY7777
 %//C?	 0   +99?T9UU+66> 7   %%4	 &    @     
) ) ) ) )> $$*:$;;; Z1111
 !++K> ,  O
 *88>O8PP'226@V2WWMJ     R.D     *448 5  O   B !      2D EEE  6Q RRR)442 5  O   4J KKK  l1D !    )33GBW3XXN>	      
1WXXXl1D      ""P #   
 *44MG	 5 	 	O   O !   
   A !    ""71P"QQQ)448 5  O   4J KKK  :U VVV)44Q 5  O   J !      S/T !        l l l l l l\   l 333
 *<@@@@
 j84444
 ====
 
z::::
 :]CCCC
 Z1111
 ====
 #--A .   ""''') #    ""(Q(Q(Q(Q"RRR
 #5   $ Z1111
 j84444
 ZIIII :99999,,..N >38ABB<888 	1#(122,??O  +2*i*H*HSJ##%%&&&cee      "1    N  2"

	6CJ$$_55D&CJJ 
	6 
	6 
	6&CJ x1}} #(J$$_55DDDDDD
	6 $
  11 | D 4    tY%% 

222222KdGT22 z488 z488	  	
 	
 	
 	 t) t|/C
 		- 		-MD' 4&& -dG,,, |	
 	- 	-MD' 4&& -dG,,, tV 		$s   ' 
44A 
AA$A= =
B
	B
 K2 2
L!<LL!-F^ 
_-__"_4 4
`5>-`00`52?x2 2y;=4y66y;__main__r  r{  )r   )F)r  )NFNNNNNFNNFFFNFr@	  )rM   rM   NNN)rM   r  )r  )FN)r  rq  (  r  hermes_bootstrapModuleNotFoundErrorr#   r@   r   r   __annotations__r/   r:   rQ   rB   rJ   rU   r  rY   ri   rz   r}   r  r  rB  r  r?  r=  r*  pathlibr~   typingr   hermes_cli.subcommands._sharedr   _add_accept_hooks_flaghermes_cli.subcommands.cronr   hermes_cli.subcommands.gatewayr   hermes_cli.subcommands.profiler   hermes_cli.subcommands.modelr   hermes_cli.subcommands.setupr   "hermes_cli.subcommands.postinstallr   hermes_cli.subcommands.whatsappr   hermes_cli.subcommands.slackr   hermes_cli.subcommands.loginr   hermes_cli.subcommands.logoutr   hermes_cli.subcommands.authr   hermes_cli.subcommands.statusr   hermes_cli.subcommands.webhookr   hermes_cli.subcommands.hooksr   hermes_cli.subcommands.doctorr   hermes_cli.subcommands.securityr   hermes_cli.subcommands.dumpr   hermes_cli.subcommands.debugr   hermes_cli.subcommands.backupr   !hermes_cli.subcommands.import_cmdr   hermes_cli.subcommands.configr   hermes_cli.subcommands.versionr   hermes_cli.subcommands.updater    hermes_cli.subcommands.uninstallr    hermes_cli.subcommands.dashboardr   hermes_cli.subcommands.guir   hermes_cli.subcommands.logsr   "hermes_cli.subcommands.prompt_sizer   hermes_cli.subcommands.memoryr   hermes_cli.subcommands.acpr   hermes_cli.subcommands.toolsr   hermes_cli.subcommands.insightsr   hermes_cli.subcommands.skillsr   hermes_cli.subcommands.pairingr   hermes_cli.subcommands.pluginsr   hermes_cli.subcommands.mcpr   hermes_cli.subcommands.clawr   r   ru   r   r.  r<  r&   r  r   r  r   r   r   _FORCE_IPV4_EARLYr*   _yaml_early	_cfg_pathr)   r+   r6   r,   _early_cfg_rawr$   r%   _early_sec_cfgr-   r.   _early_redactr1   _early_net_cfgr   r  r   _setup_loggingr  r;   r   r   _apply_ipv4r  r  rg  rf  r  rr   r\   rk   hermes_cli.model_setup_flowsr  r  r  r  r  r  r	  r
  r  r  r  r  r  r  r  r  r  r  r  r  r  r>  r  r%  r9  rB  rD  rI  rQ  rX  r[  rl  r  r  r"  r-  rN  rV  rZ  rh  r  r  ro  r{  r  r  r  r  r  r  r  r  r  r  objectr  r   r  r	  rN  rT  rV  r[  r  r  r  r  r  rw  r  r  r  r  r2  r`  rf  rk  rs  rz  r0  r  r  r  r/  _DEFAULT_QWEN_PORTAL_MODELSr  r  r  r  r  r1  r  r  r  r  r  r#  r'  r,  r:  r=  r@  rD  rH  rL  rP  rV  rZ  r^  rb  ri  rm  rq  rt  rz  r}  r  r  r  r  r  r  r  r%	  r  r  r  r  r  r  r-  r1  rI  rK  rV  r_  rP  r{  r  r  r  r  	Namespacer  ru  r  r  r  r  r
  _warn_stale_dashboard_processesrW  rb  rf  ri  ru  rw  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/  rE  r4  rG  rD  r[  re  rC  rF  rn  r  r  r4  r  r  r  r  r  r  r  r	  r
  r	  r%
  r+
  rH
  rJ
  rW
  rZ
  rf
  r{
  rw
  ry
  r|
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  r
  rr  rI   rC   r   <module>r     s&  * * *r	 	 	 	D	 
			 



% % % %Z )-  , , ,    :6 6- 6 6 6 6 6.   ,     T    8tCy 8T 8 8 8 83:    (	^ 	^ 	^ 	^
t 
 
 
 
 ! "" 
*Q--                      [ Z Z Z Z Z 9 9 9 9 9 9 ? ? ? ? ? ? ? ? ? ? ? ? ; ; ; ; ; ; ; ; ; ; ; ; G G G G G G A A A A A A ; ; ; ; ; ; ; ; ; ; ; ; = = = = = = 9 9 9 9 9 9 = = = = = = ? ? ? ? ? ? ; ; ; ; ; ; = = = = = = A A A A A A 9 9 9 9 9 9 ; ; ; ; ; ; = = = = = = E E E E E E = = = = = = ? ? ? ? ? ? = = = = = = C C C C C C C C C C C C 7 7 7 7 7 7 9 9 9 9 9 9 G G G G G G = = = = = = 7 7 7 7 7 7 ; ; ; ; ; ; A A A A A A = = = = = = ? ? ? ? ? ? ? ? ? ? ? ? 7 7 7 7 7 7 9 9 9 9 9 9s t    $ tH~~$+3355 33|$$ % % %zF zF zF zFz      . - - - - - 4 4 4 4 4 4  |f4 5 5 5 5  	!!M1I T)g... 	="2[2266<"N	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=""*44+//
B??Nz.$// U . 2 23C D D ,:=#m:L:L:R:R:T:TBJ67'++Ir:::nd++ 	%0B0B<0P0P 	% $	 	 	 	D		>>>>>>N tLLCHQRRLLLLbQQ./ / E       	 	 	D	  IIIIII$                   4 4 4 4 4 4 4 4
                                         * 
	8	$	$ S#X(=      C C$J    &*d *sTz * * * *Z
BC 
B 
B 
B 
BG4 G G G G	D 	 	 	 	   $    "Cd C C C C;# ; ; ; ;$od o o o odnT nhsm n n n nb # (3-    ( $      $Z%t Z%t Z% Z% Z% Z%z%s %x} % % % %P (3-     EI9 994<SM9	9 9 9 9x #NF#;<< 	 $    8 49* * *	*,0*
4sCx !* * * *4N N N N N Nb 

  &I;;;  
     D T    680 80 80 80v2 2dTk 2TD[ 2 2 2 2cND cN4 cNE$s)T/4J cN cN cN cNL5f 5c 5 5 5 50,8C= , , , ,^: :S :C : : : :2 (,""!#b b}bb C=b sm	b
 b b d^b b C=b C=b b b b }b b b b bJ   *   (d    2v v vr    ]Y ]Y ]Y@& & &&  , , ,*
) 
) 
)c d    Y' Y' Y' Y'x
 
 
X* * *
DsC}%&    U3S=12    *$ 3    *   
  	
   
   @C    D9" 9" 9" 9"xL@s L@t L@ L@ L@ L@f 	2K 2K
2K2K 2K 	2K
 
2K 2K 2K 2Kj3WC 3W4 3WD 3W 3W 3W 3Wl 129K $ $ $ $ $`  C C Cs CT\]`Ta C C C CL# #    *
/ 
/ 
/ 
/0 0 0 0 NR=Q =Q =Q =QD7B 7B 7BL , K K K    +# +$ + + + +M M M MhP P3 PS P% P P P PjC C    
 
 
 
 
 
*Z Z Z~              >         
 
 
      	 	 	   26 ( ( ($ ($ ( ( ( (V, , ,
  <     @	 sTz    'U4tS4Z3O-P ' ' ' 'T/ / /s /% /TW / / / /d($ (4 ( ( ( (^ !$_L _L _L	c_L	_L 	_L
 _L  _L _L _L _LD4$sCx.4/ 4 4 4 4r #%!%1 1 1	1	1 c3h	1
 1 
c3h$	1  1 1 1 1h 38 v v v4 v4 vD v v v vr:d :t : : : :49 9 9 9 9 9x:T : : : :!&t !&4 !&QU !&Z^ !& !& !& !&HET E4 ED E E E E$:d :x~ : : : :2"tDz " " " "J8T 8d4j 8 8 8 8vFt FS	 F F F FR"C4 "CD "C "C "C "CJ#d #t # # # #Ly'($ y' y' y' y'| %)h h hc(T/h 
#Yh h h hV& & & &R? ? ? ?DS S    * Ot4 t4t4	t4 t4 t4 t4r #B @& @& @&F+DI +D +Xc] + + + +\#Y!.1c]   $ 59
 

$,SM
	
 
 
 
& i i#Yi	i i 	i 
i i i iX-#Y-	- - 
	- - - -h    G 3 T#Y T hsm     # 4    "$s) $ 4    $s) $ 4    DI D  3 SV     Dd D D D D  d3i d t    "qX49 qX4 qXD qX qX qX qXh  8 S T#Y    H/T / / / /J J J JJ J J J   J "&&(	$ $ $	c$ 
c3h$	$ !$	$
 
$ $ $ $N#T # # # #14$; 1 1 1 14 DJ      59r r rr'*Tzr	%S/r r r rj%S/"15   6 /0d d dd(+d	%d

d d d dN d  t          FT%d
*;%<      "&#	  	c 
c3h$	 	
 
   D 4$; $    .AH AH AH AHN "&	=R =R =RS	=R 
c3h$	=R 	=R
 
=R =R =R =RF "&	tD tD tDS	tD 
c3h$	tD 	tD
 
tD tD tD tDnS	(,S#X(=	D[   8/ /S#X- / / / / /%D % % % % "&!
 !
 !
S	!
 
c3h$	!
 
	!
 !
 !
 !
H.49 .t . . . .044 44 44 44nF- F- F- F- F- F- F- F-RN NT N N N Nb  ,GC G G G GAEu AE AE AEc AE AE AE AE AEHVQ VQ VQ VQr] ] ] ]@" " "J/2 /2 /2d:I :I :Iz] ] ] ] ]@+Kd Kt K K K K\| | |~;
 ;
 ;
 ;
|"# " " " "Js # $    x x xv  
% 
% 
% 
%    8 !y    8 #    " d
        Fd    * .--eV_-!E7+7)$  T T T T T    0D 0 0 0 0@
 @
 @
 @
F) ) ) )FT F F F FR&T & & & &R< < <~  .  "1 1 1
 
 
        [ [ [|  zDFFFFF sg   
 2L ?IL I""L %I"&B%L LL9M MM M3 3M;:M;