#!/usr/bin/env python3 """Simple file server for Mission Control dynamic content""" import http.server import socketserver import socket import json import os import glob from datetime import datetime PORT = 8081 WORKSPACE = "/home/ubuntu/.openclaw/workspace" OPENCLAW = "/home/ubuntu/.openclaw" class Handler(http.server.SimpleHTTPRequestHandler): def do_GET(self): if self.path == "/api/agents": self.serve_agents() elif self.path == "/api/memory": self.serve_memory() elif self.path == "/api/docs": self.serve_docs() elif self.path.startswith("/api/doc/"): self.serve_doc() elif self.path == "/api/cron": self.serve_cron() elif self.path.startswith("/api/script/"): self.serve_script() else: super().do_GET() def serve_agents(self): try: with open(f"{OPENCLAW}/openclaw.json") as f: config = json.load(f) agents = config.get("agents", {}).get("list", []) self.send_json(agents) except Exception as e: self.send_json({"error": str(e)}) def serve_memory(self): try: memory_dir = f"{WORKSPACE}/memory" files = sorted(glob.glob(f"{memory_dir}/*.md"), reverse=True) entries = [] for f in files[:10]: name = os.path.basename(f) with open(f) as fp: content = fp.read(2000) entries.append({"name": name, "content": content}) self.send_json(entries) except Exception as e: self.send_json({"error": str(e)}) def serve_docs(self): try: docs_dir = f"{WORKSPACE}/docs" files = sorted(glob.glob(f"{docs_dir}/*.md")) docs = [] for f in files: name = os.path.basename(f) with open(f) as fp: content = fp.read(500) docs.append({"name": name, "preview": content[:200] + "..."}) self.send_json(docs) except Exception as e: self.send_json({"error": str(e)}) def serve_cron(self): try: # Read crontab for this user import subprocess result = subprocess.run(["crontab", "-l"], capture_output=True, text=True) jobs = [] for line in result.stdout.split("\n"): if line.strip() and not line.startswith("#"): jobs.append(line) self.send_json(jobs) except Exception as e: self.send_json({"error": str(e)}) def serve_doc(self): try: # Extract filename from /api/doc/{filename} filename = self.path.replace("/api/doc/", "") filename = filename.replace("%20", " ").replace("%2F", "/") filepath = os.path.join(f"{WORKSPACE}/docs", filename) # Security: ensure path is within docs directory real_path = os.path.realpath(filepath) docs_dir = os.path.realpath(f"{WORKSPACE}/docs") if not real_path.startswith(docs_dir): self.send_json({"error": "Invalid path"}) return with open(real_path) as f: content = f.read() self.send_json({"name": filename, "content": content}) except Exception as e: self.send_json({"error": str(e)}) def serve_script(self): try: # Extract script name from /api/script/{name} script_name = self.path.replace("/api/script/", "") script_name = script_name.replace("%20", " ").replace("%2F", "/") # Map script names to files script_map = { "daily-brief": f"{WORKSPACE}/daily-brief.sh", "openrouter-monitor": f"{WORKSPACE}/cron/openrouter-monitor.sh", "gateway-reboot": f"{WORKSPACE}/gateway-start.sh" # if exists } filepath = script_map.get(script_name) if not filepath or not os.path.exists(filepath): self.send_json({"error": "Script not found"}) return with open(filepath) as f: content = f.read() self.send_json({"name": script_name, "content": content}) except Exception as e: self.send_json({"error": str(e)}) def send_json(self, data): self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() self.wfile.write(json.dumps(data).encode()) if __name__ == "__main__": os.chdir(WORKSPACE) # Allow IPv6 and IPv4 connections socketserver.TCPServer.address_family = socket.AF_INET6 with socketserver.TCPServer(("", PORT), Handler) as httpd: print(f"Serving at http://[::]:{PORT}") httpd.serve_forever()