SPB Git

spb/zyquo-agent Public MIT

The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.

Swift 94.7% Shell 4.1% Python 0.7% Makefile 0.5%
2.1 KB · 55 lines swift
Raw Blame History
1//2//  PersistenceService.swift3//  Zyquo Agent4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//8//  JSON persistence in ~/Library/Application Support/ZyquoAgent/:9//    vault.zq                    encrypted API-key vault (SecureKeyStore)10//    Workspaces/                 per-task working directories (WorkspaceManager)11//    settings.json, personas.json, …  generic documents12//13//  Ported from Zyquo Cloud (root folder renamed ZyquoCloud → ZyquoAgent;14//  Cloud's per-conversation persistence is superseded by Agent's Task15//  persistence, which arrives with the Agent layer).16//1718import Foundation1920struct PersistenceService {21    static let shared = PersistenceService()2223    let rootDirectory: URL24    /// Per-task working directories root (Phase 2 Workspace layer).25    var workspacesDirectory: URL { rootDirectory.appendingPathComponent("Workspaces") }2627    private let encoder: JSONEncoder28    private let decoder: JSONDecoder2930    init(rootDirectory: URL? = nil) {31        let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]32        self.rootDirectory = rootDirectory ?? base.appendingPathComponent("ZyquoAgent")33        encoder = JSONEncoder()34        encoder.outputFormatting = [.prettyPrinted, .sortedKeys]35        encoder.dateEncodingStrategy = .iso860136        decoder = JSONDecoder()37        decoder.dateDecodingStrategy = .iso860138        try? FileManager.default.createDirectory(at: workspacesDirectory, withIntermediateDirectories: true)39    }4041    // MARK: - Generic documents (personas, templates, settings…)4243    func load<T: Decodable>(_ type: T.Type, from fileName: String) -> T? {44        let url = rootDirectory.appendingPathComponent(fileName)45        guard let data = try? Data(contentsOf: url) else { return nil }46        return try? decoder.decode(type, from: data)47    }4849    func save<T: Encodable>(_ value: T, to fileName: String) {50        let url = rootDirectory.appendingPathComponent(fileName)51        guard let data = try? encoder.encode(value) else { return }52        try? data.write(to: url, options: .atomic)53    }54}55