+
    #j                        R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHtH	t	H
t
 ^ RIHt ^ RIHt ]! ]! ]4      P#                  4       P$                  4      t]]P(                  9  d   ]P(                  P+                  ^ ]4       ^ RIHt ]! 4       t]R,          t]R,          t. R;OtR R	 ltR
 tR R ltR R ltR R lt RRRR/R R llt!R R lt"R R lt#R R lt$R R lt%R t&R t'R t(R  t)R! t*R" t+R# t,R$ t-R% t.R& t/R' t0R( t1R) t2R* t3R+ t4R, t5R- t6R. t7R/ t8R0 t9R1 t:R2 t;R3 t<R4 t=R5 t>R6 t?R7 R8 lt@R9 tA]BR:8X  d
   ]A! 4        R# R# )<a  Google Workspace API CLI for Hermes Agent.

Uses the Google Workspace CLI (`gws`) when available, but preserves the
existing Hermes-facing JSON contract and falls back to the Python client
libraries if `gws` is not installed.

Usage:
  python google_api.py gmail search "is:unread" [--max 10]
  python google_api.py gmail get MESSAGE_ID
  python google_api.py gmail send --to user@example.com --subject "Hi" --body "Hello"
  python google_api.py gmail reply MESSAGE_ID --body "Thanks"
  python google_api.py calendar list [--from DATE] [--to DATE] [--calendar primary]
  python google_api.py calendar create --summary "Meeting" --start DATETIME --end DATETIME
  python google_api.py drive search "budget report" [--max 10]
  python google_api.py contacts list [--max 20]
  python google_api.py sheets get SHEET_ID RANGE
  python google_api.py sheets update SHEET_ID RANGE --values '[[...]]'
  python google_api.py sheets append SHEET_ID RANGE --values '[[...]]'
  python google_api.py docs get DOC_ID
N)datetime	timedeltatimezone)MIMEText)Path)get_hermes_homezgoogle_token.jsonzgoogle_client_secret.jsonc                0    V ^8  d   QhR\         R\         /# )   payloadreturn)dict)formats   "q/opt/hermes-venv/lib/python3.14/site-packages/../../../skills/productivity/google-workspace/scripts/google_api.py__annotate__r   9   s            c                 T    \        V 4      pVP                  R 4      '       g   RVR &   V# )typeauthorized_user)r   get)r
   
normalizeds   & r   "_normalize_authorized_user_payloadr   9   s*    gJ>>&!!.
6r   c                     \         P                  4       '       gp   \        R \        P                  R7       \        R\        \        4      P                  R,           2\        P                  R7       \        P                  ! ^4       R# R# )z.Not authenticated. Run the setup script first:filez	  python zsetup.pyN)	
TOKEN_PATHexistsprintsysstderrr   __file__parentexit r   r   _ensure_authenticatedr#   @   sU    >SZZP	$x.//*<=>SZZP r   c                :    V ^8  d   QhR\         \        ,          /# r	   r   )liststr)r   s   "r   r   r   G   s      d3i r   c                      \         P                  ! \        P                  4       4      p T P                  R 4      p\        T\
        4      '       d   T'       d   T# \        \        4      #   \         d    \        \        4      u # i ; i)scopes)	jsonloadsr   	read_text	Exceptionr&   SCOPESr   
isinstance)datar)   s     r   _stored_token_scopesr1   G   sg    zz*..01 XXhF&$F<  F|s   (A* *BBc                2    V ^8  d   QhR\         R,          /# )r	   r   Nr'   )r   s   "r   r   r   R   s      S4Z r   c                  n    \         P                  ! R 4      p V '       d   V # \        P                  ! R4      # )HERMES_GWS_BINgws)osgetenvshutilwhich)overrides    r   _gws_binaryr<   R   s(    yy)*H<<r   c                F    V ^8  d   QhR\         \        \        3,          /# r%   r   r'   )r   s   "r   r   r   Y   s      $sCx. r   c                  f    \         P                  P                  4       p \        \        4      V R &   V # )%GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE)r7   environcopyr'   r   )envs    r   _gws_envrD   Y   s&    
**//
C36z?C/0Jr   paramsbodyc                n    V ^8  d   QhR\         \        ,          R\        R,          R\        R,          /# )r	   partsrE   NrF   )r&   r'   r   )r   s   "r   r   r   _   s-     ! !DI !$+ !D4K !r   c                   \        4       pV'       g   \        R 4      h\        4        V.V OpVe(   VP                  R\        P
                  ! V4      .4       Ve(   VP                  R\        P
                  ! V4      .4       \        P                  ! VRR\        4       R7      pVP                  ^ 8w  d   VP                  P                  4       ;'       g%    VP                  P                  4       ;'       g    Rp\        V\        P                  R7       \        P                  ! VP                  ;'       g    ^4       VP                  P                  4       pV'       g   / #  \        P                   ! V4      #   \        P"                   dQ    \        R\        P                  R7       \        T\        P                  R7       \        P                  ! ^4        R# i ; i)	zgws not installedNz--paramsz--jsonT)capture_outputtextrC   zUnknown gws errorr   z+ERROR: Unexpected non-JSON output from gws:)r<   RuntimeErrorr#   extendr*   dumps
subprocessrunrD   
returncoder   stripstdoutr   r   r!   r+   JSONDecodeError)rH   rE   rF   binarycmdresulterrrS   s   &$$     r   _run_gwsrY   _   sZ   ]F.//
E
C

J

6 234

Hdjj./0^^J	F Amm!!#SSv}}':':'<SS@Sc

#""''a(]]  "F	zz&!! ;#**Mf3::&s   &E< <A!G! G!c                R    V ^8  d   QhR\         R\         \        \        3,          /# r	   msgr   r>   )r   s   "r   r   r      s&     V Vt VS#X Vr   c                     V P                  R / 4      P                  R. 4       Uu/ uF  qR,          VR,          bK  	  up# u upi )r
   headersnamevalue)r   )r\   hs   & r   _headers_dictrb      s@    +.779b+A+E+EiQS+TU+TafIqz!+TUUUs   Ac                0    V ^8  d   QhR\         R\        /# r[   r>   )r   s   "r   r   r      s      t  r   c                 D   R pV P                  R/ 4      pVP                  R/ 4      P                  R4      '       d8   \        P                  ! VR,          R,          4      P                  RRR7      pV# VP                  R4      '       Ed   VR,           Fy  pVP                  R4      R	8X  g   K  VP                  R/ 4      P                  R4      '       g   KD  \        P                  ! VR,          R,          4      P                  RRR7      p M	  V'       g   VR,           Fz  pVP                  R4      R
