Created
February 17, 2026 10:05
-
-
Save gabrielmontagne/852b24d3329f01a53479e1d2d993bc76 to your computer and use it in GitHub Desktop.
review gate for pi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Review Gate Extension | |
| * | |
| * Toggle with /review-gate. When active, intercepts edit/write tool calls: | |
| * writes /tmp/review-a, /tmp/review-b, and /tmp/proposed.diff, then prompts | |
| * inside pi. Empty input = approve, text = block with reason. | |
| */ | |
| import type { ExtensionAPI, EditToolCallEvent, WriteToolCallEvent } from "@mariozechner/pi-coding-agent"; | |
| import { readFile, writeFile } from "fs/promises"; | |
| import { resolve } from "path"; | |
| export default function (pi: ExtensionAPI) { | |
| let enabled = true; | |
| pi.registerCommand("review-gate", { | |
| description: "Toggle review gate for edit/write tools", | |
| handler: async (_args, ctx) => { | |
| enabled = !enabled; | |
| ctx.ui.notify(`Review gate ${enabled ? "on" : "off"}`, "info"); | |
| }, | |
| }); | |
| pi.on("tool_call", async (event, ctx) => { | |
| if (!enabled) return undefined; | |
| if (event.toolName !== "edit" && event.toolName !== "write") return undefined; | |
| if (!ctx.hasUI) return undefined; | |
| const path = resolve(ctx.cwd, event.input.path as string); | |
| let a: string; | |
| let b: string; | |
| if (event.toolName === "edit") { | |
| const input = event.input as EditToolCallEvent["input"]; | |
| a = input.oldText; | |
| b = input.newText; | |
| } else { | |
| const input = event.input as WriteToolCallEvent["input"]; | |
| try { | |
| a = await readFile(path, "utf-8"); | |
| } catch { | |
| a = ""; | |
| } | |
| b = input.content; | |
| } | |
| await writeFile("/tmp/review-a", a); | |
| await writeFile("/tmp/review-b", b); | |
| const label = event.input.path as string; | |
| const diff = await pi.exec("diff", [ | |
| "-u", | |
| "--label", | |
| `a/${label}`, | |
| "--label", | |
| `b/${label}`, | |
| "/tmp/review-a", | |
| "/tmp/review-b", | |
| ]); | |
| const diffText = diff.stdout || "(no differences)\n"; | |
| await writeFile("/tmp/proposed.diff", diffText); | |
| const response = await ctx.ui.input(`${event.toolName} ${label}`); | |
| if (response === undefined) { | |
| return { block: true, reason: "Review cancelled" }; | |
| } | |
| if (response.trim() === "") return undefined; | |
| return { block: true, reason: response.trim() }; | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment