Ë
    ãß²jõ7  ã            !       óD  — d Z ddlZddlZddlZddlmZmZmZ  ej                  d«      Z	dZ
dZdZdZd	ed
efd„Zd$d„Zd„ Zd„ Zd$d„Zdddœd	ededededee   dedee   dedededeee      dee   dedee   ded
ef d„Zd Zd!Zd	ededee   dedee   defd"„Zd$d#„Zy)%ab  Background-process launch path: ``terminal(background=true)`` spawns a tracked
process via the process registry (Popen locally, ``env.execute`` in a sandbox),
stamps gateway routing metadata for completion / watch-pattern notifications and
returns the JSON result. Lazy ``tools.terminal_tool`` imports keep the origin's
monkeypatch points authoritative.
é    N)ÚAnyÚListÚOptionalztools.terminal_toolu  background=true without notify_on_complete=true means this process runs SILENTLY â€” you will not be told when it exits. If this is a bounded task (test suite, build, CI poller, deploy, anything with a defined end), you almost certainly wanted notify_on_complete=true so the system pings you on exit. Re-launch with notify_on_complete=true, or call process(action='poll') / process(action='wait') yourself to learn the outcome. Only ignore this hint for genuine long-lived processes that never exit (servers, watchers, daemons).uU  This looks like a homebrewed CI poller built from `gh pr view --json statusCheckRollup` and/or `gh pr checks | jq`. That shape has burned us repeatedly in hermes-agent dev work (PRs #31329, #31448, #31695, #31709, #31745, #32264, #33131) â€” stdout buffering kills output capture, jq null-key edge cases silently exit the loop, conclusion-vs-status field confusion exits early with bogus all-green verdicts, TTY-only summary banners never appear when piped. Use the canonical snippets in the green-ci-policy skill instead: the exit-code-driven `gh pr checks $PR >/dev/null` (rc 0 = green, 8 = pending, else fail) for exit-on-first-fail behavior, or the column-2 awk-on-tabs poller (`awk -F"\t" "$2==\"pending\""`) for sharded matrices. Load skill_view(name='github/hermes-agent-dev', file_path='references/green-ci-policy.md') for the verbatim snippets. If you must roll a custom loop with rich structured output, write each tick to a known file (`tee -a $TMPDIR/ci.log`) and rely on `process(action='log')` to read THAT file â€” do not rely on background-process stdout capture for line-buffered shell loops.u\  notify_on_complete / watch_patterns are not available in this session â€” it cannot receive an async completion after the turn ends (a one-shot runner such as `hermes -z`, a cron job, a Kanban worker, or a stateless HTTP endpoint). The process is running in the background; retrieve its result with process(action='poll') or process(action='wait').))Úwatcher_chat_idÚHERMES_SESSION_CHAT_ID)Úwatcher_user_idÚHERMES_SESSION_USER_ID)Úwatcher_user_nameÚHERMES_SESSION_USER_NAME)Úwatcher_thread_idÚHERMES_SESSION_THREAD_ID)Úwatcher_message_idÚHERMES_SESSION_MESSAGE_ID)Úparent_session_idÚHERMES_SESSION_IDÚcommandÚreturnc                 óN   — d| v xs d| v }d| v xs
 d| v xs d| v }d| v xs |xr |S )Nz
gh pr viewzgh pr checksz jq z| jqz$(jqÚstatusCheckRollup© )r   Úhas_ghÚhas_jqs      úC/home/ubuntu/.hermes/hermes-agent/tools/terminal_tool_background.pyÚ_looks_like_homebrew_ci_pollerr   G   sI   € Ø˜WÐ$ÒA¨¸'Ð(A€FØ�wÐÒH &¨GÐ"3ÒH°vÀÐ7H€Fà 'Ð)Ò@¨fÒ.?¸Ð@ó    c           	      ón   —  |dd«      }|sy|| _         t        D ]  \  }}t        | | ||d«      «       Œ y)z‡Copy the spawning chat's routing metadata onto the process session so
    completion / watch notifications reach the right chat/thread.ÚHERMES_SESSION_PLATFORMÚ N)Úwatcher_platformÚ_ROUTING_FIELDSÚsetattr)Úproc_sessionÚget_session_envÚplatformÚattrÚvars        r   Ú_stamp_gateway_routingr'   N   sE   € ñ Ð8¸"Ó=€HÙØØ$,€LÔ!Ü$ò >‰	ˆˆcÜ�˜d¡O°C¸Ó$<Õ=ñ>r   c                ó¶   — t        ||||xs ||¬«      }	|dk(  r- | j                  dt        |d«      r|j                  nd |dœ|	¤ŽS  | j                  dd|i|	¤ŽS )N)r   ÚcwdÚtask_idÚowner_task_idÚsession_keyÚlocalÚenv)Úenv_varsÚuse_ptyr   )ÚdictÚspawn_localÚhasattrr.   Úspawn_via_env)
