/** * Bundle IDs that are escalations-in-disguise. The approval UI shows a warning * badge for these; they are NOT blocked. Power users may legitimately want the * model controlling a terminal. * * Imported by the renderer via the `./sentinelApps` subpath (package.json * `exports`), which keeps Next.js from reaching index.ts → mcpServer.ts → * @modelcontextprotocol/sdk (devDep, would fail module resolution). Keep * this file import-free so the subpath stays clean. */ /** These apps can execute arbitrary shell commands. */ const SHELL_ACCESS_BUNDLE_IDS = new Set([ "com.apple.Terminal", "com.googlecode.iterm2", "com.microsoft.VSCode", "dev.warp.Warp-Stable", "com.github.wez.wezterm", "io.alacritty", "net.kovidgoyal.kitty", "com.jetbrains.intellij", "com.jetbrains.pycharm", ]); /** Finder in the allowlist ≈ browse + open-any-file. */ const FILESYSTEM_ACCESS_BUNDLE_IDS = new Set(["com.apple.finder"]); const SYSTEM_SETTINGS_BUNDLE_IDS = new Set(["com.apple.systempreferences"]); export const SENTINEL_BUNDLE_IDS: ReadonlySet = new Set([ ...SHELL_ACCESS_BUNDLE_IDS, ...FILESYSTEM_ACCESS_BUNDLE_IDS, ...SYSTEM_SETTINGS_BUNDLE_IDS, ]); export type SentinelCategory = "shell" | "filesystem" | "system_settings"; export function getSentinelCategory(bundleId: string): SentinelCategory | null { if (SHELL_ACCESS_BUNDLE_IDS.has(bundleId)) return "shell"; if (FILESYSTEM_ACCESS_BUNDLE_IDS.has(bundleId)) return "filesystem"; if (SYSTEM_SETTINGS_BUNDLE_IDS.has(bundleId)) return "system_settings"; return null; }