
    (Gj                        U d Z ddlmZ ddlZddlmZ ddlmZ  ej                    Z	da
daded<   ddZddZddZddZdddZddZdddZdS ) z9Shared CLI/TUI-safe helpers for background MCP discovery.    )annotationsN)nullcontext)OptionalFzOptional[threading.Thread]_mcp_discovery_threadreturnboolc                     	 ddl m}   |             pi                     d          }t          |t                    ot          |          dk    S # t          $ r Y dS w xY w)zBCheap config probe so non-MCP users avoid importing the MCP stack.r   )read_raw_configmcp_serversT)hermes_cli.configr
   get
isinstancedictlen	Exception)r
   r   s     </home/rurouni/.hermes/hermes-agent/hermes_cli/mcp_startup.py_has_configured_mcp_serversr      s    555555&((.B33MBB+t,,E[1A1AA1EE    tts   AA 
AAthread_namestrNonec                    t           5  t          r	 ddd           dS dat                      s	 ddd           dS d fd}t          j        ||d          }|a|                                 ddd           dS # 1 swxY w Y   dS )zBSpawn one shared background MCP discovery thread for this process.NTr   r   c                 v    	 t                       d S # t          $ r                      dd           Y d S w xY w)Nz$Background MCP tool discovery failedT)exc_info)-_discover_mcp_tools_without_interactive_oauthr   debug)loggers   r   	_discoverz1start_background_mcp_discovery.<locals>._discover&   sZ    T=????? T T TCdSSSSSSTs    !88)targetnamedaemonr   r   )_mcp_discovery_lock_mcp_discovery_startedr   	threadingThreadr   start)r   r   r   threads   `   r   start_background_mcp_discoveryr(      s>    
  ! 	        "&*,, 	       	T 	T 	T 	T 	T 	T !
 
 

 !''                 s   	A=A=3A==BBexplicit'float | None'floatc                    | | S 	 ddl m}m} t          |                    dd                    } |            pi                     d|          }t          |          }|dk    r|n|S # t
          $ r Y dS w xY w)uy  Resolve the MCP discovery wait bound: explicit arg > config > default.

    Reads ``mcp_discovery_timeout`` from config.yaml, defaulting to the value in
    ``DEFAULT_CONFIG`` (single source of truth) when the key is absent. Kept lazy
    and fail-safe — a missing/invalid value or a broken config falls back to a
    short safe bound so startup can never hang or crash.
    Nr   )load_configDEFAULT_CONFIGmcp_discovery_timeoutg      ?)r   r-   r.   r+   r   r   )r)   r-   r.   defaultrawvals         r   _resolve_discovery_timeoutr3   5   s     AAAAAAAA**+BCHHII{}}"''(?IICjjAggss7*   sss   A#A* *
A87A8c                     	 ddl m}  n# t          $ r
 t          } Y nw xY w |             5  ddlm}  |             ddd           dS # 1 swxY w Y   dS )zCRun MCP discovery without letting OAuth read from the user's stdin.r   )suppress_interactive_oauth)discover_mcp_toolsN)tools.mcp_oauthr5   r   r   tools.mcp_toolr6   )r5   r6   s     r   r   r   J   s    1>>>>>>> 1 1 1%0"""1 
$	#	%	%  555555                 s   	 AAAtimeoutc                    t           }||                                sdS |                    t          |                      dS )u  Wait for background MCP discovery before the first tool snapshot.

    ``thread.join(timeout)`` returns the INSTANT discovery completes, so this
    only ever blocks for the real connect time of a still-pending server —
    users with no MCP servers or fast servers pay ~0s.  The bound (from
    ``mcp_discovery_timeout`` in config) just caps the wait so a dead server
    can't freeze startup; servers that miss it are picked up by the automatic
    late-binding refresh.
    Nr9   )r   is_alivejoinr3   r9   r'   s     r   wait_for_mcp_discoveryr?   W   sD     #F~V__..~
KK27;;K<<<<<    c                 @    t           } | duo|                                 S )a5  Return True if THIS module's background discovery thread is still running.

    Mirrors ``tui_gateway.entry.mcp_discovery_in_flight`` for the surfaces that
    start discovery through ``start_background_mcp_discovery`` here (the desktop
    app + dashboard WebSocket sidecar via ``tui_gateway/ws.py``, and
    ``hermes dashboard``).  Those processes populate THIS module's
    ``_mcp_discovery_thread``, not ``tui_gateway.entry``'s, so the late-refresh
    scheduler must consult both to decide whether a slow server's tools are
    still pending (see #51587).
    N)r   r<   )r'   s    r   mcp_discovery_in_flightrB   g   s#     #F3&//"3"33r@   c                n    t           }|dS |                    |            |                                 S )al  Block until THIS module's background discovery finishes, up to ``timeout``.

    Returns True if discovery has completed (thread absent or no longer alive),
    False if it is still running after the timeout.  Unlike
    ``wait_for_mcp_discovery`` this accepts an unbounded/long wait and reports
    the outcome, for the off-critical-path late-refresh waiter.
    NTr;   )r   r=   r<   r>   s     r   join_mcp_discoveryrD   v   s:     #F~t
KKK       r@   )r   r   )r   r   r   r   )r)   r*   r   r+   r!   )N)r9   r*   r   r   )r9   r*   r   r   )__doc__
__future__r   r$   
contextlibr   typingr   Lockr"   r#   r   __annotations__r   r(   r3   r   r?   rB   rD    r@   r   <module>rL      s   ? ? ? " " " " " "     " " " " " "      $in&&  48  8 8 8 8
 
 
 
   4   *
 
 
 
= = = = = 4 4 4 4! ! ! ! ! ! !r@   