§
    øžyjØ] ã                   óª  — 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	Z	ddl
mZ ddlmZmZmZ ddlmZmZmZmZ ddlmZ  ej        d¦  «        Zg d¢Zg d	¢Zd
dgZg d¢Zee         ed<    e h d£¦  «        Z!e e         ed<    e h d£¦  «        Z"e e         ed<   dZ#dede$fd„Z%defd„Z& e h d£¦  «        Z' e h d£¦  «        Z( e h d£¦  «        Z) e h d£¦  «        Z*defd„Z+defd„Z,defd„Z-defd„Z.d edefd!„Z/d eddfd"„Z0d eddfd#„Z1d edefd$„Z2d ede$fd%„Z3d edee         fd&„Z4de$fd'„Z5dpd ed(ee         dee         fd)„Z6d ede$fd*„Z7deddfd+„Z8d,edee         fd-„Z9d.Z:de;eef         fd/„Z<e G d0„ d1¦  «        ¦   «         Z=dede>fd2„Z?dede>fd3„Z@dede$fd4„ZAi ZBe;ee>eCeCeDf         f         ed5<   d6ZEd7edeCfd8„ZFdedeDfd9„ZGdedefd:„ZHdede;fd;„ZIddd<œded=ee         d>ee$         ddfd?„ZJdee=         fd@„ZKdAe$deeeef                  fdB„ZL	 	 	 	 	 	 dqd edDee         dEe$dFe$dGe$dHe$d=ee         defdI„ZMdrdedJe$dee;         fdK„ZNdrdJe$dee         fdL„ZOdMededeeD         fdN„ZPdMededdfdO„ZQdeddfdP„ZRdrd edQe$defdR„ZSd,eddfdS„ZTd,eddfdT„ZUd ededdfdU„ZVdeddfdV„ZWdefdW„ZXd eddfdX„ZYdefdY„ZZdZefd[„Z[d\edZed]edefd^„Z\dpd ed_ed`eeeef                  defda„Z]dbedee         fdc„Z^ddedeeddfdf„Z_ddede`e         fdg„Zadpdhed ee         defdi„Zbdjedkedleddfdm„Zcdjedkedefdn„Zdd,edefdo„ZedS )su_  
Profile management for multiple isolated Hermes instances.

Each profile is a fully independent HERMES_HOME directory with its own
config.yaml, .env, memory, sessions, skills, gateway, cron, and logs.
Profiles live under ``~/.hermes/profiles/<name>/`` by default.

The "default" profile is ``~/.hermes`` itself â€” backward compatible,
zero migration needed.

Usage::

    hermes profile create coder          # fresh profile + bundled skills
    hermes profile create coder --clone  # also copy config, .env, SOUL.md, skills
    hermes profile create coder --clone-all  # full copy of source profile
    coder chat                           # use via wrapper alias
    hermes -p coder chat                 # or via flag
    hermes profile use coder             # set as sticky default
    hermes profile delete coder          # remove profile + alias + service
é    N)Ú	dataclass)ÚPathÚPurePosixPathÚPureWindowsPath)ÚDictÚListÚOptionalÚTuple)Úis_excluded_skill_pathz^[a-z0-9][a-z0-9_-]{0,63}$)	ÚmemoriesÚsessionsÚskillsÚskinsÚlogsÚplansÚ	workspaceÚcronÚhome)úconfig.yamlú.envúSOUL.mdzmemories/MEMORY.mdzmemories/USER.md)úgateway.pidúgateway_state.jsonúprocesses.jsonÚ_CLONE_ALL_STRIP>   ÚbinÚprofilesÚnode_modulesú
.worktreesúhermes-agentÚ_CLONE_ALL_DEFAULT_EXCLUDE_ROOT>   ústate-snapshotsÚbackupsr   Úcheckpointsústate.dbústate.db-shmústate.db-walÚ_CLONE_ALL_HISTORY_EXCLUDE_ROOTz.no-bundled-skillsÚprofile_dirÚreturnc                 ó^   — 	 | t           z                       ¦   «         S # t          $ r Y dS w xY w)z>Return True if the profile opted out of bundled-skill seeding.F)ÚNO_BUNDLED_SKILLS_MARKERÚexistsÚOSError©r)   s    ú9/home/ragecks/.hermes/hermes-agent/hermes_cli/profiles.pyÚhas_bundled_skills_opt_outr1   ‰   sA   € ðØÕ6Ñ6×>Ò>Ñ@Ô@Ð@øÝð ð ð Øˆuˆuðøøøs   ‚ ž
,«,Ú
source_dirc                 óÞ   ‡‡— |                       ¦   «         Š‰t          ¦   «                               ¦   «         k    Šdt          dt          t                   dt          t                   fˆˆfd„}|S )uW  Exclude infrastructure artifacts when cloning a profile via --clone-all.

    Three categories:
      1. Root-level entries in ``_CLONE_ALL_HISTORY_EXCLUDE_ROOT`` â€” session
         history, backups, and snapshots that belong to the SOURCE profile
         and should never carry into a fresh clone.  Applies to any source.
      2. Root-level entries in ``_CLONE_ALL_DEFAULT_EXCLUDE_ROOT`` â€” known
         Hermes infrastructure directories that only the default profile
         (``~/.hermes``) ever contains.  Gated on ``source_dir`` actually
         being the default profile so a named-profile source never has its
         own data silently dropped.
      3. Universal exclusions at any depth â€” Python bytecode caches that
         are stale or regenerable (``__pycache__``, ``*.pyc``, ``*.pyo``)
         and runtime sockets / temp files (``*.sock``, ``*.tmp``).

    The export-side ignore (``_default_export_ignore``) uses the same
    two-tier pattern with the broader ``_DEFAULT_EXPORT_EXCLUDE_ROOT`` set
    because the export archive is a portable snapshot rather than a live
    clone.
    Ú	directoryÚnamesr*   c                 óz  •— g }|D ]´}|dk    s|                      d¦  «        r|                     |¦  «         Œ3	 t          | ¦  «                             ¦   «         ‰k    }n# t          t
          f$ r d}Y nw xY w|r?|t          v r|                     |¦  «         Œ”‰r|t          v r|                     |¦  «         Œµ|S )NÚ__pycache__)z.pycz.pyoú.sockú.tmpF)ÚendswithÚappendr   Úresolver.   Ú
ValueErrorr(   r!   )r4   r5   ÚignoredÚentryÚat_rootÚis_default_sourceÚsource_resolveds        €€r0   Ú_ignorez+_clone_all_copytree_ignore.<locals>._ignore©   sô   ø€ ØˆØð 	*ð 	*ˆEð ˜Ò&Ð&Ø—>’>Ð"CÑDÔDð 'ð —’˜uÑ%Ô%Ð%Øð Ý˜y™/œ/×1Ò1Ñ3Ô3°ÒF��øÝ�ZÐ(ð  ð  ð  ð  ���ð	 øøøð
 ð *àÕ;Ð;Ð;Ø—N’N 5Ñ)Ô)Ð)Øà$ð *¨Õ2QÐ)QÐ)QØ—N’N 5Ñ)Ô)Ð)øØˆs   º%A Á A6Á5A6)r<   Ú_get_default_hermes_homeÚstrr   )r2   rC   rA   rB   s     @@r0   Ú_clone_all_copytree_ignorerF   ‘   s|   øø€ ð* !×(Ò(Ñ*Ô*€OØ'Õ+CÑ+EÔ+E×+MÒ+MÑ+OÔ+OÒOÐð�3ð ¥t­C¤yð µT½#´Yð ð ð ð ð ð ð ð6 €Nó    >   ú	auth.lockú
errors.logú.update_checkú.hermes_historyúhermes_state.dbúresponse_store.dbúresponse_store.db-shmúresponse_store.db-walr   r   r   Ú	sandboxesÚaudio_cacher$   Úimage_cacher   Úactive_profileÚdocument_cacheÚbrowser_screenshotsr   r%   ú	auth.jsonr   r   r    r&   r'   r   r   >   úUSER.mdú	AGENTS.mdú	CLAUDE.mdú	MEMORY.mdú	todo.jsonú.cursorrulesúdesktop.jsonúsystem_prompt.mdr   r   ÚpluginsÚscriptsr   r   Ú	knowledgeÚpreferencesr   r   >   ÚtmpÚrootÚsudoÚtestÚhermesÚdefault>   ÚacpÚmcpÚchatr   ÚdumpÚloginÚmodelÚsetupÚtoolsÚconfigÚdoctorÚhonchoÚlogoutr   ÚstatusÚupdateÚgatewayÚpairingr_   ÚprofileÚversionÚinsightsr   ÚwhatsappÚ	uninstallc                  ó$   — t          ¦   «         dz  S )aŽ  Return the directory where named profiles are stored.

    Anchored to the hermes root, NOT to the current HERMES_HOME
    (which may itself be a profile).  This ensures ``coder profile list``
    can see all profiles.

    In Docker/custom deployments where HERMES_HOME points outside
    ``~/.hermes``, profiles live under ``HERMES_HOME/profiles/`` so
    they persist on the mounted volume.
    r   ©rD   © rG   r0   Ú_get_profiles_rootr�     s   € õ $Ñ%Ô%¨
Ñ2Ð2rG   c                  ó"   — ddl m}   | ¦   «         S )zïReturn the default (pre-profile) HERMES_HOME path.

    In standard deployments this is ``~/.hermes``.
    In Docker/custom deployments where HERMES_HOME is outside ``~/.hermes``
    (e.g. ``/opt/data``), returns HERMES_HOME directly.
    r   ©Úget_default_hermes_root)Úhermes_constantsr„   rƒ   s    r0   rD   rD     s%   € ð 9Ð8Ð8Ð8Ð8Ð8Ø"Ð"Ñ$Ô$Ð$rG   c                  ó$   — t          ¦   «         dz  S )z2Return the path to the sticky active_profile file.rS   r   r€   rG   r0   Ú_get_active_profile_pathr‡   $  s   € å#Ñ%Ô%Ð(8Ñ8Ð8rG   c                  ó4   — t          j        ¦   «         dz  dz  S )z)Return the directory for wrapper scripts.z.localr   )r   r   r€   rG   r0   Ú_get_wrapper_dirr‰   )  s   € åŒ9‰;Œ;˜Ñ! EÑ)Ð)rG   Únamec                 óð   — t          | t          ¦  «        st          | ¦  «        } |                      ¦   «         }|st          d¦  «        ‚|                     ¦   «         dk    rdS |                     ¦   «         S )u  Return the canonical profile id used on disk and in CLI ``-p`` argv.

    Named profiles are stored lowercase under ``profiles/<id>/``. The special
    alias ``default`` is matched case-insensitively (``Default`` â†’ ``default``).
    Dashboards and tools may pass title-cased display labels; normalize before
    validation, assignment, and subprocess spawn (see issue #18498).
    zprofile name cannot be emptyrh   )Ú
isinstancerE   Ústripr=   ÚcasefoldÚlower)rŠ   Ústrippeds     r0   Únormalize_profile_namer‘   2  sq   € õ �d�CÑ Ô ð Ý�4‰yŒyˆØ�zŠz‰|Œ|€HØð 9ÝÐ7Ñ8Ô8Ð8Ø×ÒÑÔ˜iÒ'Ð'ØˆyØ�>Š>ÑÔÐrG   c                 ó¨   — | dk    rdS t                                | ¦  «        st          d| ›d�¦  «        ‚| t          v rt          d| ›d�¦  «        ‚dS )u  Raise ``ValueError`` if *name* is not a valid profile identifier.

    Validates the input as-given â€” strict lowercase match. Callers that accept
    mixed-case or title-cased input from users (dashboard UI, CLI args) should
    call :func:`normalize_profile_name` first. This separation keeps validate
    honest about what the on-disk directory name must look like, while
    ingress-point normalization handles UX flexibility (see #18498).

    Also rejects names in :data:`_RESERVED_NAMES` (``hermes``, ``test``,
    ``tmp``, ``root``, ``sudo``) that would create confusing on-disk
    collisions (a ``hermes`` profile inside ``~/.hermes/``) or get refused
    at alias-creation time anyway. ``default`` is a special pass-through â€”
    it's a valid alias for the built-in root profile.
    rh   NzInvalid profile name ú%. Must match [a-z0-9][a-z0-9_-]{0,63}zProfile name uz    is reserved â€” it collides with either the Hermes installation itself or a common system binary.  Pick a different name.)Ú_PROFILE_ID_REÚmatchr=   Ú_RESERVED_NAMES©rŠ   s    r0   Úvalidate_profile_namer˜   D  s�   € ð ˆyÒÐØˆÝ×Ò Ñ%Ô%ð 
