
    (Gj_                       U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
mZ ddlmZ ddlmZmZmZ ddlmZmZ ddlmZ dadZdZ ej        d          ZdbdZdcdZdddZdedZdfdZ  e!            Z"de#d<   dgdhdZ$ej%        dgdid            Z&d Z'djd#Z(e
 G d$ d%                      Z)e
 G d& d'                      Z*dkd*Z+dld-Z,dmd/Z-dnd1Z.dddddddd2dod:Z/d;d<dpd@Z0dqdCZ1ddddddDdrdEZ2dd;dFdsdIZ3dtdJZ4dudKZ5dtdLZ6dvdMZ7dvdNZ8dvdOZ9dPZ:dwdQZ;dxdRZ<d;dSdydWZ=dzdYZ>d;d<d{dZZ? ej        d[          Z@d\d]d|d`ZAdS )}u  Per-profile first-class Project store.

A **Project** is a human-named, multi-folder workspace. Unlike the desktop's
old inferred "workspaces" (derived from each session's ``cwd`` + a git probe)
and unlike kanban's self-generated worktrees, a Project is an explicit,
persisted entity the user creates and names. It anchors:

- **Desktop session grouping** — a session belongs to a project when its
  ``cwd`` lives under one of the project's folders (longest-prefix match).
- **Kanban task worktrees** — a task linked to a project creates its worktree
  under the project's primary repo with a deterministic branch name, instead
  of the random ``wt/<task-id>`` fallback.

Scope: **per-profile**, stored at ``$HERMES_HOME/projects.db`` (resolved via
``get_hermes_home()``), mirroring sessions / config / cron. This deliberately
differs from kanban, whose board DB is root-anchored and shared across
profiles. A Project may *bind* a kanban board (``board_slug``) so the two
systems agree on the repo + branch convention without merging their stores.

The schema is intentionally small and additive: column additions go through
:func:`_add_column_if_missing` so opening an old DB is always safe.
    )annotationsN)	dataclassfield)Path)IterableListOptional)add_column_if_missing	write_txnget_hermes_homereturnr   c                 $    t                      dz  S )zThe per-profile projects DB path (``$HERMES_HOME/projects.db``).

    Profile-aware: ``get_hermes_home()`` already points at the active profile's
    home. Tests pass an explicit ``db_path`` to :func:`connect`.
    projects.dbr        </home/rurouni/.hermes/hermes-agent/hermes_cli/projects_db.pyprojects_db_pathr   ,   s     },,r   a  
CREATE TABLE IF NOT EXISTS projects (
    id            TEXT PRIMARY KEY,
    slug          TEXT NOT NULL UNIQUE,
    name          TEXT NOT NULL,
    description   TEXT,
    icon          TEXT,
    color         TEXT,
    board_slug    TEXT,
    primary_path  TEXT,
    created_at    INTEGER NOT NULL,
    archived      INTEGER NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS project_folders (
    project_id  TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    path        TEXT NOT NULL,
    label       TEXT,
    is_primary  INTEGER NOT NULL DEFAULT 0,
    added_at    INTEGER NOT NULL,
    PRIMARY KEY (project_id, path)
);

CREATE INDEX IF NOT EXISTS idx_project_folders_path
    ON project_folders(path);

CREATE TABLE IF NOT EXISTS project_meta (
    key    TEXT PRIMARY KEY,
    value  TEXT
);

-- Git repos found by scanning the filesystem (desktop "repo-first" discovery).
-- Cached here so the overview is instant after the first scan instead of
-- re-walking the disk every time the Projects view opens.
CREATE TABLE IF NOT EXISTS discovered_repos (
    root          TEXT PRIMARY KEY,
    label         TEXT,
    last_seen     INTEGER NOT NULL
);
z^[a-z0-9][a-z0-9\-_]{0,63}$namestrc                    t          | pd                                                                          }t          j        dd|                              d          }|dd                             d          }|pdS )z8Derive a slug candidate from a human name (best-effort). z
[^a-z0-9]+--_N@   project)r   striplowerresub)r   ss     r   _slugifyr"   n   sm    DJB%%''A
}c1%%++D11A	#2#TA>	r   slugOptional[str]c                    | dS t          |                                                                           }|sdS t                              |          st          d| d          |S )z>Lowercase + strip a slug; validate; return ``None`` for empty.Nzinvalid project slug zc: must be 1-64 chars, lowercase alphanumerics / hyphens / underscores, not starting with '-' or '_')r   r   r   _SLUG_REmatch
ValueError)r#   r!   s     r   normalize_slugr)   v   s}    |tD		!!A t>>! 
D   
 
 	

 Hr   c                 0    dt          j        d          z   S )Np_   )secrets	token_hexr   r   r   _new_project_idr/      s    '#A&&&&r   intc                 B    t          t          j                              S N)r0   timer   r   r   _nowr4      s    ty{{r   pathc                    t           j                            t           j                            t	          |                                                               }|                    d          p|S )zEAbsolute, user-expanded, separator-normalized path (no trailing sep)./\)osr5   abspath
