
    jh1                       d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ  ej0                  e      Z ee      j8                  j8                  j;                         Zd	Zd
ee ef   dee ef   fdZ!d
ee ef   dee e f   fdZ"d
ee ef   de de ddfdZ#de de$fdZ%dgg dg dg dg dg dddgg dg dg dg dg dg dg dg dd Z&d
ee ef   de fd!Z'd
ee ef   d"e ddfd#Z(dd$l)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 dd%l5m6Z6m7Z7 d&e fd'Z8dd(l9m:Z:m;Z;m<Z<m=Z= g d)Z>d*e de fd+Z?e:Z@e;ZAe<ZBe=ZCd, Z:d- Z;d. Z<d/ Z=de$fd0ZDdd1e dz  ddfd2ZEdd4e d5e d6e$de fd7ZF ej                  d8      ZHd9e de fd:ZIdd4e d;eJd5eKd<e dz  deKf
d=ZLdd4e d;eJd5eKd<e dz  deKf
d>ZMdd4e d5e$de$fd?ZNdd&e d@eJdAeJdeJfdBZOdCePfdDZQd
ePfdEZRd
ePfdFZSd
ePfdGZTddHedz  dePe e f   fdIZUd3dJd
ePdKe$fdLZVde$fdMZWde$fdNZXde$fdOZYd
ePfdPZZd
ePfdQZ[d
ePfdRZ\d
ePfdSZ]d
ePfdTZ^dU Z_dV Z`dWe deJfdXZadY ZbdZ Zcd[ Zdd\ Zed] Zfd^ Zgd_ Zhd
ePfd`Zidd
ePdae$fdbZjd
ePde$fdcZkdde de fdeZld
ePdfe dee    fdgZmd
ePdfe dde de$fdhZn eediz        djz  dkz  dlz  dmz  Zodn Zpdodpdqdrdsdtdudvdwdx	ZqdyePfdzZrd{ede$fd|Zsd}d~eVfdde[fdde\fddeifddejfdde^fgZtd Zud
ePde$fdZvd
ePfdZwy)u  
Interactive setup wizard for Hermes Agent.

Modular wizard with independently-runnable sections:
  1. Model & Provider — choose your AI provider and model
  2. Terminal Backend — where your agent runs commands
  3. Agent Settings — iterations, compression, session reset
  4. Messaging Platforms — connect Telegram, Discord, etc.
  5. Tools — configure TTS, web search, image generation, etc.

Config files are stored in ~/.hermes/ for easy access.
    N)Path)OptionalDictAny)get_nous_subscription_features)managed_nous_tools_enabled)base_url_hostname)get_optional_skills_dirz*https://hermes-agent.nousresearch.com/docsconfigreturnc                     | j                  d      }t        |t              rt        |      S t        |t              r"|j	                         rd|j	                         iS i S )Nmodeldefault)get
isinstancedictstrstrip)r   current_models     5/home/ubuntu/.hermes/hermes-agent/hermes_cli/setup.py_model_config_dictr   %   sS    JJw'M-&M""-%-*=*=*?=..011I    c                 ^    | j                  d      }t        |t              rt        |      S i S Ncredential_pool_strategiesr   r   r   )r   
strategiess     r   _get_credential_pool_strategiesr   .   s*    89J)*d;4
CCr   providerstrategyc                 4    |sy t        |       }|||<   || d<   y r   )r   )r   r   r    r   s       r   _set_credential_pool_strategyr"   3   s'    08J#Jx+5F'(r   c                 n    | r| dk(  ry| dk(  ryddl m} |j                  |       }|sy|j                  dv S )NcustomF
openrouterTr   PROVIDER_REGISTRY>   api_keyoauth_device_code)hermes_cli.authr'   r   	auth_type)r   r'   pconfigs      r   "_supports_same_provider_pool_setupr-   ;   sE    x8+<1##H-G @@@r   copilot-acp)gpt-5.4zgpt-5.4-miniz
gpt-5-minigpt-5.3-codexzgpt-5.2-codexgpt-4.1gpt-4ogpt-4o-minizclaude-opus-4.6zclaude-sonnet-4.6zclaude-sonnet-4.5zclaude-haiku-4.5zgemini-2.5-pro)zgemini-3.1-pro-previewzgemini-3-pro-previewzgemini-3-flash-previewzgemini-3.1-flash-lite-preview)glm-5.1glm-5zglm-4.7zglm-4.5zglm-4.5-flash)	kimi-k2.6	kimi-k2.5zkimi-k2-thinkingzkimi-k2-turbo-previewzstep-3.5-flashzstep-3.5-flash-2603)ztrinity-large-thinkingztrinity-large-previewztrinity-mini)zMiniMax-M2.7zMiniMax-M2.5zMiniMax-M2.1z
MiniMax-M2)anthropic/claude-opus-4.6anthropic/claude-sonnet-4.6zopenai/gpt-5zgoogle/gemini-3-flash)r8   r9   zopenai/gpt-5.4zgoogle/gemini-3-pro-previewzgoogle/gemini-3-flash-preview)r/   r0   zclaude-sonnet-4-6zgemini-3-flashr5   r7   minimax-m2.7)r6   r7   r4   r5   zmimo-v2.5-proz	mimo-v2.5zmimo-v2-prozmimo-v2-omnir:   zminimax-m2.5zqwen3.6-pluszqwen3.5-plus)zQwen/Qwen3.5-397B-A17Bz"Qwen/Qwen3-235B-A22B-Thinking-2507z#Qwen/Qwen3-Coder-480B-A35B-Instructzdeepseek-ai/DeepSeek-R1-0528zdeepseek-ai/DeepSeek-V3.2zmoonshotai/Kimi-K2.5)r.   copilotgeminizaikimi-codingkimi-coding-cnstepfunarceeminimax
minimax-cn
ai-gatewaykilocodezopencode-zenzopencode-gohuggingfacec                     | j                  d      }t        |t              r:t        |j                  d      xs d      j	                         j                         S y)Nagentreasoning_effort )r   r   r   r   r   lower)r   	agent_cfgs     r   _current_reasoning_effortrM   t   sI    

7#I)T"9==!34:;AACIIKKr   effortc                 ^    | j                  d      }t        |t              si }|| d<   ||d<   y )NrH   rI   r   )r   rN   rL   s      r   _set_reasoning_effortrP   {   s3    

7#Ii&	#w$*I !r   )cfg_getDEFAULT_CONFIGget_hermes_homeget_config_pathget_env_pathload_configsave_configsave_env_valueremove_env_valueget_env_valueensure_hermes_home)Colorscolortitlec                     t                t        t        d|  t        j                  t        j                               y)zPrint a section header.u   ◆ N)printr]   r\   CYANBOLD)r^   s    r   print_headerrc      s&    	G	%$ugV[[
9:r   )print_error
print_infoprint_successprint_warning))u%   Hermes Setup — Non-interactive modeu*   Hermes 配置向导 —— 非交互模式)z+The interactive wizard cannot be used here.0   当前环境无法使用交互式配置向导。)z@Configure Hermes using environment variables or config commands:=   你可以通过环境变量或配置命令来设置 Hermes：)z?Or set OPENROUTER_API_KEY / OPENAI_API_KEY in your environment.E   或者在环境变量中设置 OPENROUTER_API_KEY / OPENAI_API_KEY。)zERun 'hermes setup' in an interactive terminal to use the full wizard.B   如需完整向导，请在交互式终端中运行：hermes setup)  Skipped (keeping current)u#     已跳过（保留当前设置）)z  Enter for defaultu     直接回车使用默认项)zCtrl+C to exitu   Ctrl+C 退出)z
  Select [u     请选择 [)zPlease enter a number betweenu!   请输入一个数字，范围：)Please enter a numberu   请输入数字)Please enter 'y' or 'n'u   请输入 y 或 n)zLaunch hermes chat now?u&   现在立即启动 hermes 聊天吗？)7Connect a messaging platform? (Telegram, Discord, etc.)u:   现在连接消息平台吗？（Telegram、Discord 等）)"Set up messaging now (recommended)u$   现在配置消息平台（推荐）)1   Skip — set up later with 'hermes setup gateway'u9   先跳过，之后可通过 'hermes setup gateway' 配置textc                 n    t        | t              s| S | }t        D ]  \  }}|j                  ||      } |S N)r   r   _SETUP_TRANSLATIONSreplace)rr   
translatedoldnews       r   _translate_setup_textrz      sA    dC J' 2S''S1
2r   c                 ,    t        t        |              y rt   )_orig_print_errorrz   messages    r   rd   rd      s    +G45r   c                 ,    t        t        |              y rt   )_orig_print_inforz   r}   s    r   re   re      s    *734r   c                 ,    t        t        |              y rt   )_orig_print_successrz   r}   s    r   rf   rf          -g67r   c                 ,    t        t        |              y rt   )_orig_print_warningrz   r}   s    r   rg   rg      r   r   c                  |    t        t        dd      } | y	 t        | j                               S # t        $ r Y yw xY w)z;Return True when stdin looks like a usable interactive TTY.stdinNF)getattrsysboolisatty	Exception)r   s    r   is_interactive_stdinr      s@    C$'E}ELLN## s   / 	;;reasonc                    t                t        t        dt        j                  t        j                               t                | rt        |        t        d       t                t        d       t        d       t        d       t        d       t                t        d       t        d       t                y	)
z8Print guidance for headless/non-interactive setup flows.u.   ⚕ Hermes 配置向导 —— 非交互模式rh   ri   z)  hermes config set model.provider customz;  hermes config set model.base_url http://localhost:8080/v1z1  hermes config set model.default your-model-namerj   rk   N)r`   r]   r\   ra   rb   re   )r   s    r   #print_noninteractive_setup_guidancer      s    	G	%@&++v{{
[\	G6AB	GNO:;LMBC	GVWST	Gr   Fquestionr   passwordc                    t        |       } |r	|  d| d}n|  d}	 |r.ddl}|j                  t        |t        j                              }n#t        t        |t        j                              }t        |      }|j                         xs |xs dS # t        t        f$ r" t                t        j                  d       Y yw xY w)z'Prompt for input with optional default. []: : r   NrJ      )rz   getpassr]   r\   YELLOWinput_sanitize_pasted_inputr   KeyboardInterruptEOFErrorr`   r   exit)r   r   r   displayr   valuecleaneds          r   promptr      s    $X.HJb	-Jb/OOE'6==$ABE%78E(/}}/'/R/x( s   A5B .CCz\x1b\[\s*200~|\x1b\[\s*201~r   c                 V    t        | t              r| s| S t        j                  d|       S )z@Strip terminal bracketed-paste control markers from pasted text.rJ   )r   r   _BRACKETED_PASTE_PATTERNsub)r   s    r   r   r   
  s&    eS!#''E22r   choicesdescriptionc                 (    ddl m}  || ||d|      S )z?Single-select menu using curses. Delegates to curses_radiolist.r   )curses_radiolist)selectedcancel_returnsr   )hermes_cli.curses_uir   )r   r   r   r   r   s        r   _curses_prompt_choicer     s    5HgPR`kllr   c           	          t        | |||      }|dk\  r(||k(  rt        d       t                |S t                |S t        t        | t        j
                               t        |      D ]N  \  }}||k(  rdnd}||k(  r*t        t        d| d| t        j                               >t        d| d|        P t        d|d	z    d
       	 	 t        t        dt        |       d|d	z    dt        j                              }|s|S t        |      d	z
  }d|cxk  rt        |      k  r|S  t        dt        |              x# t        $ r t        d       Y t        t        f$ r" t                t!        j"                  d	       Y Fw xY w)zPrompt for a choice from a list with arrow key navigation.

    Escape keeps the current default (skips the question).
    Ctrl+C exits the wizard.
    )r   r   rl   u   ●u   ○   z  Enter for default (r   z)  Ctrl+C to exitz  Select [1-z] (z): z$Please enter a number between 1 and rm   )r   re   r`   r]   r\   r   	enumerateGREENr   lenDIMintrd   
ValueErrorr   r   r   r   )	r   r   r   r   idxichoicemarkerr   s	            r   prompt_choicer     s     '7
TC
ax'>45GN
	%&--
()w' *	6w,E<%"VHAfX.=>Bvhax()* &w{m3DEF
	S\N#gk]#F

SE e*q.CC&#g,&
 '>s7|nMN   	1/0!8, 	GHHQK	s$   9E 
#E .E F-FFc                 N   t        |       } |rdnd}	 	 t        t        |  d| dt        j                              j                         j                         }s|S |dv ry|dv ry	t        d
       `# t        t        f$ r" t                t        j                  d       Y Jw xY w)z=Prompt for yes/no. Ctrl+C exits, empty input returns default.u   Y/n（回车默认是）u   y/N（回车默认否）Tr   r   r   >   yyes>   nnoFrn   )rz   r   r]   r\   r   r   rK   r   r   r`   r   r   rd   )r   r   default_strr   s       r   prompt_yes_nor   C  s    $X.H07,=WK
	exj;-s;V]]KL  NL K-.#  "8, 	GHHQK	s   AA3 3.B$#B$itemspre_selectedc                 h    |g }ddl m}  || |t        |      t        |            }t        |      S )u  
    Display a multi-select checklist and return the indices of selected items.

    Each item in `items` is a display string. `pre_selected` is a list of
    indices that should be checked by default. A "Continue →" option is
    appended at the end — the user toggles items with Space and confirms
    with Enter on "Continue →".

    Falls back to a numbered toggle interface when simple_term_menu is
    unavailable.

    Returns:
        List of selected indices (not including the Continue option).
    r   )curses_checklist)r   )r   r   setsorted)r^   r   r   r   chosens        r   prompt_checklistr   \  s>     5L<(	F &>r   varc           
         | j                  dg       }dj                  |dd       }t        |      dkD  r|dt        |      dz
   dz  }t                t        t	        d| j                  d| d	          d
