o
    6iiB&                  
   @   s  d dl Zd dlZd dlZd dlZd dlZd dlZd dlZd dlm	Z	 d dl
mZmZ e	dZed d Zed d Zd	Zd
ZdZee	 d d Zee	 d d d Zd:dee dedefddZdefddZdefddZdeddfddZdeddfddZdefd d!ZdedB fd"d#Z defd$d%Z!d&ed'edefd(d)Z"d*edefd+d,Z#d-ed.ed/ed0edef
d1d2Z$d3ed4eddfd5d6Z%defd7d8Z&e'd9kre(e&  dS dS );    N)Path)Requesturlopenz-/home/isthekid/.openclaw/workspace/monitoringstatezopenclaw-update-state.jsonlogszopenclaw-update-monitor.logzadner.cruz@bertelsmann.comzAmerica/New_Yorkzubuntu@150.136.218.171z.ssh
oracle_vpsz.npm-globalbinopenclaw<   cmdtimeoutreturnc                 C   sP   t j| t jt jd|d}|jdkr#tdd|  d|j d|j |j S )NT)stdoutstderrtextr   r   zCommand failed:  z	
STDERR:
z	
STDOUT:
)	
subprocessrunPIPE
returncodeRuntimeErrorjoinr   r   strip)r   r   p r   H/home/isthekid/.openclaw/workspace/monitoring/openclaw_update_monitor.pyr      s   
$
r   c                   C   s   t jt jj S )N)dtdatetimenowtimezoneutc	isoformatr   r   r   r   now_iso   s   r"   c                   C   s(   t  rtt  S d d d d d ddS )Nunknown)last_checked_atcurrent_version_last_seenlatest_version_last_seenlast_alerted_versionlast_alerted_atsource_validation)
STATE_PATHexistsjsonloads	read_textr   r   r   r   
load_state!   s   r/   c                 C   s,   t jjddd t tj| ddd  d S )NTparentsexist_ok   )indent
)r*   parentmkdir
write_textr,   dumps)r   r   r   r   
save_state.   s   r:   msgc                 C   s^   t jjddd dt  d|  d}t d}|| W d    d S 1 s(w   Y  d S )NTr0   [z] r5   a)LOG_PATHr6   r7   r"   openwrite)r;   linefr   r   r   log3   s
   "rC   c                  C   sh   t tddg} | d}| d}|dks|dks||kr!tdt| ||d  }|dd	 S )
Nstatusz--json{}z?Could not locate JSON object in `openclaw status --json` output   runtimeVersion )	r   OPENCLAW_BINfindrfindr   r,   r-   getr   )outstartenddatar   r   r   parse_status_version:   s   

rS   c                  C   s,   t tddg} td| }|r|dS d S )NupdaterD   z(npm\s+latest\s+([0-9]+(?:\.[0-9]+){1,3})rH   )r   rK   researchgroup)rO   mr   r   r   parse_latest_from_update_statusD   s
   
rY   c                  C   s   t g d} |  S )N)npmviewr	   version)r   r   )rO   r   r   r   parse_latest_from_npmM   s   r]   r=   bc                 C   sn   dt fdd}|| ||}}tt|t|}|dg|t|  7 }|dg|t|  7 }||k||k  S )Nvc                 S   s   dd t d| D S )Nc                 S   s   g | ]}t |qS r   )int).0xr   r   r   
<listcomp>U   s    z3compare_versions.<locals>.parts.<locals>.<listcomp>z\d+)rU   findall)r_   r   r   r   partsT   s   zcompare_versions.<locals>.partsr   )strmaxlen)r=   r^   re   papbnr   r   r   compare_versionsR   s   rl   r\   c                 C   s   d}t |dddd}z\t|dd}t| d}W d    n1 s'w   Y  |d	d
}|dd
p9d
}|dd
}| |v sU|| sUt| t	
dd
|dkrfd|dp\|||d d dW S W n	 typ   Y nw dd|  dddS )Nz>https://api.github.com/repos/openclaw/openclaw/releases/latestzapplication/vnd.github+jsonzopenclaw-update-monitor)Acceptz
User-Agent)headers   r   zutf-8tag_namerJ   bodyhtml_urlz^[^0-9]*r   githubnamei  )sourcetitleurlnotesfallbackz	OpenClaw z-https://github.com/openclaw/openclaw/releaseszKRelease notes were not retrieved automatically. Please review release page.)r   r   r,   r-   readdecoderN   endswithrl   rU   sub	Exception)r\   rx   reqresprR   tagrr   htmlr   r   r   fetch_release_notes]   s0   *
r   current_versionnew_versionry   	notes_urlc                 C   sN   d|  d| d|d d  }dt | d}tddtt|gd	d
}| S )NzYou are an IT ops assistant. Write 8-12 concise lines for an executive update recommendation.
Context:
- Product: OpenClaw
- Current version: z
- New version: ai  
- Goal: help decide update now vs tonight vs defer
- Environment: direct Telegram use, gateway + cron usage, OAuth already restored.
Use this structure:
1) What changed (max 3 bullets)
2) What this means for us (max 4 bullets)
3) Recommendation with one of: Update now / Schedule tonight / Defer
Do not include raw URLs in the response.
Release notes excerpt:
i	  zjsource ~/.secrets/api_keys.env >/dev/null 2>&1; python3 - <<'PY'
import json, os, urllib.request
prompt = a  
key = os.environ.get('XAI_API_KEY','').strip()
if not key:
  raise SystemExit('Missing XAI_API_KEY on VPS')
