+
    „WÝjœ°  ã                  óp  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	H
t
 ^ RIHtHtHt . RgOtRht]! 0 Rim4      t0 RjmtR R ltR R lt]P,                  R	8H  tR
tR R ltR R ltR R ltRtRtRtR R ltR R lt R R lt!R R lt"R R lt#R R lt$R R!/t%Rkt&R"R#R$R#R%R&R'R&R(]PN                  R)R*R+R,R-R,R.R#R/R0/
t(R1 R2 lt)/ t*R3]+R4&   R5 R6 lt,RlR7 R8 llt-R9 R: lt.RlR; R< llt/]P`                  ! R=]Pb                  4      t2]P`                  ! R>]Pb                  4      t3]P`                  ! R?]Pb                  4      t4R@t5^t6RAt7RBt8RlRC RD llt9RE RF lt:RG RH lt;RI RJ lt<RK RL lt=RM RN lt>RO RP lt?RQR/RR RS llt@RT RU ltARV RW ltBRXRYRZRR[RR\R]R^R/R_ R` lltCRa Rb ltDRc Rd ltERZR/Re Rf lltFR# )muŸ  Windows subprocess compatibility helpers.

* ``["npm", ...]`` â€” on Windows ``npm`` is ``npm.cmd``, a batch shim; ``Popen`` fails with
  WinError 193 because CreateProcessW can't run a ``.cmd`` without ``shell=True``/PATHEXT.
* ``start_new_session=True`` â€” POSIX ``os.setsid()`` detach; silently ignored on Windows, whose
  equivalent is the ``CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW`` creationflags bundle.
)ÚannotationsN)ÚPath)ÚMappingÚNoReturnÚSequencec               ó   € V ^8„  d   QhRR/# )é   Úreturnr   © )Úformats   "ÚQC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_cli\_subprocess_compat.pyÚ__annotate__r   <   s   € ÷ ñ ˜(ñ ó    c                ó    € ^ RI Hp V! 4        R# )é    )Ústop_for_relaunchN)Úhermes_cli._old_updaterr   )ÚcmdÚkwargsr   s   &, r   Úrunr   <   s   € å9áÖr   c               ó    € V ^8„  d   QhRRRR/# )r   ÚargsúSequence[str]r	   ú	list[str]r
   )r   s   "r   r   r   C   s   € ÷ ñ ˜-ð ¨Iñ r   c                ó:  € \        V 4      p^ pV\        V4      8  d~   W,          pV\        9   d   V^,          pK.  VP                  R4      '       d   V^,          pKP  V\        9   d1   VRV^,            \        \
        4      ,           W^,           R ,           # V# V# )az  Copy of subcommand-first git *args* (no leading ``"git"``) with :data:`NO_DRIVER_DIFF_FLAGS`
inserted right after a diff-rendering subcommand; other subcommands are returned unchanged.

Pair with :func:`noninteractive_git_env`: the env layer disables fsmonitor/hooks/pager/editor/
credential sinks, this closes the one class (attacker-named attribute drivers) env cannot reach.
Ú-N)ÚlistÚlenÚ_GIT_VALUE_OPTSÚ
startswithÚ_DIFF_RENDERING_SUBCOMMANDSÚNO_DRIVER_DIFF_FLAGS)r   ÚoutÚiÚtoks   &   r   Úharden_git_argvr%   C   sŽ   € ô ˆt‹*€CØ	€AØ
Œc�#‹hŒ,Ø�fˆØ”/Ô!Ø��FˆAÙØ�>‰>˜#×ÒØ��FˆAÙØÔ-Ô-Ø�w˜˜Q��<¤$Ô';Ó"<Õ<¸sÀqÅ5À7¸|ÕKÐKØˆ
Ø€Jr   Úwin32Ú_HERMES_GATEWAY_BREAKAWAYc               ó    € V ^8„  d   QhRRRR/# )r   ÚlineÚstrr	   r   r
   )r   s   "r   r   r   `   s   € ÷ ñ ˜Sð  Yñ r   c                ó  € ^ RI p\        '       g   VP                  V 4      # . pVP                  V RR7       FL  p\        V4      ^8¼  d)   V^ ,          VR,          8X  d   V^ ,          R9   d   V^R pVP	                  V4       KN  	  V# )uŽ  Split a user-supplied command line into tokens, Windows-safely.

``shlex.split`` (posix=True) treats every backslash as an escape, mangling Windows paths. On
Windows use ``posix=False`` and strip one layer of matching quotes per token; on POSIX this is
exactly ``shlex.split``. Raises ValueError on unbalanced quotes.

``shlex.split(line)`` (posix=True) treats every backslash as an escape character, so Windows paths are
silently mangled: ``C:\Users\me\out.txt`` becomes ``C:Usersmeout.txt`` â€” no error, just a wrong path
that then "succeeds" against a mangled relative filename (#83934) or makes a valid hook script report
"not executable" (#78293).
NF)Úposixéÿÿÿÿ)Ú'Ú")ÚshlexÚ
IS_WINDOWSÚsplitr   Úappend)r)   r0   r"   r$   s   &   r   Úsplit_command_liner4   `   sy   € ó ç‹:Ø�{‰{˜4Ó Ð Ø€CØ�{‰{˜4 uˆ{Ö-ˆÜˆs‹8�qŒ=˜S �V s¨2¥wÔ.°3°qµ6¸ZÔ3GØ�a˜�)ˆCØ�
‰
�3Žñ .ð €Jr   c               ó    € V ^8„  d   QhRRRR/# )r   ÚenvúMapping[str, str]r	   Údictr
   )r   s   "r   r   r   }   s   € ÷ ñ Ð$5ð ¸$ñ r   c                óä   € \        V 4      p\        P                  P                  R4      pV'       d>   VP                  RR4      pV'       d   V\        P                  ,           V,           MTVR&   V# )u‡  Re-add the ambient ``PYTHONPATH`` to a child environment that a
``build_subprocess_env``-style factory already built.

No-boot-through-venv: the boot interpreter is the pm STORE python, whose
imports arrive via ``PYTHONPATH=<repo>;<venv>/site-packages`` (it has no
editable install). The subprocess-env factories strip Hermes-owned
PYTHONPATH entries so agent-run children on DIFFERENT interpreter
versions never load the backend's C extensions â€” but a child that
re-execs THIS interpreter (``sys.executable -m hermes_cli.main``) runs
on the same version and needs those entries back. Prepending keeps the
launcher's repo-first ordering intact.
Ú
PYTHONPATHÚ )r8   ÚosÚenvironÚgetÚpathsep)r6   ÚmergedÚambientÚexistings   &   r   Úrestore_ambient_pythonpathrC   }   sX   € ô �#‹Y€FÜ�j‰j�n‰n˜\Ó*€GßØ—:‘:˜l¨BÓ/ˆç/7ˆG”b—j‘jÕ  8Ö+¸Wð 	ˆ|Ñð €Mr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Únamer*   Úargvr   r	   r   r
   )r   s   "r   r   r   ”   s!   € ÷ %ñ %˜sð %¨-ð %¸Iñ %r   c                óL   € \         P                  ! V 4      pT;'       g    T .VO# )u1  Resolve a Node-ecosystem command name (``npm``, ``npx``, ``yarn``â€¦) to an absolute-path argv.