expanduserr   r   rstrip)r5   ps     r   _normalize_pathr=      sJ    
**3t99??+<+<==>>A88E??ar   zset[str]_INITIALIZED_PATHSdb_pathOptional[Path]sqlite3.Connectionc                :   | | nt                      }|j                            dd           t          |                                          }t          j        t          |                    }	 t
          j        |_        ddl	m
}  ||d           |                    d           |t          vrC|                    t                     t          |           t                              |           n## t"          $ r |                                  w xY w|S )	a  Open (and initialize if needed) the per-profile projects DB.

    WAL with DELETE fallback for network filesystems (shared helper from
    ``hermes_state``). Schema init is idempotent (``CREATE TABLE IF NOT
    EXISTS`` + additive migrations) and cached per-path per-process.
    NT)parentsexist_okr   )apply_wal_with_fallbackr   )db_labelzPRAGMA foreign_keys=ON)r   parentmkdirr   resolvesqlite3connectRowrow_factoryhermes_staterE   executer>   executescript
SCHEMA_SQL_migrate_add_optional_columnsadd	Exceptionclose)r?   r5   resolvedconnrE   s        r   rK   rK      s    )77/?/A/ADKdT2224<<>>""H?3t99%%D";888888}====-...---z***)$///""8,,,   

 Ks   2BC8 8 Dc              #     K   t          |           }	 |V  	 |                                 dS # t          $ r Y dS w xY w# 	 |                                 w # t          $ r Y w w xY wxY w)au  Open a projects DB connection and guarantee it is closed on exit.

    sqlite3's connection context manager only commits/rollbacks; it does NOT
    close the file descriptor. Long-lived processes (gateway, dashboard) route
    many project operations through ``connect()``; without closing, FDs to
    ``projects.db`` accumulate. Mirrors ``kanban_db.connect_closing``.
    )r?   N)rK   rU   rT   )r?   rW   s     r   connect_closingrY      s       7###D


	JJLLLLL 	 	 	DD		JJLLLL 	 	 	D	s;   A  / 
== A'AA'
A$!A'#A$$A')
board_slugprimary_pathiconcolorrW   Nonec                    d |                      d          D             }t          D ]}||vrt          | d|| d           dS )zCAdd columns introduced after v1 to legacy DBs (safe on every open).c                    h | ]
}|d          S )r   r   ).0rows     r   	<setcomp>z0_migrate_add_optional_columns.<locals>.<setcomp>   s    OOOCCKOOOr   zPRAGMA table_info(projects)projectsz TEXTN)rO   _OPTIONAL_PROJECT_COLUMNS_add_column_if_missing)rW   colscols      r   rR   rR      sc    OO4<<0M#N#NOOOD( I Id??"4SS---HHHI Ir   c                  L    e Zd ZU ded<   dZded<   dZded<   d	Zd
ed<   ddZdS )ProjectFolderr   r5   Nr$   labelFbool
is_primaryr   r0   added_atr   dictc                R    | j         | j        t          | j                  | j        dS )Nr5   rk   rm   rn   )r5   rk   rl   rm   rn   selfs    r   to_dictzProjectFolder.to_dict   s-    IZt//	
 
 	
r   r   ro   )__name__
__module____qualname____annotations__rk   rm   rn   rt   r   r   r   rj   rj      sf         IIIEJH
 
 
 
 
 
