+
    jHàjg^  ã            
       ój  € R t ^ RIt^ RI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Ht ^ RIHtHtHt ^ RIHtHt ^ RIHtHt ^ RIHt ^ RIHtHt ^ R	IHt ^ R
I H!t! ]PD                  ! R4      t#]! 4       t$]! 4       t%]! RR4      t&]! R4      t']! RR4      t(]! RR4      t)]! RR4      t*]! RR4      t+]! RR4      t,]! RR4      t-]! RR4      t.]! RR4      t/R R lt0RRt1RSt2RTt3]Ph                  ! R4      t5]Ph                  ! R4      t6Rt7RR R!R R"R R#R$R%R&/t8R' R( lt9RUR) R* llt:R+ R, lt;R- R. lt<R/ R0 lt=R1 R2 lt>]$P                  R34      RVR4 R5 ll4       t@]$Pƒ                  R64      R7 4       tB]$P                  R84      R9 4       tC]$P                  R:4      R; R< l4       tDR= R> ltE]$P                  R?4      R@ 4       tFR]R#RA /tGRB RC ltH]$Pƒ                  RD4      RWRE RF ll4       tIRG RH ltJ]%Pƒ                  RI4      RXRJ RK ll4       tKRL RM ltLRVRN RO lltM]%Pƒ                  RP4      RQ 4       tNR# )YzâGateway restart/drain, Hermes update and background-action status dashboard routes.

Extracted from ``hermes_cli.web_server``; helpers/state that tests monkeypatch on
``web_server`` stay there and are late-bound (cycle-safe).
N)ÚPath)ÚAnyÚDictÚListÚOptional)Ú	APIRouterÚHTTPExceptionÚRequest)Úformat_docker_update_messageÚ%recommended_update_command_for_method)ÚCOMMIT_BUILD_UPDATE_MESSAGEÚis_commit_build)Úget_version_info)Ú	LateStateÚlate)Ú_ACTION_LOG_FILES)Úhttp_failurezhermes_cli.web_serverÚ*_dashboard_local_update_managed_externallyzhermes_cli.web_server_filesÚ_spawn_gateway_restartÚ_spawn_hermes_actionzhermes_cli.web_server_gatewayÚdetect_install_methodzhermes_cli.configÚget_hermes_homeÚ_config_profile_scopezhermes_cli.web_server_profilesÚ_ACTION_COMMANDSÚ_ACTION_IDSÚ_ACTION_PROCSÚ_ACTION_RESULTSc                ó0   € V ^8„  d   QhR\         R\        /# )é   ÚnameÚreturn)Ústrr   )Úformats   "ÚC/home/ubuntu/.hermes/hermes-agent/hermes_cli/web_routers/actions.pyÚ__annotate__r$   +   s   € ÷ Bñ B”sð Bœtñ Bó    c                óL   € ^ RI Hp ^ RIHp \	        V R8X  d   W 4      # TV 4      # )z‡Live Path value (``_ACTION_LOG_DIR`` on web_server_gateway, ``PROJECT_ROOT`` on
web_server; plain values are not proxied by LateState).NÚ_ACTION_LOG_DIR)Úhermes_cli.web_serverÚ
web_serverÚhermes_cli.web_server_gatewayÚweb_server_gatewayÚgetattr)r   ÚwsÚgws   &  r#   Ú_server_pathr/   +   s'   € õ 'Ý.Ü˜Ð!2Ô2�2ÓAÐA¸¸DÓAÐAr%   z0^=== hermes-update completed ([0-9a-f]{32}) ===$z1^=== hermes-update started .* ([0-9a-f]{32}) ===$zPHermes updates are managed outside this dashboard in containerized environments.ÚdockerÚdocker_update_unsupportedzimage-markerzimage-marker-invalidÚaptÚapt_update_requiredÚnixÚnix_update_unsupportedc                ól   € V ^8„  d   QhR\         R\        \        ,          R\        \        ,          RR/# )r   r   Ú	exit_codeÚpidr    N)r!   r   Úint)r"   s   "r#   r$   r$   D   s0   € ÷ !ñ !œð !¬´#­ð !¼XÄc½]ð !Ètñ !r%   c                ót   € RVRV/\         V &   \        \        \        3 F  pVP	                  V R4       K  	  R# )zKRecord a terminal result and drop the live-process registries for ``name``.r7   r8   N)r   r   r   r   Úpop)r   r7   r8   Úregistrys   &&& r#   Ú_finish_actionr=   D   s6   € à(¨)°U¸CÐ@„O�DÑÜ"Ô$4´kÓBˆØ�‰�T˜4Ö ó Cr%   c                ó@   € V ^8„  d   QhR\         R\         R\        RR/# )r   r   Úmessager7   r    N©r!   r9   )r"   s   "r#   r$   r$   K   s(   € ÷ 	*ñ 	*¤3ð 	*´ð 	*Äð 	*ÈTñ 	*r%   c           
     óê  € \        R4      pVP                  RRR7       \        V\        V ,          ,          R^ R7      ;_uu_ 4       pVP	                  RV  R\
        P                  ! R4       R	2P                  4       4       VP	                  VP                  R
