
    `gjF                        d Z ddlm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ZdZddZdddZdd	d
	 	 	 	 	 	 	 	 	 	 	 	 	 ddZdd	 	 	 	 	 	 	 	 	 	 	 ddZddZy)u  ``hermes dashboard register`` — register a self-hosted dashboard OAuth client.

Automates what a user otherwise does by hand: open the Nous Portal
``/local-dashboards`` page in a browser, click "register", copy the
resulting ``agent:{id}`` OAuth client ID, and paste it into ``~/.hermes/.env``
as ``HERMES_DASHBOARD_OAUTH_CLIENT_ID``.

This command:
  1. Resolves a fresh Nous Portal access token from the existing login
     (``~/.hermes/auth.json``), refreshing it if needed. Fails fast with a
     "run `hermes setup`" hint when the user isn't logged in.
  2. POSTs to ``{portal}/api/oauth/self-hosted-client`` with that bearer
     token, which creates a SELF_HOSTED agent client owned by the caller's
     org and returns the fully-formed ``agent:{id}`` client_id.
  3. Writes ``HERMES_DASHBOARD_OAUTH_CLIENT_ID`` and (if absent)
     ``HERMES_DASHBOARD_PORTAL_URL`` into ``~/.hermes/.env`` idempotently.
  4. Prints a post-register hint explaining that the OAuth gate only engages
     on a non-loopback bind.

The portal endpoint is the NAS half of this feature (POST
/api/oauth/self-hosted-client). The ``agent:`` prefix is applied server-side,
so this client never needs to know the namespace convention.
    )annotationsN)Optional)-amberboldbravebrightcalmclevercosmiccrispdreamyeagerelectricfancygentlegoldenhappyhiddenjollykeenlivelylucidlunarmellowmerrymightynimblenoblepolishedquietquirkyrapidserenesharpshinysilentsnappysolarsprystellarsunnyswifttidyvividvibrantwittyzesty)+	albatrossantelopebadgerbeaconcometcondorcypressdolphinemberfalconferretgalaxyglacierharborheronibexjaguarkestrellanternlynxmeadownebulaocelotorchidotterpantherpetrelquasarravenreefsparrowsummittundravortexwalruswillowyarrowkeplerteslacuriehopperturinglovelacec                 l    t        j                  t               dt        j                  t               S )z?Return a human-readable ``adjective_noun`` name (Docker-style)._)randomchoice_NAME_ADJECTIVES_NAME_NOUNS     P/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/dashboard_register.py_generate_dashboard_namerf   <   s(    mm,-.ak0J/KLLrd   c                d   t        | t              r!| j                         r| j                  d      S 	 ddlm}m}  |d      xs i }|j                  d      }t        |t              r!|j                         r|j                  d      S t        |      j                  d      S # t        $ r Y yw xY w)u  Resolve the portal base URL for the registration request.

    Precedence:
      1. ``override`` — explicit ``--portal-url`` flag or
         ``HERMES_DASHBOARD_PORTAL_URL`` env (used for testing against a
         preview/staging portal). NOTE: the access token must be valid at
         this portal — it's minted by whatever portal you logged into, so an
         override only works if the token's issuer matches (e.g. you logged
         into the same staging/preview portal).
      2. The ``portal_base_url`` stored on the Nous login — this is the
         portal that issued the token, so it's the correct default target.
      3. The production default.
    /r   )DEFAULT_NOUS_PORTAL_URLget_provider_auth_statenousportal_base_urlhttps://portal.nousresearch.com)	
isinstancestrstriprstriphermes_cli.authri   rj   get	Exception)overrideri   rj   statebases        re   _resolve_portal_base_urlrx   A   s     (C X^^%5s##	1T'/52yy*+dC TZZ\;;s##*+22377 101s   AB# 	B# #	B/.B/g      .@)existing_client_idtimeoutc           	        |j                  d       d}i }|r||d<   |r||d<   |r||d<   t        j                  |      j                  d      }t        j
                  j                  ||dd|  d	d	d
      }		 t        j
                  j                  |	|      5 }
t        j                  |
j                         j                               }ddd       t'        t(              r|j                  d      st!        d      |S # 1 sw Y   7xY w# t        j                  j                  $ r}d}	 t        j                  |j                         j                               }|j                  d      xs |j                  d      xs d}n# t        $ r Y nw xY w|j                  dk(  rt!        d      ||j                  dk(  rt!        |xs d      |t!        d|j                   |rd| z         |dz         |d}~wt        j                  j"                  $ r!}t!        d| d|j$                         |d}~ww xY w)u  POST to the portal's self-hosted-client endpoint and return the JSON body.

    When ``existing_client_id`` is provided (the client_id this install
    persisted on a prior run), it is sent so the portal updates that existing
    dashboard record in place instead of minting a duplicate — this is what
    makes re-running ``hermes dashboard register`` idempotent. The portal
    falls back to creating a fresh client if the id no longer resolves to a row
    in the caller's org (stale/deleted), so passing it is always safe.

    ``name`` may be ``None`` on the idempotent update path (re-run without an
    explicit ``--name``): omitting it tells the portal to keep the name it
    already stored rather than overwriting it. It is required on the create
    path; the caller guarantees a value there.

    Raises RuntimeError with a user-facing message on any non-2xx response or
    transport failure.
    rh   z/api/oauth/self-hosted-clientnamecustom_redirect_uri	client_idzutf-8POSTzBearer zapplication/json)AuthorizationzContent-TypeAccept)datamethodheaders)rz   N error_descriptionerrori  z[Nous Portal rejected the access token (401). Try `hermes auth add nous` to re-authenticate.i  zBYour account is not permitted to register a self-hosted dashboard.zPortal returned HTTP z: zCould not reach Nous Portal at z6Portal returned an unexpected response (no client_id).)rq   jsondumpsencodeurllibrequestRequesturlopenloadsreaddecoder   	HTTPErrorrs   rt   codeRuntimeErrorURLErrorreasonrn   dict)access_tokenrl   r|   r}   ry   rz   urlbodyr   reqresppayloadexcdetailerr_bodys                  re   _register_self_hosted_clientr   ]   sc   4 ##C())F
GCDV&9"#.[::d""7+D
..
 
 &|n5.(
	 ! 	C ^^##C#9 	7Tjj!3!3!56G	7B gt$GKK,DSTTNG	7 	7<<!! 	zz#((*"3"3"56H01 <<( 
  		88s?A  88s? XW  #CHH:. &F8}0
 	,.0
 	 <<   -o->bM
	sb   ;!D 2DD D	D H>-G=0AF
	G=
	FG=FA'G== H>H99H>r   )
public_urlc                Z   ddl m}  |       }| }t                t        d| d       t        dt        |      z          |rt        dt        |      z          |rt        dt        |      z          t                t        d       t                |rC	 dd	lm}  ||      j                  xs d
}	t        d       t        d|	 d       t        d       n!t        d       t        d       t        d       t                t        d       t        d| d       y# t        $ r d
}	Y yw xY w)z7Print the success summary + the gate-engagement caveat.r   )get_env_pathz  Wrote to :z%    HERMES_DASHBOARD_OAUTH_CLIENT_ID=z     HERMES_DASHBOARD_PORTAL_URL=z     HERMES_DASHBOARD_PUBLIC_URL=u     Heads up — Nous login only *engages* on a non-loopback bind. A plain
  `hermes dashboard` (localhost) leaves the gate off and serves locally
  without auth, which is fine for your own machine.urlparsez	your-hostzB  To require Nous login on your registered host, run the dashboardz2  bound publicly (it must be reachable at https://z) and log inz  at its /login page.zE  To require Nous login (e.g. exposing on your LAN or a public host):z#    hermes dashboard --host 0.0.0.0u0     …then log in at the dashboard's /login page.zI  If the dashboard is already running, restart it to pick up the new env.z%  Manage or revoke this dashboard at z/local-dashboardsN)hermes_cli.configr   printro   urllib.parser   hostnamert   )
r~   rl   r}   wrote_portal_urlr   r   env_path_cidr   hosts
             re   _print_post_register_hintr      s    /~HD	G	Kz
#$	
1CI
=>033GGH03z?BC	G		>
 
G	-/099H[D 	RSB4&UV%&UV34@A	G	S 

//@@QR  	D	s   D D*)D*c                |   ddl m}m} ddlm}m}m}  |       r t        d       t        j                  d       	  |       }t        | dd      xs t        j                  j                  d      }t        t!        |t"              xr |j%                               }	t'        |      }
d}	  |d      }t!        |t"              r|j%                         xs d}nd}t        | dd      }|r|}n|rd}n
t)               }t        | dd      }	 t+        |
|||      }t#        d         }t#        |j                  d      xs |xs d      }t        |xr ||k(        }|rt        d| d       nt        d| d       	  |d|       d}d}d}	  |d      }|	r||
k7  }n| xr |
j/                  d      |k7  }|r	  |d|
       d}d}d}|rD	 ddlm}  ||      }|j4                  dv r'|j6                  r|j4                   d|j6                   }|rd}	  |d       }||k7  r	  |d |       d}t9        ||
|||r|!       yd!       y# |$ rR}t        |dd      rt        d       t        d	       nt        d
|        t        j                  d       Y d}~Ud}~wt        $ r.}t        d
|        t        j                  d       Y d}~d}~ww xY w# t        $ r d}Y 1w xY w# t,        $ r.}t        d|        t        j                  d       Y d}~d}~ww xY w# t        $ r<}t        d|        t        d|        t        j                  d       Y d}~d}~ww xY w# t        $ r d}Y w xY w# t        $ r Y w xY w# t        $ r d}Y w xY w# t        $ r d}Y w xY w# t        $ r Y w xY w)"z?Register a self-hosted dashboard OAuth client with Nous Portal.r   )	AuthErrorresolve_nous_access_token)get_env_value
is_managedsave_env_valueu   ✗ `hermes dashboard register` is not available in a managed/hosted install.
  The dashboard OAuth client is provisioned by the hosting platform.   relogin_requiredFu'   ✗ You're not logged into Nous Portal.zC  Run `hermes setup` (or `hermes auth add nous`) first, then retry.u2   ✗ Could not resolve a Nous Portal access token: N
portal_urlHERMES_DASHBOARD_PORTAL_URL HERMES_DASHBOARD_OAUTH_CLIENT_IDr|   redirect_uri)r   rl   r|   r}   ry   u   ✗ Registration failed: r~   r   u   ✓ Updated dashboard ""u   ✓ Registered dashboard "u>   ✗ Failed to write HERMES_DASHBOARD_OAUTH_CLIENT_ID to .env: z5  Set it manually:  HERMES_DASHBOARD_OAUTH_CLIENT_ID=rm   rh   Tr   )httphttpsz://HERMES_DASHBOARD_PUBLIC_URL)r~   rl   r}   r   r   )rr   r   r   r   r   r   r   r   sysexitgetattrrt   osenvironrs   boolrn   ro   rp   rx   rf   r   r   rq   r   r   schemenetlocr   )argsr   r   r   r   r   r   r   portal_overridecustom_portal_suppliedrl   ry   explicit_namer|   r}   resultr~   registered_nameupdated_existingr   default_portalexisting_portalshould_write_portalwrote_public_urlr   r   parsedexisting_public_urls                               re   cmd_dashboard_registerr      s&   DKK |S	

 	02* dL$7 2::>>%<O "?C(D_-B-B-D /?O "*+MN $c*/557?4!D&$/M
 	')!$=
-%+ 31
 F;'(I&**V,::;O >y,>> ''8:;*?*;1=>99E$ 6NO'(EF -@  QO$:$:3$?>$Q 	 	8/J#, J	-12F}} 11fmm &c&--A
 "	'"/0M"N *,<jI#'  '/)!1:
 8:U  3*E2;<WXFseLM B3%HI<  "!":  )#/0(  NseTUEi[QR,    		<  	J	  	'"&	'  s   I )K K& ;	L  M( 7M: 	AN
 N N. K
AJK##KKK#"K#&	L/#LL 	M%)1M  M%(M76M7:	NN
NNN+*N+.	N;:N;)returnro   )N)ru   Optional[str]r   ro   )r   ro   rl   ro   r|   r   r}   r   ry   r   rz   floatr   r   )r~   ro   rl   ro   r}   r   r   r   r   ro   r   None)r   r   )__doc__
__future__r   r   r   r_   r   urllib.errorr   urllib.requesttypingr   ra   rb   rf   rx   r   r   r   rc   rd   re   <module>r      s   0 #  	  
    M
1D )-SS S 	S
 'S &S S 
Sx 00 0 '	0
 0 0 
0fErd   