
    `gj|                    `   d Z ddlm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  ej                  e      ZdZdZe G d	 d
             Zh dZdhZ	 	 	 	 	 	 ddZddZddZ	 	 d 	 	 	 	 	 	 	 d!dZd"dZd#dZd$dZd#dZ	 	 d%	 	 	 	 	 d&dZd'dZd(dZdddddd	 	 	 	 	 	 	 	 	 	 	 	 	 d)dZ y)*u  Migrate Hermes' MCP server config and Codex's installed curated plugins
to the format Codex expects in ~/.codex/config.toml.

When the user enables the codex_app_server runtime, the codex subprocess
runs its own MCP client and its own plugin runtime (Linear, Atlassian,
Asana, plus per-account ChatGPT apps via app/list). For both of those to
be useful, the user's choices need to be visible to codex too. This
module:

  1. Reads Hermes' YAML and writes equivalent [mcp_servers.<name>]
     entries to ~/.codex/config.toml.
  2. Queries codex's `plugin/list` for the openai-curated marketplace
     and writes [plugins."<name>@<marketplace>"] entries for any plugin
     the user has installed=true on their codex CLI. (This is what
     OpenClaw calls "migrate native codex plugins" — the YouTube-video-
     worthy bit Pash highlighted: Canva, GitHub, Calendar, Gmail
     pre-configured.)
  3. Writes a [permissions] default profile so users on this runtime
     don't get an approval prompt on every write attempt.

What translates (MCP servers):
  Hermes mcp_servers.<n>.command/args/env  → codex stdio transport
  Hermes mcp_servers.<n>.url/headers       → codex streamable_http transport
  Hermes mcp_servers.<n>.timeout           → codex tool_timeout_sec
  Hermes mcp_servers.<n>.connect_timeout   → codex startup_timeout_sec

What does NOT translate (warned + skipped):
  Hermes-specific keys (sampling, etc.) — codex's MCP client has no
  equivalent. Listed in the per-server skipped[] field of the report.

What's NOT migrated (intentional):
  AGENTS.md — codex respects this file natively in its cwd. Hermes' own
  AGENTS.md (project-level) is already in the worktree, so codex picks
  it up without translation. No code needed.
    )annotationsN)	dataclassfield)Path)AnyOptionaluU   # managed by hermes-agent — `hermes codex-runtime migrate` regenerates this sectionz"# end hermes-agent managed sectionc                      e Zd ZU dZdZded<    ee      Zded<    ee	      Z
ded	<    ee      Zded
<   dZded<   dZded<    ee      Zded<   dZded<   dZded<   ddZy)MigrationReportzOutcome of a migration pass.NOptional[Path]target_path)default_factoryz	list[str]migratedzdict[str, list[str]]skipped_keys_per_servermigrated_pluginsOptional[str]plugin_query_errorwrote_permissions_defaulterrorsFboolwrittendry_runc                   g }| j                   r|j                  d| j                          n*| j                  r|j                  d| j                          | j                  r|j                  dt        | j                         d       | j                  D ]M  }| j                  j                  |g       }|rddj                  |       dnd}|j                  d	| |        O n|j                  d
       | j                  rN|j                  dt        | j                         d       | j                  D ]  }|j                  d	|         n*| j                  r|j                  d| j                          | j                  r|j                  d| j                         | j                  D ]  }|j                  d|         dj                  |      S )Nz(dry run) Would write zWrote z	Migrated z MCP server(s):z (skipped: , ) z  - z&No MCP servers found in Hermes config.z native Codex plugin(s):z Codex plugin discovery skipped: zWrote default_permissions = u   ⚠ 
)r   appendr   r   r   lenr   getjoinr   r   r   r   )selflinesnameskippednoteerrs         \/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/codex_runtime_plugin_migration.pysummaryzMigrationReport.summaryH   s   <<LL1$2B2B1CDE\\LL6$"2"2!345==LL9S%7$8HI 266::4D;Bk$))G"4!5Q7  tD6$012 LLAB  LLC 5 5677OP -- ,tD6]+,$$LL;D<S<S;TUV))LL.1146 ;; 	'CLL4u&	'yy    )returnstr)__name__
__module____qualname____doc__r   __annotations__r   listr   dictr   r   r   r   r   r   r   r(    r)   r'   r
   r
   :   s}    &"&K&5Hi549$4O1O"'"=i=(,,/3}3d3FI3GTGT r)   r
   >   cwdenvurlargscommandenabledheaderstimeout	transportdescriptionconnect_timeoutsamplingc                    t        |t              sdg fS g }i }t        |j                  d            }t        |j                  d            }|r|r|j	                  d       d}|rt        |d         |d<   |j                  d      xs g }|r|D cg c]  }t        |       c}|d<   |j                  d      xs i }|r9|j                         D 	