t
        j                               t                |rt        d|        | j                  d      rt        d| d           t                | j                  d      r$t        d| j                  d| d	          d      }n!t        d| j                  d| d	                }|rt        | d	   |       t        d       yt        d       y)zEDisplay a nicely formatted API key input screen for a single env var.tools, N   z, +z more     ─── r   name
    ───z  Enables: urlz  Get your key at: r   r   r   Tr        ✓ Savedz/  Skipped (configure later with 'hermes setup'))r   joinr   r`   r]   r\   ra   re   r   rX   rf   rg   )r   r   	tools_strr   s       r   _prompt_api_keyr   y  s.   GGGR E		%)$I
5zA~s3u:>*%00		G	%,sww}c&kBC:NPVP[P[
\]	G[,-
wwu~(U56	G
wwzCGGHc&k:;<tLCGGHc&k:;<=s6{E*m$GHr   c                    t                t        d       g }t        |       }	 ddlm}  |       }|r|j                  d       n|j                  d       t        d      r|j                  d       n|j                  d       |j                  j                  r|j                  d	       nn|j                  j                  rGd
}|j                  j                  rd|j                  j                   d}|j                  |ddf       n|j                  d       |j                  j                  }|j                  j                  r|j                  d       nj|j                  j                  rd}|rd| d}|j                  |ddf       n5d}|dk(  rd}n|dk(  rd}n|dk(  rd}n|dk(  rd}|j                  dd|f       |j                  j                  r|j                  d       n|j                  j                  r|j                  d       n}d}		 ddlm}
 dd lm}  |         |
       D ]1  }|j$                  d!k(  r	 |j'                         r|j(                  }	 n3 |	r|j                  d"|	 dddf       n|j                  d#       	 ddlm} dd lm}  |        d} |       D ]!  }	 |j'                         r|j(                  } n# |r|j                  d$| dddf       t-        | d%d&d'(      }|j.                  j                  r|j                  d)       ni|d*k(  rt        d+      r|j                  d,       nF|d-k(  r)t        d.      st        d/      r|j                  d0       n|d1k(  rt        d2      r|j                  d3       n|d4k(  rt        d5      r|j                  d6       n|d7k(  r(t        d8      st        d9      r|j                  d:       n|d;k(  rD	 j0                  j3                  d;      du}|r|j                  d<       np|j                  d=       n^|d>k(  rH	 ddl}|j0                  j3                  d>      du}|r|j                  d?       n#|j                  d@       n|j                  dA       |j6                  j                  r|j                  dB       nqt-        | dCdD      dEk(  r:|j6                  j8                  r|j                  dF       n9|j                  dG       n't;               r|j<                  r|j                  dH       t        dI      rt        dJ      r|j                  dK       n.t        dI      r|j                  dL       n|j                  dM       t        dN      r|j                  dO       	 ddPlm }  |dQ      xs i }|jC                  dR      s|jC                  dS      r|j                  dT       t        dU      r|j                  dV       n|j                  dW       |j                  dX       |j                  dY       |j                  dZ       tE        d[ |D              }tG        |      }tI        | d\| d]       t                |D ]z  \  }}}|r*t        d^tK        d_tL        jN                         d`|        3t        d^tK        datL        jP                         d`| d`tK        db| dtL        jR                                | t                |D cg c]  \  }}}|r
||f }}}}|r/tU        dc       dddl+m,} tU        de |        df       t                t                t        tK        dgtL        jN                               t        tK        dhtL        jN                               t        tK        ditL        jN                               t                dddl+m,} t        tK        dj |        dktL        jZ                  tL        j\                               t                t        d^tK        dltL        j^                         dmta                       t        d^tK        dntL        j^                         dmtc                       t        d^tK        dotL        j^                         dp| dq       t                t        tK        drtL        jR                               t                t        tK        dstL        jZ                  tL        j\                               t                t        d^tK        dttL        jN                         du       t        d^tK        dvtL        jN                         dw       t        d^tK        dxtL        jN                         dy       t        d^tK        dztL        jN                         d{       t        d^tK        d|tL        jN                         d}       t                t        d^tK        d~tL        jN                         d       t        d^tK        dtL        jN                         d       t        d^tK        dtL        jN                                t        d       t                t        d       t        d^tK        dta                tL        jR                                t        d^tK        dtc                tL        jR                                t                t        tK        drtL        jR                               t                t        tK        dtL        jZ                  tL        j\                               t                t        d^tK        dtL        jN                         d       t        d^tK        dtL        jN                         d       t        d^tK        dtL        jN                         d       t                y# t
        $ r g }Y w xY w# t
        $ r Y 	w xY w# t
        $ r Y 	w xY w# t
        $ r Y 	Zw xY w# t
        $ r d}Y 	Hw xY w# t
        $ r d}Y #w xY w# t
        $ r d}Y w xY w# t
        $ r Y pw xY wc c}}}w )z#Print the setup completion summary.zTool Availability Summaryr   get_available_vision_backends)Vision (image analysis)TN)r   Fzrun 'hermes setup' to configureOPENROUTER_API_KEY)Mixture of AgentsTN)r   Fr   )z(Web Search & Extract (Nous subscription)TNWeb Search & ExtractzWeb Search & Extract ()TN)r   FzbEXA_API_KEY, PARALLEL_API_KEY, FIRECRAWL_API_KEY/FIRECRAWL_API_URL, TAVILY_API_KEY, or SEARXNG_URL)z%Browser Automation (Nous Browser Use)TNzBrowser AutomationzBrowser Automation (zVnpm install -g agent-browser, set CAMOFOX_URL, or configure Browser Use or BrowserbaseBrowserbasezOnpm install -g agent-browser and set BROWSERBASE_API_KEY/BROWSERBASE_PROJECT_IDzBrowser Usez8npm install -g agent-browser and set BROWSER_USE_API_KEYCamofoxCAMOFOX_URLzLocal browserznpm install -g agent-browserF)z$Image Generation (Nous subscription)TN)Image GenerationTN)list_providers)_ensure_plugins_discoveredfalzImage Generation ()r   FzFAL_KEY or OPENAI_API_KEYzVideo Generation (ttsr   edger   )z-Text-to-Speech (OpenAI via Nous subscription)TN
elevenlabsELEVENLABS_API_KEY)zText-to-Speech (ElevenLabs)TNopenaiVOICE_TOOLS_OPENAI_KEYOPENAI_API_KEY)zText-to-Speech (OpenAI)TNrB   MINIMAX_API_KEY)zText-to-Speech (MiniMax)TNmistralMISTRAL_API_KEY)z Text-to-Speech (Mistral Voxtral)TNr<   GEMINI_API_KEYGOOGLE_API_KEY)zText-to-Speech (Google Gemini)TNneutts)zText-to-Speech (NeuTTS local)TN)u)   Text-to-Speech (NeuTTS — not installed)Frun 'hermes setup tts'	kittentts)z Text-to-Speech (KittenTTS local)TN)u,   Text-to-Speech (KittenTTS — not installed)Fr   )zText-to-Speech (Edge TTS)TN)z#Modal Execution (Nous subscription)TNterminalbackendmodal)zModal Execution (direct Modal)TN)zModal ExecutionFzrun 'hermes setup terminal')z0Modal Execution (optional via Nous subscription)TNTINKER_API_KEYWANDB_API_KEY)RL Training (Tinker)TN)r   Fr   )r   Fr   
HASS_TOKEN)zSmart Home (Home Assistant)TN)get_provider_auth_statespotifyaccess_tokenrefresh_token)zSpotify (PKCE OAuth)TNGITHUB_TOKEN)Skills Hub (GitHub)TN)r  Fr  )zTerminal/CommandsTN)zTask Planning (todo)TN)zSkills (view, create, edit)TNc              3   .   K   | ]  \  }}}|s
d   yw)r   N ).0_avails      r   	<genexpr>z'_print_setup_summary.<locals>.<genexpr>`  s     D5!e!Ds   /z tool categories available:z   u   ✓r   u   ✗z	(missing zDSome tools are disabled. Run 'hermes setup tools' to configure them,display_hermes_homezor edit z+/.env directly to add the missing API keys.   ┌─────────────────────────────────────────────────────────┐uA   │              ✓ Setup Complete!                          │   └─────────────────────────────────────────────────────────┘u   📁 All your files are in z/:z	Settings:r   z	API Keys:zData:      z/cron/, sessions/, logs/u   ────────────────────────────────────────────────────────────u    📝 To edit your configuration:zhermes setupz           Re-run the full wizardzhermes setup modelz    Change model/providerzhermes setup terminalz Change terminal backendzhermes setup gatewayz  Configure messagingzhermes setup toolsz    Configure tool providerszhermes configz         View current settingszhermes config editz    Open config in your editorzhermes config set <key> <value>z.                          Set a specific valuez   Or edit the files directly:znano u   🚀 Ready to go!hermesz              Start chattingzhermes gatewayz      Start messaging gatewayzhermes doctorz       Check for issues)2r`   rc   r   agent.auxiliary_clientr   r   appendrZ   webmanaged_by_nous	availablecurrent_providerbrowser	image_genagent.image_gen_registryr   hermes_cli.pluginsr   r   is_availabledisplay_nameagent.video_gen_registryrQ   r   util	find_specimportlib.utilr   direct_overrider   nous_auth_presentr*   r   r   sumr   re   r]   r\   r   REDr   rg   hermes_constantsr  ra   rb   r   rT   rU   ) r   hermes_hometool_statussubscription_featuresr   _vision_backendslabelbrowser_providermissing_browser_hint_img_backendr   r   _p_list_video_providers_ensure_plugins_video_backend_vptts_provider	importlib	neutts_okkittentts_okr   _spotify_stateavailable_counttotal_countr   r  missing_varr
  r   disabled_tools_dhhs                                    r   _print_setup_summaryr?    s    
G,-K:6BH8: BC`a )*<=MN   00ST		"	"	,	,& $$55,-B-F-F-W-W,XXYZEE4./  a  	b -44EE$$44PQ		&	&	0	0$*+;*<A>EE4./w},= ! .J ! *#0 0#A !5*>?	
 &&66OP		(	(	2	2;< 	?E&($& 77e#(') )	 "4\N! DdDQRWX
TT(* 	C##%%(%5%5N &	 00@BD$OP 65*fEL  00XY		%-8L*MFG		!./=AQ3RBC		"}5F'GCD		"}5F'GKL		!}5E'F-XhJiIJ		!	!00:$FI LMmn		$	!!$>>33K@LL OPpqDE""22NO	Y	/7	: &&66MNXY	#	%*?*Q*Q[\ %&=+I?@	'	(KLLM \"FG;0;Arn-1C1CO1TCD
 ^$>?IJ 89 ;< BC D{DDOk"K/"!K=0KLM	G(3 $iCeV\\231TF;<eE6::./qa	+VW>XZ`ZdZd8e7fg	 
G:ESS&6dE3UtSkSNSR	
 	A(STU 
G	 @  BH  BN  BN	

 
OQWQ]Q]	

 
 @  BH  BN  BN	

 
G =	%-dfXR8&++v{{
ST	G	Ck6==12"_5F4G
HI	Ck6==12"\^4D
EF	
eGV]]+,F;-?WX 
G	%
FJJ
'(	G	%2FKK
MN	G	Cnfll344T
UV	C*FLL9::S
TU	C-v||<==U
VW	C,fll;<<Q
RS	C*FLL9::V
WX	G	Cov||455S
TU	
e(&,,788VW 
C7FG
HI	
:;	G	
*+	Co/016::>?
@A	Cln-.

;<
=>	G	%
FJJ
'(	G	%#V[[&++
>?	G	Ch-..J
KL	C&566S
TU	Cov||455L
MN	Gc  V !  		(   0  	I	  	! L	!J  F Ts   o -o* oo* p
 0o:p
 *p 3!p. Aq  qqoo	o'#o* &o''o* *	o76o7:	pp
 pp
 
ppp+*p+.p=<p= 	qqc                    | j                  di       }t                t        d       |j                  dd      }|rdnd}t        d       t        d       t	        d	|      }|j                         d
v |d<   |j                  dd      }t	        dt        |            }	 t        |      |d<   |j                  dd      }t	        dt        |            }	 t        |      |d<   |j                  dd      }	t	        dt        |	            }
	 t        |
      |d<   y# t        $ r Y xw xY w# t        $ r Y Qw xY w# t        $ r Y yw xY w)zMPrompt for container resource settings (Docker, Singularity, Modal, Daytona).r   zContainer Resource Settings:container_persistentTr   r   z5  Persistent filesystem keeps files between sessions.z;  Set to 'no' for ephemeral sandboxes that reset each time.z.  Persist filesystem across sessions? (yes/no)>   1r   r   truecontainer_cpur     CPU corescontainer_memory     Memory in MB (5120 = 5GB)container_disk   z  Disk in MB (51200 = 50GB)N)

setdefaultr`   re   r   r   rK   r   floatr   r   )r   r   current_persistpersist_labelpersist_strcurrent_cpucpu_strcurrent_memmem_strcurrent_diskdisk_strs              r   _prompt_container_resourcesrV    s]     R0H	G-. ll#94@O,E$MFGLM8-K (3'8'8':>W'WH#$ ,,2K]C$45G$)'N!
 ,,148K2C4DEG'*7|#$
 << 0%8L3S5FGH%(]!"      s6   D D) D8 	D&%D&)	D54D58	EEc                    | j                  di       }t                t        d       t        d       t        d       ddlm} |j                  d      xs d}d	j                  |      }t        d
| d|      j                         xs |}||vrt        d| d| d       ||v r|nd}||d<   t        d|       |j                  dd      }|rdnd}t        d|      j                         dv |d<   |j                  dd      }t        dt        |            }		 t        |	      |d<   |j                  dd      }
t        dt        |
            }	 t        |      |d<   |j                  dd      dvrt        d       d|d<   t                t        d        t        d!       t!               }|rt        d"       t#        d#       t        d$t%        d%      xs d&d'      }t        d(t%        d)      xs |j                  d*d&            }t        d+t%        d,      xs |j                  d-d&            }|rt        d%|       |rt        d)|       |rt        d,|       y.y.# t        $ r Y Aw xY w# t        $ r Y w xY w)/zLPrompt for Vercel Sandbox settings without exposing unsupported disk sizing.r   zVercel Sandbox settings:z/  Filesystem persistence uses Vercel snapshots.zX  Snapshots restore files only; live processes do not continue after sandbox recreation.r   )_SUPPORTED_VERCEL_RUNTIMESvercel_runtimenode24r   z  Runtime (r   zUnsupported Vercel runtime 'z', keeping .TERMINAL_VERCEL_RUNTIMErA  Tr   r   z-  Persist filesystem with snapshots? (yes/no)>   rB  r   r   rC  rD  r   rE  rF  rG  rH  rI  rJ  >   r   rJ  zVVercel Sandbox does not support custom disk sizing; resetting container_disk to 51200.zVercel authentication:z=  Use a long-lived Vercel access token plus project/team IDs.z1  Found defaults in nearest .vercel/project.json.VERCEL_OIDC_TOKENz    Vercel access tokenVERCEL_TOKENrJ   r   z    Vercel project IDVERCEL_PROJECT_ID	projectIdz    Vercel team IDVERCEL_TEAM_IDorgIdN)rK  r`   re   tools.terminal_toolrX  r   r   r   r   rg   rX   rK   r   rL  r   r   _read_nearest_vercel_projectrY   rZ   )r   r   rX  current_runtimesupported_labelruntimerM  rN  rP  rQ  rR  rS  linked_projecttokenprojectteams                   r   _prompt_vercel_sandbox_settingsrl    s     R0H	G)*@Aij>ll#34@Oii :;O{?"315GMMObSbG004WI[HYYZ[\%48R%R/X`!(H,g6ll#94@O,E$M'-7(eg*(+H#$ ,,2K]C$45G$)'N! ,,148K2C4DEG'*7|#$ ||$e,J>no!&H	G'(NO13NFG(),mN.K.Qr\`aE)*Qn.@.@b.QG &'J>+=+=gr+JD ~u-*G4'. G    s$   I I- 	I*)I*-	I:9I:startc           	      x   | xs t        j                         j                         }|j                         r|j                  }|g|j
                  D ]  }|dz  dz  }|j                         s	 t        j                  |j                  d            }t        |t              si c S |j                  d      |j                  d      dj                         D ci c](  \  }}t        |t               r|j#                         r||* c}}c S  i S # t        t        j                  f$ r i cY c S w xY wc c}}w )z=Read project/team defaults from the nearest Vercel link file.z.vercelzproject.jsonutf-8encodingr`  rb  )r`  rb  )r   cwdresolveis_fileparentparentsexistsjsonloads	read_textOSErrorJSONDecodeErrorr   r   r   r   r   r   )rm  current	directoryproject_filedatakeyr   s          r   rd  rd  &  s!   "
