§
    øžyj  ã                  ó¦   — U d Z ddlmZ ddlZddlmZmZ dZdd„Zdd„Z	dd„Z
dd„Zdd„Zdd„Zdd„Zeee	e
eeegZded<   ddddœZded<   dd„ZdS )u¿  Output-pattern failure hints for the terminal tool.

When a command exits non-zero, the raw stderr often confuses models into
wasted diagnostic turns (e.g. retrying `python` when only `python3` exists,
or re-sending a gh field list that the installed gh doesn't support).

This module extends the exit-code semantics table in ``terminal_tool`` with
an *output-pattern* tier: a bounded scan of the command output that maps
well-known failure shapes to one short, actionable recovery hint.

Design rules (keep these when adding patterns):

* Only fires on non-zero exit codes â€” never annotate success.
* At most ONE hint per result, first match wins; patterns are ordered by
  observed frequency in production trajectories (state.db mining, Aug 2026).
* Scans only the first ``_SCAN_CHARS`` of output â€” hints must key on error
  headers, not deep context.
* Hints state the *next action*, not a diagnosis essay. One or two sentences.
* Pure function, no I/O, no config reads â€” trivially unit-testable.

Frequencies quoted below come from a 250k-terminal-result window of the
production session DB (Aug 2026): together these classes cover ~14k failed
calls whose retry chains averaged 1.4 extra tool turns each.
é    )ÚannotationsN)ÚCallableÚOptionali   ÚcommandÚstrÚoutputÚreturnúOptional[str]c                óf   — t          j        d|¦  «        }|sd S d|                     d¦  «        › d�S )NzUnknown JSON field: "?(\w+)z2The installed gh does not support the JSON field 'é   ub   '. The valid field list is printed in the output above â€” retry using only fields from that list.©ÚreÚsearchÚgroup©r   r   Úms      ú:/home/ragecks/.hermes/hermes-agent/tools/terminal_hints.pyÚ_hint_gh_unknown_json_fieldr   #   sH   € õ 	Œ	Ð0°&Ñ9Ô9€AØð Øˆtð	&¸Q¿WºWÀQ¹Z¼Zð 	&ð 	&ð 	&ðó    c                ó”   — t          j        d|¦  «        }|sd S |                     d¦  «        }|dk    r	 dS |dk    r	 dS d|› d|› d	�S )
NzE(?:bash: line \d+: |bash: |sh: \d*:? ?)?([\w.+-]+): command not foundr   Úpythonun   This system has no bare `python` â€” use `python3`, or the project venv's interpreter (e.g. .venv/bin/python).Úpipuo   This system has no bare `pip` â€” use `pip3`, `python3 -m pip`, or the project venv's pip (e.g. .venv/bin/pip).ú`z6` is not installed or not on PATH. Verify with `which zK`; install it or use an absolute path instead of retrying the same command.r   )r   r   r   Úmissings       r   Ú_hint_command_not_foundr   0   s�   € å
Œ	ÐZÐ\bÑcÔc€AØð ØˆtØ�gŠg�a‰jŒj€GØ�(ÒÐðBð	
ð 	
ð �%ÒÐð>ð	
ð 	
ð
	%ˆGð 	%ð 	%Øð	%ð 	%ð 	%ðr   c                óf   — t          j        d|¦  «        }|sd S d|                     d¦  «        › d�S )Nz?(?:ModuleNotFoundError|ImportError): No module named '?([\w.]+)zPython cannot import 'r   zÏ'. Most often the wrong interpreter is running: activate the project venv (e.g. `source .venv/bin/activate`) or invoke its python directly. Only pip install if the package is genuinely absent from that venv.r   r   s      r   Ú_hint_module_not_foundr   G   sK   € å
