""" Lightweight preview server — serves frontend/out/ on port 3001. Used only for Claude Code preview panel. The real backend runs on 7000. """ import os from pathlib import Path from fastapi import FastAPI from fastapi.responses import FileResponse, HTMLResponse from fastapi.staticfiles import StaticFiles import uvicorn OUT = Path(__file__).parent / "frontend" / "out" app = FastAPI() # Serve _next assets directly if (OUT / "_next").exists(): app.mount("/_next", StaticFiles(directory=str(OUT / "_next")), name="next-assets") @app.get("/{full_path:path}") async def spa(full_path: str): # Try exact file match candidate = OUT / full_path if candidate.is_file(): return FileResponse(str(candidate)) # Try with .html html = OUT / (full_path.rstrip("/") + ".html") if full_path else OUT / "index.html" if html.is_file(): return FileResponse(str(html)) # SPA fallback return FileResponse(str(OUT / "index.html")) @app.get("/") async def root(): return FileResponse(str(OUT / "index.html")) if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=3001, log_level="warning")