// // PersistenceService.swift // Zyquo MLX // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // import Foundation /// Canonical data locations (charter naming conventions) and small JSON /// persistence helpers used across stores. enum PersistenceService { /// `~/Library/Application Support/ZyquoMLX/` static var appSupportDirectory: URL { FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] .appendingPathComponent("ZyquoMLX", isDirectory: true) } static var modelsDirectory: URL { appSupportDirectory.appendingPathComponent("Models", isDirectory: true) } static var datasetsDirectory: URL { appSupportDirectory.appendingPathComponent("Datasets", isDirectory: true) } static var runsDirectory: URL { appSupportDirectory.appendingPathComponent("Runs", isDirectory: true) } static var pythonDirectory: URL { appSupportDirectory.appendingPathComponent("py", isDirectory: true) } /// Create all canonical directories if missing (first launch). static func ensureDirectories() throws { let fm = FileManager.default for url in [appSupportDirectory, modelsDirectory, datasetsDirectory, runsDirectory] { try fm.createDirectory(at: url, withIntermediateDirectories: true) } } static func loadJSON(_ type: T.Type, from url: URL) throws -> T { let data = try Data(contentsOf: url) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 return try decoder.decode(type, from: data) } static func saveJSON(_ value: T, to url: URL) throws { let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 encoder.outputFormatting = [.prettyPrinted, .sortedKeys] try encoder.encode(value).write(to: url, options: .atomic) } }