Project Files
src / tools / git-diff-tool.ts
import { tool } from "@lmstudio/sdk"
import { simpleGit } from "simple-git"
import { z } from "zod"
import { formatGitError } from "../git/error-formatting"
import { resolveAndValidateRepoPath } from "../path/validation"
import type { Tool, ToolsProviderController } from "@lmstudio/sdk"
/**
* Create the git diff tool.
*
* @param ctl Tools provider controller supplied by the LM Studio SDK.
* @returns The configured git diff tool.
*/
export function createGitDiffTool(ctl: ToolsProviderController): Tool {
return tool({
name: "git_diff",
description:
'Get a diff of unstaged or staged changes in a cloned git repository. Use "staged" to see staged changes, otherwise shows unstaged changes. Optionally diff a specific file.',
parameters: {
repoName: z.string().describe("Directory name of the cloned git repository."),
staged: z
.boolean()
.optional()
.default(false)
.describe("If true, show staged changes. If false, show unstaged changes."),
file: z.string().optional().describe("Specific file path to diff within the repository."),
},
/**
* Executes the git diff command.
*
* @param arguments_ Validated tool parameters.
* @param arguments_.repoName Repository directory name relative to the working directory.
* @param arguments_.staged When true, show staged changes; otherwise show unstaged changes.
* @param arguments_.file Optional file path within the repo to diff.
* @param context Runtime tool context supplied by the SDK.
* @returns The diff output, or a user-facing error string.
*/
implementation: async (arguments_, context) => {
const { repoName, file } = arguments_
const staged = arguments_.staged === true
const repoPath = resolveAndValidateRepoPath(repoName, ctl.getWorkingDirectory())
const git = simpleGit(repoPath)
const scope = staged ? "staged" : "unstaged"
const target = typeof file === "string" ? `"${file}" in "${repoName}"` : `"${repoName}"`
context.status(`Computing ${scope} diff for ${target}…`)
try {
let diffResult: string
if (staged) {
diffResult = typeof file === "string" ? await git.diff(["--cached", file]) : await git.diff(["--cached"])
} else {
diffResult = typeof file === "string" ? await git.diff([file]) : await git.diff()
}
return diffResult || "(no changes)"
} catch (error) {
return formatGitError("git_diff", repoName, error)
}
},
})
}