ci c]  \  }	}
t        |	      t        |
       c}
}	|d<   |j                  d      }|rt        |      |d<   n|rt        |d         |d<   |j                  d	      xs i }|r9|j                         D 	
ci c]  \  }	}
t        |	      t        |
       c}
}	|d
<   |j                  d      dk(  r|j	                  d       nddgfS d|v r	 t        |d         |d<   d|v r	 t        |d         |d<   |j                  d      du rd|d<   |D ]<  }|t        v r|j	                  | d        |t        vs)|j	                  | d       > ||fS c c}w c c}
}	w c c}
}	w # t        t        f$ r |j	                  d       Y w xY w# t        t        f$ r |j	                  d       Y w xY w)a  Translate one Hermes MCP server config to the codex inline-table dict
    representation. Returns (codex_entry, skipped_keys).

    codex_entry is a dict ready for TOML serialization, or None when the
    server can't be translated (e.g. neither command nor url present).Nr8   r6   z0url (both command and url set; preferring stdio)Fr7   r5   r4   r:   http_headersr<   ssez%transport=sse (codex auto-negotiates)zno command or url fieldr;   tool_timeout_secztimeout (not numeric)r>   startup_timeout_seczconnect_timeout (not numeric)r9   z (no codex equivalent)z (unknown Hermes key))
isinstancer2   r   r   r   r+   itemsfloat	TypeError
ValueError_KEYS_DROPPED_WITH_WARNING_KNOWN_HERMES_KEYS)r#   
hermes_cfgr$   outhas_commandhas_urlr7   ar5   kvr4   r:   keys                 r'   _translate_one_serverrT      s    j$'RxGCz~~i01K:>>%()GwIJZ	23I~~f%++/0a3q60CKnnU#)r58YY[ATQ#a&#a&.ACJnnU#SCJ	E*+E
..+1r>Emmo"Nda3q63q6>"NC>>+&%/NNBC/000 J	4&+Jy,A&BC"# J&	<).z:K/L)MC%&
 ~~i E)I  :,,NNcU"89:**NNcU"789	: <W 1 B #O :& 	4NN23	4
 :& 	<NN:;	<s6   H3H8H>/I I*  I'&I'* JJc                   t        | t              r| rdS dS t        | t        t        f      rt	        |       S t        | t
              rx| j                  dd      j                  dd      j                  dd      j                  d	d
      j                  dd      j                  dd      j                  dd      }d| dS t        | t              rdj                  d | D              }d| dS t        | t              r2dj                  d | j                         D              }|rd|z   dz   S dS t        dt        |       j                         )u   Minimal TOML value formatter for the value types we emit.

    We only emit strings, numbers, booleans, and tables of those — no nested
    arrays of tables. This covers everything codex's MCP schema accepts.truefalse\\\"\"z\b	z\tr   z\nz\fz\rr   c              3  2   K   | ]  }t        |        y wN)_format_toml_value).0rR   s     r'   	<genexpr>z%_format_toml_value.<locals>.<genexpr>   s     ?A,Q/?s   []c              3  T   K   | ]   \  }}t        |       d t        |        " yw) = N)
_quote_keyrb   )rc   rQ   rR   s      r'   rd   z%_format_toml_value.<locals>.<genexpr>   s/      
=AQz!}oS!3A!6 78
s   &(z{ z }z{}zUnsupported TOML value type: )rE   r   intrG   reprr+   replacer1   r    r2   rF   rI   typer,   )valueescapedrF   s      r'   rb   rb      s8   
 %v+G+%#u&E{% WT6"WS% WT5!WT5!WT5!WT5!WT5! 	 7)1~%		???5'|%		 
EJ[[]
 
 ',te|d"55
4T%[5I5I4JK
LLr)   c                ~    t        d | D              r| r| S | j                  dd      j                  dd      }d| dS )zEReturn key bare-or-quoted depending on whether it's a valid bare key.c              3  H   K   | ]  }|j                         xs |d v   yw)z-_N)isalnum)rc   cs     r'   rd   z_quote_key.<locals>.<genexpr>   s"     
1199;#!t)#
1s    "rX   rY   rZ   r[   )allrl   )rS   ro   s     r'   ri   ri      sB    