++-G..00 
	 9,~=""$	::l44g4FGD $%I "XXk2'* eg
U %%%++- J
 	

$ I --. 	I	
s   0%D-D6D32D3quickr  c                d
   ddl m}m} t        d       t	        d       t	        dt
         d       t                ddlm} 	  |         |       }|j                  d| j                  d            | d<   d|v r	|d   | d<   n| j!                  dd       d}| j                  d      }t#        |t$              r|j                  d      }|st'        |      r	 ddlm}	 ddlm}
 ddlm}  |
|      }|j5                         }t7        |      }t9        d |D              }||z
  }t                t        d       t	        d       t	        d       t	        d       t                |dkD  rt	        d| d| d| d| d	       nt	        d| d|        t;        dd      rX | |	|ddddddddd ddd!"              |
|      }t7        |j5                               }t	        d#| d$       t;        dd      rX|d%kD  rgg d&}t=        |       j                  |d'      }dd%d(d)j                  |d      }t?        d*||      }g d)|   }tA        | ||       tC        d+| d,|        |rd}n)	 dd.l"m#} tI         |             }tK        |       }||v rd}|rd/d0d1d2d3d4d5d6d7d8d9d:d;}|j                  ||xs d<      }t                t        d=       t	        d>|        t	        d?       t	        d@       t                g dA}t?        dB|d(      }|dk(  rCtM        dCdDE      jO                         }|rtQ        dF|       tC        dG       nt	        dH       n|d%k(  rtM        dI      jO                         xs dJ}dK}tS        |      dLk(  } | rdM}tM        |dDE      jO                         }!|!rtQ        dN|!       | jU                  dOi       jU                  dPi       }"||"dQ<   | r-g dR}#|#dSgz   }$t?        dT|$d      }%|%t7        |#      k  r|#|%   ndU}&ntM        dV      jO                         }&|&rtQ        dW|&       tC        dX| |&rd|& dYndz          nt	        dH       nt	        dZ        ||        |s|d[k7  rtW        |        yyy# t        t        f$ r t                t	        d       Y \t        $ r:}t        j                  d	|       t        d
|        t	        d       Y d}~d}~ww xY w# t        $ r!}t        j                  d-|       Y d}~d}~ww xY w# t        $ r tI               }Y w xY w)\u  Configure the inference provider and default model.

    Delegates to ``cmd_model()`` (the same flow used by ``hermes model``)
    for provider selection, credential prompting, and model picking.
    This ensures a single code path for all provider setup — any new
    provider added to ``hermes model`` is automatically available here.

    When *quick* is True, skips credential rotation, vision, and TTS
    configuration — used by the streamlined first-time quick setup.
    r   )rV   rW   zInference Providerz.Choose how to connect to your main chat model.
   Guide: z/integrations/providers)select_provider_and_modelzProvider setup skipped.z0select_provider_and_model error during setup: %sz%Provider setup encountered an error: z*You can try again later with: hermes modelNr   custom_providersr   )SimpleNamespace)	load_pool)auth_add_commandc              3   l   K   | ],  }t        t        |d d            j                  d      s)d . yw)sourcerJ   manualr   N)r   r   
startswith)r  entrys     r   r  z'setup_model_provider.<locals>.<genexpr>  s-     pUWUHVX=Y9Z9e9efn9oqps   *44z!Same-Provider Fallback & RotationzHHermes can keep multiple credentials for one provider and rotate betweenzCthem when a credential is exhausted or rate-limited. This preserveszEyour primary provider while reducing interruptions from quota issues.zCurrent pooled credentials for r   z (z	 manual, z$ auto-detected from env/shared auth)z2Add another credential for same-provider fallback?FrJ   g      .@,  )r   r+   r,  r(   
portal_urlinference_url	client_idscope
no_browsertimeoutinsecure	ca_bundlemin_key_ttl_secondszProvider pool now has z credential(s).r   )uU   Fill-first / sticky — keep using the first healthy credential until it is exhausteduJ   Round robin — rotate to the next healthy credential after each selectionu5   Random — pick a random healthy credential each time
fill_first   )r  round_robinrandomz'Select same-provider rotation strategy:zSaved z rotation strategy: z7Could not configure same-provider fallback in setup: %sr   zNous Portal API keyzGitHub CopilotzGitHub Copilot ACPz
Z.AI / GLMzKimi / MoonshotzKimi / Moonshot (China)zStepFun Step PlanMiniMaxz
MiniMax CN	AnthropiczVercel AI Gatewayzyour custom endpoint)znous-apir;   r.   r=   r>   r?   r@   rB   rC   	anthropicrD   r$   zyour providerz"Vision & Image Analysis (optional)z+Vision uses a separate multimodal backend. z=doesn't currently provide one Hermes can auto-use for vision,z4so choose a backend now or skip and configure later.)u<   OpenRouter — uses Gemini (free tier at openrouter.ai/keys)uB   OpenAI-compatible endpoint — base URL, API key, and vision modelzSkip for nowzConfigure vision:z  OpenRouter API keyTr   r   u/   OpenRouter key saved — vision will use Geminiu%   Skipped — vision won't be availablez  Base URL (blank for OpenAI)zhttps://api.openai.com/v1z	  API keyzapi.openai.comz  OpenAI API keyr   	auxiliaryvisionbase_url)r2   r3   r1   zgpt-4.1-minizgpt-4.1-nanozUse default (gpt-4o-mini)zSelect vision model:r3   z0  Vision model (blank = use main/custom default)AUXILIARY_VISION_MODELzVision configured with r   uR   Skipped — add later with 'hermes setup' or configure AUXILIARY_VISION_* settingsnous),hermes_cli.configrV   rW   rc   re   
_DOCS_BASEr`   hermes_cli.mainr  
SystemExitr   r   loggerdebugrg   r   popr   r   r-   typesr  agent.credential_poolr  hermes_cli.auth_commandsr  entriesr   r%  r   r   r   r"   rf   r  r   r   r   r   r   rX   r	   rK  _setup_tts_provider)'r   r  rV   rW   r  exc
_refreshedselected_provider_mr  r  r  poolr  entry_countmanual_count
auto_countstrategy_labelscurrent_strategydefault_strategy_idxstrategy_idxstrategy_value_vision_needs_setupr   r+  _prov_names_prov_display_vision_choices_vision_idx_or_key	_base_url_api_key_label_is_native_openai_oai_key_vaux_oai_vision_models_vm_choices_vm_idx_selected_vision_models'                                          r   setup_model_providerr  K  s    ;%&?@J<'>?@	G :A!# J nnWfjj.ABF7OZ'%/0B%C!"

%t, 	G	B"dFF:. 78IJI	Y-7A./DllnGg,KpgppL$|3JG<=Z U W GA~56G5H;- X$~Yzl:^`
 <=N<OrR]Q^_` TV[\ #!2"$" $#'&*"&"#( $!&"&,2" !!23!$,,.13K=PQ)   TV[\, Q#
 $C6#J#N#NO`bn#o "##$( #&*	 %
  -=#( 
 "I!V-f6GX'8&99MnM]^_
 #	%L"#@#BC #''7"88 00"'-'/,7* &$-,
 $(9;L;_P_`9:@PQRSIJ

 $$7!L!3dCIIKG3W=OPBCA>?EEGfKfI(N 1) <@P P !3nt<BBDH/:))+r:EEhPRS$-j!$)m&"48S7T"TK+,BKQRSG #S);%<< +73* + .44f-g-m-m-o*)"#;=ST-i[99O2315UWY
 BCkl &&0F# 15C )* .,- AGM=cUCD?@@A@  	YLLRTWXX	Y  	%"u	%sP   Q? DS+ 7A,S+ )T ?$S(&S(./S##S(+	T4TTT/.T/c                  b    t        j                  d      duxs t        j                  d      duS )z Check if espeak-ng is installed.	espeak-ngNespeak)shutilwhichr  r   r   _check_espeak_ngr  ,  s*    <<$D0VFLL4JRV4VVr   c            	         ddl } ddl}t               st                t	        d       |j
                  dk(  rt        d       n&|j
                  dk(  rt        d       nt        d       t                t        d	d
      rl	 |j
                  dk(  r| j                  g dd
       n:|j
                  dk(  r| j                  g dd
       n| j                  g dd
       t        d       nt	        d       t                t        d       t        d       t                	 | j                  |j                  ddddddgd
d       t        d       y
# | j                  t        f$ r#}t	        d|        t        d       Y d}~yd}~ww xY w# | j                  | j                  f$ r#}t        d|        t        d        Y d}~yd}~ww xY w)!zHInstall NeuTTS dependencies with user approval. Returns True on success.r   Nz,NeuTTS requires espeak-ng for phonemization.darwinz$Install with: brew install espeak-ngwin32z%Install with: choco install espeak-ngz(Install with: sudo apt install espeak-ngzInstall espeak-ng now?T)brewinstallr  )check)chocor  r  -y)sudoaptr  r  r  zespeak-ng installedz+Could not install espeak-ng automatically: z,Please install it manually and re-run setup.FzJespeak-ng is required for NeuTTS. Install it manually before using NeuTTS.z#Installing neutts Python package...z<This will also download the TTS model (~300MB) on first use.-mpipr  -Uzneutts[all]--quietr  r  r  zneutts installed successfullyzFailed to install neutts: z2Try manually: python -m pip install -U neutts[all])
subprocessr   r  r`   rg   platformre   r   runrf   CalledProcessErrorFileNotFoundError
executableTimeoutExpiredrd   )r  r   es      r   _install_neutts_depsr  1  s    DE<<8#=>\\W$>?AB148<<8+NN#C4NP\\W,NN#JRVNWNN#PX\N]34 fg 
G45MN	G
^^T5)T=)T 	 	
 	56% 113DE  KA3OPIJ& )):+D+DE 045GHs1    A*E !0F F
'FF
G(GGc            
      D   ddl } ddl}d}t                t        d       t                	 | j	                  |j
                  dddd|d	d
gdd       t        d       y# | j                  | j                  f$ r'}t        d|        t        d| d       Y d}~yd}~ww xY w)zKInstall KittenTTS dependencies with user approval. Returns True on success.r   Nz^https://github.com/KittenML/KittenTTS/releases/download/0.8.1/kittentts-0.8.1-py3-none-any.whlzOInstalling kittentts Python package (~25-80MB model downloaded on first use)...r  r  r  r  	soundfiler  Tr  r  z kittentts installed successfullyzFailed to install kittentts: z(Try manually: python -m pip install -U 'z' soundfileF)
r  r   r`   re   r  r  rf   r  r  rd   )r  r   	wheel_urlr  s       r   _install_kittentts_depsr  c  s    	1  
G`a	G
^^T5)T9kS\] 	 	
 	89)):+D+DE 3A378=i[TUs   1A B8BBc           
          | j                  di       }|j                  dd      }t        |       }dddddd	d
ddd	}|j                  ||      }t                t        d       t	        d|        t                g }g }t               r.|j                  r"|j                  d       |j                  d       |j                  g d       |j                  g d       |j                  d| d       t        |      dz
  }t        d||      }	|	|k(  ry||	   }
|
dk(  }|
dk(  r.d}
t	        d       t        d      st        d      rt        d       |
dk(  r	 j                  j                  d      du}|rt!        d       nt                t	        d        t	        d!       t	        d"       t                t#        d#d$      rt%               sTt        d%       d}
nEt	        d&       d}
n6|
d'k(  rOt        d(      }|s#t                t'        d)d$*      }|rt)        d(|       t!        d+       nt        d,       d}
n|
dk(  r^|s\t        d      xs t        d      }|st                t'        d-d$*      }|rt)        d|       t!        d.       nt        d,       d}
n|
d/k(  rt        d0      }|sMt                t'        d1d$*      }|rt)        d0|       t!        d2       nd3d4lm} t        d5 |        d6       d}
|
d/k(  rt                t'        d7      }|r|j/                         r|j/                         | j1                  di       j1                  d/i       d8<   t!        d9|j/                                 n|
d:k(  rOt        d;      }|st                t'        d<d$*      }|rt)        d;|       t!        d=       n[t        d,       d}
nL|
d>k(  rNt        d?      }|s9t                t'        d@d$*      }|rt)        d?|       t!        dA       nt        d,       d}
n|
dBk(  rdt        dC      xs t        dD      }|st                t	        dE       t'        dFd$*      }|rt)        dC|       t!        dG       nt        d,       d}
n|
dHk(  r	 d3dl}|j                  j                  dH      du}|rt!        dI       n[t                t	        dJ       t	        dK       t                t#        dLd$      rt5               st        dM       d}
nt	        dN       d}
d| vri | d<   |
| d   d<   t7        |        t!        dO|j                  |
|
              y# t        $ r d}Y w xY w# t        $ r d}Y w xY w)Pz@Interactive TTS provider selection with install flow for NeuTTS.r   r   r   zEdge TTS