8X  g   K  VP                  R/ 4      P                  R4      '       g   KD  \        P                  ! VR,          R,          4      P                  RRR7      p V# 	  V# ) r
   rF   r0   zutf-8replace)errorsrH   mimeTypez
text/plainz	text/html)r   base64urlsafe_b64decodedecode)r\   rF   r
   parts   &   r   _extract_message_bodyrm      s_   Dggi$G{{62""6**''(?@GGXaGb K 
W		G$$Dxx
#|38L8P8PQW8X8X//VV0DELLW]fLg % ((88J';6488FB;O;S;STZ;[;[!33DL4HIPPQXajPkDK	 ) Kr   c                0    V ^8  d   QhR\         R\        /# )r	   docr   r>   )r   s   "r   r   r      s      4 C r   c                 V   . pV P                  R / 4      P                  R. 4       Fq  pVP                  R/ 4      pVP                  R. 4       FF  pVP                  R/ 4      pVP                  R4      '       g   K.  VP                  VR,          4       KH  	  Ks  	  RP                  V4      # )rF   content	paragraphelementstextRunre   )r   appendjoin)ro   
text_partselementrr   petext_runs   &     r   _extract_doc_textr{      s    J7762&**9b9KKR0	--
B/Bvvi,H||I&&!!(9"56 0 : 77:r   c                0    V ^8  d   QhR\         R\         /# )r	   r`   r   r3   )r   s   "r   r   r      s     
 
3 
3 
r   c                     V '       g   V # R V 9  d   V # V P                  R4      '       d   V # V R,          pRV9   g   RV9   d   V # V R,           # )TZ:
   NN+-)endswith)r`   tails   & r   _datetime_with_timezoner      sP    
%~~c:D
d{cTk3;r   c            
     &   \        4        ^ RIHp  ^ RIHp V P                  \        \        4      \        4       4      pVP                  '       d   VP                  '       dm   VP                  V! 4       4       \        P                  \        P                  ! \        \        P                   ! VP#                  4       4      4      ^R7      4       VP$                  '       g2   \'        R\(        P*                  R7       \(        P,                  ! ^4       V# )z-Load and refresh credentials from token file.)Credentials)RequestindentzToken is invalid. Re-run setup.r   )r#   google.oauth2.credentialsr   google.auth.transport.requestsr   from_authorized_user_filer'   r   r1   expiredrefresh_tokenrefresh
write_textr*   rN   r   r+   to_jsonvalidr   r   r   r!   )r   r   credss      r   get_credentialsr      s    5611#j/CWCYZE}}},,,gi JJ24::emmo3NO	
 ;;;/cjjALr   c                 2    ^ RI Hp V! W\        4       R7      # )    )build)credentials)googleapiclient.discoveryr   r   )apiversionr   s   && r   build_servicer      s    /?+<==r   c                    \        4       '       Ed%   \        . RORRRV P                  RV P                  /R7      pVP	                  R. 4      p. pV F  p\        . R ORRRVR,          RR	R
. R!O/R7      p\        V4      pVP                  RVR,          RVR,          RVP	                  RR4      RVP	                  RR4      RVP	                  RR4      RVP	                  RR4      RVP	                  RR4      RVP	                  R. 4      /4       K  	  \        \        P                  ! V^RR7      4       R# \        R R4      pVP                  4       P                  4       P                  RV P                  V P                  R7      P                  4       pVP	                  R. 4      pV'       g   \        R4       R# . pV F  pVP                  4       P                  4       P	                  RVR,          R	. R!OR7      P                  4       p\        V4      pVP                  RVR,          RVR,          RVP	                  RR4      RVP	                  RR4      RVP	                  RR4      RVP	                  RR4      RVP	                  RR4      RVP	                  R. 4      /4       K  	  \        \        P                  ! V^RR7      4       R# )"gmailmessagesuserIdmeq
maxResultsrE   idr   metadatametadataHeadersFromToSubjectDatethreadIdfromre   tosubjectdatesnippetlabelslabelIdsFr   ensure_asciiNv1)r   r   r   zNo messages found.r   r   r   r   )r   usersr   r&   r   r   r   r   )r   r   r   r   )r<   rY   querymaxr   rb   ru   r   r*   rN   r   r   r   r&   execute)argsresultsr   outputmsg_metar\   r^   services   &       r   gmail_searchr      s   }}2dC\488L
 ;;z2. H5d(4.j%'H	C $C(GMM#d)JGKK3'++dB/w{{9b9GKK3swwy"5cggj"5	 !. 	djj>?GT*Gmmo&&(--tzzdhh . gi  {{:r*H"#Fmmo&&(,,HTN:= - 
 ') 	  $#d)JGKK+'++dB'w{{9b1GKK+swwy"-cggj"-	
 		   
$**VAE
:;r   c                    \        4       '       d   \        . RORRRV P                  RR/R7      p\        V4      pRVR,          RVR,          RVP	                  R	R
4      RVP	                  RR
4      RVP	                  RR
4      RVP	                  RR
4      RVP	                  R. 4      R\        V4      /p\        \        P                  ! V^RR7      4       R# \        R R4      pVP                  4       P                  4       P	                  RV P                  RR7      P                  4       p\        V4      pRVR,          RVR,          RVP	                  R	R
4      RVP	                  RR
4      RVP	                  RR
4      RVP	                  RR
4      RVP	                  R. 4      R\        V4      /p\        \        P                  ! V^RR7      4       R# )r   r   r   r   r   fullr   r   r   r   re   r   r   r   r   r   r   r   r   rF   Fr   Nr   )r   r   r   r   )r<   rY   
message_idrb   r   rm   r   r*   rN   r   r   r   r   )r   r\   r^   rW   r   s   &    r   	gmail_getr     s   }}1dD$//8VL
  $#d)JGKK+'++dB'w{{9b1GKK+cggj"-)#.	
 	djj>?GT*G
--/
"
"
$
(
( ) gi  C Gc$iC
OFB'gkk$#7;;y"-FB'#''*b)%c*	F 
$**VAE
:;r   c                 ^   \        4       '       Ed4   \        V P                  V P                  '       d   R MR4      pV P                  VR&   V P
                  VR&   V P                  '       d   V P                  VR&   V P                  '       d   V P                  VR&   \        P                  ! VP                  4       4      P                  4       pRV/pV P                  '       d   V P                  VR&   \        . ROR	R
/VR7      p\        \        P                   ! RRRVR,          RVP#                  RR4      /^R7      4       R# \%        RR4      p\        V P                  V P                  '       d   R MR4      pV P                  VR&   V P
                  VR&   V P                  '       d   V P                  VR&   V P                  '       d   V P                  VR&   \        P                  ! VP                  4       4      P                  4       pRV/pV P                  '       d   V P                  VR&   VP'                  4       P)                  4       P+                  R
VR7      P-                  4       p\        \        P                   ! RRRVR,          RVP#                  RR4      /^R7      4       R# )htmlplainr   r   ccr   rawr   r   r   r   rE   rF   statussentr   re   r   Nr   r   rF   r   r   r   send)r<   r   rF   r   r   r   r   from_headerri   urlsafe_b64encodeas_bytesrk   	thread_idrY   r   r*   rN   r   r   r   r   r   r   )r   messager   rF   rW   r   s   &     r   
gmail_sendr   :  s   }}499			fwG!\\	777 GGGDM"..GFO&&w'7'7'9:AACs|>>>#~~D2d#

 	djj(FD&,
FJJWaceLfgpqrsGT*GtyyDIII&7CGGGGDMGIwww**

"
"7#3#3#5
6
=
=
?C3<D~~~>>Z]]_%%',,Dt,DLLNF	$**hfTlJ

S]_aHbclm
nor   c                    \        4       '       Edj   \        . RORRRV P                  RRR. RO/R
7      p\        V4      pVP	                  RR4      pVP                  R4      '       g   RV 2p\        V P                  4      pVP	                  RR4      VR&   W4R&   V P                  '       d   V P                  VR&   VP	                  R	4      '       d   VR	,          VR&   VR	,          VR&   \        P                  ! VP                  4       4      P                  4       p\        . RORR/RVRVR,          /R7      p\        \        P                  ! RRRVR,          RVP	                  RR4      /^R7      4       R# \!        R R4      pVP#                  4       P%                  4       P	                  RV P                  R. ROR7      P'                  4       p\        V4      pVP	                  RR4      pVP                  R4      '       g   RV 2p\        V P                  4      pVP	                  RR4      VR&   W4R&   V P                  '       d   V P                  VR&   VP	                  R	4      '       d   VR	,          VR&   VR	,          VR&   \        P                  ! VP                  4       4      P                  4       pRVRVR,          /pVP#                  4       P%                  4       P)                  RVR7      P'                  4       p\        \        P                  ! RRRVR,          RVP	                  RR4      /^R7      4       R# ) r   r   r   r   r   r   r   r   r   
Message-IDr   re   zRe:zRe: r   r   r   zIn-Reply-To
Referencesr   r   r   r   r   r   Nr   r   r   r   )r   r   r   r   )r<   rY   r   rb   r   
startswithr   rF   r   ri   r   r   rk   r   r*   rN   r   r   r   r   r   )	r   originalr^   r   r   r   rW   r   rF   s	   &        r   gmail_replyr   e  s   }}1$doo*!#D	
  )++i,!!%((WI&G499%FB/$	"..GFO;;|$$%,\%:GM"$+L$9GL!&&w'7'7'9:AAC2d#j(:*>?

 	djj(FD&,
FJJWaceLfgpqrsGT*G}}'')--
9 .  gi  H%Gkk)R(Ge$$	"tyy!GKK+GDM I**{{<  !(!6 ' 5

"
"7#3#3#5
6
=
=
?C3
HZ$89D]]_%%',,Dt,DLLNF	$**hfTlJ

S]_aHbclm
nor   c                    \        4       '       dz   \        . RORR/R7      pVP                  R. 4       Uu. uF)  pRVR,          RVR,          RVP                  RR4      /NK+  	  pp\        \        P
                  ! V^R	7      4       R
# \        R R4      pVP                  4       P                  4       P                  RR7      P                  4       pVP                  R. 4       Uu. uF)  pRVR,          RVR,          RVP                  RR4      /NK+  	  pp\        \        P
                  ! V^R	7      4       R
# u upi u upi )r   r   r   r   r   r   r_   r   re   r   Nr   )r   )r   r   r   r&   )r<   rY   r   r   r*   rN   r   r   r   r&   r   )r   r   lr   r   s   &    r   gmail_labelsr     s   }}?SWHXYY`YdYdemoqYrsYrTU44&!F)VQUU62=NOYrsdjj*+GT*Gmmo$$&++4+8@@BGU\U`U`aikmUnoUnPQtQtWfaivr9JKUnFo	$**VA
&' t ps   /D:&/D?c                    / pV P                   '       d   V P                   P                  R 4      VR&   V P                  '       d   V P                  P                  R 4      VR&   \        4       '       d]   \	        . RORRRV P
                  /VR7      p\        \        P                  ! RVR,          RVP                  R	. 4      /^R
7      4       R# \        RR4      pVP                  4       P                  4       P                  RV P
                  VR7      P                  4       p\        \        P                  ! RVR,          RVP                  R	. 4      /^R
7      4       R# ),addLabelIdsremoveLabelIdsr   r   r   r   r   r   r   r   Nr   )r   r   rF   )r   r   r   modify)
add_labelssplitremove_labelsr<   rY   r   r   r*   rN   r   r   r   r   r   r   r   rF   rW   r   s   &   r   gmail_modifyr     s   D"oo33C8]!%!3!3!9!9#!>}}4dD$//:

 	djj$th

:r8RS\]^_GT*G]]_%%'..dtUY.ZbbdF	$**dF4L(FJJz24NOXY
Z[r   c                     \         P                  ! \        P                  4      p\	        V P
                  ;'       g    VP                  4       4      p\	        V P                  ;'       g"    V\        ^R7      ,           P                  4       4      p\        4       '       Edg   \        . RORV P                  RVRVRV P                  RRR	R
/R7      p. pVP                  R. 4       F  pVP                  RVR,          RVP                  RR4      RVP                  R/ 4      P                  RVP                  R/ 4      P                  RR4      4      RVP                  R/ 4      P                  RVP                  R/ 4      P                  RR4      4      RVP                  RR4      RVP                  RR4      RVP                  RR4      RVP                  RR4      /4       K  	  \        \         P"                  ! V^RR7      4       R# \%        RR4      pVP'                  4       P)                  V P                  W#V P                  RR
R7      P+                  4       p. pVP                  R. 4       F  pVP                  RVR,          RVP                  RR4      RVP                  R/ 4      P                  RVP                  R/ 4      P                  RR4      4      RVP                  R/ 4      P                  RVP                  R/ 4      P                  RR4      4      RVP                  RR4      RVP                  RR4      RVP                  RR4      RVP                  RR4      /4       K  	  \        \         P"                  ! V^RR7      4       R# )   )dayscalendar
calendarIdtimeMintimeMaxr   singleEventsTorderBy	startTimer   itemsr   summaryz
(no title)startdateTimer   re   endlocationdescriptionr   htmlLinkFr   Nv3)r   r   r   r   r   r   )r   eventsr&   )r   nowr   utcr   r   	isoformatr   r   r<   rY   r   r   r   ru   r   r*   rN   r   r   r&   r   )r   r   time_mintime_maxr   r   er   s   &       r   calendar_listr    s   
,,x||
$C&tzz'D'DS]]_EH&txx'X'XC):K4K3V3V3XYH}}*dmm88dhh;

 Wb)AMMag155L9w+//