Ýð* Dð *ð *ð *ñ
ô 
ð 	
ð �ÐÐÝð&˜Dð &ð &ð &ñ
ô 
ð 	
ð ÐrG   c                 ó`   — t                                | ¦  «        st          d| ›d�¦  «        ‚dS )uÔ  Raise ``ValueError`` if *name* is not a safe wrapper-alias identifier.

    The alias is used verbatim as a filename under :func:`_get_wrapper_dir`
    (``~/.local/bin``), so it must be a single safe command name with no path
    separators or traversal segments â€” otherwise a value like ``../../.bashrc``
    would escape the wrapper directory and clobber arbitrary user files. We
    reuse the profile id regex, which already forbids ``/``, ``.``, and ``..``.
    zInvalid alias name r“   N)r”   r•   r=   r—   s    r0   Úvalidate_alias_namerš   b  sL   € õ ×Ò Ñ%Ô%ð 
Ýð* $ð *ð *ð *ñ
ô 
ð 	
ð
ð 
rG   c                 ój   — t          | ¦  «        }|dk    rt          ¦   «         S t          ¦   «         |z  S )z4Resolve a profile name to its HERMES_HOME directory.rh   )r‘   rD   r�   ©rŠ   Úcanons     r0   Úget_profile_dirrž   r  s7   € å" 4Ñ(Ô(€EØ�	ÒÐÝ'Ñ)Ô)Ð)ÝÑÔ %Ñ'Ð'rG   c                 ór   — t          | ¦  «        }|dk    rdS t          |¦  «                             ¦   «         S )z)Check whether a profile directory exists.rh   T)r‘   rž   Úis_dirrœ   s     r0   Úprofile_existsr¡   z  s9   € å" 4Ñ(Ô(€EØ�	ÒÐØˆtÝ˜5Ñ!Ô!×(Ò(Ñ*Ô*Ð*rG   c                 óª  — t          | ¦  «        }	 t          |¦  «         n&# t          $ r}t          |¦  «        cY d}~S d}~ww xY w|t          v rd|› d�S |t
          v rd|› d�S t          ¦   «         }t          j        dk    }	 t          j
        |rdnd|gddd	d
d¬¦  «        }|j        dk    r‡|j                             ¦   «                              ¦   «         d         }||r|› d�n|z  }|t          |¦  «        k    r.	 |                     d	¬¦  «        }d|v rdS n# t           $ r Y nw xY wd|› d|› d�S n# t"          t          j        f$ r Y nw xY wdS )z±Return a human-readable collision message, or None if the name is safe.

    Checks: alias-name validity, reserved names, hermes subcommands, existing
    binaries in PATH.
    Nú'z' is a reserved namez$' conflicts with a hermes subcommandÚwin32ÚwhereÚwhichTúutf-8Úreplaceé   )Úcapture_outputÚtextÚencodingÚerrorsÚtimeoutr   ú.bat©r¬   ú	hermes -pz&' conflicts with an existing command (ú))r‘   rš   r=   rE   r–   Ú_HERMES_SUBCOMMANDSr‰   ÚsysÚplatformÚ
subprocessÚrunÚ
returncodeÚstdoutr�   Ú
splitlinesÚ	read_textÚ	ExceptionÚFileNotFoundErrorÚTimeoutExpired)	rŠ   r�   ÚexcÚwrapper_dirÚ
is_windowsÚresultÚexisting_pathÚexpectedÚcontents	            r0   Úcheck_alias_collisionrÆ   †  sâ  € õ # 4Ñ(Ô(€EðÝ˜EÑ"Ô"Ð"Ð"øÝð ð ð Ý�3‰xŒxˆˆˆˆˆˆøøøøðøøøà•ÐÐØ.�5Ð.Ð.Ð.Ð.ØÕ#Ð#Ð#Ø>�5Ð>Ð>Ð>Ð>õ #Ñ$Ô$€KÝ” Ò(€JðÝ”Ø"Ð/ˆWˆW¨°Ð7Ø d°WÀYÐXYð
ñ 
ô 
ˆð Ô Ò!Ð!Ø"œM×/Ò/Ñ1Ô1×<Ò<Ñ>Ô>¸qÔAˆMà"¸
Ð&M¨ n n n nÈÑNˆHØ¥ H¡¤Ò-Ð-ðØ&×0Ò0¸'Ð0ÑBÔB�GØ" gÐ-Ð-Ø#˜tð .øå ð ð ð Ø�DðøøøàT�uÐTÐTÀMÐTÐTÐTÐTð "øõ �zÔ8Ð9ð ð ð Øˆðøøøð ˆ4sN   ‘! ¡
A«?¹A¿AÂA;D7 Ä D ÄD7 Ä
D*Ä'D7 Ä)D*Ä*D7 Ä7EÅEc                  ó¶   — t          t          ¦   «         ¦  «        } | t          j                             dd¦  «                             t          j        ¦  «        v S )z!Check if ~/.local/bin is in PATH.ÚPATHÚ )rE   r‰   ÚosÚenvironÚgetÚsplitÚpathsep)rÀ   s    r0   Ú_is_wrapper_dir_in_pathrÏ   °  sA   € åÕ&Ñ(Ô(Ñ)Ô)€KØ�"œ*Ÿ.š.¨°Ñ4Ô4×:Ò:½2¼:ÑFÔFÐFÐFrG   Útargetc                 ór  — t          | ¦  «        }|rt          |¦  «        n|}t          |¦  «         t          ¦   «         }	 |                     dd¬¦  «         n-# t          $ r }t          d|› d|› �¦  «         Y d}~dS d}~ww xY wt          j        dk    }|rS||› d�z  }	 |                     d|› d	�d
¬¦  «         |S # t          $ r }t          d|› d|› �¦  «         Y d}~dS d}~ww xY w||z  }	 t          j
        d¦  «        pd}|                     dt          j        |¦  «        › d|› d�d
¬¦  «         |                     |                     ¦   «         j        t          j        z  t          j        z  t          j        z  ¦  «         |S # t          $ r }t          d|› d|› �¦  «         Y d}~dS d}~ww xY w)u·  Create a shell wrapper script at ~/.local/bin/<name>.

    The wrapper file is named after ``name`` (the alias). The profile it
    activates is ``target`` if given, otherwise ``name`` â€” this lets a custom
    alias name point at a differently-named profile without a post-hoc rewrite.

    On Windows, creates a ``.bat`` file instead of a POSIX shell script.
    Returns the path to the created wrapper, or None if creation failed.
    T©ÚparentsÚexist_oku   âš  Could not create ú: Nr¤   r¯   z@echo off
hermes -p z %*
r§   r°   u    âš  Could not create wrapper at rg   z#!/bin/sh
exec z -p z "$@"
)r‘   rš   r‰   Úmkdirr.   Úprintr´   rµ   Ú
write_textÚshutilr¦   ÚshlexÚquoteÚchmodÚstatÚst_modeÚS_IEXECÚS_IXGRPÚS_IXOTH)	rŠ   rÐ   r�   ry   rÀ   ÚerÁ   Úwrapper_pathÚ
hermes_exes	            r0   Úcreate_wrapper_scriptrå   ¶  s;  € õ # 4Ñ(Ô(€EØ06ÐAÕ$ VÑ,Ô,Ð,¸E€Gõ ˜ÑÔÐÝ"Ñ$Ô$€KðØ×Ò $°ÐÑ6Ô6Ð6Ð6øÝð ð ð ÝÐ8 kÐ8Ð8°QÐ8Ð8Ñ9Ô9Ð9Øˆtˆtˆtˆtˆtøøøøðøøøõ ” Ò(€JØð Ø"¨ ^ ^ ^Ñ3ˆð	Ø×#Ò#Ð$N¸gÐ$NÐ$NÐ$NÐY`Ð#ÑaÔaÐaØÐøÝð 	ð 	ð 	ÝÐH°\ÐHÐHÀQÐHÐHÑIÔIÐIØ�4�4�4�4�4øøøøð	øøøð # UÑ*ˆð	Ýœ hÑ/Ô/Ð;°8ˆJØ×#Ò#Ð$dµu´{À:Ñ7NÔ7NÐ$dÐ$dÐT[Ð$dÐ$dÐ$dÐovÐ#ÑwÔwÐwØ×Ò˜|×0Ò0Ñ2Ô2Ô:½T¼\ÑIÍDÌLÑXÕ[_Ô[gÑgÑhÔhÐhØÐøÝð 	ð 	ð 	ÝÐH°\ÐHÐHÀQÐHÐHÑIÔIÐIØ�4�4�4�4�4øøøøð	øøøsI   ÁA Á
BÁ#A>Á>BÂ!B> Â>
C(ÃC#Ã#C(Ã1BF Æ
F6ÆF1Æ1F6c                 ó¤  — t          ¦   «         }t          | ¦  «        }	 t          |¦  «         n# t          $ r Y dS w xY wt          j        dk    }||z  g}|r|                     d||› d�z  ¦  «         |D ]Y}|                     ¦   «         rC	 |                     d¬¦  «        }d|v r| 	                    ¦   «           dS ŒI# t          $ r Y ŒUw xY wŒZdS )	zARemove the wrapper script for a profile. Returns True if removed.Fr¤   r   r¯   r§   r°   r±   T)r‰   r‘   rš   r=   r´   rµ   Úinsertr-   r»   Úunlinkr¼   )rŠ   rÀ   r�   rÁ   Ú
candidatesrã   rÅ   s          r0   Úremove_wrapper_scriptrê   á  s+  € å"Ñ$Ô$€KÝ" 4Ñ(Ô(€EðÝ˜EÑ"Ô"Ð"Ð"øÝð ð ð Øˆuˆuðøøøå” Ò(€Jð  Ñ%Ð&€JØð ;Ø×Ò˜!˜[¨e¨>¨>¨>Ñ9Ñ:Ô:Ð:à"ð 	ð 	ˆØ×ÒÑ Ô ð 	ðà&×0Ò0¸'Ð0ÑBÔB�Ø 'Ð)Ð)Ø ×'Ò'Ñ)Ô)Ð)Ø˜4˜4ð *øõ ð ð ð Ø�ðøøøð	ð ˆ5s   Ÿ/ ¯
=¼=Â.B?Â?
CÃCc                 ó(  — | dz  }|                      ¦   «         sdS 	 ddlm}m} ddlm}m}  |t          | ¦  «        ¦  «        }	  |¦   «         \  }}||k     r |dd¬¦  «          ||¦  «         dS #  ||¦  «         w xY w# t          $ r Y dS w xY w)	u×  Bring a copied profile config.yaml up to the current schema.

    Profile creation can clone a config file that predates schema tracking (no
    ``_config_version``) or that is simply older than the running Hermes. If we
    leave it untouched, the first desktop/doctor view of the new profile shows a
    scary ``v0 â†’ latest`` warning even though we just created the profile. Scope
    the normal migration pipeline to the new profile and keep it non-interactive.
    r   Nr   )Úreset_hermes_home_overrideÚset_hermes_home_override)Úcheck_config_versionÚmigrate_configFT)ÚinteractiveÚquiet)	r-   r…   rì   rí   Úhermes_cli.configrî   rï   rE   r¼   )	r)   Úconfig_pathrì   rí   rî   rï   ÚtokenÚcurrent_verÚ
latest_vers	            r0   Ú#_migrate_profile_config_if_outdatedr÷   ÿ  sÿ   € ð  Ñ-€KØ×ÒÑÔð ØˆðØYÐYÐYÐYÐYÐYÐYÐYØJÐJÐJÐJÐJÐJÐJÐJà(Ð(­¨[Ñ)9Ô)9Ñ:Ô:ˆð	.Ø&:Ð&:Ñ&<Ô&<Ñ#ˆK˜Ø˜ZÒ'Ð'Ø�¨5¸Ð=Ñ=Ô=Ð=à&Ð& uÑ-Ô-Ð-Ð-Ð-øÐ&Ð& uÑ-Ô-Ð-Ð-øøøøÝð ð ð ð 	ˆˆð	øøøs)   �(B Á A3 Á&B Á3B Â B Â
BÂBÚprofile_namec                 ó^   — t          ¦   «                              t          | ¦  «        ¦  «        S )u  Return the alias name of the wrapper that activates *profile_name*, or None.

    A wrapper created by :func:`create_wrapper_script` is a file named after the
    alias whose body invokes ``hermes -p <profile>``. When the alias name equals
    the profile name this is trivial, but a custom alias (``hermes profile alias
    <profile> --name <custom>``) produces a differently-named file â€” so the
    display side cannot assume ``wrapper == profile`` and must reverse-look-up.

    A custom alias (name != profile) is preferred over the profile-named wrapper
    so ``profile list``/``show`` surface the command the user actually typed.
    Results are sorted for deterministic output when several aliases match.

    For listing ALL profiles at once, prefer :func:`build_alias_map` â€” calling
    this per-profile re-reads every wrapper file N times (O(N*M)); on a wrapper
    dir like ``~/.local/bin`` that also holds large unrelated binaries (ffmpeg
    etc.) that meant multi-second ``list_profiles`` latency and desktop timeouts.
    )Úbuild_alias_maprÌ   r‘   )rø   s    r0   Úfind_alias_for_profilerû     s'   € õ$ ÑÔ× Ò Õ!7¸Ñ!EÔ!EÑFÔFÐFrG   i    c                  óX  — t          ¦   «         } i }|                      ¦   «         s|S t          j        dk    }d}t	          |                      ¦   «         ¦  «        D �]N}|                     ¦   «         sŒ|r|j        dk    rŒ&|s|j        rŒ0	 t          |ddd¬¦  «        5 }| 	                    t          ¦  «        }ddd¦  «         n# 1 swxY w Y   n# t          t          f$ r Y ŒŠw xY w|                     |¦  «        }|d	k    rŒª||t          |¦  «        z   d…         }|                     ¦   «         r.|                     dd
¦  «        d                              ¦   «         nd}	|	s�Œt#          |	¦  «        }	|r|j        n|j        }
|
|	k    r|                     |	|
¦  «         �ŒI|
||	<   �ŒP|S )a•  Single-pass reverse map ``{canonical_profile -> alias_name}``.

    Scans the wrapper dir ONCE (vs. :func:`find_alias_for_profile` per profile)
    and reads only a small head slice of each candidate wrapper, skipping
    binaries. A custom alias (file name != profile) wins over the profile-named
    wrapper, matching ``find_alias_for_profile``'s preference; deterministic via
    sorted iteration.
    r¤   z
hermes -p r¯   Úrr§   Ústrict)r¬   r­   Néÿÿÿÿé   r   rÉ   )r‰   r    r´   rµ   ÚsortedÚiterdirÚis_fileÚsuffixÚopenÚreadÚ_WRAPPER_READ_LIMITr.   ÚUnicodeDecodeErrorÚfindÚlenr�   rÍ   r‘   ÚstemrŠ   Ú
setdefault)rÀ   rÂ   rÁ   Úprefixr?   ÚfrÅ   ÚidxÚrestr�   Úaliass              r0   rú   rú   <  s  € õ #Ñ$Ô$€KØ€FØ×ÒÑÔð ØˆÝ” Ò(€JØ€Få˜×+Ò+Ñ-Ô-Ñ.Ô.ð "ñ "ˆØ�}Š}‰Œð 	Øàð 	˜%œ,¨&Ò0Ð0ØØð 	˜eœlð 	Øð	Ý�e˜S¨7¸8ÐDÑDÔDð 6ÈØŸ&š&Õ!4Ñ5Ô5�ð6ð 6ð 6ñ 6ô 6ð 6ð 6ð 6ð 6ð 6ð 6øøøð 6ð 6ð 6ð 6øøåÕ+Ð,ð 	ð 	ð 	àˆHð	øøøð �lŠl˜6Ñ"Ô"ˆØ�"Š9ˆ9ØØ�s�S ™[œ[Ñ(Ð)Ð)Ô*ˆà26·*²*±,´,ÐF�—
’
˜4 Ñ#Ô# AÔ&×,Ò,Ñ.Ô.Ð.ÀBˆØð 	ÙÝ& uÑ-Ô-ˆØ(Ð8�”
�
¨e¬jˆð �EŠ>ˆ>Ø×Ò˜e UÑ+Ô+Ð+Ñ+à!ˆF�5‰M‰MØ€Ms6   ÂCÂCÂ9CÃC		Ã	CÃC		ÃCÃC%Ã$C%c                   ó*  — e Zd ZU dZeed<   eed<   eed<   eed<   dZe	e         ed<   dZ
e	e         ed<   d	Zeed
<   dZeed<   dZe	e         ed<   dZe	e         ed<   dZe	e         ed<   dZe	e         ed<   dZe	e         ed<   dZeed<   d	Zeed<   dS )ÚProfileInfoz$Summary information about a profile.rŠ   ÚpathÚ
is_defaultÚgateway_runningNrn   ÚproviderFÚhas_envr   Úskill_countÚ
alias_pathÚ
alias_nameÚdistribution_nameÚdistribution_versionÚdistribution_sourcerÉ   ÚdescriptionÚdescription_auto)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rE   Ú__annotations__r   Úboolrn   r	   r  r  r  Úintr  r  r  r  r  r  r   r€   rG   r0   r  r  q  s  € € € € € € à.Ð.Ø
€I€I�IØ
€J€J�JØÐÐÑØÐÐÑØ€Eˆ8�CŒ=ÐÐÑØ"€Hˆh�sŒmÐ"Ð"Ñ"Ø€GˆTÐÐÑØ€K�ÐÐÑØ!%€J�˜”Ð%Ð%Ñ%ð !%€J�˜”Ð$Ð$Ñ$à'+Ð�x ”}Ð+Ð+Ñ+Ø*.Ð˜( 3œ-Ð.Ð.Ñ.Ø)-Ð˜ #œÐ-Ð-Ñ-ð €K�ÐÐÑð
 #Ð�dÐ"Ð"Ñ"Ð"Ð"rG   r  c                 ó�  — | dz  }|                      ¦   «         sdS 	 ddl}t          |dd¬¦  «        5 }|                     |¦  «        pi }ddd¦  «         n# 1 swxY w Y   t	          |t
          ¦  «        sdS |                     d¦  «        |                     d	¦  «        |                     d
¦  «        fS # t          $ r Y dS w xY w)u  Return ``(name, version, source)`` from the profile's ``distribution.yaml``
    if present; ``(None, None, None)`` otherwise.

    Failures (missing file, bad YAML) are swallowed â€” a bad manifest should
    never break ``hermes profile list`` for an unrelated profile.
    zdistribution.yaml)NNNr   Nrý   r§   r°   rŠ   rz   Úsource)r  Úyamlr  Ú	safe_loadrŒ   ÚdictrÌ   r¼   )r)   Úmf_pathr*  r  Údatas        r0   Ú_read_distribution_metar/  ’  s'  € ð Ð/Ñ/€GØ�?Š?ÑÔð  ØÐð ØˆˆˆÝ�'˜3¨Ð1Ñ1Ô1ð 	+°QØ—>’> !Ñ$Ô$Ð*¨ˆDð	+ð 	+ð 	+ñ 	+ô 	+ð 	+ð 	+ð 	+ð 	+ð 	+ð 	+øøøð 	+ð 	+ð 	+ð 	+å˜$¥Ñ%Ô%ð 	$Ø#Ð#à�HŠH�VÑÔØ�HŠH�YÑÔØ�HŠH�XÑÔð