ElevenLabsz
OpenAI TTSzxAI TTSzMiniMax TTSzMistral Voxtral TTSzGoogle Gemini TTSNeuTTS	KittenTTS)	r   r   r   xairB   r   r<   r   r   z"Text-to-Speech Provider (optional)z	Current: zCNous Subscription (managed OpenAI TTS, billed to your subscription)znous-openai)	z-Edge TTS (free, cloud-based, no setup needed)z+ElevenLabs (premium quality, needs API key)z(OpenAI TTS (good quality, needs API key)z$xAI TTS (Grok voices, needs API key)z<MiniMax TTS (high quality with voice cloning, needs API key)z>Mistral Voxtral TTS (multilingual, native Opus, needs API key)zJGoogle Gemini TTS (30 prebuilt voices, prompt-controllable, needs API key)z5NeuTTS (local on-device, free, ~300MB model download)z<KittenTTS (local on-device, free, lightweight ~25-80MB ONNX)Keep current (r   r   zSelect TTS provider:Nr   zKOpenAI TTS will use the managed Nous gateway and bill to your subscription.r   r   ziDirect OpenAI credentials are still configured and may take precedence until removed from ~/.hermes/.env.r   FzNeuTTS is already installedzNeuTTS requires:uH     • Python package: neutts (~50MB install + ~300MB model on first use)u,     • System package: espeak-ng (phonemizer)z Install NeuTTS dependencies now?Tz9NeuTTS installation incomplete. Falling back to Edge TTS.zISkipping install. Set tts.provider to 'neutts' after installing manually.r   r   zElevenLabs API keyr   zElevenLabs API key savedz.No API key provided. Falling back to Edge TTS.zOpenAI API key for TTSzOpenAI TTS API key savedr  XAI_API_KEYzxAI API key for TTSzxAI TTS API key savedr   r  zQNo xAI API key provided for TTS. Configure XAI_API_KEY via hermes setup model or z//.env to use xAI TTS. Falling back to Edge TTS.z:xAI voice_id (Enter for 'eve', or paste a custom voice ID)voice_idzxAI voice_id set to: rB   r   zMiniMax API key for TTSzMiniMax TTS API key savedr   r   zMistral API key for TTSzMistral TTS API key savedr<   r   r   z<Get a free API key at https://aistudio.google.com/app/apikeyzGemini API key for TTSzGemini TTS API key savedr   zKittenTTS is already installedzCKittenTTS is lightweight (~25-80MB, CPU-only, no API key required).z:Voices: Jasper, Bella, Luna, Bruno, Rosie, Hugo, Kiki, LeozInstall KittenTTS now?z<KittenTTS installation incomplete. Falling back to Edge TTS.zLSkipping install. Set tts.provider to 'kittentts' after installing manually.zTTS provider set to: )r   r   r`   rc   re   r   r$  r  extendr   r   rZ   rg   r   r!  r   rf   r   r  r   rX   r'  r  r   rK  r"  r  rW   )r   
tts_configr  r*  provider_labelscurrent_labelr   	providerskeep_current_idxr   r   selected_via_nousr6  already_installedexistingr(   r>  r  s                     r   r  r  |  sY   E2&J!~~j&9:6B " (% 
O $''(8:JKM	G56=/*+	GGI!#(=(O(O\]'NN
	
 stNN^M?!457|a'
.9I
JC
~H M1= `a12mDT6U{ 8	& ) 8 8 B$ N 78G)*abEFG?F+-!"]^%Hfg!	\	! !56G1DAG3W=89NO!	X	&7 !9:]mL\>]G5EG7A89NO!	U	 /G2TBG}g656H--1VH 500
 "uGZ[HHNN,QYQ_Q_Qa!!%,77rB:N 5hnn6F5GHI 
Y	 !23G6FG0':9:NO!	Y	 !23G6FG0':9:NO!	X	 !12UmDT6UGUV5EG/989NO!	[	 	&! ) 8 8 ET Q :;G\]STG5t<.0!"`a%Hij! Fu (F5M*)/*=*=h*Q)RSTI  	& %	&Z  	& %	&s$   U !U/ U,+U,/U=<U=c                     t        |        y)z.Standalone TTS setup (for 'hermes setup tts').N)r  r   s    r   	setup_ttsr  C  s
    r   c           	         ddl }t        d       t        d       t        d       t        dt         d       t	                t        | dd	d
      }|j                         dk(  }g d}d
dddddd}ddddddd}d}|r |j                  d       d||<   ||d<   |dz  }|}|j                  d| d       |||<   t        d||      }	|j                  |	      }
|	|k(  rt        d |        y|
| j                  di       d	<   |
d
k(  rt        d!       t        d"       t	                t        d#       t        d$       t        d%       t        | dd&d'      }t        d(|xs t        t        j                                     }|r|| d   d&<   t	                t!        d)      }|rt        d*       n,t#        d+d,      rt        d-d./      }|rt%        d)|       t        d0       n|
dk(  rt        d1       t'        j(                  d      }|st+        d2       t        d3       nt        d4|        t        | dd5d6      }t        d7|      }|| d   d5<   t%        d8|       t-        |        nn|
dk(  rt        d9       t'        j(                  d:      xs t'        j(                  d      }|st+        d;       t        d<       nt        d=|        t        | dd>d?      }t        d@|      }|| d   d><   t%        dA|       t-        |        n|
dk(  rt        dB       t        dC       ddDlm} ddElm} t7        t9               xr t;        |       j<                  xr  |d            } |t        | ddF            }d,}|r5dGdHg}|dIk(  rd}n|dJk(  rd}nt!        dK      rdnd}t        dL||      }|dk(  }|r5dI| d   dF<   t        dM       t!        dK      st!        dN      rt        dO       ndJ| d   dF<   t        dP       	 t?        d       t	                t        dZ       t        d[       t!        dK      }|rNt        d\       t#        d]d,      rmt        d^d./      }t        d_d./      } |rt%        dK|       | rCt%        dN|        n6t        d^d./      }t        d_d./      } |rt%        dK|       | rt%        dN|        t-        |        n|
dk(  rt        d`       t        da       t        db       t        dc       	 t?        d       t	                t!        di      }!|!r>t        dj       t#        dkd,      rMt        dld./      }"|"r>t%        di|"       t        dm       n&t        dld./      }"|"rt%        di|"       t        dn       t        | ddod6      }t        dp|      }|| d   do<   t%        dq|       t-        |        n|
dk(  r:t        dr       t        ds       t        dt       	 t?        du       tS        |        n|
dk(  rt        dy       t        dz       t!        d{      xs d'}#t        d||#      }$|$rt%        d{|$       t!        d}      xs d'}%t        d~|%xs tU        jV                  dd'            }&|&rt%        d}|&       t!        d      xs d}'t        d|'      }(|(r|(dk7  rt%        d|(       t!        d      xs d'})t        t        j                         dz  dz        }*t        d|)xs |*      }+|+rt%        d|+       |$rt#        dd.      rt        d       ddl!}g d},|+r|,jY                  d|+g       |(r|(dk7  r|,jY                  d|(g       |,j                  |&r|& d|$ n|$       |,j                  d       |jE                  |,d.d.d      }|jJ                  dk(  rt        d       n1t+        d|jL                  jO                                 t        d       t%        d|
       |
dk(  rt%        d| d   j                  dFd             |
dk(  rt%        d| d   j                  dd             t[        |        t	                t        d|
        y# t@        $ r t        dQ       ddl!}t'        j(                  dR      }|r)|jE                  |dSdTdUtF        jH                  dgd.d.V      }n'|jE                  tF        jH                  dWdSdTdgd.d.V      }|jJ                  dk(  rt        dX       nt+        dY       Y w xY w# t@        $ r t        dd       ddl!}t'        j(                  dR      }|r)|jE                  |dSdTdUtF        jH                  dgd.d.V      }n'|jE                  tF        jH                  dWdSdTdgd.d.V      }|jJ                  dk(  rt        de       nNt+        df       |jL                  r7t        dg|jL                  jO                         jQ                         dh           Y w xY w# t@        $ r t        dv       ddl!}t'        j(                  dR      }|r)|jE                  |dSdTdUtF        jH                  dugd.d.V      }n'|jE                  tF        jH                  dWdSdTdugd.d.V      }|jJ                  dk(  rt        dw       nNt+        dx       |jL                  r7t        dg|jL                  jO                         jQ                         dh           Y w xY w)z)Configure the terminal execution backend.r   NTerminal Backendz1Choose where Hermes runs shell commands and code.z8This affects tool execution, file access, and isolation.r  z/developer-guide/environmentsr   r   localr   Linux)z.Local - run directly on this machine (default)z7Docker - isolated container with configurable resourcesz Modal - serverless cloud sandboxzSSH - run on a remote machinez2Daytona - persistent cloud development environmentzCVercel Sandbox - cloud microVM with snapshot filesystem persistencedockerr   sshdaytonavercel_sandbox)r   r   r  r         r   r  r   r  r  )r  r	  r   r
  r  r     z.Singularity/Apptainer - HPC-friendly containersingularityr  r   zSelect terminal backend:zKeeping current backend: zTerminal backend: Localz&Commands run directly on this machine.zGateway working directory:z)  Used by Telegram/Discord/cron sessions.z4  CLI/TUI always uses your launch directory instead.rr  rJ   z  Gateway working directorySUDO_PASSWORDzSudo password: configuredz<Enable sudo support? (stores password for apt install, etc.)Fz  Sudo passwordTr   zSudo password savedzTerminal backend: DockerzDocker not found in PATH!z3Install Docker: https://docs.docker.com/get-docker/zDocker found: docker_imagez*nikolaik/python-nodejs:python3.11-nodejs20z  Docker imageTERMINAL_DOCKER_IMAGEz'Terminal backend: Singularity/Apptainer	apptainerz(Singularity/Apptainer not found in PATH!z@Install: https://apptainer.org/docs/admin/main/installation.htmlzFound: singularity_imagez3docker://nikolaik/python-nodejs:python3.11-nodejs20z  Container imageTERMINAL_SINGULARITY_IMAGEzTerminal backend: Modalz@Serverless cloud sandboxes. Each session gets its own container.)is_managed_tool_gateway_ready)normalize_modal_mode
modal_modezUse my Nous subscriptionzUse my own Modal accountmanageddirectMODAL_TOKEN_IDz,Select how Modal execution should be billed:zPModal execution will use the managed Nous gateway and bill to your subscription.MODAL_TOKEN_SECRETzZDirect Modal credentials are still configured, but this backend is pinned to managed mode.z+Requires a Modal account: https://modal.comzInstalling modal SDK...uvr  r  --pythoncapture_outputrr   r  zmodal SDK installedu2   Install failed — run manually: pip install modalzModal authentication:z/  Get your token at: https://modal.com/settingsz!  Modal token: already configuredz  Update Modal credentials?z    Modal Token IDz    Modal Token SecretzTerminal backend: Daytonaz*Persistent cloud development environments.zBEach session gets a dedicated sandbox with filesystem persistence.zSign up at: https://daytona.iozInstalling daytona SDK...zdaytona SDK installedu4   Install failed — run manually: pip install daytona	  Error: r   DAYTONA_API_KEYz%  Daytona API key: already configuredz  Update API key?z    Daytona API keyz    Updatedz    Configureddaytona_imagez  Sandbox imageTERMINAL_DAYTONA_IMAGEz Terminal backend: Vercel SandboxzDCloud microVM sandboxes with snapshot-backed filesystem persistence.z=Requires the optional SDK: pip install 'hermes-agent[vercel]'vercelzInstalling vercel SDK...zvercel SDK installeduC   Install failed — run manually: pip install 'hermes-agent[vercel]'zTerminal backend: SSHz)Run commands on a remote machine via SSH.TERMINAL_SSH_HOSTz  SSH host (hostname or IP)TERMINAL_SSH_USERz
  SSH userUSERTERMINAL_SSH_PORT22z
  SSH portTERMINAL_SSH_KEYz.sshid_rsaz  SSH private key pathz  Test SSH connection?z  Testing connection...)r
  -ozBatchMode=yesr.  zConnectTimeout=5z-iz-p@zecho ok
   )r!  rr   r  z  SSH connection successful!z  SSH connection failed: z'  Check your SSH key and host settings.TERMINAL_ENVTERMINAL_MODAL_MODEautor\  rY  rZ  zTerminal backend set to: ).r  rc   re   r  r`   rQ   systemr  r   r   rK  rf   r   r   r   homerZ   r   rX   r  r  rg   rV  tools.managed_tool_gatewayr  tools.tool_backend_helpersr  r   r   r   r$  
__import__ImportErrorr  r  r   r  
returncodestderrr   
splitlinesrl  osgetenvr  rW   )-r   	_platformcurrent_backendis_linuxterminal_choicesidx_to_backendbackend_to_idxnext_idxr  terminal_idxselected_backendcurrent_cwdrr  existing_sudo	sudo_pass
docker_bincurrent_imageimagesing_binr  r  managed_modal_availabler  use_managed_modalmodal_choicesdefault_modal_idxmodal_mode_idxr  uv_binresultexisting_tokentoken_idtoken_secretexisting_keyr(   current_hosthostcurrent_userusercurrent_portportcurrent_keydefault_keyssh_keyssh_cmds-                                                r   setup_terminal_backendrd  M  s
    #$BCIJJ<'DEF	Gfj)WMO!W,H !X'e	VfgN A!PQefgNH PQ#0x (0}%A  n_,=Q?@'6N#$ "$46FL &)),7''..?@A3CFj"%i07"/0;< 	/0>?IJfj%D2K4S3tyy{CST(+F:u% 	%o623JE
 04@I	:34	X	%01 \\(+
56LM
|45  
NLxy'7-2z>*.6#F+	]	*?@ <<,K]0KDER 
+,
4G  RG  H*M:27z./3U;#F+	W	$/0UVLC"&&( 7*62DD7 .g6	#
 *'&*l*ST
!"**M Y&$%!x'$%!)67G)HAa!*>!N
 !/! 3/8F:|,ij-.-@T2Up 08F:|,DEX7#> G./HI*+;<N>? !>F%&:TJH#)*BT#RL&'7B#&';\J!"6F%&>N"#3X>"#7F#F+	Y	&12?@WX34	Uy!4 	$%67>?0%8 !6F"#4g>!-02TBG0':./  
OMyz(-8.3z?+/7#F+	-	-89YZRS	Ux 2 	(/	U	"-.>? %%89?R3\B.5 %%89?RlL$IBIIfb4IJ.5 %%89ATlL1DDL.5 $$67=2$))+.9:1;3M+N-w7 M":DA01NGg/d|,NNtdV1TF+>NN9%^^GDtUW^XF  A%<= 9&--:M:M:O9PQRDE >#347",fZ.@.D.D\SY.Z[++0&2D2H2HIY[c2de	G-.>-?@AQ  X45!d+'^^"!%&NN# (,! , F (^^uiI'+! , F
 $$)!"78!"VW7X|  	U23\\$'F#UIz3>>9U#' (  $^^T5)YG#' ( 
   A%56TU==6==+>+>+@+K+K+Mb+Q*RST-	Un  	U12\\$'F#UIz3>>8T#' (  $^^T5)XF#' ( 
   A%45cd==6==+>+>+@+K+K+Mb+Q*RST-	Us9    a ;d  $g/ B%c=<c= C(g,+g,/C(kkc                    d| j                  di       d<   t        d       d| j                  di       d<   d| j                  d	i       d
<   d| d	   d<   | j                  di       j                  dddd       t        |        t	        d       t        d       t        d       t        d       t        d       t        d       y)zDApply recommended defaults for all agent settings without prompting.Z   rH   	max_turnsHERMES_MAX_ITERATIONSallr   tool_progressTcompressionenabled      ?	thresholdsession_resetboth  r  )modeidle_minutesat_hourzApplied recommended defaults:z  Max iterations: 90z  Tool progress: allz  Compression threshold: 0.50z5  Session reset: inactivity (1440 min) + daily (4:00)z.  Run `hermes setup agent` later to customize.N)rK  rY   updaterW   rf   re   r  s    r   _apply_default_agent_settingsrv    s    24Fgr";/
 ,-8=Fi$_56:FmR(3)-F=+&
or*113  12%&%&./FG?@r   c           	      X
   t        d       t        dt         d       t                t	        t        | ddd            }t        d       t        d	       t        d
| d       t        d|      }	 t        |      }|dkD  r@|| j                  di       d<   | j                  dd       t        d       t        d|        t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        | ddd      }t        d|      }|j                         dv rGd| vri | d<   |j                         | d   d<   t        |        t        d|j                                 nt        d| d | d!       t        d"       t        d#       t        d$       d%| j                  d&i       d'<   t        | d&d(d)      }t        d*t	        |            }	 t!        |      }d)|cxk  rd+k  rn n|| d&   d(<   t        d,| d&   j#                  d(d)              t        d-       t        d.       t        d/       t        d       t        d0       t        d1       t        d2       t        d       t        d3       t        d       g d4}	| j#                  d5i       }
|
j#                  d6d7      }|
j#                  d8d9      }|
j#                  d:d;      }dd<d=d>d?j#                  |d      }t%        d@|	|      }| j                  d5i        |dk(  rd7| d5   d6<   t        dAt	        |            }	 t        |      }|dkD  r|| d5   d8<   t        dBt	        |            }	 t        |      }d|cxk  rdCk  rn n|| d5   d:<   t        dD| d5   j#                  d8d9       dE| d5   j#                  d:d;       dF       n|d<k(  rYdG| d5   d6<   t        dAt	        |            }	 t        |      }|dkD  r|| d5   d8<   t        dD| d5   j#                  d8d9       dH       n|d=k(  rbdI| d5   d6<   t        dBt	        |            }	 t        |      }d|cxk  rdCk  rn n|| d5   d:<   t        dJ| d5   j#                  d:d;       dF       n#|d>k(  rdK| d5   d6<   t        dL       t        dM       t        |        y# t        $ r t        d       Y w xY w# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y tw xY w# t        $ r Y w xY w# t        $ r Y w xY w)NzSConfigure agent behavior: iterations, progress display, compression, session reset.Agent Settingsr  z/user-guide/configurationrH   rg  rf  r   z1Maximum tool-calling iterations per conversation.z3Higher = more complex tasks, but costs more tokens.zPress Enter to keep z5. Use 90 for most tasks or 150+ for open exploration.zMax iterationsr   Nrh  zMax iterations set to z%Invalid number, keeping current valuerJ   zTool Progress Displayz=Controls how much tool activity is shown (CLI and messaging).u-     off     — Silent, just the final responseu>     new     — Show tool name only when it changes (less noise)u7     all     — Show every tool call with a short previewu0     verbose — Full args, results, and debug logsr   rj  ri  zTool progress mode>   ri  ry   offverbosezTool progress set to: zUnknown mode 'z', keeping ''zContext CompressionzAAutomatically summarizes old messages when context gets too long.zNHigher threshold = compress later (use more context). Lower = compress sooner.Trk  rl  rn  rm  z Compression threshold (0.5-0.95)gffffff?z%Context compression threshold set to zSession Reset PolicyzJMessaging sessions (Telegram, Discord, etc.) accumulate context over time.zMEach message adds to the conversation history, which means growing API costs.zMTo manage this, sessions can automatically reset after a period of inactivityzLor at a fixed time each day. When a reset happens, the agent saves importantuR   things to its persistent memory first — but the conversation context is cleared.z=You can also manually reset anytime by typing /reset in chat.)zDInactivity + daily reset (recommended - reset whichever comes first)z6Inactivity only (reset after N minutes of no messages)z+Daily only (reset at a fixed hour each day)zDNever auto-reset (context lives until /reset or context compression)zKeep current settingsro  rr  rp  rs  rq  rt  r  r   r  r   )rp  idledailynonezSession reset mode:z  Inactivity timeout (minutes)z%  Daily reset hour (0-23, local time)   zSessions reset after z min idle or daily at z:00r|  z min of inactivityr}  zSessions reset daily at r~  zGSessions will never auto-reset. Context is managed only by compression.zFLong conversations will grow in cost. Use /reset manually when needed.)rc   re   r  r`   r   rQ   r   r   rK  r  rY   rf   r   rg   rK   rW   rL  r   r   )r   current_maxmax_iter_strmax_itercurrent_moderr  current_thresholdthreshold_strrn  reset_choicescurrent_policycurrent_idlecurrent_hourdefault_reset	reset_idxidle_stridle_valhour_strhour_vals                      r   setup_agent_settingsr    s    !"J<'@AB	G gfg{BGHKBCDE
{m+`a *K8L?|$a<
 ;CFgr*;7JJ{D)4528*=>
 rN&'NO>?OPHIAB69ouML&5Dzz|77F" "F9-1ZZ\y/*F.tzz|n=>tfLaHI &'RSX 7;FmR(3{DQ=sCT?UVM-(	)#t#1:F=!+. 
/}0E0I0I+W[0\/]^
 '(T W rNW V \ rNNOrNM ZZ4N!%%ff5L!%%nd;L!%%i3LAqAEElTUVM3]MRI
or*A~*0':C<MN	8}H!|:B'7 A3|CTU	8}HH""5='	2 	#F?$;$?$?PT$U#VVlms  uD  nE  nI  nI  JS  UV  nW  mX  X[  \	
 
a*0':C<MN	8}H!|:B'7 	#F?$;$?$?PT$U#VVhi	
 
a*1'A3|CTU	8}HH""5='	2 	&vo'>'B'B9a'P&QQTU	
 
a*0'U	
 	T	

 W  ?=>?L  n  		  		  		  		sm   3AS 1!S S- 4!S= 1T !T SS	S*)S*-	S:9S:=	T
	T
	TT	T)(T)c                  P   t        d       t        d      } | ryt        d       t        dd      sbt        d      sVt        d       t        dd	      r?t        d
       t	        d      }|r't        d|j                  dd             t        d       yt        d       ddl}	 t	        dd	      }|sy |j                  d|      st        d       0	 t        d|       t        d       t                t        d       t        d       t        d       t        d       t                t	        d      }|r(t        d|j                  dd             t        d       nt        d       t                t        d       t        d       t        d        |r"|j                  d!      d   j                         nd}|rFt        d"| d#d	      rt        d$|       t        d%|        yt	        d&      }|rt        d$|       yyt        d'       t	        d(      }|rt        d$|       yy))z1Configure Telegram bot credentials and allowlist.TelegramTELEGRAM_BOT_TOKENzTelegram: already configuredzReconfigure Telegram?FTELEGRAM_ALLOWED_USERSuA   ⚠️  Telegram has no user allowlist - anyone can use your bot!Add allowed users now?Tz6   To find your Telegram user ID: message @userinfobot"Allowed user IDs (comma-separated)r   rJ   zTelegram allowlist configuredNz'Create a bot via @BotFather on Telegramr   zTelegram bot tokenr   z^\d+:[A-Za-z0-9_-]{30,}$znInvalid token format. Expected: <numeric_id>:<alphanumeric_hash> (e.g., 123456789:ABCdefGHI-jklMNOpqrSTUvwxYZ)zTelegram token saved,   🔒 Security: Restrict who can use your botz!   To find your Telegram user ID:z&   1. Message @userinfobot on Telegramz:   2. It will reply with your numeric ID (e.g., 123456789)?Allowed user IDs (comma-separated, leave empty for open access)zATelegram allowlist configured - only listed users can use the botu@   ⚠️  No allowlist set - anyone who finds your bot can use it!:   📬 Home Channel: where Hermes delivers cron job results,.   cross-platform messages, and notifications.z:   For Telegram DMs, this is your user ID (same as above).,zUse your user ID (z) as the home channel?TELEGRAM_HOME_CHANNELzTelegram home channel set to zHHome channel ID (or leave empty to set later with /set-home in Telegram)zI   You can also set this later by typing /set-home in your Telegram chat.z*Home channel ID (leave empty to set later))rc   rZ   re   r   r   rX   rv   rf   rematchrd   r`   splitr   )r  allowed_usersr  ri  first_user_idhome_channels         r   _setup_telegramr    s
   12H124e< !9:^_ !94@WX$*+O$PM$&'?AVAVWZ\^A_`%&EF89
+d;rxx3U;@ '/()	G=>2378KL	GIM /1F1FsB1OPYZUV	GKL?@KL;HM'',Q/557bM-m_<RSUYZ2MB9-IJ!"lmL6E  	^_JK2LA r   c                     t        d       t        d      } | rt        d       t        dd      slt        d      s`t        d       t        dd	      rIt        d
       t	        d      }|r1t        |      }t        ddj                  |             t        d       yt        d       t	        dd	      }|syt        d|       t        d       t                t        d       t        d       t        d       t        d       t                t        d       t                t	        d      }|r2t        |      }t        ddj                  |             t        d       nt        d       t                t        d       t        d       t        d       t        d       t        d       t	        d      }|rt        d |       yy)!z0Configure Discord bot credentials and allowlist.DiscordDISCORD_BOT_TOKENzDiscord: already configuredzReconfigure Discord?FDISCORD_ALLOWED_USERSu@   ⚠️  Discord has no user allowlist - anyone can use your bot!r  TuJ      To find Discord ID: Enable Developer Mode, right-click name → Copy IDr  r  zDiscord allowlist configuredNz;Create a bot at https://discord.com/developers/applicationszDiscord bot tokenr   zDiscord token savedr  z    To find your Discord user ID:z/   1. Enable Developer Mode in Discord settingsu'      2. Right-click your name → Copy IDzB   You can also use Discord usernames (resolved on gateway start).zLAllowed user IDs or usernames (comma-separated, leave empty for open access)uF   ⚠️  No allowlist set - anyone in servers with your bot can use it!r  r  uA      To get a channel ID: right-click a channel → Copy Channel IDz0   (requires Developer Mode in Discord settings)zH   You can also set this later by typing /set-home in a Discord channel.9Home channel ID (leave empty to set later with /set-home)DISCORD_HOME_CHANNEL)
rc   rZ   re   r   r   _clean_discord_user_idsrX   r   rf   r`   )r  r  cleaned_idsri  r  s        r   _setup_discordr    s   01H013U; !89]^ !94@kl$*+O$PM$&=m&L&'>@UV%&DELM&6E&.'(	G=>12@A89	GST	GVM -m<.0EF45[\	GKL?@RSABYZUVL-|< r   rawc                 j   g }| j                  dd      j                  d      D ]  }|j                         }|j                  d      r1|j	                  d      r |j                  d      j                  d      }|j                         j                  d      r|dd	 }|s||j                  |        |S )
zGStrip common Discord mention prefixes from a comma-separated ID string.r   rJ   r  z<@>z<@!zuser:r  N)	rv   r  r   r  endswithlstriprstriprK   r  )r  r   uids      r   r  r    s    G{{3#))#.  iik>>$CLL$5**U#**3/C99;!!'*ab'CNN3  Nr   c                     t        d       t        d      } | r.t        d       t        dd      st        dd      r
t	                yt        d	       t        d
       t        d       t        d       t        d       t        d       t        d       t                t        d       t                t	                t                t        dd      }|syt        d|       t        dd      }|rt        d|       t        d       t                t        d       t        d       t                t        d      }|r(t        d|j                  dd             t        d       nt        d       t        d       t                t        d       t        d        t        d!       t        d"       t        d#       t        d$      }|rt        d%|j                                yy)&z Configure Slack bot credentials.SlackSLACK_BOT_TOKENzSlack: already configuredzReconfigure Slack?FzcRegenerate the Slack app manifest with the latest command list? (recommended after `hermes update`)TNzSteps to create a Slack app:u9      1. Go to https://api.slack.com/apps → Create New AppuG         Pick 'From an app manifest' — we'll generate one for you below.u=      2. Enable Socket Mode: Settings → Socket Mode → EnableuB         • Create an App-Level Token with 'connections:write' scopeu4      3. Install to Workspace: Settings → Install AppzD   4. After installing, invite the bot to channels: /invite @YourBotzU   Full guide: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/slack/zSlack Bot Token (xoxb-...)r   zSlack App Token (xapp-...)SLACK_APP_TOKENzSlack tokens savedr  u\      To find a Member ID: click a user's name → View full profile → ⋮ → Copy member IDzTAllowed user IDs (comma-separated, leave empty to deny everyone except paired users)SLACK_ALLOWED_USERSr   rJ   zSlack allowlist configureduJ   ⚠️  No Slack allowlist set - unpaired users will be denied by default.zw   Set SLACK_ALLOW_ALL_USERS=true or GATEWAY_ALLOW_ALL_USERS=true only if you intentionally want open workspace access.r  r  zC   To get a channel ID: open the channel in Slack, then right-clickuN      the channel name → Copy link — the ID starts with C (e.g. C01ABC2DE3F).zF   You can also set this later by typing /set-home in a Slack channel.r  SLACK_HOME_CHANNEL)rc   rZ   re   r   "_write_slack_manifest_and_instructr`   r   rX   rf   rv   rg   r   )r  	bot_token	app_tokenr  r  s        r   _setup_slackr    s   ./H./159 <
 34-.JKXYNOSTEFUV	Gfg	G
 '(	G3dCI$i03dCI()4&'	G=>mn	G^M ,m.C.CC.LM23bc  M  	N	GKL?@TU_`WXUVL+\-?-?-AB r   c                     	 ddl m}  ddlm}  | dd      }t	         |             dz  }|j
                  j                  dd	       dd
l}|j                  |j                  |dd      dz   d       t        d|        t        d       t        d       y
# t        $ r#}t        d|        t        d       Y d
}~y
d
}~ww xY w)u  Generate the Slack manifest, write it under HERMES_HOME, and print
    paste-into-Slack instructions.

    Exposed as its own helper so both the initial setup flow and the
    "reconfigure? → no" branch can refresh the manifest without the user
    re-entering tokens. Failures are non-fatal — if the manifest write
    fails for any reason, we print a warning and skip rather than abort
    the whole Slack setup.
    r   )_build_full_manifest)rS   HermeszYour Hermes agent on Slack)bot_namebot_descriptionzslack-manifest.jsonT)rv  exist_okNr  F)indentensure_ascii
ro  rp  zSlack app manifest written to: u      Paste it into https://api.slack.com/apps → your app → Features → App Manifest → Edit, then Save.  Slack will prompt to reinstall if scopes or slash commands changed.z\   Re-run `hermes slack manifest --write` anytime to refresh after Hermes adds new commands.zCouldn't write Slack manifest: zI   You can generate it manually later with: hermes slack manifest --write)hermes_cli.slack_clir  r'  rS   r   ru  mkdirrx  
write_textdumpsrf   re   r   rg   )r  rS   manifesttarget_jsonr  s         r   r  r  Z  s    
=4'8
 o'(+@@D48KKK?$F 	 	
 	7x@A=	

 	(	
  
7u=>,	
 	

s   BB 	C"C  Cc            	      <   t        d       t        d      xs t        d      } | rt        d       t        dd      syt        d       t        d	       t        d
       t	                t        d      }|rt        d|j                  d             t	                t        d       t        dd      }|r1t        d|       t        d      }|rt        d|       t        d       n?t        d      }|rt        d|       t        dd      }|rt        d|       t        d       |st        d      rt	                t        dd      }|rt        dd       t        d       |rdnd}	 t        d       t	                t        d,       t        d-       t	                t        d.      }
|
r(t        d/|
j-                  d0d1             t        d2       nt        d3       t	                t        d4       t        d5       t        d6       t        d7      }|rt        d8|       yyy# t        $ r t        d| d       d dl}t        j                  d!      }|r)|j                  |d"d#d$t        j                   |gdd%      }	n'|j                  t        j                   d&d"d#|gdd%      }	|	j"                  d k(  rt        | d'       nRt%        d(| d)       |	j&                  r7t        d*|	j&                  j)                         j+                         d+           Y w xY w)9zConfigure Matrix credentials.MatrixMATRIX_ACCESS_TOKENMATRIX_PASSWORDzMatrix: already configuredzReconfigure Matrix?FNzMWorks with any Matrix homeserver (Synapse, Conduit, Dendrite, or matrix.org).zC   1. Create a bot user on your homeserver, or use your own accountzE   2. Get an access token from Element, or provide user ID + passwordz0Homeserver URL (e.g. https://matrix.example.org)MATRIX_HOMESERVERr  zCAuth: provide an access token (recommended), or user ID + password.z-Access token (leave empty for password login)Tr   u9   User ID (@bot:server — optional, will be auto-detected)MATRIX_USER_IDzMatrix access token savedzUser ID (@bot:server)PasswordzMatrix credentials savedz$Enable end-to-end encryption (E2EE)?MATRIX_ENCRYPTIONrC  zE2EE enabledzmautrix[encryption]mautrixzInstalling z...r   r  r  r  r  r   r  z
 installedu.   Install failed — run manually: pip install 'r{  r"  r   r  z-   Matrix user IDs look like @username:serverr  MATRIX_ALLOWED_USERSr   rJ   zMatrix allowlist configuredE   ⚠️  No allowlist set - anyone who can message the bot can use it!uI   📬 Home Room: where Hermes delivers cron job results and notifications.zE   Room IDs look like !abc123:server (shown in Element room settings)zD   You can also set this later by typing /set-home in a Matrix room.z6Home room ID (leave empty to set later with /set-home)MATRIX_HOME_ROOM)rc   rZ   re   r   r`   r   rX   r  rf   r8  r9  r  r  r  r  r   r  r:  rg   r;  r   r<  rv   )r  
homeserverri  user_idr   	want_e2ee
matrix_pkgr  rT  rU  r  	home_rooms               r   _setup_matrixr    s   23W}EV7WH/02E:^_TUVW	GJKJ*J,=,=c,BC	GTUBTRE,e4TU+W51201+W5*t4,h745/0!"H%P	.7.).7*Y
	Uy!, 	ABBC`a1=3H3Hb3QR78^_^_Z[YZST	-y9 _ 1  	UZL45\\$'F#UIz3>>:V#'d ( 
 $^^T5)ZH#'d (    A%J78 NzlZ[\]==6==+>+>+@+K+K+Mb+Q*RST'	Us   (H$ $C3LLc                     t        d       t        d      } | rt        d       t        dd      syt        d       t        d       t        d	       t	                t        d
      }|rt        d|j                  d             t        dd      }|syt        d|       t        d       t	                t        d       t        d       t        d       t	                t        d      }|r(t        d|j                  dd             t        d       nt        d       t	                t        d       t        d       t        d       t        d      }|rt        d|       t        d       y) z%Configure Mattermost bot credentials.
MattermostMATTERMOST_TOKENzMattermost: already configuredzReconfigure Mattermost?FNz/Works with any self-hosted Mattermost instance.uF      1. In Mattermost: Integrations → Bot Accounts → Add Bot Accountz   2. Copy the bot tokenz3Mattermost server URL (e.g. https://mm.example.com)MATTERMOST_URLr  z	Bot tokenTr   zMattermost token savedr  u6      To find your user ID: click your avatar → Profilez'   or use the API: GET /api/v4/users/mer  MATTERMOST_ALLOWED_USERSr   rJ   zMattermost allowlist configuredr  uL   📬 Home Channel: where Hermes delivers cron job results and notifications.uH      To get a channel ID: click channel name → View Info → copy the IDzK   You can also set this later by typing /set-home in a Mattermost channel.r  MATTERMOST_HOME_CHANNEL2   Open config in your editor:  hermes config edit)
rc   rZ   re   r   r`   r   rX   r  rf   rv   )r  mm_urlri  r  r  s        r   _setup_mattermostr    s6   /0H346>@AWX)*	GIJF's);<;.E%u-*+	G=>GH89	G\]M1=3H3Hb3QR78Z[	G]^YZ\]UVL0,?CDr   c                  L   t        d       t        d      } | rt        d       t        dd      syt        d       t        d       t        d	       t        d
       t	                t        d       t	                t        d      }|st        d       yt        d|j                  d             t        dd      }|st        d       yt        d|       t        d       t	                t        d       t        d       t	                t        d      }|r(t        d|j                  dd             t        d       nt        d       t	                t        d       t        d       t        d      }|rt        d |       t	                t        d!       t        d"d      r:t        d#      }|r-	 t        d$t        t        |                   t        d%|        t	                t        d'       t        d(       t        d)       y# t        $ r t        d&       Y Bw xY w)*z'Configure BlueBubbles iMessage gateway.zBlueBubbles (iMessage)BLUEBUBBLES_SERVER_URLzBlueBubbles: already configuredzReconfigure BlueBubbles?FNuC   Connects Hermes to iMessage via BlueBubbles — a free, open-sourcez1macOS server that bridges iMessage to any device.z4   Requires a Mac running BlueBubbles Server v1.0.0+z%   Download: https://bluebubbles.app/uN   In BlueBubbles Server → Settings → API, note your Server URL and Password.z6BlueBubbles server URL (e.g. http://192.168.1.10:1234)u5   Server URL is required — skipping BlueBubbles setupr  zBlueBubbles server passwordTr   u3   Password is required — skipping BlueBubbles setupBLUEBUBBLES_PASSWORDzBlueBubbles credentials savedu0   🔒 Security: Restrict who can message your botzJ   Use iMessage addresses: email (user@icloud.com) or phone (+15551234567)zIAllowed iMessage addresses (comma-separated, leave empty for open access)BLUEBUBBLES_ALLOWED_USERSr   rJ   z BlueBubbles allowlist configureduI   ⚠️  No allowlist set — anyone who can iMessage you can use the bot!uJ   📬 Home Channel: phone or email for cron job delivery and notifications.zD   You can also set this later with /set-home in your iMessage chat.z/Home channel address (leave empty to set later)BLUEBUBBLES_HOME_CHANNELz6Advanced settings (defaults are fine for most setups):z$Configure webhook listener settings?z%Webhook listener port (default: 8645)BLUEBUBBLES_WEBHOOK_PORTWebhook port set to z'Invalid port number, using default 8645zBRequires the BlueBubbles Private API helper for typing indicators,zGread receipts, and tapback reactions. Basic messaging works without it.zC   Install: https://docs.bluebubbles.app/helper-bundle/installation)rc   rZ   re   r   r`   r   rg   rX   r  rf   rv   r   r   r   )r  
server_urlr   r  r  webhook_ports         r   _setup_bluebubblesr  	  s   )*56H457?TUBCEF67	G_`	GPQJMN+Z->->s-CD3dCHKL)8412	GAB[\	GfgM2M4I4I#r4RS89^_	G[\UVKLL1<@	GGH;UCEFI93s<?P;QR 4\NCD 
GSTXYTU  IGHIs   4,H H#"H#c                      ddl m}   |         y)z5Configure QQ Bot (Official API v2) via gateway setup.r   )_setup_qqbotN)hermes_cli.gatewayr  )_gateway_setup_qqbots    r   r  r  H	  s    Gr   c                  &   t        d       t        d      } | rt        d       t        dd      syt	                t        d       t        d       t        d	       t	                t        d
       t	                t        d      }|r-	 t        dt        t        |                   t        d|        t        dd      }|rt        d|       t        d       nt        d       t        dd       t	                t        d       ddlm} t        d |        d       t        d       t        d       t	                t        d       t        d       t	                t        d       t        d       y# t        $ r t        d       Y w xY w) zConfigure webhook integration.WebhooksWEBHOOK_ENABLEDzWebhooks: already configuredzReconfigure webhooks?FNuD   ⚠  Webhook and SMS platforms require exposing gateway ports to thezE   internet. For security, run the gateway in a sandboxed environmentzB   (Docker, VM, etc.) to limit blast radius from prompt injection.zX   Full guide: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/webhooks/zWebhook port (default 8644)WEBHOOK_PORTr  z'Invalid port number, using default 8644z-Global HMAC secret (shared across all routes)Tr   WEBHOOK_SECRETzWebhook secret saveduE   No secret set — you must configure per-route secrets in config.yamlrC  zWebhooks enabled! Next steps:r   r  z   1. Define webhook routes in z/config.yamlz3   2. Point your service (GitHub, GitLab, etc.) at:z3      http://your-server:8644/webhooks/<route-name>z   Route configuration guide:z_   https://hermes-agent.nousresearch.com/docs/user-guide/messaging/webhooks/#configuring-routesr  )rc   rZ   re   r   r`   rg   r   rX   r   r   rf   r   r'  r  )r  r_  secretr>  s       r   _setup_webhooksr  N	  sS   ./H124e<	GXYYZVW	Gij	G/0D	E>3s4y>:078 CdSF'0,-]^$f-	G12<0EFDEDE	G./pq	GCDCD-  	ECD	Es   	,E9 9FFc           	      Z  ./ ddl m}m/m} t	        d       t        d       t        d       t                 |       }g }g }t        |      D ]D  \  }} /|      }|j                  |d    d|d    d	| d
       |dk(  s4|j                  |       F t        d||      }	|	st        d       y|	D ]  }
 |||
           dt        dt        fd.t        ./fd |       D              }|rt                t        d       t        d       g }t        d      rt        d      s|j                  d       t        d      rt        d      s|j                  d       t        d      rt        d      s|j                  d       t        d      rt        d      s|j                  d        t        d!      r't        d"      st        d#      s|j                  d$       |rlt                t        d%d&j!                  |              t        d'       t        d(       t        d)       |D ]  }t        d*|j#                          d+       ! ddl}|j'                         d,k(  }|j'                         d-k(  }|j'                         d.k(  }dd/l m}m}m}m}m}m}m}m}m}m}m}m}m }m!}m"}m#} m$}!  |       }" |       }# |       }$|$xs |xs |}%t                |$r |       r |        t                |$r |       r |        t                |#rO|$r |        r
 |!d0       ntK        d1d2      r	 |$r |        n"|r |        n|rdd3l&m'}& |&jQ                          nm|"rO|$r |        r
 |!d7       nXtK        d8d2      rK	 |$r |        n"|r |        n|rdd3l&m'}& |&jY                          n|%r|$rd;})n|rd<})nd=})tK        d>|) d?d2      rt	 d}*d@}+d@},|$r |d@A      \  }*}+n*|r |d@A       d2}+ndd3l&m'}& |&j[                  d@A       d2}+d2},t                |+r'|,s%tK        dBd2      r	 |$r ||*dCk(  D       n	|r |        nt        dG       |$rt        dH       t        dI       nfddJl.m/}-  |-       rCt        dK       t        dL       t        dM       t        dN       t        dO       t        dP       nt        dK       t        dQ       t        d       yy# |$ rA}'tS        d4       t        |'      jU                         D ]  }(t        d5|(         Y d}'~'Nd}'~'w|$ r }'tS        d6|'         |!d0       Y d}'~'qd}'~'wtV        $ r}'tS        d6|'        Y d}'~'d}'~'ww xY w# |$ rA}'tS        d9       t        |'      jU                         D ]  }(t        d5|(         Y d}'~'d}'~'w|$ r }'tS        d:|'         |!d7       Y d}'~'d}'~'wtV        $ r}'tS        d:|'        Y d}'~'d}'~'ww xY w# |$ rB}'tS        d9       t        |'      jU                         D ]  }(t        d5|(         Y d}'~'d}'~'w|$ r!}'tS        d:|'         |!d7       Y d}'~'d}'~'wtV        $ r}'tS        d:|'        Y d}'~'5d}'~'ww xY w# tV        $ r$}'tS        dE|'        t        dF       Y d}'~'d}'~'ww xY w)Rz*Configure messaging platform integrations.r   )_all_platforms_platform_status_configure_platformMessaging PlatformszAConnect to messaging platforms to chat with Hermes from anywhere.z&Toggle with Space, confirm with Enter.emojir   r,  z  (r   
configuredzSelect platforms to configure:zENo platforms selected. Run 'hermes setup gateway' later to configure.Nstatusr   c                 z    | j                         }|dk(  xs$ |j                  d      xs |j                  d       S )Nnot configured	partiallyzplugin disabled)rK   r  )r  ss     r   _is_progressz#setup_gateway.<locals>._is_progress	  sC    LLN!! /||K(/||-.
 	
r   c              3   :   K   | ]  }  |              y wrt   r  )r  pr
  r   s     r   r  z setup_gateway.<locals>.<genexpr>	  s!      ./%a()s   u   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━zMessaging platforms configured!r  r  r  r  r  r  r  r  r  r  r  BlueBubbles	QQ_APP_IDQQBOT_HOME_CHANNELQQ_HOME_CHANNELQQBotzNo home channel set for: r   z7   Without a home channel, cron jobs and cross-platformz2   messages can't be delivered to those platforms.z1   Set one later with /set-home in your chat, or:z     hermes config set z_HOME_CHANNEL <channel_id>r  DarwinWindows)_is_service_installed_is_service_runningsupports_systemd_serviceshas_conflicting_systemd_unitshas_legacy_hermes_units install_linux_gateway_from_setup$print_systemd_scope_conflict_warningprint_legacy_unit_warningsystemd_startsystemd_restartlaunchd_installlaunchd_startlaunchd_restartUserSystemdUnavailableErrorSystemScopeRequiresRootError$_system_scope_wizard_would_need_root_print_system_scope_remediationrestartz)  Restart the gateway to pick up changes?T)gateway_windowsu0     Restart failed — user systemd not reachable:r   z  Restart failed: rm  z  Start the gateway service?u.     Start failed — user systemd not reachable:z  Start failed: systemdlaunchdzScheduled Taskz  Install the gateway as a z. service? (runs in background, starts on boot)F)forcez  Start the service now?r4  )r4  z  Install failed: z.  You can try manually: hermes gateway installz/  You can install later: hermes gateway installzA  Or as a boot-time service: sudo hermes gateway install --systemz'  Or run in foreground:  hermes gateway)is_containerz,Start the gateway to bring your bots online:z>   hermes gateway run          # Run as container main processrJ   z4For automatic restarts, use a Docker restart policy:z*   docker run --restart unless-stopped ...z/   docker restart <container>  # Manual restartz2   hermes gateway              # Run in foreground)0r  r  r   r  rc   re   r`   r   r  r   r   r   anyrf   rZ   rg   r   upperr  r4  r  r  r  r  r  r  r  r  r  r  r  r  r   r!  r"  r#  r$  r   
hermes_clir&  r%  rd   r<  r   rm  r  r'  r*  )0r   r  r  	platformsr   r   r   platr  r   r   any_messagingmissing_homer?  	_is_linux	_is_macos_is_windowsr  r  r  r  r  r  r  r  r  r  r  r  r   r!  r"  r#  r$  service_installedservice_runningsupports_systemdsupports_service_managerr&  r  linesvc_nameinstalled_scopedid_installstarted_inliner*  r
  r   s0                                                 @@r   setup_gatewayr>  }	  sw   XX&'RS78	G I ELY' #4!$'WaWc&CD\!"	#   @%VHZ[ ,IcN+,
S 
T 
  3A3C M :78 -.}#8
 
+,-m"7
 	**+MBV4W(12=Ic;d.%./=AR3S(G5dii6M5NOPPQKLJK$ -djjl^;UV 	%$$&'1	$$&(2	&&(I5	
 	
 	
 	
 	
( 23-/46#3#Oy#OK  = ?02G 7 9%'G$H$J/	:JDQ:'')"')$>'//1 $H$J/8=tD8'%"%$>'--/ &$$+-hZ7ef$Q&*O"'K%*N'7W^c7d4"'e4&* ?'//e/<&*)-G">mLfhl>m@/ -_5P Q!* - LM#bcDE5~IJ[\2QRGHLMIJOP:y p 3 + RS #A 1 1 3 +4&k*+3 ?
  "4QC 893I>>  :"4QC 899: 3 + PQ #A 1 1 3 +4&k*+3 ="21# 673G<<  8"21# 6778L  ; 3'(XY(+A(9(9(; 3 %4&k 23; E'*:1#(>?;GDD( @'*:1#(>??@  Q"4QC 89OPPQs   0,S ,U# AY= (W/ U 7TU !T<<U UU #W,(7V$$W,,WW,W''W,/Y:47X1+Y= 1Y:9YY= Y:!Y5/Y= 5Y::Y= =	Z*Z%%Z*first_installc                 $    ddl m}  |||        y)u  Configure tools — delegates to the unified tools_command() in tools_config.py.

    Both `hermes setup tools` and `hermes tools` use the same flow:
    platform selection → toolset toggles → provider/API key configuration.

    Args:
        first_install: When True, uses the simplified first-install flow
            (no platform menu, prompts for all unconfigured API keys).
    r   )tools_command)r?  r   N)hermes_cli.tools_configrA  )r   r?  rA  s      r   setup_toolsrC  m
  s     6f=r   c                    	 ddl m}  |       ry	 	 ddl m} dt        fd}t        | t              r| j                  d      nd}t        |t              rZ|j                  d	      xs d
j                         j                         }||v r |||         ry|dk(  rdD ]  }t        |      s y dD ]  }t        |      s y |j                         D ]  \  }}|dk(  r ||      s y y# t        $ r Y w xY w# t        $ r i }Y w xY w)u  Return True when any known inference provider has usable credentials.

    Sources of truth:
      * ``PROVIDER_REGISTRY`` in ``hermes_cli.auth`` — lists every supported
        provider along with its ``api_key_env_vars``.
      * ``active_provider`` in the auth store — covers OAuth device-code /
        external-OAuth providers (Nous, Codex, Qwen, Gemini CLI, ...).
      * The legacy OpenRouter aggregator env vars, which route generic
        ``OPENAI_API_KEY`` / ``OPENROUTER_API_KEY`` values through OpenRouter.
    r   get_active_providerTr&   r   c                 L    | j                   D ]  }|dk(  r	t        |      s y y)NCLAUDE_CODE_OAUTH_TOKENTF)api_key_env_varsrZ   )r,   env_vars     r   _has_keyz0_model_section_has_credentials.<locals>._has_key
  s5    // 	G 33W%	 r   r   Nr   rJ   r%   )r   r   r;   F)r*   rF  r   r'   r   r   r   r   r   rK   rZ   r   )	r   rF  r'   rK  	model_cfgprovider_idrJ  pidr,   s	            r   _model_section_has_credentialsrO  
  s4   7  !
5T  (2&$'?

7#TI)T" }}Z06B==?EEG++)+67,&C   ) 
 < ! *//1 W )G Y  
  s"   C, C; ,	C87C8;D	D	r,  c                 T    | j                  dd      d   j                         }|xs | S )zFStrip trailing parenthetical qualifiers from a gateway platform label.(r   r   )r  r   )r,  bases     r   _gateway_platform_short_labelrS  
  s*    ;;sAq!'')D=5r   section_keyc                     |dk(  rt        |       sy| j                  d      }t        |t              r |j	                         r|j	                         S t        |t
              r1t        |j                  d      xs |j                  d      xs d      S y|dk(  rt        | ddd      }d	| S |d