RR7      4       VP                  R4      '       g   VP	                  R4       RRR4       \        WR4       R#   + '       g   i     L; i)zBRecord a non-spawned action result and write it to the action log.r'   T)ÚparentsÚexist_okÚab)Ú	bufferingz
=== z completed z%Y-%m-%d %H:%M:%Sz ===
úutf-8Úreplace©ÚerrorsÚ
ó   
N)
r/   ÚmkdirÚopenr   ÚwriteÚtimeÚstrftimeÚencodeÚendswithr=   )r   r?   r7   Úlog_dirÚlog_files   &&&  r#   Ú_record_completed_actionrU   K   s»   € äÐ,Ó-€GØ‡M�M˜$¨€MÔ.Ü	ˆgÔ)¨$Õ/Õ/°À×	CÕ	CÀxØ�‰˜ ˜v [´·²Ð?RÓ1SÐ0TÐTZÐ[×bÑbÓdÔeØ�‰�w—~‘~ g°i�~Ó@ÔAØ×Ñ ×%Ò%Ø�N‰N˜5Ô!÷	 
Dô
 �4 DÖ)÷ 
D×	Cús   ÁBC"Ã"C2	c                óR   € V ^8„  d   QhR\         R\        R\        \        ,          /# )r   ÚpathÚnr    )r   r9   Úlistr!   )r"   s   "r#   r$   r$   W   s%   € ÷ "ñ "”dð "œsð "¤t¬C¥yñ "r%   c                ó€  €  V P                  4       P                  pT^ 8:  g   T^ 8:  d   . # \        ^ T\        ,
          4      pTp\
        p^ p. pRp T P                  R4      ;_uu_ 4       p	YC8”  d„   Ya8:  d~   \        YTT,
          4      p
YJ,          pT	P                  T4       T	P                  T
4      pTP                  T4       YkP                  R4      ,          p\        T^,          \        4      pK‰  T^ 8”  d-   T	P                  T^,
          4       T	P                  ^4      R8g  pRRR4       RP                  \        T4      4      P                  RRR7      P!                  4       pT'       d   T'       d
   TR	,          pYÁ) R #   \         d    . u # i ; i  + '       g   i     Lz; i  \         d    . u # i ; i)
