Replace the linear setup.sh with an interactive menu-driven installer:
- First-time wizard with OS detection and profile selection
- Install profiles: Core SIGINT, Maritime, Weather, RF Security, Full, Custom
- System health check (tools, SDR devices, ports, permissions, venv, PostgreSQL)
- Automated PostgreSQL setup for ADS-B history (creates DB, user, tables, indexes)
- Environment configurator for interactive INTERCEPT_* variable editing
- Update tools (rebuild source-built binaries)
- Uninstall/cleanup with granular options and double-confirm for destructive ops
- View status table of all tools with installed/missing state
- CLI flags: --non-interactive, --profile=, --health-check, --postgres-setup, --menu
- .env file helpers (read/write) with start.sh auto-sourcing
- Bash 3.2 compatible (no associative arrays) for macOS support
Update all documentation to reflect the new menu system:
- README.md: installation section with profiles, CLI flags, env config, health check
- CLAUDE.md: entry points and local setup commands
- docs/index.html: GitHub Pages install cards with profile mentions
- docs/HARDWARE.md: setup script section with profile table
- docs/TROUBLESHOOTING.md: health check and profile-based install guidance
- docs/DISTRIBUTED_AGENTS.md: controller quick start
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Running via sudo creates data/radiosonde/ as root. On next run the
config write fails with an unhandled OSError, Flask returns an HTML 500,
and the frontend shows a cryptic JSON parse error.
Three-layer fix:
- start.sh: pre-create known data dirs before chown, add certs/ to the
list, export INTERCEPT_SUDO_UID/GID for runtime use
- generate_station_cfg: catch OSError with actionable message, chown
newly created files to the real user via _fix_data_ownership()
- start_radiosonde: wrap config generation in try/except so it returns
JSON instead of letting Flask emit an HTML error page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolves the machine's LAN IP via hostname -I so users see a
clickable URL they can use from other devices on the network.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When start.sh runs via sudo, chown instance/ and data/ back to the
invoking user so the SQLite DB stays accessible without sudo. Also
adds a clear error message in get_connection() when the DB can't be
opened due to permissions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When stopping gunicorn with Ctrl+C, the gevent worker's handle_quit()
calls sys.exit(0) inside a greenlet, causing gevent to print a
SystemExit traceback. Add a gunicorn config with post_worker_init hook
that marks SystemExit as a non-error in gevent's hub.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All other docs already reference sudo ./start.sh but the inline usage
comments in start.sh itself and the --help example in USAGE.md were
missing it, which could lead users to run without root privileges.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Long-lived SSE connections prevent the gevent worker from exiting on
SIGINT. --graceful-timeout 5 force-kills the worker after 5 seconds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gunicorn's gevent worker (-k gevent) handles monkey-patching internally.
The manual patch_all() in app.py ran in the master process before worker
fork, preventing the worker from booting (no 'Booting worker' log line,
server unreachable).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolves ModuleNotFoundError when running outside a venv by auto-detecting
the venv/bin/python relative to the script, falling back to VIRTUAL_ENV
or system python3.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add start.sh as the recommended production entry point with:
- gunicorn + gevent worker for concurrent SSE/WebSocket handling
- CLI flags for port, host, debug, HTTPS, and dependency checks
- Auto-fallback to Flask dev server if gunicorn not installed
- Conditional gevent monkey-patch in app.py via INTERCEPT_USE_GEVENT env var
- Docker CMD updated to use start.sh
- Updated all docs, setup.sh, and requirements.txt accordingly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>