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

78 lines
2.6 KiB
Swift

import Foundation
/// Gemini CLI OAuth client resolution helpers for token refresh.
/// Mirrors Antigravity's env override pattern.
public enum GeminiOAuthConfig: Sendable {
public struct ClientCredentials: Sendable, Equatable {
public let clientID: String
public let clientSecret: String
public init(clientID: String, clientSecret: String) {
self.clientID = clientID
self.clientSecret = clientSecret
}
}
/// Test-injectable environment view so suites can override OAuth knobs without
/// mutating process-wide env (which races parallel Gemini suites).
public struct EnvironmentValues: Sendable, Equatable {
public var clientID: String?
public var clientSecret: String?
public var oauth2JSPath: String?
public init(clientID: String? = nil, clientSecret: String? = nil, oauth2JSPath: String? = nil) {
self.clientID = clientID
self.clientSecret = clientSecret
self.oauth2JSPath = oauth2JSPath
}
public static func fromProcessEnvironment(
_ environment: [String: String] = ProcessInfo.processInfo.environment) -> Self
{
Self(
clientID: environment["GEMINI_OAUTH_CLIENT_ID"],
clientSecret: environment["GEMINI_OAUTH_CLIENT_SECRET"],
oauth2JSPath: environment["GEMINI_OAUTH2_JS_PATH"])
}
}
@TaskLocal public static var environmentOverride: EnvironmentValues?
public static var currentEnvironment: EnvironmentValues {
self.environmentOverride ?? .fromProcessEnvironment()
}
public static var configuredClientID: String? {
self.currentEnvironment.clientID?
.trimmingCharacters(in: .whitespacesAndNewlines)
.nilIfEmpty
}
public static var configuredClientSecret: String? {
self.currentEnvironment.clientSecret?
.trimmingCharacters(in: .whitespacesAndNewlines)
.nilIfEmpty
}
public static var configuredOAuth2JSPath: String? {
self.currentEnvironment.oauth2JSPath?
.trimmingCharacters(in: .whitespacesAndNewlines)
.nilIfEmpty
}
public static func environmentClient() -> ClientCredentials? {
guard let clientID = configuredClientID,
let clientSecret = configuredClientSecret
else {
return nil
}
return ClientCredentials(clientID: clientID, clientSecret: clientSecret)
}
}
extension String {
fileprivate var nilIfEmpty: String? {
self.isEmpty ? nil : self
}
}