Files
oai-swift/oAI/Services/AgentSkillFilesService.swift

72 lines
2.4 KiB
Swift

//
// AgentSkillFilesService.swift
// oAI
//
// Manages per-skill file directories in Application Support/oAI/skills/<uuid>/
//
import Foundation
import UniformTypeIdentifiers
final class AgentSkillFilesService {
static let shared = AgentSkillFilesService()
private let baseDirectory: URL = {
let appSupport = FileManager.default.urls(for: .applicationSupportDirectory,
in: .userDomainMask).first!
return appSupport.appendingPathComponent("oAI/skills", isDirectory: true)
}()
func skillDirectory(for id: UUID) -> URL {
baseDirectory.appendingPathComponent(id.uuidString, isDirectory: true)
}
func ensureDirectory(for id: UUID) {
try? FileManager.default.createDirectory(
at: skillDirectory(for: id), withIntermediateDirectories: true)
}
func listFiles(for id: UUID) -> [URL] {
guard let contents = try? FileManager.default.contentsOfDirectory(
at: skillDirectory(for: id),
includingPropertiesForKeys: [.fileSizeKey],
options: .skipsHiddenFiles)
else { return [] }
return contents.sorted { $0.lastPathComponent < $1.lastPathComponent }
}
func addFile(from sourceURL: URL, to id: UUID) throws {
ensureDirectory(for: id)
let dest = skillDirectory(for: id).appendingPathComponent(sourceURL.lastPathComponent)
if FileManager.default.fileExists(atPath: dest.path) {
try FileManager.default.removeItem(at: dest)
}
try FileManager.default.copyItem(at: sourceURL, to: dest)
}
func deleteFile(at url: URL) {
try? FileManager.default.removeItem(at: url)
}
func deleteAll(for id: UUID) {
try? FileManager.default.removeItem(at: skillDirectory(for: id))
}
func hasFiles(for id: UUID) -> Bool {
!listFiles(for: id).isEmpty
}
/// Returns (filename, content) for all readable text files
func readTextFiles(for id: UUID) -> [(name: String, content: String)] {
listFiles(for: id).compactMap { url in
guard let content = try? String(contentsOf: url, encoding: .utf8) else { return nil }
return (url.lastPathComponent, content)
}
}
/// Returns file size in bytes, or nil if unavailable
func fileSize(at url: URL) -> Int? {
(try? url.resourceValues(forKeys: [.fileSizeKey]))?.fileSize
}
}