3 browser-native chat surfaces (atlas-chat / atlas-hud / atlas-command, no build step) + 11 Python automation scripts (cluster, tray, finance, reminders, autonomy loops) + 2 patterns documented (cluster-then-polish, anti-impulse R1-R10) MIT licensed, anonymized from production stack.
143 lines
5.2 KiB
Python
143 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
atlas_autonomy_export.py - Expose autonomy loop state via JSON for live dashboard.
|
|
|
|
Reads:
|
|
- autonomy_queue.json (pending/completed)
|
|
- autonomy_loop.log (last 50 lines)
|
|
- vault/00_Atlas_Wiki/_autonomy/*.md (last 20 outputs)
|
|
|
|
Writes:
|
|
- atlas-autonomy.json — consumed by Atlas Command AUTONOMY tab
|
|
|
|
Runs: every 1 min via Atlas-Autonomy-Export schtask (lightweight).
|
|
"""
|
|
import json
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
import io
|
|
if sys.stdout.encoding != 'utf-8':
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
|
|
|
QUEUE = Path(r"C:\Users\Gebruiker\.config\atlas\autonomy_queue.json")
|
|
LOG = Path(r"C:\Users\Gebruiker\.config\atlas\autonomy_loop.log")
|
|
AUTO = Path(r"C:\Users\Gebruiker\MEGA\Atlas Corporation\00_Atlas_Wiki\_autonomy")
|
|
OUT = Path(r"C:\Users\Gebruiker\AppData\Local\Atlas\analyses\atlas-autonomy.json")
|
|
SSH = "root@<YOUR_VPS_IP>"
|
|
REMOTE = "/opt/atlas/dashboard/atlas-autonomy.json"
|
|
|
|
|
|
def parse_frontmatter(text):
|
|
"""Extract simple YAML frontmatter (between --- markers)."""
|
|
if not text.startswith("---"):
|
|
return {}, text
|
|
end = text.find("---", 3)
|
|
if end == -1:
|
|
return {}, text
|
|
yaml_block = text[3:end].strip()
|
|
body = text[end+3:].strip()
|
|
fm = {}
|
|
for line in yaml_block.split("\n"):
|
|
if ":" in line:
|
|
k, v = line.split(":", 1)
|
|
fm[k.strip()] = v.strip()
|
|
return fm, body
|
|
|
|
|
|
def main():
|
|
state = {
|
|
"generated_at": datetime.now().isoformat(timespec="seconds"),
|
|
"loop_running": False,
|
|
"queue_pending": 0,
|
|
"queue_completed": 0,
|
|
"log_tail": [],
|
|
"recent_outputs": [],
|
|
"next_fire": None,
|
|
"task_state": None,
|
|
}
|
|
|
|
# Queue
|
|
if QUEUE.exists():
|
|
try:
|
|
q = json.loads(QUEUE.read_text(encoding="utf-8"))
|
|
state["queue_pending"] = len(q.get("pending", []))
|
|
state["queue_completed"] = len(q.get("completed", []))
|
|
if q.get("completed"):
|
|
last = q["completed"][-1]
|
|
state["last_completed"] = {
|
|
"topic": last.get("topic"),
|
|
"node": last.get("node"),
|
|
"model": last.get("model"),
|
|
"completed_at": last.get("completed_at"),
|
|
"elapsed_s": last.get("elapsed_s"),
|
|
}
|
|
except Exception as e:
|
|
state["queue_err"] = str(e)[:100]
|
|
|
|
# Log tail
|
|
if LOG.exists():
|
|
try:
|
|
lines = LOG.read_text(encoding="utf-8", errors="replace").splitlines()
|
|
state["log_tail"] = lines[-50:]
|
|
except Exception:
|
|
pass
|
|
|
|
# Schtask state
|
|
try:
|
|
r = subprocess.run(
|
|
["powershell.exe", "-NoProfile", "-Command",
|
|
"$t=Get-ScheduledTask -TaskName Atlas-Autonomy-Hourly -ErrorAction SilentlyContinue;"
|
|
"if ($t) { $i=Get-ScheduledTaskInfo $t; "
|
|
"Write-Output ('STATE:' + $t.State + '|LAST:' + $i.LastRunTime + '|NEXT:' + $i.NextRunTime + '|RESULT:' + $i.LastTaskResult) }"],
|
|
capture_output=True, text=True, timeout=10
|
|
)
|
|
out = r.stdout.strip()
|
|
if out.startswith("STATE:"):
|
|
parts = dict(p.split(":", 1) for p in out[6:].split("|"))
|
|
state["task_state"] = "STATE:" + out[6:]
|
|
state["loop_running"] = (parts.get("STATE") != "Disabled")
|
|
state["next_fire"] = parts.get("NEXT")
|
|
except Exception as e:
|
|
state["task_state_err"] = str(e)[:100]
|
|
|
|
# Recent outputs (last 20 by mtime)
|
|
if AUTO.exists():
|
|
try:
|
|
md_files = sorted(AUTO.glob("*.md"), key=lambda p: p.stat().st_mtime, reverse=True)[:20]
|
|
for p in md_files:
|
|
try:
|
|
text = p.read_text(encoding="utf-8", errors="replace")
|
|
fm, body = parse_frontmatter(text)
|
|
state["recent_outputs"].append({
|
|
"filename": p.name,
|
|
"mtime": datetime.fromtimestamp(p.stat().st_mtime).isoformat(timespec="seconds"),
|
|
"topic": fm.get("topic", "?"),
|
|
"node": fm.get("node", "?"),
|
|
"model": fm.get("model", "?"),
|
|
"elapsed_s": fm.get("elapsed_s", "?"),
|
|
"polish_status": fm.get("polish_status", "?"),
|
|
"body_preview": body[:400].replace("\n", " ").strip(),
|
|
})
|
|
except Exception:
|
|
pass
|
|
except Exception as e:
|
|
state["outputs_err"] = str(e)[:100]
|
|
|
|
state["recent_output_count"] = len(state["recent_outputs"])
|
|
|
|
OUT.parent.mkdir(parents=True, exist_ok=True)
|
|
OUT.write_text(json.dumps(state, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
print(f"wrote {OUT}")
|
|
print(f" pending={state['queue_pending']} completed={state['queue_completed']} outputs={state['recent_output_count']}")
|
|
try:
|
|
subprocess.run(["scp", str(OUT), f"{SSH}:{REMOTE}"], check=True, timeout=20)
|
|
print(f"pushed to {SSH}:{REMOTE}")
|
|
except Exception as e:
|
|
print(f"scp fail: {e}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|