Úprocess_registryr.   Úenv_typer   r)   Úeffective_task_idr*   r,   Úeffective_ptyÚcommons
             r   Ú_spawnr:   Y   s~   € ä˜' sÐ4EØ 'Ò <Ð+<È+ôW€Fà�7ÒØ+Ð×+Ñ+ð `Ü '¨¨UÔ 3�S—W’W¸À}ñ`ØX^ñ`ð 	`à)Ð×)Ñ)Ñ<¨cÐ<°VÑ<Ð<r   c                 ó®   — |s|s||fS ddl m}m}  |«       rt        | |«       ||fS d|d<   t        |d<   t
        j                  d| j                  «       y)zâFinite sessions (stateless HTTP, one-shot Kanban workers) can't route a
    completion back after the turn ends: drop the flags and tell the agent to
    poll. Otherwise stamp gateway routing. Returns (notify, watch_patterns).r   ©Úasync_delivery_supportedr#   FÚnotify_on_completeÚnotify_unsupportedzjbackground proc %s: async delivery unsupported on this session; notify_on_complete/watch_patterns disabled)FN)Úgateway.session_contextr=   r#   r'   Ú_ASYNC_UNSUPPORTED_NOTEÚloggerÚinfoÚid)r"   Úresult_datar>   Úwatch_patternsr=   r#   s         r   Ú_apply_async_supportrG   c   se   € ñ ¡.Ø! >Ð1Ð1ßQáÔ!Ü˜|¨_Ô=Ø! >Ð1Ð1Ø(-€KÐ$Ñ%Ü(?€KÐ$Ñ%Ü
‡K�Kð FØGSÇÁôXàr   c           
      ó¸  — d|_         |j                  d||j                  dœt        dd D ��ci c]!  \  }}|j	                  d«      t        ||«      “Œ# c}}¥d|j                  dœ¥}t        t        j                  j                  d«      d	d«      }t        |«      r |«       nd}|�|j                  |«      ry| j                  j                  |«       yc c}}w )
að  Gateway mode: register a fast watcher so completion triggers a new
    agent turn (CLI mode uses the completion_queue directly).

    Armed on the live gateway loop right away: the post-turn drain alone leaves a
    process that finishes while its launching turn is still running unwatched, and
    the chat mute for as long as that turn lasts (#112033). Before the gateway
    serves, or while it stops, the descriptor waits in ``pending_watchers`` for the
    startup / post-turn drain instead.é   )Ú
session_idÚcheck_intervalr,   r$   NéÿÿÿÿÚwatcher_T)r>   r   zgateway.runÚ_gateway_runner_ref)Úwatcher_intervalrD   r   r    ÚremoveprefixÚgetattrr   ÚsysÚmodulesÚgetÚcallableÚarm_process_watcherÚpending_watchersÚappend)r5   r"   r,   r%   Ú_ÚwatcherÚ
runner_refÚrunners           r   Ú_register_completion_watcherr]   u   sÖ   € ð %&€LÔ!à"—o‘o¸È;Ø ×1Ñ1ñô *¨#¨2Ð.÷0Ùˆt�Qð ×Ñ˜ZÓ(¬'°,ÀÓ*EÑEó 0ðð
 #¸×9WÑ9Wò€Gô œŸ™Ÿ™¨Ó7Ð9NÐPTÓU€JÜ% jÔ1‰ZŒ\°t€FØÐ˜f×8Ñ8¸ÔAØØ×%Ñ%×,Ñ,¨WÕ5ùó0s   ®&C)Úcompletion_output_charsÚheartbeat_secondsr.   r6   r7   r*   r,   Úworkdirr)   r8   r>   rF   Úapproval_noter^   Úpty_disabled_reasonr_   c                 óª  — ddl m} ddlm}m}m}  |||||¬«      }	 t        |||| |||||¬«	      }d|j                  |j                  dddœ}|r||d	<   |r||d
