276d2bb6-619d-4888-ba11-8a6.../Sources/data/ClipperConfig.swift

76 lines
2.6 KiB
Swift
Raw Permalink Normal View History

//
// ClipperConfig.swift
// plugin
//
// Loads ~/.config/codeisland/clipper-config.json on demand.
// Schema:
// { "deepseek_api_key": "sk-...",
// "default_translate_target": "zh" }
//
// Never bundles a key. If the file is missing/empty we surface a
// state-E "" screen with a helper that copies the path to the
// clipboard so the user can `open -e` it.
//
import Foundation
struct ClipperConfig {
var deepseekApiKey: String
var defaultTranslateTarget: String // "zh" | "en" | "ja"
static let configPath: String = {
let home = NSHomeDirectory()
return "\(home)/.config/codeisland/clipper-config.json"
}()
static var configDir: String {
let home = NSHomeDirectory()
return "\(home)/.config/codeisland"
}
/// Best-effort load. If anything is missing we return nil so the UI
/// can render the onboarding banner never throws to the caller.
static func load() -> ClipperConfig? {
let url = URL(fileURLWithPath: configPath)
guard let data = try? Data(contentsOf: url) else {
ClipperDebugLog.write("config: file missing at \(configPath)")
return nil
}
guard let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
ClipperDebugLog.write("config: malformed JSON")
return nil
}
let key = (obj["deepseek_api_key"] as? String) ?? ""
let target = (obj["default_translate_target"] as? String) ?? "zh"
if key.trimmingCharacters(in: .whitespaces).isEmpty
|| key.trimmingCharacters(in: .whitespaces) == "TODO" {
ClipperDebugLog.write("config: deepseek_api_key empty/TODO")
return nil
}
return ClipperConfig(deepseekApiKey: key, defaultTranslateTarget: target)
}
/// Write a stub file the user can edit. Idempotent won't clobber
/// an existing real config.
@discardableResult
static func ensureStubExists() -> Bool {
let fm = FileManager.default
if fm.fileExists(atPath: configPath) { return false }
try? fm.createDirectory(atPath: configDir, withIntermediateDirectories: true)
let stub = """
{
"deepseek_api_key": "TODO",
"default_translate_target": "zh"
}
"""
do {
try stub.write(toFile: configPath, atomically: true, encoding: .utf8)
ClipperDebugLog.write("config: wrote stub at \(configPath)")
return true
} catch {
ClipperDebugLog.write("config: stub write failed: \(error)")
return false
}
}
}