diff --git a/dashboards/tracker-web/src/app/dashboard/fleet/jobs/page.tsx b/dashboards/tracker-web/src/app/dashboard/fleet/jobs/page.tsx index 633423c3..cac0350f 100644 --- a/dashboards/tracker-web/src/app/dashboard/fleet/jobs/page.tsx +++ b/dashboards/tracker-web/src/app/dashboard/fleet/jobs/page.tsx @@ -48,6 +48,13 @@ const FLEET_REPOS = [ ]; const FLEET_BASE_BRANCH = 'main'; +// Factories set up on this machine. Selecting one routes the job to that factory's +// product (the factory polling that product claims it). +const FLEET_FACTORIES = [ + { id: 'mac-1', label: 'mac-1 — LysnrAI (autoship + PR)', productId: 'lysnrai' }, + { id: 'mac-2', label: 'mac-2 — ChronoMind (human gate + PR)', productId: 'chronomind' }, +]; + export default function FleetJobsPage() { const { token } = useAuth(); const [jobs, setJobs] = useState([]); @@ -56,6 +63,7 @@ export default function FleetJobsPage() { // New-job form state const [showForm, setShowForm] = useState(false); + const [factoryId, setFactoryId] = useState(FLEET_FACTORIES[0].id); const [body, setBody] = useState(''); const [priority, setPriority] = useState<'critical' | 'high' | 'medium' | 'low'>('high'); const [caps, setCaps] = useState('build'); @@ -97,24 +105,32 @@ export default function FleetJobsPage() { .split(',') .map(c => c.trim()) .filter(Boolean); - const { job } = await submitJob({ - idempotencyKey: `ui-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - bodyMd: body.trim(), - priority, - capabilities, - ...(repo - ? { - repo, - baseBranch: FLEET_BASE_BRANCH, - ...(verifyCmd.trim() ? { verify: verifyCmd.trim() } : {}), - ...(autoMerge ? { autoMerge: true } : {}), - } - : {}), - }); + const factory = FLEET_FACTORIES.find(f => f.id === factoryId) ?? FLEET_FACTORIES[0]; + const { job } = await submitJob( + { + idempotencyKey: `ui-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, + bodyMd: body.trim(), + priority, + capabilities, + ...(repo + ? { + repo, + baseBranch: FLEET_BASE_BRANCH, + ...(verifyCmd.trim() ? { verify: verifyCmd.trim() } : {}), + ...(autoMerge ? { autoMerge: true } : {}), + } + : {}), + }, + factory.productId + ); + // Route the dashboard view to the factory's product so the job is visible. + if (typeof window !== 'undefined') { + localStorage.setItem('tracker_selected_product', factory.productId); + } setSubmitMsg({ ok: true, text: - `Submitted ${job.id} (stage: ${job.stage})` + + `Submitted ${job.id} to ${factory.id} (${factory.productId}, stage: ${job.stage})` + (repo ? ` — PR mode: ${repo}@${FLEET_BASE_BRANCH}${verifyCmd.trim() ? ' +verify' : ''}${autoMerge ? ' +auto-merge' : ''}` : ' — no PR (plain job)') + @@ -128,7 +144,7 @@ export default function FleetJobsPage() { } finally { setSubmitting(false); } - }, [body, caps, priority, repo, verifyCmd, autoMerge, refresh]); + }, [body, caps, priority, repo, verifyCmd, autoMerge, factoryId, refresh]); return (
@@ -147,6 +163,23 @@ export default function FleetJobsPage() { {showForm && (
+
+ + +