54 lines · 2.5 KB
import { allConfident } from "./decide";
import type { FixPlan } from "./plan";

export const MERGEFIX_MODES = ["propose", "auto"] as const;
export type MergeFixMode = (typeof MERGEFIX_MODES)[number];

/** An explicit request wins; otherwise the repository's opt-in decides, and proposals are the default. */
export function resolveMode(requested: MergeFixMode | undefined, repoAutoApply: boolean): MergeFixMode {
  return requested ?? (repoAutoApply ? "auto" : "propose");
}

/** Only auto mode lands a plan without review, and only when decide.ts raised no reasons for any file. */
export function shouldAutoApply(mode: MergeFixMode, plan: FixPlan): boolean {
  return (
    mode === "auto" &&
    plan.autoApply &&
    plan.files.every((file) => file.status === "planned" && allConfident(file.decision))
  );
}

/** Accepted files whose picks fell below the confidence threshold; applying them needs an explicit confirmation. */
export function belowThreshold(plan: FixPlan, paths: string[]): string[] {
  const wanted = new Set(paths);
  return plan.files.flatMap((file) =>
    file.status === "planned" && wanted.has(file.path) && !allConfident(file.decision) ? [file.path] : [],
  );
}

export type Resolution = { path: string; content: string };

export type Selection = { ok: true; resolutions: Resolution[] } | { ok: false; error: string };

/** Picks the accepted files of a proposal; omitted `paths` means every file that has a resolution. */
export function selectResolutions(plan: FixPlan, paths?: string[]): Selection {
  const available = new Map(
    plan.files.flatMap((file) =>
      file.status === "planned" && file.resolution !== null ? [[file.path, file.resolution] as const] : [],
    ),
  );
  const wanted = paths === undefined ? [...available.keys()] : [...new Set(paths)];