9fd04b0ce4
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.
82 lines
3.0 KiB
Swift
82 lines
3.0 KiB
Swift
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)
|
|
}
|
|
}
|