ð 	
øõ
 ð  ð  ð  ØÐÐð øøøs:   �B7 ³AÁB7 ÁAÁB7 ÁAÁB7 Á9=B7 Â7
CÃCc                 óˆ  — | dz  }|                      ¦   «         sdS 	 ddlm}  ||¦  «        }|                     di ¦  «        }t	          |t
          ¦  «        r|dfS t	          |t          ¦  «        r?|                     d¦  «        p|                     d¦  «        |                     d¦  «        fS dS # t          $ r Y dS w xY w)	zLRead model/provider from a profile's config.yaml. Returns (model, provider).r   )NNr   )Úread_user_config_rawrn   Nrh   r  )r-   rò   r1  rÌ   rŒ   rE   r,  r¼   )r)   ró   r1  ÚcfgÚ	model_cfgs        r0   Ú_read_config_modelr4  «  sì   € à Ñ-€KØ×ÒÑÔð Øˆzðð 	;Ð:Ð:Ð:Ð:Ð:Ø"Ð" ;Ñ/Ô/ˆØ—G’G˜G RÑ(Ô(ˆ	Ý�i¥Ñ%Ô%ð 	#Ø˜d�?Ð"Ý�i¥Ñ&Ô&ð 	aØ—=’= Ñ+Ô+ÐE¨y¯}ª}¸WÑ/EÔ/EÀyÇ}Â}ÐU_ÑG`ÔG`Ð`Ð`ØˆzøÝð ð ð Øˆzˆzðøøøs   �?B3 ÁAB3 Â3
CÃ Cc                 óÆ   — 	 ddl m}  || dz  d¬¦  «        	 �dS n# t          $ r Y nw xY w	 ddl m}m}  || d	z  ¦  «        } ||| ¬
¦  «        duS # t          $ r Y dS w xY w)u  Check if a gateway is running for a given profile directory.

    Primary signal is the profile's ``gateway.pid`` (verified against the
    runtime lock).  That check fails closed whenever the lock isn't held by
    *this* reader â€” which is exactly the case for a dashboard process that is
    a separate s6 service from the gateway it's reporting on (Docker), or any
    launch-service-managed gateway that left a fresh ``gateway_state.json`` but
    no live PID file.  In those cases fall back to validating the PID recorded
    in the profile's own ``gateway_state.json`` against the live process table,
    mirroring the ``/api/status`` sidebar's liveness logic so the two surfaces
    agree.  Parameterized by ``profile_dir`` so it never mutates ``HERMES_HOME``.
    r   )Úget_running_pidr   F)Úcleanup_staleNT)Úget_runtime_status_running_pidÚread_runtime_statusr   )Úexpected_home)Úgateway.statusr6  r¼   r8  r9  )r)   r6  r8  r9  Úruntimes        r0   Ú_check_gateway_runningr=  ¿  sé   € ðØ2Ð2Ð2Ð2Ð2Ð2àˆO˜K¨-Ñ7ÀuÐMÑMÔMØðð �4ðøõ ð ð ð Øˆðøøøðð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð &Ð% kÐ4HÑ&HÑIÔIˆØ-Ð-¨gÀ[ÐQÑQÔQÐY]Ð]Ð]øÝð ð ð Øˆuˆuðøøøs   ‚ œ
)¨)­$A Á
A ÁA Ú_SKILL_COUNT_CACHEg      >@Ú
skills_dirc                 óz  — 	 |                       ¦   «         j        }n# t          $ r Y dS w xY w	 t          j        | ¦  «        5 }|D ]L}	 |                     d¬¦  «        r#|                      d¬¦  «        j        }||k    r|}Œ=# t          $ r Y ŒIw xY w	 ddd¦  «         n# 1 swxY w Y   n# t          $ r Y nw xY w|S )a\  Cheap change-signature for a skills tree.

    Max mtime of ``skills_dir`` and its immediate children (category dirs).
    Adding/removing a category bumps ``skills_dir``'s mtime; adding/removing a
    skill inside a category bumps that category dir's mtime. One ``scandir``
    (not a recursive walk) keeps this O(#categories), not O(#files).
    g        F)Úfollow_symlinksN)rÝ   Úst_mtimer.   rÊ   Úscandirr    )r?  ÚsigÚitr?   Úms        r0   Ú_skills_dir_signaturerG  ì  s@  € ðØ�oŠoÑÔÔ(ˆˆøÝð ð ð ØˆsˆsðøøøðÝŒZ˜
Ñ#Ô#ð 	 rØð ð �ðØ—|’|°E�|Ñ:Ô:ð $Ø!ŸJšJ°u˜JÑ=Ô=ÔF˜Ø˜sš7˜7Ø"#˜CøøÝð ð ð Ø�Hðøøøðð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	øøõ ð ð ð Øˆðøøøà€Jse   ‚ œ
*©*®B+ ÁBÁ9BÂBÂ
BÂBÂBÂBÂB+ ÂB#Â#B+ Â&B#Â'B+ Â+
B8Â7B8c                 óž  — | dz  }|                      ¦   «         sdS t          |¦  «        }t          |¦  «        }t          j        ¦   «         }t                               |¦  «        }|�(|d         |k    r||d         z
  t          k     r|d         S d}|                     d¦  «        D ]}t          |¦  «        rŒ|dz  }Œ|||ft          |<   |S )zECount installed skills in a profile (cached by skills-dir signature).r   r   Nr   é   zSKILL.md)	r    rE   rG  Útimer>  rÌ   Ú_SKILL_COUNT_TTL_SECONDSÚrglobr   )r)   r?  ÚkeyÚ	signatureÚnowÚcachedÚcountÚmds           r0   Ú_count_skillsrS    så   € à˜xÑ'€JØ×ÒÑÔð Øˆqå
ˆj‰/Œ/€CÝ% jÑ1Ô1€IÝ
Œ)‰+Œ+€CÝ×#Ò# CÑ(Ô(€FàÐØ�1ŒI˜Ò"Ð"Ø�6˜!”9‰_Õ 8Ò8Ð8à�aŒyÐà€EØ×Ò˜zÑ*Ô*ð ð ˆÝ! "Ñ%Ô%ð 	ØØ�‰
ˆˆØ(¨#¨uÐ5Õ�sÑØ€LrG   c                 ó   — | dz  S )Nzprofile.yamlr€   r/   s    r0   Ú_profile_yaml_pathrU  /  s   € Ø˜Ñ'Ð'rG   c                 óò  — t          | ¦  «        }|                     ¦   «         sdddœS 	 ddl}t          |dd¬¦  «        5 }|                     |¦  «        pi }ddd¦  «         n# 1 swxY w Y   n# t
          $ r dddœcY S w xY wt          |t          ¦  «        sdddœS t          | 	                    d	¦  «        pd¦  «         
                    ¦   «         t          | 	                    d
d¦  «        ¦  «        dœS )u  Read ``<profile_dir>/profile.yaml`` and return a dict.

    Returns ``{"description": "", "description_auto": False}`` when the
    file is missing or unreadable. Never raises â€” a corrupt
    profile.yaml on an unrelated profile must not break
    ``hermes profile list``.
    rÉ   F©r  r   r   Nrý   r§   r°   r  r   )rU  r  r*  r  r+  r¼   rŒ   r,  rE   rÌ   r�   r&  )r)   r  r*  r  r.  s        r0   Úread_profile_metarX  3  s[  € õ ˜kÑ*Ô*€DØ�<Š<‰>Œ>ð >Ø!°uÐ=Ð=Ð=ð>ØˆˆˆÝ�$˜ gÐ.Ñ.Ô.ð 	+°!Ø—>’> !Ñ$Ô$Ð*¨ˆDð	+ð 	+ð 	+ñ 	+ô 	+ð 	+ð 	+ð 	+ð 	+ð 	+ð 	+øøøð 	+ð 	+ð 	+ð 	+øøåð >ð >ð >Ø!°uÐ=Ð=Ð=Ð=Ð=ð>øøøå�d�DÑ!Ô!ð >Ø!°uÐ=Ð=Ð=å˜4Ÿ8š8 MÑ2Ô2Ð8°bÑ9Ô9×?Ò?ÑAÔAÝ  §¢Ð*<¸eÑ!DÔ!DÑEÔEðð ð s5   ªA0 Á A$ÁA0 Á$A(Á(A0 Á+A(Á,A0 Á0BÂBrW  r  r   c                óþ  — |                       ¦   «         st          d| › �¦  «        ‚ddl}t          | ¦  «        }i }|                     ¦   «         rl	 t          |dd¬¦  «        5 }|                     |¦  «        pi }ddd¦  «         n# 1 swxY w Y   t          |t          ¦  «        r|}n# t          $ r i }Y nw xY w|�| 
                    ¦   «         |d<   |�t          |¦  «        |d<   dd	lm}  |||d
¬¦  «         dS )zãUpdate ``<profile_dir>/profile.yaml`` in place.

    Only the explicitly passed fields are overwritten; unspecified
    fields preserve existing values. Creates the file if missing.
    Profile directory itself must exist.
    z"profile directory does not exist: r   Nrý   r§   r°   r  r   )Úatomic_yaml_writeF)Ú	sort_keys)r    r½   r*  rU  r  r  r+  rŒ   r,  r¼   r�   r&  ÚutilsrZ  )	r)   r  r   r*  r  Úexistingr  ÚloadedrZ  s	            r0   Úwrite_profile_metar_  L  s�  € ð ×ÒÑÔð TÝÐ RÀ[Ð RÐ RÑSÔSÐSØ€K€K€KÝ˜kÑ*Ô*€DØ€HØ‡|‚|�~„~ð ð	Ý�d˜C¨'Ð2Ñ2Ô2ð 1°aØŸš¨Ñ*Ô*Ð0¨b�ð1ð 1ð 1ñ 1ô 1ð 1ð 1ð 1ð 1ð 1ð 1øøøð 1ð 1ð 1ð 1å˜&¥$Ñ'Ô'ð "Ø!�øøÝð 	ð 	ð 	ØˆHˆHˆHð	øøøàÐØ"-×"3Ò"3Ñ"5Ô"5ˆ�ÑØÐ#Ý'+Ð,<Ñ'=Ô'=ˆÐ#Ñ$ð (Ð'Ð'Ð'Ð'Ð'àÐ�d˜H°Ð6Ñ6Ô6Ð6Ð6Ð6s6   ÁB* Á#BÁ;B* ÂBÂB* ÂBÂB* Â*B9Â8B9c                  ó6  — g } t          ¦   «         }t          ¦   «         }|                     ¦   «         rºt          |¦  «        \  }}t	          |¦  «        \  }}}t          |¦  «        }|                      t          d|dt          |¦  «        |||dz   	                    ¦   «         t          |¦  «        ||||                     dd¦  «        |                     dd¦  «        ¬¦  «        ¦  «         t          ¦   «         }	|	                     ¦   «         �r‰t          ¦   «         }
t          |	                     ¦   «         ¦  «        D �]X}|                     ¦   «         sŒ|j        }|dk    rŒ&t"                               |¦  «        sŒAt          |¦  «        \  }}|
                     t'          |¦  «        ¦  «        }|rt(          j        d	k    }||r|› d
�n|z  }nd}t	          |¦  «        \  }}}t          |¦  «        }|                      t          ||dt          |¦  «        |||dz   	                    ¦   «         t          |¦  «        |r| 	                    ¦   «         r|nd|||||                     dd¦  «        |                     dd¦  «        ¬¦  «        ¦  «         �ŒZ| S )z4Return info for all profiles, including the default.rh   Tr   r  rÉ   r   F)rŠ   r  r  r  rn   r  r  r  r  r  r  r  r   r¤   r¯   N)rŠ   r  r  r  rn   r  r  r  r  r  r  r  r  r  r   )r‰   rD   r    r4  r/  rX  r;   r  r=  r-   rS  rÌ   r�   rú   r  r  rŠ   r”   r•   r‘   r´   rµ   )r   rÀ   Údefault_homern   r  Ú	dist_nameÚdist_versionÚdist_sourceÚmetaÚprofiles_rootÚ	alias_mapr?   rŠ   r  rÁ   r  s                   r0   Úlist_profilesrh  u  sÀ  € à€HÝ"Ñ$Ô$€Kõ ,Ñ-Ô-€LØ×ÒÑÔð Ý,¨\Ñ:Ô:‰ˆˆxÝ/FÀ|Ñ/TÔ/TÑ,ˆ	�< Ý  Ñ.Ô.ˆØ�Š�ØØØÝ2°<Ñ@Ô@ØØØ! FÑ*×2Ò2Ñ4Ô4Ý% lÑ3Ô3Ø'Ø!-Ø +ØŸš °Ñ3Ô3Ø!ŸXšXÐ&8¸%Ñ@Ô@ð
ñ 
ô 
ñ 	ô 	ð 	õ" 'Ñ(Ô(€MØ×ÒÑÔñ &õ $Ñ%Ô%ˆ	Ý˜M×1Ò1Ñ3Ô3Ñ4Ô4ð !	ñ !	ˆEØ—<’<‘>”>ð ØØ”:ˆDØ�yÒ Ð ØÝ!×'Ò'¨Ñ-Ô-ð ØÝ0°Ñ7Ô7‰OˆE�8Ø"ŸšÕ'=¸dÑ'CÔ'CÑDÔDˆJØð "Ý œ\¨WÒ4�
Ø(À:Ð,]¨zÐ,?Ð,?Ð,?Ð,?ÐS]Ñ^�
�
à!�
Ý3JÈ5Ñ3QÔ3QÑ0ˆI�| [Ý$ UÑ+Ô+ˆDØ�OŠO�KØØØ Ý 6°uÑ =Ô =ØØ!Ø ™×/Ò/Ñ1Ô1Ý)¨%Ñ0Ô0Ø*4ÐW¸×9JÒ9JÑ9LÔ9LÐW˜:˜:ÐSWØ%Ø"+Ø%1Ø$/Ø ŸHšH ]°BÑ7Ô7Ø!%§¢Ð*<¸eÑ!DÔ!Dðñ ô ñ ô ð ñ ð$ €OrG   Ú	multiplexc                 ó¦  — t          ¦   «         pd}| s|t          |¦  «        fgS dt          ¦   «         fg}t          ¦   «         }|                     ¦   «         ryt          |                     ¦   «         ¦  «        D ]W}|                     ¦   «         sŒ|j        }|dk    rŒ%t           	                    |¦  «        sŒ@| 
                    ||f¦  «         ŒX|S )uà  Return the ``(profile_name, hermes_home)`` pairs a gateway should serve.

    This is the single chokepoint for "which profiles does the inbound gateway
    handle" so later multiplexing phases never re-derive the set.

    - ``multiplex=False`` (default): returns exactly one entry for the *active*
      profile â€” byte-for-byte the single-profile behavior the gateway has
      always had. The name is ``"default"`` for the default profile or the
      active named profile's id.
    - ``multiplex=True``: returns the default profile plus every valid named
      profile under ``profiles/``, each paired with its own HERMES_HOME.

    Intentionally lightweight (a directory scan + name validation only): no
    per-profile config reads, gateway-running probes, or skill counts like
    :func:`list_profiles`. It runs on gateway startup and must stay cheap.

    The returned ``hermes_home`` is the path to pass to
    ``set_hermes_home_override`` when scoping a turn to that profile.
    rh   )Úget_active_profile_namerž   rD   r�   r    r  r  rŠ   r”   r•   r;   )ri  ÚactiveÚserverf  r?   rŠ   s         r0   Úprofiles_to_servern  ½  sç   € õ( %Ñ&Ô&Ð3¨)€FØð 3Ø�¨Ñ0Ô0Ð1Ð2Ð2à&/Õ1IÑ1KÔ1KÐ%LÐ$M€Eå&Ñ(Ô(€MØ×ÒÑÔð 	(Ý˜M×1Ò1Ñ3Ô3Ñ4Ô4ð 	(ð 	(ˆEØ—<’<‘>”>ð ØØ”:ˆDØ�yÒ Ð ØÝ!×'Ò'¨Ñ-Ô-ð ØØ�LŠL˜$ ˜Ñ'Ô'Ð'Ð'à€LrG   FÚ
clone_fromÚ	clone_allÚclone_configÚno_aliasÚ	no_skillsc                 ó¦  — |r|€|s|rt          d¦  «        ‚t          | ¦  «        }t          |¦  «         |dk    rt          d¦  «        ‚t          |¦  «        }|                     ¦   «         rt          d|› d|› �¦  «        ‚d}	|€|s|rk|€ddlm}
  |
¦   «         }	n-t          |¦  «        }t          |¦  «         t          |¦  «        }	|	                     ¦   «         st          d	|pd
› d|	› �¦  «        ‚|rL|	rJt          j        |	|dt          |	¦  «        ¬¦  «         t          D ]}||z                       d¬¦  «         Œ�nB|                     dd¬¦  «         t           D ]}||z                       dd¬¦  «         Œ|	��t"          D ]o}|	|z  }|                     ¦   «         rT||z  }t          j        ||¦  «         |dk    r4	 t'          j        t+          |¦  «        d¦  «         Œ_# t,          $ r Y Œkw xY wŒp|	dz  }|                     ¦   «         rt          j        ||dz  dd¬¦  «         t.          D ]Q}|	|z  }|                     ¦   «         r6||z  }|j                             dd¬¦  «         t          j        ||¦  «         ŒR|dz  }|                     ¦   «         sK	 |                     dd¬¦  «         t'          j        t+          |¦  «        d¦  «         n# t,          $ r Y nw xY w|dz  }|                     ¦   «         s/	 ddlm} |                     |d¬¦  «         n# t8          $ r Y nw xY w|r1	 |t:          z                       dd¬¦  «         n# t,          $ r Y nw xY w|st=          |¦  «         |rJ|                     ¦   «         r6	 tA          ||                     ¦   «         d¬¦  «         n# t8          $ r Y nw xY wtC          |¦  «         |S )aÙ  Create a new profile directory.

    Parameters
    ----------
    name:
        Profile identifier (lowercase, alphanumeric, hyphens, underscores).
    clone_from:
        Source profile to clone from. If ``None`` and clone_config/clone_all
        is True, defaults to the currently active profile.
    clone_all:
        If True, do a full copytree of the source (all state).
    clone_config:
        If True, copy config files (config.yaml, .env, SOUL.md), installed
        skills, and selected profile identity files from the source profile.
    no_alias:
        If True, skip wrapper script creation.
    no_skills:
        If True, create an empty profile with no bundled skills, and write
        a marker file so ``hermes update`` skips re-seeding this profile's
        skills. Mutually exclusive with ``clone_config``/``clone_all`` (those
        explicitly copy skills from the source).

    Returns
    -------
    Path
        The newly created profile directory.
    Nz‡--no-skills is mutually exclusive with --clone / --clone-from / --clone-all (cloning explicitly copies skills from the source profile).rh   uS   Cannot create a profile named 'default' â€” it is the built-in profile (~/.hermes).ú	Profile 'ú' already exists at r   ©Úget_hermes_homezSource profile 'rl  z' does not exist at T©ÚsymlinksÚignore©Ú
