UNPKG

@cyanheads/git-mcp-server

Version:

An MCP (Model Context Protocol) server enabling LLMs and AI agents to interact with Git repositories. Provides tools for comprehensive Git operations including clone, commit, branch, diff, log, status, push, pull, merge, rebase, worktree, tag management,

108 lines 4.44 kB
/** * @fileoverview Defines the core logic, schemas, and types for the git_rebase tool. * @module src/mcp-server/tools/gitRebase/logic */ import { execFile } from "child_process"; import { promisify } from "util"; import { z } from "zod"; import { logger, sanitization, } from "../../../utils/index.js"; import { McpError, BaseErrorCode } from "../../../types-global/errors.js"; import { getGitStatus, GitStatusOutputSchema } from "../gitStatus/logic.js"; const execFileAsync = promisify(execFile); // 1. DEFINE the Zod input schema. export const GitRebaseBaseSchema = z.object({ path: z.string().default(".").describe("Path to the local Git repository."), mode: z .enum(["start", "continue", "abort", "skip"]) .default("start") .describe("Rebase operation mode."), upstream: z .string() .min(1) .optional() .describe("The upstream branch or commit to rebase onto."), branch: z.string().min(1).optional().describe("The branch to rebase."), interactive: z .boolean() .default(false) .describe("Perform an interactive rebase."), strategy: z .enum(["recursive", "resolve", "ours", "theirs", "octopus", "subtree"]) .optional() .describe("The merge strategy to use."), strategyOption: z .string() .optional() .describe("Pass a specific option to the merge strategy."), onto: z .string() .min(1) .optional() .describe("Rebase onto a specific commit/branch instead of the upstream's base."), }); export const GitRebaseInputSchema = GitRebaseBaseSchema.refine((data) => !(data.mode === "start" && !data.interactive && !data.upstream), { message: "An 'upstream' branch/commit is required for 'start' mode unless 'interactive' is true.", path: ["upstream"], }); // 2. DEFINE the Zod response schema. export const GitRebaseOutputSchema = z.object({ success: z.boolean().describe("Indicates if the command was successful."), message: z.string().describe("A summary message of the result."), rebaseCompleted: z .boolean() .optional() .describe("True if the rebase finished successfully."), needsManualAction: z .boolean() .optional() .describe("True if conflicts or interactive steps require user input."), status: GitStatusOutputSchema.optional().describe("The status of the repository after the rebase operation."), }); /** * 4. IMPLEMENT the core logic function. * @throws {McpError} If the logic encounters an unrecoverable issue. */ export async function gitRebaseLogic(params, context) { const operation = `gitRebaseLogic:${params.mode}`; logger.debug(`Executing ${operation}`, { ...context, params }); const workingDir = context.getWorkingDirectory(); if (params.path === "." && !workingDir) { throw new McpError(BaseErrorCode.VALIDATION_ERROR, "No session working directory set. Please specify a 'path' or use 'git_set_working_dir' first."); } const targetPath = sanitization.sanitizePath(params.path === "." ? workingDir : params.path, { allowAbsolute: true }).sanitizedPath; const args = ["-C", targetPath, "rebase"]; switch (params.mode) { case "start": if (params.interactive) args.push("-i"); if (params.strategy) args.push(`--strategy=${params.strategy}`); if (params.strategyOption) args.push(`-X${params.strategyOption}`); if (params.onto) args.push("--onto", params.onto); if (params.upstream) args.push(params.upstream); if (params.branch) args.push(params.branch); break; default: args.push(`--${params.mode}`); break; } logger.debug(`Executing command: git ${args.join(" ")}`, { ...context, operation, }); const { stdout, stderr } = await execFileAsync("git", args); const output = stdout + stderr; const status = await getGitStatus({ path: targetPath }, context); return { success: true, message: `Rebase ${params.mode} executed successfully.`, rebaseCompleted: /successfully rebased/i.test(output), needsManualAction: /conflict|stopped at|edit/i.test(output), status, }; } //# sourceMappingURL=logic.js.map