
    Tdj)                        d Z ddlmZ ddlZddlZej        dk    ZdaddZdd
Z	dddZ
ddZ e              e	              e             dS )u  Windows UTF-8 bootstrap for Hermes entry points.

Python on Windows has two long-standing text-encoding footguns:

1. ``sys.stdout`` / ``sys.stderr`` are bound to the console code page
   (``cp1252`` on US-locale installs), so ``print("café")`` crashes with
   ``UnicodeEncodeError: 'charmap' codec can't encode character``.

2. Child processes spawned via ``subprocess`` don't know to use UTF-8
   unless ``PYTHONUTF8`` and/or ``PYTHONIOENCODING`` are set in their
   environment — so any Python subprocess (the execute_code sandbox,
   delegation children, linter subprocesses, etc.) inherits the same
   cp1252 defaults and hits the same UnicodeEncodeError.

This module fixes both on Windows *only* — POSIX is untouched.  It
should be imported at the very top of every Hermes entry point
(``hermes``, ``hermes-agent``, ``hermes-acp``, ``python -m gateway.run``,
``batch_runner.py``, ``cron/scheduler.py``) before any other imports
that might do file I/O or print to stdout.

What this module does on Windows:

  - Sets ``os.environ["PYTHONUTF8"] = "1"`` (PEP 540 UTF-8 mode) so
    every child process we spawn uses UTF-8 for ``open()`` and stdio.
  - Sets ``os.environ["PYTHONIOENCODING"] = "utf-8"`` for belt-and-
    suspenders — some tools read this instead of / in addition to
    ``PYTHONUTF8``.
  - Reconfigures ``sys.stdout`` / ``sys.stderr`` to UTF-8 in the current
    process, using the ``reconfigure()`` API (Python 3.7+).  This fixes
    ``print("café")`` in the parent without a re-exec.

What this module does NOT do:

  - It does not re-exec Python with ``-X utf8``, so ``open()`` calls in
    the *current* process still default to locale encoding.  Those need
    an explicit ``encoding="utf-8"`` at the call site (lint rule
    ``PLW1514`` / ``PYI058``).  Ruff is the right tool for that sweep.

What this module does on POSIX:

  - Nothing.  POSIX systems are already UTF-8 by default in 99% of cases,
    and we don't want to touch ``LANG``/``LC_*`` behavior that users may
    have configured intentionally.  If someone hits a C/POSIX locale on
    Linux, they can export ``PYTHONUTF8=1`` themselves — we won't override.

