import fs from 'fs';
import path from 'path';
import { resolvePilotHome } from '../utils/pilotPaths.js';
const DEFAULT_SETTINGS = {
version: 1,
allowedTools: [],
disallowedTools: [],
skipPermissions: true,
};
const TOOL_NAME_ALIASES = new Map([
['Read', 'read_file'],
['Write', 'write_file'],
['Edit', 'edit_file'],
['MultiEdit', 'edit_file'],
['Glob', 'glob'],
['Grep', 'grep'],
['Bash', 'bash'],
['Task', 'agent'],
['TodoWrite', 'todo_write'],
['WebFetch', 'web_fetch'],
['WebSearch', 'web_search'],
]);
export function getPermissionSettingsPath(env = process.env) {
return path.join(resolvePilotHome(env), 'permissions.json');
}
export function normalizePermissionEntry(entry) {
const trimmed = typeof entry === 'string' ? entry.trim() : '';
if (!trimmed) return '';
const bashMatch = /^Bash\((.*)\)$/.exec(trimmed);
if (bashMatch) {
const pattern = bashMatch[1]?.trim();
return pattern ? `bash:${pattern}` : 'bash';
}
return TOOL_NAME_ALIASES.get(trimmed) || trimmed;
}
export function normalizePermissionSettings(value) {
const obj = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
return {
version: 1,
allowedTools: normalizeStringArray(obj.allowedTools),
disallowedTools: normalizeStringArray(obj.disallowedTools),
skipPermissions: Boolean(obj.skipPermissions),
lastUpdated: typeof obj.lastUpdated === 'string' ? obj.lastUpdated : undefined,
};
}
export function readPermissionSettings(env = process.env) {
try {
const raw = fs.readFileSync(getPermissionSettingsPath(env), 'utf8');
return normalizePermissionSettings(JSON.parse(raw));
} catch {
return { ...DEFAULT_SETTINGS };
}
}
export function writePermissionSettings(updates, env = process.env) {
const next = normalizePermissionSettings({
...readPermissionSettings(env),
...(updates || {}),
lastUpdated: new Date().toISOString(),
});
const filePath = getPermissionSettingsPath(env);
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
return next;
}
function normalizeStringArray(value) {
if (!Array.isArray(value)) return [];
const seen = new Set();
const out = [];
for (const item of value) {
const normalized = normalizePermissionEntry(item);
if (!normalized || seen.has(normalized)) continue;
seen.add(normalized);
out.push(normalized);
}
return out;
}