import { z } from "zod";
import { getCommitUrlForHash, getGitHubCompareUrl, gitRemoteUrlToWeb, isGitHubUrl, SUPERBLOCKS_LIVE_GIT_BRANCH, } from "@superblocksteam/shared";
import { GIT_OPERATION_BUSY_MESSAGE_FOR_CLARK, } from "../../../../git-operation-lock.js";
import { GitAuthError, GitConflictError, GitNonFastForwardError, GitRemoteError, classifyGitError, } from "../../../../git-service/index.js";
import { getSyncCountsAgainstDefaultBranch } from "../../../../git-service/status-sync.js";
import { getLogger } from "../../../../util/logger.js";
import { createToolFactory, PermissionLevel, ToolCategory, ToolExecutionError, } from "../types.js";
const GIT_OPERATIONS = [
    "commit",
    "create_pr",
    "deploy",
    "diff",
    "log",
    "log_from_main",
    "merge_abort",
    "pull",
    "stage",
    "status",
];
const gitInputSchema = z
    .object({
    operation: z.enum(GIT_OPERATIONS).describe("The git operation to run"),
    count: z
        .number()
        .int()
        .min(1)
        .max(50)
        .optional()
        .describe("Number of commits to return for log (default 10, max 50)"),
    staged: z
        .boolean()
        .optional()
        .describe("For diff: if true, show staged (cached) changes instead of unstaged"),
    paths: z
        .array(z.string())
        .optional()
        .describe('For stage: file paths to stage (relative to repo root). Use ["."] to stage all.'),
    message: z
        .string()
        .optional()
        .describe("For commit: commit message describing the changes"),
    title: z
        .string()
        .max(150)
        .optional()
        .describe("For create_pr: pull request title. Generate a concise summary of the changes."),
    body: z
        .string()
        .max(2000)
        .optional()
        .describe("For create_pr: pull request body/description in markdown. Summarize what changed and why."),
    sha: z
        .string()
        .optional()
        .describe("For deploy: the full git commit SHA on the main/default branch to deploy (required for deploy)"),
})
    .superRefine((data, ctx) => {
    if (data.operation === "stage") {
        if (!data.paths || data.paths.length === 0) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: "paths is required for stage and must have at least one path",
                path: ["paths"],
            });
        }
    }
    if (data.operation === "commit") {
        if (data.message === undefined || data.message.trim() === "") {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: "message is required for commit and must be non-empty",
                path: ["message"],
            });
        }
    }
    if (data.operation === "deploy") {
        if (data.sha === undefined ||
            data.sha.trim() === "" ||
            !/^[0-9a-f]{5,40}$/i.test(data.sha.trim())) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: "sha is required for deploy and must be a valid git commit SHA",
                path: ["sha"],
            });
        }
    }
});
const REMOTE_LIVE_BRANCH = `origin/${SUPERBLOCKS_LIVE_GIT_BRANCH}`;
const GIT_DESCRIPTION = `Run a git operation in the repository. ` +
    `All work happens on the ${SUPERBLOCKS_LIVE_GIT_BRANCH} branch. ` +
    `Use status for working tree and sync state; log for recent commits on ${SUPERBLOCKS_LIVE_GIT_BRANCH}; ` +
    `log_from_main to fetch and list commits on the default branch (origin/main) — ` +
    `use this to get commit SHAs for deploy; ` +
    `diff for changes (unstaged or staged); stage to stage paths; ` +
    `commit to stage all, commit with a message, and push to ${REMOTE_LIVE_BRANCH}; ` +
    `merge_abort to abort an in-progress merge; ` +
    `pull to fetch and merge ${REMOTE_LIVE_BRANCH} and sync; ` +
    `create_pr to generate a GitHub "new pull request" URL — ` +
    `always show the returned prUrl as a clickable markdown link so the user can open it ` +
    `(provide title and body you generate from the session context); ` +
    `deploy to build and deploy a specific commit from the main/default branch ` +
    `(requires the full SHA from log_from_main — the SHA MUST be a commit directly on main, ` +
    `not a commit from a feature branch; always use log_from_main first to get the correct SHA). ` +
    `If commit reports pushed=false with a non-fast-forward error, use pull to ` +
    `merge remote changes (resolving any conflicts), then commit again.`;