k(  rt        | d
dd      }d| S |dk(  rOddlm}m	}  |       D cg c]#  } ||      r ||      dk7  rt        |d         % }}|rdj                  |      S y|dk(  rjg }	t        d      r|	j                  d       t        d      r|	j                  d       t        d      r|	j                  d       |	rdj                  |	      S yyc c}w )a)  Return a short summary if a setup section is already configured, else None.

    Used after OpenClaw migration to detect which sections can be skipped.
    ``get_env_value`` is the module-level import from hermes_cli.config
    so that test patches on ``setup_mod.get_env_value`` take effect.
    r   Nr   r  r   r   r  r   z	backend: rH   rg  rf  zmax turns: gatewayr   )r  r   r  r,  r   r   r   zTTS/ElevenLabsBROWSERBASE_API_KEYBrowserFIRECRAWL_API_KEY	Firecrawl)rO  r   r   r   r   r   rQ   r  r  r   rS  r   rZ   r  )
r   rT  r   r   rg  r  r   r/  r  r   s
             r   _get_section_config_summaryr[  
  s    g-f5

7#eS!ekkm;;= eT"uyy+Quyy/AQ\RR	
	"&*iI7)$$		FG["E	YK((			!G '(
%*:4*@DT*T *$w-8

 

 99Z((		-.LL)*./LL#,-LL%99U##+
s   (Fc                     t        | |      }|syt                t        d| d|        t        d|j	                          dd       S )zShow an already-configured section summary and offer to skip.

    Returns True if the user chose to skip, False if the section should run.
    Fr   r   z  Reconfigure ?r   )r[  r`   rf   r   rK   )r   rT  r,  summarys       r   _skip_configured_sectionr_  
  sO     *&+>G	GBugRy)*~ekkm_A>NNNr   zoptional-skills	migrationzopenclaw-migrationscriptszopenclaw_to_hermes.pyc                     t         j                         syt        j                  j	                  dt               } | | j
                  yt        j                  j                  |       }ddl}||j                  | j                  <   	 | j
                  j                  |       |S # t        $ r( |j                  j                  | j                  d        w xY w)zLoad the openclaw_to_hermes migration script as a module.

    Returns the loaded module, or None if the script can't be loaded.
    Nopenclaw_to_hermesr   )_OPENCLAW_SCRIPTrw  r6  r   spec_from_file_locationloadermodule_from_specr   modulesr   exec_moduler   r  )specmod_syss      r   _load_openclaw_migration_modulerm    s    
 ""$>>11.D |t{{*
..
)
)$
/C !DLL$ J  D)s   B# #1Cu\   ⚠ Gateway/messaging — this will configure Hermes to use your OpenClaw messaging channelsuE   ⚠ Telegram — this will point Hermes at your OpenClaw Telegram botuE   ⚠ Slack — this will point Hermes at your OpenClaw Slack workspaceuC   ⚠ Discord — this will point Hermes at your OpenClaw Discord botuL   ⚠ WhatsApp — this will point Hermes at your OpenClaw WhatsApp connectionuM   ⚠ Config values — OpenClaw settings may not map 1:1 to Hermes equivalentsuO   ⚠ Instruction file — may contain OpenClaw-specific setup/restart proceduresuJ   ⚠ Memory/context file — may reference OpenClaw-specific infrastructureu?   ⚠ Context file — may contain OpenClaw-specific instructions)	rV  telegramslackdiscordwhatsappr   soulmemorycontextreportc                    | j                  dg       }|st        d       y|D cg c]  }|j                  d      dk(  s| }}|D cg c]  }|j                  d      dk(  s| }}|D cg c]  }|j                  d      dk(  s| }}t               }|rt        t	        dt
        j                               |D ]  }|j                  d	d
      }|j                  dd      }	|	rIt        |	      j                  t        t        j                               d      }
t        d|dd|
        nt        d|        |j                         }t        |	      j                         }t        j                         D ]  \  }}||v s||v s|j                  |       !  t                |rjt        t	        dt
        j                               |D ]8  }|j                  d	d
      }|j                  dd      }t        d|dd|        : t                |rjt        t	        dt
        j                                |D ]8  }|j                  d	d
      }|j                  dd      }t        d|dd|        : t                |rt        t	        dt
        j                               t#        |      D ](  }t        t	        d| t
        j                               * t                t        t	        dt
        j                               t        t	        dt
        j                               t        t	        dt
        j                               t                yyc c}w c c}w c c}w )zPrint a detailed dry-run preview of what migration would do.

    Groups items by category and adds explicit warnings for high-impact
    changes like gateway token takeover and config value differences.
    r   zNothing to migrate.Nr  migratedconflictskippedz  Would import:kindunknowndestinationrJ   ~r  z<22s    → z:  Would overwrite (conflicts with existing Hermes config):r   zalready existsr   z  Would skip:u     ── Warnings ──z    zF  Note: OpenClaw config values may have different semantics in Hermes.uM     For example, OpenClaw's tool_call_execution: "auto" ≠ Hermes's yolo mode.zL  Instruction files (.md) from OpenClaw may contain incompatible procedures.)r   re   r   r`   r]   r\   r   r   rv   r   r5  rK   _HIGH_IMPACT_KIND_KEYWORDSr   addr   r   r   )ru  r   r   migrated_itemsconflict_itemsskipped_itemswarnings_shownitemrz  dest
dest_short
kind_lower
dest_lowerkeywordwarningr   s                   r   _print_migration_previewr  E  s    JJw#E()!&HA!%%/Z*GaHNH!&HA!%%/Z*GaHNH %F1xI)EQFMFUNe%v||45" 	0D88FI.D88M2.D Y..s499;/?E
tDkzl;<tfo& JT*J$>$D$D$F 0 j(Gz,A"&&w/0	0 	ePRXR_R_`a" 	2D88FI.DXXh(89FF4+Rx01	2 	eOVZZ01! 	2D88FI.DXXh+FF4+Rx01	2 	 e.>?n- 	:G%$wi(&--89	:e\^d^k^klmeegmgtgtuvebdjdqdqrs U IHFs"   MM	M!#M!-M&M&r(  c                 2   t        j                         dz  }|j                         syt        j	                         syt                t        d       t        d|        t        d       t                t        dd      st        d	       yt               }|j	                         st        t                      	 t               }|t        d       y	 	 |j#                  d
d
d      }|j%                  |j'                         | j'                         dd
ddd
|d	      }|j)                         }|j+                  di       }|j+                  dd      }	|	dk(  rt                t        d       yt                t        d|	 d       t        d       t                t-        |       t        dd      st        d       t        d       y	 |j%                  |j'                         | j'                         dd
ddd
|d	      }
|
j)                         }|j+                  di       }|j+                  dd      }|j+                  d d      }|j+                  d!d      }|j+                  d"d      }t                |rt/        d#| d$       |rt        d%| d&       |rt        d%| d'       |rt        | d(       |j+                  d)      }|rt        d*|        t/        d+       y# t        $ r/}t        d|        t        j!                  dd       Y d
}~yd
}~ww xY w# t        $ r/}t        d|        t        j!                  dd       Y d
}~yd
}~ww xY w# t        $ r/}t        d|        t        j!                  dd       Y d
}~yd
}~ww xY w),a  Detect ~/.openclaw and offer to migrate during first-time setup.

    Runs a dry-run first to show the user exactly what would be imported,
    overwritten, or taken over. Only executes after explicit confirmation.

    Returns True if migration ran successfully, False otherwise.
    z	.openclawFzOpenClaw Installation DetectedzFound OpenClaw data at zDHermes can preview what would be imported before making any changes.z+Would you like to see what can be imported?Tr   zLSkipping migration. You can run it later with: hermes claw migrate --dry-runNz Could not load migration script.z!Could not load migration script: z$OpenClaw migration module load error)exc_infofull)preset)	source_roottarget_rootexecuteworkspace_target	overwritemigrate_secrets
