
    iG                        U d 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ZddlZddl	m
Z
 ddlmZ ddlmZmZmZmZmZ  ej        e          Z e            dz  ZdZdZd	Zd
ZdZg dZ ed ed e ej         dd                                        Z!ee"d<   dZ# ej$        d          Z%de&dee&         fdZ'de&de&dee&         fdZ(de&de
fdZ)de&de&fdZ*dHdee
         de
fdZ+de&de
fdZ,de
d e&de
fd!Z-d e&de&fd"Z.de
d e&de
fd#Z/	 dHde
de&d$ee
         de0fd%Z1e!ddfd&ee&         de
de&d'ed(eee                  d$ee
         dee2e&e&f         fd)Z3de
dee
         fd*Z4de
de&dee&         fd+Z5de
de&ddfd,Z6de
de&ddfd-Z7de
dee         fd.Z8d/e&defd0Z9d/e
defd1Z:d2e
de&dee&         fd3Z; G d4 d5          Z<dee         d6e&de&fd7Z=d8Z>de
d9e&de2fd:Z?	 	 	 	 dId=ed>e2d?ee
         d@edee&ef         f
dAZ@	 	 	 	 	 dJd=edCed>e2d?ee
         d@edee&eAf         fdDZBdHd?ee
         defdEZCdHd?ee
         dee&ef         fdFZDdHd?ee
         dee&ef         fdGZEdS )KuV	  
Checkpoint Manager — Transparent filesystem snapshots via a single shared
shadow git store.

Creates automatic snapshots of working directories before file-mutating
operations (``write_file``, ``patch``, ``terminal`` with destructive flags),
triggered once per conversation turn.  Provides rollback to any previous
checkpoint.

This is NOT a tool — the LLM never sees it.  It's transparent infrastructure
controlled by the ``checkpoints`` config flag or ``--checkpoints`` CLI flag.

Storage layout (single shared store, git objects deduplicated across projects)
-----------------------------------------------------------------------------

    ~/.hermes/checkpoints/
        store/                          — single bare-ish git repo
            HEAD, config, objects/      — standard git internals (shared)
            refs/hermes/<hash16>        — per-project branch tip
            indexes/<hash16>            — per-project git index
            projects/<hash16>.json      — {workdir, created_at, last_touch}
            info/exclude                — default excludes (shared)
        .last_prune                     — auto-prune idempotency marker
        legacy-<timestamp>/             — archived pre-v2 per-project shadow
                                          repos (auto-migrated on first init)

Why a single store?
-------------------

The pre-v2 design kept a full shadow repo per working directory.  Each one
re-stored most of the project's files under its own ``objects/`` tree, with
zero sharing across worktrees of the same project.  A single user with a
dozen worktrees of the same repo burned ~40 MB each (~500 MB total) storing
the same blobs over and over.  A single shared store lets git's content-
addressable object DB deduplicate across projects and across turns, so adding
a new worktree costs near-zero.

The shadow store uses ``GIT_DIR`` + ``GIT_WORK_TREE`` + ``GIT_INDEX_FILE``
so no git state leaks into the user's project directory.

Auto-maintenance
----------------

Shadow state accumulates over time.  ``prune_checkpoints`` deletes refs whose
recorded working directory no longer exists (orphan) or whose last touch is
older than ``retention_days`` (stale), then runs ``git gc --prune=now`` to
reclaim object storage.  A size-cap pass drops the oldest checkpoints per
project until total store size is under ``max_total_size_mb``.
    N)Path)get_hermes_home)DictListOptionalSetTuplecheckpointsstorezrefs/hermesindexesprojectszlegacy-)2znode_modules/zdist/zbuild/ztarget/zout/z.next/z.nuxt/z__pycache__/z*.pycz*.pyoz.cache/z.pytest_cache/z.mypy_cache/z.ruff_cache/z	coverage/z	.coveragez.venv/zvenv/zenv/z.git/z.hg/z.svn/z.worktrees/z*.soz*.dylibz*.dllz*.oz*.az*.jarz*.classz*.exez*.objz*.mp4z*.movz*.mkvz*.webmz*.zipz*.tarz*.tar.gzz*.tgzz*.7zz*.rarz*.isoz.envz.env.*z
.env.localz.env.*.localz	.DS_Storez	Thumbs.dbz*.log
   <   HERMES_CHECKPOINT_TIMEOUT30_GIT_TIMEOUTiP  z^[0-9a-fA-F]{4,64}$commit_hashreturnc                     | r|                                  sdS |                     d          rd| S t                              |           sd| S dS )zValidate a commit hash to prevent git argument injection.

    Returns an error string if invalid, None if valid.
    Values starting with '-' would be interpreted as git flags
    (e.g., '--patch', '-p') instead of revision specifiers.
    zEmpty commit hash-z/Invalid commit hash (must not start with '-'): z4Invalid commit hash (expected 4-64 hex characters): N)strip
startswith_COMMIT_HASH_REmatch)r   s    =/home/piyush/.hermes/hermes-agent/tools/checkpoint_manager.py_validate_commit_hashr      st      #k//11 #""c"" QPPPP  -- VUkUUU4    	file_pathworking_dirc                 "   | r|                                  sdS t          j                            |           rd| S t	          |          }|| z                                  }	 |                    |           n# t          $ r d| cY S w xY wdS )zValidate a file path to prevent path traversal outside the working directory.

    Returns an error string if invalid, None if valid.
    zEmpty file pathz/File path must be relative, got absolute path: z7File path escapes the working directory via traversal: N)r   ospathisabs_normalize_pathresolverelative_to
ValueError)r   r   abs_workdirresolveds       r   _validate_file_pathr*      s    
  !IOO-- !  	w}}Y ONNNN!+..Ki'0022HW[)))) W W WVVVVVVW4s   $A: :BB
path_valuec                 h    t          |                                                                           S )z;Return a canonical absolute path for checkpoint operations.)r   
expanduserr%   )r+   s    r   r$   r$      s(    
&&((00222r   c                     t          t          |                     }t          j        |                                                                          dd         S )z6Deterministic per-project hash: sha256(abs_path)[:16].N   )strr$   hashlibsha256encode	hexdigest)r   abs_paths     r   _project_hashr6      sF    ?;//00H>(//++,,6688"==r   basec                 $    | pt           t          z  S )z+Return the single shared shadow store path.)CHECKPOINT_BASE_STORE_DIRNAME)r7   s    r   _store_pathr;      s    #O~55r   c                     t                      S )u  Return the shared store path.

    Retained for backward-compatibility with callers / tests that imported
    this helper.  Under v2 the shadow git storage is shared across all
    projects — per-project isolation lives in refs and indexes, not in
    separate repo directories.
    )r;   )r   s    r   _shadow_repo_pathr=      s     ==r   dir_hashc                     | t           z  |z  S N)_INDEXES_DIRNAMEr   r>   s     r   _index_pathrC      s    ##h..r   c                     t            d|  S )N/)_REFS_PREFIX)r>   s    r   	_ref_namerG      s    ''X'''r   c                 "    | t           z  | dz  S )Nz.json)_PROJECTS_DIRNAMErB   s     r   _project_meta_pathrJ      s    $$('9'9'999r   
