951 lines · 44.3 KB · Swift
RawDownload
import AppKitimport CodexBarCoreimport Observationimport ServiceManagement enum RefreshFrequency: String, CaseIterable, Identifiable {    case manual    case oneMinute    case twoMinutes    case fiveMinutes    case fifteenMinutes    case thirtyMinutes    case adaptive    /// Adaptive plus consent-gated local agent activity. Kept after plain Adaptive so the    /// privacy-preserving mode remains the first adaptive choice.    case adaptiveAgentAware     var id: String {        self.rawValue    }     /// nil for `.manual` (no timer) and adaptive modes (delay is computed per tick by    /// `AdaptiveRefreshPolicy`, not a fixed interval).    var seconds: TimeInterval? {        switch self {        case .manual: nil        case .oneMinute: 60        case .twoMinutes: 120        case .fiveMinutes: 300        case .fifteenMinutes: 900        case .thirtyMinutes: 1800        case .adaptive, .adaptiveAgentAware: nil        }    }     var label: String {        switch self {        case .manual: L("refresh_manual")        case .oneMinute: L("refresh_1min")        case .twoMinutes: L("refresh_2min")        case .fiveMinutes: L("refresh_5min")        case .fifteenMinutes: L("refresh_15min")        case .thirtyMinutes: L("refresh_30min")        case .adaptive: L("refresh_adaptive")        case .adaptiveAgentAware: L("refresh_adaptive_agent_aware")        }    }     var usesAdaptivePolicy: Bool {        self == .adaptive || self == .adaptiveAgentAware    }} enum AdaptiveActivityScanConsent: String, Sendable {    case undecided    case allowed    case declined} enum MenuBarMetricPreference: String, CaseIterable, Identifiable {    case automatic    case primary    case secondary    case primaryAndSecondary    case tertiary    case extraUsage    case average    case monthlyPlan     var id: String {        self.rawValue    }     var label: String {        switch self {        case .automatic: L("metric_pref_automatic")        case .primary: L("metric_pref_primary")        case .secondary: L("metric_pref_secondary")        case .primaryAndSecondary: "\(L("metric_pref_primary")) + \(L("metric_pref_secondary"))"        case .tertiary: L("metric_pref_tertiary")        case .extraUsage: L("metric_pref_extra_usage")        case .average: L("metric_pref_average")        case .monthlyPlan: L("metric_mistral_monthly_plan")        }    }} enum KiroMenuBarDisplayMode: String, CaseIterable, Identifiable {    case automatic    case hidden    case creditsLeft    case percentLeft    case creditsAndPercent    case usedAndTotal    case overageCreditsWhenExhausted    case overageCostWhenExhausted    case overageCreditsAndCostWhenExhausted     var id: String {        self.rawValue    }     var label: String {        switch self {        case .automatic: L("Automatic")        case .hidden: L("Hidden")        case .creditsLeft: L("Credits left")        case .percentLeft: L("Percent left")        case .creditsAndPercent: L("Credits + percent")        case .usedAndTotal: L("Used / total")        case .overageCreditsWhenExhausted: L("Overage credits at zero")        case .overageCostWhenExhausted: L("Overage cost at zero")        case .overageCreditsAndCostWhenExhausted: L("Overage credits + cost at zero")        }    }} enum MultiAccountMenuLayout: String, CaseIterable, Identifiable {    case segmented    case stacked     var id: String {        self.rawValue    }     var label: String {        switch self {        case .segmented: L("multi_account_layout_segmented")        case .stacked: L("multi_account_layout_stacked")        }    }} enum CostSummaryDisplayStyle: String, CaseIterable, Identifiable {    case inlineSummary    case costSubmenu    case both     var id: String {        self.rawValue    }     var label: String {        switch self {        case .inlineSummary: L("cost_summary_style_inline")        case .costSubmenu: L("cost_summary_style_submenu")        case .both: L("cost_summary_style_both")        }    }     var helpText: String {        switch self {        case .inlineSummary: L("cost_summary_style_inline_help")        case .costSubmenu: L("cost_summary_style_submenu_help")        case .both: L("cost_summary_style_both_help")        }    }     var showsInlineSummary: Bool {        self != .costSubmenu    }     var showsCostSubmenu: Bool {        self != .inlineSummary    }} struct CachedCodexAccountReconciliationSnapshot {    let activeSource: CodexActiveSource    let loadedAt: Date    let snapshot: CodexAccountReconciliationSnapshot} struct CachedCodexAccountMenuProjection: Equatable {    let activeSource: CodexActiveSource    let loadedAt: Date    let projection: CodexVisibleAccountProjection} enum CodexAccountMenuProjectionRevalidationResult: Equatable {    case skipped    case discarded    case unchanged    case updated} @MainActor@Observablefinal class SettingsStore {    static let sharedDefaults = AppGroupSupport.sharedDefaults()    static let mergedOverviewProviderLimit = 6    static let productionCodexAccountReconciliationSnapshotCacheInterval: TimeInterval = 2    static let isRunningTests: Bool = {        let env = ProcessInfo.processInfo.environment        if env["XCTestConfigurationFilePath"] != nil {            return true        }        if env["TESTING_LIBRARY_VERSION"] != nil {            return true        }        if env["SWIFT_TESTING"] != nil {            return true        }        return NSClassFromString("XCTestCase") != nil    }()     #if DEBUG    static var codexAccountReconciliationSnapshotCacheIntervalOverrideForTesting: TimeInterval?    #endif     @ObservationIgnored let userDefaults: UserDefaults    @ObservationIgnored let configStore: CodexBarConfigStore    @ObservationIgnored let antigravityOAuthCredentialsStore: AntigravityOAuthCredentialsStore    @ObservationIgnored var config: CodexBarConfig    @ObservationIgnored var configPersistTask: Task<Void, Never>?    @ObservationIgnored var configLoading = false    @ObservationIgnored var tokenAccountsLoaded = false    @ObservationIgnored var cachedCodexAccountReconciliationSnapshot:        CachedCodexAccountReconciliationSnapshot?    @ObservationIgnored var cachedCodexAccountMenuProjection: CachedCodexAccountMenuProjection?    @ObservationIgnored var codexAccountReconciliationGeneration: UInt = 0    #if DEBUG    @ObservationIgnored var _test_codexAccountSnapshotLoader:        (@Sendable (CodexActiveSource) -> CodexAccountReconciliationSnapshot)?    #endif    @ObservationIgnored var mergedMenuLastSelectedWasOverviewStorage = false    @ObservationIgnored var selectedMenuProviderRawStorage: String?    var defaultsState: SettingsDefaultsState    var configRevision: Int = 0    var providerDetailSettingsRevision: Int = 0    var backgroundWorkSettingsRevision: Int = 0    var costUsageSettingsRevision: UInt64 = 0    var providerOrder: [UsageProvider] = []    var providerEnablement: [UsageProvider: Bool] = [:]    @ObservationIgnored var providerEnablementRevisions: [UsageProvider: UInt64] = [:]    @ObservationIgnored var providerConfigRevisions: [UsageProvider: UInt64] = [:]    @ObservationIgnored var providerConfigFingerprints: [UsageProvider: Data] = [:]     static func shouldBridgeSharedDefaults(for userDefaults: UserDefaults) -> Bool {        if !self.isRunningTests {            return true        }        if userDefaults === UserDefaults.standard {            return true        }        if let shared = sharedDefaults, userDefaults === shared {            return true        }        return false    }     init(        userDefaults: UserDefaults = .standard,        configStore: CodexBarConfigStore = CodexBarConfigStore(),        zaiTokenStore: any ZaiTokenStoring = KeychainZaiTokenStore(),        syntheticTokenStore: any SyntheticTokenStoring = KeychainSyntheticTokenStore(),        codexCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "codex-cookie",            promptKind: .codexCookie),        claudeCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "claude-cookie",            promptKind: .claudeCookie),        cursorCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "cursor-cookie",            promptKind: .cursorCookie),        opencodeCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "opencode-cookie",            promptKind: .opencodeCookie),        factoryCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "factory-cookie",            promptKind: .factoryCookie),        minimaxCookieStore: any MiniMaxCookieStoring = KeychainMiniMaxCookieStore(),        minimaxAPITokenStore: any MiniMaxAPITokenStoring = KeychainMiniMaxAPITokenStore(),        kimiTokenStore: any KimiTokenStoring = KeychainKimiTokenStore(),        augmentCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "augment-cookie",            promptKind: .augmentCookie),        ampCookieStore: any CookieHeaderStoring = KeychainCookieHeaderStore(            account: "amp-cookie",            promptKind: .ampCookie),        copilotTokenStore: any CopilotTokenStoring = KeychainCopilotTokenStore(),        tokenAccountStore: any ProviderTokenAccountStoring = FileTokenAccountStore(),        antigravityOAuthCredentialsStore: AntigravityOAuthCredentialsStore = AntigravityOAuthCredentialsStore(),        performInitialProviderDetection: Bool = !SettingsStore.isRunningTests)    {        // Capture this before app-group/config migrations can create prior-installation state.        let hadExistingConfig = (try? configStore.load()) != nil        let hadPreviousInstallationState = hadExistingConfig || Self.hadPreviousAppLaunch(userDefaults: userDefaults)        let appGroupID = AppGroupSupport.currentGroupID()        let appGroupMigration: AppGroupSupport.MigrationResult        if Self.isRunningTests {            appGroupMigration = AppGroupSupport.migrateLegacyDataIfNeeded(standardDefaults: userDefaults)        } else {            Self.scheduleAppGroupMigration()            appGroupMigration = AppGroupSupport.MigrationResult(status: .targetUnavailable)        }        let sharedDefaultsAvailable = Self.sharedDefaults != nil        if !Self.isRunningTests {            CodexBarLog.logger(LogCategories.settings).info(                "App group resolved",                metadata: [                    "groupID": appGroupID,                    "sharedDefaultsAvailable": sharedDefaultsAvailable ? "1" : "0",                    "migrationStatus": appGroupMigration.status.rawValue,                    "migratedSnapshot": appGroupMigration.copiedSnapshot ? "1" : "0",                    "migratedDefaults": "\(appGroupMigration.copiedDefaults)",                ])        }         if userDefaults.object(forKey: "openAIWebAccessEnabled") == nil,           let legacyOpenAIWebAccess = userDefaults.object(forKey: "openAIWebAccess") as? Bool        {            userDefaults.set(legacyOpenAIWebAccess, forKey: "openAIWebAccessEnabled")        }        let hasStoredOpenAIWebAccessPreference = userDefaults.object(forKey: "openAIWebAccessEnabled") != nil        let legacyStores = CodexBarConfigMigrator.LegacyStores(            zaiTokenStore: zaiTokenStore,            syntheticTokenStore: syntheticTokenStore,            codexCookieStore: codexCookieStore,            claudeCookieStore: claudeCookieStore,            cursorCookieStore: cursorCookieStore,            opencodeCookieStore: opencodeCookieStore,            factoryCookieStore: factoryCookieStore,            minimaxCookieStore: minimaxCookieStore,            minimaxAPITokenStore: minimaxAPITokenStore,            kimiTokenStore: kimiTokenStore,            augmentCookieStore: augmentCookieStore,            ampCookieStore: ampCookieStore,            copilotTokenStore: copilotTokenStore,            tokenAccountStore: tokenAccountStore)        let config = CodexBarConfigMigrator.loadOrMigrate(            configStore: configStore,            userDefaults: userDefaults,            stores: legacyStores)        self.userDefaults = userDefaults        self.configStore = configStore        self.antigravityOAuthCredentialsStore = antigravityOAuthCredentialsStore        self.config = config        self.configLoading = true        let defaultsState = Self.loadDefaultsState(            userDefaults: userDefaults,            hadPreviousInstallationState: hadPreviousInstallationState)        self.defaultsState = defaultsState        self.mergedMenuLastSelectedWasOverviewStorage = defaultsState.mergedMenuLastSelectedWasOverview        self.selectedMenuProviderRawStorage = defaultsState.selectedMenuProviderRaw        self.updateProviderState(config: config)        self.configLoading = false        CodexBarLog.setFileLoggingEnabled(self.debugFileLoggingEnabled)        userDefaults.removeObject(forKey: "showCodexUsage")        userDefaults.removeObject(forKey: "showClaudeUsage")        LaunchAtLoginManager.setEnabled(self.launchAtLogin)        if performInitialProviderDetection {            self.runInitialProviderDetectionIfNeeded()        }        self.ensureAlibabaProviderAutoEnabledIfNeeded()        self.applyTokenCostDefaultIfNeeded()        if self.claudeUsageDataSource != .cli {            if Self.isRunningTests {                self.claudeWebExtrasEnabled = false            } else {                self.defaultsState.claudeWebExtrasEnabledRaw = false            }        }        let resolvedOpenAIWebAccessEnabled = if hasStoredOpenAIWebAccessPreference {            self.defaultsState.openAIWebAccessEnabled        } else {            Self.inferredInitialOpenAIWebAccessEnabled(                config: config,                hadExistingConfig: hadExistingConfig)        }        if Self.isRunningTests {            self.openAIWebAccessEnabled = resolvedOpenAIWebAccessEnabled        } else {            self.defaultsState.openAIWebAccessEnabled = resolvedOpenAIWebAccessEnabled        }        KeychainAccessGate.isDisabled = self.debugDisableKeychainAccess    }} extension SettingsStore {    private struct NotificationDefaults {        let statusChecksEnabled: Bool        let sessionQuotaNotificationsEnabled: Bool        let predictivePaceWarningNotificationsEnabled: Bool    }     private static func scheduleAppGroupMigration() {        Task.detached(priority: .utility) {            let result = AppGroupSupport.migrateLegacyDataIfNeeded()            CodexBarLog.logger(LogCategories.settings).info(                "App group migration completed",                metadata: [                    "migrationStatus": result.status.rawValue,                    "migratedSnapshot": result.copiedSnapshot ? "1" : "0",                    "migratedDefaults": "\(result.copiedDefaults)",                ])        }    }     private static func inferredInitialOpenAIWebAccessEnabled(        config: CodexBarConfig,        hadExistingConfig: Bool) -> Bool    {        guard let codex = config.providerConfig(for: .codex) else { return false }        if let cookieSource = codex.cookieSource {            return cookieSource.isEnabled        }        if codex.sanitizedCookieHeader != nil {            return true        }        return hadExistingConfig    }     // swiftlint:disable:next function_body_length    private static func loadDefaultsState(        userDefaults: UserDefaults,        hadPreviousInstallationState: Bool) -> SettingsDefaultsState    {        let refreshFrequency = Self.loadRefreshFrequency(            userDefaults: userDefaults,            hadPreviousInstallationState: hadPreviousInstallationState)        let adaptiveActivityScanConsent = Self.loadAdaptiveActivityScanConsent(userDefaults: userDefaults)        let refreshAllProvidersOnMenuOpen = userDefaults.object(            forKey: "refreshAllProvidersOnMenuOpen") as? Bool ?? false        let launchAtLogin = userDefaults.object(forKey: "launchAtLogin") as? Bool ?? false        let debugMenuEnabled = userDefaults.object(forKey: "debugMenuEnabled") as? Bool ?? false        let debugDisableKeychainAccess = Self.loadDebugDisableKeychainAccess(userDefaults: userDefaults)        let debugFileLoggingEnabled = userDefaults.object(forKey: "debugFileLoggingEnabled") as? Bool ?? false        let debugLogLevelRaw = userDefaults.string(forKey: "debugLogLevel") ?? CodexBarLog.Level.verbose.rawValue        if Self.isRunningTests, userDefaults.string(forKey: "debugLogLevel") == nil {            userDefaults.set(debugLogLevelRaw, forKey: "debugLogLevel")        }        let debugLoadingPatternRaw = userDefaults.string(forKey: "debugLoadingPattern")        let debugKeepCLISessionsAlive = userDefaults.object(forKey: "debugKeepCLISessionsAlive") as? Bool ?? false        let notificationDefaults = Self.loadNotificationDefaults(userDefaults: userDefaults)        let quotaWarnings = Self.loadQuotaWarningDefaults(userDefaults: userDefaults)        let quotaWarningMarkersVisibleDefault = userDefaults.object(forKey: "quotaWarningMarkersVisible") as? Bool        let quotaWarningMarkersVisible = quotaWarningMarkersVisibleDefault ?? true        if Self.isRunningTests, quotaWarningMarkersVisibleDefault == nil {            userDefaults.set(true, forKey: "quotaWarningMarkersVisible")        }        let weeklyProgressWorkDays = userDefaults.object(forKey: "weeklyProgressWorkDays") as? Int        let usageBarsShowUsed = userDefaults.object(forKey: "usageBarsShowUsed") as? Bool ?? false        let resetTimesShowAbsolute = userDefaults.object(forKey: "resetTimesShowAbsolute") as? Bool ?? false        let providerChangelogLinksEnabled = userDefaults.object(            forKey: "providerChangelogLinksEnabled") as? Bool ?? false        let menuBarShowsBrandIconWithPercent = userDefaults.object(            forKey: "menuBarShowsBrandIconWithPercent") as? Bool ?? false        let menuBarHidesCritters = userDefaults.object(forKey: "menuBarHidesCritters") as? Bool ?? false        let menuBarHighContrastOnInactiveDisplays = userDefaults.object(            forKey: "menuBarHighContrastOnInactiveDisplays") as? Bool ?? false        let menuBarDisplayModeRaw = userDefaults.string(forKey: "menuBarDisplayMode")            ?? MenuBarDisplayMode.percent.rawValue        let menuBarShowsResetTimeWhenExhausted = userDefaults.object(            forKey: "menuBarShowsResetTimeWhenExhausted") as? Bool ?? false        let kiroMenuBarDisplayModeRaw = userDefaults.string(forKey: "kiroMenuBarDisplayMode")            ?? KiroMenuBarDisplayMode.automatic.rawValue        let historicalTrackingEnabled = userDefaults.object(forKey: "historicalTrackingEnabled") as? Bool ?? false        let multiAccountMenuLayoutRaw = Self.loadMultiAccountMenuLayoutRaw(userDefaults: userDefaults)        let resolvedPreferences = Self.loadMenuBarMetricPreferences(userDefaults: userDefaults)        let storedMenuBarLayout = Self.loadMenuBarLayout(userDefaults: userDefaults, key: "menuBarLayout")        let menuBarLayoutOverridesRaw = Self.loadMenuBarLayoutOverrides(userDefaults: userDefaults)        let menuBarLayoutSizeRaw = userDefaults.string(forKey: "menuBarLayoutSize")            ?? MenuBarLayoutSize.regular.rawValue        let menuBarLayoutGapRaw = userDefaults.string(forKey: "menuBarLayoutGap")            ?? MenuBarLayoutGap.regular.rawValue        let copilotBudgetExtrasEnabled = userDefaults.object(forKey: "copilotBudgetExtrasEnabled") as? Bool ?? false        let copilotIconSecondaryWindowIDRaw = Self.loadCopilotIconSecondaryWindowIDRaw(userDefaults: userDefaults)        let costUsageEnabled = userDefaults.object(forKey: "tokenCostUsageEnabled") as? Bool ?? false        let codexLocalSessionCostLedgerEnabled = userDefaults.object(            forKey: "codexLocalSessionCostLedgerEnabled") as? Bool ?? false        let rawCostUsageHistoryDays = userDefaults.object(forKey: "tokenCostUsageHistoryDays") as? Int ?? 30        let costUsageHistoryDays = max(1, min(365, rawCostUsageHistoryDays))        let costComparisonPeriodsEnabled = userDefaults.object(            forKey: "costComparisonPeriodsEnabled") as? Bool ?? false        let costSummaryDisplayStyleRaw = Self.loadCostSummaryDisplayStyleRaw(            userDefaults: userDefaults,            costUsageEnabled: costUsageEnabled)        let hidePersonalInfo = userDefaults.object(forKey: "hidePersonalInfo") as? Bool ?? false        let randomBlinkEnabled = userDefaults.object(forKey: "randomBlinkEnabled") as? Bool ?? false        let confettiOnReset = Self.loadConfettiOnResetDefaults(userDefaults: userDefaults)        let menuBarShowsHighestUsage = userDefaults.object(forKey: "menuBarShowsHighestUsage") as? Bool ?? false        let claudeOAuthKeychainReadStrategyRaw = Self.loadClaudeOAuthKeychainReadStrategyRaw(userDefaults: userDefaults)        let claudeOAuthKeychainPromptModeRaw = userDefaults.string(forKey: "claudeOAuthKeychainPromptMode")        let claudeWebExtrasEnabledRaw = userDefaults.object(forKey: "claudeWebExtrasEnabled") as? Bool ?? false        let creditsExtrasDefault = userDefaults.object(forKey: "showOptionalCreditsAndExtraUsage") as? Bool        let showOptionalCreditsAndExtraUsage = creditsExtrasDefault ?? true        if Self.isRunningTests, creditsExtrasDefault == nil {            userDefaults.set(true, forKey: "showOptionalCreditsAndExtraUsage")        }        let codexSparkUsageVisibleDefault = userDefaults.object(forKey: "codexSparkUsageVisible") as? Bool        let codexSparkUsageVisible = codexSparkUsageVisibleDefault ?? true        if Self.isRunningTests, codexSparkUsageVisibleDefault == nil {            userDefaults.set(true, forKey: "codexSparkUsageVisible")        }        let openAIWebAccessDefault = userDefaults.object(forKey: "openAIWebAccessEnabled") as? Bool        let openAIWebAccessEnabled = openAIWebAccessDefault ?? false        if Self.isRunningTests, openAIWebAccessDefault == nil {            userDefaults.set(false, forKey: "openAIWebAccessEnabled")        }

Lines 1–500 of 951.