missing_okrÒ   r   é€  r   )rz  Údirs_exist_okú¥# Per-profile secrets for this Hermes profile.
# API keys and tokens set here override the shell environment.
# Behavioral settings belong in config.yaml, not here.
r§   r°   r   )ÚDEFAULT_SOUL_MDz—This profile opted out of bundled-skill seeding (`hermes profile create --no-skills`).
Delete this file to re-enable sync on the next `hermes update`.
FrW  )"r=   r‘   r˜   rž   r-   ÚFileExistsErrorr…   rx  r    r½   rÙ   ÚcopytreerF   r   rè   rÖ   Ú_PROFILE_DIRSÚ_CLONE_CONFIG_FILESÚcopy2rÊ   rÜ   rE   r.   Ú_CLONE_SUBDIR_FILESÚparentrØ   Úhermes_cli.default_soulr�  r¼   r,   r÷   r�   r_  Ú_maybe_register_gateway_service)rŠ   ro  rp  rq  rr  rs  r  r�   r)   r2   rx  ÚstaleÚsubdirÚfilenameÚsrcÚdstÚsource_skillsÚrelpathÚenv_pathÚ	soul_pathr�  s                        r0   Úcreate_profiler”  æ  sZ  € ðH ð 
�jÐ,°Ð,À	Ð,ÝðJñ
ô 
ð 	
õ # 4Ñ(Ô(€EÝ˜%Ñ Ô Ð à�	ÒÐÝØañ
ô 
ð 	
õ " %Ñ(Ô(€KØ×ÒÑÔð TÝÐR¨%ÐRÐRÀ[ÐRÐRÑSÔSÐSð €JØÐ Ð¨lÐØÐà8Ð8Ð8Ð8Ð8Ð8Ø(˜Ñ*Ô*ˆJˆJå/°
Ñ;Ô;ˆJÝ! *Ñ-Ô-Ð-Ý(¨Ñ4Ô4ˆJØ× Ò Ñ"Ô"ð 	Ý#Ø[ :Ð#9°Ð[Ð[ÈzÐ[Ð[ñô ð ð ð 0+�Zð 0+åŒØØØÝ-¨jÑ9Ô9ð		
ñ 	
ô 	
ð 	
õ &ð 	:ð 	:ˆEØ˜5Ñ ×(Ò(°DÐ(Ñ9Ô9Ð9Ð9ñ	:ð 	×Ò $°ÐÑ6Ô6Ð6Ý#ð 	Fð 	FˆFØ˜6Ñ!×(Ò(°ÀÐ(ÑEÔEÐEÐEð Ñ!Ý/ð !ð !�Ø  8Ñ+�Ø—:’:‘<”<ð !Ø%¨Ñ0�CÝ”L  cÑ*Ô*Ð*ð
   6Ò)Ð)ð!ÝœH¥S¨¡X¤X¨uÑ5Ô5Ð5Ð5øÝ&ð !ð !ð !Ø ˜Dð!øøøøð '¨Ñ1ˆMØ×#Ò#Ñ%Ô%ð jÝ” ¨{¸XÑ/EÐPTÐdhÐiÑiÔiÐiõ /ð +ð +�Ø  7Ñ*�Ø—:’:‘<”<ð +Ø%¨Ñ/�CØ”J×$Ò$¨T¸DÐ$ÑAÔAÐAÝ”L  cÑ*Ô*Ð*øð ˜VÑ#€HØ�?Š?ÑÔð 
ð		Ø×ÒðKð !ð	  ñ ô ð õ ŒH•S˜‘]”] EÑ*Ô*Ð*Ð*øÝð 	ð 	ð 	ØˆDð	øøøð
 ˜iÑ'€IØ×ÒÑÔð ð	Ø?Ð?Ð?Ð?Ð?Ð?Ø× Ò  ¸7Ð ÑCÔCÐCÐCøÝð 	ð 	ð 	ØˆDð	øøøð
 ð 	ð	ØÕ3Ñ3×?Ò?ðTð !ð	 @ñ ô ð ð øõ ð 	ð 	ð 	ØˆDð	øøøð ð 9Ý+¨KÑ8Ô8Ð8ð
 ð �{×(Ò(Ñ*Ô*ð ð	ÝØØ'×-Ò-Ñ/Ô/Ø!&ðñ ô ð ð øõ
 ð 	ð 	ð 	ØˆDð	øøøõ $ EÑ*Ô*Ð*àÐsZ   Ç"G(Ç(
G5Ç4G5Ê 9K Ë
K'Ë&K'ÌL" Ì"
L/Ì.L/Ì5M Í
M"Í!M"Î$N2 Î2
N?Î>N?rñ   c           
      ó:  — t          | ¦  «        rg g g ddœS t          t          ¦  «        j        j                             ¦   «         }	 t          j        t          j        ddgi t          j
        ¥dt          | ¦  «        i¥t          |¦  «        ddddd¬	¦  «        }|j        d
k    rD|j                             ¦   «         r+t          j        |j                             ¦   «         ¦  «        S |sat#          d|j        › �¦  «         |j                             ¦   «         r1t#          d|j                             ¦   «         dd…         › �¦  «         dS # t
          j        $ r |st#          d¦  «         Y dS t(          $ r}|st#          d|› �¦  «         Y d}~dS d}~ww xY w)u¿  Seed bundled skills into a profile via subprocess.

    Uses subprocess because sync_skills() caches HERMES_HOME at module level.
    Returns the sync result dict, or None on failure.

    Profiles that opted out of bundled skills (via ``hermes profile create
    --no-skills`` â€” which writes ``.no-bundled-skills`` to the profile root)
    are skipped and get an empty-result dict so callers can report
    "opted out" instead of "failed".
    T)ÚcopiedÚupdatedÚuser_modifiedÚskipped_opt_outz-cziimport json; from tools.skills_sync import sync_skills; r = sync_skills(quiet=True); print(json.dumps(r))ÚHERMES_HOMEr§   r¨   é<   )ÚenvÚcwdrª   r«   r¬   r­   r®   r   u%   âš  Skill seeding returned exit code z  NéÈ   u!   âš  Skill seeding timed out (60s)u   âš  Skill seeding failed: )r1   r   Ú__file__rˆ  r<   r¶   r·   r´   Ú
executablerÊ   rË   rE   r¸   r¹   r�   ÚjsonÚloadsr×   Ústderrr¾   r¼   )r)   rñ   Úproject_rootrÂ   râ   s        r0   Úseed_profile_skillsr¥  §  sÜ  € õ " +Ñ.Ô.ð 
àØØØ#ð	
ð 
ð 	
õ �‘>”>Ô(Ô/×7Ò7Ñ9Ô9€LðÝ”ÝŒ^˜TðAðBð @•2”:Ð?˜}­c°+Ñ.>Ô.>Ð?Ð?Ý�LÑ!Ô!Ø d°WÀYÐXZð
ñ 
ô 
ˆð Ô Ò!Ð! f¤m×&9Ò&9Ñ&;Ô&;Ð!Ý”:˜fœm×1Ò1Ñ3Ô3Ñ4Ô4Ð4Øð 	:ÝÐM¸&Ô:KÐMÐMÑNÔNÐNØŒ}×"Ò"Ñ$Ô$ð :ÝÐ8˜6œ=×.Ò.Ñ0Ô0°°#°Ô6Ð8Ð8Ñ9Ô9Ð9ØˆtøÝÔ$ð ð ð Øð 	7ÝÐ5Ñ6Ô6Ð6ØˆtˆtÝð ð ð Øð 	4ÝÐ2¨qÐ2Ð2Ñ3Ô3Ð3Øˆtˆtˆtˆtˆtøøøøðøøøs&   ÁB!E Ã*A#E Å FÅ2	FÅ;FÆFc                 óÖ  — g }t          ¦   «         }|                     ¦   «         s|S t          ¦   «         dz  }t          |                     ¦   «         ¦  «        D �]}|                     ¦   «         rt
                               |j        ¦  «        sŒ7|j        dk    rŒC|dz  }|                     ¦   «         rŒ]	 | 	                    ¦   «         rt          j        ||¦  «         n|                     dd¬¦  «         t          j        t          |¦  «        d¦  «         |                     |j        ¦  «         ŒÜ# t"          $ r'}| st%          d|j        › d|› �¦  «         Y d	}~�Œd	}~ww xY w|S )
u‚  Give every named profile that predates per-profile ``.env`` files one.

    Profiles created before the dashboard/CLI started seeding a ``.env``
    (PR #44792) have none, so once the Channels/Keys endpoints became
    profile-scoped those profiles stopped inheriting the root install's
    credentials and showed everything as unconfigured. To avoid breaking
    anyone on update, copy the DEFAULT install's ``.env`` into each named
    profile that lacks one â€” that preserves the effective credentials those
    profiles were already running with (they previously read the root
    ``.env`` via the process environment). Users can then diverge per
    profile from there.

    Falls back to the placeholder header when the default install has no
    ``.env`` itself. Never overwrites an existing profile ``.env``.

    Returns the list of profile names that received a backfilled ``.env``.
    r   rh   r€  r§   r°   r~  u%   âš  Could not seed .env for profile 'z': N)r�   r    rD   r  r  r”   r•   rŠ   r-   r  rÙ   r†  rØ   rÊ   rÜ   rE   r;   r.   r×   )rñ   Ú
backfilledrf  Údefault_envr?   r’  râ   s          r0   Úbackfill_profile_envsr©  Ô  sŸ  € ð$ €JÝ&Ñ(Ô(€MØ×ÒÑ!Ô!ð ØÐå*Ñ,Ô,¨vÑ5€Kå˜×-Ò-Ñ/Ô/Ñ0Ô0ð Rñ RˆØ�|Š|‰~Œ~ð 	¥^×%9Ò%9¸%¼*Ñ%EÔ%Eð 	ØØŒ:˜Ò"Ð"ØØ˜6‘>ˆØ�?Š?ÑÔð 	Øð	RØ×"Ò"Ñ$Ô$ð Ý”˜[¨(Ñ3Ô3Ð3Ð3à×#Ò#ðOð %ð	 $ñ ô ð õ ŒH•S˜‘]”] EÑ*Ô*Ð*Ø×Ò˜eœjÑ)Ô)Ð)Ð)øÝð 	Rð 	Rð 	RØð RÝÐP¸e¼jÐPÐPÈQÐPÐPÑQÔQÐQøøøøùøøøøð	Røøøð Ðs   Â7A=D5Ä5
E&Ä?E!Å!E&r�   c                 óê  ‡— 	 ddl }n# t          $ r g cY S w xY w	 |                     ¦   «         }n# t          $ r |}Y nw xY wt	          j        ¦   «         h}	 |                     t	          j        ¦   «         ¦  «                             ¦   «         }|�0|                     |j	        ¦  «         |                     ¦   «         }|­0n# t          $ r Y nw xY w	 |                     t	          j        ¦   «         ¦  «         
                    ¦   «         }n# t          $ r d}Y nw xY wh d£}d}g }	|                     g d¢¦  «        D �]4}
	 |
j        }|                     d¦  «        }|�||v rŒ'|�|                     d¦  «        |k    rŒC|                     d¦  «        pg }|sŒ]d	                     |¦  «        Št          j                             |d         ¦  «                             ¦   «         }t%          ˆfd
„|D ¦   «         ¦  «        p|dk    p|                     d¦  «        }|sŒâd„ |D ¦   «         }||z  sŒôd}t)          |¦  «        D ]†\  }}|dv r7|dz   t+          |¦  «        k     r!t-          ||dz            ¦  «        | k    rd} nHŒ@|                     d¦  «        r1t-          |                     dd¦  «        d         ¦  «        | k    rd} nŒ‡|se	 |
                     ¦   «         pi                      dd¦  «        }|r't3          |¦  «                             ¦   «         |k    rd}n# t          $ r Y nw xY w|r|	                     |¦  «         �Œ# |j        |j        |j        f$ r Y �Œ&t          $ r Y �Œ2w xY w|	S )uÄ  PIDs of running Hermes *backends* bound to this profile.

    The ``gateway.pid`` file only tracks the messaging gateway.  A Desktop app
    spawns a headless ``serve`` (or legacy ``dashboard --no-open``) backend per
    profile that holds the profile's SQLite connection open and keeps writing
    sessions/WAL/sandbox files â€” the writer that makes ``rmtree`` hit
    ``ENOTEMPTY`` (and, pre-fix, resurrected the tree).  ``gateway.pid`` never
    names it, so find it by inspection: a Hermes backend subcommand
    (``serve``/``dashboard``/``gateway``) that is bound to *this* profile either
    by a ``--profile <canon>`` / ``-p <canon>`` selector or by a ``HERMES_HOME``
    that resolves to ``profile_dir``.

    Best-effort and tightly scoped: current-user processes only, backend
    subcommands only (never an interactive ``chat``/``tui``), and never this
    process or its ancestors.  Returns an empty list if ``psutil`` can't
    inspect anything.
    r   N>   rm  rw   Ú	dashboard)zhermes_cli.mainzhermes-gatewayÚtui_gateway)ÚpidrŠ   ÚusernameÚcmdliner­  r®  r¯  ú c              3   ó    •K  — | ]}|‰v V — Œ	d S ©Nr€   )Ú.0ÚmarkerÚjoineds     €r0   ú	<genexpr>z._profile_bound_backend_pids.<locals>.<genexpr>J  s(   øè è € ÐBÐB¨�F˜fÐ$ÐBÐBÐBÐBÐBÐBrG   rg   c                 ó6   — h | ]}|                      ¦   «         ’ŒS r€   )r�   )r³  Útoks     r0   ú	<setcomp>z._profile_bound_backend_pids.<locals>.<setcomp>S  s    € Ð2Ð2Ð2 c�c—i’i‘k”kÐ2Ð2Ð2rG   F>   ú-pú	--profiler   Tz