On Windows these ship as ``.cmd`` batch shims that CreateProcessW won't execute by bare name;
``shutil.which`` resolves via PATHEXT to a fully-qualified path whose extension routes it
through ``cmd.exe /c``.
)ÚshutilÚwhich)rE   rF   Úresolveds   && r   Úresolve_node_commandrK   ”   s(   € ô �|Š|˜DÓ!€HØ×Ð˜Ð$˜tÐ$Ð$r   i   i   i   c               ó   € V ^8„  d   QhRR/# ©r   r	   Úintr
   )r   s   "r   r   r   ³   s   € ÷ Vñ V˜cñ Vr   c                 óV   € \         '       g   ^ # \        \        ,          \        ,          # )ul  Win32 creationflags detaching a child from the parent console/group; 0 elsewhere.

Pair with the default ``start_new_session=False`` (POSIX uses ``start_new_session=True``).
CREATE_NEW_PROCESS_GROUP stops Ctrl+C propagating; CREATE_NO_WINDOW gives the child a hidden
console descendants (git, gh, cmd, node, â€¦) inherit so they don't flash â€” deliberately replacing
the old DETACHED_PROCESS approach, which re-created the per-descendant console-flash bug
(#54220/#56747) at every spawn; CREATE_BREAKAWAY_FROM_JOB escapes Electron/Tauri job objects. A
job that forbids breakaway yields PermissionError from Popen â€” callers catch OSError and fall
back to :func:`windows_detach_flags_without_breakaway`.

Rationale: This both detaches it from the parent's console lifetime (closing the launching terminal
doesn't CTRL_CLOSE it) AND gives every console-subsystem descendant (git, gh, cmd, node, â€¦) a console to
inherit, so they don't allocate visible flashing ones. This deliberately replaces the old
``DETACHED_PROCESS`` approach: MSDN specifies CREATE_NO_WINDOW is *ignored* when combined with
DETACHED_PROCESS, and a truly console-less daemon re-creates the per-descendant console-flash bug
(#54220/#56747) at every spawn â€” see the note on ``_DETACHED_PROCESS`` above. Electron (Desktop app) and
Tauri (bootstrap installer) wrap their children in job objects; without breakaway, those children die
when the parent process exits even though they have their own console. This was the missing flag that
made the post-update gateway respawn watcher silently die alongside the Tauri updater after the Electron
Desktop's update flow finished.
)r1   Ú_CREATE_NEW_PROCESS_GROUPÚ_CREATE_NO_WINDOWÚ_CREATE_BREAKAWAY_FROM_JOBr
   r   r   Úwindows_detach_flagsrS   ³   s   € ÷, ‹:ÙÜ$Ô'8Õ8Ô;UÕUÐUr   c               ó   € V ^8„  d   QhRR/# rM   r
   )r   s   "r   r   r   Î   s   € ÷ 9ñ 9°ñ 9r   c                 ó@   € \         '       g   ^ # \        \        ,          # )zS:func:`windows_detach_flags` minus ``CREATE_BREAKAWAY_FROM_JOB``; 0 on non-Windows.)r1   rP   rQ   r
   r   r   Ú&windows_detach_flags_without_breakawayrV   Î   s   € ç‹:ÙÜ$Ô'8Õ8Ð8r   c               ó   € V ^8„  d   QhRR/# rM   r
   )r   s   "r   r   r   Õ   s   € ÷ 2ñ 2˜Cñ 2r   c                 ó*   € \         '       d   \        # ^ # )aH  Win32 creationflags hiding the child's console without detaching it; 0 elsewhere.

For short-lived synchronous helpers (``taskkill``, ``where``, version probes): no flash, but the
child stays in the parent's process group and job so Ctrl+C and job teardown still propagate.
Stdio is inherited, so ``capture_output=True`` works.
)r1   rQ   r
   r   r   Úwindows_hide_flagsrY   Õ   s   € ÷ !+£
ÔÐ1°Ð1r   c               ó   € V ^8„  d   QhRR/# ©r   r	   r8   r
   )r   s   "r   r   r   à   s   € ÷ \ñ \˜dñ \r   c                 ó„   € \        \        P                  4      p RV R&   RV R&   R\        P                  RV R\        4       /# )u�  ``subprocess.run`` kwargs for the updater's network git calls.

GitHub answers anonymous fetches with HTTP 401 during outages (and for
unreachable repos); git then prompts ``Username for 'https://github.com':``
on the inherited terminal and the update sits there forever. Disable the
prompt so the fetch fails fast into ``_classify_fetch_failure``. Only the
*prompt* is disabled â€” a configured credential helper / askpass still
runs, so a private-fork origin keeps authenticating non-interactively.
Lives here, dependency-free, because the update hand-off's bootstrap
interpreter runs the treeless conversion before any dependency exists.
Ú0ÚGIT_TERMINAL_PROMPTÚNeverÚGCM_INTERACTIVEÚstdinr6   Úcreationflags)r8   r<   r=   Ú
subprocessÚDEVNULLrY   )r6   s    r   Úno_prompt_git_kwargsre   à   sG   € ô Œr�z‰zÓ
€CØ!$€CÐÑØ$€CÐÑð ”Z×'Ñ'¨°°_ÔFXÓFZÐ[Ð[r   c               ó   € V ^8„  d   QhRR/# ©r   r	   ÚNoner
   )r   s   "r   r   r   ó   s   € ÷ ñ  tñ r   c                 óŽ   € \         '       g   R#  ^ RIp \        V R4      '       d   RR lpWn        R# R#   \         d     R# i ; i)uÅ  Stub ``platform._syscmd_ver`` on Windows so it never flashes a console. No-op elsewhere.

``platform.win32_ver()`` shells out ``cmd /c ver`` without CREATE_NO_WINDOW, so a windowless
parent (pythonw gateway, kanban workers) flashes a cmd window whenever a dependency touches
``platform.uname()`` at import. With the stub, ``win32_ver()`` takes its documented fallback to
``sys.getwindowsversion()`` â€” same data, in-process. Call before heavy imports.
NÚ_syscmd_verc                ó
   € WV3# ©Nr
   )ÚsystemÚreleaseÚversionÚsupported_platformss   &&&&r   Ú_quiet_syscmd_verÚ8suppress_platform_ver_console.<locals>._quiet_syscmd_ver  s   € à¨Ð/Ð/r   )r;   r;   r;   )r&   Úwin16Údos)r1   ÚplatformÚhasattrrj   Ú	Exception)ru   rq   s     r   Úsuppress_platform_ver_consolerx   ó   sG   € ÷ ‹:Ùð
Ûä�8˜]×+Ò+ô0ð $5Ö ñ ,øô ô Úðús   �!5 µAÁAc               ó   € V ^8„  d   QhRR/# r[   r
   )r   s   "r   r   r   
  s   € ÷ 'ñ ' Tñ 'r   c                 ó:   € \         '       d   R\        4       /# RR/# )zæPopen kwargs detaching a child on Windows, or ``start_new_session=True`` on POSIX.

Bare ``start_new_session=True`` is accepted but has no effect on Windows: the child stays
attached to the parent console and dies when it closes.
rb   Ústart_new_sessionT)r1   rS   r
   r   r   Úwindows_detach_popen_kwargsr|   
  s#   € ÷ ƒzØÔ!5Ó!7Ð8Ð8Ø Ð&Ð&r   ÚGIT_NO_LAZY_FETCHÚ1zcredential.helperr;   zcore.askPasszcore.fsmonitorÚfalsezcore.untrackedCachezcore.hooksPathz
