+
    lHàj#  ã                  ó4  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
Ht ^ RIHtHt ^ RIHt ^ RIHtHt ]P(                  ! ]4      t]R R l4       tR	 R
 lt] ! R R4      4       t]P4                  ! RRR7      tR]R&   R R ltR R ltR# )zúDashboard-mediated callback bridge for MCP OAuth: the SDK still does discovery, DCR, PKCE, state
validation and token exchange; this only moves the two human/browser callbacks from a loopback
listener into the already-authenticated dashboard session.)ÚannotationsN)Úcontextmanager)Ú	dataclassÚfield)ÚIterator)Úparse_qsÚurlparsec               ó    € V ^8„  d   QhRRRR/# )é   Úvarzcontextvars.ContextVarÚreturnzIterator[None]© )Úformats   "Ú>/home/ubuntu/.hermes/hermes-agent/tools/mcp_dashboard_oauth.pyÚ__annotate__r      s   € ÷ ñ Ð.ð ¸.ñ ó    c              #  óˆ   "  € V P                  V4      p Rx € V P                  V4       R#   T P                  T4       i ; i5i)zGSet *var* to *value* for the block, restoring the previous value after.N)ÚsetÚreset)r   ÚvalueÚtokens   && r   Úcontextvar_setr      s4   é € ð �G‰G�E‹N€EðÛà�	‰	�%Öøˆ�	‰	�%Õüs   ‚A•, ™A¬?¿Ac               ó    € V ^8„  d   QhRRRR/# )r
   ÚexcÚBaseExceptionr   Ústrr   )r   s   "r   r   r      s   € ÷ *ñ *˜=ð *¨Sñ *r   c                óR   € \        V 4      ;'       g    \        V 4      P                  # )z‹``str(exc)``, or the type name when it is empty (bare ``TimeoutError()``/``RuntimeError()``)
so ``mark_error`` never records a blank cause.)r   ÚtypeÚ__name__)r   s   &r   Úexception_messager      s    € ô ˆs‹8×)Ð)”t˜C“y×)Ñ)Ð)r   c                  óÂ  € ] tR t^%t$ R]R&   R]R&   R]R&   R]R&   R]R&   RtR	]R
&   ]! ]P                  R7      tR]R&   Rt	R]R&   Rt
R]R&   RtR]R&   ]! ]R7      tR]R&   RtR]R&   ]! RRR7      tR	]R&   ]! RRR7      tR]R&   ]! RRRR7      tR]R&   ]! RRRR7      tR]R&   ]! ]P(                  RRR7      tR]R &   ]! ]P(                  RRR7      tR]R!&   ]! ]P(                  RRR7      tR]R"&   ]! ]P0                  RRR7      tR#]R$&   R% R& ltR' R( ltR;R) R* lltR+R/R, R- lltR<R. R/ lltR0 R1 ltRR/R2 R3 llt R4 R5 lt!R6 R7 lt"]#R8 R9 l4       t$R:t%R# )=ÚDashboardOAuthFlowr   Úflow_idÚserver_nameú
str | NoneÚprofileÚhermes_homeÚredirect_uriFÚboolÚreconnect_live)Údefault_factoryÚfloatÚ
created_atÚstartingÚstatusNÚauthorization_urlÚerrorz
list[dict]ÚtoolsÚ Údiscovery_error)ÚdefaultÚinitÚ	cancelledÚexpected_state)r4   r5   Úreprz)tuple[str, str | None, str | None] | NoneÚ	_callbackÚ_callback_error)r*   r5   r8   zthreading.EventÚ_authorization_readyÚ_callback_readyÚ_worker_donezthreading.LockÚ_lockc               ó    € V ^8„  d   QhRRRR/# )r
   Úurlr   r   ÚNoner   )r   s   "r   r   ÚDashboardOAuthFlow.__annotate__=   s   € ÷ ,ñ ,°3ð ,¸4ñ ,r   c              ƒ  óØ  "  € \        \        V4      P                  4      P                  RR.4      ^ ,          pV'       g   \	        R4      hV P
                  ;_uu_ 4        V P                  '       d   \        R4      hV P                  R9   d   V P                  4        W n
        Wn        RV n        V P                  P                  4        RRR4       R#   + '       g   i     R# ; i5i)u)  Record the SDK's authorization URL (with its ``state``) for the dashboard to show.