AEE'2<N<R<RSY[]<^_quuUB'++JeR8H8L8LVUW8XYAEE*b1quu]B7!%%"-AEE*b1	 	 * 	djj>?J-Gnn##==(88$ $  gi 
 F[["%!D'quuY5QUU7B'++Jgr8J8N8NvWY8Z[155#''
AEE%4D4H4HQS4TUj"-1553aeeHb)j"-	
 		 & 
$**VAE
:;r   c                    R V P                   RRV P                  /RRV P                  //pV P                  '       d   V P                  VR&   V P                  '       d   V P                  VR&   V P
                  '       dV   V P
                  P                  R4       Uu. uF,  q"P                  4       '       g   K  RVP                  4       /NK.  	  upVR&   \        4       '       do   \        . ROR
V P                  /VR7      p\        \        P                  ! RRRVR,          R VP                  R R4      RVP                  RR4      /^R7      4       R# \        R	R4      pVP!                  4       P#                  V P                  VR7      P%                  4       p\        \        P                  ! RRRVR,          R VP                  R R4      RVP                  RR4      /^R7      4       R# u upi )r   r   r   r   r   r   r   email	attendeesr   r   r   r   createdr   re   r   r   Nr   )r   rF   )r   r   insert)r   r   r   r   r   r	  r   rR   r<   rY   r   r   r*   rN   r   r   r   r  r   )r   eventr  rW   r   s   &    r   calendar_creater    s   4<<*djj)
DHH%E
 }}} MMj#//m~~~<@NN<P<PQT<Uc<UqY`Y`Yb2w	2<Uck}}, $--0

 	djji&,vzz)R0

