feat: Add pi permission gate and track pi config
gitignore used `agent` which ignored the directory itself, preventing
exceptions from taking effect. `agent/*` ignores contents while keeping
the directory traversable for the `!` patterns.

Assisted-by: Claude Opus 4.6 via pi
change lvwlunxoltquuvwunupuwywollkmqylr
commit b96e507e4e4d54cc979e2335ee4880c1b80c52ca
author Alpha Chen <alpha@kejadlen.dev>
date
parent uvxkpvos
diff --git a/.pi/.gitignore b/.pi/.gitignore
new file mode 100644
index 00000000..1c280075
--- /dev/null
+++ b/.pi/.gitignore
@@ -0,0 +1,3 @@
+agent/*
+!agent/extensions/
+!agent/settings.json
diff --git a/.pi/agent/extensions/permission-gate.ts b/.pi/agent/extensions/permission-gate.ts
new file mode 100644
index 00000000..bceaa6d4
--- /dev/null
+++ b/.pi/agent/extensions/permission-gate.ts
@@ -0,0 +1,44 @@
+/**
+ * Permission Gate Extension
+ *
+ * Requires explicit user confirmation before every tool call.
+ * Shows tool name and a summary of the arguments, then asks to allow or block.
+ */
+
+import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
+
+export default function (pi: ExtensionAPI) {
+	pi.on("tool_call", async (event, ctx) => {
+		if (!ctx.hasUI) return;
+
+		const summary = formatArgs(event.toolName, event.input);
+		const allowed = await ctx.ui.confirm(event.toolName, summary);
+
+		if (!allowed) {
+			return { block: true, reason: "Blocked by user" };
+		}
+	});
+}
+
+function formatArgs(toolName: string, input: Record<string, unknown>): string {
+	switch (toolName) {
+		case "bash":
+			return `$ ${input.command}`;
+		case "read":
+			return `${input.path}` + (input.offset ? ` (offset ${input.offset})` : "");
+		case "write":
+			return `${input.path} (${String(input.content ?? "").length} chars)`;
+		case "edit":
+			return `${input.path}`;
+		default: {
+			const keys = Object.keys(input);
+			if (keys.length === 0) return "(no arguments)";
+			return keys.map((k) => `${k}: ${truncate(String(input[k]), 80)}`).join("\n");
+		}
+	}
+}
+
+function truncate(s: string, max: number): string {
+	if (s.length <= max) return s;
+	return s.slice(0, max) + "…";
+}
diff --git a/.pi/agent/settings.json b/.pi/agent/settings.json
new file mode 100644
index 00000000..36e43037
--- /dev/null
+++ b/.pi/agent/settings.json
@@ -0,0 +1,10 @@
+{
+  "lastChangelogVersion": "0.52.6",
+  "defaultProvider": "anthropic",
+  "defaultModel": "claude-opus-4-6",
+  "skills": [
+    "~/.claude/skills"
+  ],
+  "enableSkillCommands": true,
+  "defaultThinkingLevel": "off"
+}
\ No newline at end of file