index_filec                    t          |          }t          j                                        }t	          |           |d<   t	          |          |d<   |                    dd           |                    dd           |t	          |          |d<   n|                    dd           t          j        |d<   t          j        |d<   d	|d
<   |S )uJ  Build env dict that redirects git to the shared store.

    The shared store is internal Hermes infrastructure — it must NOT inherit
    the user's global or system git config.  User-level settings like
    ``commit.gpgsign = true``, signing hooks, or credential helpers would
    either break background snapshots or, worse, spawn interactive prompts
    (pinentry GUI windows) mid-session every time a file is written.

    Isolation strategy:
    * ``GIT_CONFIG_GLOBAL=<os.devnull>`` — ignore ``~/.gitconfig`` (git 2.32+).
    * ``GIT_CONFIG_SYSTEM=<os.devnull>`` — ignore ``/etc/gitconfig`` (git 2.32+).
    * ``GIT_CONFIG_NOSYSTEM=1`` — legacy belt-and-suspenders for older git.

    ``index_file``, if given, forces git to use a per-project index under
    ``store/indexes/<hash>`` so projects don't race on a shared index.
    GIT_DIRGIT_WORK_TREEGIT_NAMESPACEN GIT_ALTERNATE_OBJECT_DIRECTORIESGIT_INDEX_FILEGIT_CONFIG_GLOBALGIT_CONFIG_SYSTEM1GIT_CONFIG_NOSYSTEM)r$   r!   environcopyr0   popdevnull)r   r   rK   normalized_working_direnvs        r   _git_envr\      s    * -[99
*//

CZZC	N566CGGOT"""GG.555 #J $'''!zC!zC!$CJr   argstimeoutallowed_returncodesc           
         t          |          }|                                sJd| }t                              dd                    dgt          |           z             |           dd|fS |                                sJd| }t                              dd                    dgt          |           z             |           dd|fS t          |t          |          |          }dgt          |           z   }	|pt                      }	 t          j        |	d	d	||t          |          
          }
|
j        dk    }|
j                                        }|
j                                        }|s>|
j        |vr5t                              dd                    |	          |
j        |           |||fS # t          j        $ r? d| dd                    |	           }t                              |d	           dd|fcY S t"          $ r}t%          |dd          }|dk    r6t                              dd                    |	          d	           Y d}~dS d| }t                              dd                    |	          |d	           dd|fcY d}~S d}~wt&          $ rM}t                              dd                    |	          |d	           ddt          |          fcY d}~S d}~ww xY w)a5  Run a git command against the shared store.  Returns (ok, stdout, stderr).

    ``allowed_returncodes`` suppresses error logging for known/expected non-zero
    exits while preserving the normal ``ok = (returncode == 0)`` contract.
    Example: ``git diff --cached --quiet`` returns 1 when changes exist.
    zworking directory not found: zGit command skipped: %s (%s) gitF z&working directory is not a directory: rK   T)capture_outputtextr^   r[   cwdr   z(Git command failed: %s (rc=%d) stderr=%szgit timed out after zs: )exc_infofilenameNzGit executable not found: %s)Frc   zgit not foundz,Git command failed before execution: %s (%s)z#Unexpected git error running %s: %s)r$   existsloggererrorjoinlistis_dirr\   r0   set
subprocessrun
returncodestdoutr   stderrTimeoutExpiredFileNotFoundErrorgetattr	Exception)r]   r   r   r^   r_   rK   rZ   msgr[   cmdresultokrt   ru   excmissing_targets                   r   _run_gitr     sF    -[99!((** F.DFF3SXXugT

>R5S5SUXYYYb#~!((** O7MOO3SXXugT

>R5S5SUXYYYb#~
5#455*
M
M
MC'DJJ
C-6 #*++
 
 
 !#$$&&$$&& 	f'/BBBLL:v0&   66!!$   @W@@#@@S4(((b#~    j$77U""LL7#QULVVV------F.DFFCSXXc]]TWbfgggb#~ # # #:CHHSMM3Y]^^^b#c(("""""""#s@   B(F8 8AK5	K5AJ:JK5K5(AK0*K50K5c                    |                                  sdS t          |           }d}t          t          h}t	          |                                           D ]}|j        }||v s|                    t                    r)|ot          j
        d          }| t           | z  }	 |                    dd           n4# t          $ r'}t                              d|           Y d}~ dS d}~ww xY w||z  }	 t          j        t#          |          t#          |                     # t          $ r&}t                              d||           Y d}~d}~ww xY w|}	|t                              d|           |S )a<  Move pre-v2 per-project shadow repos into a ``legacy-<ts>/`` dir.

    The pre-v2 layout had one shadow git repo per working directory directly
    under ``CHECKPOINT_BASE``.  The v2 layout wants a single ``store/`` dir.
    Rather than delete the old data (users might want to recover), rename
    everything except our own v2 entries into ``legacy-<timestamp>/``.  The
    legacy dir is subject to the same retention sweep and can be manually
    cleared with ``hermes checkpoints clear-legacy``.

    Returns the legacy-archive path, or None if nothing to migrate.
    Nz%Y%m%d-%H%M%STparentsexist_okz'Could not create legacy archive dir: %sz*Could not archive legacy checkpoint %s: %sz_Migrated pre-v2 checkpoint repos to %s. Clear with `hermes checkpoints clear-legacy` when safe.)rj   r;   r:   _PRUNE_MARKER_NAMErn   iterdirnamer   _LEGACY_PREFIXtimestrftimemkdirOSErrorrk   warningshutilmover0   info)
r7   r   legacy_rootreservedchildr   stampr~   dest_s
             r   _migrate_legacy_storer   S  s    ;;== tE"&K 23Hdllnn%% U Uz8t~>> M/22EN!;E!;!;;K!!$!>>>>   H#NNNtttttt T!	UKE

CII.... 	U 	U 	UNNGPSTTTTTTTT	U 	AF	
 	
 	

 s0   %B==
C.C))C.7/D''
E1EEc                    | j         }|                                 sD	 |                    dd           n# t          $ r}d| cY d}~S d}~ww xY wt	          |           | dz                                  rdS |                     dd           | t
          z                      d           | t          z                      d           t          j        	                                }t          j
        |d<   t          j
        |d<   d	|d
<   dD ]}|                    |d           	 t          j        dddt          |           gdd|t                    }|j        dk    rd|j                                         S n(# t          j        t(          f$ r}d| cY d}~S d}~ww xY wt          |          }t+          g d| |           t+          g d| |           t+          g d| |           t+          g d| |           t+          g d| |           | dz  }|                    d           |dz                      d                    t0                    dz   d           t2                              d|            dS )zInitialise the shared shadow store if needed.  Returns error or None.

    Also performs one-time migration of pre-v2 per-directory shadow repos
    into ``legacy-<timestamp>/``.
    Tr   z"Could not create checkpoint base: NHEAD)r   rR   rS   rT   rU   )rM   rN   rQ   rO   rP   rb   initz--bare)re   rf   r[   r^   r   zShadow store init failed: )configz
user.emailzhermes@local)r   z	user.namezHermes Checkpoint)r   zcommit.gpgsignfalse)r   ztag.gpgSignr   )r   zgc.auto0r   exclude
utf-8encodingz"Initialised checkpoint store at %s)parentrj   r   r   r   rA   rI   r!   rV   rW   rY   rX   rq   rr   r0   r   rs   ru   r   rv   rw   r   
write_textrm   DEFAULT_EXCLUDESrk   debug)	r   r   r7   r~   init_envkr|   cfg_wdinfo_dirs	            r   _init_storer     s    <D<<>> $	>JJtdJ3333 	> 	> 	>=========	> 	d###   t	KKtK,,,
$$d$333
%%t%444
 z  H$&JH !$&JH !&)H"#2  Q	2FHc%jj1d,
 
 

 !!G0C0C0E0EGGG "%'89 2 2 21C111111112 YYF555ufEEE9995&III222E6BBB///???'''777v~HNNDN!!!	%%		"##d*W &    LL5u===4s9   5 
AA	A	A)AF   F%F F% F%c                    t          |          }t          | |          }t          j                    }t          t	          |                    ||d}|                                ro	 t          j        |                    d                    }t          |t                    r|                    d|          |d<   n# t          t          f$ r Y nw xY w	 |j                            dd           |                    t          j        |          d           dS # t          $ r'}t$                              d||           Y d}~dS d}~ww xY w)	zDCreate or update ``projects/<hash>.json`` with workdir + timestamps.)workdir
created_at
last_touchr   r   r   Tr   z'Could not write project metadata %s: %sN)r6   rJ   r   r0   r$   rj   jsonloads	read_text
isinstancedictgetr   r'   r   r   r   dumpsrk   r   )r   r   r>   	meta_pathnowmetaexistingr~   s           r   _register_projectr     sn   [))H"5(33I
)++C !=!=>> #38 8D 	z)"5"5w"5"G"GHHH(D)) E%-\\,%D%D\"$ 	 	 	D	Ptd;;;TZ--@@@@@ P P P>	3OOOOOOOOOPs,   (AB? ?CCAD 
E(E

Ec                 t   t          |          }t          | |          }|                                st          | |           dS 	 t	          j        |                    d                    }n# t          t          f$ r i }Y nw xY wt          t          |                    |d<   t          j                    |d<   |                    d|d                    	 |                    t	          j        |          d           dS # t          $ r'}t                              d||           Y d}~dS d}~ww xY w)z7Update last_touch for a project, preserving created_at.Nr   r   r   r   r   z(Could not update project metadata %s: %s)r6   rJ   rj   r   r   r   r   r   r'   r0   r$   r   
setdefaultr   r   rk   r   )r   r   r>   r   r   r~   s         r   _touch_projectr     sT   [))H"5(33I %---z)--w-??@@Z    /+6677DODOOL$|"4555QTZ--@@@@@ Q Q Q?CPPPPPPPPPQs*   (A0 0BB)D 
D7D22D7c                 j   | t           z  }|                                sg S g }|                    d          D ]z}|j        }	 t	          j        |                    d                    }n# t          t          f$ r Y Fw xY wt          |t                    s`||d<   |                    |           {|S )z/Return all registered projects under the store.z*.jsonr   r   _hash)rI   rj   globstemr   r   r   r   r'   r   r   append)r   projects_diroutr   r>   r   s         r   _list_projectsr     s    ,,L   	C!&&x00 	 		>	:i1171CCDDDD$ 	 	 	H	$%% 	 W

4Js   (A++A?>A?r"   c                     d}	 t          |                               d          D ]}|dz  }|t          k    r|c S n# t          t          f$ r Y nw xY w|S )z;Quick file count estimate (stops early if over _MAX_FILES).r   *   )r   rglob
_MAX_FILESPermissionErrorr   )r"   countr   s      r   _dir_file_countr     s    Ed!!#&& 	 	AQJEz!! "	 W%   Ls   7> > AAc                     d}	 |                      d          D ]C}	 |                                r||                                j        z  }4# t          $ r Y @w xY wn# t          $ r Y nw xY w|S )z9Best-effort recursive size in bytes.  Returns 0 on error.r   r   )r   is_filestatst_sizer   )r"   totalps      r   _dir_size_bytesr     s    EC 	 	A99;; .QVVXX--E   		    Ls4   A 0AA 
AA AA 
A+*A+shadow_repoc                     t          | |          }|r|S t          | |           	 | dz                      t          t	          |                    dz   d           n# t
          $ r Y nw xY wdS )a  Backwards-compatible initialiser.

    In v1 ``shadow_repo`` was a per-project dir; in v2 it's the shared
    ``store/`` path (or a test path that we respect).  We initialise the
    store at ``shadow_repo``, create per-project markers, and return None
    on success.
    HERMES_WORKDIRr   r   r   N)r   r   r   r0   r$   r   )r   r   errs      r   _init_shadow_repor   "  s     k;
/
/C
 
k;///	'	'33,,--4w 	4 	
 	
 	
 	
    4s   7A 
A+*A+c            	       $   e Zd ZdZ	 	 	 	 d"dededed	efd
Zd#dZd$dededefdZ	dede
e         fdZedededdfd            ZdededefdZd%dedededefdZdedefdZdededefdZdedededdfdZdedededdfd Zdeddfd!ZdS )&CheckpointManageraB  Manages automatic filesystem checkpoints.

    Designed to be owned by AIAgent.  Call ``new_turn()`` at the start of
    each conversation turn and ``ensure_checkpoint(dir, reason)`` before
    any file-mutating tool call.  The manager deduplicates so at most one
    snapshot is taken per directory per turn.

    Parameters
    ----------
    enabled : bool
        Master switch (from config / CLI flag).
    max_snapshots : int
        Keep at most this many checkpoints per directory.
    max_total_size_mb : int
        Hard ceiling on total store size.  Oldest checkpoints per project
        are dropped when the store exceeds this after a commit.
    max_file_size_mb : int
        Skip adding any single file larger than this to a checkpoint.
        (Implemented via ``.gitignore`` excludes + a post-stage size check.)
    F     r   enabledmax_snapshotsmax_total_size_mbmax_file_size_mbc                    || _         t          dt          |                    | _        t          dt          |                    | _        t          dt          |                    | _        t                      | _        d | _        d S )Nr   r   )	r   maxintr   r   r   rp   _checkpointed_dirs_git_available)selfr   r   r   r   s        r   __init__zCheckpointManager.__init__S  su      C$6$677!$Q,=(>(>!?!? #As+;'<'< = =,/EE.2r   r   Nc                 8    | j                                          dS )zAReset per-turn dedup.  Call at the start of each agent iteration.N)r   clear)r   s    r   new_turnzCheckpointManager.new_turne  s    %%'''''r   autor   reasonc                 D   | j         sdS | j        <t          j        d          du| _        | j        st                              d           | j        sdS t          t          |                    }|dt          t          j	                              fv rt                              d|           dS || j
        v rdS | j
                            |           	 |                     ||          S # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)u   Take a checkpoint if enabled and not already done this turn.

        Returns True if a checkpoint was taken, False otherwise.
        Never raises — all errors are silently logged.
        FNrb   z#Checkpoints disabled: git not foundrE   z,Checkpoint skipped: directory too broad (%s)z!Checkpoint failed (non-fatal): %s)r   r   r   whichrk   r   r0   r$   r   homer   add_takery   )r   r   r   abs_dires        r   ensure_checkpointz#CheckpointManager.ensure_checkpointm  s5    | 	5&"(,u"5"5T"AD& DBCCC" 	5ok2233 sC	,,---LLGQQQ5d---5##G,,,	::gv... 	 	 	LL<a@@@55555	s   C/ /
D9DDc           	         t          t          |                    }t          t                    }|dz                                  sg S t          t          |                    }t          d|ddt          | j                  g||ddh          \  }}}|r|sg S g }|	                                D ]}	|	
                    dd	          }
t          |
          d
k    r}|
d         |
d         |
d         |
d	         dddd}t          dd|
d          d|
d         g||ddh          \  }}}|r|r|                     ||           |                    |           |S )z?List available checkpoints for a directory (most recent first).r   logz--format=%H|%h|%aI|%sz-n      r_   |      r   r      )hash
short_hash	timestampr   files_changed
insertions	deletionsdiffz--shortstatz~1)r0   r$   r;   r9   rj   rG   r6   r   r   
splitlinessplitlen_parse_shortstatr   )r   r   r   r   refr}   rt   r   resultslinepartsentrystat_okstat_outs                 r   list_checkpointsz"CheckpointManager.list_checkpoints  s   ok2233O,,&&(( 	Ig..// C14T=O9P9PQ7!$c

 
 
FA  	 	I %%'' 	& 	&DJJsA&&E5zzQ!!H"'(!&q#Ah%&"#!"  (0]uQxOOOU1XF7),c
( ( ($1
  ;x ;))(E:::u%%%r   	stat_liner  c                 r   t          j        d|           }|r%t          |                    d                    |d<   t          j        d|           }|r%t          |                    d                    |d<   t          j        d|           }|r't          |                    d                    |d<   dS dS )	z-Parse git --shortstat output into entry dict.z
(\d+) filer   r  z(\d+) insertionr  z(\d+) deletionr  N)researchr   group)r  r  ms      r   r
  z"CheckpointManager._parse_shortstat  s     ImY// 	5%(__E/"I()44 	2"%aggajj//E,I'33 	1!$QWWQZZE+	1 	1r   r   c                 l   t          |          }|rd|dS t          t          |                    }t          t                    }|dz                                  sdddS t          dd|g||          \  }}}|s	dd| ddS t          |          }	t          ||	          }
t          d	d
g||t          dz  |
           t          dd|dg|||
          \  }}}t          d|ddg|||
          \  }}}t          |	          }t          d|g|||
dh           |s|sdddS d|r|nd|r|nddS )z<Show diff between a checkpoint and the current working tree.Fsuccessrl   r   'No checkpoints exist for this directorycat-file-tCheckpoint '' not foundr   -Ar   r^   rK   r  z--stat--cachedrd   z
--no-color	read-treer   rK   r_   zCould not generate diffTrc   )r  r   r  )r   r0   r$   r;   r9   rj   r   r6   rC   r   rG   )r   r   r   hash_errr   r   r}   r   r   r>   rK   ok_statr  ok_diffdiff_outr  s                   r   r  zCheckpointManager.diff  s   (55 	9$x888ok2233O,,&&(( 	Z$/XYYY{+UG
 

As  	X$/Vk/V/V/VWWW )) 11
 	%w%)j	B 	B 	B 	B  (X{J77z 
  
  
1  ([*l;7z 
  
  
1 !!+s#UG&&)U	, 	, 	, 	,  	Jw 	J$/HIII  '/HHR '/HHR
 
 	
r   r   c                    t          |          }|rd|dS t          t          |                    }|rt          ||          }|rd|dS t	          t
                    }|dz                                  sdddS t          dd|g||          \  }}	}
|sdd| d|
pd	d
S |                     |d|d	d          d           t          |          }t          ||          }|r|nd}t          d|d|g||t          dz  |          \  }}}
|sdd|
 |
pd	d
S t          ddd|g||          \  }}}	|r|nd}d|d	d         ||d}|r||d<   |S )z$Restore files to a checkpoint state.Fr  r   r  r  r  r  r   N)r  rl   r   z$pre-rollback snapshot (restoring to    ).checkout--r   r"  zRestore failed: r   --format=%s-1unknownT)r  restored_tor   	directoryfile)r   r0   r$   r*   r;   r9   rj   r   r   r6   rC   r   )r   r   r   r   r&  r   path_errr   r}   r   r   r>   rK   restore_targetrt   ok2
reason_outr   r|   s                      r   restorezCheckpointManager.restore  s   (55 	9$x888ok2233 	=*9g>>H =#(8<<<O,,&&(( 	Z$/XYYY{+UG
 

As  	*$/Vk/V/V/V [D* * * 	

7U;rPQr?UUUVVV )) 11
&/8S"dN;7L1$4!
 
 
FC  	*$/G#/G/G [D* * * &M45ug
 
Z  #1	 &rr? 	
 
  	'&F6Nr   c                    t          |          }|                                r|}n|j        }h d}|j        k    r<t          fd|D                       rt	                    S j        j        k    <t	          |          S )z?Resolve a file path to its working directory for checkpointing.>	   .hg.gitgo.modpom.xml
Cargo.tomlpackage.jsonpyproject.tomlGemfileMakefilec              3   F   K   | ]}|z                                   V  d S r@   )rj   ).0r  checks     r   	<genexpr>z=CheckpointManager.get_working_dir_for_path.<locals>.<genexpr><  s3      99AEAI%%''999999r   )r$   ro   r   anyr0   )r   r   r"   	candidatemarkersrG  s        @r   get_working_dir_for_pathz*CheckpointManager.get_working_dir_for_path0  s    y));;== 	$IIIG G Gu|##999999999 "5zz!LE u|##
 9~~r   c                    t          t                    }t          ||          }|rt                              d|           dS t          ||           t          |          t          k    r#t                              dt          |           dS t          |          }t          ||          }t          |          }|                                r`t          dd|dz   g||dh          \  }}	}
|r|	rt          d	|	g|||dh
           nB	 |                                 n,# t          $ r Y n w xY w|j                            dd           t          ddg||t"          dz  |          \  }}
}|st                              d|           dS | j        dk    r|                     |||           t          dd|dz   g||dh          \  }}	}
|ot)          |	          }|r=t          ddd|	g||dh|          \  }}
}
|rt                              d|           dS nLt          ddg|||          \  }}}
|r1|                                st                              d|           dS t          dg|||          \  }}}|r|st                              d|           dS d|d|d g}|r	d|d!|	d|d g}t          ||||          \  }}}|r|st                              d"|           dS d#||g}|rd#|||	g}t          |||          \  }}
}|st                              d$|           dS t                              d%|||d&d'                    |                     |||           |                     |           dS )(z*Take a snapshot.  Returns True on success.z Checkpoint store init failed: %sFz#Checkpoint skipped: >%d files in %s	rev-parsez--verifyz	^{commit}r   r   r$  r%  Tr   r   r!  r   r"  zCheckpoint git-add failed: %sr   z
diff-indexr#  --quietr   )r_   rK   z$Checkpoint skipped: no changes in %sls-filesrd   z$Checkpoint skipped: empty tree in %sz
write-treez Checkpoint write-tree failed: %scommit-tree-m--no-gpg-sign-pz!Checkpoint commit-tree failed: %s
update-refz Checkpoint update-ref failed: %szCheckpoint taken in %s: %s (%s)Nr+  )r;   r9   r   rk   r   r   r   r   r6   rC   rG   rj   r   unlinkr   r   r   r   r   _drop_oversize_from_indexboolr   _prune_enforce_size_cap)r   r   r   r   r   r>   rK   r  ok_ref
ref_commitr   r}   has_refr(  ok_lsls_outok_treetree_shacommit_args	ok_commitnew_shaupdate_args	ok_updates                          r   r   zCheckpointManager._takeF  s   O,,%-- 	LL;SAAA5uk*** ;''*44LL>
KXXX5 -- 11
!!
  	A$,j#*;<{%(E% % %!FJ
  *  *-;)),	    %%''''   D ##D4#@@@ DM5+ 1$
 
 

As  	LL8#>>>5 1$$**5+zJJJ
 !)*cK&78;!$!
 !
 !

A
 -T*-- 	$z9jA{%&C%	  MGQ  C[QQQu
  (Z({%     E61
  V\\^^ C[QQQu "*NE;!"
 "
 "
3  	h 	LL;SAAA5 %hfoN 	e((D*dFTcdK"*!#
 #
 #
	7C  	 	LL<cBBB5 $S'2 	C'gzBK$
 
	1c  	LL;SAAA56VWUWVWUW[YYY 	E;,,, 	u%%%ts   D! !
D.-D.r   rK   c                 b   | j         dz  dz  }|dk    rdS t          g d|||          \  }}}|r|sdS d |                    d          D             }t          |          }	g }
|D ]K}	 |	|z                                  j        }n# t          $ r Y ,w xY w||k    r|
                    |           L|
sdS t          	                    dt          |
          | j                    d	}t          dt          |
          |          D ])}|
|||z            }t          g d
|z   |||dh           *dS )zRemove any staged file larger than ``max_file_size_mb`` from the index.

        Lets the agent keep snapshotting source code while refusing to
        swallow generated assets (datasets, model weights, logs, videos).
           r   N)rP  r#  z-zrd   c                     g | ]}||S  rj  )rF  r   s     r   
<listcomp>z?CheckpointManager._drop_oversize_from_index.<locals>.<listcomp>  s    666qA6666r    z<Checkpoint: dropping %d oversize file(s) (>%d MB) from index   )rmr#  rO  r/  r   r%  )r   r   r  r$   r   r   r   r   rk   r   r	  range)r   r   r   rK   capr}   rt   r   pathsr(   oversizerelsizeBATCHichunks                   r   rW  z+CheckpointManager._drop_oversize_from_index  s    #d*T1!88F ***;:
 
 
FA  	 	F 76FLL00666%k22  	% 	%C#c)//119   czz$$$ 	FJMM40	
 	
 	
 q#h--// 	 	AQq5y[)E333e;{z%(E    	 	s   *B
BBr  c                    t          dd|g||dh          \  }}}|sdS 	 t          |          }n# t          $ r Y dS w xY w|| j        k    rdS t          dd|g||          \  }}	}|r|	sdS |	                                }
|
| j         d         }d}|D ]t}t          d| dg||          \  }}}|r|s dS t          d	d
d|g||          \  }}}|r|r|nd}d|d|dg}|	d|d|d|dg}t          |||          \  }}}|r|s dS |}u|dS t          d||g||           t          g d||           t          g d||t
          dz             dS )u  Keep only the last ``max_snapshots`` commits on the per-project ref.

        v1's ``_prune`` was documented as a no-op (``git``'s pack mechanism
        was supposed to handle it, but only the log view was limited — loose
        objects accumulated forever).  v2 actually rewrites the ref to drop
        commits older than ``max_snapshots`` and then runs ``git gc`` on the
        store so unreachable objects are reclaimed.
        rev-list--countr   r   N	--reverserN  ^{tree}r   r0  r1  
checkpointrQ  rR  rS  rT  rU  reflogexpirez--expire=nowz--allgcz--prune=nowrO  r   r^   )r   r   r'   r   r  r   )r   r   r   r  r}   rt   r   r   ok_listlist_outcommitskeep
new_parentshar`  ra  ok_msgrz   
commit_msgr]   rc  rd  s                         r   rY  zCheckpointManager._prune  s]    !C(%!$
 
 
FA  	F	KKEE 	 	 	FF	D&&&F  (c*E; 
  
1  	h 	F%%''**++, %)
 	! 	!C#+///0%$ $ GXq  ( %tS15+ NFC !'@3@LJ!8T:OD%%xzj/;$,T5+$F$F!Iw G  JJF,Z0%EEE 	999;	
 	
 	
 	,,,;q(8	
 	
 	
 	
 	
 	
s   1 
??c           
         | j         dk    rdS | j         dz  dz  }t          |          }||k    rdS t                              d| j         |dz             t	          ddt
          g|t          |j                  dh	          \  }}}|r|sdS d
 |                                D             }d}t          d          D ]}t          |          }||k    r n|D ]}	t	          dd|	g|t          |j                  dh	          \  }
}}	 |
rt          |          nd}n# t          $ r d}Y nw xY w|dk    r^t	          dd|	g|t          |j                            \  }}}|r|s|                                }|dd         }d}d}|D ]}t	          d| dg|t          |j                            \  }}}|r|sd} nwt	          ddd|g|t          |j                            \  }}}|r|r|nd}d|d|dg}|	d|d|d|dg}t	          ||t          |j                            \  }}}|r|sd} n|}|s|dt	          d|	|g|t          |j                             d}|s nt	          g d|t          |j                             t	          g d|t          |j                  t          dz              dS )!zIf total store size exceeds ``max_total_size_mb``, drop oldest
        checkpoints across ALL projects until under the cap.
        r   Nrh  uA   Checkpoint store exceeded %d MB (actual %d MB) — pruning oldest   for-each-ref--format=%(refname)r   r   c                 :    g | ]}|                                 |S rj  r   rF  rs     r   rk  z7CheckpointManager._enforce_size_cap.<locals>.<listcomp>S  s%    <<<a!''))<<<<r   Fr   ry  rz  r   r{  rN  r|  Tr   r0  r1  r}  rQ  rR  rS  rT  rU  r~  r  r   r  )r   r   rk   r   r   rF   r0   r   r  ro  r   r'   r   )r   r   	cap_bytesrt  r}   rt   r   refsany_droppedr  ok_count	count_outr   r  r  r  r  r  failr  r`  ra  r  rz   r  r]   rc  rd  s                               r   rZ  z#CheckpointManager._enforce_size_cap<  s    !Q&&F*T1D8	u%%9FO"D[$9	
 	
 	
 !2LA3u|$$!$
 
 
FA
  	 	F<<6,,..<<<r 1	 1	A"5))Dy   +# +#)1C0%U\9J9J),* * *&)Q.6=C	NNNAEE!   EEEA::'/c2E3u|;L;L( ($1  h "--//qrr{,0
 ) )C+3$&7&7&78%U\ARAR, ,(GXq # ( #%-tS95#elBSBS& &NFC )/!H3!HLJ)8T:WD!- -xz $j/ C,4T5#elBSBS,T,T)Iw$ G #!(JJ :-,Z8%U\ARARSSS"  	9993u|$$	
 	
 	
 	,,,3u|$$lQ.>	
 	
 	
 	
 	
 	
s   DD.-D.)Fr   r   r   )r   N)r   r@   )__name__
__module____qualname____doc__rX  r   r   r   r0   r   r   r   r  staticmethodr
  r  r:  rL  r   r   rW  rY  rZ  rj  r   r   r   r   =  sV        . !$ "3 33 3 	3
 3 3 3 3$( ( ( (   S  #  4        D'C 'DJ ' ' ' 'R 
1C 
1 
1 
1 
1 
1 \
10
 0
# 0
$ 0
 0
 0
 0
d7 73 7S 7S 7TX 7 7 7 7r# #    ,D Dc Dd D D D DL,,(+,9=,	, , , ,\@
D @
s @
 @
 @
 @
 @
 @
DU
t U
 U
 U
 U
 U
 U
 U
r   r   r4  c                 "   | sd| S d| dg}t          | d          D ]\  }}|d         }d|v r}|                    d          d                             d          d                             d	          d         d
d         }|d                             d          d         }| d| }|                    dd          }|                    dd          }|                    dd          }	|rd| d|dk    rdnd d| d|	 d	}
nd}
|                    d| d|d          d| d|d          |
 	           |                    d           |                    d           |                    d           d                    |          S )z+Format checkpoint list for display to user.zNo checkpoints found for u   📸 Checkpoints for z:
r   r  T+r   r   N   ra   r  r  r  z  (z filesrc   z, +z/-r,  z  z. r  r   z4
  /rollback <N>             restore to checkpoint Nz>  /rollback diff <N>        preview changes since checkpoint NzC  /rollback <N> <file>      restore a single file from checkpoint Nr   )	enumerater  r   r   rm   )r
   r4  linesrv  cptsdatefilesinsdeler   s              r   format_checkpoint_listr    s    7696663Y3334E;** O O2_"99#q!'',,Q/55c::1=bqbABk?((--a0D2B**ff\1%%vvk1%% 	QQQEQJJSSBQQ3QQ$QQQDDDM!MMr,/MM2MMHMtMMNNNN	LLHIII	LLQRRR	LLVWWW99Ur   z.last_pruner  c                 `    t          dd|g| t          | j                  dh          \  }}}|S )z6Delete a ref from the store.  Returns True on success.rU  z-dr   r   )r   r0   r   )r   r  r}   r   s       r   _delete_refr    s@    	tS!5#el*;*; E  HB1 Ir      Tretention_daysdelete_orphanscheckpoint_baser   c           
         |pt           }dddddd}|                                s|S t          |          }d}| dk    rt          j                    | dz  z
  }|                                D ]}|                                s|j        t          k    r)|j                            t                    r| dk    rO	 |
                                j        }	n# t          $ r Y vw xY w|	|k    r	 t          |          }
t          j        |           |dxx         |
z  cc<   |dxx         dz  cc<   nC# t          $ r6}|dxx         dz  cc<   t                              d	||           Y d
}~nd
}~ww xY w|dz                                  s$|dxx         dz  cc<   d
}|rd
}|dz  }|                                rC	 |                    d                                          }n# t          t&          f$ r d
}Y nw xY w|!t)          |                                          sd}|r| dk    rld}	 |                    d          D ]4}	 |
                                j        }||k    r|}%# t          $ r Y 1w xY wn# t          $ r Y nw xY w|dk    r||k     rd}|3	 t          |          }
t          j        |           |dxx         |
z  cc<   |dk    r|dxx         dz  cc<   n|dxx         dz  cc<   # t          $ r<}|dxx         dz  cc<   t                              d|j        |           Y d
}~d
}~ww xY wt-          |          }|dz                                  r1t/          |          D ]}|                    d          pd}|                    d          pd}|s4|dxx         dz  cc<   d
}|r&|r!t)          |                                          sd}n9| dk    r3t3          |                    dd          pd          }|dk    r||k     rd}|t5          |          }t7          ||           	 t9          ||          }|                                r|                                 n# t          $ r Y nw xY w	 t=          ||          }|                                r|                                 n# t          $ r Y nw xY w|dk    r|dxx         dz  cc<   u|dxx         dz  cc<   t?          g d|tA          |                     t?          g d|tA          |          tB          dz             |dk    rJ|dz  dz  }tE          d          D ]}t          |          }
|
|k    r nt?          dd tF          g|tA          |          d!h"          \  }}}|rd# |$                                D             ng }|s nzd$}|D ]n}t?          d%d&|g|tA          |          d!h"          \  } }!}	 | rtK          |!          nd}"n# tL          $ r d}"Y nw xY w|"dk    rYt?          d%d'|g|tA          |                    \  }#}$}|#r|$s|$$                                }%|%dd
         }&d
}'d$}(|&D ]})t?          d(|) d)g|tA          |                    \  }*}+}|*r|+sd*}( nmt?          d+d,d-|)g|tA          |                    \  },}	}|,r|	r|	nd.}-d/|+d0|-d1g}.|'	d/|+d2|'d0|-d1g}.t?          |.|tA          |                    \  }/}0}|/r|0sd*}( n|0}'|(s|'Kt?          d3||'g|tA          |                     d*}p|s nt?          g d|tA          |                     t?          g d|tA          |          tB          dz             t          |          }1||1z
  }2|2|d         k    r|2|d<   |S )4u  Delete stale/orphan checkpoints and reclaim store space.

    A project entry is deleted when either:

    * ``delete_orphans=True`` and its ``workdir`` no longer exists on disk
      (the original project was deleted / moved); OR
    * its ``last_touch`` is older than ``retention_days`` days.

    Additionally, if ``max_total_size_mb > 0`` and the store exceeds that
    after orphan/stale pruning, the oldest commit per remaining project is
    dropped until the store is under the cap.

    Legacy-archive dirs (``legacy-*``) older than ``retention_days`` are
    also deleted.

    Returns a dict with counts ``{"scanned", "deleted_orphan",
    "deleted_stale", "errors", "bytes_freed"}``.

    Never raises — maintenance must never block interactive startup.
    r   scanneddeleted_orphandeleted_staleerrorsbytes_freedg        iQ r  r  r   r  z&Failed to delete legacy archive %s: %sNr   r  r   r   r   orphanr   staler  z&Failed to prune checkpoint repo %s: %sr   rc   r   r   r~  r  r   r  rh  r   r  r  r   r   c                 :    g | ]}|                                 |S rj  r  r  s     r   rk  z%prune_checkpoints.<locals>.<listcomp>s  s%    DDDa!''))DDDDr   Fry  rz  r{  rN  r|  Tr   r0  r1  r}  rQ  rR  rS  rT  rU  )'r9   rj   r   r   r   ro   r   r:   r   r   r   st_mtimer   r   rmtreerk   r   r   r   UnicodeDecodeErrorr   r   r;   r   r   floatrG   r  rC   rV  rJ   r   r0   r   ro  rF   r  r   r'   )3r  r  r  r   r7   r|   size_beforecutoffr   r  rt  r~   r   r   	wd_markernewestr   mtr   r   r>   r   r  idxmpr  _ir}   rt   r   r  any_dropok_cr  r   ok_llor  r  r  r  r  ok_ttshaok_mrz   r]   ok_cmrd  
size_afterdeltas3                                                      r   prune_checkpointsr    sv
   4 -oD F ;;== !$''K F~55 AV AV||~~ 	:'':  00 	""JJLL)   F{{U&u--e$$$}%%%-%%%'''1,'''' U U Ux   A%   GPSTTTTTTTTU &&(( 	yQ $ 		"%)G 00I!! ##'1171CCIIKKGG!34 # # #"GGG#d7mm&:&:&<&<!>nq00F	S)) ! !A!VVXX.;;%'F" ! ! ! !!    zzfvoo >
	V"5))DM%   =!!!T)!!!!!'(((A-(((('''1,''' 	V 	V 	V8!NNCUZQTUUUUUUUU	V
 E   s"5)) !	- !	-Dxx((.BHhhy))/RG 9"F %w %d7mm6J6J6L6L %!!##"488L!#<#<#ABB
>>j6&9&9$F~H%%Cs###!%22::<< !JJLLL   'x8899;;  IIKKK   !!'(((A-(((('''1,'''' 	9993t99	
 	
 	
 	,,,3t99lQ&6	
 	
 	
 	
 q  )D047IBii : :&u--9$$E (#%:LI3t99),! ! !FA
 IKRDD6#4#4#6#6DDDDPR E  +$ +$C)1#Y4eSYY-0E* * *&D)Q"26 =IA% " " " !"zz "*#[#6s4yy# #KD"a   !r !  mmooG"122;D04J D# - -(0(S*;*;*;<eSYY) )dA  $ "4 "#'D!E%-"M4=uc$ii& &
a $(?A?aa< -tT3P%1$14z$(#$@D,4T5#d)),L,L)w$ "G "#'D!E%,

 !z1 lC<eSYYOOO#HH E===s4yy   000s4yy,*:   
 !&&J*$Evm$$$ %}Ms   <C
C#"C#.AD22
E2<,E--E2 (G))G?>G?2I=
!I,+I=,
I96I=8I99I==
J
	J
 AK<<
M1L==M8Q>>
R
R8S
SS	XX,+X,   min_interval_hoursc                    |pt           }ddi}	 |                                sdddddd|d<   |S |t          z  }t          j                    }|                                ra	 t	          |                    d                                                    }	||	z
  |dz  k     rd	|d<   |S n# t          t          f$ r Y nw xY wt          | |||
          }
|
|d<   	 |
                    t          |          d           n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w|
d         |
d         z   }|dk    r3t                              d||
d         |
d         |
d         dz             nD# t          $ r7}t                              d|           t          |          |d<   Y d}~nd}~ww xY w|S )a'  Idempotent wrapper around ``prune_checkpoints`` for startup hooks.

    Writes ``CHECKPOINT_BASE/.last_prune`` on completion so subsequent
    calls within ``min_interval_hours`` short-circuit.

    Returns ``{"skipped": bool, "result": prune_checkpoints-dict,
    "error": optional str}``.
    skippedFr   r  r|   r   r   i  T)r  r  r  r   z+Could not write checkpoint prune marker: %sNr  r  zZcheckpoint auto-maintenance: pruned %d entry(ies) (%d orphan, %d stale), reclaimed %.1f MBr  r  z&checkpoint auto-maintenance failed: %srl   )r9   rj   r   r   r  r   r   r   r'   r  r   r0   rk   r   r   ry   r   )r  r  r  r  r   r7   r   markerr   last_tsr|   r~   r   s                r   maybe_auto_prune_checkpointsr    sC    -oD'/C, {{}} 	AA CM J**ikk==?? 	 0 0' 0 B B H H J JKK=#5#<<<%)C	NJ = Z(    #)) /	
 
 
 H	Mc#hh9999 	M 	M 	MLLFLLLLLLLL	M '(6/+BB199KK;'('}%5         ?EEE3xxG  Jsl    E= 1E= "AB+ *E= +B?<E= >B??E= $D  ?E=  
D/
D*%E= *D//AE= =
F>-F99F>c           
      *   | pt           }t          |          ddddg g d}|                                s|S t          |          }|                                r@t	          |          |d<   |dz                                  rt          |          D ]}|                    d          pd}|                    d          pd}t          |          }t          dd	|g|t          |          d
h          \  }}	}
	 |rt          |	          nd}n# t          $ r d}Y nw xY w|d                             ||t          |          o t          |                                          |                    d          |                    d          |d           t          |d                   |d<   |                                D ]}|                                r|j                            t&                    r	 t	          |          }n# t(          $ r d}Y nw xY w|dxx         |z  cc<   	 |                                j        }n# t(          $ r d}Y nw xY w|d                             |j        ||d           t	          |          |d<   |S )zReturn a summary of the shadow store.

    ``{"base": path, "store_size_bytes": N, "legacy_size_bytes": N,
       "total_size_bytes": N, "project_count": N, "projects": [...],
       "legacy_archives": [...]}``
    r   )r7   store_size_byteslegacy_size_bytestotal_size_bytesproject_countr   legacy_archivesr  r   r   rc   r   ry  rz  r   r   r   r   r   )r   r   rj   r   r   r  r  r  r  )r   
size_bytesmtimer  )r9   r0   rj   r;   r   r   r   rG   r   r   r'   r   rX  r   r	  r   ro   r   r   r   r   r   r  )r  r7   r   r   r   r>   r   r  r}   r  r   r  r   rt  r  s                  r   store_statusr    s    -oDD		 C ;;== 
E||~~ "1%"8"8FN""$$ 	&u--  88G,,2((9--3))#+C0%T),$ $ $ Iq 029c)nnnGG!      GGG J&&$&"7mmFW0D0D0F0F"&((<"8"8"&((<"8"8&( (     s://C  <<>> 	ej33NCC 	&u--   #$$$,$$$ZZ\\*   !"))
"+ +    .d33CJs6   =DD D =HHH0I

IIc                    | pt           }ddd}|                                s|S t          |          }	 t          j        |           ||d<   d|d<   n3# t
          $ r&}t                              d||           Y d}~nd}~ww xY w|S )	z{Nuke the entire checkpoint base (store + legacy).  Irreversible.

    Returns ``{"bytes_freed": N, "deleted": bool}``.
    r   Fr  deletedr  Tr  z&Could not clear checkpoint base %s: %sN)r9   rj   r   r   r  r   rk   r   )r  r7   r   rt  r~   s        r   	clear_allr  @  s    
 -oD
.
.C;;== 
4  DLd!MI L L L?sKKKKKKKKLJs   A 
BA??Bc                    | pt           }ddd}|                                s|S t          |                                          D ]}|                                r|j                            t                    s6	 t          |          }t          j
        |           |dxx         |z  cc<   |dxx         dz  cc<   {# t          $ r&}t                              d||           Y d}~d}~ww xY w|S )zhDelete all ``legacy-*`` archive directories.

    Returns ``{"bytes_freed": N, "deleted": count}``.
    r   r  r  r  r   z&Could not delete legacy archive %s: %sN)r9   rj   rn   r   ro   r   r   r   r   r   r  r   rk   r   )r  r7   r   r   rt  r~   s         r   clear_legacyr  S  s    
 -oD
*
*C;;== 
dllnn%% 	Q 	Q||~~ 	UZ%:%:>%J%J 		Q"5))DM%   $&	NNNaNNNN 	Q 	Q 	QNNCUCPPPPPPPP	QJs   =AC
C1C,,C1r@   )r  TNr   )r  r  TNr   )Fr  r1   r   loggingr!   r  r   rq   r   pathlibr   hermes_constantsr   typingr   r   r   r   r	   	getLoggerr  rk   r9   r:   rF   rA   rI   r   r   r   minr   getenvr   __annotations__r   compiler   r0   r   r*   r$   r6   r;   r=   rC   rG   rJ   r   r\   rX  r   r   r   r   r   r   r   r   r   r   r  r   r  r  objectr  r  r  r  rj  r   r   <module>r     s  0 0 0d    				 				             , , , , , , 3 3 3 3 3 3 3 3 3 3 3 3 3 3		8	$	$ "/##m3   = = = @ CCCCC		2Mt(T(T$U$UVVWWc W W W 
 "*344s x}     3 S Xc]    ,3 3 3 3 3 3
>s >s > > > >6 6htn 6 6 6 6 6
3 4    /t /s /t / / / /( ( ( ( ( (:d :c :d : : : : "&" """ " 
	" " " "R  .2!%;# ;#
s);#;# ;# 	;#
 "#c(+;# ;# 4c>;# ;# ;# ;#D- -$ - - - -`?t ?# ?(3- ? ? ? ?DPT P P P P P P*Q$ QS QT Q Q Q Q($ 4:    &
# 
# 
 
 
 
$ 3    (4 c hsm    6T	
 T	
 T	
 T	
 T	
 T	
 T	
 T	
nT
 s s    J # t # $     &*	n nnn d^n 	n
 
#s(^n n n nd  &*@ @@@ @ d^	@
 @ 
#v+@ @ @ @N@ @(4. @D @ @ @ @F x~ c3h    & (4. DcN      r   