:r2	

  	 	J-G^^$$E$JRRTF	$**)fTl6::i,FJJz2.	
  % ds   G)8G)c                    \        4       '       dW   \        . R	ORV P                  RV P                  /R7       \	        \
        P                  ! RRRV P                  /4      4       R# \        R R4      pVP                  4       P                  V P                  V P                  R7      P                  4        \	        \
        P                  ! RRRV P                  /4      4       R# )
r   r   eventIdr   r   deletedNr   )r   r  )r   r   delete)r<   rY   r   event_idr   r*   rN   r   r   r  r   )r   r   s   & r   calendar_deleter  (  s    }}1<Xacgcpcp:qrdjj(Iy$--HIJJ-GNNt}}dmmLTTV	$**h	9dmmD
EFr   c           	         V P                   '       d   V P                  MR V P                   R2p\        4       '       dT   \        . RORVRV P                  RR/R7      p\        \        P                  ! VP                  R. 4      ^R	R
7      4       R# \        RR4      pVP                  4       P                  WP                  RR7      P                  4       pVP                  R. 4      p\        \        P                  ! V^R	R
7      4       R# )zfullText contains ''drivefilesr   pageSizefieldsz4files(id, name, mimeType, modifiedTime, webViewLink)r   Fr   Nr   )r   r  r  )r  r  r&   )	raw_queryr   r<   rY   r   r   r*   rN   r   r   r  r&   r   )r   r   r   r   r  s   &    r   drive_searchr  8  s    ...DJJ0CDJJ<q.QE}}&UDHHP
 	djjWb1!%PQGT*Gmmo""
((+a # gi  KK$E	$**U15
9:r   c                z   Rp\        4       '       dB   \        . RORV P                  RV/R7      p\        \        P
                  ! V^RR7      4       R# \        RR	4      pVP                  4       P                  V P                  VR
7      P                  4       p\        \        P
                  ! V^RR7      4       R# )z+Get metadata for a single Drive file by ID.zRid, name, mimeType, modifiedTime, size, webViewLink, parents, owners(emailAddress)r  fileIdr  r   Fr   Nr   r  r  )r  r  r   )
r<   rY   file_idr   r*   rN   r   r  r   r   )r   r  rW   r   s   &   r   	drive_getr   N  s    aF}}%dllHf=
 	djj>?GT*G]]_  V DLLNF	$**VAE