Idempotent: safe to call multiple times.  ``_bootstrap_once`` guards
against double-reconfigure.
    )annotationsNwin32Freturnboolc                    t           sdS t          rdS t          j                            dd           t          j                            dd           dD ]T} t          t          | d          }|t          |dd          }|/	  |dd	
           ># t          t          f$ r Y Qw xY wt          t          dd          }|9t          |dd          }|&	  |dd	
           n# t          t          f$ r Y nw xY wdadS )ul  Apply the Windows UTF-8 bootstrap if we're on Windows.

    Returns True if bootstrap was applied (i.e. we're on Windows and
    haven't already done this), False otherwise.  The return value is
    advisory — callers normally don't need it, but tests may want to
    assert the path was taken.

    Idempotent: subsequent calls after the first are a no-op.
    F
PYTHONUTF81PYTHONIOENCODINGzutf-8)stdoutstderrNreconfigurereplace)encodingerrorsstdinT)	_IS_WINDOWS_bootstrap_appliedosenviron
setdefaultgetattrsysOSError
ValueError)stream_namestreamr   r   s       6/home/thesage/.hermes/hermes-agent/hermes_bootstrap.pyapply_windows_utf8_bootstrapr   ;   sZ     u u J,,,,J,g666 ,  k400>fmT::
 	K;;;;;$ 	 	 	 D	 C$''Ee]D99"WY?????Z(    4s$   BB'&B'C$ $C87C8Nonec                     t           sdS 	 ddl} t          | d          r	 	 dd}|| _        dS dS # t          $ r Y dS w xY w)u  Stub ``platform._syscmd_ver`` on Windows — decode-crash + flash guard.

    CPython's ``platform.win32_ver()`` (reached via ``platform.uname()`` /
    ``platform.platform()``, which the OpenAI SDK touches for its
    platform headers) shells out ``cmd /c ver``. Two failure modes:

    - **Console flash**: the ``check_output(..., shell=True)`` call has no
      ``CREATE_NO_WINDOW``, so a windowless parent (pythonw gateway, slash
      workers, kanban workers) flashes a visible console per call.
    - **UnicodeDecodeError on Python 3.11.0/3.11.1**: those micros lack
      CPython's ``encoding="locale"`` fix (added 3.11.2), so under PEP 540
      UTF-8 mode (which we enable above) the ``ver`` output — OEM code page
      bytes on localized Windows — is strict-utf-8 decoded and raises,
      crashing ``platform.platform()`` in any process that inherits
      ``PYTHONUTF8=1`` (issue #69413).

    Stubbing ``_syscmd_ver`` to return its inputs makes ``win32_ver()`` hit
    its documented fallback and read the version from
    ``sys.getwindowsversion()`` — same data, in-process, no subprocess.
    Mirrors ``hermes_cli._subprocess_compat.suppress_platform_ver_console``
    (kept there for callers that don't import bootstrap); double
    application is harmless. Lives here so EVERY entry point gets it —
    ``tui_gateway/slash_worker.py``, ``tui_gateway/entry.py``,
    ``run_agent.py``, ``batch_runner.py``, and ``cli.py`` import only
    ``hermes_bootstrap``, never ``hermes_cli.main``.
    Nr   _syscmd_ver r   win16dosc                    | ||fS N )systemreleaseversionsupported_platformss       r   _quiet_syscmd_verz8suppress_platform_ver_console.<locals>._quiet_syscmd_ver   s    w//    )r"   r"   r"   r#   )r   platformhasattrr!   	Exception)r/   r-   s     r   suppress_platform_ver_consoler2   }   s    6  8]++ 	5AC6O0 0 0 0 $5H   	5 	5    s   !0 
>>src_root
str | Nonec                   | p_t           j                            d          p@t           j                            t           j                            t                              }d t          j        D             t          j        dd<   t           j                            |          fdt          j        D             t          j        dd<   t          j                            d|           dS )u  Stop a package in the current directory from shadowing Hermes modules.

    Hermes ships top-level modules with common names (``utils``, ``proxy``,
    ``ui``).  Python always seeds ``sys.path`` with the current directory, so
    launching an entry point from a project that has its own ``utils/`` package
    makes ``from utils import ...`` resolve to the *user's* package and crash
    with an ImportError before the gateway can even start.

    The current directory reaches ``sys.path`` two ways, and a complete guard
    has to handle both:

      - As the empty string ``""`` (or ``"."``) that Python inserts at
        ``sys.path[0]`` for ``-m`` / script launches.
      - As its own *absolute* path, when a venv activation or a project that
        adds itself to ``PYTHONPATH`` puts the directory there explicitly.

    We drop the relative forms outright, then force the real Hermes source root
    to the front — relocating it ahead of any absolute cwd entry rather than
    only inserting when absent, so an absolute cwd path can't keep winning.

    ``src_root`` defaults to the directory this module lives in, which is the
    repository root for every shipped entry point, so the guard is
    self-sufficient and does not depend on the spawner exporting an env var.
    HERMES_PYTHON_SRC_ROOTc                    g | ]}|d v|	S ))r"   .r(   ).0ps     r   
<listcomp>z&harden_import_path.<locals>.<listcomp>   s"    ===!9*<*<1*<*<*<r.   Nc                Z    g | ]'}t           j                            |          k    %|(S r(   )r   pathabspath)r9   r:   root_abss     r   r;   z&harden_import_path.<locals>.<listcomp>   s1    III"'//!*<*<*H*H1*H*H*Hr.   r   )	r   r   getr=   dirnamer>   __file__r   insert)r3   rootr?   s     @r   harden_import_pathrE      s    2  rz~~&>?? 27??
!!D DD >=ch===CHQQQKwt$$HIIIIchIIICHQQQKHOOAtr.   c                     t           j                            dd                                          sdS 	 ddlm}  |                                  dS # t          $ r Y dS w xY w)u  Put the durable lazy-install dir on ``sys.path`` if one is configured.

    On immutable Docker images the agent venv is sealed and lazy installs
    are redirected to a writable dir on the data volume
    (``HERMES_LAZY_INSTALL_TARGET``, e.g. ``/opt/data/lazy-packages``).
    Packages installed there on a previous run must be importable on this
    run, so we activate the dir here — at the very first import, before any
    backend module imports its SDK.

    The activation appends to the END of ``sys.path`` so the core venv
    always wins name collisions (see ``tools.lazy_deps`` for the full
    security rationale). Never raises; a missing/empty target is a no-op.
    HERMES_LAZY_INSTALL_TARGETr"   Nr   	lazy_deps)r   r   r@   striptoolsrI   activate_durable_lazy_targetr1   rH   s    r   rL   rL      s     :>>6;;AACC ######..00000    	s   A 
A A )r   r   )r   r   r'   )r3   r4   r   r   )__doc__
__future__r   r   r   r/   r   r   r   r2   rE   rL   r(   r.   r   <module>rO      s   / /b # " " " " " 				 



lg% ? ? ? ?D( ( ( (V! ! ! ! !H   :          
       r.   