<   |	s|
s	t        |d<   | r4t        | «      r)|j                  dd«      }|r|dz   t        z   nt        |d<   t        |||	|
«      \  }	}
 |t        |	«      |
d¬«      \  }
}|r&t        j!                  d|j                  |«       ||d<   |	rkd|_        d|d<   |rt%        |«      |_        |j(                  rt+        |||«       ddlm}  |«       rd|d<   t0        |d<   n|r|j3                  ||«      |d<   n|rd|d<   |
rt5        |
«      |_        |j6                  |d<   t9        j:                  |d¬«      S # t<        $ r.}t9        j:                  dd |d|› �«      dœd¬«      cY d}~S d}~ww xY w)zéSpawn *command* as a tracked background process and return the JSON result.

    Never inline-polls ``is_interrupted()``: the spawn detaches and returns
    exit_code 0 immediately, so the stale-interrupt kill cannot occur here.
    r   ©r5   )Ú_redact_terminal_error_textÚ_resolve_command_cwdÚ#_resolve_notification_flag_conflict)r`   Údefault_cwdr,   r6   )r.   r6   r   r)   r7   r*   r,   r8   zBackground process startedN)ÚoutputrJ   ÚpidÚ	exit_codeÚerrorÚapprovalÚpty_noteÚhintr   z

T)r>   rF   Ú
backgroundzbackground proc %s: %sÚwatch_patterns_ignoredr>   )Úis_delegated_child_contextFÚsubagent_noter_   zGheartbeat needs notify=true delivery, which this session cannot receiveÚheartbeat_ignoredrF   )Úensure_asciirL   z$Failed to start background process: )ri   rk   rl   )Útools.process_registryr5   Útools.terminal_toolre   rf   rg   r:   rD   rj   Ú_SILENT_BACKGROUND_HINTr   rT   Ú_HOMEBREW_CI_POLLER_HINTrG   ÚboolrB   Úwarningr>   Úintr^   r   r]   Úagent.delegation_contextrr   Ú_SUBAGENT_NOTIFY_NOTEÚarm_heartbeatÚlistrF   ÚjsonÚdumpsÚ	Exception)r   r.   r6   r7   r*   r,   r`   r)   r8   r>   rF   ra   r^   rb   r_   r5   re   rf   rg   Úeffective_cwdr"   rE   ÚexistingÚconflict_noterr   Úes                             r   Úspawn_background_processrˆ   �   s(  € õ 8÷ñ ñ )Ø S°kÈHô€Mð4ÜØ #°À'È}Ø/¸ÈkØ'ô
ˆð
 ">È\Ï_É_Ø*×.Ñ.¸QÈñOˆáØ&3ˆK˜
Ñ#ÙØ&9ˆK˜
Ñ#Ù!©.Ü"9ˆK˜ÑÙÔ5°gÔ>Ø"—‘ v¨rÓ2ˆHÙS[ 8¨fÑ#4Ô7OÒ#OÜ(@ð ˜Ñô .BØ˜+Ð'9¸>ó.KÑ*Ð˜Ná(KÜ#Ð$6Ó7ÈÐcgô)
Ñ%ˆ˜ñ Ü�N‰NÐ3°\·_±_ÀmÔTØ4AˆKÐ0Ñ1ÙØ.2ˆLÔ+Ø04ˆKÐ,Ñ-Ù&Ü7:Ð;RÓ7S�Ô4Ø×,Ò,Ü,Ð-=¸|È[ÔYÝKÙ)Ô+Ø49�Ð0Ñ1Ü/D�˜OÒ,Ù"ð 4D×3QÑ3QÐR^Ð`qÓ3r�Ð/Ò0ÙØ/xˆKÐ+Ñ,ÙÜ*.¨~Ó*>ˆLÔ'Ø,8×,GÑ,GˆKÐ(Ñ)Ü�z‰z˜+°EÔ:Ð:øÜò Ü�z‰zØ rÙ0Ð3WÐXYÐWZÐ1[Ó\ñ
ð ôõ 	ûðús   žE<F Æ	GÆ$#GÇGÇGa£  You are a subagent: this process's completion notice will NOT reach your parent, and the process is killed when you finish. Before you finish, either wait for it (process_manage wait), kill it, or hand it to your parent with process_manage(action='handoff', session_id=..., data='<purpose>') so the parent receives its completion. For CI watchers prefer returning the fact (PR number, SHA) and letting the parent watch.a>  The user sent a message while this command was running, so it was moved to the background WITHOUT being killed and is still running. You will be notified when it exits (notify_on_complete). Read the user's message and respond to it now; use process(action='poll'|'wait'|'log', session_id=...) to check on this command.c                 óH   ‡ ‡‡‡‡— |dk7  rydt         dt        fˆ ˆˆˆˆfd„}|S )a¢  Build the ``yield_handler`` a foreground ``env.execute`` calls when the tool thread is
    asked to yield (a user message arrived mid-command). Local backend only: the live Popen
    is adopted by the process registry as a notify-on-complete background session and the
    partial output is returned to the model right away. Other backends return None (no
    adoptable host process) and the foreground wait continues.r-   NÚoutput_so_farr   c           	      óî   •— ddl m} |j                  | ‰‰‰‰xs ‰‰|¬«      }t        ||‰«       t        j                  d|j                  |j                  «       |d |j                  |j                  dœS )Nr   rd   )r   r)   r*   r+   r,   rŠ   z7foreground command yielded to background as %s (pid %s))ri   Ú
