+
    lHà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t^ RI	t	^ RI
t
^ RIt ^ RIt^ RIHt ^ RIHt ^ RIt^ RIHt ^ RIHt ^ RIHt ]P2                  ! ]4      t]P8                  t]P<                  tRt Rt!R#t"]]#]#.R3,          t$]]%]&]#]#3,          ,          .R3,          t']].R3,          t(]]%]#,          .R3,          t)]. ]%]&]#]#3,          ,          3,          t*^t+R$t,R%t-R	t.R
t/R&t0R R lt1R R lt2R R lt3R'R R llt4R(R R llt5R R lt6R R lt7R R lt8R R lt9R R lt:R R  lt; ! R! R"4      t<R#   ] d    Rt ELi ; i))a  Shared file sync manager for remote execution backends.

Tracks local file changes via mtime+size, detects deletions, and syncs to
remote environments transactionally.  Used by SSH, Modal, and Daytona.
Docker uses bind mounts (live host FS view) and doesn't need this.
N©ÚPath)ÚCallable)Úget_hermes_home)Ú_file_mtime_key)Úmtime_is_racyg      @ÚHERMES_FORCE_FILE_SYNCÚsync_back_max_byteszhermes-sync-back-c                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn)Úint)Úformats   "ÚA/home/ubuntu/.hermes/hermes-agent/tools/environments/file_sync.pyÚ__annotate__r   D   s   € ÷  ñ  œcñ  ó    c                 ó"  € ^ RI Hp  V ! 4       ;'       g    / P                  R4      ;'       g    / P                  \        4      pVe    \	        V4      # \        #   \
        \        3 d$    \        P                  R\        T4        \        # i ; i)z¯Extraction cap; config.yaml ``terminal.sync_back_max_bytes`` overrides it for trees that
legitimately exceed 2 GiB (a skipped extraction silently discards the whole download).)Úload_configÚterminalz.sync_back: ignoring non-integer terminal.%s=%r)
Úhermes_cli.configr   ÚgetÚ_SYNC_BACK_MAX_BYTES_KEYr   Ú	TypeErrorÚ
ValueErrorÚloggerÚwarningÚ_SYNC_BACK_MAX_BYTES)r   Úraws     r   Ú_sync_back_max_bytesr   D   s‚   € õ .á‹M×Ð˜R×$Ñ$ ZÓ0×6Ð6°B×
;Ñ
;Ô<TÓ
U€CØ
‚ð	lÜ�s“8ˆOô  Ðøô œ:Ð&ô 	lÜ�N‰NÐKÔMeÐgjÕkÜÐð	lús   Á	
A Á,BÂBc                ó$   € V ^8„  d   QhR\         /# r   ©Ústr)r   s   "r   r   r   R   s   € ÷ 5ñ 5¤ñ 5r   c                 ó>   € \          \        P                  ! 4        R2# )zòTemp prefix embedding the owning PID so the stale sweep can tell a hard-killed
process's leftovers from another live gateway's in-flight transfer without guessing
from mtime (a staging dir's mtime does not move while content streams into it).Ú-)Ú_SYNC_BACK_TEMP_PREFIXÚosÚgetpid© r   r   Ú_sync_back_temp_prefixr)   R   s   € ô %Ð%¤b§i¢i£k ]°!Ð4Ð4r   c                ó0   € V ^8„  d   QhR\         R\        /# )r   Únamer   )r"   Úbool)r   s   "r   r   r   Y   s   € ÷ ,ñ ,¤#ð ,¬$ñ ,r   c                óÂ   € V \        \        4      R P                  R^4      ^ ,          pVP                  4       '       g   R# \        P
                  ! \        V4      4      # )z‰Whether the process that created a sync-back temp entry may still be running.
Names without a PID count as alive: the age cutoff applies.Nr$   T)Úlenr%   ÚsplitÚisdigitÚpsutilÚ
pid_existsr   )r+   Úpid_parts   & r   Ú_temp_entry_owner_aliver4   Y   sP   € ð ”CÔ.Ó/Ð0Ð1×7Ñ7¸¸QÓ?ÀÕB€HØ×Ñ×ÒÙÜ×ÒœS ›]Ó+Ð+r   c                ó>   € V ^8„  d   QhR\         R,          R\        /# )r   Útemp_dirNr   )r   r   )r   s   "r   r   r   b   s   € ÷ ñ ¬D°4­Kð Ä3ñ r   c                óô  € T ;'       g    \        \        P                  ! 4       4      p\        P                  ! 4       \        ,
          p^ p \        VP                  \         R24      4      pT F´  p TP                  4       '       d   K  \        TP                  4      '       d"   TP                  4       P                  T8¼  d   KX  TP!                  4       '       d   \"        P$                  ! T4       MTP'                  4        T^,          p\        P                  RT4       K¶  	  T#   \         d    \        P                  RT4        ^ # i ; i  \         d    \        P                  RT4        EK  i ; i)a[  Remove sync-back tars and staging dirs left behind by a hard-killed process.

