
    `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y)z9Shared CLI/TUI-safe helpers for background MCP discovery.    )annotationsN)nullcontext)OptionalFzOptional[threading.Thread]_mcp_discovery_threadc                     	 ddl m}   |        xs i j                  d      }t        |t              xr t        |      dkD  S # t        $ r Y y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     I/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/mcp_startup.py_has_configured_mcp_serversr      sR    5&(.B33MB+t,E[1AA1EE  s   ?A 	AAc                     t         5  t        r
	 ddd       ydat               s
	 ddd       yd fd}t        j                  ||d      }|a|j                          ddd       y# 1 sw Y   yxY w)zBSpawn one shared background MCP discovery thread for this process.NTc                 `    	 t                y # t        $ r  j                  dd       Y y 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&   s1    T=? TCdSTs   
 --)targetnamedaemonreturnNone)_mcp_discovery_lock_mcp_discovery_startedr   	threadingThreadr   start)r   thread_namer   threads   `   r   start_background_mcp_discoveryr&      sz     
 !  "&*, 	T !!

 !''  s   A(A(0A((A1c                    | | S 	 ddl m}m} t        |j	                  dd            } |       xs i j	                  d|      }t        |      }|dkD  r|S |S # t
        $ r Y y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.
    r   )load_configDEFAULT_CONFIGmcp_discovery_timeoutg      ?)r
   r(   r)   floatr   r   )explicitr(   r)   defaultrawvals         r   _resolve_discovery_timeoutr0   5   su     A**+BCHI}"''(?ICjAgs*7* s   AA A 	A$#A$c                     	 ddl m}   |        5  ddlm}  |        ddd       y# t        $ r	 t        } Y /w xY w# 1 sw Y   yxY w)zCRun MCP discovery without letting OAuth read from the user's stdin.r   )suppress_interactive_oauth)discover_mcp_toolsN)tools.mcp_oauthr2   r   r   tools.mcp_toolr3   )r2   r3   s     r   r   r   J   sL    1> 
$	% 5   1%0"1 s   & ;88Ac                l    t         }||j                         sy|j                  t        |              y)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timeout)r   is_alivejoinr0   r8   r%   s     r   wait_for_mcp_discoveryr<   W   s.     #F~V__.
KK27;K<    c                 :    t         } | duxr | j                         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   r9   )r%   s    r   mcp_discovery_in_flightr?   g   s      #F3&//"33r=   c                Z    t         }|y|j                  |        |j                          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.
    Tr7   )r   r:   r9   r;   s     r   join_mcp_discoveryrA   v   s/     #F~
KKK    r=   )r   bool)r$   strr   r   )r,   'float | None'r   r+   r   )N)r8   rD   r   r   )r8   rD   r   rB   )__doc__
__future__r   r!   
contextlibr   typingr   Lockr   r    r   __annotations__r   r&   r0   r   r<   r?   rA    r=   r   <module>rL      sX    ? "  " $inn&  48 1 8
4*
= 4!r=   