import permissionSystemExtension from "../pi-permission-system/src/index.ts"; import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; const BUNDLE_CONFIGS = [ { source: fileURLToPath(new URL("../config/pi-permission-policy.jsonc", import.meta.url)), target: "policy.jsonc", }, { source: fileURLToPath(new URL("../config/pi-permission-hard-guards.jsonc", import.meta.url)), target: "hard-guards.jsonc", }, ] as const; function seedBundlePermissionConfigs(): void { const targetDir = join(getAgentDir(), "extensions", "pi-permission-system"); mkdirSync(targetDir, { recursive: true, mode: 0o700 }); for (const entry of BUNDLE_CONFIGS) { const targetPath = join(targetDir, entry.target); if (existsSync(targetPath)) continue; const legacyPath = entry.target === "policy.jsonc" ? join(targetDir, "config.json") : undefined; const sourcePath = legacyPath && existsSync(legacyPath) ? legacyPath : entry.source; const temporaryPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`; writeFileSync(temporaryPath, readFileSync(sourcePath, "utf8"), { encoding: "utf8", mode: 0o600, flag: "wx", }); try { renameSync(temporaryPath, targetPath); } catch (error) { try { unlinkSync(temporaryPath); } catch { /* best effort */ } if (!existsSync(targetPath)) throw error; } } } /** Seed user-editable policy files before registering permission hooks. */ export default function bundledPermissionSystemExtension(pi: ExtensionAPI): void { seedBundlePermissionConfigs(); permissionSystemExtension(pi); }