:;r   c                `   ^ RI p^ RIHp \        V P                  4      P                  4       pVP                  4       '       g5   \        RV 2\        P                  R7       \        P                  ! ^4       V P                  ;'       g,    VP                  \        V4      4      ^ ,          ;'       g    RpRV P                  ;'       g    VP                  /pV P                  '       d   V P                  .VR&   \!        RR	4      pV! \        V4      VR
R7      pVP#                  4       P%                  VVRR7      P'                  4       p\        \(        P*                  ! RRRVR,          RVP-                  RR4      RVP-                  RR4      RVP-                  RR4      /^RR7      4       R# )zUpload a local file to Drive. Falls through to Python client even when gws
is installed, because gws doesn't do multipart uploads.N)MediaFileUploadzERROR: file not found: r   zapplication/octet-streamr_   parentsr  r   T)mimetype	resumablezid, name, mimeType, webViewLink)rF   
media_bodyr  r   uploadedr   re   rh   webViewLinkFr   )	mimetypesgoogleapiclient.httpr"  r   path
expanduserr   r   r   r   r!   	mime_type
guess_typer'   r_   r    r   r  creater   r*   rN   r   )	r   r)  r"  
local_pathmimer   r   mediarW   s	   &        r   drive_uploadr3  ^  s^    4dii++-J'
|43::F>>ccY11#j/B1EccIcD		44Z__5H{{{#{{mGT*GC
OddKE]]_##0 $  gi	 
 
$***fTl

62&FJJz2.vzz-4 e% &r   c                   ^ RI p^ RIHp \        RR4      pVP	                  4       P                  V P                  RR7      P                  4       pVP                  RR4      pVP                  R	V P                  4      pR
RRRRRRR/pV P                  '       d$   \        V P                  4      P                  4       M\        P                  ! 4       V,          pWW9   d   V P                  ;'       g    Wu,          ^ ,          p	Wu,          ^,          p
V P                  '       g$   VP                  '       g   VP                  V
4      pVP	                  4       P                  V P                  V	R7      pM*VP	                  4       P!                  V P                  R7      pVP"                  P%                  RRR7       VP'                  \)        V4      R4      pV! W4      pRpV'       g   VP+                  4       w  rK  VP-                  4        \/        \0        P2                  ! RRRV P                  R	VR\)        V4      RV/^RR7      4       R# )zDownload a Drive file to a local path. Google-native files (Docs/Sheets/Slides)
must be exported; binary files are downloaded as-is.N)MediaIoBaseDownloadr  r   zid, name, mimeTyper  rh   re   r_   z$application/vnd.google-apps.documentz'application/vnd.google-apps.spreadsheetz(application/vnd.google-apps.presentationz#application/vnd.google-apps.drawing)r  rh   r  T)r#  exist_okwbFr   
downloadedr   r+  r   )zapplication/pdfz.pdf)ztext/csvz.csv)z	image/pngz.png)ior*  r5  r   r  r   r  r   r   r   r,  cwdexport_mimesuffixwith_suffixexport_media	get_mediar    mkdirFileIOr'   
next_chunkcloser   r*   rN   )r   r:  r5  r   metar1  r_   native_export_mapout_pathr<  default_extrequestfh
downloaderdone_s   &               r   drive_downloadrN  ~  s    8GT*G ==?dll;OPXXZD88J#D88FDLL)D 	/0K13G24O-/D	 26tDKK ++-$((*tBSH &&DD*;*A!*D'-a0{{{8???++K8H--/..dll[.Y--/++4<<+@OO$6	3x=$	'B$R1JD'')4HHJ	$**,dllHD e% &r   c                 l   R V P                   RR/pV P                  '       d   V P                  .VR&   \        4       '       df   \        . RORR/VR7      p\	        \
        P                  ! RR	R
VR
,          R VP                  R R4      RVP                  RR4      /^RR7      4       R# \        RR4      pVP                  4       P                  VRR7      P                  4       p\	        \
        P                  ! RR	R
VR
,          R VP                  R R4      RVP                  RR4      /^RR7      4       R# )r_   rh   z"application/vnd.google-apps.folderr#  r  r  zid, name, webViewLinkr   r   r
  r   re   r(  Fr   Nr   rF   r  )r  r  r/  )r_   r    r<   rY   r   r*   rN   r   r   r  r/  r   r   s   &   r   drive_create_folderrQ    s$   		8D {{{;;-Y}}(56

 	djji&,FJJvr*6::mR8	

 %) 	* 	GT*G]]_##6M#NVVXF	$**)fTl

62&vzz-4	
 e% &r   c                 .   R V P                   RV P                  /pV P                   R9   dT   V P                  '       g2   \        R\        P
                  R7       \        P                  ! ^4       V P                  VR&   McV P                   R8X  dS   V P                  '       g2   \        R\        P
                  R7       \        P                  ! ^4       V P                  VR&   \        4       '       d   \        . RORV P                  R	V P                  /VR
7      p\        \        P                  ! RRRVP                  RR4      RV P                  RVR,          R VR ,          /^RR7      4       R# \        RR4      pVP!                  4       P#                  V P                  VV P                  RR7      P%                  4       p\        \        P                  ! RRRVP                  RR4      RV P                  RVR,          R VR ,          /^RR7      4       R# )r   rolez6ERROR: --email is required for type=user or type=groupr   emailAddressdomainz+ERROR: --domain is required for type=domainr  r  sendNotificationEmailr   r   sharedpermissionIdr   re   Fr   Nr   )r  rF   rV  r  >   usergroup)r  permissionsr/  )r   rS  r  r   r   r   r!   rU  r<   rY   r  notifyr*   rN   r   r   r[  r/  r   )r   
permissionrW   r   s   &   r   drive_sharer^    s   				J yy%%zzzJQTQ[Q[\HHQK%)ZZ
>"	h	{{{?cjjQHHQK#{{
8}}.$,,' 
 	djjhFJJtR0dllJv&Jv&
 %) 	* 	GT*G  "))||"kk	 * 
 gi  
$**(

4,$,,
6"
6" e% &r   c           
     v   V P                   '       d   \        4       '       dM   \        . RORV P                  /R7       \	        \
        P                  ! RRRV P                  RR/4      4       R# \        RR	4      pVP                  4       P                  V P                  R
7      P                  4        \	        \
        P                  ! RRRV P                  RR/4      4       R# RR/p\        4       '       dN   \        . RORV P                  /VR7       \	        \
        P                  ! RRRV P                  RR/4      4       R# \        RR	4      pVP                  4       P                  V P                  VR7      P                  4        \	        \
        P                  ! RRRV P                  RR/4      4       R# )zITrash or permanently delete a Drive file. Defaults to trash (reversible).r  r  r   r   r  	permanentTNr   r6  trashedr   F)r  rF   )r  r  r  )r  r  update)r`  r<   rY   r  r   r*   rN   r   r  r  r   rb  )r   r   rF   s   &  r   drive_deleterc    sL   ~~~==18T\\:RS$**h	8T\\;X\]^_.dll3;;=djj(Ix{TXYZ[ tD}}(dll+	

 	djj(Ix{TYZ[\GT*GMMO$,,T:BBD	$**h	8T\\;PUV
WXr   c                    \        4       '       Ed   \        . RORRRV P                  RR/R7      p. pVP                  R. 4       F  pVP                  R/ .4      pVP                  R	. 4      pVP                  R
. 4      pTP	                  RV'       d   V^ ,          P                  RR4      MRRV Uu. uF  qwP                  RR4      NK  	  upRV Uu. uF  qP                  RR4      NK  	  up/4       K  	  \        \        P                  ! V^RR7      4       R# \        R R4      p	V	P                  4       P                  4       P                  RV P                  RR7      P                  4       p. pVP                  R. 4       F  pVP                  R/ .4      pVP                  R	. 4      pVP                  R
. 4      pTP	                  RV'       d   V^ ,          P                  RR4      MRRV Uu. uF  qwP                  RR4      NK  	  upRV Uu. uF  qP                  RR4      NK  	  up/4       K  	  \        \        P                  ! V^RR7      4       R# u upi u upi u upi u upi )peopleconnectionsresourceNamez	people/mer  personFieldsz!names,emailAddresses,phoneNumbersr   namesemailAddressesphoneNumbersr_   displayNamere   emailsr`   phonesFr   Nr   )rg  r  rh  )re  re  rf  r&   )r<   rY   r   r   ru   r   r*   rN   r   re  rf  r&   r   )
r   r   contactspersonri  rm  rn  r  pr   s
   &         r   contacts_listrr  "  s   }}7DHH C
 kk-4FJJw-EZZ 0"5FZZ3FOO5a]B7bv>v!55"-v>v>v!55"-v> 	 5 	djj!%@AHd+Gnn**,11 8 2  gi	 
 H++mR0

7RD),b1NB/uE!HLL3"6:6auuWb)6:6:6auuWb)6:
 		 1 
$**Xae
<=- ?>$ ;:s   2II"2I'I,c                    \        4       '       d\   \        . R
ORV P                  RV P                  /R7      p\	        \
        P                  ! VP                  R. 4      ^RR7      4       R# \        R R4      pVP                  4       P                  4       P                  V P                  V P                  R	7      P                  4       p\	        \
        P                  ! VP                  R. 4      ^RR7      4       R# )sheetsvaluesspreadsheetIdranger   Fr   Nv4)rv  rw  )rt  spreadsheetsru  r   )r<   rY   sheet_idrw  r   r*   rN   r   r   ry  ru  r   )r   rW   r   s   &  r   
sheets_getr{  Q  s    }}7#T]]GTZZH
 	djjHb1!%PQHd+G!!#**,00mm4:: 1 gi  
$**VZZ"-ae
LMr   c                    \         P                  ! V P                  4      pR V/p\        4       '       dr   \	        . RORV P
                  RV P                  RR/VR7      p\        \         P                  ! RVP                  R^ 4      RVP                  RR	4      /^R
7      4       R# \        RR4      pVP                  4       P                  4       P                  V P
                  V P                  RVR7      P                  4       p\        \         P                  ! RVP                  R^ 4      RVP                  RR	4      /^R
7      4       R# )ru  rt  rv  rw  valueInputOptionUSER_ENTEREDr   updatedCellsupdatedRangere   r   Nrx  )rv  rw  r}  rF   )rt  ry  ru  rb  )r*   r+   ru  r<   rY   rz  rw  r   rN   r   r   ry  rb  r   r   ru  rF   rW   r   s   &    r   sheets_updater  b  s(   ZZ$FfD}}:"N
 
 	djj.&**^Q*GY_YcYcdrtvYwx  BC  D  	EHd+G!!#**,33mm4::'d 4  gi  
$**nfjj&C^U[U_U_`nprUst}~
  Ar   c                    \         P                  ! V P                  4      pR V/p\        4       '       dr   \	        . RORV P
                  RV P                  RRRR/VR7      p\        \         P                  ! R	VP                  R
/ 4      P                  R	^ 4      /^R7      4       R# \        RR4      pVP                  4       P                  4       P                  V P
                  V P                  RRVR7      P                  4       p\        \         P                  ! R	VP                  R
/ 4      P                  R	^ 4      /^R7      4       R# )ru  rt  rv  rw  r}  r~  insertDataOptionINSERT_ROWSr   r  updatesr   Nrx  )rv  rw  r}  r  rF   )rt  ry  ru  ru   )r*   r+   ru  r<   rY   rz  rw  r   rN   r   r   ry  ru   r   r  s   &    r   sheets_appendr  |  s   ZZ$FfD}}:"N"M	 	
 	djj.&**Y*C*G*GXY*Z[defgHd+G!!#**,33mm4::'-d 4  gi  
$**nfjjB&?&C&CNTU&VW`a
bcr   c                   RRV P                   //pV P                  '       d   RRV P                  //.VR&   \        4       '       d|   \        . ROVR7      p\	        \
        P                  ! RRRVP                  RR4      RVP                  R/ 4      P                  RR4      R	VP                  R	R4      /^R
R7      4       R# \        RR4      pVP                  4       P                  VRR7      P                  4       p\	        \
        P                  ! RRRVP                  RR4      RVP                  R/ 4      P                  RR4      R	VP                  R	R4      /^R
R7      4       R# )zACreate a new spreadsheet. Returns the new spreadsheet ID and URL.
propertiestitlert  rF   r   r
  rv  re   spreadsheetUrlFr   Nrx  z'spreadsheetId,properties,spreadsheetUrlrP  )rt  ry  r/  )r  
sheet_namer<   rY   r   r*   rN   r   r   ry  r/  r   r   s   &   r   sheets_creater    sQ   7DJJ/0D''4??)CDEX}}>TJdjjiVZZ<VZZb155grBfjj)92>	

 %) 	* 	Hd+G!!#**C + gi  