zBReturn the last ``n`` lines of ``path`` without loading huge logs.FÚrbrK   Nr%   rF   rG   rH   :é   NN)ÚstatÚst_sizeÚOSErrorÚmaxÚ_ACTION_LOG_TAIL_MAX_BYTESÚ$_ACTION_LOG_TAIL_INITIAL_CHUNK_BYTESrM   ÚminÚseekÚreadÚappendÚcountÚ _ACTION_LOG_TAIL_MAX_CHUNK_BYTESÚjoinÚreversedÚdecodeÚ
splitlines)rW   rX   ÚsizeÚ
min_offsetÚoffsetÚ
chunk_sizeÚnewline_countÚchunksÚdrop_partial_first_lineÚhandleÚ	read_sizeÚchunkÚliness   &&           r#   Ú_tail_linesrx   W   s€  € ðØ�y‰y‹{×"Ñ"ˆð 	ˆA„v�˜”Øˆ	ä�Q˜Ô9Õ9Ó:€JØ€FÜ5€JØ€MØ€FØ#ÐðØ�Y‰Y�t�_Œ_ ØÔ%¨-Ô*<Ü 
°ZÕ,?Ó@�	ØÕ#�Ø—‘˜FÔ#ØŸ™ IÓ.�Ø—‘˜eÔ$Ø§¡¨UÓ!3Õ3�Ü  ¨a¥Ô1QÓR’
Ø˜ŒzØ—‘˜F Q�JÔ'Ø*0¯+©+°a«.¸EÑ*AÐ'÷ ð �H‰H”X˜fÓ%Ó&×-Ñ-¨g¸iÐ-ÓH×SÑSÓU€Eß§5Ø�b•	ˆØ��ˆ:Ðøô= ô ØŠ	ðú÷ �_ûô ô ØŠ	ðúsB   ‚F ÁF- Á+B=FÄ(F- ÆFÆFÆF*	Æ%F- Æ*F- Æ-F=Æ<F=c                ó\   € V ^8„  d   QhR\         \        ,          R\        \        ,          /# ©r   rw   r    ©rY   r!   r   )r"   s   "r#   r$   r$   |   s&   € ÷ `ñ `¬t´C­yð `¼XÄc½]ñ `r%   c                ó
  € R;rRp\        V 4       F^  w  rEVP                  R4      '       d   Tp\        P                  VP	                  4       4      pV'       g   KK  TpVP                  ^4      pK`  	  V'       d	   W!8”  d   V# R# )u"  Latest successful update id from ``update.log`` â€” the durable record that survives
the update restarting the dashboard (losing the in-memory ``Popen``/result registries).
Only a completion marker after the latest start marker counts, so a stale success
cannot mask a newer failed attempt.Nz=== hermes update started éÿÿÿÿ)Ú	enumerateÚ
startswithÚ_UPDATE_ACTION_COMPLETED_REÚ	fullmatchÚstripÚgroup)rw   Ú
last_startÚlast_completedÚcompleted_action_idÚindexÚlineÚmatchs   &      r#   Ú#_durable_completed_update_action_idrŠ   |   s|   € ð
 #%Ð$€JØ)-ÐÜ  Ö'‰ˆØ�?‰?Ð7×8Ò8ØˆJÜ+×5Ñ5°d·j±j³lÓCˆß‰5Ø"ˆNØ"'§+¡+¨a£.Òñ (÷ #6¸.Ô:UÐÐ_Ð[_Ð_r%   c                ó\   € V ^8„  d   QhR\         \        ,          R\        \        ,          /# rz   r{   )r"   s   "r#   r$   r$   �   s"   € ÷ ñ ¬D´­Ið ¼(Ä3½-ñ r%   c                óÜ   € \        V 4       F\  pVP                  R4      '       g   K  \        P                  VP	                  4       4      pV'       d   VP                  ^4      u # Ru # 	  R# )zWAction id named by the latest ``hermes-update started`` header of THIS dashboard's log.z=== hermes-update started N)rj   r   Ú_UPDATE_ACTION_STARTED_REr�   r‚   rƒ   )rw   rˆ   r‰   s   &  r#   Ú _latest_spawned_update_action_idrŽ   �   sP   € ä˜–ˆØ�?‰?Ð7×8Ô8Ü-×7Ñ7¸¿
¹
»ÓEˆEß%*�5—;‘;˜q“>Ò4°Ò4ñ  ñ r%   c                óR   € V ^8„  d   QhR\         R\        R\        \        ,          /# )r   rS   r   r    )r   r!   r   )r"   s   "r#   r$   r$   –   s%   € ÷ ñ ¤$ð ¬cð ´h¼sµmñ r%   c                ó"  € \         P                  ! \        \        4      ;_uu_ 4        W R2,          P	                  RR7      P                  4       p\        P                  ! RV4      '       d   TMRuuRRR4       #   + '       g   i     R# ; i)zéAction id of the latest spawn of ``name`` from its sidecar (survives the log's tail
bound and rotation). A visible start header wins: a dashboard predating the sidecar wrote
only the header, and the newest header IS the latest spawn.z
.action_idz	utf-8-sig)Úencodingz[0-9a-f]{32}N)Ú
contextlibÚsuppressr_   ÚUnicodeDecodeErrorÚ	read_textr‚   Úrer�   )rS   r   Úvalues   && r#   Ú_persisted_action_idr˜   –   sg   € ô 
×	Ò	œWÔ&8×	9Õ	9Ø˜V :Ð.Õ.×9Ñ9À;Ð9ÓO×UÑUÓWˆÜŸš _°e×<Ò<‰uÀ$÷ 
:×	9×	9Ñ	9ñ ús   ¨A
A=Á=B	z/api/gateway/restartc                ó:   € V ^8„  d   QhR\         \        ,          /# )r   Úprofile)r   r!   )r"   s   "r#   r$   r$   ¡   s   € ÷ Dñ D¤8¬C¥=ñ Dr%   c              ƒ  ó®   "  € \        RRR4      ;_uu_ 4        \        V RR7      w  rRRR4       RRRXP                  R	R
/#   + '       g   i     L"; i5i)z°Kick off a ``hermes gateway restart --interrupt`` in the background: the user-commanded force
path that supersedes a drain (D6, 19b26244046), so live sessions do not refuse it.zFailed to spawn gateway restartéô  zFailed to restart gatewayT)Ú	interruptNÚokr8   r   zgateway-restart)r   r   r8   )rš   ÚprocÚ_reuseds   &  r#   Úrestart_gatewayr¡       sM   é € ô 
Ð7¸Ð>Y×	ZÕ	ZÜ.¨wÀ$ÔG‰ˆ÷ 
[à�$˜˜tŸx™x¨Ð1BÐCÐC÷ 
[×	Züs   ‚A˜A¨AÁA	ÁAz/api/gateway/migrate/planc               ƒ  óv   "  € ^ RI Hp  \        P                  ! V 4      G Rj  x€L
 pVP	                  4       #  L5i)z\Preflight for folding per-profile gateways into one multiplexer (same JSON as the CLI plan).)Úbuild_migration_planN)Úhermes_cli.gateway_migrater£   ÚasyncioÚ	to_threadÚto_dict)r£   Úplans     r#   Úgateway_migrate_planr©   ©   s0   é € õ @Ü×"Ò"Ð#7Ó8×8€DØ�<‰<‹>Ðñ 9ùs   ‚ 9¢7£9z/api/gateway/migratec               ƒ  ó²   "  € ^ RI Hp  \        RRR4      ;_uu_ 4        V ! . ROR4      pRRR4       RRR	XP                  R
R/#   + '       g   i     L"; i5i)z¸Run ``hermes gateway migrate --multiplex --yes`` detached; the CLI re-runs the preflight and
refuses (exit 1 into the action log) when blocked, so the UI should gate on the plan first.)r   zFailed to spawn gateway migraterœ   z!Failed to start gateway migrationzgateway-migrateNrž   Tr8   r   )ÚgatewayÚmigratez--multiplexz--yes)r*   r   r   r8   )r   rŸ   s     r#   Úgateway_migrater­   ±   sQ   é € õ CÜ	Ð7¸Ð>a×	bÕ	bÙ#Ò$RÐTeÓfˆ÷ 
cà�$˜˜tŸx™x¨Ð1BÐCÐC÷ 
c×	büs   ‚AžAªAÁA	ÁAz/api/gateway/drainc                ó$   € V ^8„  d   QhR\         /# )r   Úrequest)r	   )r"   s   "r#   r$   r$   ¼   s   € ÷ *ñ *¤ñ *r%   c              ƒ  ó¶  "  € ^ RI HpHpHp  V P	                  4       G Rj  x€L
 pT;'       g    / p\        VP                  RR4      4      P                  4       P                  4       p\        \        V P                  RR4      RR4      ;'       g    RpVR8X  d&   V! 4       p\        P                  R	Wg4       R
RRRRV/# VR8w  d   \        RRV: R2R7      hV! \        V4      \        VP                  RR4      4      R7      p\        P                  RWhR,          4       R
RRRRVR,          RV! 4       RVR,          /#  EL!  \
         d    / p EL/i ; i5i)u«  Begin or cancel an external (NAS-driven) gateway drain.

Authenticated by the non-interactive token-auth seam (the ``dashboard_auth/drain``
plugin registers this path as a token route and verifies the bearer secret);
without that plugin the cookie gate covers a gated bind and the legacy
session-token gate a loopback bind â€” never unauthenticated on a network bind.

Body ``{"action": "drain"|"cancel"}``. Only the ``.drain_request.json`` marker is
written/removed here â€” the gateway's ``_drain_control_watcher`` owns the state
transition (the marker IS the control channel). Idempotent on both sides;
``POST /api/gateway/restart`` is the force-override that supersedes a drain.
)Úclear_drain_requestÚdrain_requestedÚwrite_drain_requestNÚactionÚdrainÚtoken_principalÚ	principalÚ	dashboardÚcancelz1Gateway drain CANCEL requested by %s (existed=%s)rž   TÚwas_drainingi�  zUnknown drain action z; expected 'drain' or 'cancel'©Ústatus_codeÚdetailÚsuppress_notificationF)r·   r¾   z>Gateway drain BEGIN requested by %s (suppress_notification=%s)Úrequested_atÚdraining)Úgateway.drain_controlr±   r²   r³   ÚjsonÚ	Exceptionr!   Úgetr‚   Úlowerr,   ÚstateÚ_logÚinfor   Úbool)	r¯   r±   r²   r³   Úbodyr´   r·   ÚexistedÚpayloads	   &        r#   Úgateway_drainrÍ   »   sV  é € ÷ `Ñ_ðØ—\‘\“^×#ˆð �:ˆ:�2€DÜ�—‘˜( GÓ,Ó-×3Ñ3Ó5×;Ñ;Ó=€Fäœ §¡Ð/@À$ÓGÈÐVZÓ[×jÐjÐ_j€Ià�ÔÙ%Ó'ˆÜ�	‰	ÐEÀyÔZØ�d˜H h°ÀÐHÐHØ�ÔÜ¨Ð6KÈFÉ:ÐUsÐ4tÔuÐuá!Ü�i“.¼¸T¿X¹XÐF]Ð_dÓ=eÓ8fô€Gô 	‡I�IØHÈ)Ð]tÕUuôð 	ˆd�H˜g ~°w¸~Õ7Nð 	‘OÓ%Ð'>ÀÐH_Õ@`ð	ð ò+ $øÜô Ø‹ðüs=   ‚EŽE ¡E¢E ¦E¯DEÅE ÅEÅEÅEÅEc          
      ój   € V ^8„  d   QhR\         R\         R\         R\        \         \        3,          /# )r   Úerrorr?   Úupdate_commandr    )r!   Údictr   )r"   s   "r#   r$   r$   é   s1   € ÷ ñ œ3ð ¬ð ¼cð ÄdÌ3ÔPSÈ8Ånñ r%   c                 ó:   € \        R V^R7       RRRRRR RV RVR	V/# )
úhermes-update)r7   rž   Fr8   Nr   rÏ   r?   rÐ   )rU   )rÏ   r?   rÐ   s   &&&r#   Ú_update_refusedrÔ   é   s3   € Ü˜_¨gÀÕCàˆe�U˜D &¨/¸7ÀEÈ9ÐV]Ø˜.ðð r%   z/api/hermes/updatec               ƒ  ó  "  € \        \        R4      4      '       d   \        R\        R4      # \	        4       '       d   \
        R,           p \        RV R4      # ^ RIHpHp V! \        R4      4      pVeJ   \        \        P                  VP                  R4      VP                  VP                  4      pV! V4       V# \        P                  R	4      pVeJ   VP                  4       f8   R
