Files
cross-py-builder/ctrl/static/index.html
T
Brett Williams 0e89919342 Add controller with web UI and retire CLI
- 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.
2026-08-30 21:55:46 -05:00

69 lines
2.0 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cross-Py-Builder</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<header>
<h1>Cross-Py-Builder</h1>
<p id="worker-summary"></p>
</header>
<main>
<section class="card" id="submit-card">
<h2>New build</h2>
<form id="job-form">
<div class="field">
<label for="mode">Source</label>
<select id="mode">
<option value="upload">Upload zip</option>
<option value="git">Git repo</option>
</select>
</div>
<div class="field" id="upload-field">
<label for="file">Project zip</label>
<input type="file" id="file" accept=".zip">
</div>
<div class="field" id="url-field" hidden>
<label for="url">Git URL</label>
<input type="text" id="url" placeholder="https://…">
</div>
<div class="fields-row">
<div class="field">
<label for="os">OS</label>
<select id="os"><option value="">Any</option></select>
</div>
<div class="field">
<label for="cpu">CPU</label>
<select id="cpu"><option value="">Any</option></select>
</div>
</div>
<button type="submit">Submit build</button>
<p id="submit-msg" class="msg"></p>
</form>
</section>
<section class="card">
<h2>Jobs</h2>
<div id="jobs"><p class="muted">Loading…</p></div>
</section>
</main>
<div id="modal" class="modal" hidden>
<div class="modal-body">
<button id="modal-close" class="close" aria-label="Close">&times;</button>
<h3 id="modal-title"></h3>
<div class="job-meta"><code id="modal-meta"></code></div>
<div id="status-badge" class="badge"></div>
<div id="artifacts"></div>
<pre id="log"></pre>
</div>
</div>
<script src="/app.js"></script>
</body>
</html>