""" dev.py ====== This script acts as a local development orchestrator. Instead of recreating the frontend in Python, which would violate the "Don't Repeat Yourself" (DRY) principle and introduce massive technical debt, this script leverages the existing architecture. It performs four main actions sequentially: 1. Executes `roi.py` to fetch the latest market data and generate the frontend JSON files. 2. Executes `bun install` to ensure frontend JS dependencies are present. 3. Executes `bun run build` to compile the TypeScript frontend into browser-ready JavaScript. 4. Spawns a local Python HTTP server pointing to the `www/` directory. """ import os # Required for changing working directories and checking paths. import subprocess # Required for spawning external processes (like 'bun' and other python scripts). import sys # Required to grab the current Python executable path. import http.server # Required to run the local web server. import socketserver # Required to bind the HTTP handler to a specific port. def main() -> None: """ Main execution function for the local development server orchestrator. """ # ------------------------------------------------------------------------- # STEP 1: GENERATE BACKEND DATA # ------------------------------------------------------------------------- print(">>> [1/4] Running roi.py to generate updated JSON data...") try: subprocess.run([sys.executable, "roi.py"], check=True) except subprocess.CalledProcessError as e: sys.exit(f"!!! Error: Failed to execute roi.py. Process exited with code {e.returncode}") # ------------------------------------------------------------------------- # STEP 2: INSTALL FRONTEND DEPENDENCIES # ------------------------------------------------------------------------- # Unlike 'uv run', 'bun run' does not automatically install missing dependencies # defined in package.json. We must explicitly invoke 'bun install' first to # populate the node_modules/ directory. print(">>> [2/4] Installing frontend dependencies via Bun...") try: subprocess.run(["bun", "install"], check=True) except FileNotFoundError: # We catch the FileNotFoundError here because this is the first time 'bun' is invoked. sys.exit("!!! Error: 'bun' command not found. Please ensure Bun is installed (https://bun.sh/) and in your PATH.") except subprocess.CalledProcessError as e: sys.exit(f"!!! Error: Frontend dependency installation failed. Bun exited with code {e.returncode}") # ------------------------------------------------------------------------- # STEP 3: BUILD THE FRONTEND # ------------------------------------------------------------------------- # Compiles the TypeScript inside ts/ to JavaScript inside www/ print(">>> [3/4] Building the TypeScript frontend using Bun...") try: subprocess.run(["bun", "run", "build"], check=True) except subprocess.CalledProcessError as e: sys.exit(f"!!! Error: Frontend build failed. Bun exited with code {e.returncode}") # ------------------------------------------------------------------------- # STEP 4: SERVE THE FRONTEND LOCALLY # ------------------------------------------------------------------------- print(">>> [4/4] Starting local development server...") PORT = 8000 WEB_DIR = "www" if not os.path.isdir(WEB_DIR): sys.exit(f"!!! Error: Directory '{WEB_DIR}' does not exist. The build step may have failed silently.") os.chdir(WEB_DIR) Handler = http.server.SimpleHTTPRequestHandler with socketserver.TCPServer(("", PORT), Handler) as httpd: print(f">>> Serving at http://localhost:{PORT}") print(">>> Press Ctrl+C to stop the server.") try: httpd.serve_forever() except KeyboardInterrupt: print("\n>>> Shutting down development server gracefully. Goodbye!") if __name__ == '__main__': main()