$**)OR8L"-11'2>&**%5r:	
 e% &r   c                 4   \        4       '       dq   \        . RORV P                  /R7      pRVP                  RR4      RVP                  RR4      R\	        V4      /p\        \        P                  ! V^RR7      4       R# \        R R	4      pVP                  4       P                  V P                  R
7      P                  4       pRVP                  RR4      RVP                  RR4      R\	        V4      /p\        \        P                  ! V^RR7      4       R# )docs
documentIdr   r  re   rF   Fr   Nr   r  r  	documentsr   )r<   rY   doc_idr   r{   r   r*   rN   r   r  r   )r   ro   rW   r   s   &   r   docs_getr    s    }}3\4;;<WXSWWWb)#'',3%c*

 	djj>?FD)G




!
!T[[
!
9
A
A
CC"%cgglB/!#&F
 
$**VAE
:;r   c                   RV P                   /p\        4       '       d   \        . ROVR7      pM:\        RR4      pVP	                  4       P                  VR7      P                  4       pVP                  RR4      pV P                  '       d    V'       d   \        W@P                  ^R7       \        \        P                  ! RR	RTRVP                  RR4      R
V'       d   RV R2MR/^RR7      4       R# )z<Create a new Doc. Optionally seed it with initial body text.r  r  r  r   r  re   indexr   r
  urlz#https://docs.google.com/document/d/z/editFr   N)r  r  r/  )r  r<   rY   r   r  r/  r   r   rF   _docs_insert_textr   r*   rN   )r   rF   ro   r   r  s   &    r   docs_creater    s    TZZ D}}6TB-!((d(3;;=WW\2&FyyyV&))15	$**)f"%f4VHEBRT	
 e% &r   c                   \        4       '       d   \        . RORV P                  /R7      pMD\        RR4      pVP	                  4       P                  V P                  R7      P                  4       pVP                  R/ 4      P                  R. 4      p^pV F6  pVP                  R4      p\        V\        4      '       g   K,  Wd8  g   K4  TpK8  	  \        V^,
          ^4      pV P                  P                  R	4      '       d   V P                  MV P                  R	,           p\        V P                  WR
7       \        \        P                  ! RRRV P                  RVR\!        V4      /^RR7      4       R# )z*Append text to the end of an existing Doc.r  r  r   r   r  rF   rq   endIndex
r  r   appendedinserted_at
charactersFr   Nr  )r<   rY   r  r   r  r   r   r/   intr   rK   r   r  r   r*   rN   len)	r   ro   r   rq   	end_indexrx   eiinsert_indexrK   s	   &        r   docs_appendr    s)   }}3\4;;<WX-!%%%=EEG
 ggfb!%%i4GI[[$b#2>I  y1}a(L		**400499dii$6FDdkk4<	$***dkk|c$i	
 e% &r   c                @    V ^8  d   QhR\         R\         R\        RR/# )r	   r  rK   r  r   N)r'   r  )r   s   "r   r   r     s.     ^ ^c ^ ^S ^T ^r   c                    RRRV/RV//.p\        4       '       d   \        . RORV /RV/R7       R	# \        RR
4      pVP                  4       P	                  V RV/R7      P                  4        R	# )z4Send a batchUpdate with a single insertText request.
insertTextr   r  rK   r  r  requestsr   Nr   )r  rF   )r  r  batchUpdate)r<   rY   r   r  r  r   )r  rK   r  r  r   s   &&&  r   r  r    s     	%(D
 H }}0 &)h'	

 	FD)G##vZ<R#S[[]r   c                     \         P                  ! R R7      p V P                  RRR7      pVP                  R4      pVP                  RRR7      pVP                  R4      pVP	                  RR	R
