native macOS codings agent orchestrator
1import Darwin
2import Foundation
3
4/// Static metadata about the app and host machine. Registered once with PostHog
5/// at startup so every event ships with these dimensions and dashboards can
6/// slice by app version, OS, hardware, locale.
7nonisolated enum AnalyticsContext {
8 static var superProperties: [String: String] {
9 let bundle = Bundle.main
10 let osVersion = ProcessInfo.processInfo.operatingSystemVersion
11 let appVersion = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "unknown"
12 let buildNumber = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "unknown"
13
14 return [
15 "app_version": appVersion,
16 "build_number": buildNumber,
17 "os_version": "\(osVersion.majorVersion).\(osVersion.minorVersion).\(osVersion.patchVersion)",
18 "os_major": "\(osVersion.majorVersion)",
19 "os_minor": "\(osVersion.minorVersion)",
20 "device_model": deviceModel,
21 "cpu_arch": cpuArch,
22 "locale": Locale.current.identifier,
23 ]
24 }
25
26 private static var deviceModel: String {
27 sysctlString("hw.model") ?? "unknown"
28 }
29
30 private static var cpuArch: String {
31 #if arch(arm64)
32 return "arm64"
33 #elseif arch(x86_64)
34 return "x86_64"
35 #else
36 return "unknown"
37 #endif
38 }
39
40 private static func sysctlString(_ name: String) -> String? {
41 var size = 0
42 guard sysctlbyname(name, nil, &size, nil, 0) == 0, size > 0 else { return nil }
43 var bytes = [UInt8](repeating: 0, count: size)
44 guard sysctlbyname(name, &bytes, &size, nil, 0) == 0 else { return nil }
45 let payload = bytes.prefix(while: { $0 != 0 })
46 return String(bytes: payload, encoding: .utf8)
47 }
48}