1import { Type } from "@sinclair/typebox";
2import type { AgentTool } from "@mariozechner/pi-agent-core";
3import simpleGit from "simple-git";
4import { ToolInputError } from "../../../util/errors.js";
5import { formatSize, truncateHead } from "../../../util/truncate.js";
6
7// Trust boundary: refs and paths are passed directly to simple-git, which is
8// scoped to the workspace. The user chose to clone this repo, so its contents
9// are trusted. See AGENTS.md § Workspace Sandboxing.
10
11const ShowSchema = Type.Object({
12 ref: Type.String({ description: "Commit hash or ref" }),
13});
14
15export const createGitShowTool = (workspacePath: string): AgentTool => ({
16 name: "git_show",
17 label: "Git Show",
18 description: "Show commit message and diff for a given ref.",
19 parameters: ShowSchema as any,
20 execute: async (_toolCallId: string, params: any) => {
21 if (!String(params.ref ?? "").trim()) {
22 throw new ToolInputError("ref must be a non-empty string");
23 }
24 const git = simpleGit(workspacePath);
25 const raw = await git.show([params.ref]);
26 const truncation = truncateHead(raw);
27
28 let text = truncation.content;
29 if (truncation.truncated) {
30 text += `\n\n[truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`;
31 }
32
33 return {
34 content: [{ type: "text", text }],
35 details: { ref: params.ref, ...(truncation.truncated ? { truncation } : {}) },
36 };
37 },
38});