core.pagerÚcatzcore.editorÚtruezsequence.editorzdiff.externalzcore.sshCommandzssh -o BatchMode=yesc               ó    € V ^8„  d   QhRRRR/# )r   r6   r7   r	   Útupler
   )r   s   "r   r   r   2  s   € ÷ ñ Ð#4ð ¸ñ r   c                óæ  € V P                  RR4      pV P                  R4      ;'       g!    \        P                  P                  VR4      pV P                  R4      ;'       g    RV P                  R4      ;'       g!    \        P                  P                  VR4      \        P                  P                  VR	R
4      3p. pV F3  p VP	                  \        P
                  ! V4      P                  4       K5  	  V P                  R4      V P                  R4      V P                  R4      WP                  R4      V P                  R4      .VO5#   \         d    TP	                  R4        K«  i ; i)z­Everything that decides which files ``git config --system/--global`` reads, plus the
global candidates' mtimes so an edit to ``~/.gitconfig`` is picked up without a restart.ÚHOMEr;   ÚXDG_CONFIG_HOMEz.configÚGIT_CONFIG_SYSTEMz/etc/gitconfigÚGIT_CONFIG_GLOBALz
.gitconfigÚgitÚconfigNÚGIT_CONFIG_NOSYSTEMÚPATH)r>   r<   ÚpathÚjoinr3   ÚstatÚst_mtime_nsÚOSError)r6   ÚhomeÚxdgÚ
candidatesÚstampsr�   s   &     r   Ú_safe_directory_cache_keyr–   2  s,  € ð �7‰7�6˜2Ó€DØ
�'‰'Ð#Ó
$×
EÐ
E¬¯©¯©°T¸9Ó(E€Cà�‰Ð#Ó$×8Ð8Ð(8Ø�‰Ð#Ó$×HÐH¬¯©¯©°T¸<Ó(HÜ
�‰�‰�S˜% Ó*ð€Jð
 €FÛˆð	 Ø�M‰Mœ"Ÿ'š' $›-×3Ñ3Ö4ñ ð 	�‰Ð#Ó$ c§g¡gÐ.AÓ&BÀCÇGÁGÐLaÓDbØ�g‰gÐ'Ó(¨#¯'©'°&«/ðà<Bñð øô ô 	 Ø�M‰M˜$×ð	 ús   Ã/EÅE0Å/E0zdict[tuple, list[str]]Ú_safe_directory_cachec               ó    € V ^8„  d   QhRRRR/# )r   Úbase_envr7   r	   r   r
   )r   s   "r   r   r   K  s   € ÷ 2ñ 2Ð%6ð 2¸9ñ 2r   c                óú  € \        V 4      p\        P                  V4      pVe   \        V4      # \	        V 4      p\        V4       F9  pVR8X  g   VP                  \        4      '       g   K'  VP                  VR4       K;  	  VP                  RR4       RVR&   . pR F¥  p \        P                  ! RRVRR	R
.RRRR^\        P                  VR\        4       R7
      pTP                  ^ 8w  d   KS  TP                  P!                  R4      pT'       d   TR,          R8X  d   TP                  4        TP#                  T4       K§  	  \        V4      \        V&   V#   \        \        P                  3 d     KÛ  i ; i)a1  The user's configured ``safe.directory`` values, in git's own effective order.

Read with ``git config -z --get-all`` under *base_env* (the caller's untouched environment) so
an explicit ``GIT_CONFIG_GLOBAL``/``GIT_CONFIG_SYSTEM`` still points at the file the user means.
Best-effort: any failure (git missing, malformed config, timeout) yields no entries and leaves
the caller exactly as it behaved before. Memoised per process on the inputs that select the
config files (and the global file's mtime): ``noninteractive_git_env()`` runs on every internal
git call, including the startup banner probe, and two ``git config`` children per call is
~10 ms against ~0.2 ms for the rest of the function.

``safe.directory`` is an *ordered* multi-valued setting and an empty value resets every entry
seen so far, so a user can revoke a system-wide ``safe.directory=*`` and then name only the
repositories they actually trust. Order and empty resets are therefore policy, not formatting:
scopes are read lowest-precedence first (system, then global) and every value is preserved
verbatim -- no de-duplication (it is a sequence, not a set) and no dropping of the reset
marker, either of which would resurrect a revoked wildcard and widen trust. ``-z`` keeps a
value containing whitespace or a newline as the single entry git reads it as.
NÚGIT_CONFIG_PARAMETERSÚGIT_CONFIG_COUNTr]   r^   r‰   rŠ   ú-zz	--get-allúsafe.directoryTúutf-8ÚreplaceF)	Úcapture_outputÚtextÚencodingÚerrorsÚtimeoutra   r6   Úcheckrb   Ú r;   )z--systemz--globalr-   )r–   r—   r>   r   r8   r   Ú_GIT_CONFIG_INJECT_PREFIXESÚpoprc   r   rd   rY   r‘   ÚSubprocessErrorÚ
returncodeÚstdoutr2   Úextend)	r™   Ú	cache_keyÚcachedr6   ÚkeyÚvaluesÚscopeÚprocÚrecordss	   &        r   Ú_user_safe_directoriesrµ   K  sW  € ô& *¨(Ó3€IÜ"×&Ñ& yÓ1€FØÒÜ�F‹|ÐÜ
ˆx‹.€Cä�CŽyˆØÐ)Ô)¨S¯^©^Ô<W×-XÔ-XØ�G‰G�C˜Öñ ð ‡G�GÐ Ô%Ø!$€CÐÑØ€FÛ)ˆð	Ü—>’>Ø˜ %¨¨{Ð<LÐMØ#¨$¸ÈØ¤×!3Ñ!3¸ÀEÜ0Ó2ô	ˆDð �?‰?˜aÔÙð —+‘+×#Ñ# DÓ)ˆß�w˜r•{ bÔ(Ø�K‰KŒMØ�‰�gÖñ# *ô$ (,¨F£|Ô˜)Ñ$Ø€Møô œ×3Ñ3Ð4ô 	Úð	ús   Â"<EÅE:Å9E:c               ó    € V ^8„  d   QhRRRR/# ©r   ÚbaseúMapping[str, str] | Noner	   zdict[str, str]r
   )r   s   "r   r   r   €  s   € ÷ ñ Ð3ð ¸~ñ r   c                óœ   € \        V e   T M\        P                  4      p ^ RIHp V! RVR7      P
                  #   \         d    Tu # i ; i)a,  PM's full Git environment, or the original base for system-Git fallback.

Keep lazy acquisition under PM's policy (not just installed-package lookup).
Unsupported targets and failed acquisition must not disable a working system
Git. Callers apply their own config/security isolation after selection.
©Úensurer‰   )r™   )r8   r<   r=   Úpmr¼   r6   rw   )r¸   r6   r¼   s   &  r   Úselected_git_envr¾   €  sH   € ô �tÒ'‰t¬R¯Z©ZÓ
8€CðÝá�e cÔ*×.Ñ.Ð.øÜô ØŠ
ðús   ¡; »AÁ
Ac               ó    € V ^8„  d   QhRRRR/# )r   Úproject_rootr   r	   rh   r
   )r   s   "r   r   r   �  s   € ÷ "ñ " ð "¨ñ "r   c                óô  € \         P                  R8w  g'   \        V 4      R,          P                  4       '       g   R# ^ RIHp ^ RIHp V! R4      P                  pV'       d=   \        V^ ,          4      P                  4       P                  V! 4       4      '       g   R# ^ RIHp V! RRR	7      P                  p\        R
 VP                  4        4       R4      pV'       d   V\         P"                  R&   R# R# )aŸ  Put PM's git on PATH, and in PM's facts, for a Windows git checkout.