1S
11c
kk$'//U;Gwiq>r)   c           	        t         g}| s>|s<|s:|j                  d       |j                  t               dj                  |      dz   S |rF|j	                  d      r|nd| }|j                  d       |j                  dt        |              | rt        | j                               D ]v  }| |   }|j                  d       |j                  dt        |       d       |j                         D ]-  \  }}|j                  t        |       dt        |              / x |rt        |d	 
      D ]  }	|	j                  d      xs d}|	j                  d      xs d}
t        |	j                  dd            }| d|
 }|j                  d       |j                  dt        |       d       |j                  dt        |               |j                  d       |j                  t               dj                  |      dz   S )u  Render the managed [mcp_servers.<n>] / [plugins.<id>] / [permissions]
    block for ~/.codex/config.toml.

    Args:
        servers: dict of MCP server name → translated codex inline-table
        plugins: optional list of {name, marketplace, enabled} for native
            Codex plugins to enable. (E.g. the Linear / Atlassian / Asana
            curated plugins, or per-account ChatGPT apps.)
        default_permission_profile: when set, write `[permissions] default`
            so the user doesn't get an approval prompt on every write
            attempt. Common values: "workspace-write", "read-only",
            "full-access".
    z@# (no MCP servers, plugins, or permissions configured by Hermes)r   :r   zdefault_permissions = z[mcp_servers.rf   rh   c                P    | j                  dd       d| j                  dd       S )Nr#   r   @marketplace)r   )ps    r'   <lambda>z+render_codex_toml_section.<locals>.<lambda>%  s+    quuVB7G6H!%%P]^`JaIb4c r)   )rS   r#   ry   openai-curatedr9   Trx   	[plugins.z
enabled = )MIGRATION_MARKERr   MIGRATION_END_MARKERr    
startswithrb   sortedkeysri   rF   r   r   )serverspluginsdefault_permission_profilerM   
normalizedr#   cfgrQ   rR   pluginry   r9   	qualifieds                r'   render_codex_toml_sectionr      s   $ 
C7+E

UV

'(yy~$$! *44S9 '/01 	
 	

2

+,>z,J+KLM7<<>* 	ID$-CJJrNJJz$'7&8:;		 I1

jm_C0B10E/FGHI		I W*cd 	CF::f%+D **]3G7GK6::i67G&+/IJJrNJJ:i#8"9;<JJ$6w$?#@AB	C JJrNJJ#$99S>D  r)   c                   | j                         s|S | j                  d      }d}t        |      D ]*  \  }}|j                         }|j	                  d      s(|} n || j                  d      }|r| d| S |S dj                  |d|       j                  d      }dj                  ||d       j                  d      }|r
| d| d| S | d| S )a  Insert Hermes' managed Codex TOML block while keeping root keys root-scoped.

    TOML has no syntax to return to the document root after a table header.
    Therefore appending a root key like `default_permissions = ...` after a
    user table such as `[features]` actually creates `features.default_permissions`,
    which Codex rejects. Insert the managed block before the first table header
    so its root keys remain top-level, while preserving user content verbatim.
    TkeependsNre   r   z

