
    Ki?&                        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dlmZ  ej        e          ZdZdZdZd	Zd
ZdZdZdZdZdZd+dZd,dZd-dZd.dZd/dZdddd0d#Zd$d%d&d1d*Z dS )2u  GitHub Copilot authentication utilities.

Implements the OAuth device code flow used by the Copilot CLI and handles
token validation/exchange for the Copilot API.

Token type support (per GitHub docs):
  gho_          OAuth token           ✓  (default via copilot login)
  github_pat_   Fine-grained PAT      ✓  (needs Copilot Requests permission)
  ghu_          GitHub App token      ✓  (via environment variable)
  ghp_          Classic PAT           ✗  NOT SUPPORTED

Credential search order (matching Copilot CLI behaviour):
  1. COPILOT_GITHUB_TOKEN env var
  2. GH_TOKEN env var
  3. GITHUB_TOKEN env var
  4. gh auth token  CLI fallback
    )annotationsN)Path)OptionalOv23li8tweQw6odWQebzz$https://github.com/login/device/codez+https://github.com/login/oauth/access_tokenz0https://api.github.com/copilot_internal/v2/tokenzhttps://api.githubcopilot.comghp_)gho_github_pat_ghu_)COPILOT_GITHUB_TOKENGH_TOKENGITHUB_TOKEN      tokenstrreturnboolc                Z    |                                                      t                    S )zICheck if a token is a classic PAT (ghp_*), which Copilot doesn't support.strip
startswith_CLASSIC_PAT_PREFIXr   s    4/home/ubuntu/hermes-agent/hermes_cli/copilot_auth.pyis_classic_patr   5   s    ;;==##$7888    tuple[bool, str]c                n    |                                  } | sdS |                     t                    rdS dS )zYValidate that a token is usable with the Copilot API.

    Returns (valid, message).
    )FzEmpty token)Fu3  Classic Personal Access Tokens (ghp_*) are not supported by the Copilot API. Use one of:
  → `copilot login` or `hermes model` to authenticate via OAuth
  → A fine-grained PAT (github_pat_*) with Copilot Requests permission
  → `gh auth login` with the default device code flow (produces gho_* tokens))TOKr   r   s    r   validate_copilot_tokenr    :   sG    
 KKMME $##+,, 

 
 :r   tuple[str, str]c                 N   t           D ]b} t          j        | d                                          }|r7t	          |          \  }}|st
                              d| |           \|| fc S ct                      }|r*t	          |          \  }}|st          d|           |dfS dS )zResolve a GitHub token suitable for Copilot API use.

    Returns (token, source) where source describes where the token came from.
    Raises ValueError if only a classic PAT is available.
     z"Token from %s is not supported: %sz5Token from `gh auth token` is a classic PAT (ghp_*). zgh auth token)r#   r#   )	COPILOT_ENV_VARSosgetenvr   r    loggerwarning_try_gh_cli_token
ValueError)env_varvalvalidmsgr   s        r   resolve_copilot_tokenr/   O   s     $ 	  	 i$$**,, 	 /44JE3 8'3   <	  E &+E22
s 	MMM   o%%6r   	list[str]c                 n   g } t          j        d          }|r|                     |           ddt          t	          j                    dz  dz  dz            fD ]Z}|| v rt          j                            |          r4t          j	        |t          j
                  r|                     |           [| S )zIReturn candidate ``gh`` binary paths, including common Homebrew installs.ghz/opt/homebrew/bin/ghz/usr/local/bin/ghz.localbin)shutilwhichappendr   r   homer%   pathisfileaccessX_OK)
candidatesresolved	candidates      r   _gh_cli_candidatesr?   n   s    J|D!!H $(### 	DIKK("U*T122 ) )	
 
""7>>)$$ 	)9bg)F)F 	)i(((r   Optional[str]c                 ^   t                      D ]} 	 t          j        | ddgddd          }n?# t          t          j        f$ r&}t
                              d| |           Y d}~Vd}~ww xY w|j        dk    r4|j        	                                r|j        	                                c S dS )	zGReturn a token from ``gh auth token`` when the GitHub CLI is available.authr   Tr   )capture_outputtexttimeoutz#gh CLI token lookup failed (%s): %sNr   )
r?   
subprocessrunFileNotFoundErrorTimeoutExpiredr'   debug
returncodestdoutr   )gh_pathresultexcs      r   r)   r)      s    %'' ) )		^&'*#	  FF ":#<= 	 	 	LL>MMMHHHH	 !!fm&9&9&;&;!=&&(((((4s   .A*A%%A*z
github.comi,  )hosttimeout_secondsrP   rQ   floatc                8	   ddl }ddl}|                     d          }d| d}d| d}|j                            t
          dd                                          }|j                            ||d	d
dd          }	 |j        	                    |d          5 }t          j        |                                                                          }	ddd           n# 1 swxY w Y   nE# t          $ r8}
t                              d|
           t#          d|
            Y d}
