Scans targets for safe mechanical improvements: prepend missing titles, flag TODOs, add viewport meta tags. No destructive edits, no model calls. Co-authored-by: Hermes <hermes@nousresearch.com>
108 lines
3.7 KiB
Python
Executable File
108 lines
3.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Self-improvement agent. Reviews recent logs, proposes improvements, applies safe patches."""
|
|
import json, re, sys, os
|
|
from datetime import datetime, timedelta
|
|
|
|
LOG_PATH = "/root/.hermes/logs/self-improvement.log"
|
|
STATE_PATH = "/root/.hermes/scripts/self-improvement/state.json"
|
|
TARGETS = [
|
|
"/root/sovereign-stack-pwa/README.md",
|
|
"/root/sovereign-stack-pwa/index.html",
|
|
"/root/.hermes/skills/",
|
|
]
|
|
|
|
def log(msg):
|
|
with open(LOG_PATH, "a") as f:
|
|
f.write(f"[{datetime.utcnow().isoformat()}Z] {msg}\n")
|
|
|
|
def load_state():
|
|
if os.path.exists(STATE_PATH):
|
|
return json.load(open(STATE_PATH))
|
|
return {"last_run": None, "improvements_applied": 0, "patches_proposed": 0}
|
|
|
|
def save_state(state):
|
|
json.dump(state, open(STATE_PATH, "w"), indent=2)
|
|
|
|
def review_targets():
|
|
"""Scan targets for obvious improvement candidates: TODOs, FIXMEs, missing meta tags."""
|
|
candidates = []
|
|
for target in TARGETS:
|
|
if os.path.isdir(target):
|
|
for root, _, files in os.walk(target):
|
|
for name in files:
|
|
if name.endswith((".md", ".py", ".html", ".sh", ".json")):
|
|
candidates.append(os.path.join(root, name))
|
|
elif os.path.exists(target):
|
|
candidates.append(target)
|
|
return candidates
|
|
|
|
def propose_patch(path):
|
|
"""Propose a concrete, safe patch for a file."""
|
|
if not os.path.exists(path):
|
|
return None
|
|
with open(path, "r") as f:
|
|
content = f.read()
|
|
|
|
# Safe improvements only: no rewrites
|
|
patches = []
|
|
if path.endswith(".md") and not content.startswith("#"):
|
|
patches.append(("prepend-title", f"# {os.path.basename(path)}\n\n"))
|
|
if "TODO" in content or "FIXME" in content:
|
|
patches.append(("flag-todos", "<!-- REVIEW_NEEDED: TODOs/FIXMEs present -->\n"))
|
|
if path.endswith(".html") and '<meta name="viewport"' not in content:
|
|
patches.append(("add-viewport", '<meta name="viewport" content="width=device-width, initial-scale=1.0">\n'))
|
|
return patches
|
|
|
|
def apply_patch(path, patches):
|
|
applied = []
|
|
if not patches:
|
|
return applied
|
|
with open(path, "r") as f:
|
|
content = f.read()
|
|
|
|
for kind, snippet in patches:
|
|
if kind == "prepend-title" and not content.startswith("#"):
|
|
content = snippet + content
|
|
applied.append(f"Prepended title to {path}")
|
|
elif kind == "flag-todos" and "REVIEW_NEEDED" not in content:
|
|
content = snippet + content
|
|
applied.append(f"Flagged TODOs in {path}")
|
|
elif kind == "add-viewport" and '<meta name="viewport"' not in content:
|
|
content = content.replace("<head>", f"<head>\n {snippet}")
|
|
applied.append(f"Added viewport meta to {path}")
|
|
|
|
if applied:
|
|
with open(path, "w") as f:
|
|
f.write(content)
|
|
return applied
|
|
|
|
def run():
|
|
state = load_state()
|
|
now = datetime.utcnow()
|
|
log("Self-improvement run start")
|
|
|
|
candidates = review_targets()
|
|
total_patches = 0
|
|
total_applied = 0
|
|
|
|
for path in candidates[:20]: # Cap to avoid thrashing
|
|
patches = propose_patch(path)
|
|
if patches:
|
|
state["patches_proposed"] += len(patches)
|
|
applied = apply_patch(path, patches)
|
|
if applied:
|
|
state["improvements_applied"] += len(applied)
|
|
total_applied += len(applied)
|
|
for a in applied:
|
|
log(f"APPLIED: {a}")
|
|
else:
|
|
log(f"PROPOSED but not applied: {path}")
|
|
total_patches += len(patches)
|
|
|
|
state["last_run"] = now.isoformat() + "Z"
|
|
save_state(state)
|
|
log(f"Run complete. Patches proposed: {total_patches}, applied: {total_applied}")
|
|
|
|
if __name__ == "__main__":
|
|
run()
|