A flow whose EARLIER attempt already ended is re-minted here instead of raising: the MCP server
task inherits this handle for the whole life of the task, so ``RuntimeError: OAuth flow already
ended`` escaped the SDK's auth flow on every retry and parked the server ("failed initial
connection after 3 attempts") with no way back short of restarting Hermes (#114739). A flow the
user CANCELLED stays terminal â€” the retrying worker must not reopen what they abandoned.
ÚstateNz-OAuth authorization URL did not include statez+OAuth flow already ended: cancelled by userÚauthorization_required>   r0   Úapproved)r   r   ÚqueryÚgetÚ
ValueErrorr>   r6   ÚRuntimeErrorr.   Ú_reopen_ended_attemptr7   r/   r;   r   )Úselfr@   rD   s   && r   Úpublish_authorization_urlÚ,DashboardOAuthFlow.publish_authorization_url=   s¥   é € ô œ #›×,Ñ,Ó-×1Ñ1°'¸D¸6ÓBÀ1ÕEˆßÜÐLÓMÐMØ�Z�Z‹ZØ�~�~ˆ~Ü"Ð#PÓQÐQØ�{‰{Ð3Ô3Ø×*Ñ*Ô,Ø"'ÔØ%(Ô"Ø2ˆDŒKØ×%Ñ%×)Ñ)Ô+÷ �Z�ZŠZüs   ‚AC*Á A,CÃ
C*ÃC'	Ã!	C*c               ó   € V ^8„  d   QhRR/# ©r
   r   rA   r   )r   s   "r   r   rB   S   s   € ÷ !ñ ! tñ !r   c                óú   € \         P                  RV P                  V P                  V P                  4       RV n        RV n        RV n        RV n        V P                  P                  4        RV n        RV n        R# )uù   Reset an ended attempt so the next authorization URL mints a fresh state (caller holds
``self._lock``). The ended attempt's URL, state and spent authorization code are dropped â€”
replaying them would hand the SDK a code the provider already burned.zQMCP OAuth: dashboard flow %s for '%s' ended (%s); re-minting for the next attemptNr-   )ÚloggerÚinfor"   r#   r.   r/   r7   r9   r:   r<   Úclearr0   ©rL   s   &r   rK   Ú(DashboardOAuthFlow._reopen_ended_attemptS   sh   € ô 	�‰ÐgØ—L‘L $×"2Ñ"2°D·K±Kô	Aà!%ˆÔØ"ˆÔØˆŒØ#ˆÔØ×Ñ×"Ñ"Ô$ØˆŒ
Ø ˆŽr   c               ó    € V ^8„  d   QhRRRR/# )r
   Útimeoutr+   r   r   r   )r   s   "r   r   rB   a   s   € ÷ &ñ &¸ð &Èñ &r   c              ƒ  	ó  "  € \         P                  ! V P                  P                  V4      G R j  x€L
 '       g   \	        R4      hV P
                  '       g    \        V P                  ;'       g    R4      hV P
                  #  LR5i)Nz+Timed out waiting for MCP authorization URLz)MCP OAuth flow ended before authorization)ÚasyncioÚ	to_threadr;   ÚwaitÚTimeoutErrorr/   rJ   r0   ©rL   rX   s   &&r   Úwait_for_authorization_urlÚ-DashboardOAuthFlow.wait_for_authorization_urla   si   é € Ü×&Ò& t×'@Ñ'@×'EÑ'EÀwÓO×OÖOÜÐLÓMÐMØ×%×%Ð%Ü˜tŸz™z×XÐXÐ-XÓYÐYØ×%Ñ%Ð%ñ	 Pùs    ‚/B±B²	B¼BÁBÁ1BÚissc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )r
   Úcoder$   rD   r0   ra   r   rA   r   )r   s   "r   r   rB   h   s4   € ÷ 'ñ 'Ø!ð'Ø*4ð'Ø=Gð'ØNXð'à	ñ'r   c               óÊ  € V P                   ;_uu_ 4        V P                  P                  4       '       d   \        R4      hV P                  e,   Ve(   \
        P                  ! V P                  V4      '       g   \        R4      hV'       d   W0n        MV'       d   WV3V n        MRV n        V P                  P                  4        RRR4       R#   + '       g   i     R# ; i)u§   Hand the browser redirect to the waiting flow; ``state`` must match exactly.