RRVP                   RR	RR/p\"        P                  R	4      pV'       d   WdR&   V# \$        P&                  ! ^4      p\)        RRR4      ;_uu_ 4        \+        R.R	RV/R7      pRRR4       R
RRXP                   RR	RV/#   + '       g   i     L$; i5i)z-Kick off ``hermes update`` in the background.ÚPROJECT_ROOTzcommit-buildÚ z- The built-in local updater is disabled here.Ú#dashboard_update_managed_externally)Úevaluate_update_admissionÚrecord_refusal_receiptNÚupdate_not_in_placerÓ   rž   Tr8   r   Úalready_runningÚ	action_idzFailed to spawn hermes updaterœ   zFailed to start updateÚupdateÚHERMES_ACTION_ID)Úenv_overrides)r   r/   rÔ   r   r   Ú_MANAGED_EXTERNALLY_MESSAGEÚhermes_cli.update_contractrÙ   rÚ   Ú_UPDATE_REFUSAL_ERROR_CODESrÄ   Úcoder?   rÐ   r   Úpollr8   r   ÚsecretsÚ	token_hexr   r   )r?   rÙ   rÚ   ÚrefusalÚresponseÚexistingrÝ   rŸ   s           r#   Úupdate_hermesrë   ñ   sc  é € ô ”| NÓ3×4Ò4Ü˜~Ô/JÈBÓOÐOä1×3Ò3Ü-Ð0_Õ_ˆäÐDÀgÈrÓRÐR÷ ]á'¬°^Ó(DÓE€GØÒÜ"Ü'×+Ñ+¨G¯L©LÐ:OÓPÐRY×RaÑRaÐcj×cyÑcyó
ˆñ 	˜wÔ'Øˆä× Ñ  Ó1€HØÒ §¡£Ò 7Ø˜$  x§|¡|°V¸_ÐN_ÐaeÐfˆÜ—O‘O OÓ4ˆ	ßØ$-�[Ñ!Øˆä×!Ò! "Ó%€IÜ	Ð5°sÐ<T×	UÕ	UÜ# X J°ÐPbÐdmÐOnÔoˆ÷ 
Và�$˜˜tŸx™x¨°À+ÈyÐYÐY÷ 
V×	Uüs$   ‚DFÄ1FÅE9ÅFÅ9F		ÆFc                  ó   € R # )z@Hermes is managed by Termux APT; run `pkg upgrade hermes-agent`.© rí   r%   r#   Ú<lambda>rî     s   € ÑUr%   c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# )r   Ústatusr    )rÑ   r!   r   )r"   s   "r#   r$   r$     s&   € ÷ `ñ `¤$¤s¬C x¥.ð `´Sñ `r%   c                 ó”   € V P                  R 4      pV P                  R4      ;'       g    R R2V'       d   RV 2,           # R,           # )ÚsourceVersionÚchannelÚstablez releasez vr×   ©rÄ   )rð   Úversions   & r#   Ú_source_release_labelr÷     sE   € Ø�j‰j˜Ó)€GØ�j‰j˜Ó#×/Ð/ xÐ0°Ð9Ïw¸rÀ'À¸^Õ_Ð_Ð\^Õ_Ð_r%   z/api/hermes/update/checkc                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   Úforcerš   )rÉ   r   r!   )r"   s   "r#   r$   r$   "  s"   € ÷ Lñ L¤Tð L¼HÄS½Mñ Lr%   c              ƒ  ó   "  € \        \        R4      4      '       d'   RRR\        4       P                  RRRRR	RR
RR\        /# \        4       '       d'   RRR\        4       P                  RRRRR	RR
RR\        /# \        \        R4      4      pRVR\        4       P                  RRRRR	VR8H  R
\        V4      RR/p\        P                  V4      pVe   V! 4       VR&   V# / p ^ RIHp \        V4      ;_uu_ 4        \        P                  ! W`R7      G Rj  x€L
 pRRR4       VP                  R4      pWsR&   Vf   RVR&   V# V^ 8X  dS   VP                  R4      '       d<   VP                  R4      pVP'                  VR,          VR\)        V4       R2R7       V# V^ 8X  d   RVR&   V# RVR&   VP                  R4      '       d0   VP'                  VP                  R4      R\)        V4       R2R7       VP'                  VP                  R4      VP                  R4      VP                  R4      R7       VP                  R . 4      R!,           U	u. uF)  p	/ V	CR"V	R",          R#,          R$V	R$,          R%,          /CNK+  	  up	VR &   V#  ELr  + '       g   i     ELy; i  \          d    \"        P%                  R4       Rp EL�i ; iu up	i 5i)&uû  Report whether a Hermes update is available, without applying it.

