feat(privacy-host): add signed native calendar contacts and reminders host
Add the owner-only AF_UNIX Reyna CLI privacy host, strict signed-app installation, and typed native routing for Calendar, Contacts, and Reminders.\n\nAdd bounded system-status paths and config-only direct local-service wrappers. Preserve MacMiniMCP pending explicit cutover approval.\n\nApple Notes is intentionally deferred: no native Notes operations, Apple Events declaration, or Automation helper are included; legacy Notes handling remains untouched.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import Foundation
|
||||
|
||||
// MARK: - System info data models (read-only, no TCC)
|
||||
|
||||
struct SystemInfoItem: Codable, Equatable, Sendable {
|
||||
let macos_version: String
|
||||
let build: String?
|
||||
let uname: String?
|
||||
let hw_model: String?
|
||||
let cpu_brand: String?
|
||||
let is_macos_26_plus: Bool?
|
||||
let speech_analyzer_expected: String?
|
||||
}
|
||||
|
||||
struct SpeechApiStatusItem: Codable, Equatable, Sendable {
|
||||
let system: SystemInfoItem
|
||||
let swift_availability: [String: String]? // minimal stub
|
||||
let conclusion: String
|
||||
}
|
||||
|
||||
enum SystemProviderError: Error, Equatable, Sendable {
|
||||
case unavailable(String)
|
||||
}
|
||||
|
||||
protocol SystemInfoProviding: Sendable {
|
||||
func getSystemInfo() throws -> SystemInfoItem
|
||||
func getSpeechApiStatus() throws -> SpeechApiStatusItem
|
||||
}
|
||||
|
||||
// Production provider - reads sw_vers / uname / sysctl, no permission needed
|
||||
struct ProductionSystemInfoProvider: SystemInfoProviding {
|
||||
func getSystemInfo() throws -> SystemInfoItem {
|
||||
let ver = ProcessInfo.processInfo.operatingSystemVersion
|
||||
let verString = "\(ver.majorVersion).\(ver.minorVersion).\(ver.patchVersion)"
|
||||
// Best-effort hw model / cpu / uname without spawning processes in Swift? Use sysctl/mib.
|
||||
var hwModel: String? = nil
|
||||
var cpuBrand: String? = nil
|
||||
var unameStr: String? = nil
|
||||
// Use ProcessInfo hostName as fallback for minimal
|
||||
// For hw.model, use sysctlbyname where possible - but keep simple fallback to avoid C interop complexity
|
||||
// We'll try reading via sysctl nametable via Foundation
|
||||
#if os(macOS)
|
||||
hwModel = sysctlString("hw.model")
|
||||
cpuBrand = sysctlString("machdep.cpu.brand_string")
|
||||
#endif
|
||||
let m = ver.majorVersion
|
||||
let is26 = m >= 26
|
||||
let expected = is26 ? "likely available (macOS 26+)" : "not available - requires macOS 26+"
|
||||
return SystemInfoItem(
|
||||
macos_version: verString,
|
||||
build: nil,
|
||||
uname: unameStr,
|
||||
hw_model: hwModel,
|
||||
cpu_brand: cpuBrand,
|
||||
is_macos_26_plus: is26,
|
||||
speech_analyzer_expected: expected
|
||||
)
|
||||
}
|
||||
|
||||
func getSpeechApiStatus() throws -> SpeechApiStatusItem {
|
||||
let info = try getSystemInfo()
|
||||
let major = ProcessInfo.processInfo.operatingSystemVersion.majorVersion
|
||||
let conclusion: String
|
||||
if major >= 26 {
|
||||
conclusion = "macOS 26+ detected — SpeechAnalyzer/SpeechTranscriber should be available per Apple docs."
|
||||
} else {
|
||||
conclusion = "macOS \(info.macos_version) detected — SpeechAnalyzer requires macOS 26+."
|
||||
}
|
||||
return SpeechApiStatusItem(system: info, swift_availability: nil, conclusion: conclusion)
|
||||
}
|
||||
|
||||
private func sysctlString(_ name: String) -> String? {
|
||||
var size = 0
|
||||
let rc1 = sysctlbyname(name, nil, &size, nil, 0)
|
||||
if rc1 != 0 { return nil }
|
||||
var buffer = [CChar](repeating: 0, count: size)
|
||||
let rc2 = sysctlbyname(name, &buffer, &size, nil, 0)
|
||||
if rc2 != 0 { return nil }
|
||||
return String(cString: buffer)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user