``iss`` (RFC 9207) is carried through â€” see ``tools.mcp_oauth._parse_redirect_query``.
zOAuth callback already receivedNzOAuth callback state mismatchz,OAuth callback did not include code or error)
r>   r<   Úis_setrI   r7   ÚsecretsÚcompare_digestr:   r9   r   )rL   rc   rD   r0   ra   s   &$$$$r   Údeliver_callbackÚ#DashboardOAuthFlow.deliver_callbackh   s¢   € ð �Z�Z‹ZØ×#Ñ#×*Ñ*×,Ò,Ü Ð!BÓCÐCØ×"Ñ"Ò*¨eªmÄ7×CYÒCYÐZ^×ZmÑZmÐot×CuÒCuÜ Ð!@ÓAÐAßØ',Õ$ßØ"&¨sÐ!3�•à'U�Ô$Ø× Ñ ×$Ñ$Ô&÷ �Z�ZŠZús   •A$CÁ:CÂCÂ+CÃC"	c               ó    € V ^8„  d   QhRRRR/# )r
   rX   r+   r   z"tuple[str, str | None, str | None]r   )r   s   "r   r   rB   |   s   € ÷ 	ñ 	¨uð 	ÐAcñ 	r   c           	   ƒ  	ó†  "  € \         P                  ! V P                  P                  V4      G R j  x€L
 '       g   \	        R4      hV P
                  '       d   \        RV P
                   24      hV P                  f5   \        RV P                   RV P                   RV P                  : R24      hV P                  #  L�5i)Nz(Timed out waiting for MCP OAuth callbackzOAuth authorization failed: zMCP OAuth flow for 'z.' ended without an authorization code (status=z, error=Ú))rZ   r[   r<   r\   r]   r:   rJ   r9   r#   r.   r0   r^   s   &&r   Úwait_for_callbackÚ$DashboardOAuthFlow.wait_for_callback|   s²   é € Ü×&Ò& t×';Ñ';×'@Ñ'@À'ÓJ×JÖJÜÐIÓJÐJØ××ÐÜÐ!=¸d×>RÑ>RÐ=SÐTÓUÐUØ�>‰>Ò!ÜØ& t×'7Ñ'7Ð&8ð 9ØŸ;™;˜- x°·
±
©~¸Qð@óAð Að �~‰~Ðñ Kùs   ‚/C±B?²	C¼CÁA'Cc               ó   € V ^8„  d   QhRR/# rP   r   )r   s   "r   r   rB   ‡   s   € ÷ ñ ˜tñ r   c                	ó¼   € V P                   ;_uu_ 4        V P                  R 8X  d   \        R4      hRV n        RV n        RRR4       R#   + '       g   i     R# ; i)r0   zOAuth flow already endedrF   N)r>   r.   rJ   r0   rU   s   &r   Úmark_approvedÚ DashboardOAuthFlow.mark_approved‡   s=   € Ø�Z�Z‹ZØ�{‰{˜gÔ%Ü"Ð#=Ó>Ð>Ø$ˆDŒKØˆDŒJ÷	 �Z�ZŠZús   •+A
Á
A	c               ó$   € V ^8„  d   QhRRRRRR/# )r
   r0   r   r6   r(   r   rA   r   )r   s   "r   r   rB   Ž   s!   € ÷ 'ñ ' ð '°4ð 'ÀDñ 'r   c               óÈ  € V P                   ;_uu_ 4        V P                  ;'       g    TV n        V P                  R9   d    RRR4       R# RV n        T;'       g    RV n        V P                  f    V P
                  f   V P                  V n        V P                  P                  4        V P                  P                  4        RRR4       R#   + '       g   i     R# ; i)aÎ  Fail the flow with *error*; the first reason wins. Waking the callback waiter makes the
worker fail too, and its follow-on ``mark_error`` must not clobber the cause the user needs.