7       VP	                  R\
        ^
R7       VP                  \        R7       VP                  R4      pVP	                  R4       VP                  \        R7       VP                  R4      pVP	                  RRR7       VP	                  RRR7       VP	                  RRR7       VP	                  RRR7       VP	                  RRRRR7       VP	                  RRRR7       VP	                  R RR!R"7       VP                  \        R7       VP                  R#4      pVP	                  RR$R
7       VP	                  RRR7       VP	                  RRRRR7       VP                  \        R7       VP                  R%4      pVP                  \        R7       VP                  R&4      pVP	                  R4       VP	                  R'RR(R"7       VP	                  R)RR*R"7       VP                  \        R7       VP                  R+4      pVP                  RRR7      pVP                  R,4      pVP	                  R-RR.R"7       VP	                  R/RR0R"7       VP	                  R\
        ^R7       VP	                  R1R2R7       VP                  \        R7       VP                  R34      pVP	                  R4RR7       VP	                  R-RR5R67       VP	                  R/RR7R67       VP	                  R8RR7       VP	                  R9RR7       VP	                  R:RR;R"7       VP	                  R1R2R7       VP                  \        R7       VP                  R<4      pVP	                  R=4       VP	                  R1R2R7       VP                  \        R7       VP                  R>4      pVP                  RRR7      pVP                  R4      pVP	                  R4       VP	                  R\
        ^
