chore: remove BMAD framework files and IDE configuration artifacts
Clean up unused BMAD workflow, agent, and command files across all IDE configurations (.agent, .clinerules, .cursor, .gemini, .github, .kilocode, .opencode) and internal module files (_bmad/bmb, _bmad/bmm). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
131
tools/circuit-builder-ui/server.py
Normal file
131
tools/circuit-builder-ui/server.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Minimal backend for Circuit Builder UI.
|
||||
Serves the static UI and runs entropyk-cli validate/run on POST.
|
||||
Run from repository root: python tools/circuit-builder-ui/server.py
|
||||
Then open http://localhost:8765
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from pathlib import Path
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
PORT = 8765
|
||||
# Path to entropyk-cli from repo root (run server from repo root)
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
CLI_PATH = REPO_ROOT / "target" / "release" / "entropyk-cli"
|
||||
UI_DIR = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def run_cli(subcommand, config_json_str, run_output=None):
|
||||
"""Run entropyk-cli validate or run; config_json_str written to temp file."""
|
||||
if not CLI_PATH.exists():
|
||||
return False, f"CLI not found. Build first: cargo build --release -p entropyk-cli\nExpected: {CLI_PATH}", ""
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
|
||||
f.write(config_json_str)
|
||||
tmp_path = f.name
|
||||
try:
|
||||
cmd = [str(CLI_PATH), subcommand, "--config", tmp_path]
|
||||
if run_output is not None:
|
||||
cmd.extend(["-o", run_output])
|
||||
r = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60,
|
||||
cwd=str(REPO_ROOT),
|
||||
)
|
||||
stdout = r.stdout or ""
|
||||
stderr = r.stderr or ""
|
||||
if r.returncode != 0:
|
||||
return False, stdout or stderr or f"Exit code {r.returncode}", stderr
|
||||
return True, stdout, stderr
|
||||
except subprocess.TimeoutExpired:
|
||||
return False, "Timeout (60s)", ""
|
||||
except Exception as e:
|
||||
return False, str(e), ""
|
||||
finally:
|
||||
try:
|
||||
os.unlink(tmp_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
path = urlparse(self.path).path
|
||||
if path == "/" or path == "/index.html":
|
||||
self.serve_file(UI_DIR / "index.html", "text/html")
|
||||
elif path == "/examples/simple_working.json":
|
||||
self.serve_file(REPO_ROOT / "crates" / "cli" / "examples" / "simple_working.json", "application/json")
|
||||
elif path == "/examples/chiller_r410a_minimal.json":
|
||||
self.serve_file(REPO_ROOT / "crates" / "cli" / "examples" / "chiller_r410a_minimal.json", "application/json")
|
||||
else:
|
||||
self.send_error(404)
|
||||
|
||||
def serve_file(self, filepath, content_type):
|
||||
try:
|
||||
with open(filepath, "rb") as f:
|
||||
data = f.read()
|
||||
except FileNotFoundError:
|
||||
self.send_error(404)
|
||||
return
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", content_type)
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
|
||||
def do_POST(self):
|
||||
path = urlparse(self.path).path
|
||||
if path != "/validate" and path != "/run":
|
||||
self.send_error(404)
|
||||
return
|
||||
content_len = int(self.headers.get("Content-Length", 0))
|
||||
body = self.rfile.read(content_len)
|
||||
try:
|
||||
config_str = body.decode("utf-8")
|
||||
json.loads(config_str)
|
||||
except Exception as e:
|
||||
self.send_json(400, {"ok": False, "error": f"Invalid JSON: {e}"})
|
||||
return
|
||||
if path == "/validate":
|
||||
ok, out, err = run_cli("validate", config_str)
|
||||
else:
|
||||
ok, out, err = run_cli("run", config_str, run_output=os.path.devnull)
|
||||
self.send_json(200, {"ok": ok, "stdout": out, "stderr": err})
|
||||
|
||||
def send_json(self, status, obj):
|
||||
body = json.dumps(obj).encode("utf-8")
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def log_message(self, format, *args):
|
||||
print(f"[{self.log_date_time_string()}] {format % args}")
|
||||
|
||||
|
||||
def main():
|
||||
os.chdir(REPO_ROOT)
|
||||
print(f"Entropyk Circuit Builder UI")
|
||||
print(f" UI: http://localhost:{PORT}/")
|
||||
print(f" CLI: {CLI_PATH} {'(found)' if CLI_PATH.exists() else '(not found — run: cargo build --release -p entropyk-cli)'}")
|
||||
print(f" Root: {REPO_ROOT}")
|
||||
server = HTTPServer(("", PORT), Handler)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print("\nBye.")
|
||||
server.server_close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user