--profile=ú=rš  rÉ   )Úpsutilr¼   r<   r.   rÊ   ÚgetpidÚProcessrˆ  Úaddr­  r®  Úprocess_iterÚinforÌ   Újoinr  Úbasenamer�   ÚanyÚ
startswithÚ	enumerater
  r‘   rÍ   rË   r   r;   ÚNoSuchProcessÚAccessDeniedÚZombieProcess)r�   r)   r½  Úresolved_dirÚskiprˆ  Úcurrent_userÚbackend_tokensÚhermes_markersÚpidsÚprocrÂ  r­  ÚargvÚexe_nameÚ	is_hermesÚtokensÚboundÚir¸  Úenv_homerµ  s                        @r0   Ú_profile_bound_backend_pidsrÙ    s:  ø€ ð$ØˆˆˆˆøÝð ð ð Øˆ	ˆ	ˆ	ðøøøð#Ø"×*Ò*Ñ,Ô,ˆˆøÝð #ð #ð #Ø"ˆˆˆð#øøøõ
 ”i‘k”k�]€DðØ—’¥¤	¡¤Ñ,Ô,×3Ò3Ñ5Ô5ˆØÐ Ø�HŠH�V”ZÑ Ô Ð Ø—]’]‘_”_ˆFð Ð øøõ ð ð ð ØˆðøøøðØ—~’~¥b¤i¡k¤kÑ2Ô2×;Ò;Ñ=Ô=ˆˆøÝð ð ð Øˆˆˆðøøøð 7Ð6Ð6€NØI€NØ€Dà×#Ò#Ð$JÐ$JÐ$JÑKÔKð ;ñ ;ˆð:	Ø”9ˆDØ—(’(˜5‘/”/ˆCØˆ{˜c T˜k˜kØØÐ'¨D¯HªH°ZÑ,@Ô,@ÀLÒ,PÐ,PØà—8’8˜IÑ&Ô&Ð,¨"ˆDØð Øð —X’X˜d‘^”^ˆFÝ”w×'Ò'¨¨Q¬Ñ0Ô0×6Ò6Ñ8Ô8ˆHåÐBÐBÐBÐB°>ÐBÑBÔBÑBÔBð 1Ø˜xÒ'ð1à×&Ò& xÑ0Ô0ð ð
 ð Øð 3Ð2¨TÐ2Ñ2Ô2ˆFØ˜^Ñ+ð Øð ˆEÝ# D™/œ/ð ð ‘��3ØÐ-Ð-Ð-°!°a±%½#¸d¹)¼)Ò2CÐ2CÝ-¨d°1°q±5¬kÑ:Ô:¸eÒCÐCØ $˜Ø˜ð Dð —^’^ LÑ1Ô1ð Ý-¨c¯iªi¸¸QÑ.?Ô.?ÀÔ.BÑCÔCÀuÒLÐLØ $˜Ø˜øð ð ðØ $§¢¡¤Ð 4°"×9Ò9¸-ÈÑLÔL�HØð %¥D¨¡N¤N×$:Ò$:Ñ$<Ô$<ÀÒ$LÐ$LØ $˜øøÝ ð ð ð ð �Dðøøøð
 ð !Ø—’˜CÑ Ô Ð ùøØÔ$ fÔ&9¸6Ô;OÐPð 	ð 	ð 	Ø‰HÝð 	ð 	ð 	Ø‰Hð	øøøð €Ksš   ƒ ˆ–›0 °?¾?ÁA*C Ã
CÃCÃ8D ÄDÄDÅ"M	Å$M	Æ M	ÆBM	ÈM	È1BM	ËAL ÌM	Ì 
L-Ì*M	Ì,L-Ì-M	Í	M0Í#	M0Í/M0c                 ób  ‡— t          | |¦  «        }|sdS 	 ddlmŠm} n# t          $ r Y dS w xY w|D ]+}	  ||¦  «         Œ# t
          t          t          f$ r Y Œ(w xY wt          j        ¦   «         dz   }t          j        ¦   «         |k     rGt          ˆfd„|D ¦   «         ¦  «        sn+t          j
        d¦  «         t          j        ¦   «         |k     °G|D ]9} ‰|¦  «        r,	  ||d¬¦  «         Œ# t
          t          t          f$ r Y Œ5w xY wŒ:t          d	t          |¦  «        › d
�¦  «         dS )aÉ  Terminate any Desktop-spawned / stray backends bound to this profile.

    Complements ``_stop_gateway_process`` (which only knows ``gateway.pid``):
    without this, a live ``serve``/``dashboard`` backend keeps creating files
    under the profile dir while ``rmtree`` walks it, so the final ``rmdir``
    fails with ``ENOTEMPTY`` and the delete doesn't converge.  Best-effort:
    any failure is reported and swallowed so it never makes delete worse.
    Nr   )Ú_pid_existsÚterminate_pidg      $@c              3   ó.   •K  — | ]} ‰|¦  «        V — Œd S r²  r€   )r³  r­  rÛ  s     €r0   r¶  z)_stop_profile_backends.<locals>.<genexpr>“  s-   øè è € Ð4Ð4¨�;�;˜sÑ#Ô#Ð4Ð4Ð4Ð4Ð4Ð4rG   ç      à?T©Úforceu   âœ“ Stopped z profile backend process(es))rÙ  r;  rÛ  rÜ  r¼   ÚProcessLookupErrorÚPermissionErrorr.   rJ  rÅ  Úsleepr×   r
  )r�   r)   rÐ  Ú_terminate_pidr­  ÚdeadlinerÛ  s         @r0   Ú_stop_profile_backendsræ  x  s²  ø€ õ ' u¨kÑ:Ô:€DØð ØˆðØOÐOÐOÐOÐOÐOÐOÐOÐOøÝð ð ð Øˆˆðøøøð ð ð ˆð	ØˆN˜3ÑÔÐÐøÝ"¥OµWÐ=ð 	ð 	ð 	ØˆHð	øøøõ Œy‰{Œ{˜TÑ!€HÝ
Œ)‰+Œ+˜Ò
 Ð
 ÝÐ4Ð4Ð4Ð4¨tÐ4Ñ4Ô4Ñ4Ô4ð 	ØÝŒ
�3‰Œˆõ Œ)‰+Œ+˜Ò
 Ð
 ð
 ð ð ˆØˆ;�sÑÔð 	ðØ�˜s¨$Ð/Ñ/Ô/Ð/Ð/øÝ&­½ÐAð ð ð Ø�ðøøøð	õ 
Ð
@�˜T™œÐ
@Ð
@Ð
@ÑAÔAÐAÐAÐAs/   —   
.­.¶AÁAÁAÃ#C1Ã1DÄ
Dc                 ój  — d}d}t          |¦  «        D ]š}	 	 t          j        | |¬¦  «         n&# t          $ r t          j        | |¬¦  «         Y nw xY w dS # t          $ rJ}|}|                      ¦   «         sY d}~ dS ||dz
  k     rt          j        d|dz   z  ¦  «         Y d}~Œ“d}~ww xY w|�|‚dS )a  ``shutil.rmtree`` with a short retry loop for transient races.

    Even after stopping the gateway and profile backends, a just-terminated
    process can leave in-flight writes (SQLite ``-wal``/``-shm`` checkpoints,
    sandbox temp files) that land after ``rmtree`` has walked past a directory,
    surfacing as ``ENOTEMPTY`` (POSIX) or a transient ``PermissionError``
    (Windows file lock still releasing).  A few spaced retries let those settle
    instead of failing the whole delete on a race the next attempt would win.
    é   N)Úonexc)Úonerrorr   g333333Ó?)ÚrangerÙ   ÚrmtreeÚ	TypeErrorr.   r-   rJ  rã  )r)   Úonexc_handlerÚattemptsÚlast_excÚattemptrâ   s         r0   Ú_rmtree_with_retryrò  ¡  s  € ð €HØ#€HÝ˜‘?”?ð 0ð 0ˆð	0ðBÝ”˜k°Ð?Ñ?Ô?Ð?Ð?øÝð Bð Bð BÝ”˜k°=ÐAÑAÔAÐAÐAÐAðBøøøàˆFˆFøÝð 	0ð 	0ð 	0ØˆHØ×%Ò%Ñ'Ô'ð Ø������Ø˜ A™Ò%Ð%Ý”
˜3 '¨A¡+Ñ.Ñ/Ô/Ð/øøøøøøøøøð	0øøøð ÐØˆð Ðs8   ˜/®A¯ AÁAÁAÁAÁ
B,Á"B'Á?#B'Â'B,Úyesc                 ó˜  — t          | ¦  «        }t          |¦  «         |dk    rt          d¦  «        ‚t          |¦  «        }|                     ¦   «         st          d|› d�¦  «        ‚t          |¦  «        \  }}t          |¦  «        }t          |¦  «        }t          |¦  «        \  }}	}
t          d|› �¦  «         t          d|› �¦  «         |rt          d|› �|rd|› d	�nd
z   ¦  «         |rt          d|› �¦  «         |r+t          d|› d|	pd› �¦  «         |
rt          d|
› �¦  «         dg}t          ¦   «         |z  }|                     ¦   «         }|r|                     d|› d	�¦  «         t          d¦  «         |D ]}t          d|› �¦  «         Œ|rt          d¦  «         |stt          ¦   «          	 t          d|› d�¦  «                             ¦   «         }n(# t           t"          f$ r t          d¦  «         |cY S w xY w||k    rt          d¦  «         |S t%          ||¦  «         t'          |¦  «         |rt)          |¦  «         t+          ||¦  «         |r!t-          |¦  «        rt          d|› �¦  «         d}	 d„ }t/          ||¦  «         t          d|› �¦  «         n.# t0          $ r!}t          d|› d|› �¦  «         |}Y d}~nd}~ww xY w	 t3          ¦   «         }||k    rt5          d¦  «         t          d¦  «         n# t0          $ r Y nw xY w|�t7          d|› d|› �¦  «        |‚t          d |› d!�¦  «         |S )"zÒDelete a profile, its wrapper script, and its gateway service.

    Stops the gateway if running. Disables systemd/launchd service first
    to prevent auto-restart.

    Returns the path that was removed.
    rh   zZCannot delete the default profile (~/.hermes).
To remove everything, use: hermes uninstallru  ú' does not exist.z

Profile: z	Path:    z	Model:   z (r²   rÉ   z	Skills:  zDistribution: ú@ú?zInstalled from: z;All config, API keys, memories, sessions, skills, cron jobszCommand alias (z
This will permanently delete:u     â€¢ u0     âš  Gateway is running â€” it will be stopped.zType 'z' to confirm: z
Cancelled.z
Cancelled.u   âœ“ Removed Nc                 óä  — ddl }t          |t          ¦  «        r|d         }t          |t          ¦  «        rº	 t	          j        |t	          j         |¦  «        j        |j        z  ¦  «         n# t          $ r Y nw xY wt          j	         
                    |¦  «        }|rF	 t	          j        |t	          j         |¦  «        j        |j        z  ¦  «         n# t          $ r Y nw xY w | |¦  «         dS ‚ )a  onexc/onerror handler: add +w on PermissionError so rmtree can proceed.

            Handles two cases on NixOS (and other systems with read-only
            copies from immutable stores):
            1. The path itself isn't writable (e.g. a file with mode 0444)
            2. The *parent* directory isn't writable (e.g. mode 0555)

            Compatible with both the ``onexc`` API (3.12+, receives an
            exception instance) and the ``onerror`` API (3.11-, receives
            ``sys.exc_info()`` tuple).
            r   Nr   )rÝ   rŒ   Útuplerâ  rÊ   rÜ   rÞ   ÚS_IWUSRr.   r  Údirname)Úfuncr  r¿   Ú_statrˆ  s        r0   Ú_make_writablez&delete_profile.<locals>._make_writable  s  € ð !Ð Ð Ð õ
 ˜#�uÑ%Ô%ð Ø˜!”f�å˜#�Ñ/Ô/ð ðÝ”H˜T¥2¤7¨4¡=¤=Ô#8¸5¼=Ñ#HÑIÔIÐIÐIøÝð ð ð Ø�Dðøøøõ œŸš¨Ñ.Ô.�Øð ðÝœ ­¬°©¬Ô)@À5Ä=Ñ)PÑQÔQÐQÐQøÝ"ð ð ð Ø˜ðøøøà��T‘
”
�
�
�
às#   ¸4A- Á-
A:Á9A:Â4C Ã
C!Ã C!u   âš  Could not remove rÕ   u#   âœ“ Active profile reset to defaultz#Could not remove profile directory z

Profile 'z
' deleted.)r‘   r˜   r=   rž   r    r½   r4  r=  rS  r/  r×   r‰   r-   r;   Úinputr�   ÚKeyboardInterruptÚEOFErrorÚ_cleanup_gateway_serviceÚ!_maybe_unregister_gateway_serviceÚ_stop_gateway_processræ  rê   rò  r¼   Úget_active_profileÚset_active_profileÚRuntimeError)rŠ   ró  r�   r)   rn   r  Ú
gw_runningr  rb  rc  rd  Úitemsrã   Úhas_wrapperÚitemÚconfirmÚremove_errorrþ  râ   rl  s                       r0   Údelete_profiler  ¿  s„  € õ # 4Ñ(Ô(€EÝ˜%Ñ Ô Ð à�	ÒÐÝð:ñ
ô 
ð 	
õ
 " %Ñ(Ô(€KØ×ÒÑÔð FÝÐ D¨EÐ DÐ DÐ DÑEÔEÐEõ )¨Ñ5Ô5�O€Eˆ8Ý'¨Ñ4Ô4€JÝ Ñ,Ô,€KÝ+BÀ;Ñ+OÔ+OÑ(€Iˆ|˜[å	Ð
˜Ð
Ð
Ñ Ô Ð Ý	Ð
#�kÐ
#Ð
#Ñ$Ô$Ð$Øð LÝÐ!˜%Ð!Ð!¸Ð%IÐ%5¨(Ð%5Ð%5Ð%5Ð%5ÀrÑJÑKÔKÐKØð )ÝÐ'˜+Ð'Ð'Ñ(Ô(Ð(Øð 4ÝÐ@˜yÐ@Ð@¨<Ð+>¸3Ð@Ð@ÑAÔAÐAØð 	4ÝÐ2 [Ð2Ð2Ñ3Ô3Ð3ð 	Fð€Eõ
 $Ñ%Ô%¨Ñ-€LØ×%Ò%Ñ'Ô'€KØð 8Ø�ŠÐ6 |Ð6Ð6Ð6Ñ7Ô7Ð7å	Ð