Returns install_method ('apt'|'git'|'docker'|'nix'|'nixos'|'unknown'),
current_version, behind (commits behind, 0 = up to date, -1 = unknown count,
null = check could not run), update_available, can_apply (git only â€” the
dashboard button can apply in place), update_command, message (guidance for
non-applyable methods) and, for git installs that are behind, commits
[{sha, summary, author, at}] (additive; existing consumers ignore it).
rÖ   Úinstall_methodzdesktop-appÚcurrent_versionÚbehindNÚupdate_availableFÚ	can_applyrÐ   r×   r?   zmanaged-runtimeÚgit)Úcheck_for_updates)rù   zUpdate check failedu5   Couldn't reach the update source â€” try again later.Úheldrò   zThis build is newer than zj, which predates the gateway runtime its sessions use. It stays on this build until a newer release ships.)r  Úsource_versionr?   zYou're on the latest version.TÚrollbackz). Updating moves it back to that release.)Úrollback_tor?   ró   Úbranch)ró   r  r  Úcommits:Né   NÚsha:Né   NÚatiè  )r   r/   r   Úderived_versionr   r   rá   r   r   Ú_NON_APPLYABLE_MESSAGESrÄ   Úhermes_cli.source_checkr  r   r¥   r¦   rÃ   rÇ   Ú	exceptionrÞ   r÷   )
rù   rš   rû   rÌ   Únon_applyablerð   r  rý   rö   Úrows
   &&        r#   Úcheck_hermes_updater  !  s  é € ô ”| NÓ3×4Ò4à˜mØÔ/Ó1×AÑAØ�dÐ.°°{ÀEØ˜b )Ô-Hð	