install.ps1 stages the pinned Git for Windows into PM's store for its own
process only, and PM's facts never record it, so every later bare ``git``
(``hermes update``, the source-completion stamp, plugin installs, doctor)
died with ``[WinError 2]``. A git found under PM's store is that unrecorded
copy inherited from the installer, so it is recorded too. Callers are
explicit user actions (like ``ensure_tools_for_sync``), so acquire PM's git
outright; children inherit the PATH. The machine's own git, and a git-less
ZIP install that never runs git, are untouched. Raises what ``pm.ensure``
raises.
r&   z.gitN)Úlocate_command)Ú
store_rootr‰   r»   T)Úexplicitc              3  óX   "  € T F   w  rVP                  4       R 8X  g   K  Vx € K"  	  R# 5i)rŒ   N)Úupper)Ú.0r°   Úvalues   &  r   Ú	<genexpr>Ú expose_pm_git.<locals>.<genexpr>¨  s!   é € ÐN©™:˜3¸¿	¹	»ÀvÑ8M—’«ùs   ‚* 
*rŒ   )Úsysru   r   ÚexistsÚhermes_platform.resolverrÂ   Úpm.pathsrÃ   ÚcommandÚresolveÚis_relative_tor½   r¼   r6   ÚnextÚitemsr<   r=   )rÀ   rÂ   rÃ   Úfoundr¼   r6   r�   s   &      r   Úexpose_pm_gitrÕ   �  s®   € ô ‡|�|�wÔ¤t¨LÓ'9¸FÕ'B×&JÑ&J×&LÒ&LÙÝ7Ý#á˜5Ó!×)Ñ)€Eß”T˜% �(“^×+Ñ+Ó-×<Ñ<¹Z»\×JÒJÙÝá
� Ô
&×
*Ñ
*€CÜÑN¨¯©¬ÓNÐPTÓU€DßØ!Œ�
‰
�6Óñ r   c               ó    € V ^8„  d   QhRRRR/# r·   r
   )r   s   "r   r   r   ­  s   € ÷ <ñ <Ð!9ð <À^ñ <r   c                ó   € \        V e   T M\        P                  4      p\        V e   T M\        P                  4      pRVR&   RVR&   \	        V4       F9  pVR8X  g   VP                  \        4      '       g   K'  VP                  VR4       K;  	  VP                  RR4       \        P                  VR&   \        P                  VR	&   R
VR&   RVR&   RVR&   RVR&   \	        \        P                  4       4      pVP                  R V 4       4       \        \        V4      4      VR&   \        V4       F  w  pw  r6W1RV 2&   WaRV 2&   K  	  V# )u!  Environment for *internal* git invocations that must never prompt.