+Ñ,Ô,Ð,Øð ð ˆÝˆo�tˆoˆoÑÔÐÐØð BÝÐ@ÑAÔAÐAð ð 	Ý‰Œˆð	ÝÐ: UÐ:Ð:Ð:Ñ;Ô;×AÒAÑCÔCˆGˆGøÝ!¥8Ð,ð 	ð 	ð 	Ý�.Ñ!Ô!Ð!ØÐÐÐð	øøøð �eÒÐÝ�,ÑÔÐØÐõ ˜U KÑ0Ô0Ð0õ & eÑ,Ô,Ð,ð ð +Ý˜kÑ*Ô*Ð*õ ˜5 +Ñ.Ô.Ð.ð ð 1Ý  Ñ'Ô'ð 	1ÝÐ/ Ð/Ð/Ñ0Ô0Ð0ð &*€Lð*ð#	ð #	ð #	õJ 	˜;¨Ñ7Ô7Ð7ÝÐ*˜[Ð*Ð*Ñ+Ô+Ð+Ð+øÝð ð ð ÝÐ8 kÐ8Ð8°QÐ8Ð8Ñ9Ô9Ð9Øˆˆˆˆˆˆøøøøðøøøð
Ý#Ñ%Ô%ˆØ�UŠ?ˆ?Ý˜yÑ)Ô)Ð)ÝÐ7Ñ8Ô8Ð8øøÝð ð ð Øˆðøøøð ÐÝÐ^ÀÐ^Ð^ÐP\Ð^Ð^Ñ_Ô_ÐeqÐqå	Ð
)˜Ð
)Ð
)Ð
)Ñ*Ô*Ð*ØÐs<   Æ<%G" Ç""HÈHÊ%J- Ê-
KÊ7KËKË2L Ì
LÌLc                 óX  — 	 ddl m}  |¦   «         dk    rdS ddl m}  |¦   «         }n# t          $ r Y dS t          $ r Y dS w xY w|                     ¦   «         sdS 	 |                     | d¬¦  «         dS # t          $ r Y dS t          $ r}t          d|› �¦  «         Y d}~dS d}~ww xY w)	uá  Register a profile's gateway with s6 inside the container.

    No-op on host (systemd/launchd/windows) â€” those backends raise
    ``NotImplementedError`` on ``register_profile_gateway`` and the
    existing per-profile unit-generation paths handle lifecycle.

    Best-effort: any error (no backend detected, s6 not yet ready,
    etc.) is logged and swallowed so profile creation doesn't fail
    because the s6 supervision tree is in a weird state. The user
    can re-register manually later via the gateway start command,
    which goes through the same dispatch path.

    Port selection: each supervised profile gateway loads its own
    ``HERMES_HOME`` and binds the port resolved by ``gateway/config.py``
    from that profile's environment â€” ``API_SERVER_PORT`` (or
    ``platforms.api_server.extra.port`` in the profile's
    ``config.yaml``), defaulting to 8642. There is no ``[gateway] port``
    key and no Python-side allocator (PR #30136 review item I5 retired
    the SHA-256-derived range [9200, 9800) as dead code), so two
    profiles that both leave the port at its default will both try to
    bind 8642 â€” give each profile a distinct ``API_SERVER_PORT`` in its
    ``.env``.

    Host short-circuit: check ``detect_service_manager()`` first and
    return immediately if it isn't ``"s6"``. This keeps host
    (systemd/launchd/windows) profile creation completely silent â€”
    no ``get_service_manager()`` call, no exception path, no chance
    of the ``âš  Could not register s6 gateway service`` warning ever
    rendering on a non-container machine. The earlier
    ``supports_runtime_registration()`` check still catches the case
    where detection somehow returns ``"s6"`` but the backend isn't
    actually the S6 one.
    r   ©Údetect_service_managerÚs6N©Úget_service_managerF)Ú	start_nowu+   âš  Could not register s6 gateway service: )	Úhermes_cli.service_managerr  r  r  r¼   Úsupports_runtime_registrationÚregister_profile_gatewayr=   r×   ©rø   r  r  Úmgrr¿   s        r0   rŠ  rŠ  V  s9  € ðDØEÐEÐEÐEÐEÐEØ!Ð!Ñ#Ô# tÒ+Ð+ØˆFØBÐBÐBÐBÐBÐBØ!Ð!Ñ#Ô#ˆˆøÝð ð ð ØˆˆÝð ð ð ð 	ˆˆð	øøøð
 ×,Ò,Ñ.Ô.ð ØˆðCØ×$Ò$ \¸UÐ$ÑCÔCÐCÐCÐCøÝð ð ð ð 	ˆˆÝð Cð Cð CåÐA¸CÐAÐAÑBÔBÐBÐBÐBÐBÐBÐBÐBøøøøðCøøøs6   ‚) ˜) ©
A¶	AÁAÁA6 Á6
B)Â	B)ÂB$Â$B)c                 ó<  — 	 ddl m}  |¦   «         dk    rdS ddl m}  |¦   «         }n# t          $ r Y dS t          $ r Y dS w xY w|                     ¦   «         sdS 	 |                     | ¦  «         dS # t          $ r}t          d|› �¦  «         Y d}~dS d}~ww xY w)u  Tear down a profile's s6 gateway service inside the container.

    No-op on host. Idempotent: absent services are silently skipped
    by ``unregister_profile_gateway``.

    Same host short-circuit as :func:`_maybe_register_gateway_service`
    â€” see that docstring.
    r   r  r  Nr  u-   âš  Could not unregister s6 gateway service: )r  r  r  r  r¼   r  Úunregister_profile_gatewayr×   r  s        r0   r  r  ’  s  € ð	ØEÐEÐEÐEÐEÐEØ!Ð!Ñ#Ô# tÒ+Ð+ØˆFØBÐBÐBÐBÐBÐBØ!Ð!Ñ#Ô#ˆˆøÝð ð ð ØˆˆÝð ð ð Øˆˆðøøøà×,Ò,Ñ.Ô.ð ØˆðEØ×&Ò& |Ñ4Ô4Ð4Ð4Ð4øÝð Eð Eð EÝÐC¸cÐCÐCÑDÔDÐDÐDÐDÐDÐDÐDÐDøøøøðEøøøs0   ‚) ˜) ©
A¶	AÁAÁA4 Á4
BÁ>BÂBc                 ó\  — ddl }t          j                             d¦  «        }	 t	          |¦  «        t          j        d<   ddlm}m} |                     ¦   «         dk    r¼ |¦   «         }t          j
        ¦   «         dz  dz  dz  |› d	�z  }|                     ¦   «         r{t          j        d
dd|gddd¬¦  «         t          j        d
dd|gddd¬¦  «         |                     d¬¦  «         t          j        g d¢ddd¬¦  «         t          d|› d�¦  «         nƒ|                     ¦   «         dk    rk |¦   «         }|                     ¦   «         rMt          j        ddt	          |¦  «        gddd¬¦  «         |                     d¬¦  «         t          d¦  «         n)# t           $ r}	t          d|	› �¦  «         Y d}	~	nd}	~	ww xY w|�|t          j        d<   dS dt          j        v rt          j        d= dS dS # |�|t          j        d<   ndt          j        v rt          j        d= w xY w)z9Disable and remove systemd/launchd service for a profile.r   Nrš  )Úget_service_nameÚget_launchd_plist_pathÚLinuxz.configÚsystemdÚuserz.serviceÚ	systemctlú--userÚdisableTFé
   )rª   Úcheckr®   Ústopr|  )r#  r$  zdaemon-reloadu   âœ“ Service z removedÚDarwinÚ	launchctlÚunloadu   âœ“ Launchd service removedu   âš  Service cleanup: )rµ   rÊ   rË   rÌ   rE   Úhermes_cli.gatewayr  r  Úsystemr   r   r-   r¶   r·   rè   r×   r¼   )
rŠ   r)   Ú	_platformÚold_homer  r  Úsvc_nameÚsvc_fileÚ
plist_pathrâ   s
             r0   r  r  ­  sº  € à Ð Ð Ð õ Œz�~Š~˜mÑ,Ô,€Hð&*Ý$'¨Ñ$4Ô$4�Œ
�=Ñ!ØOÐOÐOÐOÐOÐOÐOÐOà×ÒÑÔ Ò(Ð(Ø'Ð'Ñ)Ô)ˆHÝ”y‘{”{ YÑ.°Ñ:¸VÑCÈÐF[ÐF[ÐF[Ñ[ˆHØ�ŠÑ Ô ð 9Ý”Ø  (¨I°xÐ@Ø#'¨u¸bðñ ô ð õ ”Ø  (¨F°HÐ=Ø#'¨u¸bðñ ô ð ð —’¨4�Ñ0Ô0Ð0Ý”Ø<Ð<Ð<Ø#'¨u¸bðñ ô ð õ Ð7 XÐ7Ð7Ð7Ñ8Ô8Ð8øà×ÒÑÔ 8Ò+Ð+Ø/Ð/Ñ1Ô1ˆJØ× Ò Ñ"Ô"ð 5Ý”Ø  (­C°
©O¬OÐ<Ø#'¨u¸bðñ ô ð ð ×!Ò!¨TÐ!Ñ2Ô2Ð2ÝÐ3Ñ4Ô4Ð4øøÝð +ð +ð +ÝÐ) aÐ)Ð)Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*øøøøð+øøøð ÐØ(0�BŒJ�}Ñ%Ð%Ð%Ø�bœjÐ(Ð(Ý”
˜=Ð)Ð)Ð)ð )Ð(øð ÐØ(0�BŒJ�}Ñ%Ð%Ø�bœjÐ(Ð(Ý”
˜=Ð)Ð)Ð)Ð)Ð)s0   ¥E;F! Æ G< Æ!
GÆ+GÆ=G< ÇGÇG< Ç</H+c                 óü  — ddl }| dz  }|                     ¦   «         sdS 	 |                     d¬¦  «                             ¦   «         }|                     d¦  «        rt          j        |¦  «        ndt          |¦  «        i}t          |d         ¦  «        }ddlm	} dd	lm
}  ||¦  «         t          d
¦  «        D ]8}|                     d¦  «          ||¦  «        st          d|› d�¦  «          dS Œ9	  ||d¬¦  «         n# t          t          f$ r Y nw xY wt          d|› d�¦  «         dS # t          t           f$ r t          d¦  «         Y dS t"          $ r}	t          d|	› �¦  «         Y d}	~	dS d}	~	ww xY w)z0Stop a running gateway process via its PID file.r   Nr   r§   r°   ú{r­  )rÜ  )rÛ  é   rÞ  u   âœ“ Gateway stopped (PID r²   Trß  u   âœ“ Gateway force-stopped (PID u   âœ“ Gateway already stoppedu   âš  Could not stop gateway: )rJ  r-   r»   r�   rÆ  r¡  r¢  r'  r;  rÜ  rÛ  rë  rã  r×   rá  r.   râ  r¼   )
r)   Ú_timeÚpid_fileÚrawr.  r­  rä  rÛ  Ú_râ   s
             r0   r  r  Ý  s  € àÐÐÐà˜]Ñ*€HØ�?Š?ÑÔð Øˆð2Ø× Ò ¨'Ð Ñ2Ô2×8Ò8Ñ:Ô:ˆØ"%§.¢.°Ñ"5Ô"5ÐL�tŒz˜#‰Œˆ¸EÅ3ÀsÁ8Ä8Ð;LˆÝ�$�u”+ÑÔˆð 	CÐBÐBÐBÐBÐBØ.Ð.Ð.Ð.Ð.Ð.Øˆ�sÑÔÐõ �r‘”ð 	ð 	ˆAØ�KŠK˜ÑÔÐØ�;˜sÑ#Ô#ð ÝÐ8°#Ð8Ð8Ð8Ñ9Ô9Ð9Ø��ðð	ØˆN˜3 dÐ+Ñ+Ô+Ð+Ð+øÝ"¥GÐ,ð 	ð 	ð 	ØˆDð	øøøåÐ6°Ð6Ð6Ð6Ñ7Ô7Ð7Ð7Ð7øÝ¥Ð0ð -ð -ð -ÝÐ+Ñ,Ô,Ð,Ð,Ð,Ð,Ýð 2ð 2ð 2ÝÐ0¨QÐ0Ð0Ñ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1Ð1øøøøð2øøøsH   ¡CD2 Ã6D2 Ã8D ÄD2 ÄDÄD2 ÄDÄD2 Ä2 E;Å	E;ÅE6Å6E;c                  ó¸   — t          ¦   «         } 	 |                      d¬¦  «                             ¦   «         }|sdS |S # t          t          t
          f$ r Y dS w xY w)ztRead the sticky active profile name.

    Returns ``"default"`` if no active_profile file exists or it's empty.
    r§   r°   rh   )r‡   r»   r�   r½   r  r.   )r  rŠ   s     r0   r  r    so   € õ
 $Ñ%Ô%€DðØ�~Š~ wˆ~Ñ/Ô/×5Ò5Ñ7Ô7ˆØð 	Ø�9ØˆøÝÕ1µ7Ð;ð ð ð Øˆyˆyðøøøs   �*> ¼> ¾AÁAc                 ó®  — t          | ¦  «        }t          |¦  «         |dk    r$t          |¦  «        st          d|› d|› �¦  «        ‚t	          ¦   «         }|j                             dd¬¦  «         |dk    r|                     d¬¦  «         dS |                     d¦  «        }| 	                    |dz   d	¬
¦  «         | 
                    |¦  «         dS )zlSet the sticky active profile.

    Writes to ``~/.hermes/active_profile``. Use ``"default"`` to clear.
    rh   ru  ú8' does not exist. Create it with: hermes profile create TrÒ   r|  r9   ú
r§   r°   N)r‘   r˜   r¡   r½   r‡   rˆ  rÖ   rè   Úwith_suffixrØ   r¨   )rŠ   r�   r  rc   s       r0   r  r    sû   € õ
 # 4Ñ(Ô(€EÝ˜%Ñ Ô Ð Ø�	ÒÐ¥.°Ñ"7Ô"7ÐÝð=˜ð =ð =Ø5:ð=ð =ñ
ô 
ð 	
õ
 $Ñ%Ô%€DØ„K×Ò˜d¨TÐÑ2Ô2Ð2Ø�	ÒÐà�Š˜tˆÑ$Ô$Ð$Ð$Ð$ð ×Ò˜vÑ&Ô&ˆØ�Š�u˜t‘|¨gˆÑ6Ô6Ð6Ø�Š�DÑÔÐÐÐrG   c                  ó°  — ddl m}   | ¦   «         }|                     ¦   «         }t          ¦   «                              ¦   «         }||k    rdS t	          ¦   «                              ¦   «         }	 |                     |¦  «        }|j        }t          |¦  «        dk    r(t           	                    |d         ¦  «        r|d         S n# t          $ r Y nw xY wdS )a%  Infer the current profile name from HERMES_HOME.

    Returns ``"default"`` if HERMES_HOME is not set or points to ``~/.hermes``.
    Returns the profile name if HERMES_HOME points into ``~/.hermes/profiles/<name>``.
    Returns ``"custom"`` if HERMES_HOME is set to an unrecognized path.
    r   rw  rh   r   Úcustom)r…   rx  r<   rD   r�   Úrelative_toÚpartsr
  r”   r•   r=   )rx  Úhermes_homeÚresolvedÚdefault_resolvedrf  ÚrelrB  s          r0   rk  rk  0  sé   € ð 1Ð0Ð0Ð0Ð0Ð0Ø!�/Ñ#Ô#€KØ×"Ò"Ñ$Ô$€Hå/Ñ1Ô1×9Ò9Ñ;Ô;ÐØÐ#Ò#Ð#Øˆyå&Ñ(Ô(×0Ò0Ñ2Ô2€MðØ×"Ò" =Ñ1Ô1ˆØ”	ˆÝˆu‰:Œ:˜Š?ˆ?�~×3Ò3°E¸!´HÑ=Ô=ˆ?Ø˜”8ˆOøøÝð ð ð Øˆðøøøð ˆ8s   Á.AC Ã