r   )strip
splitlines	enumeratelstripr   rstripr    )		user_textmanaged_blockr"   first_table_idxidxlinestrippedprefixsuffixs	            r'   "_insert_managed_block_at_top_levelr   3  s    ??  $ /E%)Ou% 	T;;=s#!O	 !!$'17&m_-J]JWWU+O,-44T:FWWU?+,-44T:Fm_Bvh77_Bvh''r)   c                    | j                  d      }g }d}|D ]E  }|j                         }t        |      r|j                  d      }|r2|r5|j	                  |       G dj                  |      S )u  Remove ``[plugins."<name>@<marketplace>"]`` tables that live OUTSIDE the
    managed block.

    Codex itself writes these tables when the user runs ``codex plugins enable``
    directly (i.e. before Hermes' migrate has ever touched the file). When we
    later run migrate, ``_query_codex_plugins()`` reports the same plugins via
    the live ``plugin/list`` RPC and we re-emit them inside the managed block.
    The result without this strip is duplicate ``[plugins."X@Y"]`` table
    headers — codex's strict TOML parser then refuses to load the file.

    We own the ``[plugins.*]`` namespace once migrate has run, so dropping any
    pre-existing ``[plugins.*]`` tables is safe: ``plugin/list`` is the source
    of truth for what's actually installed. The caller is expected to only
    invoke this strip when ``plugin/list`` succeeded — otherwise we'd lose
    plugins the user installed via ``codex`` without a way to re-emit them.

    Behavior:
      * Lines beginning with ``[plugins.`` start a swallow region that ends at
        the next non-``[plugins.`` table header or end-of-file.
      * Content inside the managed block is untouched (callers should run
        ``_strip_existing_managed_block`` first so the managed block has
        already been removed when this runs).
    Tr   Fr}   r   )r   r   _looks_like_table_headerr   r   r    )	toml_textr"   rM   in_plugin_tabler   r   s         r'   _strip_unmanaged_plugin_tablesr   R  s}    0   $ /ECO ;;= $H-&11+>O

4  773<r)   c                    | j                  d      sy| j                  dd      d   j                         }|j                  d      sy|j	                  d      }d|d|dz    vS )	a  Return True if ``stripped_line`` is a TOML table header.

    A header has the shape ``[name]`` or ``[[name]]`` (array-of-tables),
    optionally followed by a comment. The closing ``]`` (or ``]]``) must
    appear on the same line, and no key-assignment ``=`` can precede it.
    This distinguishes real headers from multi-line array continuation
    lines that also start with ``[`` after ``lstrip()``.
    re   F#   r   rf   =N)r   splitr   endswithindex)stripped_lineheadbracket_idxs      r'   r   r     sh     ##C(sA&q)002D==**S/Kd,[1_---r)   c                   | j                  d      }g }d}d}|D ]  }|j                  d      }|t        k(  rd}d}"|r|t        k(  rd}d}2|j	                         }|si|j                  d      rX|j                  d      sG|j                  d      s6|j                  d      s%|j                  d	      sd}|j                  |       |j                  |        d
j                  |      S )a  Remove any prior managed section so re-runs idempotently replace it.

    The managed section is everything between MIGRATION_MARKER (start) and
    MIGRATION_END_MARKER (end), inclusive of both markers. User-edited
    sections above or below are preserved verbatim.

    Backward compatibility: if the start marker is found but no end marker
    follows, we fall back to the heuristic that swallows lines until we
    hit a section that's not [mcp_servers.*]/[plugins.*]/[permissions]/
    a `default_permissions =` key. This matches what older versions of
    this code wrote so re-runs don't break configs from prior Hermes
    versions.Tr   Fr   re   z[mcp_serversz[pluginsz[permissions]z[permissions.r   )r   r   r~   r   r   r   r   r    )r   r"   rM   
in_managedsaw_end_markerr   line_stripped_nlr   s           r'   _strip_existing_managed_blockr     s       $ /ECJN ;;t,//J"N#77"
!%{{}H!h&9&9#&>##N3&&z2&&7&&7 #


4 

434 773<r)   c                J   	 ddl m} 	  || rt        |       nd      5 }|j	                  d       |j                  di |	      }ddd       g }t               }j                  d      xs g }t        |t              sg dfS |D ]Q  }	t        |	t              st        |	j                  d      xs d      }
|	j                  d      xs g }t        |t              sY|D ]  }t        |t              st        |j                  dd            }|s2t        |j                  d      xs d      j                         }|r,|dk7  r't        j                  d|j                  d      |       t        |j                  d      xs d      }|s||
f}||v r|j                  |       |j!                  ||
t        |j                  dd            d        T |dfS # t        $ r}g d| fcY d}~S d}~ww xY w# 1 sw Y   xY w# t        $ r}g d
| fcY d}~S d}~ww xY w)u  Query codex's `plugin/list` for installed curated plugins.

    Spawns `codex app-server` briefly, sends initialize + plugin/list,
    extracts plugins where installed=true. Returns (plugins, error).
    Plugins is a list of {name, marketplace, enabled} dicts ready for
    render_codex_toml_section().

    On any failure (codex not installed, RPC error, timeout) returns
    ([], error_message). Migration treats this as non-fatal — MCP
    servers and permissions still write through.
    r   )CodexAppServerClientztransport unavailable: N
