#!/usr/bin/env python3 import argparse import requests import json import websocket API = "http://localhost:8080/api" WS = "ws://localhost:8080/ws" # ----------------------------- # LIVE STREAM (IDE MODE) # ----------------------------- def stream(): ws = websocket.WebSocket() ws.connect(WS) print("📡 Fester IDE stream active\n") while True: msg = ws.recv() event = json.loads(msg) if event["type"] == "pipeline": d = event["data"] print(f"[PIPELINE] {d['action']} → {d['state']} @ {d.get('node')}") elif event["type"] == "node": print(f"[NODE] {event['data']}") # ----------------------------- # PIPELINE CONTROL # ----------------------------- def status(): r = requests.get(f"{API}/pipeline/state") print(json.dumps(r.json(), indent=2)) def retry(action): r = requests.post(f"{API}/pipeline/retry", json={"action": action}) print(r.json()) def force(action, node): r = requests.post(f"{API}/pipeline/force-node", json={ "action": action, "node": node }) print(r.json()) def pause(): requests.post(f"{API}/pipeline/pause") def resume(): requests.post(f"{API}/pipeline/resume") # ----------------------------- # SESSION CONTROL (IDE FEATURE) # ----------------------------- def sessions(): r = requests.get(f"{API}/sessions") print(json.dumps(r.json(), indent=2)) def attach(action): r = requests.post(f"{API}/session/attach", json={"action": action}) print(r.json()) def detach(action): r = requests.post(f"{API}/session/detach", json={"action": action}) print(r.json()) # ----------------------------- # POLICY CONTROL (WIZARD LAYER) # ----------------------------- def set_policy(key, value): r = requests.post(f"{API}/policy/set", json={ "key": key, "value": value }) print(r.json()) def clear_policy(key): r = requests.post(f"{API}/policy/clear", json={ "key": key }) print(r.json()) # ----------------------------- # CLI ENTRYPOINT # ----------------------------- def main(): parser = argparse.ArgumentParser("fester IDE CLI") sub = parser.add_subparsers(dest="cmd") # core sub.add_parser("stream") sub.add_parser("status") sub.add_parser("sessions") # pipeline control r = sub.add_parser("retry") r.add_argument("action") f = sub.add_parser("force") f.add_argument("action") f.add_argument("node") sub.add_parser("pause") sub.add_parser("resume") # session control a = sub.add_parser("attach") a.add_argument("action") d = sub.add_parser("detach") d.add_argument("action") # policy control p = sub.add_parser("policy-set") p.add_argument("key") p.add_argument("value") c = sub.add_parser("policy-clear") c.add_argument("key") args = parser.parse_args() # ----------------------------- # COMMAND HANDLING # ----------------------------- if args.cmd == "stream": stream() elif args.cmd == "status": status() elif args.cmd == "sessions": sessions() elif args.cmd == "retry": retry(args.action) elif args.cmd == "force": force(args.action, args.node) elif args.cmd == "attach": attach(args.action) elif args.cmd == "detach": detach(args.action) elif args.cmd == "pause": pause() elif args.cmd == "resume": resume() elif args.cmd == "policy-set": set_policy(args.key, args.value) elif args.cmd == "policy-clear": clear_policy(args.key) else: parser.print_help() if __name__ == "__main__": main()