r   rj   c                      e Zd ZU ded<   ded<   ded<   ded<   dZded	<   dZded
<   dZded<   dZded<   dZded<   dZ	ded<    e
e          Zded<   ddZdS )Projectr   idr#   r   r0   
created_atNr$   descriptionr\   r]   rZ   r[   Frl   archived)default_factoryList[ProjectFolder]foldersr   ro   c                    | j         | j        | j        | j        | j        | j        | j        | j        t          | j	                  | j
        d | j        D             dS )Nc                6    g | ]}|                                 S r   )rt   )ra   fs     r   
<listcomp>z#Project.to_dict.<locals>.<listcomp>  s     :::		:::r   )r|   r#   r   r~   r\   r]   rZ   r[   r   r}   r   )r|   r#   r   r~   r\   r]   rZ   r[   rl   r   r}   r   rr   s    r   rt   zProject.to_dict   s`    'II+IZ/ -T]++/::T\:::
 
 	
r   ru   )rv   rw   rx   ry   r~   r\   r]   rZ   r[   r   r   listr   rt   r   r   r   r{   r{      s         GGGIIIIIIOOO!%K%%%%DE $J$$$$"&L&&&&H#(5#>#>#>G>>>>
 
 
 
 
 
r   r{   rb   sqlite3.Rowc                6   |                                  }t          | d         | d         | d         | d         d|v r| d         nd d|v r| d         nd d|v r| d         nd d|v r| d         nd d	|v r| d	         nd d
|v rt          | d
                   nd
  
        S )Nr|   r#   r   r}   r~   r\   r]   rZ   r[   r   F)
r|   r#   r   r}   r~   r\   r]   rZ   r[   r   )keysr{   rl   )rb   r   s     r   _project_from_rowr   	  s    88::Dt9[[|$*74*?*?C&&T"dNNS[[%ooc'll4(4(<(<3|$$$,:d,B,BS((*4*<*<c*o&&&%   r   
project_idr   c                l    |                      d|f                                          }d |D             S )NzySELECT path, label, is_primary, added_at FROM project_folders WHERE project_id = ? ORDER BY is_primary DESC, added_at ASCc           
     ~    g | ]:}t          |d          |d         t          |d                   |d                   ;S )r5   rk   rm   rn   rq   )rj   rl   ra   rs     r   r   z!_load_folders.<locals>.<listcomp>  s]         	6G*AlO,,z]		
 	
 	
  r   rO   fetchall)rW   r   rowss      r   _load_foldersr     sQ    <<	F	  hjj	 	
     r   r   c                :    t          | |j                  |_        |S r2   )r   r|   r   )rW   r   s     r   _attach_foldersr   *  s    #D'*55GONr   	candidatec                *   |}d}|}|                      d|f                                          c|dz  }d| }|ddt          |          z
                               d          |z   }|                      d|f                                          c|S )z=Return ``candidate`` or ``candidate-2``, ``-3`` ... if taken.   z%SELECT 1 FROM projects WHERE slug = ?Nr   r   r   )rO   fetchonelenr;   )rW   r   basenr#   suffixs         r   _unique_slugr   4  s    D	AD
,,/$ hjj 	
QQ'rCKK''(0066? ,,/$ hjj Kr   )r#   r   r[   r~   r\   r]   rZ   r   Optional[Iterable[str]]r[   r~   r\   r]   rZ   c                  t          |pd                                          }|st          d          |rt          |          nt	          |          }	t                      }
t                      }g }|pg D ],}t          |          }|r||vr|                    |           -|rt          |          nd}|r||vr|	                    d|           |
|r|d         }t          |           5  t          | |	          }|                     d|
||||||rt          |          nd||f	           |D ]%}|                     d|
|d||k    rdnd|f           &	 ddd           n# 1 swxY w Y   |
S )zCreate a project and return its id.

    ``folders`` are normalized to absolute paths. If ``primary_path`` is given
    it is added to the folder set (if not already present) and marked primary;
    otherwise the first folder becomes primary.
    r   project name must not be emptyNr   zINSERT INTO projects (id, slug, name, description, icon, color, board_slug,  primary_path, created_at, archived) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0)zbINSERT INTO project_folders (project_id, path, label, is_primary, added_at) VALUES (?, ?, ?, ?, ?)r   )r   r   r(   r)   r"   r/   r4   r=   appendinsertr   r   rO   )rW   r   r#   r   r[   r~   r\   r]   rZ   slug_candidatepidnowfolder_pathsr   normprimaryuniquer5   s                     r   create_projectr   B  s   $ tzr??  ""D ;9:::-1E^D)))x~~N