payload = {
  'model': 'grok-4-fast-non-reasoning',
  'messages': [
    {'role':'system','content':'Be precise and concise. No markdown headers.'},
    {'role':'user','content':prompt}
  ],
  'temperature': 0.2
}
req = urllib.request.Request('https://api.x.ai/v1/chat/completions', data=json.dumps(payload).encode('utf-8'), headers={'Authorization': f'Bearer {key}', 'Content-Type':'application/json', 'Accept':'application/json', 'User-Agent':'xAI-Client/1.0 (OpenClaw Update Monitor)'})
with urllib.request.urlopen(req, timeout=60) as r:
  data = json.loads(r.read().decode('utf-8'))
print(data['choices'][0]['message']['content'].strip())
PYsshz-ix   rp   )r,   r9   r   GROK_VPS_KEYGROK_VPS_HOSTr   )r   r   ry   r   prompt
remote_cmdrO   r   r   r   build_grok_summaryy   s   
r   subject	body_htmlc                 C   s&   t ddddddtd| d|gd	d
 d S )Ngoggmailsendz	--accountzsrvdeskops@gmail.comz--toz	--subjectz--body-htmlr
   rp   )r   	RECIPIENT)r   r   r   r   r   
send_email   s   
r   c                  C   sl  zt  } t }t }t }|p|}|r||krdn|sdnd}t | d< || d< || d< || d< |s>td t|  W d	S t||d	k}| d
|k}|rT|sT|dkr~d}|dkrcd| d| }n|rjd| }td| d| d|  t|  W d	S t	|}	zt
|||	d |	d }
d}W n' ty } ztd|  d}d| d| d| d}
W Y d }~nd }~ww d| d| d}t|
dd}d t| d!t| d"t| d  d#t| d$t| d%tj|	d d&d' d(| d)}t|| || d
< t | d*< t|  td+| d,| d- W d	S  ty5 } ztd.|  W Y d }~d/S d }~ww )0Nbothzsecondary-onlymismatchr$   r%   r&   r)   z&No latest version detected; no action.r   r'   z	no-changezmismatch primary=z secondary=zalready-alerted=zNo email sent (z). current=z latest=ry   rx   grokz+Grok summary failed; using fallback. error=rz   u   • Change detected: OpenClaw z is available (current u   ).
• Source validation: u  .
• Risk: delaying updates may miss bug fixes/security hardening in current release train.
• Operational impact: update may require brief agent/gateway restart planning window.
• Recommendation: Schedule tonight unless active incidents require immediate patching.
• Pre-checks: export config backup, verify OAuth/session health, confirm cron baseline.
• Post-checks: run openclaw status, validate monitor job, test one end-to-end command flow.z[OpenClaw Update] z available (current: )r5   z<br>z$<p>Hi Adner,</p><p>Current version: z<br>New available version: z<br>Detected at: z<br>Validation: z: (openclaw update status + npm)<br>Recommendation source: z<br>Changelog: <a href="T)quotez`">OpenClaw Release Notes</a></p><p><strong>What changed and what this means for us:</strong><br>z9</p><p>Automated change-only alert (daily 6:00 AM ET)</p>r(   zEmail sent for new version z
 (current=z).zERROR: rH   )r/   rS   rY   r]   r"   rC   r:   rl   rN   r   r   r   r   escapereplacer   )r   r   latest_primarylatest_secondarylatestr)   has_newalready_alertedreasonrnsummarysummary_sourceger   summary_htmlr   er   r   r   main   s   



r   __main__)r
   ))r   r   r,   osrU   r   r   syspathlibr   urllib.requestr   r   BASEr*   r>   r   TIMEZONEr   rf   homer   rK   listr`   r   r"   dictr/   r:   rC   rS   rY   r]   rl   r   r   r   r   __name__exitr   r   r   r   <module>   sB   
	)
L