| """ |
| Wizard-Vibe Core β Hot Reload Watcher |
| ====================================== |
| Watches file changes and restarts the server automatically. |
| Uses inotify/file polling for cross-platform support. |
| """ |
|
|
| import os |
| import sys |
| import time |
| import subprocess |
| from pathlib import Path |
|
|
|
|
| WATCH_DIRS = ["."] |
| WATCH_EXTS = {".py", ".html", ".css", ".js"} |
| IGNORE_DIRS = {"__pycache__", ".git", "generated", "venv", ".venv"} |
|
|
|
|
| def get_mtimes(root: Path) -> dict: |
| """Get mtimes for all watched files.""" |
| mtimes = {} |
| for d in WATCH_DIRS: |
| for path in Path(d).rglob("*"): |
| if any(p in IGNORE_DIRS for p in path.parts): |
| continue |
| if path.is_file() and path.suffix in WATCH_EXTS: |
| mtimes[str(path)] = path.stat().st_mtime |
| return mtimes |
|
|
|
|
| def main(): |
| """Run the server with hot-reload.""" |
| print("π§ββοΈ Wizard-Vibe Core β Hot Reload Watcher") |
| print(" Watching: *.py, *.html, *.css, *.js") |
|
|
| |
| env = os.environ.copy() |
| env["WIZARD_HOT_RELOAD"] = "1" |
|
|
| proc = subprocess.Popen([sys.executable, "core.py"], env=env) |
| last_mtimes = get_mtimes(Path(".")) |
|
|
| try: |
| while True: |
| time.sleep(1) |
| current = get_mtimes(Path(".")) |
|
|
| if current != last_mtimes: |
| changed = [k for k in current if current[k] != last_mtimes.get(k)] |
| print(f"\nπ File change detected: {changed[0] if changed else 'unknown'}") |
| print(" Restarting server...") |
|
|
| proc.terminate() |
| try: |
| proc.wait(timeout=5) |
| except subprocess.TimeoutExpired: |
| proc.kill() |
|
|
| proc = subprocess.Popen([sys.executable, "core.py"], env=env) |
| last_mtimes = current |
| print(f" β
Server restarted (PID: {proc.pid})") |
|
|
| except KeyboardInterrupt: |
| print("\nπ Shutting down...") |
| proc.terminate() |
| proc.wait() |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|