C
&&C L] & &q!! 	&D,,%%%/;Eol+++G (7,..Aw'''<q/	4  dN334
 .8Bz***d
	
 	
 	
" ! 	 	DLL) dDtw!!AsC	   	'              4 Js   .A)E$$E(+E(F)include_archivedr   rl   List[Project]c                    d}|s|dz  }|dz  }                      |                                          } fd|D             S )NzSELECT * FROM projectsz WHERE archived = 0z ORDER BY created_at ASCc                J    g | ]}t          t          |                     S r   )r   r   )ra   r   rW   s     r   r   z!list_projects.<locals>.<listcomp>  s,    FFFAOD"3A"6"677FFFr   r   )rW   r   sqlr   s   `   r   list_projectsr     s_     #C %$$%%C<<%%''DFFFFFFFFr   
id_or_slugOptional[Project]c                *   |                      d|f                                          }|H|                      dt          |                                          f                                          }|dS t	          | t          |                    S )z,Look up a project by id first, then by slug.z#SELECT * FROM projects WHERE id = ?Nz%SELECT * FROM projects WHERE slug = ?)rO   r   r   r   r   r   )rW   r   rb   s      r   get_projectr     s     ,,-
} hjj  {ll3c*oo6K6K6M6M5O
 

(** 	 {t4!23!7!7888r   )r   r~   r\   r]   rZ   c               d   g }g }|\t          |                                          }	|	st          d          |                    d           |                    |	           |*|                    d           |                    |           |,|                    d           |                    |pd           |,|                    d           |                    |pd           |M|                    d           |                    |                                rt	          |          nd           |sdS |                    |           t          |           5  |                     d	d
                    |           d|          }
ddd           n# 1 swxY w Y   |
j        dk    S )u  Patch top-level project fields. Only provided fields change.

    ``icon``, ``color``, and ``board_slug`` accept an empty string to clear
    (store NULL) — passing ``None`` leaves the field untouched, so callers that
    want to clear must send ``""``.
    Nr   zname = ?zdescription = ?zicon = ?z	color = ?zboard_slug = ?FzUPDATE projects SET z, z WHERE id = ?r   )	r   r   r(   r   r)   r   rO   joinrowcount)rW   r   r   r~   r\   r]   rZ   setsparamsr   curs              r   update_projectr     s     DFIIOO 	?=>>>Ja%&&&k"""Jdld###K   emt$$$$%%%J4D4D4F4FPnZ000DQQQ u
MM*	4 
 
llA499T??AAA6
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 <!s   ".FF #F )rk   rm   rk   rm   c                  t          |          }|st          d          t          | |          t          d|           t                      }t	          |           5  |                     d||||f           ||                     d|||f           |rt          | ||           n<|                     d|f                                          }|t          | ||           ddd           n# 1 swxY w Y   |S )zAdd a folder to a project. Returns the normalized path.

    When ``is_primary`` is set, the folder becomes the project's primary repo
    (the previous primary is demoted, and ``projects.primary_path`` updates).
    zfolder path must not be emptyNzno such project: zlINSERT OR IGNORE INTO project_folders (project_id, path, label, is_primary, added_at) VALUES (?, ?, ?, 0, ?)zFUPDATE project_folders SET label = ? WHERE project_id = ? AND path = ?zESELECT 1 FROM project_folders WHERE project_id = ? AND is_primary = 1)r=   r(   r   r4   r   rO   _set_primary_lockedr   )rW   r   r5   rk   rm   r   r   existing_primarys           r   
add_folderr     s|    4  D :89994$$,9Z99:::
&&C	4 < <% uc*		
 	
 	
 LL4
D)  
  
	<j$7777  $||:    hjj	 
  '#D*d;;;/< < < < < < < < < < < < < < <0 Ks    BC22C69C6c                   t          |          }t          |           5  |                     d||f                                          }|                     d||f          }|h|d         r`|                     d|f                                          }|r|d         nd}|rt	          | ||           n|                     d|f           ddd           n# 1 swxY w Y   |j        dk    S )	zCRemove a folder from a project. Repoints primary if it was primary.zHSELECT is_primary FROM project_folders WHERE project_id = ? AND path = ?z=DELETE FROM project_folders WHERE project_id = ? AND path = ?Nrm   zSSELECT path FROM project_folders WHERE project_id = ? ORDER BY added_at ASC LIMIT 1r5   z4UPDATE projects SET primary_path = NULL WHERE id = ?r   )r=   r   rO   r   r   r   )rW   r   r5   r   was_primaryr   nxtnew_primarys           r   remove_folderr     sY   4  D	4  ll0
 
 (**	 	
 llK
 
 "{<'@",,0  hjj	 
 *-6#f++$K #D*kBBBBJM  )              0 <!s   B-CCCc                    |                      d|f           |                      d||f           |                      d||f           dS )z:Set the primary folder (caller already holds a write txn).z>UPDATE project_folders SET is_primary = 0 WHERE project_id = ?zKUPDATE project_folders SET is_primary = 1 WHERE project_id = ? AND path = ?z1UPDATE projects SET primary_path = ? WHERE id = ?N)rO   )rW   r   r5   s      r   r   r     st     	LLH	   	LL	,	T  
 	LL;	z    r   c                   t          |          }t          |           5  |                     d||f                                          }|	 d d d            dS t	          | ||           d d d            n# 1 swxY w Y   dS )Nz?SELECT 1 FROM project_folders WHERE project_id = ? AND path = ?FT)r=   r   rO   r   r   )rW   r   r5   r   existss        r   set_primaryr   -  s    4  D	4 4 4M
 
 (** 	 >4 4 4 4 4 4 4 4 	D*d3334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4s   .A7A77A;>A;c                    t          |           5  |                     d|f          }d d d            n# 1 swxY w Y   |j        dk    S )Nz-UPDATE projects SET archived = 1 WHERE id = ?r   r   rO   r   rW   r   r   s      r   archive_projectr   :      	4 
 
ll;j]
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 <!   488c                    t          |           5  |                     d|f          }d d d            n# 1 swxY w Y   |j        dk    S )Nz-UPDATE projects SET archived = 0 WHERE id = ?r   r   r   s      r   restore_projectr   B  r   r   c                    t          |           5  |                     d|f          }ddd           n# 1 swxY w Y   |j        dk    S )z0Hard-delete a project and its folders (cascade).z!DELETE FROM projects WHERE id = ?Nr   r   r   s      r   delete_projectr   J  s    	4 O Oll>NNO O O O O O O O O O O O O O O<!r   	active_idc                    t          |           5  ||                     dt          f           n|                     dt          |f           ddd           dS # 1 swxY w Y   dS )z9Set (or clear, when ``None``) the active project pointer.Nz&DELETE FROM project_meta WHERE key = ?ziINSERT INTO project_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value)r   rO   _ACTIVE_META_KEY)rW   r   s     r   
set_activer   Y  s    	4  LLADTCVWWWWLLH!:.  	                 s   =AA!Ac                v    |                      dt          f                                          }|r|d         nd S )Nz,SELECT value FROM project_meta WHERE key = ?value)rO   r   r   )rW   rb   s     r   get_active_idr   f  s?    
,,69I8K hjj  (3w<<D(r   )replacerepos#Iterable[tuple[str, Optional[str]]]r   c                  t                      }g }|D ]P\  }}t          |          }|s|                    ||p t          j                            |          p||f           Qt          |           5  |r|                     d           |r|                     d|           ddd           n# 1 swxY w Y   t          |          S )a  Persist scanned git repo roots into the cache.

    ``repos`` is an iterable of ``(root, label)``. Roots are normalized; the
    label falls back to the basename. Returns the number of rows written.

    When ``replace`` is true, this is the authoritative result of a fresh disk
    scan: delete stale rows first so old eval/worktree noise disappears instead
    of living forever in the cache.
    zDELETE FROM discovered_reposzINSERT INTO discovered_repos (root, label, last_seen) VALUES (?, ?, ?) ON CONFLICT(root) DO UPDATE SET label = excluded.label, last_seen = excluded.last_seenN)
r4   r=   r   r8   r5   basenamer   rO   executemanyr   )rW   r   r   r   r   rootrk   r   s           r   record_discovered_reposr   r  s)    &&CD L Let$$ 	TECRW%5%5d%;%;CtcJKKKK	4 	 	 	9LL7888 	1 	  		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 t99s   30B//B36B3
List[dict]c                h    |                      d                                          }d |D             S )z;All cached discovered repo roots, most-recently-seen first.zKSELECT root, label, last_seen FROM discovered_repos ORDER BY last_seen DESCc                >    g | ]}|d          |d         |d         dS )r   rk   	last_seen)r   rk   r   r   r   s     r   r   z)list_discovered_repos.<locals>.<listcomp>  s>        6QwZanMM  r   r   )rW   r   s     r   list_discovered_reposr     sE    <<U hjj 	    r   c               0   t          |pd                                          sdS t          |          }d}|s|dz  }d}d}|                     |                                          D ]}|d         }||k    s`|                    |                    d          t          j        z             s+|                    |                    d          dz             r*t          |          |k    rt          |          }|d	         }|dS t          | |          S )
zReturn the project owning ``path`` (longest-prefix folder match).

    A folder owns ``path`` when ``path`` equals the folder or is nested under
    it. The most specific (longest) folder wins, so nested projects resolve to
    the innermost one.
    r   NznSELECT pf.project_id AS pid, pf.path AS folder FROM project_folders pf JOIN projects p ON p.id = pf.project_idz WHERE p.archived = 0folderr7   /r   )r   r   r=   rO   r   
startswithr;   r8   sepr   r   )	rW   r5   r   targetr   best_pidbest_lenrb   r   s	            r   project_for_pathr     s'    tzr??  "" tT""F	J   '&&"HH||C  ))++ & &XVv00u1E1E1NOO!!&--"6"6"<== 6{{X%%v;;u:ttX&&&r   z[^a-z0-9._-]+r   )titletask_idr   c               X   | j         pt          | j                  }| d| }|rt                              dt          |                                                                                                        d          }|dd                             d          }|r| d| }|S )zDeterministic branch name for a project-linked kanban task.

    Shape: ``<project-slug>/<task-id>`` (optionally ``-<title-slug>``). Stable
    and human-meaningful, replacing the random ``wt/<task-id>`` fallback.
    r   r   N(   )r#   r"   r   _BRANCH_SAFE_REr    r   r   r   )r   r   r   r#   r   tslugs         r   branch_name_forr     s     <18GL11DWD %##CU)9)9););)A)A)C)CDDJJ3OOcrc
  %% 	%$$U$$DKr   )r   r   )r   r   r   r   )r#   r$   r   r$   )r   r   )r   r0   )r5   r   r   r   r2   )r?   r@   r   rA   )r?   r@   )rW   rA   r   r^   )rb   r   r   r{   )rW   rA   r   r   r   r   )rW   rA   r   r{   r   r{   )rW   rA   r   r   r   r   )rW   rA   r   r   r#   r$   r   r   r[   r$   r~   r$   r\   r$   r]   r$   rZ   r$   r   r   )rW   rA   r   rl   r   r   )rW   rA   r   r   r   r   )rW   rA   r   r   r   r$   r~   r$   r\   r$   r]   r$   rZ   r$   r   rl   )rW   rA   r   r   r5   r   rk   r$   rm   rl   r   r   )rW   rA   r   r   r5   r   r   rl   )rW   rA   r   r   r5   r   r   r^   )rW   rA   r   r   r   rl   )rW   rA   r   r$   r   r^   )rW   rA   r   r$   )rW   rA   r   r   r   rl   r   r0   )rW   rA   r   r   )rW   rA   r5   r   r   rl   r   r   )r   r{   r   r   r   r   r   r   )B__doc__
__future__r   
contextlibr8   r   r-   rJ   r3   dataclassesr   r   pathlibr   typingr   r   r	   hermes_cli.sqlite_utilr
   rf   r   hermes_constantsr   r   rQ   compiler&   r"   r)   r/   r4   r=   setr>   ry   rK   contextmanagerrY   re   rR   rj   r{   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>r     s    . # " " " " "     				 				    ( ( ( ( ( ( ( (       + + + + + + + + + + ] ] ] ] ] ] ] ] , , , , , ,- - - -'
d 2:455       ' ' ' '            #suu  $ $ $ $    6     ( L I I I I 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
:       "      $ '+"&!% $@ @ @ @ @ @H ;@G G G G G G9 9 9 9( !% $+ + + + + +f  + + + + + +\   <   &
 
 
 
           
 
 
 
) ) ) )  	! ! ! ! ! !H   " FK' ' ' ' ' 'B "*-.. EG        r   