Files
reyna-cli/native/ReynaCLIHost/Sources/ReynaCLIHostCore/AppEntry.swift
T
Adolfo Reyna 9fd04b0ce4 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.
2026-08-03 20:27:54 -04:00

76 lines
2.8 KiB
Swift

import Foundation
// Public entry point used by both SwiftPM executable and Xcode app target.
// Preserves AF_UNIX privacy-host protocol exactly as before.
// Headless design: socket-server or stdin JSON-lines mode only.
public func runReynaCLIHost(arguments: [String] = CommandLine.arguments) -> Never {
if let idx = arguments.firstIndex(of: "--socket") {
let nextIdx = idx + 1
guard nextIdx < arguments.count else {
fputs("error: --socket requires a path argument\n", stderr)
Darwin.exit(2)
}
let socketPath = arguments[nextIdx]
runSocketServer(socketPath: socketPath)
} else {
runStdinLoop()
}
}
func extractRecoverableId(from data: Data) -> String? {
if let obj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let id = obj["id"] as? String {
return id
}
guard let str = String(data: data, encoding: .utf8) else { return nil }
let pattern = "\"id\"\\s*:\\s*\"([^\"]*)\""
guard let regex = try? NSRegularExpression(pattern: pattern, options: []),
let match = regex.firstMatch(in: str, options: [], range: NSRange(str.startIndex..., in: str)),
match.numberOfRanges >= 2,
let r = Range(match.range(at: 1), in: str) else {
return nil
}
return String(str[r])
}
func writeResponse(_ response: Response) {
guard let jsonData = try? JSONEncoder().encode(response),
let jsonString = String(data: jsonData, encoding: .utf8),
let outData = (jsonString + "\n").data(using: .utf8) else {
return
}
FileHandle.standardOutput.write(outData)
}
func handleLine(_ lineData: Data) {
if lineData.isEmpty { return }
if let s = String(data: lineData, encoding: .utf8),
s.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
return
}
if let request = try? JSONDecoder().decode(Request.self, from: lineData) {
let response = dispatch(request: request)
writeResponse(response)
} else {
let recoveredId = extractRecoverableId(from: lineData)
let err = ErrorPayload(code: "invalid_request", message: "Invalid request JSON")
let resp = Response(id: recoveredId ?? "", ok: false, result: nil, error: err)
writeResponse(resp)
}
}
func runStdinLoop() -> Never {
while let line = readLine() {
if line.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { continue }
if let data = line.data(using: .utf8) {
handleLine(data)
} else {
let err = ErrorPayload(code: "invalid_request", message: "Invalid request encoding")
let resp = Response(id: "", ok: false, result: nil, error: err)
writeResponse(resp)
}
}
Darwin.exit(0)
}