output_dirselected_optionspreset_namezMigration preview failed: z OpenClaw migration preview errorr^  rw  r   z Nothing to import from OpenClaw.u   Migration Preview — z item(s) would be importedz5No changes have been made yet. Review the list below:zProceed with migration?zCMigration cancelled. You can run it later with: hermes claw migratezIUse --dry-run to preview again, or --preset minimal for a lighter import.zMigration failed: zOpenClaw migration errorry  rx  errorz	Imported z item(s) from OpenClaw.zSkipped zU item(s) that already exist in Hermes (use hermes claw migrate --overwrite to force).z" item(s) (not found or unchanged).u3    item(s) had errors — check the migration report.r  zFull report saved to: z,Migration complete! Continuing with setup...)r   r5  is_dirrd  rw  r`   rc   re   r   rT   rW   rV   rm  rg   r   r  r  resolve_selected_optionsMigratorrs  migrater   r  rf   )r(  openclaw_dirconfig_pathrk  r  r   dry_migratorpreview_reportpreview_summarypreview_countmigratorru  r^  rw  ry  	conflictserrorsr  s                     r   _offer_openclaw_migrationr    s    99;,L ""$	G12(78UV	GFPTUZ	
  "#KKM"-/;<= //d6/J||$,,.#++-! % $ 

 &--/ %((B7O#''
A6M56	G)-8RSTFG	G^, 2EBQ	
 	W	
 <<$,,.#++-! %   

 !!# jjB'G{{:q)Hkk)Q'GJ*I[[!$F	G	(+BCDXi[(}~XgY&HIJ STUL)J+J<89@Ay  9!=>;dK(  21#677$GZ  *1#.//$?sJ   =K( AL# AM (	L 1%LL #	M,%MM	N'%NNr   Model & Providerr   zText-to-Speechr   r  rV  zMessaging Platforms (Gateway)r   ToolsrH   rx  c                 @   ddl m}m}  |       r	 |d       yt                t	        t        | dd            }|r-t        t        j                  t                     t        d       t	        t        | dd            }t	        t        | d	d            }t               }t               }t               }|j                         rPdd
lm}	 |j!                  d|	j#                         j%                  d             }
	 ddl} |j(                  ||
       nd}