Only entries carrying this module's prefix are touched: at once when their owner PID
is dead, otherwise only past ``_SYNC_BACK_STALE_SECONDS``. Returns the number of
entries removed; a permission error or a race with another sync-back must not prevent
the current one.
Ú*z0sync_back: could not scan temporary directory %sz+sync_back: removed stale temporary entry %sz4sync_back: could not remove stale temporary entry %s)r   ÚtempfileÚ
gettempdirÚtimeÚ_SYNC_BACK_STALE_SECONDSÚlistÚglobr%   ÚOSErrorr   ÚdebugÚ
is_symlinkr4   r+   ÚlstatÚst_mtimeÚis_dirÚshutilÚrmtreeÚunlink)r6   Ú	directoryÚcutoffÚremovedÚ
candidatesÚ	candidates   &     r   Ú_cleanup_stale_sync_back_temprM   b   s/  € ð ×7Ð7œD¤×!4Ò!4Ó!6Ó7€IÜ�YŠY‹[Ô3Õ3€FØ€GðÜ˜)Ÿ.™.Ô,BÐ+CÀ1Ð)EÓFÓGˆ
ó  ˆ	ð	\Ø×#Ñ#×%Ò%ÙÜ& y§~¡~×6Ò6¸9¿?¹?Ó;L×;UÑ;UÐY_Ô;_ÙØ×Ñ×!Ò!Ü—’˜iÕ(à× Ñ Ô"Ø�q�LˆGÜ�L‰LÐFÈ	ÖRñ  ð €Nøô# ô Ü�‰ÐGÈÔSÚðûô ô 	\Ü�L‰LÐOÐQZ×[Ð[ð	\ús7   Á!D) Á3EÂ:EÃEÃAEÄ)!EÅEÅ!E7Å6E7c                óh   € V ^8„  d   QhR\         R\        \        \         \         3,          ,          /# )r   Úcontainer_baser   ©r"   r=   Útuple)r   s   "r   r   r   ƒ   s'   € ÷ ñ ¤Cð ¼dÄ5ÌÌcÈÅ?Õ>Sñ r   c           	     ó  € ^ RI HpHpHp V! 4        Uu. uF&  pVR,          VR,          P	                  RV ^4      3NK(  	  ppT. V! V R7      OV! V R7      O Uu. uF  pVR,          VR,          3NK  	  up,          pV# u upi u upi )z®Enumerate all (host_path, remote_path) pairs to sync to a remote. Credential paths are
remapped from the hardcoded /root/.hermes to *container_base* (remote home may differ).)Úget_credential_file_mountsÚiter_cache_filesÚiter_skills_filesÚ	host_pathÚcontainer_pathú/root/.hermes)rO   )Útools.credential_filesrS   rT   rU   Úreplace)rO   rS   rT   rU   ÚentryÚfiless   &     r   Úiter_sync_filesr]   ƒ   sÁ   € ÷ gÑfñ 0Ô1ó3á1ˆEð 
ˆ{Õ	˜UÐ#3Õ4×<Ñ<¸_ÈnÐ^_Ó`ÓaÙ1ð 
ð 3ð 
ðHÑ(¸ÔGð HÙ'°~ÔFñHóIñHˆEð 
ˆ{Õ	˜UÐ#3Õ4Ó5ñHñIõ I€Eð €Lùò3ùòIs   ”,A?ÁBc                ó0   € V ^8„  d   QhR\         R\         /# )r   rV   r   r!   )r   s   "r   r   r   “   s   € ÷ 1ñ 1¤cð 1¬cñ 1r   c                óÊ   €  \        \        V 4      P                  4       P                  4       4      #   \         d&    \        \        T 4      P                  4       4      u # i ; i)zVCanonical string form of a host path (``resolve()`` falling back to ``expanduser()``).)r"   r   Ú
expanduserÚresolver?   )rV   s   &r   Ú_resolve_host_path_strrb   “   sO   € ð1Ü”4˜	“?×-Ñ-Ó/×7Ñ7Ó9Ó:Ð:øÜô 1Ü”4˜	“?×-Ñ-Ó/Ó0Ò0ð1ús   ‚/2 ²-A"Á!A"c                ó:   € V ^8„  d   QhR\         \        ,          /# r   )Úsetr"   )r   s   "r   r   r   ›   s   € ÷ 	Sñ 	S¤¤C¥ñ 	Sr   c                 ó  €  ^ RI Hp  V ! 4       pT Uu0 uFF  p\	        T\
        4      '       g   K  TP                  R4      '       g   K4  \        TR,          4      kKH  	  up#   \         d    \        4       u # i ; iu upi )zBReturn credential files that are upload-only for remote sandboxes.)rS   rV   )rY   rS   Ú	Exceptionrd   Ú
isinstanceÚdictr   rb   )rS   Úmountsr[   s      r   Ú_credential_host_pathsrj   ›   s{   € ðÝEÙ+Ó-ˆñ
 óSáˆEœz¨%´×6ô 	3Ø;@¿9¹9À[×;Qô 	3Ô˜u [Õ1Ö2ÙñSð Søô ô Ü‹uŠðüòSs!   ‚A" “A=°A=Á	A=Á"A:Á9A:c                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r   Úremote_pathsr   ©r=   r"   )r   s   "r   r   r   §   s"   € ÷ Eñ E¤D¬¥Ið E´#ñ Er   c                ó@   € RRP                  R V  4       4      ,           # )z<Build a shell ``rm -f`` command for a batch of remote paths.zrm -f Ú c              3   óN   "  € T F  p\         P                  ! V4      x € K  	  R # 5i©N©ÚshlexÚquote)Ú.0Úps   & r   Ú	<genexpr>Ú$quoted_rm_command.<locals>.<genexpr>©   s   é € ÐD±|°!œuŸ{š{¨1Ÿ~˜~³|ùó   ‚#%©Újoin)rl   s   &r   Úquoted_rm_commandr|   §   s   € à�c—h‘hÑD±|ÓDÓDÕDÐDr   c                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r   Údirsr   rm   )r   s   "r   r   r   ¬   s"   € ÷ @ñ @œt¤C�yð @¬Sñ @r   c                ó@   € RRP                  R V  4       4      ,           # )z>Build a shell ``mkdir -p`` command for a batch of directories.z	mkdir -p ro   c              3   óN   "  € T F  p\         P                  ! V4      x € K  	  R # 5irq   rr   )ru   Úds   & r   rw   Ú'quoted_mkdir_command.<locals>.<genexpr>®   s   é € Ð!?¹$°Q¤%§+¢+¨a§. .»$ùry   rz   )r~   s   &r   Úquoted_mkdir_commandrƒ   ¬   s   € à˜Ÿ™Ñ!?¹$Ó!?Ó?Õ?Ð?r   c                ó~   € V ^8„  d   QhR\         \        \        \        3,          ,          R\         \        ,          /# )r   r\   r   ©r=   rQ   r"   )r   s   "r   r   r   ±   s/   € ÷ Fñ Fœd¤5¬¬c¨¥?Õ3ð F¼¼S½	ñ Fr   c           	     ót   € \        V  UUu0 uF  w  r\        P                  ! V4      kK  	  upp4      # u uppi )zCExtract sorted unique parent directories from (host, remote) pairs.)ÚsortedÚ	posixpathÚdirname)r\   Ú_Úremotes   &  r   Úunique_parent_dirsrŒ   ±   s,   € ä¹eÔD¹e±°”9×$Ò$ VÖ,¹eÒDÓEÐEùÓDs   ‹!4
c                ó0   € V ^8„  d   QhR\         R\         /# )r   Úpathr   r!   )r   s   "r   r   r   ¶   s   € ÷ ñ ”sð œsñ r   c                ó  a€ \         P                  ! 4       p\        V R4      ;_uu_ 4       o\        V3R lR4       F  pVP	                  V4       K  	  RRR4       VP                  4       #   + '       g   i     TP                  4       # ; i)z$Return hex SHA-256 digest of a file.Úrbc                  ó&   <€ S P                  R 4      # )i   )Úread)Úfs   €r   Ú<lambda>Ú_sha256_file.<locals>.<lambda>º   s   ø€  !§&¡&¨¤-r   r   N)ÚhashlibÚsha256ÚopenÚiterÚupdateÚ	hexdigest)rŽ   ÚhÚchunkr“   s   &  @r   Ú_sha256_filerž   ¶   se   ø€ ä�ŠÓ€AÜ	ˆd�D×	Ô	˜QÜÔ/°Ö5ˆEØ�H‰H�UŽOñ 6÷ 
ð �;‰;‹=Ð÷ 
Ö	ð �;‰;‹=Ðús   «)A,Á,B	c                   ó\  a € ] tR t^¿t o Rt]RR3V 3R lR lltRR/V 3R lR lltRR/V 3R	 lR
 lltV 3R lR lt	V 3R lR lt
R#V 3R lR lltR#V 3R lR lltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltR#V 3R lR lltR#RR/V 3R lR lllt]V 3R  lR! l4       tR"tV tR# )$ÚFileSyncManagerzúTracks local file changes and syncs to a remote environment. Backends supply transport
callbacks (upload, delete) and a file-source callable; the manager handles mtime-based
change detection, deletion tracking, rate limiting, and transactional state.Nc                óZ   <€ V ^8„  d   QhRS[ RS[RS[RS[RS[R,          RS[R,          /# )r   Úget_files_fnÚ	upload_fnÚ	delete_fnÚsync_intervalÚbulk_upload_fnNÚbulk_download_fn)Ú
GetFilesFnÚUploadFnÚDeleteFnÚfloatÚBulkUploadFnÚBulkDownloadFn)r   Ú__classdict__s   "€r   r   ÚFileSyncManager.__annotate__Ä   sQ   ø€ ÷ ,ñ ,á ð,ñ ð,ñ ð	,ñ
 ð,ñ % tÕ+ð,ñ )¨4Õ/ñ,r   c                óÊ   € Wn         W n        WPn        W`n        W0n        \
        P                  ! 4       V n        / V n        / V n	        \        4       V n        R V n        W@n        R# )g        N)Ú_get_files_fnÚ
_upload_fnÚ_bulk_upload_fnÚ_bulk_download_fnÚ
_delete_fnÚ	threadingÚLockÚ_transaction_lockÚ_synced_filesÚ_pushed_hashesrd   Ú_upload_only_host_pathsÚ_last_sync_timeÚ_sync_interval)Úselfr¢   r£   r¤   r¥   r¦   r§   s   &&&&&&&r   Ú__init__ÚFileSyncManager.__init__Ä   sW   € ð *ÔØ#ŒØ-ÔØ!1ÔØ#ŒÜ!*§¢Ó!1ˆÔØCEˆÔØ.0ˆÔÜ14³ˆÔ$Ø&)ˆÔØ+Ör   ÚforceFc                ó$   <€ V ^8„  d   QhRS[ RR/# ©r   rÁ   r   N©r,   )r   r®   s   "€r   r   r¯   Ø   s   ø€ ÷ 0ñ 0™Tð 0¨dñ 0r   c               óŒ   € V P                   ;_uu_ 4        V P                  VR7       RRR4       R#   + '       g   i     R# ; i)a  Run a sync cycle: upload changed files, delete removed files. Rate-limited to once
per ``sync_interval`` unless *force* or ``HERMES_FORCE_FILE_SYNC=1``. Transactional:
state is committed only if ALL operations succeed; on failure it rolls back so the
next cycle retries everything.)rÁ   N)r¸   Ú_sync_transaction)r¾   rÁ   s   &$r   ÚsyncÚFileSyncManager.syncØ   s0   € ð
 ×#×#Ó#Ø×"Ñ"¨Ð"Ô/÷ $×#×#Ò#úó	   •2²A	c                ó$   <€ V ^8„  d   QhRS[ RR/# rÃ   rÄ   )r   r®   s   "€r   r   r¯   à   s   ø€ ÷ .Qñ .Q©$ð .Q¸4ñ .Qr   c          	     óÀ  € V'       gV   \         P                  P                  \        4      '       g-   \	        4       V P
                  ,
          V P                  8  d   R# V P                  4       pV P                  P                  \        4       4       \        V P                  4      p\        V P                  4      p V P                  V4      w  rVpV'       g    V'       g   W`n        \	        4       V n        R# \        P                   ! RR7      ;_uu_ 4       p. p	/ p
\#        V4       Ff  w  pw  rÍ\         P$                  P'                  V\)        V4      4      p\*        P,                  ! WÎ4       \/        V4      W­&   V	P1                  Wí34       Kh  	  V P3                  W—4       RRR4       V P                  P                  X
4       V F1  pVP5                  VR4       V P                  P5                  VR4       K3  	  W`n        \	        4       V n        R#   + '       g   i     Ly; i  \6         d.   pY0n        Y@n        \8        P;                  RT4        Rp?R# Rp?ii ; i)z:Execute one sync cycle while holding the per-manager lock.Nzhermes-sync-push-©Úprefixz-file_sync: sync failed, rolled back state: %s)r&   Úenvironr   Ú_FORCE_SYNC_ENVÚ
_monotonicr¼   r½   r±   r»   rš   rj   rh   r¹   rº   Ú
_plan_syncr9   ÚTemporaryDirectoryÚ	enumeraterŽ   r{   r"   rE   Úcopy2rž   ÚappendÚ_pushÚpoprf   r   r   )r¾   rÁ   Úcurrent_filesÚ
prev_filesÚprev_hashesÚ	to_uploadÚ	new_filesÚ	to_deleteÚstagingÚstaged_filesÚpushed_hashesÚindexrV   Úremote_pathÚstaged_pathrv   Úexcs   &$               r   rÆ   Ú!FileSyncManager._sync_transactionà   sÒ  € ÷ Ü—J‘J—N‘N¤?×3Ò3Ü“˜t×3Ñ3Õ3°d×6IÑ6IÔIÙà×*Ñ*Ó,ˆØ×$Ñ$×+Ñ+Ô,BÓ,DÔEÜ˜$×,Ñ,Ó-ˆ
Ü˜4×.Ñ.Ó/ˆð"	Qð /3¯o©o¸mÓ.LÑ+ˆI )ç§YØ%.Ô"Ü'1£|�Ô$Ùô ×,Ò,Ð4G×HÕHÈGØ!�Ø "�Ü7@ÀÖ7KÑ3�EÑ3˜IÜ"$§'¡'§,¡,¨w¼¸E»
Ó"C�KÜ—L’L Ô8Ü1=¸kÓ1J�MÑ.Ø ×'Ñ'¨Ð(BÖCñ	 8Lð
 —
‘
˜<Ô3÷ Ið ×Ñ×&Ñ& }Ô5Û�Ø—‘˜a Ô&Ø×#Ñ#×'Ñ'¨¨4Ö0ñ ð "+ÔÜ#-£<ˆDÖ ÷ I×Hûô  ô 	QØ!+ÔØ"-Ôô �N‰NÐJÈC×PÒPûð	Qús>   Â<#H% Ã H% Ã7H% ÄBHÆ!A/H% ÈH"	ÈH% È%IÈ0"IÉIc                óÐ   <€ V ^8„  d   QhRS[ S[S[S[3,          ,          RS[S[ S[S[S[3,          ,          S[S[S[S[S[S[S[3,          3,          S[ S[,          3,          /# )r   rØ   r   )r=   rQ   r"   rh   r   )r   r®   s   "€r   r   r¯     s`   ø€ ÷ /ñ /Ù!¡%©©S¨¥/Õ2ð/á	‰t‘E™#™s˜(•OÕ$¡d©3±±c¹3ÁÁSÐ6HÕ0IÐ+IÕ&JÉDÑQTÍIÐUÕ	Vñ/r   c                ó  € . p\        V P                  4      pV F�  w  rE\        V4      pVe!   V P                  P                  V4      V8X  d   K6  \	        V^ ,          4      '       d   \
        MTpWsV&   V P                  P                  V4      pVe   \        V4      V8X  d   K‹  VP                  WE34       KŸ  	  V U	U
u0 uF  w  ršV
kK	  	  pp	p
V P                   Uu. uF  qÌV9  g   K  VNK  	  ppW#V3# u up
p	i u upi )zZDiff *current_files* against synced state -> ``(to_upload, new_synced_state, to_delete)``.)	rh   r¹   r   r   r   Ú_RACY_SYNC_KEYrº   rž   rÕ   )r¾   rØ   rÛ   rÜ   rV   râ   Úfile_keyÚrecorded_keyÚpushed_hashrŠ   r‹   Úcurrent_remote_pathsrv   rÝ   s   &&            r   rÑ   ÚFileSyncManager._plan_sync  sþ   € ð ,.ˆ	Ü˜×+Ñ+Ó,ˆ	Û&3Ñ"ˆIÜ& yÓ1ˆHØÒ 4×#5Ñ#5×#9Ñ#9¸+Ó#FÈ(Ô#RÙô .;¸8ÀA½;×-GÒ-G�>ÈXˆLØ%1�kÑ"Ø×-Ñ-×1Ñ1°+Ó>ˆKØÒ&¬<¸	Ó+BÀkÔ+QÙØ×Ñ˜iÐ5Ö6ñ '4ñ 9FÔF¹©9¨1£¹ÐÑFØ $× 2Ò 2ÓTÑ 2˜1Ð?SÑ6S—Q�QÑ 2ˆ	ÐTØ YÐ.Ð.ùó  GùÚTs   Ã C7ÃC=Ã+C=c                ó`   <€ V ^8„  d   QhRS[ S[S[S[3,          ,          RS[ S[,          RR/# )r   rÛ   rÝ   r   Nr…   )r   r®   s   "€r   r   r¯   '  s3   ø€ ÷ =ñ =™t¡E©#©s¨(¥OÕ4ð =ÁÁcÅð =Ètñ =r   c                óö  € V'       d    \         P                  R\        V4      4       V'       d    \         P                  R\        V4      4       V'       d@   V P                  e2   V P                  V4       \         P                  R\        V4      4       M2V F,  w  r4V P	                  W44       \         P                  RW44       K.  	  V'       d*   V P                  V4       \         P                  RV4       R# R# )zCRun the transport calls for one cycle (bulk upload when available).zfile_sync: uploading %d file(s)z+file_sync: deleting %d stale remote file(s)Nz#file_sync: bulk-uploaded %d file(s)zfile_sync: uploaded %s -> %szfile_sync: deleted %s)r   r@   r.   r³   r²   rµ   )r¾   rÛ   rÝ   rV   râ   s   &&&  r   rÖ   ÚFileSyncManager._push'  sª   € çÜ�L‰LÐ:¼CÀ	»NÔKßÜ�L‰LÐFÌÈIËÔWß˜×-Ñ-Ò9Ø× Ñ  Ô+Ü�L‰LÐ>ÄÀIÃÕOã*3Ñ&�	Ø—‘ 	Ô7Ü—‘Ð;¸YÖTñ +4÷ Ø�O‰O˜IÔ&Ü�L‰LÐ0°)Ö<ñ r   c                ó2   <€ V ^8„  d   QhRS[ R,          RR/# ©r   Úhermes_homeNr   r   )r   r®   s   "€r   r   r¯   9  s#   ø€ ÷ Añ A¡T¨D¥[ð A¸Dñ Ar   c                óŒ   € V P                   ;_uu_ 4        V P                  VR7       RRR4       R#   + '       g   i     R# ; i)zðPull remote changes back to the host: download the remote ``.hermes/`` as a tar and
apply only files whose SHA-256 differs from what was pushed. SIGINT is deferred until
complete; concurrent gateway sandboxes are serialized via a file lock.)ró   N)r¸   Ú_sync_back_transaction)r¾   ró   s   &&r   Ú	sync_backÚFileSyncManager.sync_back9  s0   € ð ×#×#Ó#Ø×'Ñ'°KÐ'Ô@÷ $×#×#Ò#úrÉ   c                ó2   <€ V ^8„  d   QhRS[ R,          RR/# rò   r   )r   r®   s   "€r   r   r¯   @  s#   ø€ ÷ bñ b±$¸µ+ð bÈñ br   c                ój  € V P                   f   R# V P                  '       g*   V P                  '       g   \        P	                  R4       R# T;'       g    \        4       R,          pVP                  P                  RRR7       Rp\        \        4       F  p V P                  V4        R# 	  \        P                  R\        V4       R#   \         d\   pTpT\        ^,
          8  d=   \        T,          p\        P                  RT^,           YV4       \        T4        Rp?K’   Rp?K˜  Rp?ii ; i)zLExecute sync-back (with retries) against a stable snapshot of manager state.Nu+   sync_back: no prior push state â€” skippingz