ð 	
ô 2×3Ò3àÐ/ØÔ/Ó1×AÑAØ�dØ  {°EØ˜b )Ô-Hð
ð 	
ô +¬<¸Ó+GÓH€Nà˜.ØÔ+Ó-×=Ñ=Ø�$Ø˜E ;°À%Ñ0GØÔ?ÀÓOÐQZÐ\`ð€Gô ,×/Ñ/°Ó?€MØÒ Ù*›_ˆ�	ÑØˆð  €FðÝ=ä" 7×+Õ+Ü"×,Ò,Ð->ÔL×LˆF÷ ,à—‘˜HÓ%ˆð
 ˆHÑØ‚~ØTˆ�	Ñð* €Nð) 
�1Œ˜Ÿ™ F×+Ò+Ø—*‘*˜_Ó-ˆØ�‰˜F 6�N¸7Ø!:Ô;PÐQWÓ;XÐ:Yð Zoð  oð 	ô 	pð$ €Nð 
�1ŒØ<ˆ�	Ñð €Nð '+ˆÐ"Ñ#Ø�:‰:�j×!Ò!à�N‰N v§z¡z°/Ó'BØ%>Ô?TÐU[Ó?\Ð>]ð ^Mð $Mð ô Nð
 	�‰˜vŸz™z¨)Ó4¸V¿Z¹ZÈÓ=QØ&,§j¡j°Ó&Að 	ô 	Cð *0¯©°I¸rÓ)BÀ3Ö)GóIÙ)G #ð V ÐU e¨S°­Z¸­^¸TÀ3ÀtÅ9ÐPTÕCTÔUÙ)GñIˆ�	Ñà€Nò; M÷ ,×+Ð+ûô ô Ü�‰Ð,Ô-Ø‹ðüò2Iùsn   ‚C KÃ#J  Ã<JÄJ	ÄJÄJ  Ä5,KÅ"A$KÇBKÉ/K	ÊKÊ	JÊJ	Ê	J  Ê "KËKËKËKc          	      óä   € V ^8„  d   QhR\         \        \        \        3,          ,          R\         \        ,          R\         \        \        \        3,          ,          R\         \        ,          /# )r   ÚresultÚdurable_action_idÚreceiptr    )r   rÑ   r!   r   r9   )r"   s   "r#   r$   r$   q  sS   € ÷ ñ Ü”Tœ#œs˜(•^Õ$ðÜ9AÄ#½ðÜQYÔZ^Ô_bÔdgÐ_gÕZhÕQiðäŒc…]ñr%   c                óœ   € V e   V P                  R4      # V'       d   ^ # Ve)   VP                  R4      R9   d   VR,          R8X  d   ^ # ^# R# )zVExit code for an action with no live process: in-memory result, else durable evidence.Nr7   ÚoutcomeÚsuccess)r  Úpartialrõ   )r  r  r  s   &&&r#   Ú_completed_exit_coder  q  sR   € ð ÒØ�z‰z˜+Ó&Ð&ßÙØÒ˜wŸ{™{¨9Ó5Ð9OÔOð ˜IÕ&¨)Ô3ˆqÐ:¸Ð:Ùr%   z/api/actions/{name}/statusc                ó0   € V ^8„  d   QhR\         R\        /# )r   r   rw   r@   )r"   s   "r#   r$   r$   ‚  s   € ÷ :ñ :¤#ð :¬cñ :r%   c           
   ƒ  ód  "  € \         P                  ! V 4      pVf   \        RRV  2R7      h\        R4      p\	        \        V^4      R4      p\        W2,          V4      pRpR;rxV R8X  dÈ   ^ RIHp	 \        \        V	! R	4      R4      4      p\        \        W2,          R4      4      ;'       g)    \        W04      ;'       g    \        P                  V 4      p
Wj8w  d   RpV'       d   R
V R2pWµ9  d   . VOVNV) R p\        V
4      pV
'       d#   T;'       g    / P                  R4      V
8X  d   Tp\        P                  V 4      pVf@   \        P                  V 4      pRpV'       d   VP                  R4      MRp\!        WÖV4      pMnVP#                  4       pVRJ pVP$                  pVeK   \&        P(                  ! \*        4      ;_uu_ 4        VP-                  ^R7       RRR4       \/        V VV4       RV RVRVRVRV/pV'       d   VVR&   Ve   VVR&   V#   + '       g   i     LA; i5i)zCTail an action log and report whether the process is still running.Né”  zUnknown action: r»   r'   iÐ  rÓ   )Úlog_file_pathrÞ   z=== hermes-update completed z ===rÝ   Fr8   )Útimeoutr   Úrunningr7   rw   r  )r   rÄ   r   r/   rc   r`   rx   Úhermes_cli.logsr  rŠ   rŽ   r˜   r   Ú_latest_update_receipt_summaryr   r   r  rå   r8   r’   r“   rÃ   Úwaitr=   )r   rw   Úlog_file_namerS   Úrequested_linesÚtailÚdurable_update_action_idÚupdate_receipt_summaryÚaction_receipt_summaryr  Úspawned_action_idÚmarkerrŸ   r  r!  r8   r7   ré   s   &&                r#   Úget_action_statusr-  �  s0  é € ô &×)Ò)¨$Ó/€MØÒÜ¨Ð6FÀtÀfÐ4MÔNÐNäÐ,Ó-€GÜœ#˜e Q›-¨Ó.€OÜ�wÕ.°Ó@€Dà#ÐØ6:Ð:ÐØˆÔõ 	2ä#FÄ{ÑS`ÐaiÓSjÐlpÓGqÓ#rÐ Ü=¼kÈ'ÕJaÐcgÓ>hÓi÷ ]ð ]Ü 4°WÓ C÷]ð ]ÜGRÇÁÐW[ÓG\ð 	à#Ô8ð (,Ð$ß#Ø3Ð4LÐ3MÈTÐRˆFØÔ!Ø&˜�˜v�¨Ð'7Ð'8Ð9�ô "@Ð@QÓ!RÐßÐ"8×">Ð">¸B×!CÑ!CÀKÓ!PÐTeÔ!eØ%;Ð"ä×Ñ˜TÓ"€DØ‚|Ü ×$Ñ$ TÓ*ˆØˆß#)ˆf�j‰j˜Ô¨tˆÜ(¨ÐKaÓb‰	à—I‘I“Kˆ	Ø˜tÐ#ˆØ�h‰hˆØÒ Ü×$Ò$¤Y×/Õ/Ø—	‘	 !�	Ô$÷ 0ä˜4 ¨CÔ0à˜˜i¨°+¸yÈ%ÐQTÐV]Ð_cÐd€HßØ 8ˆ�ÑØÒ)Ø4ˆ�ÑØ€O÷ 0×/üs>   ‚B?H0Ã%H0Ã(1H0ÄAH0Å+A&H0ÇHÇ$(H0ÈH0ÈH-	È(H0c                ó\   € V ^8„  d   QhR\         \        \        \        3,          ,          /# )r   r    )r   rÑ   r!   r   )r"   s   "r#   r$   r$   ¿  s    € ÷ ñ œh¤t¬C´¨H¥~Õ6ñ r%   c                 óV   €  ^ RI Hp  V ! 4       ;'       g    R#   \         d     R# i ; i)z=Latest update receipt, or None on any failure (never raises).©Úread_latest_receiptN)Úhermes_cli.update_receiptr1  rÃ   r0  s    r#   Ú_read_latest_receiptr3  ¿  s-   € ðÝAÙ"Ó$×,Ð,¨Ð,øÜô Úðús   ‚ – ™(§(c                ó~   € V ^8„  d   QhR\         \        ,          R\         \        \        \        3,          ,          /# )r   rÝ   r    )r   r!   rÑ   r   )r"   s   "r#   r$   r$   È  s0   € ÷  ñ  ¬h´s­mð  ÄxÔPTÔUXÔZ]ÐU]ÕP^ÕG_ñ  r%   c                ó  € RpV '       d   ^ RI Hp V! V 4      pT;'       g    \        4       pV'       g   R#  VP                  R4      ;'       g    / p/ R Uu/ uF  qDVP                  V4      bK  	  upCRVP                  R4      ;'       g    / P                  R4      RVP                  R4      RVP                  R	4      R
\	        VP                  R4      ;'       g    .  Uu0 uF5  p\        V\        4      '       g   K  \        VP                  R4      4      kK7  	  up4      RVP                  R4      ;'       g    .  Uu. uF[  p\        V\        4      '       g   K  R\        VP                  R4      4      R\        VP                  R4      ;'       g    R4      /NK]  	  upR\        VP                  R4      \        4      '       d   VP                  R4      /C# R/C# u upi u upi u upi   \         d     R# i ; i)a‚  Compact summary of dashboard action ``action_id``'s receipt when one exists, else of the
latest receipt (written by EVERY ``hermes update`` run, incl. refused/failed), or None; never
raises. Steps/skips stay in the full endpoint. ``action_id`` names the writer so a client
never credits another action's run.