Œ	ÐTÐV\Ñ]Ô]€AØð Øˆtð	E §¢¨¡¤ð 	Eð 	Eð 	Eðr   c                óL   — t          j        d|t           j        ¦  «        sd S 	 dS )Nz-^CONFLICT |Automatic merge failed|needs mergeuÈ   Git merge conflict. Do not retry this command. Resolve the conflicted files listed above (edit, then `git add`), then continue (`git rebase --continue` / commit the merge) â€” or abort with `--abort`.)r   r   ÚM©r   r   s     r   Ú_hint_merge_conflictr!   T   s/   € åŒ9ÐEÀvÍrÌtÑTÔTð Øˆtð	ðð r   c                óf   — t          j        d|¦  «        }|sd S d|                     d¦  «        › d�S )Nz+(?:fatal|error):.*?'([^']+)' already existsú'r   u†   ' already exists â€” retrying unchanged will keep failing. Reuse it, choose another name, or delete it first if it is genuinely stale.r   r   s      r   Ú_hint_already_existsr$   `   sF   € å
Œ	Ð@À&ÑIÔI€AØð Øˆtð	ˆA�GŠG�A‰JŒJð 	ð 	ð 	ðr   c                ó   — d|vrd|vrd S 	 dS )NzAPI rate limitzwas submitted too quicklyu{   GitHub API rate limit hit â€” immediate retries will keep failing. Continue with other work and retry this operation later.© r    s     r   Ú_hint_gh_rate_limitr'   l   s-   € à˜vÐ%Ð%Ð*EÈVÐ*SÐ*SØˆtð	Cðð r   c                ó   — d|vrd|vrd S 	 dS )NzPermission deniedÚEACCESz Permission denied. Check ownership/mode of the target path (`ls -la`); prefer a user-writable location. Only escalate to sudo if the task genuinely requires it.r&   r    s     r   Ú_hint_permission_deniedr*   v   s+   € Ø &Ð(Ð(¨X¸VÐ-CÐ-CØˆtð	-ðð r   z)list[Callable[[str, str], Optional[str]]]Ú_OUTPUT_HINTSu~   Exit 126: the file was found but is not executable â€” `chmod +x` it or invoke it via its interpreter (e.g. `bash script.sh`).u�   Exit 137: the process was SIGKILLed â€” usually out-of-memory or an external kill. Reduce memory use or check `dmesg | tail` before retrying.z‡Exit 124: the command hit its timeout. Raise timeout= (foreground max 600s) or run it with background=true and notify_on_complete=true.)é~   é‰   é|   zdict[int, str]Ú_EXIT_CODE_HINTSÚ	exit_codeÚintc                óÌ   — |dk    rdS |pddt           …         }|r0t          D ](}	  || pd|¦  «        }n# t          $ r Y Œw xY w|r|c S Œ)t                               |¦  «        S )aƒ  Return one short recovery hint for a failed command, or None.

    Args:
        command: The command string that ran.
        exit_code: Its exit code (non-zero for failures).
        output: Combined stdout/stderr as returned to the model.

    Only the first ``_SCAN_CHARS`` characters of output are examined and at
    most one hint is returned. Returns None for exit_code == 0.
    r   NÚ )Ú_SCAN_CHARSr+   Ú	Exceptionr/   Úget)r   r0   r   ÚwindowÚfnÚhints         r   Úannotate_failurer:   ”   s¡   € ð �A‚~€~ØˆtØˆl˜˜L�[˜LÔ)€FØð Ýð 	ð 	ˆBðØ�r˜'˜- R¨Ñ0Ô0��øÝð ð ð Ø�ðøøøàð Ø���ðå×Ò 	Ñ*Ô*Ð*s   ¦5µ
AÁA)r   r   r   r   r	   r
   )r   r   r0   r1   r   r   r	   r
   )Ú__doc__Ú
__future__r   r   Útypingr   r   r4   r   r   r   r!   r$   r'   r*   r+   Ú__annotations__r/   r:   r&   r   r   ú<module>r?      s_  ððð ð ð2 #Ð "Ð "Ð "Ð "Ð "à 	€	€	€	Ø %Ð %Ð %Ð %Ð %Ð %Ð %Ð %ð €ð
ð 
ð 
ð 
ðð ð ð ð.
ð 
ð 
ð 
ð	ð 	ð 	ð 	ð	ð 	ð 	ð 	ðð ð ð ðð ð ð ð  ØØØØØØð<€ð ð ð ñ ð 
Jð 
Yð 
Sð$ð $Ð ð ð ð ñ ð+ð +ð +ð +ð +ð +r   