codex_homezhermes-migration)client_namezplugin/list)r;   zplugin/list query failed: marketplacesz+plugin/list response missing 'marketplaces'r#   r|   r   	installedFavailabilityr   	AVAILABLEz#skipping plugin %s: availability=%sr9   T)r#   ry   r9   )!agent.transports.codex_app_serverr   	Exceptionr+   
initializerequestsetr   rE   r1   r2   r   upperloggerdebugaddr   )r   r;   r   excclientresprM   seenr   ry   market_namer   r   r   r   r#   rS   s                    r'   _query_codex_pluginsr     s7   3J6!*4s:$
 	F*<=>>-W>ED		F C!$D88N+1rLlD)@@@# ++t,+//&1E5EF//),2'4( $	Ffd+VZZU;<I vzz.9?R@FFHL ;9JJv& vzz&)/R0D%Cd{HHSM JJ*

9d ;< A$	+X 9{  3,SE2223	F 	F
  6/u5556sQ   G H 'G;H 	G8'G3-G83G8;H H 	H"HH"H"c                V    | syd}| j                         t        fd|D              S )u  Heuristic: does ``path`` look like a pytest/transient tempdir?

    pytest tempdirs live under ``pytest-of-<user>/pytest-<n>/`` (created via
    ``tmp_path`` / ``tmp_path_factory``) and are reaped between sessions.
    macOS routes ``/tmp`` through ``/private/var/folders/<…>/T`` which is
    what pytest's tempdir factory uses by default. If a HERMES_HOME pointing
    at one of those paths is burned into ``~/.codex/config.toml``, every
    codex-routed hermes-tools call fails silently once the directory is GC'd.

    We err on the side of refusing — losing a (very unlikely) real
    ``~/.hermes`` symlink that happens to live under ``/private/var/folders``
    is much less harmful than silently bricking codex's tool surface.
    F)z
pytest-of-z/pytest-z/tmp/pytestz/private/var/folders/c              3  &   K   | ]  }|v  
 y wra   r3   )rc   needler   s     r'   rd   z+_looks_like_test_tempdir.<locals>.<genexpr>*  s     :v#:s   )lowerany)pathneedlesr   s     @r'   _looks_like_test_tempdirr     s0     G J:':::r)   c                 H   ddl } i }t        j                  j                  d      xs d}|rt	        |      rd}|r||d<   t        j                  j                  d      }|r||d<   d|d<   |j                  dd	      |d<   | j
                  d
dgd}|r||d<   d|d<   d|d<   |S )a  Build the codex stdio-transport entry that launches Hermes' own
    tool surface as an MCP server. Codex's subprocess will call back into
    this for browser/web/delegate_task/vision/memory/skills tools.

    The command runs the worktree's Python via the current sys.executable
    so a hermes installed under /opt/, /usr/local/, or a venv all work.
    HERMES_HOME and PYTHONPATH are passed through so the spawned process
    sees the same config + module layout the user is running.r   NHERMES_HOMEr   
PYTHONPATH1HERMES_QUIETHERMES_REDACT_SECRETSrV   z-mz(agent.transports.hermes_tools_mcp_server)r8   r7   r5   g      >@rD   g     @rC   )sysosenvironr   r   
executable)r   r5   hermes_home
pythonpathrM   s        r'   _build_hermes_tools_mcp_entryr   -  s     C **../52K/<(M -J&LC#&77+BF#KC  >>ABC E
 "&C#CJr)   FTz
:workspace)r   r   discover_pluginsr   expose_hermes_toolsc          	        t        |      }|xs t        j                         dz  }|dz  }||_        | xs i j	                  d      xs i }t        |t              s|j                  j                  d       |S i }	|j                         D ]  \  }
}t        t        |
      |xs i       \  }}|5|j                  j                  d|