t        | dd      }|st-               sd}|rt/        d       yt        | dd      }|rt0        D ]  \  }}}||k(  st3                t3        t5        dt6        j8                               t3        t5        d|ddt6        j8                               t3        t5        dt6        j8                                ||       t        |       t3                t        | d        y t;        d|        t=        ddj?                  d t0        D                      yddl m!}  |       }t	        tE        d            xs t	        tE        d            xs |du}t3                t3        t5        dt6        j8                               t3        t5        dt6        j8                               t3        t5        dt6        j8                               t3        t5        d t6        j8                               t3        t5        d!t6        j8                               t3        t5        dt6        j8                               d}|rg|rtG        ||       yt3                tI        d"       t        d#       t=        d$       t=        d%       t=        d&       t=        d'       t=        d(       n\t3                |s|rt=        d)       t3                tK        |      }|r
t               }tM        d*d+d,gd      }|dk(  rtO        |||       ytI        d-       t=        d.t                       t=        d/tQ                       t=        d0|        t=        d1tR                t3                t=        d2       |r+t3                t=        d3       t=        d4       t=        d5       |rtU        |d6d7      stW        |       |rtU        |d8d9      stY        |       |rtU        |d:d;      st[        |       |rtU        |d<d=      st]        |       |rtU        |d>d?      st_        || @       t        |       |
r:|
j                         r*t=        dA|
        t=        dB       t=        dC|
 dD|        ta        ||       y# t*        $ r d}
Y w xY w)Eu  Run the interactive setup wizard.

    Supports full, quick, and section-specific setup:
      hermes setup           — full or quick (auto-detected)
      hermes setup model     — just model/provider
      hermes setup tts       — just text-to-speech
      hermes setup terminal  — just terminal backend
      hermes setup gateway   — just messaging platforms
      hermes setup tools     — just tool configuration
      hermes setup agent     — just agent settings
    r   )
