import { SELECTED_SURFACE } from "~/ui/tones"; import { useState } from "react"; import { startPullMergeFix } from "~/fns/mergefix"; import { MERGE_FIX_ACTIVE, useMergeFix, type MergeFix, type PullParams } from "~/hooks/use-merge-fix"; import { useAction } from "~/hooks/use-action"; import { MergeFixProposal } from "~/components/MergeFixProposal"; import { Badge } from "~/ui/Badge"; import { Panel } from "~/ui/Panel"; import { Button } from "~/ui/Button"; import { ErrorBanner } from "~/ui/Callout"; import { cn } from "~/utils/cn"; const STATUS_COPY = { queued: "Queued", running: "Analyzing conflicts", applying: "Committing fix", applied: "Fix committed", suggested: "Proposal ready", failed: "Failed", } as const; const REQUEUE_COPY = { waiting: "Rejoins the merge queue once CI passes", enqueued: "Back in the merge queue", gave_up: "Not re-queued", } as const; function percent(value: number | undefined): string { return `${Math.round((value ?? 0) * 100)}%`; } export function MergeFixPanel({ params, initial, canStart, onPick, onApplied, }: { params: PullParams; initial: MergeFix; canStart: boolean; onPick: (path: string, hunk: number, text: string) => void; onApplied: () => void; }) { const start = useAction(startPullMergeFix, { invalidate: false }); const { fix, refresh } = useMergeFix(params, initial, (next) => { if (next?.status === "applied") onApplied(); }); const [picked, setPicked] = useState(new Map()); const busy = fix !== null && MERGE_FIX_ACTIVE.has(fix.status); const startRun = async (mode: "propose" | "auto") => { const result = await start.run({ data: { ...params, mode } }); if (result) await refresh(); }; const pick = (path: string, hunk: number, id: string, text: string) => { setPicked(new Map(picked).set(`${path}#${hunk}`, id)); onPick(path, hunk, text); }; return ( ) } >
{!fix ? (

Generates candidate resolutions per conflict and asks a decision model to rank them. You get a proposal with per-file diffs, risk and reasoning to accept or reject before anything is pushed. The one-shot option commits confident, low-risk fixes directly and still falls back to a proposal for anything else.

) : (
{STATUS_COPY[fix.status]} {fix.commitSha && {fix.commitSha.slice(0, 7)}} {fix.stale && ( The head or base branch changed since this run; propose again to get a fresh fix. )} {fix.error && {fix.error}} {fix.requeue && ( {REQUEUE_COPY[fix.requeue.status]} {fix.requeue.error ? `: ${fix.requeue.error}` : ""} )} {fix.calls} model call(s)
)} {fix?.status === "suggested" && !fix.stale && ( file.hunks .map((hunk, index) => ({ hunk, index, key: `${file.path}#${index}` })) .map(({ hunk, index, key }) => (
Conflict {index + 1}: pick a candidate to edit by hand
{[...hunk.candidates] .sort((left, right) => (hunk.probabilities[right.id] ?? 0) - (hunk.probabilities[left.id] ?? 0)) .map((candidate) => ( ))}
)) } /> )}
); }