R7       VP	                  R?RR@R7       VP                  \         R7       VP                  R4      pVP	                  RA4       VP                  \"        R7       VP                  RB4      pVP	                  RCRDR
7       VP	                  RERRFR"7       VP	                  RGRRHR"7       VP	                  RIRRJR"7       VP                  \$        R7       VP                  RK4      pVP	                  RA4       VP	                  RLRRMR"7       VP	                  RNRROR"7       VP                  \&        R7       VP                  RP4      pVP	                  RQ4       VP	                  RGRRRR"7       VP                  \(        R7       VP                  RS4      pVP	                  RA4       VP	                  RTRU. RtORV7       VP	                  RWRX. RuORV7       VP	                  RYRRZR"7       VP	                  R[RR\R"7       VP	                  R]RR^R7       VP                  \*        R7       VP                  R<4      pVP	                  RA4       VP	                  R_RR`R7       VP                  \,        R7       VP                  Ra4      p	V	P                  RRR7      p
V
P                  R,4      pVP	                  R\
        ^2R7       VP                  \.        R7       VP                  Rb4      pVP                  RRR7      pVP                  R4      pVP	                  Rc4       VP	                  Rd4       VP                  \0        R7       VP                  Re4      pVP	                  Rc4       VP	                  Rd4       VP	                  RfRRgR67       VP                  \2        R7       VP                  Rh4      pVP	                  Rc4       VP	                  Rd4       VP	                  RfRRgR67       VP                  \4        R7       VP                  R34      pVP	                  RiRRjR67       VP	                  RkRRlR"7       VP                  \6        R7       VP                  Rm4      pVP                  RRR7      pVP                  R4      pVP	                  Rn4       VP                  \8        R7       VP                  R34      pVP	                  RiRRoR67       VP	                  RRRpR"7       VP                  \:        R7       VP                  Rh4      pVP	                  Rn4       VP	                  RqRRrR67       VP                  \<        R7       V P?                  4       pVPA                  V4       Rs# )vz%Google Workspace API for Hermes Agent)r   r   T)destrequiredr   actionsearchr   z%Gmail search query (e.g. 'is:unread'))helpz--max)r   default)funcr   r   r   z--to)r  z	--subjectz--bodyz--ccre   )r  z--fromr   z;Custom From header (e.g. '"Agent Name" <user@example.com>'))r  r  r  z--html
store_truezSend body as HTML)r  r  z--thread-idzThread ID for threading)r  r  replyzMessage ID to reply tor   r   z--add-labelsz Comma-separated label IDs to addz--remove-labelsz#Comma-separated label IDs to remover   r&   z--startzStart time (ISO 8601)z--endzEnd time (ISO 8601)z
--calendarprimaryr/  z	--summaryzStart (ISO 8601 with timezone))r  r  zEnd (ISO 8601 with timezone)z
--locationz--descriptionz--attendeeszComma-separated email addressesr  r  r  z--raw-queryz Use query as raw Drive API queryr  uploadr+  zLocal file path to uploadz--namez8Override file name in Drive (defaults to local filename)z--parentzParent folder IDz--mime-typez-Override MIME type (auto-detected if omitted)downloadz--outputz/Local output path (defaults to ./<name> in cwd)z--export-mimezoExport MIME for Google-native files (overrides defaults: pdf for Docs/Slides, csv for Sheets, png for Drawings)zcreate-folderr_   z#Parent folder ID (defaults to root)sharez--rolereader)r  choicesz--typerY  z--emailz4Email address (required for type=user or type=group)z--domainz!Domain (required for type=domain)z--notifyzSend notification emailz--permanentz:Permanently delete (default is trash, which is reversible)ro  rt  rz  rw  rb  z--valueszJSON array of arraysru   z--titlezSpreadsheet titlez--sheet-namez,Name of the first tab (defaults to 'Sheet1')r  r  zDocument titlezInitial body text (optional)z--textz)Text to append to the end of the documentN)r  	commenterwriterfileOrganizer	organizerowner)rY  rZ  rU  anyone)!argparseArgumentParseradd_subparsers
add_parseradd_argumentr  set_defaultsr   r   r   r   r   r   r  r  r  r  r   r3  rN  rQ  r^  rc  rr  r{  r  r  r  r  r  r  
parse_argsr  )parsersubr   	gmail_subrq  calcal_subdrvdrv_subconcon_subshsh_subr  docs_subr   s                   r   mainr    sP   $$1XYF


Y

>C NN7#E$$(T$BIX&ANN7!HNINN7bN1NNN%U#ANN< NN	N"V$ANN6DN)NN;N.NN8dN+NN62N&NN8-  CBN  CNN8L7JNKNN="3LNMNN
N#W%ANN<&>N?NN8dN+NN8-  CBN  CNNN$X&ANNN%X&ANN< NN>24VNWNN$b7\N]NNN% ..
$C  h >G6"ANN9b/FNGNN7B-BNCNN7bN1NN<N3NNN&8$ANN;N.NN9t2RNSNN7T0NNONN<N,NN?BN/NN="3TNUNN<N3NNN(8$ANN:NN<N3NNN( ..
!C  h >G8$ANN7NN7bN1NN=<^N_NNN%5!ANN9NN	N"8$ANN6 ;N<NN8R.hNiNN:r0BNCNN="3bNcNNN%:&ANN9NN:r0aNbNN?B  6gN  hNNN'?+ANN6NN:r0UNVNN+N,7#ANN9NN8X7N  ANN8V5ZN[NN9b/eNfNN:r0SNTNN:l9RNSNNN$8$ANN9NN=<xNyNNN% ..
$C  h >G6"ANN7bN1NNN& 
	!BHt<F% ANN:NN7NN
N#(#ANN:NN7NN:3INJNNN&(#ANN:NN7NN:3INJNNN&(#ANN9t2ENFNN>24bNcNNN& >>&!D""4"@HE"ANN8NNN!H%ANN9t2BNCNN8R.LNMNNN$H%ANN8NN8d1\N]NNN$DIIdOr   __main__)z.https://www.googleapis.com/auth/gmail.readonlyz*https://www.googleapis.com/auth/gmail.sendz,https://www.googleapis.com/auth/gmail.modifyz(https://www.googleapis.com/auth/calendarz%https://www.googleapis.com/auth/drivez1https://www.googleapis.com/auth/contacts.readonlyz,https://www.googleapis.com/auth/spreadsheetsz)https://www.googleapis.com/auth/documents)C__doc__r  ri   r*   r7   r9   rO   r   r   r   r   email.mime.textr   pathlibr   r'   r   resolver    _SCRIPTS_DIRr+  r  _hermes_homer   HERMES_HOMEr   CLIENT_SECRET_PATHr.   r   r#   r1   r<   rD   rY   rb   rm   r{   r   r   r   r   r   r   r   r   r   r  r  r  r  r   r3  rN  rQ  r^  rc  rr  r{  r  r  r  r  r  r  r  r  __name__r"   r   r   <module>r     s  *    	   
 2 2 $  4>))+223sxxHHOOA|$ (..
 #>> 	
! !RV !HV$
,><<@$<P'pV;p~
(\42<l"LG ;,< &@.&b&@/&dYB'>^N"A4d4&B<*&.&<^2gT zF r   