is_managedmanaged_errorzrun setup wizardNresetFz Configuration reset to defaults.reconfigurer  )datetimez
.yaml.bak.z%Y%m%d_%H%M%Snon_interactiveTz;Running in a non-interactive environment (no TTY detected).sectionr  u   │     ⚕ Hermes Setup — z<34su    │r  z configuration complete!zUnknown setup section: zAvailable sections: r   c              3   (   K   | ]
  \  }}}|  y wrt   r  )r  kr	  s      r   r  z#run_setup_wizard.<locals>.<genexpr>i  s     3T'!QA3Ts   rE  r   OPENAI_BASE_URLu@   │             ⚕ Hermes Agent Setup Wizard                │u   ├─────────────────────────────────────────────────────────┤u>   │  Let's configure your Hermes Agent installation.       │u>   │  Press Ctrl+C at any time to exit.                     │Reconfigurez#You already have Hermes configured.uA   Running the full wizard — each prompt shows your current value.z9Press Enter to keep it, or type a new value to change it.rJ   zBTip: jump straight to a section with 'hermes setup model|terminal|zC     gateway|tools|agent', or fill only missing items with --quick.u=   No existing configuration found — running first-time setup.z$How would you like to set up Hermes?u9   Quick setup — provider, model & messaging (recommended)u#   Full setup — configure everythingzConfiguration LocationzConfig file:  zSecrets file: zData folder:  zInstall dir:  z=You can edit these files directly or use 'hermes config edit'z%Settings were imported from OpenClaw.uG   Each section below will show what was imported — press Enter to keep,z#or choose to reconfigure if needed.r   r  r   r  rH   rx  rV  r  r   r  )r?  zPrevious config backed up to: z9If setup changed a value you customized, restore it with:z  cp r   )1r  r  r  r[   r   r   rW   copydeepcopyrR   rf   rV   rS   rT   rw  r  with_suffixnowstrftimer  copy2r   r   r   SETUP_SECTIONSr`   r]   r\   MAGENTArd   re   r   r*   rF  rZ   _run_quick_setuprc   r  r   _run_first_time_quick_setuprU   PROJECT_ROOTr_  r  rd  r  r>  rC  r?  )argsr  r  reset_requestedreconfigure_requestedquick_requestedr   r(  r  _dt_backup_pathr  r  r  r  r,  funcrF  active_provideris_existingmigration_ran
setup_modes                         r   run_setup_wizardr    s.    <|()74%89ODMM.1289 }e!DE74%89O]F!#K "#K,"..++O<=>
	 FLLl3  d$5u=O#7#9+I	
 	 dIt,G . 	Cg~ L e;E$<tLfnn]^ L VF#'?@A)	, 	-gY78)$))3T^3T*T)UVW 4)+O]/01 	'/01	'$&  
G	 @NN	
 
NPVP^P^	

 
 @NN	
 
Lfnn	

 
Lfnn	

 
 @NN	
 M V[1]#;<VWNO2WXXY 	 !OVWG 2+> ]F"#IG1L
 

 ?'[I )* 1234/01}-.~./	GNO:;\]89 6vwHZ[V$ 6vzK]^v& 6vwHXYV$ 6vyJ_`f 6vwPFk/: ++-3L>BCNOU<.+78-e  	 L	 s   :V VVr  c                 h   t        | d       t        |        t        |        t        |        t	                t        dddgd      }|dk(  rt        |        t        |        t	                t        d       t	                t        d       |dk7  rt        d	       t	                t        | |       y
)u   Streamlined first-time setup: provider, model, terminal & messaging.

    Applies sensible defaults for TTS (Edge), agent settings, and tools —
    the user can customize later via ``hermes setup <section>``.
    Tr  ro   rp   rq   r   z#Setup complete! You're ready to go.z)  Configure all settings:    hermes setupz1  Connect Telegram/Discord:  hermes setup gatewayN)
r  rd  rv  rW   r`   r   r>  rf   re   r?  )r   r(  r  gateway_choices       r   r  r    s     t, 6" "&) 
G"A0?	
 	
N fF	G78	G:;FG	G-r   c           
      
   ddl m}m}m} t	                t        d        |d      D cg c]  }|j                  d      s| }} |d      D cg c]  }|j                  d      r| }} |       } |       \  }	}
|xs |xs	 |xs |	|
k  }|s,t        d       t	                t        d       t        d	       y
|rIt	                t        t        |       d       |D ]  }t	        d|d            t	                |D ]   }t	                t	        t        d|d    t        j                               t        d|j                  dd              |j                  d      rt        d|d           |j                  d      r$t        d|j                  d|d          d      }n!t        d|j                  d|d                }|r!t        |d   |       t        d|d           t        d|d            |D cg c]  }|j                  d      dk(  s| }}|D cg c])  }|j                  d      dk(  r|j                  d      s|+ }}|rt	                t        d       g }|D ]W  }|j                  dg       }|rdd j!                  |d
d!        nd}|j#                  |j                  d|d          |        Y t%        d"|      }|D ]  }||   }t'        |        |rt	                t        d#       t        d$       t        d%       g }i }|D ]S  }|d   }d&|v rd'}nd(|v rd)}nd*|v rd+}n||vr|j#                  |       |j)                  |g       j#                  |       U |D cg c]  }d,d-d.d/j                  ||       }}t%        d0|      }|D ]0  }||   }||   }d1d2d3d/j                  |d      }t	                t	        t        d4| d5| d6t        j                               t	                |D ]  }t        d|j                  dd              |j                  d      rt        d|d           |j                  d      r$t        d|j                  d|d          d      }n!t        d|j                  d|d                }|rt        |d   |       t        d7       nt        d8       t	                 3 |rPt	                t        d9t        |       d:       |D ]  }t        d;|d<    d=|d>            |
| d?<   t+        |        t-        | |       y
c c}w c c}w c c}w c c}w c c}w )@u6   Quick setup — only configure items that are missing.r   )get_missing_env_varsget_missing_config_fieldscheck_config_versionu"   Quick Setup — Missing Items OnlyF)required_onlyis_requiredz(Everything is configured! Nothing to do.z:Run 'hermes setup' and choose 'Full Setup' to reconfigure,z)or pick a specific section from the menu.Nz required setting(s) missing:u	        • r   r   r   rJ   r   z  Get key at: r   r   Tr   z  Saved z
  Skipped categorytool	messagingadvancedzTool API Keysr   r~  r   r  z(Which tools would you like to configure?r  z7Connect Hermes to messaging apps to chat from anywhere.z:You can configure these later with 'hermes setup gateway'.TELEGRAMr  DISCORDr  SLACKr  u   📱 Telegramu   💬 Discordu
   💼 Slack)r  r  r  z)Which platforms would you like to set up?u   📱u   💬u   💼r   r   r   r   z	  SkippedzAdding z& new config option(s) with defaults...z  Added r  z = r   _config_version)r  r  r  r  r`   rc   r   rf   re   r   r]   r\   ra   r   rX   rg   r   r  r   r   rK  rW   r?  )r   r(  r  r  r  vmissing_requiredmissing_optionalmissing_configcurrent_ver
latest_verhas_anything_missingr   r   missing_toolsmissing_messagingchecklist_labelsr   r   selected_indicesr   platform_orderr.  r   r/  r  platform_labels	vars_listr  fields                                 r   r  r    s     
G56 (e<m@T  (e<AEE-DX  /0N24K 	 	$	$	$ #	   @AOP>? c*+,,IJK# 	-CIc&k]+,	-# 	:CG%"S[M*FKK89CGGM26789wwu~^CJ<89wwz"CGGHc&k$B#CDtTCGGHc&k$B#CDEs6{E2V67
3v;-89!	:& !1P1AEE*4E4OQPMP "55+AEE*4E 	
  _%  	YCGGGR(E:?%		%) 456RI##sww}c&k'J&KI;$WX	Y
 ,6

 $ 	!C$CC 	!
 *+LMOP 	$ 	7Cv;DT!!d" D9$%%d+  r*11#6	7( $
 	 ,)% c!Qi	
 
 ,7

 $ 	C!#&D!$I!'FVLPPQUWYZEG%,ugQtfJ?MNG  Rr :;<=775>CJ<0177:&"R#f+(F'G#HSWXE"R#f+(F'G#HIE"3v;6!-0!+.	. c.)**PQ	
 $ 	JEHU5\N#eI6F5GHI	J %/ !F -o^ Qd
s/   U
U
U*UU*U4.U
Urt   )NF)r   N)T)F)x__doc__r"  r6  rx  loggingr=  r  r  r   r  pathlibr   typingr   r   r   hermes_cli.nous_subscriptionr   r7  r   utilsr	   r'  r
   	getLogger__name__r  __file__ru  rs  r  r  r   r   r   r"   r   r-   _DEFAULT_PROVIDER_MODELSrM   rP   r  rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   hermes_cli.colorsr\   r]   rc   hermes_cli.cli_outputrd   re   rf   rg   ru   rz   r|   r   r   r   r   r   r   compiler   r   listr   r   r   r   r   r   r   r?  rV  rl  rd  r  r  r  r  r  r  rd  rv  r  r  r  r  r  r  r  r  r  r  r  r>  rC  rO  rS  r[  r_  rd  rm  r  r  r  r  r  r  r  r  r   r   <module>r     s      	 	  
   & & G A # 4			8	$H~$$++3359
tCH~ $sCx. DDcN DtCH~ D
6$sCx. 6C 6SV 6[_ 6
A 
A 
A" 	 GZ] "78PMPw _} E' Td38n  +$sCx. +# +$ +    ,; ;  &      # # 6588d d
 d &S 3  # . &2::&DE 3# 3# 3mC m$ m mWZ]aWa mmp m(C ($ ( (sUYz (eh (V/C /$ /$ /2C  D D :I I8_ _D	' 'TB/D B/Jt tCH~ J 9> Y$ Y$ Y$BW$ W
/d /d 2DU DUN d  hB4 hB`A$ A:i ibDBN3=l  ACH(
VS:l)EX>VB,E^h$ h`> >T >(;4 ;D ;|  4 43 48C= 4nOO"O+.O	O* L+<<=  	 @ nWTT^]]ZP
 =T =@B4 BD BT  "67
i(#%;</?g{# 45Y.x(. (. (.Vc.T c.r   