import { existsSync, mkdirSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { toRecord } from "./common"; export const EXTENSION_ID = "pi-quick-perms"; export interface PermissionSystemExtensionConfig { debugLog: boolean; permissionReviewLog: boolean; yoloMode: boolean; /** Additional directories to auto-allow for reads as Pi infrastructure. */ piInfrastructureReadPaths?: string[]; } export const DEFAULT_EXTENSION_CONFIG: PermissionSystemExtensionConfig = { debugLog: false, permissionReviewLog: true, yoloMode: false, }; export function resolveExtensionRoot(moduleUrl = import.meta.url): string { return join(dirname(fileURLToPath(moduleUrl)), ".."); } export const EXTENSION_ROOT = resolveExtensionRoot(); const PERMISSION_POLICY_KEYS: ReadonlySet = new Set([ "defaultPolicy", "tools", "bash", "mcp", "skills", "special", "external_directory", ]); export function detectMisplacedPermissionKeys( raw: Record, ): string[] { return Object.keys(raw).filter((key) => PERMISSION_POLICY_KEYS.has(key)); } export function normalizePermissionSystemConfig( raw: unknown, ): PermissionSystemExtensionConfig { const record = toRecord(raw); const rawPaths = record.piInfrastructureReadPaths; const piInfrastructureReadPaths: string[] | undefined = Array.isArray(rawPaths) && rawPaths.every((p): p is string => typeof p === "string") ? rawPaths : undefined; const result: PermissionSystemExtensionConfig = { debugLog: record.debugLog === true, permissionReviewLog: record.permissionReviewLog !== false, yoloMode: record.yoloMode === true, }; if (piInfrastructureReadPaths !== undefined) { result.piInfrastructureReadPaths = piInfrastructureReadPaths; } return result; } export function ensurePermissionSystemLogsDirectory( logsDir: string, ): string | undefined { try { mkdirSync(logsDir, { recursive: true }); return undefined; } catch (error) { const message = error instanceof Error ? error.message : String(error); return `Failed to create pi-quick-perms log directory '${logsDir}': ${message}`; } }