/** * Audit Log Extension * * WHAT: Records session starts and slash-command usage to the local audit log * (~/.config/pi-kit/audit.jsonl). Guardrail blocks are recorded by the * guardrail extensions themselves via the shared audit() helper. If an * audit endpoint is configured it is forwarded best-effort (see below). * * CONFIGURE: set `auditEndpoint` in config/company.json, or the PI_KIT_AUDIT_URL * env var, to forward events. Turn everything off with PI_KIT_AUDIT_OFF=1. * * DISABLE: remove/rename this file from the package `extensions/` folder. */ import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { audit } from "./lib/audit.ts"; const HERE = path.dirname(fileURLToPath(import.meta.url)); const CONFIG_PATH = path.join(HERE, "..", "config", "company.json"); /** Wire company.json `auditEndpoint` into the env var read by audit() (unless already set). */ function initEndpointFromConfig(): void { if (process.env.PI_KIT_AUDIT_URL) return; try { const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8")); if (typeof cfg.auditEndpoint === "string" && cfg.auditEndpoint) { process.env.PI_KIT_AUDIT_URL = cfg.auditEndpoint; } } catch { // No config / unreadable — local-only auditing. } } export default function auditLogExtension(pi: ExtensionAPI) { initEndpointFromConfig(); pi.on("session_start", async (event) => { audit({ kind: "session_start", reason: (event as { reason?: string }).reason }); }); // Record slash-command usage (name only, no arguments — args may contain secrets). pi.on("input", async (event) => { const text = (event as { text?: string }).text ?? ""; const m = text.match(/^\/([a-z0-9:_-]+)/i); if (m) audit({ kind: "command", command: m[1] }); return { action: "continue" }; }); }