The single source of truth for macOS permissions.
Apple APIs first, TCC database fallback.
Granted, denied, or unknown tri-state.
Pull-based via InstallerEngine.inspectSystem().
.unknown cases only. PermissionOracle sits at the center and delegates to specialized checkers.PermissionOracle always returns the same result. There is no caching, no timing dependency, and no hidden state. The Oracle asks the OS every time.actor with a .shared singleton. Returns Status values (.granted, .denied, .unknown, .error) and aggregates them into a Snapshot covering both KeyPath and Kanata.public actor PermissionOracle { public static let shared = PermissionOracle() public enum Status: Equatable, Sendable { case granted, denied, unknown case error(String) } public struct Snapshot: Sendable { let keyPath: PermissionSet let kanata: PermissionSet var isSystemReady: Bool { keyPath.accessibility.isReady && kanata.hasAllPermissions } } }
/Library/Application Support/com.apple.TCC/TCC.db). Results are cached for 10 seconds. FDA is needed to read TCC entries for Kanata's permission state.public final class FullDiskAccessChecker { // Probes system TCC.db readability as a heuristic public func hasFullDiskAccess() -> Bool func refresh() -> Bool }
WizardIssue values for any missing permissions. Used by the wizard to decide which permission page to show.SystemSnapshot (including permission state from PermissionOracle) and returns it as a pure value struct. No component queries permissions on its own.let engine = InstallerEngine() let context = await engine.inspectSystem() // Pure value struct if context.permissions.inputMonitoring != .granted { /* show wizard page */ }
InstallerEngine.inspectSystem() calls PermissionOracle.shared to gather permission stateIOHIDCheckAccess returns .granted or .denied — Oracle trusts this immediately and returnsIOHIDCheckAccess returns .unknown — Oracle falls back to TCC database query (requires Full Disk Access)SystemInspector finds missing permission → WizardRouter returns .inputMonitoring or .accessibility page.granted → advanceIOHIDCheckAccess reflects actual system state. When the Apple API gives a definitive answer, trust it unconditionally.IOHIDCheckAccess returning .granted or .denied — trust this result. Only .unknown proceeds to the TCC database fallback path.IOHIDCheckAccess calls from UI code, no ad-hoc TCC queries. One path, one source of truth.InstallerEngine.inspectSystem() gathers a complete SystemSnapshot including permissions. Consumers read the snapshot, never re-query.