~
dS d}
~
ww xY w|	                    dd          }|	                    dd          }|	                    dd          }t'          |	                    dt(                    d          }|r|st#          d           dS t#                       t#          d|            t#          d|            t#                       t#          ddd           t+          j                    |z   }t+          j                    |k     rKt+          j        |t.          z              |j                            t
          |dd                                           }|j                            ||d	d
dd          }	 |j        	                    |d!          5 }t          j        |                                                                          }ddd           n# 1 swxY w Y   n## t          $ r t#          d"dd           Y w xY w|                    d#          rt#          d$           |d#         S |                    d%d          }|d&k    rt#          d"dd           w|d'k    r`|                    d          }t1          |t2          t4          f          r|dk    rt3          |          }n|d(z  }t#          d"dd           |d)k    rt#                       t#          d*           dS |d+k    rt#                       t#          d,           dS |r"t#                       t#          d-|            dS t+          j                    |k     Kt#                       t#          d.           dS )/a  Run the GitHub OAuth device code flow for Copilot.

    Prints instructions for the user, polls for completion, and returns
    the OAuth access token on success, or None on failure/cancellation.

    This replicates the flow used by opencode and the Copilot CLI.
    r   N/zhttps://z/login/device/codez/login/oauth/access_tokenz	read:user)	client_idscopezapplication/jsonz!application/x-www-form-urlencodedHermesAgent/1.0)AcceptzContent-Type
User-Agent)dataheaders   )rE   z+Failed to initiate device authorization: %su,     ✗ Failed to start device authorization: verification_urizhttps://github.com/login/device	user_coder#   device_codeinterval   u*     ✗ GitHub did not return a device code.z!  Open this URL in your browser: z  Enter this code: z  Waiting for authorization...T)endflushz,urn:ietf:params:oauth:grant-type:device_code)rU   r_   
grant_type
   .access_tokenu    ✓errorauthorization_pending	slow_downr   expired_tokenu,     ✗ Device code expired. Please try again.access_deniedu     ✗ Authorization was denied.u     ✗ Authorization failed: u*     ✗ Timed out waiting for authorization.)urllib.requesturllib.parserstripparse	urlencodeCOPILOT_OAUTH_CLIENT_IDencoderequestRequesturlopenjsonloadsreaddecode	Exceptionr'   rh   printgetmax_DEVICE_CODE_POLL_INTERVALtimesleep_DEVICE_CODE_POLL_SAFETY_MARGIN
isinstanceintrR   )rP   rQ   urllibdomaindevice_code_urlaccess_token_urlrZ   reqrespdevice_datarO   r]   r^   r_   r`   deadline	poll_datapoll_reqrN   rh   server_intervals                        r   copilot_device_code_loginr      su    [[F;;;;OC&CCC <!!,# #   vxx 	
 .
 
 (?+
 
 !  C^##C#44 	;*TYY[[%7%7%9%9::K	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	;   BCHHHBSBBCCCttttt
 #'9;\]]R00I//-44K;??:/IJJANNH i :;;;t 
GGG	
@.>
@
@AAA	
+	
+
+,,,	GGG	
*$???? y{{_,H
)++
 
 
8==>>>L**0&H,
 ,
   688	 	 >)), C/  * 
 
	''"'== :DIIKK$6$6$8$899: : : : : : : : : : : : : : : 	 	 	#2T****H	 ::n%% 	*&MMM.))

7B''+++#2T****k!!$jj44O/C<88 _q=P=P//A#2T****o%%GGG@AAA4o%%GGG34444 	GGG8889994m )++
 
 p 
GGG	
67774sr    C- 9C!C- !C%%C- (C%)C- -
D/7-D**D/%L 9L:L L

L L
L L21L2TF)is_agent_turn	is_visionr   r   dict[str, str]c                *    ddd| rdndd}|rd|d<   |S )	z~Build the standard headers for Copilot API requests.

    Replicates the header set used by opencode and the Copilot CLI.
    zvscode/1.104.1rW   zconversation-editsagentuser)zEditor-VersionrY   zOpenai-Intentzx-initiatortruezCopilot-Vision-Request )r   r   r[   s      r   copilot_request_headersr     s?     +'-"/;wwV	 G  3,2()Nr   )r   r   r   r   )r   r   r   r   )r   r!   )r   r0   )r   r@   )rP   r   rQ   rR   r   r@   )r   r   r   r   r   r   )!__doc__
__future__r   rw   loggingr%   r4   rF   r   pathlibr   typingr   	getLogger__name__r'   rr   COPILOT_DEVICE_CODE_URLCOPILOT_ACCESS_TOKEN_URLCOPILOT_TOKEN_EXCHANGE_URLCOPILOT_API_BASE_URLr   _SUPPORTED_PREFIXESr$   r   r   r   r    r/   r?   r)   r   r   r   r   r   <module>r      s   $ # " " " " "   				                  		8	$	$ 1 @ H  P 6   5  H   "# 9 9 9 9
   *   >   *   ,  x x x x x x~        r   