``cancelled`` marks a user cancellation, which ``publish_authorization_url`` refuses to re-mint
(unlike an ordinary failure, which a retry may reopen). It is recorded even when the flow has
already ended: the user's "no" outranks the recorded cause and keeps the handle terminal.
r0   NzLMCP OAuth flow failed before the callback was received (empty error message)>   r0   rF   )	r>   r6   r.   r0   r9   r:   r;   r   r<   )rL   r0   r6   s   &&$r   Ú
mark_errorÚDashboardOAuthFlow.mark_errorŽ   s£   € ð �Z�Z‹ZØ!Ÿ^™^×8Ð8¨yˆDŒNØ�{‰{Ð3Ô3Ø÷ ‰Zð "ˆDŒKØ×pÐpÐ"pˆDŒJð �~‰~Ò%¨$×*>Ñ*>Ò*FØ'+§z¡z�Ô$Ø×%Ñ%×)Ñ)Ô+Ø× Ñ ×$Ñ$Ô&÷! �Z�ZŠZús   •.CÁCÁA)CÃC!	c               ó   € V ^8„  d   QhRR/# )r
   r   Údictr   )r   s   "r   r   rB   ¨   s   € ÷ Vñ V˜$ñ Vr   c                	óä   € V P                   ;_uu_ 4        R V P                  RV P                  RV P                  RV P                  RV P
                  /uuRRR4       #   + '       g   i     R# ; i)r"   r#   r.   r/   r0   N)r>   r"   r#   r.   r/   r0   rU   s   &r   ÚsnapshotÚDashboardOAuthFlow.snapshot¨   sN   € Ø�Z�Z‹ZØ˜tŸ|™|¨]¸D×<LÑ<LÈhÐX\×XcÑXcØ'¨×)?Ñ)?ÀÈ$Ï*É*ðV÷ �Z�Z‹Zús   •>AÁA/	c               ó   € V ^8„  d   QhRR/# rP   r   )r   s   "r   r   rB   ­   s   € ÷  ñ   $ñ  r   c                	ó:   € V P                   P                  4        R # ©N)r=   r   rU   s   &r   Úmark_worker_doneÚ#DashboardOAuthFlow.mark_worker_done­   s   € Ø×Ñ×ÑÖr   c               ó   € V ^8„  d   QhRR/# )r
   r   r(   r   )r   s   "r   r   rB   ±   s   € ÷ *ñ *˜Tñ *r   c                	ó6   € V P                   P                  4       # r~   )r=   re   rU   s   &r   Úworker_doneÚDashboardOAuthFlow.worker_done°   s   € à× Ñ ×'Ñ'Ó)Ð)r   )r9   r:   r/   r6   r0   r7   r.   )g      >@)g     Àr@)&r   Ú
__module__Ú__qualname__Ú__firstlineno__Ú__annotations__r)   r   Útimer,   r.   r/   r0   Úlistr1   r3   r6   r7   r9   r:   Ú	threadingÚEventr;   r<   r=   ÚLockr>   rM   rK   r_   rh   rm   rq   ru   rz   r   Úpropertyrƒ   Ú__static_attributes__r   r   r   r!   r!   %   st  ‡ àƒLØÓØÓØÓØÓØ €N�DÓ Ù¨d¯i©iÔ8€J�Ó8Ø€FˆCÓØ$(Ð�zÓ(Ø€Eˆ:ÓÙ¨dÔ3€Eˆ:Ó3Ø€O�SÓá E°Ô6€IˆtÓ6Ù!&¨t¸%Ô!@€N�JÓ@Ù;@ÈÐTYÐ`eÔ;f€IÐ8ÓfÙ"'°¸5ÀuÔ"M€O�ZÓMÙ,1À)Ç/Á/ÐX]ÐdiÔ,jÐ˜/ÓjÙ',¸Y¿_¹_ÐSXÐ_dÔ'e€O�_ÓeÙ$)¸)¿/¹/ÐPUÐ\aÔ$b€L�/ÓbÙ!°)·.±.ÀuÐSXÔY€Eˆ>ÓYõ,õ,!÷&ð'Ø[_÷'÷(	õð'¸%÷ 'õ4Võ
 ð ô*ó ô*r   r!   Úmcp_dashboard_oauth_flow)r4   z1contextvars.ContextVar[DashboardOAuthFlow | None]Ú_current_dashboard_flowc               ó   € V ^8„  d   QhRR/# )r
   Úflowr!   r   )r   s   "r   r   r   ¸   s   € ÷ 9ñ 9Ð1ñ 9r   c                ó"   € \        \        V 4      # )zNMake *flow* the active dashboard OAuth flow for the block (ContextVar-scoped).)r   r‘   )r“   s   &r   Údashboard_oauth_flowr•   ¸   s   € äÔ1°4Ó8Ð8r   c               ó   € V ^8„  d   QhRR/# )r
   r   zDashboardOAuthFlow | Noner   )r   s   "r   r   r   ½   s   € ÷ )ñ )Ð";ñ )r   c                 ó*   € \         P                  4       # r~   )r‘   rH   r   r   r   Úget_dashboard_oauth_flowr˜   ½   s   € Ü"×&Ñ&Ó(Ð(r   )Ú__conditional_annotations__Ú__doc__Ú
__future__r   rZ   ÚcontextvarsÚloggingrf   r‹   r‰   Ú
contextlibr   Údataclassesr   r   Útypingr   Úurllib.parser   r   Ú	getLoggerr   rR   r   r   r!   Ú
ContextVarr‘   rˆ   r•   r˜   )r™   s   @r   Ú<module>r¤      s¨   øðô>õ #ã Û Û Û Û Û Ý %ß (Ý ß +à	×	Ò	˜8Ó	$€ð ôó ðõ*ð ÷L*ð L*ó ðL*ð^ NY×McÒMcÐd~ð  IMô  NNÐ ÐJó  Nõ9÷
)r   