From c239abeec9d51b3691cfce72affd74d5c202aea9 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Sun, 31 May 2026 06:17:19 -0700 Subject: [PATCH] feat(fleet): per-repo verify + auto-merge options for PR jobs Add job-level verify (command run in the PR checkout before opening the PR) and autoMerge (squash-merge the PR once opened). Surfaced in the New Job form as a Verify-command field + Auto-merge checkbox (PR mode only); confirmation now shows PR-mode/repo. More repos added to the dropdown. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../src/app/dashboard/fleet/jobs/page.tsx | 56 ++++++++++++++++++- .../tracker-web/src/lib/fleet-client.ts | 3 + .../src/modules/fleet/coordinator.ts | 2 + .../src/modules/fleet/types.ts | 6 ++ 4 files changed, 64 insertions(+), 3 deletions(-) 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 b9d2ce8c..633423c3 100644 --- a/dashboards/tracker-web/src/app/dashboard/fleet/jobs/page.tsx +++ b/dashboards/tracker-web/src/app/dashboard/fleet/jobs/page.tsx @@ -40,6 +40,11 @@ const FLEET_REPOS = [ 'learning_ai_2nd_brain', 'learning_ai_auth_app', 'learning_agent_monitoring_fx', + 'learning_notif_scanr', + 'learning_ai_local_llms', + 'learning_ai_mac_tooling', + 'learning_ai_productivity_web', + 'learning_ai_webui_copilot', ]; const FLEET_BASE_BRANCH = 'main'; @@ -55,6 +60,8 @@ export default function FleetJobsPage() { const [priority, setPriority] = useState<'critical' | 'high' | 'medium' | 'low'>('high'); const [caps, setCaps] = useState('build'); const [repo, setRepo] = useState(''); + const [verifyCmd, setVerifyCmd] = useState(''); + const [autoMerge, setAutoMerge] = useState(false); const [submitting, setSubmitting] = useState(false); const [submitMsg, setSubmitMsg] = useState<{ ok: boolean; text: string } | null>(null); @@ -95,9 +102,24 @@ export default function FleetJobsPage() { bodyMd: body.trim(), priority, capabilities, - ...(repo ? { repo, baseBranch: FLEET_BASE_BRANCH } : {}), + ...(repo + ? { + repo, + baseBranch: FLEET_BASE_BRANCH, + ...(verifyCmd.trim() ? { verify: verifyCmd.trim() } : {}), + ...(autoMerge ? { autoMerge: true } : {}), + } + : {}), + }); + setSubmitMsg({ + ok: true, + text: + `Submitted ${job.id} (stage: ${job.stage})` + + (repo + ? ` — PR mode: ${repo}@${FLEET_BASE_BRANCH}${verifyCmd.trim() ? ' +verify' : ''}${autoMerge ? ' +auto-merge' : ''}` + : ' — no PR (plain job)') + + '.', }); - setSubmitMsg({ ok: true, text: `Submitted ${job.id} (stage: ${job.stage}).` }); setBody(''); await refresh(); } catch (err: unknown) { @@ -106,7 +128,7 @@ export default function FleetJobsPage() { } finally { setSubmitting(false); } - }, [body, caps, priority, repo, refresh]); + }, [body, caps, priority, repo, verifyCmd, autoMerge, refresh]); return (
@@ -191,6 +213,34 @@ export default function FleetJobsPage() {

)}
+ {repo && ( +
+ + setVerifyCmd(e.target.value)} + placeholder="e.g. pnpm install && pnpm test" + className="w-64 rounded border bg-background px-2 py-1 text-sm font-mono" + /> +

+ Runs in the checkout; the PR opens only if it passes. +

+
+ )} + {repo && ( + + )} diff --git a/dashboards/tracker-web/src/lib/fleet-client.ts b/dashboards/tracker-web/src/lib/fleet-client.ts index ea02164b..666641de 100644 --- a/dashboards/tracker-web/src/lib/fleet-client.ts +++ b/dashboards/tracker-web/src/lib/fleet-client.ts @@ -202,6 +202,9 @@ export interface SubmitJobBody { /** PR mode: open a PR against this repo (`owner/name` or clone URL) + base branch. */ repo?: string; baseBranch?: string; + /** PR mode: verify command run in the checkout before the PR opens; auto-merge the PR. */ + verify?: string; + autoMerge?: boolean; } /** Submit a new fleet job. Returns the created job. */ diff --git a/services/platform-service/src/modules/fleet/coordinator.ts b/services/platform-service/src/modules/fleet/coordinator.ts index 04e481f0..46765df5 100644 --- a/services/platform-service/src/modules/fleet/coordinator.ts +++ b/services/platform-service/src/modules/fleet/coordinator.ts @@ -214,6 +214,8 @@ export async function submitJob(productId: string, input: SubmitJobInput): Promi trackerItemId: input.trackerItemId, repo: input.repo, baseBranch: input.baseBranch, + verify: input.verify, + autoMerge: input.autoMerge, attempts: 0, leaseEpoch: 0, rev: 0, diff --git a/services/platform-service/src/modules/fleet/types.ts b/services/platform-service/src/modules/fleet/types.ts index ef87bc3d..f84add31 100644 --- a/services/platform-service/src/modules/fleet/types.ts +++ b/services/platform-service/src/modules/fleet/types.ts @@ -185,6 +185,8 @@ export const FleetJobDocSchema = z.object({ */ repo: z.string().optional(), baseBranch: z.string().optional(), + verify: z.string().optional(), + autoMerge: z.boolean().optional(), checkpoint: CheckpointSchema.optional(), attempts: z.number().int().nonnegative().default(0), leaseEpoch: z.number().int().nonnegative().default(0), @@ -352,6 +354,10 @@ export const SubmitJobSchema = z.object({ /** Optional PR target (§PR mode): repo (`owner/name` or clone URL) + base branch. */ repo: z.string().optional(), baseBranch: z.string().optional(), + /** PR mode options: verify command to run in the checkout before opening the PR, + * and whether to auto-merge the PR once opened. */ + verify: z.string().optional(), + autoMerge: z.boolean().optional(), /** Phase 3 DAG: inline children to create atomically with the parent. */ children: z .array(