dd	j                  |      xs d
        Y||	t        |
      <   |r||j                  t        |
      <   |j                  j                  t        |
              g }d}|rJ|sHt        |      \  }}|r||_        nd}|D ](  }|j"                  j                  |d    d|d           * |r||_        |r6t'               |	d<   d|j                  vr|j                  j                  d       t)        |	||      }|j+                         r8	 |j-                  d      }t1        |      }|rt3        |      }t5        ||      }n|}|r|S 	 |j7                  dd       ddl}|j;                  dt        |            \  }}t        |      }	 t=        j>                  |dd      5 }|jA                  |       ddd       |jC                  |       d|_#        |S # t.        $ r-}|j                  j                  d| d|        |cY d}~S d}~ww xY w# 1 sw Y   \xY w# t.        $ r2 	 |j+                         r|jE                           # t.        $ r Y  w xY ww xY w# t.        $ r,}|j                  j                  d| d|        Y d}~|S d}~ww xY w)a  Translate Hermes mcp_servers config + Codex curated plugins into
    ~/.codex/config.toml.

    Args:
        hermes_config: full ~/.hermes/config.yaml dict
        codex_home: override CODEX_HOME (defaults to ~/.codex)
        dry_run: skip the actual write; report what would happen
        discover_plugins: when True (default), query `plugin/list` against
            the live codex CLI to migrate any installed curated plugins
            into [plugins."<name>@<marketplace>"] entries. Set False to
            skip the subprocess spawn (for tests or restricted environments).
        default_permission_profile: when set (default ":workspace"), write
            top-level `default_permissions = "<name>"` so users on this
            runtime don't get an approval prompt on every write attempt.
            Built-in codex profile names are ":workspace", ":read-only",
            ":danger-no-sandbox" (note the leading ":"). Also accepts a
            user-defined profile name (no leading ":") that the user has
            configured in their own [permissions.<name>] table. Set None
            to leave permissions unset and let codex use its compiled-in
            default (which is read-only).
        expose_hermes_tools: when True (default), register Hermes' own
            tool surface (web_search, browser_*, delegate_task, vision,
            memory, skills, etc.) as an MCP server in ~/.codex/config.toml
            so the codex subprocess can call back into Hermes for tools
            codex doesn't have built in. Set False to opt out.
    )r   z.codexzconfig.tomlmcp_serversz;mcp_servers in Hermes config is not a dict; cannot migrate.Nzserver z
 skipped: r   zno transport configuredFr   Tr#   rx   ry   zhermes-tools)r   r   zutf-8)encodingzcould not read z: )parentsexist_okr   z.config.toml.)r   dirwzcould not write )$r
   r   homer   r   rE   r2   r   r   rF   rT   r+   r    r   r   r   r   r   r   r   r   exists	read_textr   r   r   r   mkdirtempfilemkstempr   fdopenwriterl   unlinkr   )hermes_configr   r   r   r   r   reporttargethermes_servers
translatedr#   r   rM   r$   r   plugin_query_succeeded
plugin_errrz   r   existingr   without_managednew_textr   tmp_fdtmp_path_strtmp_pathfhs                               r'   migrater   a  s   F W-F5tyy{X5J-'FF#)r..}=CNnd+I	
 "$J#))+ 
*	c,SY	rBW;MM  $DIIg,>,[B[+\]  #
3t98?F**3t95s4y)
* G"2jI(2F%
 &*" 	NA##**ai[!M:J9K+LM	N
 "+E( %B%D
>"0OO"">2 .G#=M }}	'''9H 8A "<_MO5o}U A5
 	'//"J  0  
 %	639 #R"#V$  M[  	MM  ?6("SE!BCM	># #  	??$OO%   	  A/xr#?@@MAs   #J/ !AL2 #K4 ;K(K4 &L2 /	K%8"K K% K%(K1-K4 4	L/> LL/	L+(L/*L++L//L2 2	M';!M""M')r#   r+   rL   r2   r*   z tuple[Optional[dict], list[str]])rn   r   r*   r+   )rS   r+   r*   r+   )NN)r   zdict[str, dict]r   zOptional[list[dict]]r   r   r*   r+   )r   r+   r   r+   r*   r+   )r   r+   r*   r+   )r   r+   r*   r   )Ng       @)r   r   r;   rG   r*   z tuple[list[dict], Optional[str]])r   r+   r*   r   )r*   r2   )r   r2   r   r   r   r   r   r   r   r   r   r   r*   r
   )!r/   
__future__r   loggingr   dataclassesr   r   pathlibr   typingr   r   	getLoggerr,   r   r~   r   r
   rK   rJ   rT   rb   ri   r   r   r   r   r   r   r   r   r   r3   r)   r'   <module>r     s  "H #  	 (   			8	$ \  ) 
 ,  ,  , d	   E
EE%EP%MP %)04:!:!!:! !.:! 		:!z(>+\.(+^ "&NNN &Nb;41n "&!0< $TT T 	T
 T !.T T Tr)   