Phase-1 bullet 3 (#91277): the receipt (written by EVERY ``hermes update`` run since #91283, including
refused and failed ones, with a ``latest.json`` pointer) is the durable success signal the Desktop and
dashboard should read instead of inferring outcomes from liveness probes across the update's stop/start
gap (#81193, #87359).
N)Úread_receipt_for_actionÚpost_updateÚpre_shaÚ
pre_updater	  Úpost_shaÚpost_versionrö   Úfleet_statesÚfleetrÆ   Ú	followupsÚstepÚreasonr×   Úuser_action)r  Ú
started_atÚfinished_atrÝ   )	r2  r6  r3  rÄ   ÚsortedÚ
isinstancerÑ   r!   rÃ   )rÝ   r  r6  ÚpostÚkÚeÚfs   &      r#   r#  r#  È  sÎ  € ð €GßÝEÙ)¨)Ó4ˆØ×/Ð/Ô-Ó/€GßÙðØ�{‰{˜=Ó)×/Ð/¨Rˆð

Ù*_Ó`Ñ*_ Q�'—+‘+˜a“.Ò Ñ*_Ñ`ð

à˜Ÿ™ LÓ1×7Ð7°R×<Ñ<¸UÓCØ˜Ÿ™ ›¨¸¿¹À)Ó9LØœFÀÇÁÈWÓAU×A[ÐA[ÐY[ÐA[Ó#sÑA[¸AÔ_iÐjkÔmq×_rÔ$7¤C¨¯©¨g«Ö$7ÑA[Ñ#sÓtð Ø#*§;¡;¨{Ó#;×#AÐ#A¸rÐ#AóZÙ#A˜aÄZÐPQÔSW×EXô ]˜6¤3 q§u¡u¨V£}Ó#5°xÄÀQÇUÁUÈ8Ã_×EZÐEZÐXZÓA[Ó\Ù#AñZà¼ÀGÇKÁKÐP]ÓD^Ô`d×9eÒ9e˜7Ÿ;™; }Ó5ñ

ð 
	
ð lpñ

ð 
	
ùÚ`ùò $tùòZøô ô Úðúsl   ¸G2 ÁG2 ÁG#Á2G2 ÂAG2 ÃG2 Ã$G(ÄG(ÄG2 Ä>G2 ÅG-Å 7G-ÆG-Æ$:G2 ÇG2 Ç#G2 Ç2HÈ Hz/api/hermes/update/receiptc               ƒ  ód   "  € \        4       p V '       g   \        RRR7      hRV R\        4       /# 5i)aJ  The FULL latest update receipt (steps, skips, gateway restart outcome, fleet
matrix) plus a compact ``summary``; 404 when no update has run since receipts landed.
Clients read this instead of inferring success from backend liveness, which misread
the update's own restart gap as a failed update/boot.

See #81193, #87359, #91277.
r  z:No update receipt found (no `hermes update` run recorded).r»   r  Úsummary)r3  r   r#  )r  s    r#   Úget_update_receiptrL  ë  s3   é € ô #Ó$€GßÜ¨Ð4pÔqÐqØ�w 	Ô+IÓ+KÐLÐLùs   ‚.0i   i    i   )r\   )N)FN)éÈ   )OÚ__doc__r¥   r’   Úloggingr–   ræ   Ú
subprocessrO   Úpathlibr   Útypingr   r   r   r   Úfastapir   r   r	   Úhermes_cli.configr
   r   râ   r   r   Úhermes_cli.version_infor   Úhermes_cli.web_depsr   r   r*   r   Úhermes_cli.web_routers._commonr   Ú	getLoggerrÇ   ÚrouterÚstatus_routerr   r   r   r   r   r   r   r   r   r   r/   ra   rb   rh   Úcompiler€   r�   rá   rã   r=   rU   rx   rŠ   rŽ   r˜   rF  r¡   rÄ   r©   r­   rÍ   rÔ   rë   r  r÷   r  r  r-  r3  r#  rL  rí   r%   r#   Ú<module>r\     s©  ðñó Û Û Û 	Û Û Û Ý ß ,Ó ,ç 5Ñ 5ç aß SÝ 4ß /Ý ;Ý 7à×ÒÐ0Ó1€Ù	‹€Ù“€ñ .2Ð2^Ð`}Ó-~Ð *ÙÐ6Ó7Ð ÙÐ2Ð4SÓTÐ ÙÐ4Ð6IÓJÐ ÙÐ(Ð*=Ó>€ÙÐ4Ð6VÓWÐ ÙÐ/Ð1PÓQÐ Ù˜Ð'FÓG€Ù˜/Ð+JÓK€ÙÐ-Ð/NÓO€õBð (Ð Ø'/Ð $Ø#,Ð  à ŸjšjÐ)\Ó]Ð ØŸJšJÐ'[Ó\Ð àpÐ ð Ð)¨>Ð;VØÐ7¸Ð@UØ	Ð#ðÐ õ!÷	*õ"õJ`õ"õð ‡�Ð#Ó$öDó %ðDð ‡�Ð'Ó(ñó )ðð ‡�Ð#Ó$ñDó %ðDð ‡�Ð!Ó"ô*ó #ð*õZð ‡�Ð!Ó"ñ!Zó #ð!ZðJ Ð*Ø	ÑUðÐ õ`ð
 ‡�Ð&Ó'öLó (ðLõ^ð  ×ÑÐ/Ó0ö:ó 1ð:õz÷ ðF ×ÑÐ/Ó0ñMó 1òMr%   