Files
2026-07-13 12:22:33 +08:00

79 lines
3.0 KiB
Swift

import Foundation
public struct KiloResolvedBearerToken: Sendable, Equatable {
public let token: String
public let sourceLabel: String
public init(token: String, sourceLabel: String) {
self.token = token
self.sourceLabel = sourceLabel
}
}
/// Resolves the Kilo bearer token shared by usage fetches and organization discovery.
///
/// Behavior mirrors the per-strategy resolution in `KiloProviderDescriptor`:
/// - `.api`: explicit `apiKey`, falling back to `KILO_API_KEY` env var.
/// - `.cli`: token from `~/.local/share/kilo/auth.json` (`kilo.access`).
/// - `.auto`: API first, falling back to CLI when API credentials are missing.
public enum KiloBearerTokenResolver {
public static func resolve(
source: KiloUsageDataSource,
apiKey: String?,
environment: [String: String] = ProcessInfo.processInfo.environment) throws -> KiloResolvedBearerToken
{
switch source {
case .api:
return try self.resolveAPI(apiKey: apiKey, environment: environment)
case .cli:
return try self.resolveCLI(environment: environment)
case .auto:
if let resolved = try? self.resolveAPI(apiKey: apiKey, environment: environment) {
return resolved
}
return try self.resolveCLI(environment: environment)
}
}
private static func resolveAPI(
apiKey: String?,
environment: [String: String]) throws -> KiloResolvedBearerToken
{
let direct = KiloSettingsReader.cleaned(apiKey)
let envValue = KiloSettingsReader.cleaned(environment[KiloSettingsReader.apiTokenKey])
if let token = direct ?? envValue {
return KiloResolvedBearerToken(token: token, sourceLabel: "api")
}
throw KiloUsageError.missingCredentials
}
private static func resolveCLI(
environment: [String: String]) throws -> KiloResolvedBearerToken
{
let url = self.authFileURL(environment: environment)
guard FileManager.default.fileExists(atPath: url.path) else {
throw KiloUsageError.cliSessionMissing(url.path)
}
let data: Data
do {
data = try Data(contentsOf: url)
} catch {
throw KiloUsageError.cliSessionUnreadable(url.path)
}
guard let token = KiloSettingsReader.parseAuthToken(data: data) else {
throw KiloUsageError.cliSessionInvalid(url.path)
}
return KiloResolvedBearerToken(token: token, sourceLabel: "cli")
}
static func authFileURL(environment: [String: String]) -> URL {
if let home = KiloSettingsReader.cleaned(environment["HOME"]) {
let expandedHome = NSString(string: home).expandingTildeInPath
return KiloSettingsReader.defaultAuthFileURL(
homeDirectory: URL(fileURLWithPath: expandedHome, isDirectory: true))
}
return KiloSettingsReader.defaultAuthFileURL(
homeDirectory: FileManager.default.homeDirectoryForCurrentUser)
}
}