returncodeÚyielded_session_idrj   )rv   r5   Úadopt_localÚ_stamp_routing_if_gatewayrB   rC   rD   rj   )	ÚprocrŠ   r5   Úsessionr   r)   r7   r,   r*   s	       €€€€€r   Ú_handlerz-yield_to_background_handler.<locals>._handlerô   s|   ø€ Ý;Ø"×.Ñ.Ø˜' sÐ4EØ!Ò6Ð%6ÀKØ'ð /ó )ˆô 	"Ð"2°G¸[ÔIÜ�‰ÐMÈwÏzÉzÐ[b×[fÑ[fÔgà#°4ÈwÏzÉzÐbi×bmÑbmñ
ð 	
r   )Ústrr1   )r   r6   r)   r7   r*   r,   r’   s   ` ```` r   Úyield_to_background_handlerr”   è   s/   ü€ ð �7ÒØð

¤cð 

¬d÷ 

ñ 

ð €Or   c                 ó~   — ddl m}m}  |«       sd|_        yt	        ||«       |j
                  rt        | ||«       yy)zNRoute the adopted session's completion like a normal notify_on_complete spawn.r   r<   FN)r@   r=   r#   r>   r'   r   r]   )r5   r‘   r,   r=   r#   s        r   r�   r�     s;   € çQÙ#Ô%Ø%*ˆÔ"ØÜ˜7 OÔ4Ø×ÒÜ$Ð%5°wÀÕLð  r   )r   N)Ú__doc__r�   ÚloggingrR   Útypingr   r   r   Ú	getLoggerrB   rx   ry   rA   r    r“   rz   r   r'   r:   rG   r]   r|   rˆ   r~   Ú_YIELDED_NOTEr”   r�   r   r   r   ú<module>r›      s¢  ðñó Û Û 
ß &Ñ &à	ˆ×	Ñ	Ð0Ó	1€ðð ð ð ð$]ð ð
€ðA¨Cð A°Dó Aó>ò=òó$6ð8 $%àòIØðIØðIØ),ðIØADðIØOWÐX[É}ðIàðIà'¨™}ðIà36ðIàGKðIð ðIð /7°t¸C±yÑ.AðIð S[Ð[^ÑR_ðIð !ð	Ið
 " #™ðIð ðIð 	óIðZXð ðTð ðØðØ"ðØ)1°#©ðØKNðà�c‰]ðà),óô4Mr   