CÃCÚroot_dirc                 ó>   ‡ — dt           dt          dt          fˆ fd„}|S )uÁ  Return an *ignore* callable for :func:`shutil.copytree`.

    Two-tier filtering:

    * **Root-level allow-list** â€” only entries whose name appears in
      ``_DEFAULT_EXPORT_INCLUDE_ROOT`` survive. Everything else (such as
      an unrelated ``x11-dev/`` directory in a Docker deployment where
      HERMES_HOME equals the cwd) is excluded. Blacklisting was tried
      first and proved unable to anticipate every non-Hermes file the
      user may have lying alongside HERMES_HOME (#58394).
    * **Universal exclusions at any depth** â€” ``__pycache__``, sockets,
      temp files; plus npm lockfiles, which may appear at the root.

    All other profile artifacts are copied through untouched.
    r4   Úcontentsr*   c                 ó&  •— t          ¦   «         }|D ]L}|dk    s|                     d¦  «        r|                     |¦  «         Œ3|dv r|                     |¦  «         ŒMt          | ¦  «        ‰k    r|                     d„ |D ¦   «         ¦  «         |S )Nr7   )r8   r9   >   úpackage.jsonúpackage-lock.jsonc              3   ó,   K  — | ]}|t           v¯|V — Œd S r²  )Ú_DEFAULT_EXPORT_INCLUDE_ROOT)r³  r?   s     r0   r¶  z:_default_export_ignore.<locals>._ignore.<locals>.<genexpr>l  s6   è è € ð ð Ø¨uÕ<XÐ/XÐ/X�Ð/XÐ/XÐ/XÐ/Xðð rG   )Úsetr:   rÀ  r   rv   )r4   rI  r>   r?   rG  s       €r0   rC   z'_default_export_ignore.<locals>._ignore`  s¸   ø€ Ý‘u”uˆØð 	#ð 	#ˆEà˜Ò%Ð%¨¯ªÐ8IÑ)JÔ)JÐ%Ø—’˜EÑ"Ô"Ð"Ð"àÐ?Ð?Ð?Ø—’˜EÑ"Ô"Ð"øõ �	‰?Œ?˜hÒ&Ð&Ø�NŠNð ð Ø#+ðñ ô ñ ô ð ð ˆrG   )rE   ÚlistrO  )rG  rC   s   ` r0   Ú_default_export_ignorerQ  O  s=   ø€ ð"�3ð ­$ð µ3ð ð ð ð ð ð ð" €NrG   ÚbaseÚbase_dirc                 óê   — ddl }| › d�}|                     |d|j        ¬¦  «        5 }|                     t	          t          |¦  «        |z  ¦  «        |¬¦  «         ddd¦  «         n# 1 swxY w Y   |S )u½  Create ``<base>.tar.gz`` of ``root_dir/base_dir`` â€” GNU tar format.

    Not :func:`shutil.make_archive`: that writes PAX (Python's tarfile default
    since 3.8), whose fractional-mtime records macOS Archive Utility rejects â€”
    double-clicking an exported profile threw "Error 94 - Bad message." GNU
    format keeps long paths working (longlink extensions) and stays integer-
    mtime, so Finder, bsdtar, and gnutar all extract it.
    r   Nú.tar.gzzw:gz)Úformat)Úarcname)Útarfiler  Ú
