Files
shockbot/mcp/pr.ts
T

91 lines
3.3 KiB
TypeScript

import { type } from "arktype";
import { buildShockbotFooter, stripExistingFooter } from "../utils/buildShockbotFooter.ts";
import { log } from "../utils/cli.ts";
import { fixDoubleEscapedString } from "../utils/fixDoubleEscapedString.ts";
import { $ } from "../utils/shell.ts";
import type { ToolContext } from "./server.ts";
import { execute, tool } from "./shared.ts";
export const PullRequest = type({
title: type.string.describe("the title of the pull request"),
body: type.string.describe("the body content of the pull request"),
base: type.string.describe("the base branch to merge into (e.g., 'main')"),
"draft?": type.boolean.describe("if true, create the pull request as a draft."),
});
function buildPrBodyWithFooter(ctx: ToolContext, body: string): string {
const footer = buildShockbotFooter({ model: ctx.toolState.model });
return `${stripExistingFooter(fixDoubleEscapedString(body))}${footer}`;
}
export const UpdatePullRequestBody = type({
pull_number: type.number.describe("the pull request number to update"),
body: type.string.describe("the new body content for the pull request"),
});
export function UpdatePullRequestBodyTool(ctx: ToolContext) {
return tool({
name: "update_pull_request_body",
description: "Update the body/description of an existing pull request",
parameters: UpdatePullRequestBody,
execute: execute(async (params) => {
const result = await ctx.gitea.rest.repository.repoEditPullRequest({
owner: ctx.repo.owner,
repo: ctx.repo.name,
index: params.pull_number,
body: { body: buildPrBodyWithFooter(ctx, params.body) },
});
log.info(`» updated pull request #${result.data.number}`);
ctx.toolState.wasUpdated = true;
return { success: true, number: result.data.number, url: result.data.html_url };
}),
});
}
export function CreatePullRequestTool(ctx: ToolContext) {
return tool({
name: "create_pull_request",
description: "Create a pull request from the current branch",
parameters: PullRequest,
execute: execute(async (params) => {
const currentBranch = $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false }).trim();
const result = await ctx.gitea.rest.repository.repoCreatePullRequest({
owner: ctx.repo.owner,
repo: ctx.repo.name,
body: {
title: params.title,
body: buildPrBodyWithFooter(ctx, params.body),
head: currentBranch,
base: params.base,
// draft: params.draft ?? false, // not in all Gitea versions
},
});
log.info(`» created pull request #${result.data.number}`);
const reviewer = ctx.payload.triggerer;
if (reviewer && result.data.number) {
try {
await ctx.gitea.rest.repository.repoCreatePullReviewRequests({
owner: ctx.repo.owner,
repo: ctx.repo.name,
index: result.data.number,
body: { reviewers: [reviewer] },
});
} catch {
log.debug(`failed to request review from ${reviewer}`);
}
}
return {
success: true,
number: result.data.number,
url: result.data.html_url,
title: result.data.title,
head: result.data.head?.label ?? result.data.head?.ref,
base: result.data.base?.label ?? result.data.base?.ref,
};
}),
});
}