import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { pullInput, requirePull, requirePullMutation } from "~/server/pull-access";
import { limitBrowse, limitWrite } from "~/server/limits";
import { currentBaseSha, loadPullRepos } from "~/server/pull-merge";
import { assertNotArchived, canAdministerAccount, requireRepoAccess } from "~/server/repos";
import { startMergeFix } from "~/server/mergefix/service";
import { applyProposal } from "~/server/mergefix/apply";
import { MERGEFIX_MODES } from "~/server/mergefix/proposal";
import { latestRuns, loadRepoSettings, saveRepoSettings } from "~/server/mergefix/store";
import { AI_ENDPOINT_KINDS, BYOK_PROVIDERS, endpointSummary } from "~/server/ai/endpoint";
import type { FixPlan } from "~/server/mergefix/plan";
import { usageSummary } from "~/server/metering/summary";
import { first } from "~/server/db";
import { forbidden } from "~/server/errors";
import { repoRef } from "~/lib/validation";
function aiUsage(summary: Awaited<ReturnType<typeof usageSummary>>) {
const meter = (id: string) => summary.meters.find((entry) => entry.meter === id);
const view = (id: string) => ({ used: meter(id)?.quantity ?? 0, cap: meter(id)?.hardCap ?? null });
return {
month: summary.period,
calls: view("ai.calls"),
tokens: view("ai.tokens"),
byokCalls: view("ai.byok_calls").used,
byokTokens: view("ai.byok_tokens").used,
};
}
export const startPullMergeFix = createServerFn({ method: "POST" })
.middleware([viewerMiddleware])
.validator(pullInput.extend({ mode: z.enum(MERGEFIX_MODES).optional() }))
.handler(async ({ data, context }) => {
const viewer = requireViewer(context.viewer);
await limitWrite(viewer);
const { pull } = await requirePullMutation(data.owner, data.repo, data.number, viewer, "write");
return { runId: await startMergeFix(pull, viewer, "button", null, data.mode) };
});