Copy of ``base`` (default ``os.environ``) with ``GIT_TERMINAL_PROMPT=0`` (fail instead of
prompting), ``GCM_INTERACTIVE=Never`` (no Git Credential Manager dialog), and isolated git
config: inherited ``GIT_CONFIG_*`` injection, global/system config, pagers, editors, fsmonitor,
external diff and hooks are all disabled so a user's repo/global config cannot hang or mutate
Hermes's plumbing calls. ``core.sshCommand`` is pinned to ``ssh -o BatchMode=yes`` so the ssh
child of a fetch/ls-remote fails instead of prompting â€” ssh bypasses ``stdin=DEVNULL`` and
opens ``/dev/tty`` directly (#104591); an agent-authenticated ssh still succeeds, and an
explicit user ``GIT_SSH_COMMAND`` env var still takes precedence over this config-layer pin.
``GIT_ASKPASS``/``SSH_ASKPASS`` env vars are left alone, but OpenSSH BatchMode disables
passphrase/password prompts, including SSH askpass. Usable keys and ssh-agent authentication
still work; Git's own working askpass helper is unaffected. Pair with
``stdin=subprocess.DEVNULL``. Internal plumbing only â€” the agent-facing terminal tool has its
own policy layer and visible PTY.

Hermes shells out to git from many non-interactive contexts â€” MCP catalog installs, plugin
install/update, profile distribution staging, worktree base fetches, desktop review-pane fetch/push.
When the remote is private, misconfigured, or requires auth, git's default behavior is to prompt on the
inherited terminal (or via an askpass helper), which silently hangs the operation until its timeout â€” or
forever at call sites without one. Ported from openai/codex#34540 / #34612 ("detach non-interactive
subprocesses from stdin"): a background tool invocation must fail fast with a readable error, not wait
for input nobody can type.
Nr]   r^   r_   r`   r›   rœ   rˆ   r‡   r~   r‹   r€   Ú	GIT_PAGERÚPAGERr�   Ú
GIT_EDITORc              3  ó*   "  € T F	  pR V3x € K  	  R# 5i)rž   Nr
   )rÇ   rÈ   s   & r   rÉ   Ú)noninteractive_git_env.<locals>.<genexpr>ä  s   é € ÐMÑ<L°5Ð&¨Õ.Ó<Lùs   ‚ÚGIT_CONFIG_KEY_ÚGIT_CONFIG_VALUE_)r8   r<   r=   rµ   r   r   r¨   r©   ÚdevnullÚ_GIT_CONFIG_OVERRIDESrÓ   r­   r*   r   Ú	enumerate)r¸   r6   Úsafe_directoriesr°   Ú	overridesÚidxrÈ   s   &      r   Únoninteractive_git_envrå   ­  sO  € ô2 �tÒ'‰t¬R¯Z©ZÓ
8€Cô .°dÒ6F©dÌBÏJÉJÓWÐØ!$€CÐÑØ$€CÐÑô �CŽyˆØÐ)Ô)¨S¯^©^Ô<W×-XÔ-XØ�G‰G�C˜Öñ ð ‡G�GÐ Ô%Ü!Ÿz™z€CÐÑÜ!Ÿz™z€CÐÑØ!$€CÐÑØ€CˆÑØ€Cˆ�LØ€CˆÑÜÔ*×0Ñ0Ó2Ó3€Ið ×ÑÑMÑ<LÓMÔMÜ!¤# i£.Ó1€CÐÑÜ& yÖ1Ñˆ‰\ˆcØ'*ˆo˜c˜UÐ#Ñ$Ø).Ð ˜uÐ%Ó&ñ 2ð €Jr   z&^filter\..+\.(?:clean|smudge|process)$z^includeif\..*\.path$z^include(?:if\..*)?\.path$zH^(filter\..*\.(clean|smudge|process)|include\.path|includeif\..*\.path)$é   zgit filter discovery failedc               ó$   € V ^8„  d   QhRRRRRR/# )r   Úcwdzstr | os.PathLike[str]r¸   r¹   r	   zdict[str, str] | Noner
   )r   s   "r   r   r      s+   € ÷ \ñ \Ø	ð\à
"ð\ð ñ\r   c                óÆ  € \        V4      p\        RR\        V 4      RRRRR\        .	^VR7      pVe   VP                  R 9  d   R	# . p\        4       pR	pVP                  P                  R
4      p\        VR,          VR,          4       EFc  w  r‰V	P                  R4      w  r«p\        P                  V
4      '       g   VP                  V
4       KH  VP                  R4      '       g    R	# \        V\        R4      R	 4      pVP!                  4       '       g–   VP#                  R4      '       g   VP#                  R4      '       d    R	# VfY   \        RR\        V 4      RR.^VR7      pVe   VP                  ^ 8w  d    R	# \        VP                  P%                  R4      4      pWm,          pVP&                  \(        P*                  P-                  V4      ,          P/                  4       pWõ9   g   VP1                  4       '       g   EK�  VP3                  4       '       d   \        V4      \4        8¼  d    R	# VP7                  V4       \        RRR\        V4      RRR\        .^VR7      pVe   VP                  R 9  d    R	# VP                  P                  R
4      p\8        ;QJ d    R V 4       F  '       g   K   RM	  RM! R V 4       4      '       d    R	# VP;                  V4       EKf  	  . p. p\        4       pV FÃ  pVP=                  4       p
V
'       d#   V
V9   g   \>        P                  V
4      '       g   K?  VP7                  V
4       VP                  V
4       \        V4      \@        8”  d    R	# V
PC                  R^4      ^ ,          R,           pVV9  g   K¡  VP7                  V4       VP                  V4       KÅ  	  \E        VR,          4      pV U
u. uF  qªR3NK  	  up
V U
u. uF  qªR3NK  	  up
,           p\G        V4       F$  w  pw  r¬W¢RVV,            2&   WÂRVV,            2&   K&  	  \        V\        V4      ,           4      VR&   V# u up
i u up
i )!a8  Harden internal git for one repository, including named clean/smudge/process filters.

The static environment can pin fixed config keys such as core.fsmonitor and
core.hooksPath, but a repository chooses filter driver names through .gitattributes.
Discover the effective filter command keys for this checkout and append empty command
overrides plus required=false to the already-isolated config block. Discovery is
bounded and fail-closed: if filter discovery cannot be trusted, callers skip the
automatic git operation instead of running with only partial hardening.
r‰   ú-CrŠ   z
--includesz--show-originr�   z--get-regexp©r¥   r6   Nr§   :r   Nr   :é   Nr   Ú
zfile:ÚGIT_DIRÚGIT_WORK_TREEz	rev-parsez--show-toplevelz
z--filez--name-onlyc              3  óL   "  € T F  p\         P                  V4      x € K  	  R # 5irl   )Ú_INCLUDE_KEYÚ	fullmatch)rÇ   rE   s   & r   rÉ   Ú.noninteractive_repo_git_env.<locals>.<genexpr>@  s   é € Ð>¹°Œ|×%Ñ% d×+Ð+»ùs   ‚"$TFÚ.z	.requiredrœ   r;   r   rÝ   rÞ   )r   rì   )$rå   Úbounded_probe_runr*   Ú_DISCOVERY_KEYS_REGEXPr«   Úsetr¬   r2   ÚzipÚ	partitionÚ_INCLUDE_IF_KEYrò   r3   r   r   r   Úis_absoluter>   ÚrstripÚparentr<   r�   Ú
expanduserrÐ   rÌ   Úis_fileÚ_MAX_INCLUDE_TARGETSÚaddÚanyr­   ÚstripÚ_FILTER_COMMAND_KEYÚ_MAX_FILTER_KEYSÚrsplitrN   rá   )rè   r¸   r6   r³   ÚnamesÚtargetsÚtoplevelÚfieldsÚoriginÚentryr°   Ú_rÈ   Úorigin_pathÚtopÚtargetÚproberÔ   ÚkeysÚrequiredÚseenÚrawÚrequired_keyÚstartrã   Úoffsets   &&                        r   Únoninteractive_repo_git_envr     s­  € ô ! Ó
&€Cô
 Ø	�”c˜#“h ¨,¸ÈÈ~Ü	ð	!à�sô€Dð
 ‚|�t—‘¨fÔ4ÙØ€EÜ›€GØ €HØ�[‰[×Ñ˜tÓ$€FÜ˜V D�\¨6°$­<×8‰ˆØŸ™¨Ó-‰ˆ�Ü×(Ñ(¨×-Ò-Ø�L‰L˜ÔÙØ× Ñ  ×)Ò)ÚÜ˜6¤# g£, -Ð0Ó1ˆØ×&Ñ&×(Ò(ð �w‰w�y×!Ò! S§W¡W¨_×%=Ò%=ÚØÒÜ'¨°´c¸#³hÀÐM^Ð(_Ø01°sô<�à’; #§.¡.°AÔ"5ÚÜ §
¡
× 1Ñ 1°&Ó 9Ó:�Ø"Õ0ˆKà×$Ñ$¤r§w¡w×'9Ñ'9¸%Ó'@Õ@×IÑIÓKˆØÔ F§M¡M§O¢OÚØ�~‰~×Ò¤3 w£<Ô3GÔ#GÚØ�‰�FÔÜ!Ø�H˜h¬¨F«°]ÀDÈ.ÔZpÐqØ˜3ô
ˆð Š=˜E×,Ñ,°FÔ:ÚØ—‘×"Ñ" 4Ó(ˆç‹3Ñ>¹Ó>�3�3Š3Ñ>¹Ó>×>Ò>ÚØ�‰�U×ñK 9ðN €DØ€HÜ“U€Dó ˆØ�i‰i‹kˆß�c˜T”kÔ)<×)FÑ)FÀs×)KÒ)KÙØ�‰�ŒØ�‰�CÔÜˆt‹9Ô'Ô'ÚØ—z‘z # qÓ)¨!Õ,¨{Õ:ˆØ˜tÖ#Ø�H‰H�\Ô"Ø�O‰O˜LÖ)ñ ô �Ð&Õ'Ó(€EÙ&*Ó+¡d˜s�r“¡dÑ+ÉÓ.RÉÀ#°W«~ÉÑ.RÕR€IÜ )¨)Ö 4Ñˆ‘�Ø25ˆo˜e f�nÐ-Ð.Ñ/Ø49Ð ¨¥Ð/Ð0Ó1ñ !5ô " %¬#¨i«.Õ"8Ó9€CÐÑØ€Jùò ,ùÒ.Rs   ÏQÏ1Qc               ó    € V ^8„  d   QhRRRR/# ©r   ÚpidrN   r	   Úboolr
   )r   s   "r   r   r   _  s   € ÷ ñ ˜ð  ñ r   c                ó>  €  \        RV  R2RR7      ;_uu_ 4       pVP                  4       P                  4       pRRR4       \        X4      ^8„  ;'       d    V^,          R8H  #   + '       g   i     L2; i  \         dƒ     \
        P                  ! RRR	R
\        T 4      .RRRR^RR7      pTP                  ^ 8H  ;'       d*    TP                  P                  4       P                  R4      u #   \         d      R# i ; i\        \        \        3 d     R# i ; i)zWZombie via ``/proc/<pid>/stat`` field 3, or ``ps -o state=`` without /proc (macOS/BSD).z/proc/z/statrŸ   )r£   NÚZÚpsz-ozstate=z-pTr    F)r¡   r¢   r£   r¤   r¥   r¦   )ÚopenÚreadr2   r   ÚFileNotFoundErrorrc   r   r*   r«   r¬   r  r   rw   Ú
IndexErrorÚPermissionErrorr‘   )r  ÚfhÚstat_fieldsÚrs   &   r   Úposix_is_zombier)  _  sÿ   € ðÜ�F˜3˜%˜uÐ%°×8Õ8¸BØŸ'™'›)Ÿ/™/Ó+ˆK÷ 9ä�;Ó !Ñ#×=Ð=¨°A­¸#Ñ(=Ð=÷ 9×8ûô ô 	ð	Ü—’Ø�t˜X t¬S°«XÐ6Ø#¨$¸ÈÐ\]ØôˆAð
 —<‘< 1Ñ$×IÐI¨¯©¯©Ó)9×)DÑ)DÀSÓ)IÒIøÜô 	Ùñ ð		úäœ¬Ð1ô ØÙðús^   ‚A7 ›A$ºA7 ÁA7 Á$A4	Á/A7 Á7DÂA C0Ã)C0Ã-DÃ0D Ã;DÃ?D Ä DÄDÄDc               ó    € V ^8„  d   QhRRRR/# r  r
   )r   s   "r   r   r   t  s   € ÷ ñ ˜#ð  $ñ r   c                óø  €  ^ RI pVP                  P                  pVP                  VP                  n        VP                  VP                  n        VP                  VP                  n        RRrCR^reVP	                  W4,          RV 4      pV'       g   VP                  4       V8H  #  VP                  V^ 4      V8H  VP                  V4       #   TP                  T4       i ; i  \        \        3 d     R# i ; i)zGpsutil-free Windows liveness probe via OpenProcess/WaitForSingleObject.Ni   i   i  F)ÚctypesÚwindllÚkernel32Úc_void_pÚOpenProcessÚrestypeÚc_uintÚWaitForSingleObjectÚGetLastErrorÚCloseHandler‘   ÚAttributeError)r  r,  r.  Ú!PROCESS_QUERY_LIMITED_INFORMATIONÚSYNCHRONIZEÚWAIT_TIMEOUTÚERROR_ACCESS_DENIEDÚhandles   &       r   Úwin32_pid_existsr<  t  sß   € ðÛØ—=‘=×)Ñ)ˆà'-§¡ˆ×ÑÔ$Ø/5¯}©}ˆ×$Ñ$Ô,Ø(.¯©ˆ×ÑÔ%Ø9?À¨;Ø,6¸Ð)Ø×%Ñ%Ð&GÕ&UÐW\Ð^aÓbˆßð ×(Ñ(Ó*Ð.AÑAÐAð	)à×/Ñ/°¸Ó:¸lÑJà× Ñ  Õ(øˆH× Ñ  Õ(ûÜ”^Ð$ô Úðús*   ‚B$C$ Â(C Â<C$ ÃC!Ã!C$ Ã$C9Ã8C9c               ó    € V ^8„  d   QhRRRR/# r  r
   )r   s   "r   r   r   �  s   € ÷ ñ ˜3ð  4ñ r   c                óÞ   € \        V 4      p \        '       d   \        V 4      # \        V 4      '       d   R#  \        P
                  ! V ^ 4       R#   \         d     R# \         d     R# i ; i)a¼  Stdlib-only "is this PID alive" check that never signals the target (zombies report dead).

For code that must run without the dependency environment: the detached gateway restart
watcher is started by whatever interpreter the updater runs on (the bare store Python after
the package-manager handoff), so it cannot import ``gateway.status`` (``utils`` pulls in
``ruamel``). ``gateway.status._pid_exists`` prefers psutil and falls back to this.
FT)rN   r1   r<  r)  r<   Úkillr%  r‘   )r  s   &r   Úpid_exists_stdlibr@  �  sa   € ô ˆc‹(€CßƒzÜ Ó$Ð$Ü�s×ÒÙðÜ
�Š��QŒñ
 øô	 ô ÚÜô Úðús   ·A ÁA,ÁA,Á'A,Á+A,c               ó    € V ^8„  d   QhRRRR/# )r   r  rN   r	   ú
int | Noner
   )r   s   "r   r   r   £  s   € ÷ ñ ˜Sð  Zñ r   c                óD   €  ^ RI Hp V! V 4      #   \         d     R# i ; i)z@The repository's stable process-start fingerprint, if available.)Úget_process_start_timeN)Úgateway.statusrD  rw   )r  rD  s   & r   Ú_process_start_timerF  £  s'   € ðÝ9á% cÓ*Ð*øÜô Úðús   ‚ �žc               ó    € V ^8„  d   QhRRRR/# )r   r¢   r*   r	   r  r
   )r   s   "r   r   r   ­  s   € ÷ Gñ G˜Sð G Tñ Gr   c                óö   € \         ;QJ d?    R \        P                  ! RV P                  4       4       4       F  '       g   K   R# 	  R# ! R \        P                  ! RV P                  4       4       4       4      # )uý   True when *text* names Hermes at a path-segment / token boundary.

A bare ``"hermes" in text`` substring test would also match unrelated processes whose paths
merely contain the letters (``...\shermesa\...``) â€” the false-positive class this prevents.
c              3  óD   "  € T F  pVP                  R4      x € K  	  R# 5i)ÚhermesN)rJ  z.hermes)r   )rÇ   Útokens   & r   rÉ   Ú%_text_names_hermes.<locals>.<genexpr>³  s'   é € ð GÙE�5ð ×ÑÐ 5×6Ð6ÛEùs   ‚ z[\\/\s=,;\"']+TF)r  Úrer2   Úlower)r¢   s   &r   Ú_text_names_hermesrO  ­  sk   € ÷ ‹3ñ GÜŸHšHÐ%6¸¿
¹
»ÔEóG�3Œ3ð GŠ3ð Gˆ3ñ GÜŸHšHÐ%6¸¿
¹
»ÔEóGó Gð Gr   c               ó    € V ^8„  d   QhRRRR/# r  r
   )r   s   "r   r   r   ·  s   € ÷ 
ñ 
 Cð 
¨Dñ 
r   c                óø   €  ^ RI pVP                  V 4      pRP                  VP                  4       ;'       g    . 4      pVP	                  4       ;'       g    Rp\        V RV 24      #   \         d     R# i ; i)z8Best-effort check that *pid* currently runs Hermes code.NÚ r;   F)ÚpsutilÚProcessrŽ   ÚcmdlineÚexerO  rw   )r  rS  ÚprocessrÏ   Ú
executables   &    r   Ú_process_command_is_hermesrY  ·  sp   € ðÛà—.‘. Ó%ˆØ—(‘(˜7Ÿ?™?Ó,×2Ð2°Ó3ˆØ—[‘[“]×(Ð( bˆ
Ü! W I¨Q¨z¨lÐ";Ó<Ð<øÜô Úðús   ‚6A* ¹A* ÁA* Á*A9Á8A9Úexpected_start_timec               ó$   € V ^8„  d   QhRRRRRR/# )r   r  rN   rZ  rB  r	   r  r
   )r   s   "r   r   r   Ä  s!   € ÷ ñ �sð °Jð È$ñ r   c               ón  € \        V \        4      '       d   \        V \        4      '       g   V ^ 8:  d   R# \        '       g   Vf   R#  \	        V 4      V8H  #  \	        V 4      pTf   R# Te	   Y!8w  d   R#  \        T 4      #   \
         d     R# i ; i  \
         d     R# i ; i  \
         d     R# i ; i)a1  Whether it is safe to use ``taskkill`` for *pid*.

The PID must be valid, currently exist, and identify a Hermes process. When the caller captured
a start-time fingerprint before the destructive action, the live process must still have the
same ``(pid, start_time)`` identity. Any ambiguity fails closed.
FT)Ú
isinstancerN   r  r1   rF  rw   rY  )r  rZ  Úcurrent_start_times   &$ r   Úpid_is_hermesr_  Ä  s¾   € ô �cœ3×Ò¤:¨c´4×#8Ò#8¸CÀ1¼HÙß‹:ØÒ&Ùð	Ü& sÓ+Ð/BÑBÐBðÜ0°Ó5Ðð Ò!ÙØÒ&Ð+=Ô+TÙðÜ)¨#Ó.Ð.øô ô 	Úð	ûô ô Úðûô ô Úðús6   Á	B ÁB Á6
B% ÂBÂBÂB"Â!B"Â%B4Â3B4c               ó    € V ^8„  d   QhRRRR/# ©r   r³   úsubprocess.Popenr	   rh   r
   )r   s   "r   r   r   â  s   € ÷ ñ Ð,ð °ñ r   c                ó¸   €  ^ RI Hp V! V P                  4        T P                  4        R#   \         d    \	        T 4        R# i ; i  \         d     R# i ; i)u-  Best-effort terminate *proc* and its descendants on both platforms; never raises.

``proc.kill()`` alone only terminates the direct child. This is cleanup on an already-failing
path whose contract is to fail open, so every failure (access denied, already reaped) is
swallowed rather than escaping the caller's ``except``.

On Windows a suspended descendant (e.g. ``git.exe``) can survive holding duplicates of the captured pipe
handles, which keeps the pipes from reaching EOF and leaks two reader threads + the process per fired
timeout â€” ``taskkill /T /F`` takes the whole tree down so the bounded drain that follows can actually
reach EOF. On POSIX the same class exists: killing the launcher leaves descendants (credential helpers,
``git-remote-https``, hook children) running and holding the pipe write ends. Callers spawn the child in
its own process group (``process_group=0``, Python â‰¥3.11), so when â€” and only when â€” the child leads its
own group (``pgid == pid``), the entire group is signalled with ``os.killpg``. The ownership check means
a fallback spawn that shares our group can never cause us to kill unrelated processes. Ported from
openai/codex#36793 ("Terminate timed-out Git process trees"); generalized for the shell-hook runner via
openai/codex#37527 ("Terminate timed-out hook process trees").
)Úkill_process_treeN)Úagent.deadlinerd  r  rw   Ú_legacy_kill_process_treer?  r‘   )r³   Ú_deadline_kill_trees   & r   rd  rd  â  sS   € ð$ÝKá˜DŸH™HÔ%ð
Ø�	‰	Žøô ô Ü! $Ô'Úðûô ô Úðús    ‚- ›A
 ­AÁAÁ
AÁAc               ó    € V ^8„  d   QhRRRR/# ra  r
   )r   s   "r   r   r     s   € ÷ ñ Ð$4ð ¸ñ r   c           
     ó>  € \         '       gV    ^ RIp\        P                  ! V P                  4      pW P                  8X  d!   \        P
                  ! W!P                  4        V P                  4        \         '       dk    \        P                  ! RRRR\        V P                  4      .\        P                  \        P                  \        P                  ^R\        4       R7       R# R#   \         d     L–i ; i  \         d     L–i ; i  \         d     R# i ; i)zULocal tree-kill fallback when agent.deadline is unavailable (partial install, cycle).NÚtaskkillz/Tz/Fz/PIDF)r¬   Ústderrra   r¥   r¦   rb   )r1   Úsignalr<   Úgetpgidr  ÚkillpgÚSIGKILLrw   r?  r‘   rc   r   r*   rd   rY   )r³   Ú_signalÚpgids   &  r   rf  rf    sÙ   € ç‹:ð	Û$ä—:’:˜dŸh™hÓ'ˆDØ—x‘xÔÜ—	’	˜$§¡Ô0ðØ�	‰	Œ÷ ƒzð	Ü�NŠN˜J¨¨d°F¼CÀÇÁ»MÐJÜ",×"4Ñ"4¼Z×=OÑ=OÜ!+×!3Ñ!3¸QÀeÜ);Ó)=÷?ñ	 øô ô 	Ùð	ûô ô Ùðûô ô 	Úð	ús7   ŽAC+ Á#C< Â A'D Ã+C9Ã8C9Ã<D
Ä	D
ÄDÄDr¤   r    r6   rè   Úraise_on_spawn_failureFÚinputc               ó8   € V ^8„  d   QhRRRRRRRRR	R
RRRRRR/# )r   rF   r   r¥   Úfloatr¤   r*   r6   r¹   rè   zstr | os.PathLike[str] | Nonerr  r  rs  z
str | Noner	   z'subprocess.CompletedProcess[str] | Noner
   )r   s   "r   r   r     s\   € ÷ 1Tñ 1TØ
ð1TØ%*ð1TØ47ð1Tà	!ð1Tà/Lð1Tð !ð1Tð 2<ð1Tð -ñ	1Tr   c               óL  € \         '       d   R\        4       /MR^ /pRp ^ RIHp	 T	! \	        V 4      3R\
        P                  R\
        P                  RVf   \
        P                  M\
        P                  RR	R
RRTRVe   \        V4      MRRV/VB w  r¨ T
P                  YaR7      w  r¼\        T4       \
        P                  ! \	        T 4      T
P                  Y¼4      #   \         d    T'       d   h  R# i ; i  \         d    \        T4       \        T
^4        R# i ; i)u?  Deadlock-safe ``subprocess.run(argv, capture_output=True, timeout=â€¦)`` for fail-open probes.

``input`` is written to the child's stdin (closed afterwards); without it stdin is ``DEVNULL``.

Returns a ``CompletedProcess`` when the child finished within *timeout* (any exit code), or
``None`` on spawn failure or timeout. With ``raise_on_spawn_failure=True`` the ``Popen``
exception propagates instead, so callers that treat a *timeout* as a verdict can still tell
"our own probe never started" apart from "the child hung".

Why not ``subprocess.run``: on Windows, ``run()``'s post-timeout cleanup calls an *unbounded*
``communicate()`` after killing the direct child. Killing it can leave a descendant (``git.exe`` under a
launcher shim, ``conhost.exe`` under wmic/powershell) holding duplicates of the captured stdout/stderr
handles, so the pipes never reach EOF and the reader-thread join blocks forever. The wmic /
``Get-CimInstance Win32_Process`` gateway scan hit exactly this during ``hermes update`` on slow-WMI
machines (#87134); the git probes hit it first (#68609 / #66037).
rb   Úprocess_groupN)Úspawn_serverr¬   rk  ra   r¢   Tr£   rŸ   r¤   r6   rè   )rs  r¥   )r1   rY   Ú"hermes_cli.local_runtime.processesrx  r   rc   ÚPIPErd   r8   rw   ÚcommunicateÚ
_close_jobÚkill_and_drainÚCompletedProcessr«   )rF   r¥   r¤   r6   rè   rr  rs  Ú_popen_kwargsÚjobrx  r³   r¬   rk  s   &$$$$$$      r   rõ   rõ     sG  € ÷* FPÃZ˜?Ô,>Ó,@ÑAÐVeÐghÐUi€MØ
€Cðõ
 	Dá Ü�‹JñRÜ)Ÿ™ðRÜ7A·±ðRà(-ª”*×$Ò$¼:¿?¹?ðRð ðRð !(ðRð 17ðRð !š_”�S”	°$ð	Rð =@ð	Rð DQñ	R‰	ˆðØ×)Ñ)°Ð)ÓG‰ˆô ˆs„OÜ×&Ò&¤t¨D£z°4·?±?ÀFÓSÐSøô ô ß!ØÚðûô ô ô 	�3ŒÜ�t˜QÔÚðús*    A7C" ÂC= Ã"C:Ã5C:Ã9C:Ã="D#Ä"D#c               ó$   € V ^8„  d   QhRRRRRR/# )r   r³   rb  Úsecondsru  r	   ztuple | Noner
   )r   s   "r   r   r   R  s"   € ÷ 
ñ 
Ð)ð 
°Eð 
¸lñ 
r   c                ó¶   € \        V 4        V P                  VR7      #   \        \        \        P
                  3 d    R;T n        ;T n        T n         R# i ; i)a\  Tree-kill *proc* (:func:`kill_process_tree`), then read what its pipes still hold for at
most *seconds*: ``(stdout, stderr)``, or ``None`` when a descendant the kill missed still
holds them. Those pipes are left to ``communicate()``'s reader threads, never closed
(closing a pipe a thread is reading blocks; a ``with Popen`` exit would close them).)r¥   N)	rd  r{  r‘   Ú
ValueErrorrc   rª   ra   r¬   rk  )r³   r‚  s   &&r   r}  r}  R  sY   € ô
 �dÔðØ×Ñ¨ÐÓ0Ð0øÜ”Z¤×!;Ñ!;Ð<ô Ø15Ð5ˆŒ
Ð5�T”[ 4¤;Úðús   � Ÿ5AÁAc               ó   € V ^8„  d   QhRR/# rg   r
   )r   s   "r   r   r   _  s   € ÷ ñ �tñ r   c                óX   € V f   R #  V P                  4        R #   \         d     R # i ; irl   )Úcloserw   )r€  s   &r   r|  r|  _  s*   € Ø
‚{ÙðØ�	‰	ŽøÜô Úðús   ˆ š)¨)c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rF   r   r¥   ru  r6   r¹   r	   r*   r
   )r   s   "r   r   r   h  s*   € ÷ )ñ )˜Mð )°uð )ÐC[ð )Ðgjñ )r   c               óÆ   € \        Y/ T;'       g    \        4       C\        CR7      pVe   VP                  ^ 8w  d   R# VP                  ;'       g    RP                  4       # )ul  Run a short ``git`` probe and return stripped stdout, or ``""`` on ANY failure.

On Windows ``run()``'s post-timeout cleanup calls an unbounded ``communicate()``; a suspended
descendant git.exe holding the pipe handles then blocks forever. Here: bounded ``communicate``,
tree-kill plus a 1s drain, then abandon the pipes; on POSIX the probe gets its own process
group so cleanup also takes down credential/remote helpers.

Security (GHSA-7x36-8jrh-v4pw): these probes run automatically against whatever directory the
session sits in, before any tool call or trust prompt, and an index refresh executes the
repo-configured ``core.fsmonitor`` program. Every probe therefore runs under
:func:`noninteractive_git_env`; diff-rendering callers additionally pass
:data:`NO_DRIVER_DIFF_FLAGS` (attribute-scoped drivers can't be disabled via env).

Killing the PATH-resolved launcher can leave a suspended descendant ``git.exe`` holding duplicates of
the captured stdout/stderr handles, so the pipes never reach EOF and the reader-thread join blocks
forever. On the Desktop agent-build path (``_start_agent_build â†’ _session_info â†’ branch() â†’ run_git``)
that turned an optional branch label into ``agent initialization timed out`` (issues #68609 / #66037).
The normal-path spawn contract mirrors the previous ``run`` call byte-for-byte: PIPE/PIPE/DEVNULL,
``text`` with UTF-8 ``errors="replace"`` decoding, and the hidden-window ``creationflags`` on Windows
only. On POSIX the probe is additionally placed in its own process group (``process_group=0``, Python
â‰¥3.11) so timeout cleanup can take down descendants â€” credential helpers, ``git-remote-https``, hook
children â€” with the launcher instead of orphaning them (see :func:`kill_process_tree`; port of
openai/codex#36793). ``process_group`` only changes which group the child belongs to; it does not detach
the terminal or alter the fast path.
rë   r;   )rõ   rå   ÚNO_LAZY_FETCH_ENVr«   r¬   r  )rF   r¥   r6   Úresults   &$$ r   Úbounded_git_proberŒ  h  sX   € ô4 ˜tÐ:t¸c×>]Ð>]ÔE[ÓE]Ð:tÔbsÐ:tÔu€FØ‚~˜×*Ñ*¨aÔ/ÙØ�M‰M×Ð˜R×&Ñ&Ó(Ð(r   )ÚFILTER_DISCOVERY_FAILEDr1   r!   rŠ  rŒ  rõ   rÕ   rå   r  r@  r_  rK   rC   r¾   r4   rx   rS   rV   r|   rY   )z--no-ext-diffz--no-textconv>   ÚlogÚdiffÚshowÚblame>   rê   ú-cú	--git-dirú--exec-pathú--namespaceú--work-tree)rÝ   rÞ   rl   )GÚ__conditional_annotations__Ú__doc__Ú
__future__r   r<   rM  rH   rc   rË   Úpathlibr   Útypingr   r   r   Ú__all__r!   Ú	frozensetr    r   r   r%   ru   r1   Ú_WINDOWS_GATEWAY_BREAKAWAY_ENVr4   rC   rK   rP   rQ   rR   rS   rV   rY   re   rx   r|   rŠ  r¨   rß   rà   r–   r—   Ú__annotations__rµ   r¾   rÕ   rå   ÚcompileÚ
IGNORECASEr  rú   rñ   rö   r   r  r�  r  r)  r<  r@  rF  rO  rY  r_  rd  rf  rõ   r}  r|  rŒ  )r—  s   @r   Ú<module>r¢     s&  øðôõ #ã 	Û 	Û Û Û 
Ý ß .Ñ .ò€ð< :Ð ñ (Ò(HÓIÐ ò Y€õõð. �\‰\˜WÑ$€
ð "=Ð õõ:õ.%ð 'Ð ð Ð ð
 (Ð õVõ69õ2õ\õ&õ.'ð  )¨#Ð.Ð ð
 GÐ à˜Ø�BØ�gØ˜7Ø�b—j‘jØ�%Ø�6Ø�vØ�Rð
 Ð-ðÐ õ$ð, 13Ð Ð-Ó 2õ2÷jõ "÷:<ð~ —j’jÐ!JÈBÏMÉMÓZÐ ð —*’*Ð5°r·}±}ÓE€à�zŠzÐ7¸¿¹ÓG€àdÐ àÐ ð Ð à7Ð ÷\õ~õ*õ2õ,õGõ
ðÀ÷ õ<õ@ð81TØ:Cð1Tà$(ð1TàOSð1Tð $)ð1Tð ?C÷1Tõh
õð)Ð^b÷ )ñ )r   