GNU_FORMATrÀ  rE   r   )rR  rG  rS  rX  Úarchive_pathÚtfs         r0   Ú_make_profile_archiver\  t  sÇ   € ð €N€N€NàÐ#Ð#Ð#€LØ	�Š�l F°7Ô3EˆÑ	FÔ	Fð AÈ"Ø
�Š�s•4˜‘>”> HÑ,Ñ-Ô-°xˆÑ@Ô@Ð@ðAð Að Añ Aô Að Að Að Að Að Að Aøøøð Að Að Að AàÐs   §5A(Á(A,Á/A,Úoutput_pathÚextra_filesc           	      ó˜  ‡‡— ddl }t          | ¦  «        }t          |¦  «         t          |¦  «        }|                     ¦   «         st          d|› d�¦  «        ‚t          |¦  «        }t          |¦  «                             d¦  «                             d¦  «        }dt          ddfˆfd	„}|d
k    rŽ| 	                    ¦   «         5 }	t          |	¦  «        d
z  }
t          j        ||
dt          |¦  «        ¬¦  «          ||
¦  «         t          ||	d
¦  «        }t          |¦  «        cddd¦  «         S # 1 swxY w Y   | 	                    ¦   «         5 }	t          |	¦  «        |z  }
ddhŠt          j        ||
dˆfd„¬¦  «          ||
¦  «         t          ||	|¦  «        }t          |¦  «        cddd¦  «         S # 1 swxY w Y   dS )u0  Export a profile to a tar.gz archive.

    ``extra_files`` maps root-relative filenames (e.g. ``desktop.json``) to
    text content staged into the archive alongside the profile's own files â€”
    the desktop app uses it to bundle its appearance/interface overlay.
    Returns the output file path.
    r   Nru  rõ  rU  z.tgzÚstagedr*   c                 óØ   •— ‰pi                       ¦   «         D ]Q\  }}t          |¦  «        } | j        |Ž }|j                             dd¬¦  «         |                     |d¬¦  «         ŒRd S )NTrÒ   r§   r°   )r	  Ú _normalize_profile_archive_partsÚjoinpathrˆ  rÖ   rØ   )r`  rF  rÅ   rB  rÐ   r^  s        €r0   Ú_stage_extrasz%export_profile.<locals>._stage_extras™  sƒ   ø€ Ø(Ð.¨B×5Ò5Ñ7Ô7ð 	9ð 	9‰LˆC�Ý4°SÑ9Ô9ˆEØ$�V”_ eÐ,ˆFØŒM×Ò¨°tÐÑ<Ô<Ð<Ø×Ò˜g°ÐÑ8Ô8Ð8Ð8ð		9ð 	9rG   rh   Try  rV   r   c                 ó(   •— ‰t          |¦  «        z  S r²  )rO  )ÚdrI  Ú_CREDENTIAL_FILESs     €r0   ú<lambda>z export_profile.<locals>.<lambda>¸  s   ø€ Ð'8½3¸x¹=¼=Ñ'H€ rG   )Útempfiler‘   r˜   rž   r    r½   r   rE   ÚremovesuffixÚTemporaryDirectoryrÙ   rƒ  rQ  r\  )rŠ   r]  r^  ri  r�   r)   ÚoutputrR  rd  Útmpdirr`  rÂ   rg  s     `         @r0   Úexport_profilern  …  s‘  øø€ ð €O€O€Oå" 4Ñ(Ô(€EÝ˜%Ñ Ô Ð Ý! %Ñ(Ô(€KØ×ÒÑÔð FÝÐ D¨EÐ DÐ DÐ DÑEÔEÐEå�+ÑÔ€Fåˆv‰;Œ;×#Ò# IÑ.Ô.×;Ò;¸FÑCÔC€Dð9�dð 9 tð 9ð 9ð 9ð 9ð 9ð 9ð �	ÒÐð ×(Ò(Ñ*Ô*ð 
	 ¨fÝ˜&‘\”\ IÑ-ˆFÝŒOØØØÝ-¨kÑ:Ô:ð	ñ ô ð ð ˆM˜&Ñ!Ô!Ð!Ý*¨4°¸ÑCÔCˆFÝ˜‘<”<ð
	 ð 
	 ð 
	 ð 
	 ñ 
	 ô 
	 ð 
	 ð 
	 ð 
	 ð 
	 ð 
	 ð 
	 øøøð 
	 ð 
	 ð 
	 ð 
	 ð 
×	$Ò	$Ñ	&Ô	&ð ¨&Ý�f‘” Ñ%ˆØ(¨&Ð1ÐÝŒØØØØHÐHÐHÐHð		
ñ 	
ô 	
ð 	
ð 	ˆ�fÑÔÐÝ& t¨V°UÑ;Ô;ˆÝ�F‰|Œ|ðð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s&   ÃA"D7Ä7D;Ä>D;ÅAF?Æ?GÇGÚmember_namec                 óp  — |                       dd¦  «        }t          |¦  «        }t          | ¦  «        }|r/|                     ¦   «         s|                     ¦   «         s|j        rt          d| › �¦  «        ‚d„ |j        D ¦   «         }|rt          d„ |D ¦   «         ¦  «        rt          d| › �¦  «        ‚|S )z4Return safe path parts for a profile archive member.ú\ú/zUnsafe archive member path: c                 ó   — g | ]}|d v¯|‘Œ	S )>   rÉ   ú.r€   ©r³  Úparts     r0   ú
<listcomp>z4_normalize_profile_archive_parts.<locals>.<listcomp>Í  s"   € ÐHÐHÐH�d°$¸iÐ2GÐ2GˆTÐ2GÐ2GÐ2GrG   c              3   ó"   K  — | ]
}|d k    V — ŒdS )z..Nr€   ru  s     r0   r¶  z3_normalize_profile_archive_parts.<locals>.<genexpr>Î  s&   è è € Ð7Ð7¨˜ šÐ7Ð7Ð7Ð7Ð7Ð7rG   )r¨   r   r   Úis_absoluteÚdriver=   rB  rÅ  )ro  Únormalized_nameÚ
posix_pathÚwindows_pathrB  s        r0   rb  rb  ¿  sé   € à!×)Ò)¨$°Ñ4Ô4€OÝ˜Ñ/Ô/€JÝ" ;Ñ/Ô/€Lð ðGà×!Ò!Ñ#Ô#ðGð ×#Ò#Ñ%Ô%ðGð Ôð	Gõ ÐE¸ÐEÐEÑFÔFÐFàHÐH˜jÔ.ÐHÑHÔH€EØð G•CÐ7Ð7°Ð7Ñ7Ô7Ñ7Ô7ð GÝÐE¸ÐEÐEÑFÔFÐFØ€LrG   ÚarchiveÚdestinationc           	      ó*  — ddl }|                     | d¦  «        5 }|                     ¦   «         D �]H}t          |j        ¦  «        } |j        |Ž }|                     ¦   «         r|                     dd¬¦  «         ŒM|                     ¦   «         st          d|j        › �¦  «        ‚|j
                             dd¬¦  «         |                     |¦  «        }|€t          d|j        › �¦  «        ‚|5  t          |d¦  «        5 }t          j        ||¦  «         ddd¦  «         n# 1 swxY w Y   ddd¦  «         n# 1 swxY w Y   	 t          j        ||j        d	z  ¦  «         �Œ9# t"          $ r Y �ŒFw xY w	 ddd¦  «         dS # 1 swxY w Y   dS )
zAExtract a profile archive without allowing path escapes or links.r   Núr:gzTrÒ   z!Unsupported archive member type: zCannot read archive member: Úwbiÿ  )rX  r  Ú
getmembersrb  rŠ   rc  ÚisdirrÖ   Úisfiler=   rˆ  ÚextractfilerÙ   ÚcopyfileobjrÊ   rÜ   Úmoder.   )	r~  r  rX  r[  ÚmemberrB  rÐ   Ú	extractedr�  s	            r0   Ú_safe_extract_profile_archiver‹  Ó  so  € à€N€N€Nà	�Š�g˜vÑ	&Ô	&ð ¨"Ø—m’m‘o”oð 	ñ 	ˆFÝ4°V´[ÑAÔAˆEØ)�[Ô)¨5Ð1ˆFà�|Š|‰~Œ~ð Ø—’ T°D�Ñ9Ô9Ð9Øà—=’=‘?”?ð Ý ØE¸¼ÐEÐEñô ð ð ŒM×Ò¨°tÐÑ<Ô<Ð<ØŸš vÑ.Ô.ˆIØÐ Ý Ð!MÀÄÐ!MÐ!MÑNÔNÐNàð 3ð 3�D ¨Ñ.Ô.ð 3°#ÝÔ" 9¨cÑ2Ô2Ð2ð3ð 3ð 3ñ 3ô 3ð 3ð 3ð 3ð 3ð 3ð 3øøøð 3ð 3ð 3ð 3ð 3ð 3ð 3ñ 3ô 3ð 3ð 3ð 3ð 3ð 3ð 3øøøð 3ð 3ð 3ð 3ðÝ”˜ ¤¨uÑ!4Ñ5Ô5Ð5Ñ5øÝð ð ð Ø‘ðøøøð/	ðð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð s~   ›CFÃ4D>ÄD'	ÄD>Ä'D+Ä+D>Ä.D+Ä/D>Ä2FÄ>EÅFÅEÅFÅ
E)Å'FÅ)
E7Å3FÅ6E7Å7FÆFÆFc                 óæ   — ddl }|                     | d¦  «        5 }d„ |                     ¦   «         D ¦   «         }|sd„ |                     ¦   «         D ¦   «         }ddd¦  «         n# 1 swxY w Y   |S )a  Return the archive's top-level directory names.

    Profile imports expect exactly one root directory. Inspecting the archive
    before extraction lets us stage the import safely instead of mutating a
    live profile tree first and reconciling names later.
    r   Nr�  c                 ó”   — h | ]E}t          |j        ¦  «        }t          |¦  «        d k    s|                     ¦   «         ¯=|d         ’ŒFS )r   r   )rb  rŠ   r
  r„  )r³  r‰  rB  s      r0   r¹  z1_inspect_profile_archive_roots.<locals>.<setcomp>ý  sP   € ð 
ð 
ð 
àÝ:¸6¼;ÑGÔG�Ý�5‰zŒz˜AŠ~ˆ~ §¢¡¤ˆ~ð �!ŒHð ˆ~ˆ~rG   c                 ój   — h | ]0}|                      ¦   «         ¯t          |j        ¦  «        d          ’Œ1S )r   )r„  rb  rŠ   )r³  r‰  s     r0   r¹  z1_inspect_profile_archive_roots.<locals>.<setcomp>  sE   € ð ð ð àØ—<’<‘>”>ðÝ0°´Ñ=Ô=¸aÔ@ðð ð rG   )rX  r  rƒ  )r~  rX  r[  Útop_dirss       r0   Ú_inspect_profile_archive_rootsr�  ó  sÐ   € ð €N€N€Nà	�Š�g˜vÑ	&Ô	&ð ¨"ð
ð 
àŸ-š-™/œ/ð
ñ 
ô 
ˆð ð 	ðð à Ÿmšm™oœoðñ ô ˆHðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð €Os   ›?A&Á&A*Á-A*rZ  c                 óæ  — ddl }t          | ¦  «        }|                     ¦   «         st          d|› �¦  «        ‚t	          |¦  «        }t          |¦  «        dk    r|                     ¦   «         nd}|p|}|st          d¦  «        ‚|€t          d¦  «        ‚t          |¦  «        }t          |¦  «         |dk    rt          d¦  «        ‚t          |¦  «        }|                     ¦   «         rt          d	|› d
|› �¦  «        ‚t          ¦   «         }	|	                     dd¬¦  «         |                     d¬¦  «        5 }
t          |
¦  «        }t          ||¦  «         ||z  }|                     ¦   «         st          d|› �¦  «        ‚|}||k    r||z  }|                     |¦  «         t%          j        t)          |¦  «        t)          |¦  «        ¦  «         ddd¦  «         n# 1 swxY w Y   |S )z§Import a profile from a tar.gz archive.

    If *name* is not given, infers it from the archive's top-level directory.
    Returns the imported profile directory.
    r   NzArchive not found: r   zpCannot determine profile name from archive. Specify it explicitly: hermes profile import <archive> --name <name>z=Profile archive must contain exactly one top-level directory.rh   u•   Cannot import as 'default' â€” that is the built-in root profile (~/.hermes). Specify a different name: hermes profile import <archive> --name <name>ru  rv  TrÒ   Úhermes_profile_import_)r  z,Profile archive root is missing or invalid: )ri  r   r-   r½   r�  r
  Úpopr=   r‘   r˜   rž   r‚  r�   rÖ   rk  r‹  r    ÚrenamerÙ   ÚmoverE   )rZ  rŠ   ri  r~  r�  Úarchive_rootÚinferred_namer�   r)   rf  rm  Ústaging_rootrŠ  Úfinal_sources                 r0   Úimport_profilerš    sz  € ð €O€O€Oå�<Ñ Ô €GØ�>Š>ÑÔð AÝÐ ?°gÐ ?Ð ?Ñ@Ô@Ð@å-¨gÑ6Ô6€HÝ%(¨¡]¤]°aÒ%7Ð%7�8—<’<‘>”>�>¸T€LØÐ(˜L€MØð 
ÝðSñ
ô 
ð 	
ð ÐÝØKñ
ô 
ð 	
õ # =Ñ1Ô1€EÝ˜%Ñ Ô Ð Ø�	ÒÐÝðVñ
ô 
ð 	
õ
 " %Ñ(Ô(€KØ×ÒÑÔð TÝÐR¨%ÐRÐRÀ[ÐRÐRÑSÔSÐSå&Ñ(Ô(€MØ×Ò ¨tÐÑ4Ô4Ð4à	×	$Ò	$Ð,DÐ	$Ñ	EÔ	Eð 9ÈÝ˜F‘|”|ˆÝ% g¨|Ñ<Ô<Ð<à  <Ñ/ˆ	Ø×ÒÑ!Ô!ð 	ÝØM¸|ÐMÐMñô ð ð !ˆØ˜5Ò Ð Ø'¨%Ñ/ˆLØ×Ò˜\Ñ*Ô*Ð*åŒ•C˜Ñ%Ô%¥s¨;Ñ'7Ô'7Ñ8Ô8Ð8ð9ð 9ð 9ñ 9ô 9ð 9ð 9ð 9ð 9ð 9ð 9øøøð 9ð 9ð 9ð 9ð" Ðs   Ä>BG&Ç&G*Ç-G*Úold_nameÚnew_nameÚnew_dirc                 ó  — d| › �}d| › �}d|› �}|dz  t          ¦   «         dz  t          j        ¦   «         dz  dz  g}t          ¦   «         }|D �]4}	 |                     ¦   «         }	n# t
          $ r |}	Y nw xY w|	|v s|                     ¦   «         sŒD|                     |	¦  «         	 t          j	        | 
                    d¬¦  «        ¦  «        }
n# t
          t          j        f$ r Y Œ›w xY w|
                     d¦  «        }t          |t          ¦  «        sŒÊ||v r|n|}||vrŒ×||v rt          d	|› d
|› �¦  «         Œñ||         }t          |t          ¦  «        r]d|vrY|                     d¦  «        r|                     dd¦  «        d         }n"d|v r|                     dd¦  «        d         n|}||d<   |                     |¦  «        ||<   |                     |j        dz   ¦  «        }	 |                     t          j        |
dd¬¦  «        dz   d¬¦  «         |                     |¦  «         n9# t
          $ r, 	 |                     d¬¦  «         n# t
          $ r Y nw xY wY �Œw xY wt          d|› d|› �¦  «         �Œ6dS )zGRename Honcho host blocks for a renamed profile without changing peers.Úhermes_zhermes.zhoncho.jsonz.honchozconfig.jsonr§   r°   Úhostsu$   âš  Honcho host block not migrated: z already exists in ÚaiPeerr9  r   rt  r9   rI  F)ÚindentÚensure_asciir=  Tr|  u   âœ“ Honcho host updated: õ    â†’ N)rD   r   r   rO  r<   r.   r  rÀ  r¡  r¢  r»   ÚJSONDecodeErrorrÌ   rŒ   r,  r×   rÆ  rÍ   r“  r>  r  rØ   Údumpsr¨   rè   )r›  rœ  r�  Úold_hostÚlegacy_old_hostÚnew_hostré   Úseenr  rD  r8  r   Úsource_hostÚblockÚbarerc   s                   r0   Ú_migrate_honcho_profile_hostr®  O  s-  € à#˜Ð#Ð#€HØ* Ð*Ð*€OØ#˜Ð#Ð#€Hð 	�-ÑÝ Ñ"Ô" ]Ñ2ÝŒ	‰Œ�iÑ -Ñ/ð€Jõ ‘e”e€DØð ,Hñ ,Hˆð	Ø—|’|‘~”~ˆHˆHøÝð 	ð 	ð 	ØˆHˆHˆHð	øøøà�tÐÐ 4§<¢<¡>¤>ÐØØ�Š�ÑÔÐð	Ý”*˜TŸ^š^°W˜^Ñ=Ô=Ñ>Ô>ˆCˆCøÝ�Ô-Ð.ð 	ð 	ð 	ØˆHð	øøøð —’˜Ñ Ô ˆÝ˜%¥Ñ&Ô&ð 	ØØ"*¨eÐ"3Ð"3�h�h¸ˆØ˜eÐ#Ð#Øà�uÐÐÝÐ\¸Ð\Ð\ÐVZÐ\Ð\Ñ]Ô]Ð]Øà�kÔ"ˆÝ�e�TÑ"Ô"ð 	# x°uÐ'<Ð'<Ø×%Ò% iÑ0Ô0ð [Ø"×(Ò(¨¨aÑ0Ô0°Ô3��à7:¸kÐ7IÐ7I�{×(Ò(¨¨aÑ0Ô0°Ô3Ð3È{�Ø"ˆE�(‰OØŸ)š) KÑ0Ô0ˆˆh‰Ø×Ò˜tœ{¨VÑ3Ñ4Ô4ˆð	Ø�NŠN�4œ: c°!À%ÐHÑHÔHÈ4ÑOÐZaˆNÑbÔbÐbØ�KŠK˜ÑÔÐÐøÝð 	ð 	ð 	ðØ—
’
 d�
Ñ+Ô+Ð+Ð+øÝð ð ð Ø�ðøøøà‰Hð	øøøõ 	ÐF¨+ÐFÐF¸HÐFÐFÑGÔGÐGÑGðY,Hð ,Hs[   ÁA'Á'A6Á5A6Â((CÃC*Ã)C*Ç/AH4È4
I*È?IÉI*É
I#É I*É"I#É#I*É)I*c                 óÈ  — t          | ¦  «        }t          |¦  «        }t          |¦  «         t          |¦  «         |dk    rt          d¦  «        ‚|dk    rt          d¦  «        ‚t          |¦  «        }t          |¦  «        }|                     ¦   «         st          d|› d�¦  «        ‚|                     ¦   «         rt          d|› d�¦  «        ‚t          |¦  «        rt          ||¦  «         t          |¦  «         |                     |¦  «         t          d|j        › d|j        › �¦  «         t          |||¦  «         t          |¦  «         t!          |¦  «        }|s"t#          |¦  «         t          d	|› �¦  «         nt          d
|› d|› �¦  «         	 t%          ¦   «         |k    r!t'          |¦  «         t          d|› �¦  «         n# t(          $ r Y nw xY w|S )zrRename a profile: directory, wrapper script, service, active_profile.

    Returns the new profile directory.
    rh   z"Cannot rename the default profile.u.   Cannot rename to 'default' â€” it is reserved.ru  rõ  z' already exists.u   âœ“ Renamed r¤  u   âœ“ Alias updated: u   âš  Cannot create alias 'u   ' â€” u   âœ“ Active profile updated: )r‘   r˜   r=   rž   r    r½   r-   r‚  r=  r  r  r”  r×   rŠ   r®  rê   rÆ   rå   r  r  r¼   )r›  rœ  Ú	old_canonÚ	new_canonÚold_dirr�  Ú	collisions          r0   Úrename_profiler´  ‹  s-  € õ
 ' xÑ0Ô0€IÝ& xÑ0Ô0€IÝ˜)Ñ$Ô$Ð$Ý˜)Ñ$Ô$Ð$à�IÒÐÝÐ=Ñ>Ô>Ð>Ø�IÒÐÝÐIÑJÔJÐJå˜iÑ(Ô(€GÝ˜iÑ(Ô(€Gà�>Š>ÑÔð JÝÐ H¨IÐ HÐ HÐ HÑIÔIÐIØ‡~‚~ÑÔð HÝÐF¨)ÐFÐFÐFÑGÔGÐGõ ˜gÑ&Ô&ð 'Ý  ¨GÑ4Ô4Ð4Ý˜gÑ&Ô&Ð&ð ‡N‚N�7ÑÔÐÝ	Ð
:˜œÐ
:Ð
:¨G¬LÐ
:Ð
:Ñ;Ô;Ð;õ ! ¨I°wÑ?Ô?Ð?õ ˜)Ñ$Ô$Ð$Ý% iÑ0Ô0€IØð HÝ˜iÑ(Ô(Ð(ÝÐ/ IÐ/Ð/Ñ0Ô0Ð0Ð0åÐF¨)ÐFÐF¸9ÐFÐFÑGÔGÐGðÝÑÔ 9Ò,Ð,Ý˜yÑ)Ô)Ð)ÝÐ<°Ð<Ð<Ñ=Ô=Ð=øøÝð ð ð Øˆðøøøð €Ns   Æ3G Ç
GÇGc                 óØ   — t          | ¦  «        }t          |¦  «         t          |¦  «        }|dk    r)|                     ¦   «         st	          d|› d|› �¦  «        ‚t          |¦  «        S )z¼Resolve a profile name to a HERMES_HOME path string.

    Called early in the CLI entry point, before any hermes modules
    are imported, to set the HERMES_HOME environment variable.
    rh   ru  r<  )r‘   r˜   rž   r    r½   rE   )rø   r�   r)   s      r0   Úresolve_profile_envr¶  Æ  sˆ   € õ # <Ñ0Ô0€EÝ˜%Ñ Ô Ð Ý! %Ñ(Ô(€Kà�	ÒÐ +×"4Ò"4Ñ"6Ô"6ÐÝð=˜ð =ð =Ø5:ð=ð =ñ
ô 
ð 	
õ
 ˆ{ÑÔÐrG   r²  )NFFFFN)F)fr$  r¡  rÊ   ÚrerÚ   rÙ   rÝ   r¶   r´   rJ  Údataclassesr   Úpathlibr   r   r   Útypingr   r   r	   r
   Úagent.skill_utilsr   Úcompiler”   r„  r…  r‡  r   rP  rE   r%  Ú	frozensetr!   r(   r,   r&  r1   rF   Ú_DEFAULT_EXPORT_EXCLUDE_ROOTrN  r–   r³   r�   rD   r‡   r‰   r‘   r˜   rš   rž   r¡   rÆ   rÏ   rå   rê   r÷   rû   r  r,  rú   r  rù  r/  r4  r=  r>  Úfloatr'  rK  rG  rS  rU  rX  r_  rh  rn  r”  r¥  r©  rÙ  ræ  rò  r  rŠ  r  r  r  r  r  rk  rQ  r\  rn  rb  r‹  rO  r�  rš  r®  r´  r¶  r€   rG   r0   ú<module>rÀ     s  ððð ð ð* €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø 
€
€
€
Ø €€€Ø !Ð !Ð !Ð !Ð !Ð !Ø 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ø .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .Ð .à 4Ð 4Ð 4Ð 4Ð 4Ð 4à�”Ð9Ñ:Ô:€ðð ð €ð"ð ð Ð ð ØðÐ ðð ð Ð �$�s”)ð ð ñ ð, 3<°)ð =ð =ð =ñ 3ô 3Ð  ¨3¤ð ð ñ ð, 3<°)ð =ð =ð =ñ 3ô 3Ð  ¨3¤ð ð ñ ð  0Ð ð¨Dð °Tð ð ð ð ð3¨4ð 3ð 3ð 3ð 3ðt  )˜yð *ð *ð *ñ  ô  Ð ðB  )˜yð *ð *ð *ñ  ô  Ð ð �)ð ð ð ñ ô €ð
  �ið !ð !ð !ñ ô Ð ð3˜Dð 3ð 3ð 3ð 3ð% $ð %ð %ð %ð %ð9 $ð 9ð 9ð 9ð 9ð
*˜$ð *ð *ð *ð *ð ð ¨ð ð ð ð ð$
 ð 
¨ð 
ð 
ð 
ð 
ð<
˜cð 
 dð 
ð 
ð 
ð 
ð (˜#ð ( $ð (ð (ð (ð (ð+˜ð + ð +ð +ð +ð +ð' ð '¨°¬ð 'ð 'ð 'ð 'ðTG ð Gð Gð Gð Gð(ð ( ð (¨X°c¬]ð (ÀhÈtÄnð (ð (ð (ð (ðV ð ¨ð ð ð ð ð<°Tð ¸dð ð ð ð ð>G¨ð G°¸#´ð Gð Gð Gð Gð6 Ð ð.˜˜c 3˜hœð .ð .ð .ð .ðj ð#ð #ð #ð #ð #ñ #ô #ñ „ð#ð@ ¨ð  °%ð  ð  ð  ð  ð2 Dð ¨Uð ð ð ð ð(¨ð °ð ð ð ð ðR ;=Ð �D˜˜e E¨5°#Ð$5Ô6Ð6Ô7Ð <Ð <Ñ <ØÐ ð dð ¨uð ð ð ð ð6˜tð ¨ð ð ð ð ðP( Dð (¨Tð (ð (ð (ð (ð 4ð ¨Dð ð ð ð ð8 "&Ø'+ð	"7ð "7ð "7Øð"7ð ˜#”ð"7ð ˜t”nð	"7ð
 
ð"7ð "7ð "7ð "7ðRE�t˜KÔ(ð Eð Eð Eð EðP& ð &¨$¨u°S¸$°YÔ/?Ô*@ð &ð &ð &ð &ðV !%ØØØØØ!%ð~ð ~Ø
ð~à˜”ð~ð ð~ð ð	~ð
 ð~ð ð~ð ˜#”ð~ð 
ð~ð ~ð ~ð ~ðB*ð * Tð *°$ð *À8ÈDÄ>ð *ð *ð *ð *ðZ1ð 1 ð 1°$°s´)ð 1ð 1ð 1ð 1ðhm sð m¸ð mÀ$ÀsÄ)ð mð mð mð mð`&B #ð &B°Dð &B¸Tð &Bð &Bð &Bð &BðR Dð ¸Dð ð ð ð ð<Tð T˜ð T 4ð T°Dð Tð Tð Tð Tðn9C°#ð 9C¸$ð 9Cð 9Cð 9Cð 9CðxE°Cð E¸Dð Eð Eð Eð Eð6-* 3ð -*°Tð -*¸dð -*ð -*ð -*ð -*ð`$2 tð $2°ð $2ð $2ð $2ð $2ðV˜Cð ð ð ð ð˜Sð  Tð ð ð ð ð2 ð ð ð ð ð>" Tð "ð "ð "ð "ðJ ð ¨sð ¸cð Àcð ð ð ð ð"7ð 7˜ð 7¨3ð 7¸XÀdÈ3ÐPSÈ8ÄnÔ=Uð 7Ðaeð 7ð 7ð 7ð 7ðt°#ð ¸$¸s¼)ð ð ð ð ð(¨4ð ¸dð Àtð ð ð ð ð@¨Dð °S¸´Xð ð ð ð ð2<ð < ð <¨H°S¬Mð <ÀTð <ð <ð <ð <ðF9H¨3ð 9H¸#ð 9HÈð 9HÐQUð 9Hð 9Hð 9Hð 9Hðx4˜Sð 4¨Cð 4°Dð 4ð 4ð 4ð 4ðv cð ¨cð ð ð ð ð ð rG   