function getGitToolInputFields(input) {
    switch (input.operation) {
        case "commit":
            return {
                gitBranch: SUPERBLOCKS_LIVE_GIT_BRANCH,
                gitMessageLength: input.message?.length ?? 0,
            };
        case "diff":
            return {
                gitDiffMode: input.staged ? "staged" : "unstaged",
            };
        case "log":
            return {
                gitRequestedCommitCount: input.count ?? 10,
            };
        case "log_from_main":
            return {
                gitRequestedCommitCount: input.count ?? 10,
            };
        case "pull":
            return {
                gitBranch: SUPERBLOCKS_LIVE_GIT_BRANCH,
                gitRemoteRef: REMOTE_LIVE_BRANCH,
            };
        case "stage":
            return {
                gitPathCount: input.paths?.length ?? 0,
            };
        case "create_pr":
            return {
                gitBranch: SUPERBLOCKS_LIVE_GIT_BRANCH,
                gitHasTitle: !!input.title,
                gitHasBody: !!input.body,
            };
        case "deploy":
            return {
                gitDeploySha: input.sha ?? "",
            };
        default:
            return {};
    }
}
function getGitToolErrorFields(error) {
    const source = error instanceof ToolExecutionError && error.cause !== undefined
        ? error.cause
        : error;
    if (source instanceof GitAuthError) {
        return {
            gitErrorKind: "auth",
            gitErrorMessage: source.message,
        };
    }
    if (source instanceof GitConflictError) {
        return {
            gitErrorKind: "conflict",
            gitErrorMessage: source.message,
            gitConflictFileCount: source.files.length,
        };
    }
    if (source instanceof GitNonFastForwardError) {
        return {
            gitErrorKind: "non_fast_forward",
            gitErrorMessage: source.message,
        };
    }
    if (source instanceof GitRemoteError) {
        return {
            gitErrorKind: "remote",
            gitErrorMessage: source.message,
        };
    }
    if (source instanceof Error) {
        return {
            gitErrorKind: source.name,
            gitErrorMessage: source.message,
        };
    }
    return {
        gitErrorKind: "unknown",
        gitErrorMessage: String(source),
    };
}
function getActionNameForOp(input) {
    if (!input || !("operation" in input)) {
        return {
            future: "run git operation",
            present: "running git operation",
            past: "ran git operation",
        };
    }
    switch (input.operation) {
        case "commit":
            return {
                future: "commit and push changes",
                present: "committing and pushing changes",
                past: "committed and pushed changes",
            };
        case "merge_abort":
            return {
                future: "abort merge",
                present: "aborting merge",
                past: "aborted merge",
            };
        case "stage":
            return {
                future: "stage files",
                present: "staging files",
                past: "staged files",
            };
        case "pull":
            return {
                future: "pull latest changes from remote",
                present: "pulling latest changes from remote",
                past: "pulled latest changes from remote",
            };
        case "create_pr":
            return {
                future: "open pull request",
                present: "opening pull request",
                past: "opened pull request",
            };
        case "deploy":
            return {
                future: "build and deploy commit",
                present: "building and deploying commit",
                past: "built and deployed commit",
            };
        case "log_from_main":
            return {
                future: "check main branch commits",
                present: "checking main branch commits",
                past: "checked main branch commits",
            };
        default:
            return {
                future: `run git ${input.operation}`,
                present: `running git ${input.operation}`,
                past: `ran git ${input.operation}`,
            };
    }
}
function formatInputForOp(input) {
    switch (input.operation) {
        case "commit":
            return { targets: [SUPERBLOCKS_LIVE_GIT_BRANCH], details: input.message };
        case "stage":
            return { targets: input.paths ?? [] };
        case "pull":
            return { targets: [REMOTE_LIVE_BRANCH] };
        case "merge_abort":
            return { targets: [] };
        case "create_pr":
            return {
                targets: [SUPERBLOCKS_LIVE_GIT_BRANCH],
                summary: input.title,
            };
        case "deploy":
            return {
                targets: [input.sha ?? ""],
                summary: "deploy commit to production",
            };
        case "log_from_main":
            return { targets: ["origin/main"] };
        default:
            return { targets: [input.operation] };
    }
}
async function getStatusSyncCounts(args) {
    const { gitService, logger } = args;
    const syncCounts = await getSyncCountsAgainstDefaultBranch({
        gitService,
        leftRef: SUPERBLOCKS_LIVE_GIT_BRANCH,
    });
    if ("degraded" in syncCounts) {
        logger.info("[git] tool status base ref missing; defaulting ahead/behind to 0", {
            gitCategory: "status",
            gitOperation: "status",
            gitOutcome: "degraded",
            gitErrorKind: "default_branch_ref_missing",
            branch: SUPERBLOCKS_LIVE_GIT_BRANCH,
            gitBaseRefCandidates: syncCounts.baseRefCandidates,
        });
    }
    return { ahead: syncCounts.ahead, behind: syncCounts.behind };
}
async function getRepositoryWebUrl(gitService) {
    try {
        const remoteUrl = (await gitService.raw(["remote", "get-url", "origin"])).trim();
        return gitRemoteUrlToWeb(remoteUrl) ?? undefined;
    }
    catch {
        return undefined;
    }
}
export const gitToolFactory = createToolFactory("git", (deps) => ({
    description: GIT_DESCRIPTION,
    category: ToolCategory.GIT,
    defaultPermission: PermissionLevel.ALLOW,
    readOnly: true,
    inputSchema: gitInputSchema,
    getActionName: (input) => getActionNameForOp(input),
    formatInput: (input) => formatInputForOp(input),
    execute: async (input) => {
        const logger = getLogger();
        const { gitService, syncService, gitOperationLock, onGitOperationComplete, onGitSetupRequired, } = deps;
        if (!gitService) {
            await onGitSetupRequired?.();
            return { setupRequired: true };
        }
        const lockResult = gitOperationLock?.tryAcquire();
        if (lockResult && !lockResult.acquired) {
            logger.warn("[git] tool execution blocked by lock", {
                gitCategory: "agent_tool",
                gitOperation: input.operation,
                gitOutcome: "blocked",
                ...getGitToolInputFields(input),
            });
            throw new ToolExecutionError(GIT_OPERATION_BUSY_MESSAGE_FOR_CLARK, {
                toolName: "git",
                input: { operation: input.operation },
                context: {},
                severity: "warn",
            });
        }
        const releaseLock = lockResult?.acquired ? lockResult.release : undefined;
        try {
            let result;
            switch (input.operation) {
                case "status": {
                    const status = await gitService.status();
                    const { ahead, behind } = await getStatusSyncCounts({
                        gitService,
                        logger,
                    });
                    result = { files: status.files, ahead, behind };
                    break;
                }
                case "log": {
                    const count = input.count ?? 10;
                    const logResult = await gitService.log({ maxCount: count });
                    const repositoryWebUrl = await getRepositoryWebUrl(gitService);
                    const commits = logResult.all.map((entry) => ({
                        sha: entry.hash,
                        message: entry.message,
                        ...(repositoryWebUrl
                            ? {
                                url: getCommitUrlForHash({
                                    hash: entry.hash,
                                    repositoryWebUrl,
                                }) ?? undefined,
                            }
                            : {}),
                    }));
                    result = { commits };
                    break;
                }
                case "log_from_main": {
                    const count = input.count ?? 10;
                    const defaultBranch = await gitService.getDefaultBranch();
                    await gitService.fetch("origin", defaultBranch);
                    const rawLog = await gitService.raw([
                        "log",
                        "--first-parent",
                        "--format=%H %s",
                        "-n",
                        count.toString(),
                        `origin/${defaultBranch}`,
                    ]);
                    const repositoryWebUrl = await getRepositoryWebUrl(gitService);
                    const commits = rawLog
                        .trim()
                        .split("\n")
                        .filter(Boolean)
                        .map((line) => {
                        const spaceIdx = line.indexOf(" ");
                        const hash = spaceIdx === -1 ? line : line.slice(0, spaceIdx);
                        const message = spaceIdx === -1 ? "" : line.slice(spaceIdx + 1);
                        return {
                            sha: hash,
                            message,
                            ...(repositoryWebUrl
                                ? {
                                    url: getCommitUrlForHash({
                                        hash,
                                        repositoryWebUrl,
                                    }) ?? undefined,
                                }
                                : {}),
                        };
                    });
                    result = { commits };
                    break;
                }
                case "diff": {
                    const staged = input.staged ?? false;
                    const diff = staged
                        ? await gitService.diff(["--cached"])
                        : await gitService.diff();
                    result = { diff };
                    break;
                }
                case "stage": {
                    if (!input.paths || input.paths.length === 0) {
                        throw new ToolExecutionError("paths is required for stage and must have at least one path", {
                            toolName: "git",
                            input,
                            context: {},
                        });
                    }
                    const paths = input.paths;
                    for (const p of paths) {
                        await gitService.add(p);
                    }
                    result = { staged: paths };
                    break;
                }
                case "commit": {
                    const message = input.message?.trim();
                    if (message === undefined || message === "") {
                        throw new ToolExecutionError("message is required for commit and must be non-empty", {
                            toolName: "git",
                            input,
                            context: {},
                        });
                    }
                    const pushLiveBranchWithAutoRecreate = async () => {
                        let remoteExists = null;
                        try {
                            const refs = await gitService.raw([
                                "ls-remote",
                                "--heads",
                                "origin",
                                `refs/heads/${SUPERBLOCKS_LIVE_GIT_BRANCH}`,
                            ]);
                            remoteExists = refs.includes(`refs/heads/${SUPERBLOCKS_LIVE_GIT_BRANCH}`);
                        }
                        catch {
                            // Continue with normal push if we cannot check remote refs.
                        }
                        try {
                            await gitService.push("origin", SUPERBLOCKS_LIVE_GIT_BRANCH);
                        }
                        catch (pushError) {
                            if (remoteExists === false) {
                                await gitService.raw([
                                    "push",
                                    "origin",
                                    `HEAD:${SUPERBLOCKS_LIVE_GIT_BRANCH}`,
                                ]);
                                return;
                            }
                            throw pushError;
                        }
                    };
                    try {
                        await gitService.add(".");
                        const commitResult = await gitService.commit(message);
                        const sha = commitResult.commit;
                        const repositoryWebUrl = await getRepositoryWebUrl(gitService);
                        onGitOperationComplete?.(); // to update the versions sidebar panel
                        let pushed = false;
                        try {
                            await pushLiveBranchWithAutoRecreate();
                            pushed = true;
                        }
                        catch (pushError) {
                            const classified = classifyGitError(pushError);
                            if (classified instanceof GitNonFastForwardError ||
                                classified instanceof GitAuthError ||
                                classified instanceof GitRemoteError) {
                                result = {
                                    sha,
                                    pushed: false,
                                    error: classified.message,
                                };
                                break;
                            }
                            throw pushError;
                        }
                        result = {
                            sha,
                            pushed,
                            ...(repositoryWebUrl
                                ? {
                                    url: getCommitUrlForHash({
                                        hash: sha,
                                        repositoryWebUrl,
                                    }) ?? undefined,
                                }
                                : {}),
                        };
                        break;
                    }
                    catch (error) {
                        const classified = classifyGitError(error);
                        if (classified instanceof GitAuthError) {
                            throw new ToolExecutionError("Git authentication failed. Please check your git credentials " +
                                "in the repository settings.", {
                                toolName: "git",
                                input: { operation: "commit", message },
                                context: {},
                                cause: classified,
                                severity: "warn",
                            });
                        }
                        if (classified instanceof GitRemoteError) {
                            throw new ToolExecutionError(`Git remote error: ${classified.message}`, {
                                toolName: "git",
                                input: { operation: "commit", message },
                                context: {},
                                cause: classified,
                                severity: "warn",
                            });
                        }
                        throw error;
                    }
                }
                case "merge_abort": {
                    try {
                        await gitService.raw(["merge", "--abort"]);
                    }
                    catch {
                        try {
                            await gitService.raw(["reset", "--hard", "HEAD"]);
                        }
                        catch (resetErr) {
                            throw new ToolExecutionError("Failed to abort merge and reset working tree.", {
                                toolName: "git",
                                input: { operation: "merge_abort" },
                                context: {},
                                cause: resetErr instanceof Error
                                    ? resetErr
                                    : new Error(String(resetErr)),
                                severity: "error",
                            });
                        }
                    }
                    onGitOperationComplete?.();
                    result = { aborted: true };
                    break;
                }
                case "create_pr": {
                    const remoteUrl = (await gitService.raw(["remote", "get-url", "origin"])).trim();
                    if (!isGitHubUrl(remoteUrl)) {
                        throw new ToolExecutionError("Cannot create a pull request URL: only GitHub repositories are supported.", {
                            toolName: "git",
                            input: { operation: "create_pr" },
                            context: { remoteUrl },
                            severity: "warn",
                        });
                    }
                    const defaultBranch = await gitService.getDefaultBranch();
                    const prUrl = getGitHubCompareUrl({
                        gitRemoteUrl: remoteUrl,
                        fromBranch: SUPERBLOCKS_LIVE_GIT_BRANCH,
                        toBranch: defaultBranch,
                        title: input.title,
                        body: input.body,
                    });
                    if (!prUrl) {
                        throw new ToolExecutionError("Cannot create a pull request URL: the remote URL could not be resolved.", {
                            toolName: "git",
                            input: { operation: "create_pr" },
                            context: { remoteUrl },
                            severity: "warn",
                        });
                    }
                    result = { prUrl, provider: "github" };
                    break;
                }
                case "pull": {
                    if (!syncService) {
                        throw new ToolExecutionError("Pull is not available: sync service is not configured.", {
                            toolName: "git",
                            input: { operation: "pull" },
                            context: {},
                            code: undefined,
                        });
                    }
                    try {
                        await gitService.fetch();
                    }
                    catch (error) {
                        const classified = classifyGitError(error);
                        if (classified instanceof GitAuthError) {
                            throw new ToolExecutionError("Git authentication failed during fetch. " +
                                "Please check your git credentials in the repository settings.", {
                                toolName: "git",
                                input: { operation: "pull" },
                                context: {},
                                cause: classified,
                                severity: "warn",
                            });
                        }
                        if (classified instanceof GitRemoteError) {
                            throw new ToolExecutionError(`Git remote error during fetch: ${classified.message}`, {
                                toolName: "git",
                                input: { operation: "pull" },
                                context: {},
                                cause: classified,
                                severity: "warn",
                            });
                        }
                        throw error;
                    }
                    try {
                        await gitService.mergeRef(REMOTE_LIVE_BRANCH);
                    }
                    catch (error) {
                        if (error instanceof GitConflictError) {
                            const conflictedFiles = await gitService.getConflictedFiles();
                            onGitOperationComplete?.();
                            return { merged: false, conflictedFiles };
                        }
                        if (error instanceof GitAuthError) {
                            throw new ToolExecutionError("Git authentication failed during merge. " +
                                "Please check your git credentials in the repository settings.", {
                                toolName: "git",
                                input: { operation: "pull" },
                                context: {},
                                cause: error,
                                severity: "warn",
                            });
                        }
                        if (error instanceof GitRemoteError) {
                            throw new ToolExecutionError(`Git remote error during merge: ${error.message}`, {
                                toolName: "git",
                                input: { operation: "pull" },
                                context: {},
                                cause: error,
                                severity: "warn",
                            });
                        }
                        throw error;
                    }
                    syncService.uploadDirectory("git-pull");
                    onGitOperationComplete?.();
                    return {
                        merged: true,
                        verificationRequired: "Merge complete. You MUST now run build_debug and build_captureScreenshot to verify the app still works after this merge. If issues are found, fix them immediately.",
                    };
                }
                case "deploy": {
                    const { deployService, applicationId } = deps;
                    if (!deployService) {
                        throw new ToolExecutionError("Deploy is not available: deploy service is not configured.", {
                            toolName: "git",
                            input: { operation: "deploy" },
                            context: {},
                        });
                    }
                    if (!applicationId) {
                        throw new ToolExecutionError("Deploy is not available: application ID is not configured.", {
                            toolName: "git",
                            input: { operation: "deploy" },
                            context: {},
                        });
                    }
                    const sha = input.sha?.trim();
                    if (!sha || !/^[0-9a-f]{5,40}$/i.test(sha)) {
                        throw new ToolExecutionError("sha is required for deploy and must be a valid git commit SHA.", {
                            toolName: "git",
                            input: { operation: "deploy", sha: input.sha },
                            context: {},
                        });
                    }
                    const defaultBranch = await gitService.getDefaultBranch();
                    await gitService.fetch("origin", defaultBranch);
                    let fullSha;
                    try {
                        fullSha = (await gitService.raw(["rev-parse", sha])).trim();
                    }
                    catch {
                        return {
                            deployed: false,
                            sha,
                            stage: "validation",
                            error: `Could not resolve "${sha}" to a valid commit. Verify the SHA exists in this repository.`,
                        };
                    }
                    let isOnMain = false;
                    try {
                        const firstParentLog = await gitService.raw([
                            "log",
                            "--first-parent",
                            "--format=%H",
                            "-n",
                            "1000",
                            `origin/${defaultBranch}`,
                        ]);
                        const mainShas = new Set(firstParentLog.trim().split("\n").filter(Boolean));
                        isOnMain = mainShas.has(fullSha);
                    }
                    catch (err) {
                        logger.warn("[git] first-parent log check failed", {
                            sha: fullSha,
                            error: err instanceof Error ? err.message : String(err),
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "validation",
                            error: `Failed to verify commit is on ${defaultBranch}: ${err instanceof Error ? err.message : String(err)}`,
                        };
                    }
                    if (!isOnMain) {
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "validation",
                            error: `Commit ${fullSha} is not a commit on the ${defaultBranch} branch. ` +
                                `Use log_from_main to find valid commit SHAs. ` +
                                `Deployments can only be made from commits directly on ${defaultBranch}. ` +
                                `If your changes are only on ${SUPERBLOCKS_LIVE_GIT_BRANCH}, create a pull request to merge into ${defaultBranch} first.`,
                        };
                    }
                    let commitMessage;
                    try {
                        commitMessage = (await gitService.raw(["log", "-1", "--format=%s", fullSha])).trim();
                    }
                    catch {
                        commitMessage = `Deploy ${fullSha.slice(0, 7)}`;
                    }
                    let directoryHash;
                    let resolvedSha;
                    try {
                        const prepared = await deployService.prepareMainCommit(fullSha);
                        directoryHash = prepared.directoryHash;
                        resolvedSha = prepared.sha;
                    }
                    catch (error) {
                        logger.warn("[git] deploy failed at prepare stage", {
                            sha: fullSha,
                            error: error instanceof Error ? error.message : String(error),
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "prepare",
                            error: `Failed to prepare commit snapshot: ${error instanceof Error ? error.message : String(error)}`,
                        };
                    }
                    let commitId;
                    try {
                        const synced = await deployService.syncMainToDbfs(directoryHash, resolvedSha);
                        commitId = synced.commitId;
                    }
                    catch (error) {
                        logger.warn("[git] deploy failed at sync stage", {
                            sha: fullSha,
                            error: error instanceof Error ? error.message : String(error),
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "sync",
                            error: `Failed to sync commit to DBFS: ${error instanceof Error ? error.message : String(error)}`,
                        };
                    }
                    try {
                        await deployService.createBuild(directoryHash, commitId);
                    }
                    catch (error) {
                        logger.warn("[git] deploy failed at build_create stage", {
                            sha: fullSha,
                            error: error instanceof Error ? error.message : String(error),
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "build_create",
                            error: `Failed to create build: ${error instanceof Error ? error.message : String(error)}`,
                        };
                    }
                    let buildResult;
                    try {
                        buildResult =
                            await deployService.pollBuildUntilComplete(directoryHash);
                    }
                    catch (error) {
                        logger.warn("[git] deploy failed at build_poll stage", {
                            sha: fullSha,
                            error: error instanceof Error ? error.message : String(error),
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "build_poll",
                            error: `Failed to poll build status: ${error instanceof Error ? error.message : String(error)}`,
                        };
                    }
                    if (!buildResult.succeeded) {
                        logger.warn("[git] deploy build failed", {
                            sha: fullSha,
                            error: buildResult.error,
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "build",
                            error: buildResult.error ?? "Build failed or timed out.",
                        };
                    }
                    try {
                        await deployService.deployCommit(commitId, commitMessage);
                    }
                    catch (error) {
                        logger.warn("[git] deploy failed at deploy stage", {
                            sha: fullSha,
                            error: error instanceof Error ? error.message : String(error),
                        });
                        return {
                            deployed: false,
                            sha: fullSha,
                            stage: "deploy",
                            error: `Failed to deploy commit: ${error instanceof Error ? error.message : String(error)}`,
                        };
                    }
                    onGitOperationComplete?.();
                    deps.onDeploySuccess?.(commitId, fullSha);
                    result = { deployed: true, sha: fullSha, commitId };
                    break;
                }
                default: {
                    const _exhaustive = input.operation;
                    throw new Error(`Unknown git operation: ${_exhaustive}`);
                }
            }
            return result;
        }
        catch (error) {
            logger.warn("[git] tool execution failed", {
                gitCategory: "agent_tool",
                gitOperation: input.operation,
                gitOutcome: "failed",
                ...getGitToolInputFields(input),
                ...getGitToolErrorFields(error),
            });
            throw error;
        }
        finally {
            releaseLock?.();
        }
    },
}));
//# sourceMappingURL=git.js.map