import { z } from "zod";
import { forbidden, notFoundError } from "../errors";
import { limitHeavy, limitWrite } from "../limits";
import { latestRuns } from "../mergefix/store";
import { startMergeFix } from "../mergefix/service";
import { applyProposal } from "../mergefix/apply";
import { MERGEFIX_MODES } from "../mergefix/proposal";
import type { FixPlan } from "../mergefix/plan";
import type { PullRow } from "../pulls";
import type { RepoRow } from "~/lib/types";
import { loadPull } from "../pulls";
import { assertNotArchived, hasPermission, loadRepoById } from "../repos";
import { scopedRepoPermission } from "../token-scope";
import { readJson, requireScopedRepo } from "./http";
import type { ApiContext } from "./http";
const HTTP_ACCEPTED = 202;
const MAX_APPLY_FILES = 100;
const startBody = z.object({ mode: z.enum(MERGEFIX_MODES).optional() });
const applyBody = z.object({
files: z.array(z.string().min(1).max(4096)).min(1).max(MAX_APPLY_FILES).optional(),
confirm_low_confidence: z.boolean().optional(),
});
async function loadScopedPull(ctx: ApiContext, owner: string, name: string, number: number, needed: "read" | "write") {
const { repo } = await requireScopedRepo(ctx, owner, name, "pulls", needed);
const pull = await loadPull(repo.id, number);
if (!pull) throw notFoundError("Pull request not found");
return { repo, pull };
}
async function requireHeadToken(ctx: ApiContext, repo: RepoRow, pull: PullRow): Promise<void> {
const headRepo = pull.head_repo_id === repo.id ? repo : await loadRepoById(pull.head_repo_id);
if (!headRepo) throw notFoundError("Head repository was deleted");
if (!hasPermission(await scopedRepoPermission(headRepo, ctx.credential, "contents"), "write")) {
throw forbidden("This token cannot push to the head branch");
}
}