.sync.lockT)ÚparentsÚexist_okz2sync_back: attempt %d failed (%s), retrying in %dsz%sync_back: all %d attempts failed: %s)r´   rº   r¹   r   r@   r   ÚparentÚmkdirÚrangeÚ_SYNC_BACK_MAX_RETRIESÚ_sync_back_oncerf   Ú_SYNC_BACK_BACKOFFr   Ú_sleep)r¾   ró   Ú	lock_pathÚlast_excÚattempträ   Údelays   &&     r   rõ   Ú&FileSyncManager._sync_back_transaction@  sþ   € à×!Ñ!Ò)Ùð ×"×"Ð"¨4×+=×+=Ð+=Ü�L‰LÐFÔGÙà ×5Ð5¤OÓ$5¸ÕEˆ	Ø×Ñ×Ñ t°dÐÔ;à%)ˆÜÔ3Ö4ˆGð"Ø×$Ñ$ YÔ/Úñ 5ô 	�‰Ð>Ô@VÐX`Öaøô ô "Ø�ØÔ3°aÕ7Ô7Ü.¨wÕ7�EÜ—N‘NÐ#WÐY`ÐcdÕYdÐfiÔqÜ˜5—M’Mõ 8ûð"ús   ÂCÃD2ÃA
D-Ä-D2c                ó$   <€ V ^8„  d   QhRS[ RR/# ©r   r  r   Nr   )r   r®   s   "€r   r   r¯   \  s   ø€ ÷ 7ñ 7©ð 7°$ñ 7r   c                óÆ  a€ \         P                  ! 4       \         P                  ! 4       J p. oRpV'       dP   \        P                  ! \        P
                  4      pV3R lp\        P                  ! \        P
                  V4        V P                  V4       V'       d\   VeV   \        P                  ! \        P
                  V4       S'       d'   \        P                  ! \        P
                  4       R# R# R# R#   T'       dY   TeT   \        P                  ! \        P
                  T4       S'       d&   \        P                  ! \        P
                  4       i i i i ; i)z>Single sync-back attempt with SIGINT protection and file lock.Nc                 óV   <€ SP                  W34       \        P                  R 4       R# )z/sync_back: SIGINT deferred until sync completesN)rÕ   r   r@   )ÚsignumÚframeÚdeferred_sigints   &&€r   Ú_defer_sigintÚ6FileSyncManager._sync_back_once.<locals>._defer_sigintg  s    ø€ Ø×&Ñ&¨ Ô7Ü—‘ÐNÖOr   )r¶   Úcurrent_threadÚmain_threadÚsignalÚ	getsignalÚSIGINTÚ_sync_back_lockedÚraise_signal)r¾   r  Úon_main_threadÚoriginal_handlerr  r  s   &&   @r   r   ÚFileSyncManager._sync_back_once\  sð   ø€ ô #×1Ò1Ó3´y×7LÒ7LÓ7NÐNˆà(*ˆØÐßÜ%×/Ò/´·±Ó>ÐõPô �MŠMœ&Ÿ-™-¨Ô7ð		7Ø×"Ñ" 9Ô-çÐ"2Ò">Ü—’œfŸm™mÐ-=Ô>ß"ô ×'Ò'¬¯©Ö6ñ	 #ñ #?‰~ø�~Ð"2Ò">Ü—’œfŸm™mÐ-=Ô>ß"ô ×'Ò'¬¯©Õ6ð	 #ð #?ˆ~ús   ÂC> Ã>9E Ä8(E c                ó$   <€ V ^8„  d   QhRS[ RR/# r	  r   )r   r®   s   "€r   r   r¯   w  s   ø€ ÷ ñ ©4ð °Dñ r   c                óê  € \         f   V P                  4        R# \        VRRR7      p \         P                  ! V\         P                  4       V P                  4         \         P                  ! V\         P
                  4       VP                  4        R#   \         d     Li ; i   \         P                  ! T\         P
                  4       M  \         d     Mi ; iTP                  4        i ; i)z;Sync-back under file lock (serializes concurrent gateways).NÚwzutf-8)Úencoding)ÚfcntlÚ_sync_back_implr˜   ÚflockÚLOCK_EXÚLOCK_UNr?   Úclose)r¾   r  Úlock_fds   && r   r  Ú!FileSyncManager._sync_back_lockedw  s°   € äŠ=à× Ñ Ô"ÙÜ�y #°Ô8ˆð	Ü�KŠK˜¤§¡Ô/Ø× Ñ Ô"ðÜ—’˜G¤U§]¡]Ô3ð �M‰MŽOøô ô ÙðûðÜ—’˜G¤U§]¡]Õ3øÜô Ùðúà�M‰M�OúsA   ª5B( Á %B ÂB%Â$B%Â(C2Â*%CÃC2ÃCÃC2ÃCÃC2c                ó   <€ V ^8„  d   QhRR/# )r   r   Nr(   )r   r®   s   "€r   r   r¯   ˆ  s   ø€ ÷ 7ñ 7 ñ 7r   c                ó  € V P                   f   \        R4      h \        V P                  4       4      p\        4        \        P                  ! \        4       RR7      w  r#\        P                  ! V4        V P                  \        V4      4        \        P                  P                  V4      p\        4       pWE8”  d6   \         P#                  RWE\$        4         \        P&                  ! V4       R# \        P(                  ! \        4       R7      ;_uu_ 4       p\*        P,                  ! V4      ;_uu_ 4       pVP/                  VRR7       RRR4       V P0                  \3        4       ,          p^ p	\        P4                  ! V4       Fƒ  w  r«pV Fw  p\        P                  P7                  W­4      pR	\        \        P                  P9                  Wæ4      4      P;                  4       ,           pW�P=                  WïW4      ,          p	Ky  	  K…  	  V	'       d   \         P?                  R
V	4       M\         PA                  R4       RRR4        \        P&                  ! V4       R#   \         d    . p ELCi ; i  \         d    ^ p ELÚi ; i  \         d     R# i ; i  + '       g   i     ELZ; i  + '       g   i     Lw; i  \         d     R# i ; i   \        P&                  ! T4       i   \         d     i i ; i; i)z1Download, diff, and apply remote changes to host.Nz/_sync_back_impl called without bulk_download_fnz.tar)rÍ   Úsuffixu]   sync_back: remote tar is %d bytes (cap %d, override with terminal.%s) â€” skipping extractionrÌ   Údata)ÚfilterÚ/z%sync_back: applied %d changed file(s)z%sync_back: no remote changes detected)!r´   ÚRuntimeErrorr=   r±   rf   rM   r9   Úmkstempr)   r&   r$  r   rŽ   Úgetsizer?   r   r   r   r   rG   rÒ   Útarfiler˜   Ú
extractallr»   rj   Úwalkr{   ÚrelpathÚas_posixÚ_apply_staged_fileÚinfor@   )r¾   Úfile_mappingÚfdÚtar_pathÚtar_sizeÚ	max_bytesrÞ   ÚtarÚupload_onlyÚappliedÚdirpathÚ	_dirnamesÚ	filenamesÚfnameÚstaged_filerâ   s   &               r   r   ÚFileSyncManager._sync_back_implˆ  sX  € à×!Ñ!Ò)ÜÐPÓQÐQð	Ü × 2Ñ 2Ó 4Ó5ˆLô 	&Ô'ô  ×'Ò'Ô/EÓ/GÐPVÔW‰ˆÜ
�Š�Œð$	Ø×"Ñ"¤4¨£>Ô2ðÜŸ7™7Ÿ?™?¨8Ó4�ô -Ó.ˆIØÔ#Ü—‘ØsØÔ)AôCð ð(Ü—	’	˜(Ö#ô' ×,Ò,Ô4JÓ4L×MÕMÐQXÜ—\’\ (×+Ô+¨sØ—N‘N 7°6�NÔ:÷ ,ð #×:Ñ:Ô=SÓ=UÕU�Ø�Ü57·W²W¸WÖ5EÑ1�G¨	Û!*˜Ü&(§g¡g§l¡l°7Ó&B˜à&)¬D´·±·±ÀÓ1VÓ,W×,`Ñ,`Ó,bÕ&b˜Ø×#:Ñ#:¸;ÐUaÓ#oÕošó	 "+ñ 6F÷ Ü—K‘KÐ GÈÕQä—L‘LÐ!HÔI÷! Nð$Ü—	’	˜(Ö#øô[ ô 	Ø‹Lð	ûô" ô Ø“ðûô: ô Úðú÷' ,×+Ð+ú÷ N×Mûô( ô ÚðûðÜ—	’	˜(Õ#øÜô ÙðýsÆ   ›I' Á7K ÂI; Â1+K ÃJ Ã6'K ÄJ5Ä<J!	ÅC	J5È,J5ÉK ÉK É'I8É7I8É;JÊK ÊJÊK ÊJÊJÊ!J2Ê,	J5Ê5K	Ë K ËKËKËLËK3Ë2LË3LË>LÌ LÌLc          
      ón   <€ V ^8„  d   QhRS[ RS[ RS[S[S[ S[ 3,          ,          RS[S[ ,          RS[/# )r   rC  râ   r7  Úupload_only_host_pathsr   )r"   r=   rQ   rd   r   )r   r®   s   "€r   r   r¯   Á  sI   ø€ ÷ ñ ÙðÙ-0ðÙ@DÁUÉ3ÑPSÈ8Å_Õ@UðÙorÑsvÕowðá	ñr   c                ó‚  € V P                   P                  V4      pVe   \        V4      V8X  d   ^ # V P                  W#4      pVf0   V P	                  W#VR7      pVf   \
        P                  RV4       ^ # V P                  Wd4      '       d   \
        P                  RV4       ^ # VeL   \        P                  P                  V4      '       d'   \        V4      V8w  d   \
        P                  RV4       \        P                  ! \        P                  P                  V4      RR7       \        P                  ! W4       ^# )a  Copy one extracted remote file onto the host if it changed since push. Returns 1 if
applied, 0 if skipped (unchanged, unmapped, or an upload-only credential). A host file
modified since push is overwritten with the remote version (last-write-wins) with a warning.)rF  z(sync_back: skipping %s (no host mapping)z2sync_back: skipping upload-only credential file %suw   sync_back: conflict on %s â€” host modified since push, remote also changed. Applying remote version (last-write-wins).T)rû   )rº   r   rž   Ú_resolve_host_pathÚ_infer_host_pathr   r@   Ú_is_upload_only_host_pathr&   rŽ   Úexistsr   Úmakedirsr‰   rE   rÔ   )r¾   rC  râ   r7  rF  rë   rV   s   &&&&&  r   r5  Ú"FileSyncManager._apply_staged_fileÁ  sý   € ð ×)Ñ)×-Ñ-¨kÓ:ˆØÒ"¤|°KÓ'@ÀKÔ'OÙà×+Ñ+¨KÓFˆ	ØÒØ×-Ñ-¨kÐ`vÐ-ÓwˆIØÒ Ü—‘ÐGÈÔUÙà×)Ñ)¨)×LÒLÜ�L‰LÐMÈ{Ô[ÙàÒ"¤r§w¡w§~¡~°i×'@Ò'@Ä\ÐR[ÓE\Ð`kÔEkÜ�N‰Nð^àôô
 	�Š”B—G‘G—O‘O IÓ.¸Õ>Ü�Š�[Ô,Ùr   c                ón   <€ V ^8„  d   QhRS[ RS[S[S[ S[ 3,          ,          R,          RS[ R,          /# )r   râ   r7  Nr   rP   )r   r®   s   "€r   r   r¯   à  sB   ø€ ÷ bñ b©cð bÁÁeÉCÑQTÈHÅoÕAVÐY]ÕA]ð bÑilÐosÕisñ br   c                óD   a€ \        V3R lT;'       g    .  4       R4      # )zAFind the host path for a known remote path from the file mapping.c              3   ó>   <"  € T F  w  rVS8X  g   K  Vx € K  	  R # 5irq   r(   )ru   Úhostr‹   râ   s   &  €r   rw   Ú5FileSyncManager._resolve_host_path.<locals>.<genexpr>â  s   øé € ÐZÑ.@™l˜dÀFÈkÑDY—T’TÓ.@ùs   ƒ“
N)Únext)r¾   râ   r7  s   &f&r   rH  Ú"FileSyncManager._resolve_host_pathà  s"   ø€ äÔZ¨l×.@Ð.@¸bÐ.@ÓZÐ\`ÓaÐar   rF  c          	      ó’   <€ V ^8„  d   QhRS[ RS[S[S[ S[ 3,          ,          R,          RS[S[ ,          R,          RS[ R,          /# )r   râ   r7  NrF  r   )r"   r=   rQ   rd   )r   r®   s   "€r   r   r¯   ä  sK   ø€ ÷ ñ ©Cð ¹tÁEÉ#ÉsÈ(ÅOÕ?TÐW[Õ?[ð Ù14±Sµ¸DµðÙLOÐRVÍJñr   c               óf  € T;'       g    \        4       pT;'       g    .  FŒ  w  rEV P                  WC4      '       d   K  \        P                  ! V4      pVP	                  VR,           4      '       g   KT  \        \        V4      P                  V\        V4      ^,           R ,          4      u # 	  R# )zçInfer a host path for a new remote file by matching path prefixes: an existing
remote->host pair whose parent directory prefixes *remote_path* gets the same
substitution (``/root/.hermes/skills/b.md`` -> ``~/.hermes/skills/b.md``).r,  N)	rd   rJ  rˆ   r‰   Ú
startswithr"   r   rü   r.   )r¾   râ   r7  rF  rQ  r‹   Ú
remote_dirs   &&&$   r   rI  Ú FileSyncManager._infer_host_pathä  s•   € ð
 "8×!@Ð!@¼3»5ÐØ(×.Ð.¨BÒ.‰LˆDØ×-Ñ-¨d×KÒKÙÜ"×*Ò*¨6Ó2ˆJØ×%Ñ% j°3Õ&6×7Ô7Üœ4 ›:×,Ñ,¨{¼3¸z»?ÈQÕ;NÐ;OÐ/PÕPÓQÒQñ /ñ r   c                ó<   <€ V ^8„  d   QhRS[ RS[S[ ,          RS[/# )r   rV   rF  r   )r"   rd   r,   )r   r®   s   "€r   r   r¯   ó  s,   ø€ ÷ Kñ K©Sð KÉ#ÉcÍ(ð KÑW[ñ Kr   c                ó   € \        V 4      V9   # rq   )rb   )rV   rF  s   &&r   rJ  Ú)FileSyncManager._is_upload_only_host_pathò  s   € ä% iÓ0Ð4JÑJÐJr   )r´   r³   rµ   r±   r¼   rº   r½   r¹   r¸   r²   r»   rq   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú_SYNC_INTERVAL_SECONDSr¿   rÇ   rÆ   rÑ   rÖ   rö   rõ   r   r  r   r5  rH  rI  ÚstaticmethodrJ  Ú__static_attributes__Ú__classdictcell__)r®   s   @r   r    r    ¿   sÏ   ø‡ € ñTð  6Ø.2Ø26÷,ò ,ð(0 E÷ 0ò 0ð.Q°÷ .Qò .Q÷`/ð /÷.=ð =÷$Aò A÷bò b÷87ð 7÷6ð ÷"7ð 7÷rð ÷>bò bñØCG÷ó ð ÷Kó öKr   r    )éÿÿÿÿrf  rf  rf  )r   é   é   l        i  rq   )rX   )=ra  r–   Úloggingr&   rˆ   rs   rE   r  r0  r9   r¶   r;   r  ÚImportErrorÚpathlibr   Útypingr   r1   Úhermes_constantsr   Útools.environments.baser   Úutilsr   Ú	getLoggerr]  r   Úsleepr  Ú	monotonicrÐ   rb  rÏ   rè   r"   r©   r=   rQ   r¬   r­   rª   r¨   rÿ   r  r   r   r%   r<   r   r)   r4   rM   r]   rb   rj   r|   rƒ   rŒ   rž   r    r(   r   r   Ú<module>rs     sy  ðñó Û Û 	Û Û Û Û Û Û Û Û ðÛõ Ý ã å ,Ý 3Ý à	×	Ò	˜8Ó	$€ð 
�‰€Ø�^‰^€
àÐ Ø*€à!€ð �S˜#�J Ð$Õ%€Ø˜˜e C¨ H�oÕ.Ð/°Ð5Õ6€Ø˜4˜& $˜,Õ'€Ø�T˜#•Y�K Ð%Õ&€Ø�b˜$˜u S¨# X�Õ/Ð/Õ0€
àÐ ØÐ Ø-Ð Ø0Ð Ø,Ð ð #Ð õ õ5õ,÷÷Bõ 1õ	SõEõ
@õ
Fõ
÷uKó uKøðS ô ØƒEðús   °E Å	EÅE