- Add ctrl/ package: Flask app (waitress), SQLite job store, background
scheduler that probes configured workers, dispatches via /upload and
/checkout_git, fetches artifacts, and serves a single-page UI
- Supporting API: /api/jobs (create/list/detail/cancel), /api/workers,
/api/capabilities, artifact download, and SSE log stream
- Workers keep the existing HTTP API; add /progress/<job_id> endpoint and
per-step build tracking for live status
- Retire agent_manager.py and the cross-py-builder CLI; controller UI is
the primary frontend
- Record design in DESIGN.md; add waitress dependency
Note: /progress is exposed on the worker but the synchronous /upload and
/checkout endpoints block until a build completes, so per-step worker
progress is not yet relayed live in the UI. Live streaming needs an
async-start worker endpoint as a follow-up.
- Add a non-blocking build lock so only one job runs at a time;
concurrent upload/checkout requests get a 409 response
- Add /healthz returning 200 when idle and 503 while a build is running
- Ignore .DS_Store artifacts
- Validate job IDs on /download and /delete; reject invalid identifiers
- Prevent zip-slip during /upload extraction via safe_extract
- Basename uploaded filenames in /update to block path traversal
- Route git-checkout jobs into pybuild-data so they can be downloaded/deleted
- Clean up job dirs on extract, checkout, and build failures
- Ignore Python bytecode and egg-info artifacts