#!/usr/bin/env python3 """ AI GitOps Actions API """ import asyncio, base64, hashlib, hmac, json, os, re, shutil, subprocess, sys, time, uuid from pathlib import Path from urllib.parse import parse_qs, urlparse from aiohttp import web # Environment WS = Path(os.environ.get("AIOS_WORKSPACE", "/data/aios-gitops/workspace")) BASE_DIR = WS / "active-runtime" APPDIR = BASE_DIR / "app" AUDITDIR = WS / "audit" WORKDIR = WS / "work" DOTDIR = WS.parent GITEA_DIR = DOTDIR / "runtime" / "gitea-bin" / "data" / "repositories" / "aios" # Load config try: import yaml config_path = WS / "active-runtime" / "app" / "config.yaml" with open(config_path) as f: CONFIG = yaml.safe_load(f) or {} except: CONFIG = {} start_time = time.time() log_ident = "aios-api" def sh(cmd, **kw): try: r = subprocess.run(cmd, capture_output=True, text=True, cwd=WS, **kw) return r.stdout.strip() if r else None except: return None def baselines(): p = WS / "baselines" / "current.json" if p.exists(): try: return json.loads(p.read_text()) except: pass return {} def commands(status): d = WS / "agents" / "commands" / status if not d.exists(): return [] return [{"name": f.name, "state": status} for f in sorted(d.iterdir()) if f.name.endswith(".md")] def agent_runs(): d = AUDITDIR / "agent-runs" if not d.exists(): return [] rs = [] for f in sorted(d.iterdir(), reverse=True): if f.name.endswith(".json"): try: j = json.loads(f.read_text()) j["file"] = f.stem rs.append(j) except: pass return rs async def handle_api(request): path = request.path if path in ('/admin/ai-evolution','/admin/ai-evolution/'): # Serve the HTML page html_path = APPDIR / 'static' / 'admin-ai-evolution.html' if html_path.exists(): return web.Response(text=html_path.read_text(), content_type='text/html') return web.Response(text='Dashboard not found', status=404) if path == '/admin/ai-evolution/api/data': result = subprocess.run(['git','tag','--list','V*'], capture_output=True, text=True, cwd=WS) tags = result.stdout.strip().splitlines() if result.returncode == 0 else [] h = subprocess.run(['git','rev-parse','--short','HEAD'], capture_output=True, text=True, cwd=WS) head = h.stdout.strip() if h.returncode == 0 else 'unknown' b = subprocess.run(['git','rev-parse','--abbrev-ref','HEAD'], capture_output=True, text=True, cwd=WS) branch = b.stdout.strip() if b.returncode == 0 else 'unknown' return web.json_response({ 'baseline': baselines(), 'versions': [{'tag':t,'name':p.name} for p in sorted((WS/'versions').glob('*')) for t in tags if p.name in t], 'commands': commands('active') + commands('running') + commands('completed'), 'agent_runs': agent_runs(), 'stats': { 'current': head, 'branch': branch, 'uptime': round(time.time()-start_time, 2), 'baseline': baselines().get('current_baseline','unknown'), } }) return web.json_response({'error':'not_found','path':path}, status=404) app = web.Application() app.router.add_route('GET', '/admin/ai-evolution', handle_api) app.router.add_route('GET', '/admin/ai-evolution/', handle_api) app.router.add_route('GET', '/admin/ai-evolution/api/data', handle_api) if __name__ == '__main__': web.run_app(app, host='127.0.0.1', port=18890)