// // PersistenceService.swift // Zyquo Local // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // import Foundation /// Conversations, personas and settings persisted as JSON under /// ~/Library/Application Support/ZyquoLocal/. enum PersistenceService { static var appSupportDirectory: URL { let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] let dir = base.appendingPathComponent("ZyquoLocal") try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true) return dir } private static var conversationsDirectory: URL { let dir = appSupportDirectory.appendingPathComponent("Conversations") try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true) return dir } private static let encoder: JSONEncoder = { let e = JSONEncoder() e.dateEncodingStrategy = .iso8601 e.outputFormatting = [.sortedKeys] return e }() private static let decoder: JSONDecoder = { let d = JSONDecoder() d.dateDecodingStrategy = .iso8601 return d }() // MARK: - Conversations (one JSON file per conversation) static func loadConversations() -> [Conversation] { let files = (try? FileManager.default.contentsOfDirectory( at: conversationsDirectory, includingPropertiesForKeys: nil)) ?? [] return files .filter { $0.pathExtension == "json" } .compactMap { url in guard let data = try? Data(contentsOf: url) else { return nil } return try? decoder.decode(Conversation.self, from: data) } .sorted { $0.updatedAt > $1.updatedAt } } static func save(_ conversation: Conversation) { let url = conversationsDirectory.appendingPathComponent("\(conversation.id.uuidString).json") try? encoder.encode(conversation).write(to: url, options: .atomic) } static func delete(conversationID: UUID) { let url = conversationsDirectory.appendingPathComponent("\(conversationID.uuidString).json") try? FileManager.default.removeItem(at: url) } // MARK: - Generic single-document storage (settings, personas, prompts) static func loadDocument(_ type: T.Type, named name: String) -> T? { let url = appSupportDirectory.appendingPathComponent("\(name).json") guard let data = try? Data(contentsOf: url) else { return nil } return try? decoder.decode(T.self, from: data) } static func saveDocument(_ value: T, named name: String) { let url = appSupportDirectory.appendingPathComponent("\(name).json") try? encoder.encode(value).write(to: url, options: .atomic) } }